@a11y-pulse/tab-orchestrator 0.3.0 → 0.5.0

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/dist/index.js CHANGED
@@ -226,14 +226,8 @@ function isCenterObscuredScript(el) {
226
226
  return false;
227
227
  }
228
228
  const rect = el.getBoundingClientRect();
229
- const x = Math.min(
230
- Math.max(rect.left + rect.width / 2, 0),
231
- window.innerWidth - 1
232
- );
233
- const y = Math.min(
234
- Math.max(rect.top + rect.height / 2, 0),
235
- window.innerHeight - 1
236
- );
229
+ const x = Math.min(Math.max(rect.left + rect.width / 2, 0), window.innerWidth - 1);
230
+ const y = Math.min(Math.max(rect.top + rect.height / 2, 0), window.innerHeight - 1);
237
231
  let hit = document.elementFromPoint(x, y);
238
232
  while (hit?.shadowRoot) {
239
233
  const inner = hit.shadowRoot.elementFromPoint(x, y);
@@ -319,9 +313,7 @@ function measureObscuringScript(el, obscurerAttr) {
319
313
  if (!el) {
320
314
  return empty;
321
315
  }
322
- for (const marked of Array.from(
323
- document.querySelectorAll(`[${obscurerAttr}]`)
324
- )) {
316
+ for (const marked of Array.from(document.querySelectorAll(`[${obscurerAttr}]`))) {
325
317
  marked.removeAttribute(obscurerAttr);
326
318
  }
327
319
  const rect = el.getBoundingClientRect();
@@ -463,9 +455,7 @@ function obscurerHandleScript() {
463
455
  return document.querySelector("[data-a11y-obscurer]");
464
456
  }
465
457
  function clearObscurerScript(obscurerAttr) {
466
- for (const marked of Array.from(
467
- document.querySelectorAll(`[${obscurerAttr}]`)
468
- )) {
458
+ for (const marked of Array.from(document.querySelectorAll(`[${obscurerAttr}]`))) {
469
459
  marked.removeAttribute(obscurerAttr);
470
460
  }
471
461
  }
@@ -551,9 +541,7 @@ function drainContextObserverScript(markerAttr) {
551
541
  if (!state) {
552
542
  return empty;
553
543
  }
554
- for (const marked of Array.from(
555
- document.querySelectorAll(`[${attributedAttr}]`)
556
- )) {
544
+ for (const marked of Array.from(document.querySelectorAll(`[${attributedAttr}]`))) {
557
545
  marked.removeAttribute(attributedAttr);
558
546
  }
559
547
  const openedWindow = state.openedWindow;
@@ -568,9 +556,7 @@ function drainContextObserverScript(markerAttr) {
568
556
  while (active?.shadowRoot?.activeElement) {
569
557
  active = active.shadowRoot.activeElement;
570
558
  }
571
- const intended = focusIns.find(
572
- (el) => el !== document.body && el !== document.documentElement
573
- ) ?? null;
559
+ const intended = focusIns.find((el) => el !== document.body && el !== document.documentElement) ?? null;
574
560
  const openingHtml = (node) => {
575
561
  const clone = node.cloneNode(false);
576
562
  clone.removeAttribute(markerAttr);
@@ -628,9 +614,7 @@ function attributedHandleScript() {
628
614
  return document.querySelector("[data-a11y-ctx-attr]");
629
615
  }
630
616
  function clearAttributedScript() {
631
- for (const marked of Array.from(
632
- document.querySelectorAll("[data-a11y-ctx-attr]")
633
- )) {
617
+ for (const marked of Array.from(document.querySelectorAll("[data-a11y-ctx-attr]"))) {
634
618
  marked.removeAttribute("data-a11y-ctx-attr");
635
619
  }
636
620
  }
@@ -646,16 +630,16 @@ function clearContextFocusInsScript() {
646
630
  function locationHrefScript() {
647
631
  return location.href;
648
632
  }
633
+ function hasFocusScript() {
634
+ return document.hasFocus();
635
+ }
649
636
 
650
637
  // src/clip.ts
651
638
  function bufferedClip(rect, pageWidth, pageHeight, buffer) {
652
639
  const left = Math.max(0, Math.min(buffer, rect.x));
653
640
  const top = Math.max(0, Math.min(buffer, rect.y));
654
641
  const right = Math.max(0, Math.min(buffer, pageWidth - rect.x - rect.width));
655
- const bottom = Math.max(
656
- 0,
657
- Math.min(buffer, pageHeight - rect.y - rect.height)
658
- );
642
+ const bottom = Math.max(0, Math.min(buffer, pageHeight - rect.y - rect.height));
659
643
  return {
660
644
  x: Math.max(0, rect.x - left),
661
645
  y: Math.max(0, rect.y - top),
@@ -832,12 +816,7 @@ function getSelector(root) {
832
816
  async function captureScreenshot(adaptor, options, handle) {
833
817
  const { width: pageWidth, height: pageHeight } = await adaptor.evaluate(pageDimensionsScript);
834
818
  const rect = await adaptor.evaluate(elementRectScript, handle);
835
- const clip = bufferedClip(
836
- rect,
837
- pageWidth,
838
- pageHeight,
839
- options.screenshotClipBuffer
840
- );
819
+ const clip = bufferedClip(rect, pageWidth, pageHeight, options.screenshotClipBuffer);
841
820
  const scale = adaptor.screenshotClipScale ?? 1;
842
821
  return adaptor.screenshotClip(clip, scale);
843
822
  }
@@ -873,9 +852,7 @@ function truncateHtml(html, options = {}) {
873
852
  async function captureUnfocusedPair(adaptor, options, handle) {
874
853
  if (await adaptor.evaluate(isCenterObscuredScript, handle)) {
875
854
  await adaptor.evaluate(scrollToCenterScript, handle);
876
- await new Promise(
877
- (resolve) => setTimeout(resolve, options.screenshotSettleDelay)
878
- );
855
+ await new Promise((resolve) => setTimeout(resolve, options.screenshotSettleDelay));
879
856
  }
880
857
  const { width: pageWidth, height: pageHeight } = await adaptor.evaluate(pageDimensionsScript);
881
858
  const focusedRect = await adaptor.evaluate(elementRectScript, handle);
@@ -895,10 +872,7 @@ async function captureUnfocusedPair(adaptor, options, handle) {
895
872
  pageHeight,
896
873
  options.screenshotClipBuffer
897
874
  );
898
- const unfocusedScreenshot = await adaptor.screenshotClip(
899
- unfocusedClip,
900
- scale
901
- );
875
+ const unfocusedScreenshot = await adaptor.screenshotClip(unfocusedClip, scale);
902
876
  const unfocusedStyles = await adaptor.evaluate(elementStylesScript, handle, [
903
877
  ...options.styleProps
904
878
  ]);
@@ -918,9 +892,7 @@ async function captureUnfocusedPair(adaptor, options, handle) {
918
892
  // src/orchestrator.ts
919
893
  function isContextDestroyedError(error) {
920
894
  const message = error instanceof Error ? error.message : String(error);
921
- return /Execution context was destroyed|Target closed|frame was detached|navigat/i.test(
922
- message
923
- );
895
+ return /Execution context was destroyed|Target closed|frame was detached|navigat/i.test(message);
924
896
  }
925
897
  var DEFAULT_SCREENSHOT_SETTLE_DELAY2 = 33;
926
898
  var DEFAULT_SCREENSHOT_CLIP_BUFFER = 10;
@@ -990,11 +962,7 @@ function createTabOrchestrator(adaptor, options = {}) {
990
962
  if (activeHandle === void 0) {
991
963
  throw new Error("unfocusedPair capture not implemented");
992
964
  }
993
- pairByStop.current ??= captureUnfocusedPair(
994
- adaptor,
995
- resolved,
996
- activeHandle
997
- );
965
+ pairByStop.current ??= captureUnfocusedPair(adaptor, resolved, activeHandle);
998
966
  return pairByStop.current;
999
967
  },
1000
968
  screenshotClip: () => {
@@ -1007,11 +975,7 @@ function createTabOrchestrator(adaptor, options = {}) {
1007
975
  if (activeHandle === void 0) {
1008
976
  throw new Error("screenshot capture not implemented");
1009
977
  }
1010
- screenshotByStop.current ??= captureScreenshot(
1011
- adaptor,
1012
- resolved,
1013
- activeHandle
1014
- );
978
+ screenshotByStop.current ??= captureScreenshot(adaptor, resolved, activeHandle);
1015
979
  return screenshotByStop.current;
1016
980
  }
1017
981
  });
@@ -1046,6 +1010,13 @@ function createTabOrchestrator(adaptor, options = {}) {
1046
1010
  baselineHref = href;
1047
1011
  return { navigation: false, raw };
1048
1012
  }
1013
+ async function documentHasFocus() {
1014
+ if (await adaptor.evaluate(hasFocusScript)) {
1015
+ return true;
1016
+ }
1017
+ await adaptor.ensureFocusReporting();
1018
+ return adaptor.evaluate(hasFocusScript);
1019
+ }
1049
1020
  let failure;
1050
1021
  try {
1051
1022
  await adaptor.ensureFocusReporting();
@@ -1075,8 +1046,7 @@ function createTabOrchestrator(adaptor, options = {}) {
1075
1046
  pairByStop.current = null;
1076
1047
  screenshotByStop.current = null;
1077
1048
  lastHasAttributed = false;
1078
- const hasFocus = await adaptor.evaluate(() => document.hasFocus());
1079
- if (!hasFocus) {
1049
+ if (!await documentHasFocus()) {
1080
1050
  end("lostFocus");
1081
1051
  break;
1082
1052
  }
@@ -1092,13 +1062,10 @@ function createTabOrchestrator(adaptor, options = {}) {
1092
1062
  if (attached.size === 0) {
1093
1063
  break;
1094
1064
  }
1065
+ const focusedAtMeasurement = await documentHasFocus();
1095
1066
  let base;
1096
1067
  try {
1097
- base = await adaptor.evaluate(
1098
- probeActiveElementScript,
1099
- styleProps,
1100
- MARKER_ATTR
1101
- );
1068
+ base = await adaptor.evaluate(probeActiveElementScript, styleProps, MARKER_ATTR);
1102
1069
  } catch (error) {
1103
1070
  if (remainingHas("contextSignals") && isContextDestroyedError(error)) {
1104
1071
  end("navigation");
@@ -1106,6 +1073,10 @@ function createTabOrchestrator(adaptor, options = {}) {
1106
1073
  }
1107
1074
  throw error;
1108
1075
  }
1076
+ if (!focusedAtMeasurement && base !== null && !base.isBody) {
1077
+ end("lostFocus");
1078
+ break;
1079
+ }
1109
1080
  let contextNav = null;
1110
1081
  if (remainingHas("contextSignals")) {
1111
1082
  const outcome = await checkContextNavigation();
@@ -1119,10 +1090,7 @@ function createTabOrchestrator(adaptor, options = {}) {
1119
1090
  if (remainingHas("contextSignals")) {
1120
1091
  let raw;
1121
1092
  try {
1122
- raw = contextNav?.raw ?? await adaptor.evaluate(
1123
- drainContextObserverScript,
1124
- MARKER_ATTR
1125
- );
1093
+ raw = contextNav?.raw ?? await adaptor.evaluate(drainContextObserverScript, MARKER_ATTR);
1126
1094
  } catch (error) {
1127
1095
  if (!isContextDestroyedError(error)) {
1128
1096
  throw error;
@@ -1131,9 +1099,7 @@ function createTabOrchestrator(adaptor, options = {}) {
1131
1099
  break;
1132
1100
  }
1133
1101
  if (raw.hasAttributed) {
1134
- const attributedRef = await adaptor.evaluateHandle(
1135
- attributedHandleScript
1136
- );
1102
+ const attributedRef = await adaptor.evaluateHandle(attributedHandleScript);
1137
1103
  let selector;
1138
1104
  try {
1139
1105
  selector = await adaptor.evaluate(getSelector, attributedRef);
@@ -1210,10 +1176,7 @@ function createTabOrchestrator(adaptor, options = {}) {
1210
1176
  if (remainingHas("contextSignals")) {
1211
1177
  let signals;
1212
1178
  try {
1213
- const raw = contextNav?.raw ?? await adaptor.evaluate(
1214
- drainContextObserverScript,
1215
- MARKER_ATTR
1216
- );
1179
+ const raw = contextNav?.raw ?? await adaptor.evaluate(drainContextObserverScript, MARKER_ATTR);
1217
1180
  signals = {
1218
1181
  openedWindow: raw.openedWindow,
1219
1182
  submittedForm: raw.submittedForm,
@@ -1240,29 +1203,16 @@ function createTabOrchestrator(adaptor, options = {}) {
1240
1203
  snapshot.contextSignals = { signals };
1241
1204
  }
1242
1205
  if (remainingHas("obscuring")) {
1243
- let raw = await adaptor.evaluate(
1244
- measureObscuringScript,
1245
- ref,
1246
- OBSCURER_ATTR
1247
- );
1206
+ let raw = await adaptor.evaluate(measureObscuringScript, ref, OBSCURER_ATTR);
1248
1207
  if (raw.fullyObscured) {
1249
- await new Promise(
1250
- (resolve) => setTimeout(resolve, OBSCURING_RECHECK_DELAY_MS)
1251
- );
1252
- raw = await adaptor.evaluate(
1253
- measureObscuringScript,
1254
- ref,
1255
- OBSCURER_ATTR
1256
- );
1208
+ await new Promise((resolve) => setTimeout(resolve, OBSCURING_RECHECK_DELAY_MS));
1209
+ raw = await adaptor.evaluate(measureObscuringScript, ref, OBSCURER_ATTR);
1257
1210
  }
1258
1211
  let obscuredBy = null;
1259
1212
  if (raw.hasObscurer) {
1260
1213
  const obscurer = await adaptor.evaluateHandle(obscurerHandleScript);
1261
1214
  try {
1262
- const obscurerSelector = await adaptor.evaluate(
1263
- getSelector,
1264
- obscurer
1265
- );
1215
+ const obscurerSelector = await adaptor.evaluate(getSelector, obscurer);
1266
1216
  obscuredBy = {
1267
1217
  selector: obscurerSelector,
1268
1218
  html: truncateHtml(raw.obscuredByHtml ?? "")
@@ -1337,6 +1287,7 @@ export {
1337
1287
  elementStylesScript,
1338
1288
  focusScript,
1339
1289
  getSelector,
1290
+ hasFocusScript,
1340
1291
  isCenterObscuredScript,
1341
1292
  pageDimensionsScript,
1342
1293
  probeActiveElementScript,