Manage ASL magazines and their articles.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
asl-articles/asl_articles/tests/test_publications.py

859 lines
32 KiB

""" Test publication operations. """
import os
import urllib.request
import urllib.error
import json
import base64
from collections import defaultdict
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import StaleElementReferenceException
from asl_articles.search import SEARCH_ALL, SEARCH_ALL_PUBLICATIONS, SEARCH_ALL_ARTICLES
from asl_articles.tests.test_articles import create_article, edit_article
from asl_articles.tests.utils import init_tests, load_fixtures, select_main_menu_option, select_sr_menu_option, \
do_search, get_search_results, get_search_result_names, check_search_result, \
do_test_confirm_discard_changes, find_parent_by_class, \
wait_for, wait_for_elem, wait_for_not_elem, find_child, find_children, find_search_result, set_elem_text, \
set_toast_marker, check_toast, send_upload_data, check_ask_dialog, check_error_msg, check_constraint_warnings, \
change_image, remove_image, get_publication_row
from asl_articles.tests.react_select import ReactSelect
# ---------------------------------------------------------------------
def test_edit_publication( webdriver, flask_app, dbconn ):
"""Test editing publications."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="publications.json" )
# edit "ASL Journal #2"
results = do_search( SEARCH_ALL_PUBLICATIONS )
sr = find_search_result( "ASL Journal (2)", results )
edit_publication( sr, {
"name": " ASL Journal (updated) ",
"edition": " 2a ",
"pub_date": "Jan 2020",
"description": " Updated ASLJ description. ",
"tags": [ "+abc", "+xyz" ],
"url": " http://aslj-updated.com ",
} )
# check that the search result was updated in the UI
sr = find_search_result( "ASL Journal (updated) (2a)" )
check_search_result( sr, _check_sr, [
"ASL Journal (updated)", "2a", "Jan 2020",
"Updated ASLJ description.", ["abc","xyz"], "http://aslj-updated.com/"
] )
# remove all fields from the publication
edit_publication( sr, {
"name": "ASLJ",
"edition": "",
"pub_date": "",
"description": "",
"tags": [ "-abc", "-xyz" ],
"url": "",
} )
# check that the search result was updated in the UI
expected = [ "ASLJ", "", "", "", [], "" ]
check_search_result( sr, _check_sr, expected )
# check that the publication was updated in the database
results = do_search( SEARCH_ALL_PUBLICATIONS )
sr = find_search_result( "ASLJ", results )
check_search_result( sr, _check_sr, expected )
# ---------------------------------------------------------------------
def test_create_publication( webdriver, flask_app, dbconn ):
"""Test creating new publications."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="publications.json" )
do_search( SEARCH_ALL_PUBLICATIONS )
# create a new publication
create_publication( {
"name": "New publication",
"edition": "#1",
"pub_date": "1st January, 1900",
"description": "New publication description.",
"tags": [ "+111", "+222", "+333" ],
"url": "http://new-publication.com"
} )
# check that the new publication appears in the UI
expected = [ "New publication", "#1", "1st January, 1900",
"New publication description.", ["111","222","333"], "http://new-publication.com/"
]
check_search_result( "New publication (#1)", _check_sr, expected )
# check that the new publication has been saved in the database
results = do_search( SEARCH_ALL_PUBLICATIONS )
sr = find_search_result( "New publication (#1)", results )
check_search_result( sr, _check_sr, expected )
# ---------------------------------------------------------------------
def test_constraints( webdriver, flask_app, dbconn ):
"""Test constraint validation."""
# initialize
init_tests( webdriver, flask_app, dbconn, disable_constraints=False, fixtures="publications.json" )
# try to create a publication with no name
dlg = create_publication( {}, expected_error="Please give it a name." )
def do_create_test( vals, expected ):
return create_publication( vals, dlg=dlg, expected_constraints=expected )
def do_edit_test( sr, vals, expected ):
return edit_publication( sr, vals, expected_constraints=expected )
# set the publication's name
do_create_test( { "name": "ASL Journal" }, [
"The publication's edition was not specified.",
"The publication date was not specified.",
"A publisher was not specified.",
] )
# try to create a duplicate publication
create_publication( { "edition": 1 }, dlg=dlg,
expected_error = "There is already a publication with this name/edition."
)
# set the publication's edition and date
do_create_test( { "edition": 3, "pub_date": "yesterday" }, [
"A publisher was not specified.",
] )
# accept the constraint warnings
find_child( "button.ok", dlg ).click()
find_child( "#ask button.ok" ).click()
results = wait_for( 2, get_search_results )
pub_sr = results[0]
# check that the search result was updated in the UI
check_search_result( pub_sr, _check_sr, [
"ASL Journal", "3", "yesterday", "", [], ""
] )
# try editing the publication
dlg = do_edit_test( pub_sr, {}, [
"A publisher was not specified.",
] )
find_child( "button.cancel", dlg ).click()
# set the publisher
do_edit_test( pub_sr, { "publisher": "Avalon Hill" }, None )
# ---------------------------------------------------------------------
def test_confirm_discard_changes( webdriver, flask_app, dbconn ):
"""Test confirmation of discarding changes made to a dialog."""
# initialize
init_tests( webdriver, flask_app, dbconn, disable_confirm_discard_changes=False, fixtures="publications.json" )
# do the test
def update_react_select( elem, val ):
select = ReactSelect( find_parent_by_class( elem, "react-select" ) )
select.select_by_name( val )
def update_multiselect( elem, vals ):
select = ReactSelect( find_parent_by_class( elem, "react-select" ) )
select.update_multiselect_values( *vals )
do_test_confirm_discard_changes( "new-publication", {
"publisher": (
lambda elem: update_react_select( elem, "Avalon Hill" ),
lambda elem: update_react_select( elem, "(none)" )
),
"tags": (
lambda elem: update_multiselect( elem, ["+foo"] ),
lambda elem: update_multiselect( elem, ["-foo"] ),
)
} )
# ---------------------------------------------------------------------
def test_delete_publication( webdriver, flask_app, dbconn ):
"""Test deleting publications."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="publications.json" )
# start to delete a publication, but cancel the operation
article_title = "ASL Journal (2)"
results = do_search( SEARCH_ALL_PUBLICATIONS )
result_names = get_search_result_names( results )
sr = find_search_result( article_title, results )
select_sr_menu_option( sr, "delete" )
check_ask_dialog( ( "Delete this publication?", article_title ), "cancel" )
# check that search results are unchanged on-screen
results2 = get_search_results()
assert results2 == results
# check that the search results are unchanged in the database
results3 = do_search( SEARCH_ALL_PUBLICATIONS )
assert get_search_result_names( results3 ) == result_names
# delete the publication
sr = find_search_result( article_title, results3 )
select_sr_menu_option( sr, "delete" )
set_toast_marker( "info" )
check_ask_dialog( ( "Delete this publication?", article_title ), "ok" )
wait_for( 2, lambda: check_toast( "info", "The publication was deleted." ) )
# check that search result was removed on-screen
wait_for( 2, lambda: article_title not in get_search_result_names() )
# check that the search result was deleted from the database
results = do_search( SEARCH_ALL_PUBLICATIONS )
assert article_title not in get_search_result_names( results )
# ---------------------------------------------------------------------
def test_images( webdriver, flask_app, dbconn ): #pylint: disable=too-many-statements
"""Test publication images."""
# initialize
init_tests( webdriver, flask_app, dbconn, max_image_upload_size=2*1024 )
def check_image( expected ):
# check the image in the publication's search result
def check_sr_image( expected ):
img = find_child( "img.image", pub_sr )
if expected:
expected_url = flask_app.url_for( "get_image", image_type="publication", image_id=pub_id )
image_url = img.get_attribute( "src" ).split( "?" )[0]
return image_url == expected_url
else:
return not img
wait_for( 2, lambda: check_sr_image( expected ) )
# check the image in the publisher's config
select_sr_menu_option( pub_sr, "edit" )
dlg = wait_for_elem( 2, "#publication-form" )
if expected:
# make sure there is an image
img = find_child( ".row.image img.image", dlg )
image_url = img.get_attribute( "src" )
assert "/images/publication/{}".format( pub_id ) in image_url
# make sure the "remove image" icon is visible
btn = find_child( ".row.image .remove-image", dlg )
assert btn.is_displayed()
# make sure the publication's image is correct
with urllib.request.urlopen( image_url ) as resp:
with open( expected, "rb" ) as fp:
assert resp.read() == fp.read()
else:
# make sure there is no image
img = find_child( ".row.image img.image", dlg )
assert img.get_attribute( "src" ).endswith( "/images/placeholder.png" )
# make sure the "remove image" icon is hidden
btn = find_child( ".row.image .remove-image", dlg )
assert not btn.is_displayed()
# make sure the publication's image is not available
url = flask_app.url_for( "get_image", image_type="publication", image_id=pub_id )
try:
with urllib.request.urlopen( url ):
pass
assert False, "Should never get here!"
except urllib.error.HTTPError as ex:
assert ex.code == 404
find_child( ".cancel", dlg ).click()
# create an publication with no image
create_publication( {"name": "Test Publication" } )
results = get_search_results()
assert len(results) == 1
pub_sr = results[0]
pub_id = pub_sr.get_attribute( "testing--pub_id" )
check_image( None )
# add an image to the publication
fname = os.path.join( os.path.split(__file__)[0], "fixtures/images/1.gif" )
edit_publication( pub_sr, { "image": fname } )
check_image( fname )
# change the publication's image
fname = os.path.join( os.path.split(__file__)[0], "fixtures/images/2.gif" )
edit_publication( pub_sr, { "image": fname } )
check_image( fname )
# remove the publication's image
edit_publication( pub_sr, { "image": None } )
check_image( None )
# try to upload an image that's too large
select_sr_menu_option( pub_sr, "edit" )
dlg = wait_for_elem( 2, "#publication-form" )
data = base64.b64encode( 5000 * b" " )
data = "{}|{}".format( "too-big.png", data.decode("ascii") )
send_upload_data( data,
lambda: find_child( ".row.image img.image", dlg ).click()
)
check_error_msg( "The file must be no more than 2 KB in size." )
# ---------------------------------------------------------------------
def test_parent_publisher( webdriver, flask_app, dbconn ):
"""Test setting a publication's parent publisher."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="parents.json" )
def check_result( sr, expected_parent ): #pylint: disable=too-many-return-statements
# check that the parent publisher was updated in the UI
elem = find_child( ".header .publisher", sr )
if expected_parent:
if elem.text != "{}".format( expected_parent[1] ):
return None
else:
if elem is not None:
return None
# check that the parent publisher was updated in the database
pub_id = sr.get_attribute( "testing--pub_id" )
url = flask_app.url_for( "get_publication", pub_id=pub_id )
with urllib.request.urlopen( url ) as resp:
pub = json.load( resp )
if expected_parent:
if pub["publ_id"] != expected_parent[0]:
return None
else:
if pub["publ_id"] is not None:
return None
# check that the parent publisher was updated in the UI
results = do_search( '"MMP News"' )
assert len(results) == 1
sr = results[0]
elem = find_child( ".header .publisher", sr )
if expected_parent:
if elem.text != "{}".format( expected_parent[1] ):
return None
else:
if elem is not None:
return None
return sr
# create a publication with no parent publisher
create_publication( { "name": "MMP News" } )
results = get_search_results()
assert len(results) == 1
sr = wait_for( 2, lambda: check_result( results[0], None ) )
# change the publication to have a publisher
edit_publication( sr, { "publisher": "Multiman Publishing" } )
sr = wait_for( 2, lambda: check_result( sr, (1, "Multiman Publishing") ) )
# change the publication back to having no publisher
edit_publication( sr, { "publisher": "(none)" } )
sr = wait_for( 2, lambda: check_result( sr, None ) )
# ---------------------------------------------------------------------
def test_cascading_deletes( webdriver, flask_app, dbconn ):
"""Test cascading deletes."""
# initialize
session = init_tests( webdriver, flask_app, dbconn )
def do_test( pub_name, expected_warning, expected_articles ):
# initialize
load_fixtures( session, "cascading-deletes-2.json" )
results = do_search( SEARCH_ALL )
# delete the specified publication
sr = find_search_result( pub_name, results )
select_sr_menu_option( sr, "delete" )
check_ask_dialog( ( "Delete this publication?", pub_name, expected_warning ), "ok" )
def check_results():
results = wait_for( 2, lambda: get_results( len(expected_articles) ) )
assert set( results ) == set( expected_articles )
def get_results( expected_len ):
# NOTE: The UI will remove anything that has been deleted, so we need to
# give it a bit of time to finish doing this.
try:
results = get_search_result_names()
except StaleElementReferenceException:
return None
results = [ r for r in results if r.startswith( "article" ) ]
if len(results) == expected_len:
return results
return None
# check that deleted associated articles were removed from the UI
check_results()
# check that associated articles were removed from the database
results = do_search( SEARCH_ALL_ARTICLES )
check_results()
# do the tests
do_test( "Cascading Deletes 1",
"No articles will be deleted", ["article 2","article 3a","article 3b"]
)
do_test( "Cascading Deletes 2",
"1 associated article will also be deleted", ["article 3a","article 3b"]
)
do_test( "Cascading Deletes 3",
"2 associated articles will also be deleted", ["article 2"]
)
# ---------------------------------------------------------------------
def test_unicode( webdriver, flask_app, dbconn ):
"""Test Unicode content."""
# initialize
init_tests( webdriver, flask_app, dbconn )
# create a publication with Unicode content
create_publication( {
"name": "japan = \u65e5\u672c",
"edition": "\u263a",
"tags": [ "+\u0e51", "+\u0e52", "+\u0e53" ],
"url": "http://\ud55c\uad6d.com",
"description": "greece = \u0395\u03bb\u03bb\u03ac\u03b4\u03b1"
} )
# check that the new publication is showing the Unicode content correctly
results = do_search( SEARCH_ALL_PUBLICATIONS )
assert len( results ) == 1
check_search_result( results[0], _check_sr, [
"japan = \u65e5\u672c", "\u263a",
None,
"greece = \u0395\u03bb\u03bb\u03ac\u03b4\u03b1",
[ "\u0e51", "\u0e52", "\u0e53" ],
"http://xn--3e0b707e.com/"
] )
# ---------------------------------------------------------------------
def test_clean_html( webdriver, flask_app, dbconn ):
"""Test cleaning HTML content."""
# initialize
init_tests( webdriver, flask_app, dbconn )
replace = [
"[\u00ab\u00bb\u201c\u201d\u201e\u201f foo\u2014bar \u2018\u2019\u201a\u201b\u2039\u203a]",
"[\"\"\"\"\"\" foo - bar '''''']"
]
# create a publication with HTML content
create_publication( {
"name": "name: <span onclick='boo!'> <b>bold</b> <xxx>xxx</xxx> <i>italic</i> {}".format( replace[0] ),
"edition": "<i>2</i>",
"description": "bad stuff here: <script>HCF</script> {}".format( replace[0] )
}, toast_type="warning" )
# check that the HTML was cleaned
sr = check_search_result( None, _check_sr, [
"name: bold xxx italic {}".format( replace[1] ),
"2",
None,
"bad stuff here: {}".format( replace[1] ),
[], None
] )
assert find_child( ".name", sr ).get_attribute( "innerHTML" ) \
== "name: <span> <b>bold</b> xxx <i>italic</i> {}</span> (<i>2</i>)".format( replace[1] )
assert check_toast( "warning", "Some values had HTML cleaned up.", contains=True )
# update the publication with new HTML content
edit_publication( sr, {
"name": "<div onclick='...'>updated</div>"
}, toast_type="warning" )
results = get_search_results()
assert len(results) == 1
wait_for( 2, lambda: find_child( ".name", results[0] ).text == "updated (2)" )
assert check_toast( "warning", "Some values had HTML cleaned up.", contains=True )
# ---------------------------------------------------------------------
def test_timestamps( webdriver, flask_app, dbconn ):
"""Test setting of timestamps."""
# initialize
init_tests( webdriver, flask_app, dbconn )
# create a publication
create_publication( { "name": "My Publication" } )
results = get_search_results()
assert len(results) == 1
pub_sr = results[0]
pub_id = pub_sr.get_attribute( "testing--pub_id" )
# check its timestamps
row = get_publication_row( dbconn, pub_id, ["time_created","time_updated"] )
assert row[0]
assert row[1] is None
# update the publication
edit_publication( pub_sr, { "name": "My Publication (updated)" } )
# check its timestamps
row2 = get_publication_row( dbconn, pub_id, ["time_created","time_updated"] )
assert row2[0] == row[0]
assert row2[1] > row2[0]
# ---------------------------------------------------------------------
def test_article_lists( webdriver, flask_app, dbconn ):
"""Test showing articles that belong to a publication."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="publications.json" )
def check_articles( results, expected ):
for pub_name,article_title in expected.items():
pub_sr = find_search_result( pub_name, results )
articles = find_child( ".collapsible", pub_sr )
if article_title:
# check that the article appears in the publication's search result
assert find_child( ".caption", articles ).text == "Articles:"
articles = find_children( "li", articles )
assert len(articles) == 1
assert articles[0].text == article_title
# check that the "edit publication" dialog is correct
select_sr_menu_option( pub_sr, "edit" )
dlg = find_child( ".MuiDialog-root" )
articles = find_children( ".articles li", dlg )
assert len(articles) == 1
assert articles[0].text == article_title
find_child( "button.cancel", dlg ).click()
else:
# check that the publication has no associated articles
assert articles is None
# check that the "edit publication" dialog is correct
select_sr_menu_option( pub_sr, "edit" )
dlg = find_child( ".MuiDialog-root" )
articles = find_children( ".articles", dlg )
assert len(articles) == 0
find_child( "button.cancel", dlg ).click()
# check that the publications have no articles associated with them
results = do_search( SEARCH_ALL_PUBLICATIONS )
pub_name1, pub_name2 = "ASL Journal (1)", "MMP News"
check_articles( results, { pub_name1: None, pub_name2: None } )
# create an article that has no parent publication
create_article( { "title": "no parent" } )
check_articles( results, { pub_name1: None, pub_name2: None } )
# create an article that has a parent publication
article_title = "test article"
create_article( { "title": article_title, "publication": pub_name1 } )
check_articles( results, { pub_name1: article_title, pub_name2: None } )
# move the article to another publication
article_sr = find_search_result( article_title )
edit_article( article_sr, { "publication": pub_name2 } )
check_articles( None, { pub_name1: None, pub_name2: article_title } )
# change the article to have no parent publication
edit_article( article_sr, { "publication": "(none)" } )
check_articles( None, { pub_name1: None, pub_name2: None } )
# move the article back into a publication
edit_article( article_sr, { "publication": pub_name1 } )
check_articles( None, { pub_name1: article_title, pub_name2: None } )
# delete the article
select_sr_menu_option( article_sr, "delete" )
check_ask_dialog( ( "Delete this article?", article_title ), "ok" )
check_articles( None, { pub_name1: None, pub_name2: None } )
# ---------------------------------------------------------------------
def test_article_order( webdriver, flask_app, dbconn ):
"""Test ordering of articles."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="article-order.json" )
def check_article_order( expected ):
# check the article order in the database
articles = defaultdict( list )
query = dbconn.execute(
"SELECT pub_name, article_title, article_seqno"
" FROM article LEFT JOIN publication"
" ON article.pub_id = publication.pub_id"
" ORDER BY article.pub_id, article_seqno"
)
for row in query:
articles[ row[0] ].append( ( row[1], row[2] ) )
assert articles == expected
# check the article order in the UI
results = do_search( SEARCH_ALL )
for pub_name in expected:
if not pub_name:
continue
sr = find_search_result( pub_name, results )
select_sr_menu_option( sr, "edit" )
dlg = wait_for_elem( 2, "#publication-form" )
articles = [ a.text for a in find_children( ".articles li.draggable", dlg ) ]
find_child( ".cancel", dlg ).click()
assert articles == [ a[0] for a in expected[pub_name] ]
# create some articles (to check the seq# is being assigned correctly)
create_article( { "title": "Article 1", "publication": "Publication A" } )
check_article_order( {
"Publication A": [ ("Article 1",1) ]
} )
create_article( { "title": "Article 2", "publication": "Publication A" } )
check_article_order( {
"Publication A": [ ("Article 1",1), ("Article 2",2) ]
} )
create_article( { "title": "Article 3", "publication": "Publication A" } )
check_article_order( {
"Publication A": [ ("Article 1",1), ("Article 2",2), ("Article 3",3) ]
} )
# create some articles (to check the seq# is being assigned correctly)
create_article( { "title": "Article 5", "publication": "Publication B" } )
check_article_order( {
"Publication A": [ ("Article 1",1), ("Article 2",2), ("Article 3",3) ],
"Publication B": [ ("Article 5",1) ]
} )
create_article( { "title": "Article 6", "publication": "Publication B" } )
check_article_order( {
"Publication A": [ ("Article 1",1), ("Article 2",2), ("Article 3",3) ],
"Publication B": [ ("Article 5",1), ("Article 6",2) ]
} )
# NOTE: It would be nice to test re-ordering articles via drag-and-drop,
# but Selenium just ain't co-operating... :-/
# move an article to another publication
sr = find_search_result( "Article 1" )
edit_article( sr, { "publication": "Publication B" } )
check_article_order( {
"Publication A": [ ("Article 2",2), ("Article 3",3) ],
"Publication B": [ ("Article 5",1), ("Article 6",2), ("Article 1",3) ]
} )
# remove the article from the publication
sr = find_search_result( "Article 1" )
edit_article( sr, { "publication": "(none)" } )
check_article_order( {
"Publication A": [ ("Article 2",2), ("Article 3",3) ],
"Publication B": [ ("Article 5",1), ("Article 6",2) ],
None: [ ("Article 1", None) ]
} )
# add the article to another publication
sr = find_search_result( "Article 1" )
edit_article( sr, { "publication": "Publication A" } )
check_article_order( {
"Publication A": [ ("Article 2",2), ("Article 3",3), ("Article 1",4) ],
"Publication B": [ ("Article 5",1), ("Article 6",2) ],
} )
# ---------------------------------------------------------------------
def test_default_image( webdriver, flask_app, dbconn ):
"""Test displaying a publication's default image."""
# initialize
init_tests( webdriver, flask_app, dbconn, fixtures="default-publication-image.json" )
# initialize
from asl_articles.tests.test_publishers import edit_publisher #pylint: disable=import-outside-toplevel
images = [ "1.gif", "2.gif", "3.gif" ]
image_fnames = {
f: os.path.join( os.path.split(__file__)[0], "fixtures/images/"+f )
for f in images
}
def read_image_data( fname ):
with open( fname, "rb" ) as fp:
return fp.read()
image_data = {
f: read_image_data( image_fnames[f] )
for f in images
}
# show the test publisher/publication
results = do_search( SEARCH_ALL )
publ_sr = find_search_result( "Joe Publisher", results )
pub_sr = find_search_result( "My Publication", results )
def check_images( publ_expected, pub_expected ):
do_check_image( publ_sr, publ_expected )
do_check_image( pub_sr, pub_expected )
def do_check_image( sr, expected ):
img = find_child( "img.image", sr )
if img:
assert expected
image_url = img.get_attribute( "src" )
with urllib.request.urlopen( image_url ) as resp:
assert resp.read() == image_data[ expected ]
else:
assert not expected
# add an image to the publisher
edit_publisher( publ_sr, { "image": image_fnames["1.gif"] } )
check_images( "1.gif", "1.gif" )
# add an image to the publication
edit_publication( pub_sr, { "image": image_fnames["2.gif"] } )
check_images( "1.gif", "2.gif" )
# remove the publisher's image
edit_publisher( publ_sr, { "image": None } )
check_images( None, "2.gif" )
# add a different image to the publisher
edit_publisher( publ_sr, { "image": image_fnames["3.gif"] } )
check_images( "3.gif", "2.gif" )
# remove the publication's image
edit_publication( pub_sr, { "image": None } )
check_images( "3.gif", "3.gif" )
# detach the publication from the publisher
edit_publication( pub_sr, { "publisher": "(none)" } )
check_images( "3.gif", None)
# ---------------------------------------------------------------------
def create_publication( vals, toast_type="info", expected_error=None, expected_constraints=None, dlg=None ):
"""Create a new publication."""
# initialize
set_toast_marker( toast_type )
# create the new publication
if not dlg:
select_main_menu_option( "new-publication" )
dlg = wait_for_elem( 2, "#publication-form" )
_update_values( dlg, vals )
find_child( "button.ok", dlg ).click()
# check what happened
if expected_error:
# we were expecting an error, confirm the error message
check_error_msg( expected_error )
return dlg # nb: the dialog is left on-screen
elif expected_constraints:
# we were expecting constraint warnings, confirm them
check_constraint_warnings( "Do you want to create this publication?", expected_constraints, "cancel" )
return dlg # nb: the dialog is left on-screen
else:
# we were expecting the create to work, confirm this
wait_for( 2,
lambda: check_toast( toast_type, "created OK", contains=True )
)
wait_for_not_elem( 2, "#publication-form" )
return None
def edit_publication( sr, vals, toast_type="info", expected_error=None, expected_constraints=None ):
"""Edit a publication's details."""
# initialize
if sr:
select_sr_menu_option( sr, "edit" )
else:
pass # nb: we assume that the dialog is already on-screen
dlg = wait_for_elem( 2, "#publication-form" )
# update the specified publication's details
_update_values( dlg, vals )
set_toast_marker( toast_type )
find_child( "button.ok", dlg ).click()
# check what happened
if expected_error:
# we were expecting an error, confirm the error message
check_error_msg( expected_error )
return dlg # nb: the dialog is left on-screen
elif expected_constraints:
# we were expecting constraint warnings, confirm them
check_constraint_warnings( "Do you want to update this publication?", expected_constraints, "cancel" )
return dlg # nb: the dialog is left on-screen
else:
# we were expecting the update to work, confirm this
expected = "updated OK" if sr else "created OK"
wait_for( 2,
lambda: check_toast( toast_type, expected, contains=True )
)
wait_for_not_elem( 2, "#publication-form" )
return None
def _update_values( dlg, vals ):
"""Update a publication's values in the form."""
for key,val in vals.items():
if key == "image":
if val:
change_image( dlg, val )
else:
remove_image( dlg )
elif key == "name":
elem = find_child( ".row.name .react-select input", dlg )
set_elem_text( elem, val )
elem.send_keys( Keys.RETURN )
elif key == "publisher":
select = ReactSelect( find_child( ".row.publisher .react-select", dlg ) )
select.select_by_name( val )
elif key == "tags":
select = ReactSelect( find_child( ".row.tags .react-select", dlg ) )
select.update_multiselect_values( *val )
else:
if key == "edition":
sel = "input.edition"
elif key == "description":
sel = ".row.description textarea"
else:
sel = ".row.{} input".format( key )
set_elem_text( find_child( sel, dlg ), val )
# ---------------------------------------------------------------------
def _check_sr( sr, expected ):
"""Check a search result."""
# check the name and edition
expected_name = expected[0]
if expected[1]:
expected_name += " ({})".format( expected[1] )
if find_child( ".name", sr ).text != expected_name:
return False
# check the publication date
elem = find_child( ".pub_date", sr )
if expected[2]:
assert elem
if elem.text != expected[2]:
return False
else:
assert elem is None
# check the description
if find_child( ".description", sr ).text != expected[3]:
return False
# check the tags
tags = [ t.text for t in find_children( ".tag", sr ) ]
if tags != expected[4]:
return False
# check the publication's link
elem = find_child( "a.open-link", sr )
if expected[5]:
assert elem
if elem.get_attribute( "href" ) != expected[5]:
return False
else:
assert elem is None
return True