@ai-ecoverse/slicc-browsers 1.7.6 → 1.7.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/guard-driver.mjs +20 -2
- package/guard-runner.mjs +16 -2
- package/guard-vectors.json +2 -2
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ Popups are observed by `Target.targetCreated` with the opener's `openerId`, or b
|
|
|
191
191
|
|
|
192
192
|
**The control rule.** Every vector has a control on an ordinary origin: the same setup and trigger against an unprotected origin must succeed. A missing or failing control fails the id. With `via: "guard"`, the control runs through the guard. With `via: "unguarded"`, the runner runs setup and trigger through its own CDP against the ordinary origin and against the protected stand-in, and both must show the effect. The runner reports the control's transport as `via`.
|
|
193
193
|
|
|
194
|
-
**Refusals.** Each refusable step has a refusal name: its `as`, or `refused.<i>`, where `i` is its index in the vector's steps, setup then trigger, with each `children` step's steps right after it, counted from 0 before `on` is applied. When a guard refuses the step and the error matches `refusal.match`, the runner sets that name to `true` in the leg's observations. On that leg, an observation whose `dependsOn` lists the name is skipped; every other observation is checked as usual. A guard that refuses the step on every origin passes in one of two ways: through the guard, with the step refused on both legs, or with an unguarded control and the guard's matched refusal on the guarded leg. With `via: "guard"`, a refusal on one leg only fails that leg. A guard that allows the step must pass its control through the guard.
|
|
194
|
+
**Refusals.** Each refusable step has a refusal name: its `as`, or `refused.<i>`, where `i` is its index in the vector's steps, setup then trigger, with each `children` step's steps right after it, counted from 0 before `on` is applied. When a guard refuses the step and the error matches `refusal.match`, the runner sets that name to `true` in the leg's observations. On that leg, an observation whose `dependsOn` lists the name is skipped; every other observation is checked as usual. A guard that refuses the step on every origin passes in one of two ways: through the guard, with the step refused on both legs, or with an unguarded control and the guard's matched refusal on the guarded leg. With `via: "guard"`, a refusal on one leg only fails that leg. The comparison only counts steps that ran on both legs. A step that ran on one leg only (for example a `children` step on the control's popup, when the guarded leg never gets that popup attached) doesn't fail the row by itself, and the row reports it in `ran`, as `{ "refused.5": "control-only" }` or `"guarded-only"`. Observations that depend on such a step follow their `dependsOn` on each leg. A guard that allows the step must pass its control through the guard.
|
|
195
195
|
|
|
196
196
|
**Liveness.** A runner checks `live` through its own CDP, never through the guard path: either the protected document loaded (title, marker or URL), or the guard returned its own refusal for a refusable step. A failing `live` fails the id.
|
|
197
197
|
|
|
@@ -285,7 +285,7 @@ target. In observations and liveness checks, an `any` alternative that reference
|
|
|
285
285
|
a `null` origin is dropped and the rest are evaluated; the row skips only when
|
|
286
286
|
every alternative of an `any`, or a required (`all`, `not` or plain) check, needs it. Tags and cookie names are unique per leg. `variant`
|
|
287
287
|
selects one variant or an array; omission selects all. `parallel` defaults to 1.
|
|
288
|
-
`log(row)` receives completed rows. A variant supplies the wait before an
|
|
288
|
+
`log(row)` receives completed rows. Besides `control`, `guarded`, `live`, `why` and `errors`, a row may carry `ran` (steps that ran on one leg only) and `notes` (settles skipped because their registration was refused). A variant supplies the wait before an
|
|
289
289
|
explicit `Target.detachFromTarget` step and for a `settle.variant` step.
|
|
290
290
|
|
|
291
291
|
Every runnable vector has a declarative `liveCheck`; every observation has a
|
|
@@ -336,7 +336,7 @@ load event never ends a wait. After a child's `children` steps that include `Pag
|
|
|
336
336
|
the runner waits, bounded at 5 s, for the child's first document to commit and load before
|
|
337
337
|
any later child step. `{ "settle": { "beacon", "required": true, "dependsOn"? } }` waits
|
|
338
338
|
for that beacon at the fixture and fails the row with `settle: no beacon from <origin>
|
|
339
|
-
within <ms>ms` when it never arrives, unless a refusal it `dependsOn` was recorded
|
|
339
|
+
within <ms>ms` when it never arrives, unless a refusal it `dependsOn` was recorded. It checks `dependsOn` again while it waits, since a child's `children` steps may still be running. When the registration it depends on was refused, the settle is skipped, the row's `notes` gets `<leg> settle:skipped-refused beacon <origin>`, and the row is judged on its other observations. The rows
|
|
340
340
|
whose `allowedBeacon` comes from an earlier document settle on it before their trigger.
|
|
341
341
|
Beacons use `navigator.sendBeacon`, with a `fetch(…, { keepalive: true })` fallback. An observation that reads a background step's `as` result
|
|
342
342
|
waits for that step, up to 10 s, and fails with `<as> did not complete within …` past it. Redirect
|
package/guard-driver.mjs
CHANGED
|
@@ -173,7 +173,18 @@ export function result(vector, run) {
|
|
|
173
173
|
}
|
|
174
174
|
const c = run.control ? judge(vector, 'control', run.control) : null;
|
|
175
175
|
const g = run.guarded ? judge(vector, 'guarded', run.guarded) : null;
|
|
176
|
-
const
|
|
176
|
+
const ranOn = (observed, name) => typeof observed?.[name] === 'boolean';
|
|
177
|
+
const both = (name) => ranOn(run.control, name) && ranOn(run.guarded, name);
|
|
178
|
+
const only = (a, b) =>
|
|
179
|
+
(a?.refused ?? []).filter((name) => both(name) && !(b?.refused ?? []).includes(name));
|
|
180
|
+
const ran = Object.fromEntries(
|
|
181
|
+
refusals(vector)
|
|
182
|
+
.filter(
|
|
183
|
+
(name) =>
|
|
184
|
+
run.control && run.guarded && ranOn(run.control, name) !== ranOn(run.guarded, name)
|
|
185
|
+
)
|
|
186
|
+
.map((name) => [name, ranOn(run.control, name) ? 'control-only' : 'guarded-only'])
|
|
187
|
+
);
|
|
177
188
|
const why = [];
|
|
178
189
|
let control = c?.pass ? 'pass' : 'fail';
|
|
179
190
|
if (!c) why.push('no control');
|
|
@@ -195,7 +206,14 @@ export function result(vector, run) {
|
|
|
195
206
|
} else why.push(...g.mismatches);
|
|
196
207
|
const live = run.live === true ? 'pass' : 'fail';
|
|
197
208
|
if (live === 'fail') why.push('not live');
|
|
198
|
-
return {
|
|
209
|
+
return {
|
|
210
|
+
...row,
|
|
211
|
+
control,
|
|
212
|
+
guarded,
|
|
213
|
+
live,
|
|
214
|
+
...(Object.keys(ran).length ? { ran } : {}),
|
|
215
|
+
...(why.length ? { why: why.join('; ') } : {}),
|
|
216
|
+
};
|
|
199
217
|
}
|
|
200
218
|
|
|
201
219
|
const passed = (r) =>
|
package/guard-runner.mjs
CHANGED
|
@@ -107,6 +107,7 @@ class Execution {
|
|
|
107
107
|
this.contexts = [];
|
|
108
108
|
this.pending = [];
|
|
109
109
|
this.errors = [];
|
|
110
|
+
this.notes = [];
|
|
110
111
|
this.answers = [];
|
|
111
112
|
this.attachSettings = new Map();
|
|
112
113
|
this.childSteps = [];
|
|
@@ -604,13 +605,20 @@ class Execution {
|
|
|
604
605
|
}
|
|
605
606
|
|
|
606
607
|
async settle(settle) {
|
|
607
|
-
|
|
608
|
+
const refused = () => (settle.dependsOn ?? []).some((name) => this.refused[name]);
|
|
609
|
+
const skipped = () => {
|
|
610
|
+
this.notes.push(
|
|
611
|
+
`settle:skipped-refused ${settle.beacon ? `beacon ${settle.beacon}` : settle.title ? `title ${settle.title}` : 'load'}`
|
|
612
|
+
);
|
|
613
|
+
};
|
|
614
|
+
if (refused()) return skipped();
|
|
608
615
|
if (settle.variant) await sleep(this.delay);
|
|
609
616
|
if (settle.title && !this.reader) {
|
|
610
617
|
await sleep(settle.ms ?? 1500);
|
|
611
618
|
return;
|
|
612
619
|
}
|
|
613
620
|
const met = await this.poll(async () => {
|
|
621
|
+
if (refused()) return true;
|
|
614
622
|
if (settle.beacon)
|
|
615
623
|
return (
|
|
616
624
|
(await this.requestCheck({ beacon: settle.beacon }, this.actionRequestStart)) &&
|
|
@@ -628,6 +636,7 @@ class Execution {
|
|
|
628
636
|
.some((e) => e.method === 'Page.loadEventFired' && e.sessionId === event.sessionId)
|
|
629
637
|
);
|
|
630
638
|
}, settle.ms ?? 1500);
|
|
639
|
+
if (refused()) return skipped();
|
|
631
640
|
if (settle.required && !met)
|
|
632
641
|
this.errors.push(
|
|
633
642
|
`settle: no ${settle.beacon ? `beacon from ${settle.beacon}` : settle.title ? `title ${settle.title}` : 'load'} within ${settle.ms ?? 1500}ms`
|
|
@@ -986,7 +995,7 @@ class Execution {
|
|
|
986
995
|
side: this.side,
|
|
987
996
|
});
|
|
988
997
|
const live = this.side === 'control' ? true : await this.check(this.vector.liveCheck);
|
|
989
|
-
return { observed, live, errors: this.errors };
|
|
998
|
+
return { observed, live, errors: this.errors, notes: this.notes };
|
|
990
999
|
} finally {
|
|
991
1000
|
this.stopped = true;
|
|
992
1001
|
await pumping;
|
|
@@ -1218,6 +1227,11 @@ async function executeRow(job, opts, clients, set, slot, index) {
|
|
|
1218
1227
|
errors: [...legs.control.errors, ...legs.guarded.errors],
|
|
1219
1228
|
designDependent: vector.designDependent ?? [],
|
|
1220
1229
|
};
|
|
1230
|
+
const notes = [
|
|
1231
|
+
...(legs.control.notes ?? []).map((note) => `control ${note}`),
|
|
1232
|
+
...(legs.guarded.notes ?? []).map((note) => `guarded ${note}`),
|
|
1233
|
+
];
|
|
1234
|
+
if (notes.length) row.notes = notes;
|
|
1221
1235
|
if (row.errors.length) {
|
|
1222
1236
|
row.control = 'fail';
|
|
1223
1237
|
row.guarded = 'fail';
|
package/guard-vectors.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"setVersion": "1.7.
|
|
3
|
+
"setVersion": "1.7.7",
|
|
4
4
|
"sources": [
|
|
5
5
|
{
|
|
6
6
|
"repo": "ai-ecoverse/slicc-cli",
|
|
@@ -5172,7 +5172,7 @@
|
|
|
5172
5172
|
},
|
|
5173
5173
|
"beacon": {
|
|
5174
5174
|
"means": "a beacon from {target}",
|
|
5175
|
-
"dependsOn": ["refused.7", "refused.8"],
|
|
5175
|
+
"dependsOn": ["refused.3", "refused.7", "refused.8"],
|
|
5176
5176
|
"requires": ["autoAttach"],
|
|
5177
5177
|
"check": {
|
|
5178
5178
|
"beacon": "{target}",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-browsers",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.7",
|
|
4
4
|
"description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -65,13 +65,13 @@
|
|
|
65
65
|
"trust:dry": "npx fledgling sync --dry-run -y --skip-publish",
|
|
66
66
|
"release": "semantic-release",
|
|
67
67
|
"test:guard": "npm run test:guard-integration && npm run test:guard-sweep",
|
|
68
|
-
"test:guard-integration": "node --test test/integration/guard-fit.test.mjs test/integration/guard-chain.test.mjs test/integration/guard-validation.test.mjs test/integration/guard-liveness.test.mjs test/integration/guard-observations.test.mjs test/integration/guard-child-latency.test.mjs test/integration/guard-adoption.test.mjs test/integration/guard-scoping.test.mjs test/integration/guard-late-pause.test.mjs",
|
|
68
|
+
"test:guard-integration": "node --test test/integration/guard-fit.test.mjs test/integration/guard-chain.test.mjs test/integration/guard-validation.test.mjs test/integration/guard-liveness.test.mjs test/integration/guard-observations.test.mjs test/integration/guard-child-latency.test.mjs test/integration/guard-adoption.test.mjs test/integration/guard-scoping.test.mjs test/integration/guard-late-pause.test.mjs test/integration/guard-legs.test.mjs",
|
|
69
69
|
"test:guard-sweep": "node scripts/test-guards.mjs",
|
|
70
70
|
"test:guard-target": "node --test test/integration/guard-runner.test.mjs",
|
|
71
71
|
"test:unit:guard": "node --experimental-test-coverage --test --test-coverage-include=guard-runner.mjs --test-coverage-include=fixture-server.mjs --test-coverage-lines=100 test/unit/guard-*.test.mjs"
|
|
72
72
|
},
|
|
73
73
|
"devDependencies": {
|
|
74
|
-
"@ai-ecoverse/slicc-shared-web": "1.23.
|
|
74
|
+
"@ai-ecoverse/slicc-shared-web": "1.23.1",
|
|
75
75
|
"@biomejs/biome": "2.5.15",
|
|
76
76
|
"ajv": "8.20.0",
|
|
77
77
|
"ajv-formats": "3.0.1",
|