238 lines
7.9 KiB
JavaScript
238 lines
7.9 KiB
JavaScript
import test from 'node:test';
|
|
import assert from 'node:assert/strict';
|
|
import {
|
|
harness,
|
|
props,
|
|
result,
|
|
committed,
|
|
text,
|
|
apply,
|
|
refresh,
|
|
adopt,
|
|
retry,
|
|
reason,
|
|
} from './helpers/profile-support-installation.mjs';
|
|
const prepare = (h) => {
|
|
h.change(reason);
|
|
h.confirm();
|
|
};
|
|
test('installation requires current proof, MFA, confirmation and a substantive reason; duplicate clicks send once', () => {
|
|
for (const patch of [
|
|
{ ready: false },
|
|
{ mfa_confirmed: false },
|
|
{ consistent: false },
|
|
]) {
|
|
const h = harness(props(patch));
|
|
prepare(h);
|
|
assert.equal(h.button(apply).props.disabled, true);
|
|
h.click(apply);
|
|
assert.equal(h.sent.length, 0);
|
|
}
|
|
const h = harness();
|
|
h.click(apply);
|
|
assert.equal(h.sent.length, 0);
|
|
h.change('short');
|
|
h.confirm();
|
|
h.click(apply);
|
|
assert.equal(h.sent.length, 0);
|
|
prepare(h);
|
|
h.click(apply);
|
|
h.click(apply);
|
|
assert.equal(h.sent.length, 1);
|
|
});
|
|
test('uncertain retry freezes the original body and preserves edits made after sending', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
const first = h.click(apply);
|
|
h.change(reason + ' later');
|
|
await h.fail(null, first);
|
|
h.click(retry);
|
|
assert.deepEqual(h.sent[1].data, first.data);
|
|
await h.reply(result(first));
|
|
assert.equal(h.reason, reason + ' later');
|
|
await h.reply(committed(first), h.reloads[0]);
|
|
assert.equal(h.reason, reason + ' later');
|
|
assert.equal(h.leave(), true);
|
|
});
|
|
test('a matching acknowledgement clears only the unchanged preparation and confirms via a fresh preview', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
const request = h.click(apply);
|
|
await h.reply(result(request));
|
|
assert.equal(h.reason, '');
|
|
await h.reply(committed(request), h.reloads[0]);
|
|
assert.equal(h.leave(), false);
|
|
assert.equal(h.button(apply).props.disabled, true);
|
|
});
|
|
test('an authenticated own receipt resolves uncertainty through GET without a second POST', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
const request = h.click(apply);
|
|
await h.fail();
|
|
h.click(refresh);
|
|
await h.reply(committed(request), h.reloads[0]);
|
|
assert.equal(h.reason, '');
|
|
assert.equal(h.sent.length, 1);
|
|
assert.equal(h.button(retry), undefined);
|
|
});
|
|
test('absence from a preview does not discard an uncertain attempt', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
const request = h.click(apply);
|
|
await h.fail();
|
|
h.click(refresh);
|
|
await h.reply(props({ hash: 'd'.repeat(64) }), h.reloads[0]);
|
|
assert.equal(h.button(adopt).props.disabled, true);
|
|
h.click(retry);
|
|
assert.deepEqual(h.sent[1].data, request.data);
|
|
});
|
|
test('changed proof requires explicit comparison and renewed confirmation', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
h.click(refresh);
|
|
await h.reply(props({ hash: 'd'.repeat(64) }), h.reloads[0]);
|
|
assert.equal(h.button(apply).props.disabled, true);
|
|
h.click(adopt);
|
|
assert.equal(h.button(apply).props.disabled, true);
|
|
assert.equal(h.reason, reason);
|
|
h.confirm();
|
|
h.click(apply);
|
|
assert.equal(h.sent[0].data.hash, 'd'.repeat(64));
|
|
});
|
|
test('a definitive rejection retains the reason and prepares a fresh command only after review', async () => {
|
|
for (const status of [409, 422]) {
|
|
const h = harness();
|
|
prepare(h);
|
|
const first = h.click(apply);
|
|
await h.fail(status);
|
|
if (status === 409) {
|
|
await h.reply(props({ hash: 'd'.repeat(64) }), h.reloads[0]);
|
|
h.click(adopt);
|
|
}
|
|
assert.equal(h.reason, reason);
|
|
assert.equal(h.button(retry), undefined);
|
|
h.confirm();
|
|
h.click(apply);
|
|
assert.notEqual(
|
|
h.sent[1].data.idempotency_key,
|
|
first.data.idempotency_key,
|
|
);
|
|
}
|
|
});
|
|
test('responses for another actor, destination, command or code cannot acknowledge this attempt', async () => {
|
|
for (const patch of [
|
|
{ actor_id: 2 },
|
|
{ target: { database: 'another_test', port: 55441 } },
|
|
{ command_key: 'other' },
|
|
{ code_hash: 'e'.repeat(64) },
|
|
]) {
|
|
const h = harness();
|
|
prepare(h);
|
|
const request = h.click(apply);
|
|
await h.reply(result(request, patch));
|
|
assert.equal(h.reason, reason);
|
|
assert.ok(h.button(retry));
|
|
assert.equal(h.reloads.length, 0);
|
|
}
|
|
});
|
|
test('restored access without fresh MFA cannot repeat the pending command', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
const request = h.click(apply);
|
|
await h.fail(403);
|
|
assert.equal(h.button(retry), undefined);
|
|
h.click(refresh);
|
|
await h.reply(props({ mfa_confirmed: false }), h.reloads[0]);
|
|
assert.equal(h.button(retry), undefined);
|
|
h.click(refresh);
|
|
await h.reply(props(), h.reloads[1]);
|
|
h.click(retry);
|
|
assert.deepEqual(h.sent[1].data, request.data);
|
|
});
|
|
test('an older GET cannot erase an acknowledged result; the later own receipt restores readiness', async () => {
|
|
const h = harness();
|
|
prepare(h);
|
|
const request = h.click(apply);
|
|
h.click(refresh);
|
|
await h.reply(result(request));
|
|
await h.reply(props(), h.reloads[0]);
|
|
assert.match(text(h.tree), /ainda n\u00e3o confirma/);
|
|
h.click(refresh);
|
|
await h.reply(committed(request), h.reloads[1]);
|
|
assert.doesNotMatch(text(h.tree), /ainda n\u00e3o confirma/);
|
|
});
|
|
test('a successful refresh clears a previous refresh failure', async () => {
|
|
const h = harness();
|
|
h.click(refresh);
|
|
await h.fail(null, h.reloads[0]);
|
|
assert.match(text(h.tree), /poss\u00edvel actualizar/);
|
|
h.click(refresh);
|
|
await h.reply(props(), h.reloads[1]);
|
|
assert.doesNotMatch(text(h.tree), /poss\u00edvel actualizar/);
|
|
});
|
|
test('late writes and reads cannot alter a form belonging to another actor or destination', async () => {
|
|
for (const patch of [
|
|
{ actorId: 2 },
|
|
{ target: { database: 'other_test', port: 55441 } },
|
|
]) {
|
|
const h = harness();
|
|
prepare(h);
|
|
const old = h.click(apply);
|
|
h.click(refresh);
|
|
const oldRead = h.reloads[0];
|
|
h.render(props(patch));
|
|
h.change('New actor preparation');
|
|
await h.reply(result(old), old);
|
|
await h.reply(committed(old), oldRead);
|
|
assert.equal(h.reason, 'New actor preparation');
|
|
assert.equal(h.sent.length, 1);
|
|
assert.equal(h.guards, 1);
|
|
}
|
|
});
|
|
test('only one leave guard protects the draft and preserves internal refreshes', () => {
|
|
const h = harness();
|
|
assert.equal(h.guards, 1);
|
|
assert.equal(h.leave(), false);
|
|
h.change(reason);
|
|
assert.equal(h.leave(), true);
|
|
assert.equal(h.confirmCalls, 1);
|
|
assert.equal(h.leave(true), false);
|
|
assert.equal(h.confirmCalls, 1);
|
|
});
|
|
const baseProps = (patch = {}) => ({
|
|
...props(),
|
|
bootstrap: {
|
|
initialized: false,
|
|
holders: [],
|
|
version: null,
|
|
rule: 'Existing rule',
|
|
pending: null,
|
|
},
|
|
...patch,
|
|
});
|
|
test('base installer guards both designated accounts and its submitted preparation', async () => {
|
|
const h = harness(baseProps({ installed: true }), 'base');
|
|
h.number(0, '1');
|
|
h.number(1, '2');
|
|
h.change(reason);
|
|
h.confirm();
|
|
assert.equal(h.leave(), true);
|
|
h.click('Pedir confirma\u00e7\u00e3o ao segundo titular');
|
|
await h.reply({ confirmation_url: '/synthetic-confirmation' });
|
|
assert.equal(h.leave(), false);
|
|
h.number(1, '3');
|
|
assert.equal(h.leave(), true);
|
|
assert.equal(h.guards, 1);
|
|
});
|
|
test('known base installation success does not prompt on sent fields when the follow-up read fails', async () => {
|
|
const h = harness(baseProps(), 'base');
|
|
prepare(h);
|
|
h.click('Instalar schema 040000');
|
|
await h.reply({ changed: true });
|
|
await h.fail(null, h.reloads[0]);
|
|
assert.equal(h.reason, reason);
|
|
assert.equal(h.leave(), false);
|
|
h.change(reason + ' later');
|
|
assert.equal(h.leave(), true);
|
|
});
|