v3.23.0: the start-with-reset suite option

A suite may carry `start_reset` (store schema v2, default false; the editor's
"Start with card reset" checkbox): before the run, the server physically
resets the card and runs the full re-initialization - `_card_reset_reinit`
(extracted from the eSIM profile-switch reinit) does reset_card() + equip +
_apply_equipped_card + the shell registration probe.

The reset runs in _test_suite_run_request before the preset/ADM checks:
- the run's preset must still match the post-reset ICCID (a mismatch refuses
  the start with a re-select hint),
- a require_adm suite re-verifies the ADM for the new card session (the
  latch is per session).

The suite report carries start_reset + reset {ok, iccid, ms}; the PWA shows
"started with a card reset" in the report header and a RESET badge in the
suite list.  Mid-run resets stay fatal.

Documented caveat: the init drain consumes the card's initial proactive
commands, so a script cannot catch the first command after the reset (they
stay in the proactive log).

Docs: test-scripts.md, api.md, help EN/RU, repo AGENTS.
Tests: 843 frontend + 827 Python; sw cache simple-v413.
This commit is contained in:
2026-10-07 09:22:24 +03:00
parent eee2888a2b
commit 6bea57599c
12 changed files with 277 additions and 48 deletions
+7 -1
View File
@@ -43,6 +43,7 @@ function snapshot() {
started: 1, finished: 2,
suite: {
id: 'a'.repeat(32), name: 'regression', require_adm: true,
start_reset: true, reset: {ok: true, iccid: '8901000000000000001', ms: 1234},
session_start: 1, session_end: 1, session_changed: false,
counters_before: {'2': '0000000010'}, counters_after: {'2': '0000000012'},
members: [
@@ -76,6 +77,7 @@ test('testReportMarkdown renders the members, steps, notes and logs', () => {
assert.match(md, /# Test suite report: regression/);
assert.match(md, /- status: error/);
assert.match(md, /- Preset: SE test1/);
assert.match(md, /- started with a card reset \(ICCID 8901000000000000001\) \u00b7 1\.2 s/);
assert.match(md, /passed: 1, warnings: 0, failed: 1, skipped: 1/);
assert.match(md, /wall time: 12\.3 s/);
assert.match(md, /SCP80: 2 0000000010 -> 0000000012/);
@@ -133,6 +135,8 @@ test('the Test script pill hosts the four suite views and their wiring', () => {
}
assert.ok(/id="test-suite-name"[^>]*oninput="testSuiteNameChanged\(\)"/.test(html));
assert.ok(/id="test-suite-adm"[^>]*onchange="testSuiteAdmChanged\(\)"/.test(html));
assert.ok(/id="test-suite-reset"[^>]*onchange="testSuiteResetChanged\(\)"/.test(html));
assert.ok(/data-l10n-title="Reset and fully re-initialize the card/.test(html));
assert.ok(/id="test-script-adm"[^>]*onchange="testScriptAdmChanged\(\)"/.test(html));
assert.ok(/id="test-suite-run-btn"[^>]*data-needs="card"/.test(html));
assert.ok(/id="test-run-btn"[^>]*data-needs="card"/.test(html));
@@ -156,7 +160,8 @@ test('a single script run sends its require_adm flag and keeps its id', () => {
test('the suite save adopts the stored suite (the server normalises the order)', async () => {
const calls = [];
const suite = {id: 'a'.repeat(32), name: 'edited', require_adm: false, scripts: []};
const suite = {id: 'a'.repeat(32), name: 'edited', require_adm: false,
start_reset: true, scripts: []};
_testSuites = [suite];
_testSuiteIdx = 0;
globalThis.testCurrentSuite = () => suite;
@@ -171,6 +176,7 @@ test('the suite save adopts the stored suite (the server normalises the order)',
await new Promise(r => setTimeout(r, 10));
assert.strictEqual(calls[0][0], '/api/test/suites/update');
assert.strictEqual(calls[0][1].suite.scripts.length, 0);
assert.strictEqual(calls[0][1].suite.start_reset, true);
assert.strictEqual(_testSuites[0].name, 'stored');
});