v3.16.0: test scripts move to a server-side store
The scripts lived in the browser's localStorage although only the local
server can run them. The new test_scripts.py store
(~/.pysim-simple-server/test_scripts.json, --test-scripts PATH) sits next to
the card presets: stable uuids and timestamps, atomic writes, and every
mutation is validated with the runner's own engine (the submitted shape is
kept - the normaliser's output is not re-normalisable: it fills defaults
like an 'any' PoR check that the check normaliser then rejects), so a stored
script cannot fail at run start for a validation reason. Import accepts the
old localStorage export as-is (export/import remains the migration path; the
PWA import also takes an exported array).
- /api/test/scripts (GET card-free: path/count + scripts), POST create,
/update, /delete and /import serve the store; the endpoints answer 503
without a store and 500 on a write failure, like the preset endpoints.
- /api/test/run takes a stored script_id (resolved when no inline script is
sent); the PWA sends the edited copy inline plus the id for the report,
and the run snapshot carries script_id.
- The PWA's Test script pill loads from the store, writes through on edits
(debounced name, immediate step/new/copy/delete), reports load/save/delete
failures inline, and exports the portable {name, steps} shape.
Tests: 808 frontend + 701 Python; sw cache simple-v379.
This commit is contained in:
@@ -517,6 +517,39 @@ class TestRunnerActions(RunnerTestCase):
|
||||
self.assertIs(preset, inline)
|
||||
self.assertIsNone(err)
|
||||
|
||||
def test_run_script_resolves_the_stored_id(self):
|
||||
import types
|
||||
entry = {'id': 'a' * 32, 'name': 'stored',
|
||||
'steps': [{'type': 'action', 'kind': 'status',
|
||||
'params': {'attempts': 1}}]}
|
||||
|
||||
class Store:
|
||||
def get(self, sid):
|
||||
return entry if sid == entry['id'] else None
|
||||
|
||||
server = types.SimpleNamespace(test_scripts=Store())
|
||||
# the inline script wins (the PWA sends the edited copy) - the id is
|
||||
# carried for the report
|
||||
raw, sid, err = S._test_run_script_from_body(
|
||||
server, {'script': {'name': 'inline', 'steps': [{}]},
|
||||
'script_id': entry['id']})
|
||||
self.assertEqual(raw['name'], 'inline')
|
||||
self.assertEqual(sid, entry['id'])
|
||||
self.assertIsNone(err)
|
||||
# script_id alone resolves from the store
|
||||
raw, sid, err = S._test_run_script_from_body(server, {'script_id': entry['id']})
|
||||
self.assertEqual(raw, {'name': 'stored', 'steps': entry['steps']})
|
||||
self.assertEqual(sid, entry['id'])
|
||||
self.assertIsNone(err)
|
||||
raw, sid, err = S._test_run_script_from_body(server, {'script_id': 'nope'})
|
||||
self.assertIsNone(raw)
|
||||
self.assertIn('not found', err)
|
||||
# neither form: the normaliser reports the missing script
|
||||
raw, sid, err = S._test_run_script_from_body(server, {})
|
||||
self.assertIsNone(raw)
|
||||
self.assertIsNone(sid)
|
||||
self.assertIsNone(err)
|
||||
|
||||
def test_preset_completeness_is_validated(self):
|
||||
script = T.normalise_script({'steps': [
|
||||
{'type': 'action', 'kind': 'scp80', 'params': {'apdu': '80E2900000'}},
|
||||
|
||||
Reference in New Issue
Block a user