@ai-ecoverse/slicc-browsers 1.20.1 → 1.20.3

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.
@@ -198,12 +198,45 @@ async function sendPair(client, session, method, down, up) {
198
198
  return [first, await outcome(client.send(method, up, session))];
199
199
  }
200
200
 
201
- async function inputMethods(client, session, methods, point, missing, side) {
201
+ const POINTER_METHODS = new Set([
202
+ 'Input.dispatchMouseEvent',
203
+ 'Input.dispatchTouchEvent',
204
+ 'Input.dispatchDragEvent',
205
+ 'Input.emulateTouchFromMouseEvent',
206
+ 'Input.synthesizePinchGesture',
207
+ 'Input.synthesizeScrollGesture',
208
+ 'Input.synthesizeTapGesture',
209
+ ]);
210
+
211
+ async function pageFocus(reader, observer) {
212
+ await observe(
213
+ reader,
214
+ observer,
215
+ '(() => { window.focus(); const i = document.getElementById("typed"); if (i) i.focus(); return true; })()'
216
+ );
217
+ }
218
+
219
+ async function inputMethods(
220
+ client,
221
+ session,
222
+ methods,
223
+ point,
224
+ missing,
225
+ side,
226
+ reader,
227
+ observer,
228
+ mode
229
+ ) {
202
230
  const results = {};
203
231
  const { x, y } = point;
204
232
  const drag = { items: [], files: [], dragOperationsMask: 1 };
205
- for (const method of methods) {
233
+ const ordered = [
234
+ ...methods.filter((method) => method !== 'Input.dispatchKeyEvent'),
235
+ ...methods.filter((method) => method === 'Input.dispatchKeyEvent'),
236
+ ];
237
+ for (const method of ordered) {
206
238
  const name = method.slice('Input.'.length);
239
+ if (mode !== 'focused' && POINTER_METHODS.has(method)) await pageFocus(reader, observer);
207
240
  let outs;
208
241
  if (method === 'Input.dispatchKeyEvent')
209
242
  outs = [
@@ -833,7 +866,17 @@ async function driveInput(client, reader, page, observer, inputList, mode, frame
833
866
  await refocus();
834
867
  const typed = await key(client, reader, page, observer, refocus, mode !== 'focused');
835
868
  await refocus();
836
- const inputs = await inputMethods(client, page, inputList, point, missing, side);
869
+ const inputs = await inputMethods(
870
+ client,
871
+ page,
872
+ inputList,
873
+ point,
874
+ missing,
875
+ side,
876
+ reader,
877
+ observer,
878
+ mode
879
+ );
837
880
  await refocus();
838
881
  const focusedKey = await outcome(
839
882
  client.send('Input.dispatchKeyEvent', { type: 'keyDown', key: 'a', code: 'KeyA' }, page)
@@ -895,7 +938,48 @@ async function driveCast(client, page, frameMs) {
895
938
  };
896
939
  }
897
940
 
898
- export async function driveReveal(client, reader, page, observer, frameMs, missing, side) {
941
+ function classifyRevealOverlap(
942
+ captureStartedAt,
943
+ revealAt,
944
+ pendingWhenRevealAcknowledged,
945
+ captureSettledAt
946
+ ) {
947
+ if (typeof captureStartedAt !== 'number' || typeof revealAt !== 'number') return 'unknown';
948
+ if (revealAt <= captureStartedAt) return 'before';
949
+ if (pendingWhenRevealAcknowledged) return 'during';
950
+ if (typeof captureSettledAt === 'number' && captureSettledAt < revealAt) return 'after';
951
+ return 'unknown';
952
+ }
953
+
954
+ function revealRaceVerdict(overlap, side, ok, shownRefused) {
955
+ if (overlap === 'during' || overlap === 'before') return side === 'control' ? ok : shownRefused;
956
+ if (overlap === 'after') return ok || shownRefused;
957
+ return false;
958
+ }
959
+
960
+ async function finishReveal(
961
+ client,
962
+ reader,
963
+ page,
964
+ observer,
965
+ frameMs,
966
+ { ok, text, overlap, revealRacePass }
967
+ ) {
968
+ const revealedPress = await click(client, reader, page, observer);
969
+ await style(reader, observer, 'hidden', frameMs);
970
+ const rehidden = await shot(client, page);
971
+ return {
972
+ revealedShot: ok,
973
+ revealedRefusal: text,
974
+ revealOverlap: overlap,
975
+ revealRacePass,
976
+ revealedClick: revealedPress.ok,
977
+ revealedClickRefusal: refusal(revealedPress.out),
978
+ rehiddenShot: rehidden.ok,
979
+ };
980
+ }
981
+
982
+ async function attemptRevealCapture(client, reader, page, observer, side) {
899
983
  const captureStartedAt = await observe(reader, observer, 'performance.now()');
900
984
  let captureSettled = false;
901
985
  let captureSettledAt;
@@ -920,31 +1004,38 @@ export async function driveReveal(client, reader, page, observer, frameMs, missi
920
1004
  const out = await pending;
921
1005
  const ok = out.ok && typeof out.result?.data === 'string' && out.result.data.length > 0;
922
1006
  const text = refusal(out);
923
- let overlap = 'unknown';
924
- if (typeof captureStartedAt !== 'number' || typeof revealAt !== 'number') overlap = 'unknown';
925
- else if (revealAt <= captureStartedAt) overlap = 'before';
926
- else if (pendingWhenRevealAcknowledged) overlap = 'during';
927
- else if (typeof captureSettledAt === 'number' && captureSettledAt < revealAt) overlap = 'after';
928
- if (overlap === 'unknown') missing.push('reveal/capture overlap unproven');
1007
+ const overlap = classifyRevealOverlap(
1008
+ captureStartedAt,
1009
+ revealAt,
1010
+ pendingWhenRevealAcknowledged,
1011
+ captureSettledAt
1012
+ );
929
1013
  const shownRefused = Boolean(text && (text === SHOWN || /^slicc: refused/.test(text)));
930
- let revealRacePass = false;
931
- if (overlap === 'during' || overlap === 'before')
932
- revealRacePass = side === 'control' ? ok : shownRefused;
933
- else if (overlap === 'after') revealRacePass = ok || shownRefused;
934
- const revealedPress = await click(client, reader, page, observer);
935
- await style(reader, observer, 'hidden', frameMs);
936
- const rehidden = await shot(client, page);
937
1014
  return {
938
- revealedShot: ok,
939
- revealedRefusal: text,
940
- revealOverlap: overlap,
941
- revealRacePass,
942
- revealedClick: revealedPress.ok,
943
- revealedClickRefusal: refusal(revealedPress.out),
944
- rehiddenShot: rehidden.ok,
1015
+ ok,
1016
+ text,
1017
+ overlap,
1018
+ revealRacePass: revealRaceVerdict(overlap, side, ok, shownRefused),
945
1019
  };
946
1020
  }
947
1021
 
1022
+ export async function driveReveal(client, reader, page, observer, frameMs, missing, side) {
1023
+ const maxAttempts = 3;
1024
+ let last = null;
1025
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
1026
+ last = await attemptRevealCapture(client, reader, page, observer, side);
1027
+ if (last.overlap !== 'unknown')
1028
+ return finishReveal(client, reader, page, observer, frameMs, last);
1029
+ if (attempt < maxAttempts) await style(reader, observer, 'hidden', frameMs);
1030
+ }
1031
+ missing.push(`reveal/capture overlap unproven (${maxAttempts} attempts)`);
1032
+ return finishReveal(client, reader, page, observer, frameMs, {
1033
+ ...last,
1034
+ overlap: 'unknown',
1035
+ revealRacePass: false,
1036
+ });
1037
+ }
1038
+
948
1039
  function frameObservations({ pageAttached, origin, read, leaks, picture, input, captures }) {
949
1040
  return {
950
1041
  exists: true,
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "schemaVersion": 1,
3
- "setVersion": "1.20.1",
3
+ "setVersion": "1.20.3",
4
4
  "sources": [
5
5
  {
6
6
  "repo": "ai-ecoverse/slicc-cli",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-ecoverse/slicc-browsers",
3
- "version": "1.20.1",
3
+ "version": "1.20.3",
4
4
  "description": "SLICC's shared browser catalog, JSON schemas and discovery conformance corpus",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -84,7 +84,7 @@
84
84
  "test:unit:guard": "mkdir -p coverage/unit && node --experimental-vm-modules --no-warnings --experimental-test-coverage --test --test-concurrency=1 --test-coverage-include=guard-runner.mjs --test-coverage-include=guard-driver.mjs --test-coverage-include=extension-frame.mjs --test-coverage-include=fixture-server.mjs --test-coverage-include=fixture-client.mjs --test-coverage-include=observer-target.mjs --test-coverage-include=frame-read.mjs --test-coverage-include=bfcache-restore.mjs --test-coverage-include=protected-error-page.mjs --test-coverage-include=unparseable-url.mjs --test-coverage-include=scripts/browser-runner.mjs --test-coverage-include=scripts/validate.mjs --test-reporter=lcov --test-reporter-destination=coverage/unit/guard.lcov test/unit/guard-*.test.mjs && slicc-diff-cover coverage/unit/guard.lcov"
85
85
  },
86
86
  "devDependencies": {
87
- "@ai-ecoverse/slicc-cdp": "1.45.2",
87
+ "@ai-ecoverse/slicc-cdp": "1.46.2",
88
88
  "@ai-ecoverse/slicc-shared-web": "2.13.10",
89
89
  "@biomejs/biome": "2.6.4",
90
90
  "ajv": "8.20.0",