Various HTML improvements
This commit is contained in:
1 parent
fd943696fb
commit
8c1fa0af57
16 files changed
+403
-45
No files matched your search
@@ -58,6 +58,25 @@ class WebTests(unittest.TestCase):
|
||||
self.assertEqual(response.status_code, 200, response.text)
|
||||
return response.json()
|
||||
|
||||
def test_names_follow_gui_repository_even_when_package_is_elsewhere(self):
|
||||
repository = self.root / 'application-folder'
|
||||
repository.mkdir()
|
||||
(repository / 'names').write_text('Alice\nBob\n', encoding='utf-8')
|
||||
service = Finalisation(self.root, 'Bnot', 'token', repository=repository)
|
||||
self.assertEqual(service.state()['expectedNames'], ['Alice', 'Bob'])
|
||||
(self.root / 'names').write_text('Claire\n', encoding='utf-8')
|
||||
self.assertEqual(service.state()['expectedNames'], ['Claire'])
|
||||
|
||||
def test_expected_names_use_local_roster_and_refresh_after_name_save(self):
|
||||
(self.root / 'names').write_text('Alice\nBob\nAlice\n\n', encoding='utf-8')
|
||||
state = self.client.get('/api/state').json()
|
||||
self.assertEqual(state['expectedNames'], ['Alice', 'Bob'])
|
||||
state = self.save('name', 'Alice')
|
||||
self.assertEqual(state['copies'][0]['name'], 'Alice')
|
||||
self.assertEqual(state['expectedNames'], ['Alice', 'Bob'])
|
||||
(self.root / 'names').write_text('', encoding='utf-8')
|
||||
self.assertEqual(self.service.state()['expectedNames'], [])
|
||||
|
||||
def test_session_origin_and_paths(self):
|
||||
outsider = TestClient(create_app(self.service, 'browser-token'))
|
||||
self.assertEqual(outsider.get('/api/state').status_code, 403)
|
||||
@@ -164,6 +183,35 @@ class WebTests(unittest.TestCase):
|
||||
self.assertEqual(len(calls), 1)
|
||||
self.assertEqual(self.service.job['status'], 'failed')
|
||||
|
||||
def test_names_only_skip_rendering_before_first_cache_and_after_restart(self):
|
||||
from copienator.review_snapshot import stage
|
||||
output = self.root / 'Bnot/Copie01'
|
||||
data = {'Ex 1': {'pdf_path': self.root/'Copies/Copie01/Ex 1.pdf',
|
||||
'result': {'score': 3, 'feedback': []}, 'coordinates': [0, 0]}}
|
||||
with staged_files(output) as staging:
|
||||
stage(output, staging, data, {}, engine='standard', bnote={'images': []})
|
||||
self.save('name', 'Alice')
|
||||
self.assertFalse((output / '.reviewed-render-state.json').exists())
|
||||
reopened = Finalisation(self.root, 'Bnot', 'token')
|
||||
calls = []
|
||||
class Process:
|
||||
def __init__(self, command, **kwargs):
|
||||
calls.append(command[3])
|
||||
self.stdout = StringIO('done\n')
|
||||
def __enter__(self): return self
|
||||
def __exit__(self, *args): pass
|
||||
def wait(self): return 0
|
||||
with patch('copienator.finalisation.subprocess.Popen', Process):
|
||||
reopened._regenerate(False)
|
||||
self.assertEqual(calls, ['giving-names'])
|
||||
self.save('name', 'Bob')
|
||||
# A score edited outside the session must invalidate the names-only shortcut.
|
||||
set_score(output/'score.json', 'Ex 1', '1')
|
||||
calls.clear()
|
||||
with patch('copienator.finalisation.subprocess.Popen', Process):
|
||||
self.service._regenerate(False)
|
||||
self.assertEqual(calls, ['regenerate-reviewed', 'giving-names'])
|
||||
|
||||
def test_os_lock_blocks_cli_and_releases(self):
|
||||
with EvaluationLock(self.root):
|
||||
with self.assertRaises(CliError):
|
||||
@@ -256,6 +304,33 @@ class SnapshotTests(unittest.TestCase):
|
||||
|
||||
@unittest.skipUnless(os.environ.get('DISPLAY'), 'Tk requires a display')
|
||||
class WebGuiTests(unittest.TestCase):
|
||||
def test_web_button_requires_read_outputs_and_remains_enabled_when_stale(self):
|
||||
from copienator_gui.app import CopienatorApp
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
(root / 'Copies').mkdir()
|
||||
(root / 'labels').write_text('Ex 1\n')
|
||||
app = CopienatorApp(Path.cwd(), False, root)
|
||||
self.addCleanup(app.destroy)
|
||||
def state():
|
||||
app._update_controls()
|
||||
return str(app.finalisation_web_button.cget('state'))
|
||||
self.assertEqual(state(), 'disabled')
|
||||
output = root / 'BGnot/Copie01'
|
||||
output.mkdir(parents=True)
|
||||
atomic_write_json(output/'bnote.json', {'images': []})
|
||||
self.assertEqual(state(), 'disabled')
|
||||
seed(root, 'BGnot')
|
||||
self.assertEqual(state(), 'normal')
|
||||
app.state_store.update_step('read_annotations', status='stale')
|
||||
self.assertEqual(state(), 'normal')
|
||||
app.active_step_id = 'read_annotations'
|
||||
self.assertEqual(state(), 'disabled')
|
||||
app.active_step_id = None
|
||||
self.assertEqual(state(), 'normal')
|
||||
app.state_store.evaluation = None
|
||||
self.assertEqual(state(), 'disabled')
|
||||
|
||||
def test_modal_lock_and_return_to_existing_workflow(self):
|
||||
from copienator_gui.app import CopienatorApp
|
||||
from copienator.finalisation_server import WebSession
|
||||
@@ -295,3 +370,90 @@ class WebGuiTests(unittest.TestCase):
|
||||
self.assertIsNone(app.web_session)
|
||||
self.assertIsNone(app.grab_current())
|
||||
self.assertEqual(app.state_store.step('read_annotations')['status'], 'stale')
|
||||
|
||||
|
||||
class IncrementalReviewedTests(unittest.TestCase):
|
||||
def test_only_changed_copies_render_and_missing_outputs_are_retried(self):
|
||||
from copienator.commands import regenerate_reviewed, annotating
|
||||
from copienator.review_snapshot import stage
|
||||
from copienator.custom_remarks import set_remark
|
||||
import shutil
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
seed(root, 'BGnot')
|
||||
pdf = root / 'Copies/Copie01/Ex 1.pdf'
|
||||
pdf.write_bytes(b'answer')
|
||||
data = {'Ex 1': {'pdf_path':pdf, 'result':{'score':3,'feedback':[]},'coordinates':[0,0]}}
|
||||
output = root / 'BGnot/Copie01'
|
||||
with staged_files(output) as staging:
|
||||
stage(output, staging, data, {}, engine='grouped')
|
||||
shutil.copytree(output, root / 'BGnot/Copie02')
|
||||
workspace = EvaluationWorkspace(root)
|
||||
with patch.object(annotating, 'make_base_image', return_value=(Image.new('RGB',(100,100),'white'),0,0)), \
|
||||
patch.object(annotating, 'compose_label_image', return_value=(Image.new('RGB',(100,120),'white'),20)) as compose, \
|
||||
patch('copienator.commands.reading_grouped_annotations.get_extra_pdfs_as_images', return_value=[]):
|
||||
def run(count):
|
||||
compose.reset_mock()
|
||||
self.assertEqual(regenerate_reviewed.run(workspace,'BGnot',incremental=True), 0)
|
||||
self.assertEqual(compose.call_count,count)
|
||||
run(2)
|
||||
run(0)
|
||||
set_score(output/'score.json','Ex 1','2')
|
||||
run(1)
|
||||
run(0)
|
||||
set_remark(root,'01','Ex 1','Justifier.')
|
||||
run(1)
|
||||
set_remark(root,'01','Ex 1','')
|
||||
run(1)
|
||||
(output/'Ex 1.jpg').unlink()
|
||||
run(1)
|
||||
(root/'Text2').mkdir()
|
||||
(root/'Text2/Ex 1.pdf').write_bytes(b'changed question')
|
||||
run(2)
|
||||
run(0)
|
||||
self.assertEqual(regenerate_reviewed.run(workspace,'BGnot'),0)
|
||||
self.assertEqual(compose.call_count,2)
|
||||
|
||||
def test_incremental_transfers_apply_changes_and_undo_without_repeating(self):
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
seed(root)
|
||||
workspace = EvaluationWorkspace(root)
|
||||
from copienator.annotation_modifications import rebuild
|
||||
with patch.object(modify_annotations, 'rebuild', wraps=rebuild) as render:
|
||||
def run(text, count):
|
||||
(root / DRAFT).write_text('### Source: Bnot\n' + text)
|
||||
render.reset_mock()
|
||||
self.assertEqual(modify_annotations.run(workspace, annotation_dir='Bnot', incremental=True), 0)
|
||||
self.assertEqual(render.call_count, count)
|
||||
run('Copie01 Ex 1 c{40}1> Ex 2|\n', 1)
|
||||
run('Copie01 Ex 1 c{40}1> Ex 2|\n', 0)
|
||||
run('Copie01 Ex 1 c{50}1> Ex 2|\n', 1)
|
||||
run('', 1)
|
||||
run('', 0)
|
||||
self.assertEqual(Image.open(root/'Bnot/Copie01/Ex 1.jpg').height,120)
|
||||
|
||||
@patch('copienator.commands.giving_names.configuration.RETURN_ANSWERS_ENABLED', False)
|
||||
def test_return_publication_skips_unchanged_and_repairs_missing_files(self):
|
||||
import shutil
|
||||
with tempfile.TemporaryDirectory() as temporary:
|
||||
root = Path(temporary)
|
||||
seed(root)
|
||||
shutil.copytree(root/'Bnot/Copie01',root/'Bnot/Copie02')
|
||||
atomic_write_json(root/'Copies/Copie02.json',{'name':'Bob'})
|
||||
atomic_write_json(root/'Copies/Copie01.json',{'name':'Alice'})
|
||||
workspace = EvaluationWorkspace(root)
|
||||
from copienator.return_answers import publish_answer_returns
|
||||
with patch.object(giving_names,'publish_answer_returns',wraps=publish_answer_returns) as publish:
|
||||
def run(count):
|
||||
publish.reset_mock()
|
||||
self.assertEqual(giving_names.prepare_named_returns(workspace,'Bnot',incremental=True),0)
|
||||
self.assertEqual(publish.call_count,count)
|
||||
run(2)
|
||||
run(0)
|
||||
set_score(root/'Bnot/Copie01/score.json','Ex 1','1')
|
||||
run(1)
|
||||
run(0)
|
||||
(root/'A Rendre/Bob (02)/info.json').unlink()
|
||||
run(1)
|
||||
self.assertTrue((root/'A Rendre/Bob (02)/info.json').is_file())
|
||||
Reference in new issue
Block a user