v3.21.0: the test-runner tolerance batch + the proactive cleanup action
Five reported issues, plus the action that makes an explicit drain possible: - on_fail is honoured by every step failure: an expectation with no pending command (or a FETCH that returns nothing) fails as a Command/Fetch check at the step's level instead of raising past it; the default still stops the run, on_fail "warning" continues (the tolerant consume-if-pending form). - the run cleanup answers ok (0x00) and keeps draining while the TR answers 91XX (bounded); a cancel is only sent when a script asks for it - it tells the card the user aborted the session and pushes assertive applets onto an error path. - new `proactive` action: STATUS rounds consume every announced command (respond/first TERMINAL RESPONSE results, attempts/interval_ms bound) until the card answers 9000; an optional require asserts at least one drained command (an empty drain fails it), the final SW is the step's SW check and a still-pending command is handed to the next step. PWA editor + summary + validation, EN/RU help, docs, action-kind drift test. - the PoR response form follows the command's TAR: _tar_is_rm (preset role entries + the TS 101 220 Annex D ISD/RFM allocations) decides; a non-RM TAR's reply is always raw (TS 102 226 4) - no fabricated status word even when the bytes happen to parse (01 00 0B 91 ... used to read as SW 000B). - a secured data too short for the compact structure (a 2-byte applet reply) is recovered by _por_header_parse (the decode minus the compact parse; a malformed packet or a failed RC/CC/DS check still yields no por) and reported raw, so short applet replies are assertable via por.data. Docs: test-scripts.md, api.md, help EN/RU, repo AGENTS. sw cache simple-v396. Tests: 825 frontend + 755 Python green.
This commit is contained in:
@@ -107,6 +107,10 @@ test('testScriptProblem accepts good scripts and names bad ones', () => {
|
||||
assert.match(testScriptProblem({
|
||||
steps: [{ type: 'action', kind: 'file-read', params: {} }] }), /file path/);
|
||||
assert.match(testScriptProblem({ steps: [{ type: 'expect' }] }), /command is required/);
|
||||
assert.match(testScriptProblem({ steps: [{ type: 'action', kind: 'proactive',
|
||||
params: { attempts: 0 } }] }), /attempts/);
|
||||
assert.strictEqual(testScriptProblem({ steps: [{ type: 'action', kind: 'proactive',
|
||||
params: {} }] }), '');
|
||||
// the selected SCP80 source decides which value is required
|
||||
assert.match(testScriptProblem({ steps: [{ type: 'action', kind: 'scp80',
|
||||
params: { source: 'apdu', sp: 'AA' } }] }), /SCP80/);
|
||||
@@ -116,6 +120,29 @@ test('testScriptProblem accepts good scripts and names bad ones', () => {
|
||||
params: { source: 'sp', sp: 'AA', apdu: '80E2' } }] }), '');
|
||||
});
|
||||
|
||||
test('the proactive cleanup step collects its fields', () => {
|
||||
_testEditStep = { type: 'action', kind: 'proactive', params: {} };
|
||||
_testEditChecks = [];
|
||||
_testEditStepIndex = 0;
|
||||
fakeForm({ 'test-step-kind': 'proactive', 'test-f-presult': 'ok', 'test-f-pfirst': 'cancel',
|
||||
'test-f-pattempts': '5', 'test-f-pinterval': '0', 'test-f-prequire': 'refresh',
|
||||
'test-f-prequal': '00', 'test-f-sw': '', 'test-f-cdata': '', 'test-f-fail': 'error' });
|
||||
testStepCollect();
|
||||
const p = _testEditStep.params;
|
||||
assert.strictEqual(p.respond.result, 'ok');
|
||||
assert.strictEqual(p.first.result, 'cancel');
|
||||
assert.strictEqual(p.attempts, 5);
|
||||
assert.strictEqual(p.interval_ms, 0);
|
||||
assert.deepStrictEqual(p.require, { command: 'REFRESH', qualifier: '00' });
|
||||
// an empty require field drops the assertion
|
||||
fakeForm({ 'test-step-kind': 'proactive', 'test-f-presult': 'ok', 'test-f-pfirst': '',
|
||||
'test-f-pattempts': '3', 'test-f-pinterval': '200', 'test-f-prequire': '',
|
||||
'test-f-prequal': '', 'test-f-sw': '', 'test-f-cdata': '', 'test-f-fail': 'error' });
|
||||
testStepCollect();
|
||||
assert.ok(!('first' in _testEditStep.params));
|
||||
assert.ok(!('require' in _testEditStep.params));
|
||||
});
|
||||
|
||||
test('testStepSummary renders actions', () => {
|
||||
assert.strictEqual(
|
||||
testStepSummary({ type: 'action', kind: 'menu-select', params: { item_id: 3 },
|
||||
@@ -135,6 +162,15 @@ test('testStepSummary renders actions', () => {
|
||||
assert.strictEqual(
|
||||
testStepSummary({ type: 'action', kind: 'status', params: { attempts: 5 } }),
|
||||
'STATUS x5 (poll)');
|
||||
assert.strictEqual(
|
||||
testStepSummary({ type: 'action', kind: 'proactive',
|
||||
params: { attempts: 5, respond: { result: 'ok' },
|
||||
require: { command: 'REFRESH', qualifier: '00' } } }),
|
||||
'PROACTIVE x5 require REFRESH q=00 TR ok');
|
||||
assert.strictEqual(
|
||||
testStepSummary({ type: 'action', kind: 'proactive',
|
||||
params: { attempts: 3, first: { result: 'cancel' } } }),
|
||||
'PROACTIVE x3 TR ok first cancel');
|
||||
assert.strictEqual(
|
||||
testStepSummary({ type: 'action', kind: 'file-read', params: { path: 'MF/2FE2' } }),
|
||||
'READ MF/2FE2');
|
||||
|
||||
Reference in New Issue
Block a user