doc-detective 4.22.0 → 4.24.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.
Files changed (105) hide show
  1. package/dist/common/src/schemas/schemas.json +43158 -10448
  2. package/dist/common/src/types/generated/config_v3.d.ts +1 -1
  3. package/dist/common/src/types/generated/context_v3.d.ts +1 -1
  4. package/dist/common/src/types/generated/report_v3.d.ts +1 -1
  5. package/dist/common/src/types/generated/resolvedTests_v3.d.ts +2 -2
  6. package/dist/common/src/types/generated/spec_v3.d.ts +1 -1
  7. package/dist/common/src/types/generated/step_v3.d.ts +453 -1
  8. package/dist/common/src/types/generated/step_v3.d.ts.map +1 -1
  9. package/dist/common/src/types/generated/swipe_v3.d.ts +288 -0
  10. package/dist/common/src/types/generated/swipe_v3.d.ts.map +1 -0
  11. package/dist/common/src/types/generated/swipe_v3.js +7 -0
  12. package/dist/common/src/types/generated/swipe_v3.js.map +1 -0
  13. package/dist/common/src/types/generated/test_v3.d.ts +1935 -967
  14. package/dist/common/src/types/generated/test_v3.d.ts.map +1 -1
  15. package/dist/core/appium.d.ts +2 -1
  16. package/dist/core/appium.d.ts.map +1 -1
  17. package/dist/core/appium.js +47 -13
  18. package/dist/core/appium.js.map +1 -1
  19. package/dist/core/ptyProbeWorker.d.ts +2 -0
  20. package/dist/core/ptyProbeWorker.d.ts.map +1 -0
  21. package/dist/core/ptyProbeWorker.js +61 -0
  22. package/dist/core/ptyProbeWorker.js.map +1 -0
  23. package/dist/core/ptyWatchdog.d.ts +77 -0
  24. package/dist/core/ptyWatchdog.d.ts.map +1 -0
  25. package/dist/core/ptyWatchdog.js +179 -0
  26. package/dist/core/ptyWatchdog.js.map +1 -0
  27. package/dist/core/resolveTests.d.ts.map +1 -1
  28. package/dist/core/resolveTests.js +16 -4
  29. package/dist/core/resolveTests.js.map +1 -1
  30. package/dist/core/tests/appGestures.d.ts +27 -0
  31. package/dist/core/tests/appGestures.d.ts.map +1 -0
  32. package/dist/core/tests/appGestures.js +325 -0
  33. package/dist/core/tests/appGestures.js.map +1 -0
  34. package/dist/core/tests/appSurface.d.ts +23 -3
  35. package/dist/core/tests/appSurface.d.ts.map +1 -1
  36. package/dist/core/tests/appSurface.js +166 -19
  37. package/dist/core/tests/appSurface.js.map +1 -1
  38. package/dist/core/tests/browserWait.d.ts +1 -1
  39. package/dist/core/tests/browserWait.d.ts.map +1 -1
  40. package/dist/core/tests/browserWait.js +108 -84
  41. package/dist/core/tests/browserWait.js.map +1 -1
  42. package/dist/core/tests/click.d.ts.map +1 -1
  43. package/dist/core/tests/click.js +12 -8
  44. package/dist/core/tests/click.js.map +1 -1
  45. package/dist/core/tests/findElement.d.ts.map +1 -1
  46. package/dist/core/tests/findElement.js +96 -13
  47. package/dist/core/tests/findElement.js.map +1 -1
  48. package/dist/core/tests/mobileBrowser.d.ts +46 -0
  49. package/dist/core/tests/mobileBrowser.d.ts.map +1 -0
  50. package/dist/core/tests/mobileBrowser.js +141 -0
  51. package/dist/core/tests/mobileBrowser.js.map +1 -0
  52. package/dist/core/tests/mobilePlatform.d.ts +1 -7
  53. package/dist/core/tests/mobilePlatform.d.ts.map +1 -1
  54. package/dist/core/tests/mobilePlatform.js +5 -27
  55. package/dist/core/tests/mobilePlatform.js.map +1 -1
  56. package/dist/core/tests/movement.d.ts +43 -0
  57. package/dist/core/tests/movement.d.ts.map +1 -0
  58. package/dist/core/tests/movement.js +92 -0
  59. package/dist/core/tests/movement.js.map +1 -0
  60. package/dist/core/tests/swipe.d.ts +8 -0
  61. package/dist/core/tests/swipe.d.ts.map +1 -0
  62. package/dist/core/tests/swipe.js +158 -0
  63. package/dist/core/tests/swipe.js.map +1 -0
  64. package/dist/core/tests/typeKeys.d.ts +8 -1
  65. package/dist/core/tests/typeKeys.d.ts.map +1 -1
  66. package/dist/core/tests/typeKeys.js +123 -23
  67. package/dist/core/tests/typeKeys.js.map +1 -1
  68. package/dist/core/tests.d.ts +7 -1
  69. package/dist/core/tests.d.ts.map +1 -1
  70. package/dist/core/tests.js +250 -74
  71. package/dist/core/tests.js.map +1 -1
  72. package/dist/core/utils.d.ts +2 -1
  73. package/dist/core/utils.d.ts.map +1 -1
  74. package/dist/core/utils.js +62 -4
  75. package/dist/core/utils.js.map +1 -1
  76. package/dist/hints/context.d.ts.map +1 -1
  77. package/dist/hints/context.js +4 -0
  78. package/dist/hints/context.js.map +1 -1
  79. package/dist/hints/types.d.ts +3 -4
  80. package/dist/hints/types.d.ts.map +1 -1
  81. package/dist/index.cjs +44005 -10132
  82. package/dist/reporters/htmlReporter.js +3 -2
  83. package/dist/reporters/htmlReporter.js.map +1 -1
  84. package/dist/runtime/androidInstaller.d.ts +27 -0
  85. package/dist/runtime/androidInstaller.d.ts.map +1 -1
  86. package/dist/runtime/androidInstaller.js +138 -2
  87. package/dist/runtime/androidInstaller.js.map +1 -1
  88. package/dist/runtime/browserStepKeys.d.ts +17 -1
  89. package/dist/runtime/browserStepKeys.d.ts.map +1 -1
  90. package/dist/runtime/browserStepKeys.js +25 -0
  91. package/dist/runtime/browserStepKeys.js.map +1 -1
  92. package/dist/runtime/heavyDeps.d.ts +25 -0
  93. package/dist/runtime/heavyDeps.d.ts.map +1 -1
  94. package/dist/runtime/heavyDeps.js +34 -0
  95. package/dist/runtime/heavyDeps.js.map +1 -1
  96. package/dist/runtime/inferRuntimeNeeds.js +8 -2
  97. package/dist/runtime/inferRuntimeNeeds.js.map +1 -1
  98. package/dist/runtime/installer.d.ts +9 -0
  99. package/dist/runtime/installer.d.ts.map +1 -1
  100. package/dist/runtime/installer.js +17 -1
  101. package/dist/runtime/installer.js.map +1 -1
  102. package/dist/runtime/loader.d.ts.map +1 -1
  103. package/dist/runtime/loader.js +85 -1
  104. package/dist/runtime/loader.js.map +1 -1
  105. package/package.json +1 -1
@@ -0,0 +1,141 @@
1
+ // Native app surfaces phase A5: mobile web browsers on managed devices.
2
+ // With a mobile platform entry, `browsers` means the browser ON the device,
3
+ // driven through the same per-device Appium session the app surfaces use:
4
+ // Chrome on the Android emulator (UiAutomator2 + server-managed chromedriver)
5
+ // and Safari on the iOS simulator (XCUITest). Everything here is pure —
6
+ // support-matrix decisions, config rejection, and capability shapes — so the
7
+ // preflights stay unit-testable without a device.
8
+ import path from "node:path";
9
+ // The device browser each mobile target supports. There is exactly one per
10
+ // platform — the on-device browser is part of the device image, not an
11
+ // installable engine choice, so unsupported names SKIP (they can never
12
+ // become available on that target) rather than falling back.
13
+ const SUPPORTED_MOBILE_BROWSER = {
14
+ android: "chrome",
15
+ ios: "safari",
16
+ };
17
+ // Subdirectory of the Doc Detective cache where the Appium server stores the
18
+ // chromedrivers it auto-downloads to match the device's Chrome version.
19
+ const MOBILE_CHROMEDRIVER_DIR = "chromedriver-mobile";
20
+ export { mobileBrowserSupport, mobileBrowserConfigError, buildMobileBrowserCapabilities, defaultMobileBrowserName, mobileBrowserGate, MOBILE_CHROMEDRIVER_DIR, };
21
+ // The browser a mobile context gets when the runOn entry names none — the
22
+ // mobile analog of the desktop first-available default.
23
+ function defaultMobileBrowserName(platform) {
24
+ return SUPPORTED_MOBILE_BROWSER[platform];
25
+ }
26
+ // The A5 support matrix: chrome+android and safari+ios are the only pairs.
27
+ // The reason names both the rejected and the supported browser so the fix is
28
+ // one edit away.
29
+ function mobileBrowserSupport({ platform, browserName, }) {
30
+ const supported = SUPPORTED_MOBILE_BROWSER[platform];
31
+ if (browserName === supported)
32
+ return { supported: true };
33
+ return {
34
+ supported: false,
35
+ reason: `Skipping context: '${browserName}' isn't available on ${platform}. '${supported}' is the supported ${platform} browser — set browsers: "${supported}" (or omit browsers) on the ${platform} runOn entry.`,
36
+ };
37
+ }
38
+ // Device-fixed browser config is rejected loudly rather than silently
39
+ // ignored: `headless` belongs to the device descriptor, and window/viewport
40
+ // dimensions are fixed by the device's screen. `headless: true` is the
41
+ // schema-injected default (AJV useDefaults), so only an authored `false` is
42
+ // distinguishable and rejectable.
43
+ function mobileBrowserConfigError(browser) {
44
+ if (!browser)
45
+ return null;
46
+ if (browser.headless === false) {
47
+ return "browser headless is meaningless for a device browser — the device owns its display. Set headless on the device descriptor (device.headless) instead.";
48
+ }
49
+ const authoredDimensions = (value) => value && typeof value === "object" && Object.keys(value).length > 0;
50
+ if (authoredDimensions(browser.window)) {
51
+ return "browser window dimensions are fixed by the device's screen and can't be set on a mobile context. Choose a different device (device.deviceType) if you need another size.";
52
+ }
53
+ if (authoredDimensions(browser.viewport)) {
54
+ return "browser viewport dimensions are fixed by the device's screen and can't be set on a mobile context. Choose a different device (device.deviceType) if you need another size.";
55
+ }
56
+ return null;
57
+ }
58
+ // The one decision point the mobile preflights consult before any toolchain
59
+ // work: does this context get a device-browser session, a SKIP, or a FAIL?
60
+ // Order matters — the mixed guard first (a scope limit, so SKIP, and config
61
+ // on a context that can't run at all shouldn't fail the run), then the loud
62
+ // config rejection, then the support matrix with the platform default filled.
63
+ function mobileBrowserGate({ platform, browser, hasBrowserStep, hasAppStep, }) {
64
+ if (!hasBrowserStep)
65
+ return { action: "proceed", browserName: null };
66
+ if (hasAppStep) {
67
+ // Interleaving native app surfaces and the device browser in one context
68
+ // needs foreground + NATIVE_APP/WEBVIEW context switching — its own
69
+ // subsystem, deferred past A6 (which shipped the interaction vocabulary;
70
+ // see the design doc's A6 entry). Both halves run today — in separate
71
+ // tests/contexts.
72
+ return {
73
+ action: "skip",
74
+ level: "warning",
75
+ reason: `Skipping context on '${platform}': mixing native app surfaces and browser steps in one mobile context isn't supported yet — put the web steps and the app steps in separate tests or contexts. Mobile-web-only and native-app-only contexts both run today.`,
76
+ };
77
+ }
78
+ const configError = mobileBrowserConfigError(browser);
79
+ if (configError) {
80
+ return {
81
+ action: "fail",
82
+ reason: `Mobile context on '${platform}': ${configError}`,
83
+ };
84
+ }
85
+ const browserName = browser?.name ?? defaultMobileBrowserName(platform);
86
+ const support = mobileBrowserSupport({ platform, browserName });
87
+ if (!support.supported) {
88
+ return { action: "skip", level: "warning", reason: support.reason };
89
+ }
90
+ return { action: "proceed", browserName };
91
+ }
92
+ // Session capabilities for the device browser. Mirrors the per-platform app
93
+ // capability shapes in appSurface.ts (APP_DRIVER_PLATFORMS) — same drivers,
94
+ // same udid pinning, same WDA timeout floor and derived-data opt-in — but
95
+ // with `browserName` in place of an app identifier, which puts the session
96
+ // in a web context from the start.
97
+ function buildMobileBrowserCapabilities({ platform, udid, cacheDir, timeout, }) {
98
+ if (platform === "android") {
99
+ return {
100
+ platformName: "Android",
101
+ "appium:automationName": "UiAutomator2",
102
+ browserName: "Chrome",
103
+ "appium:udid": udid,
104
+ "appium:newCommandTimeout": 600,
105
+ // adb operations can be slow on a cold emulator (same floor as app
106
+ // sessions).
107
+ "appium:adbExecTimeout": 120000,
108
+ "wdio:enforceWebDriverClassic": true,
109
+ // On-device chromedriver management: the server downloads a
110
+ // chromedriver matching the device's Chrome version. Requires the
111
+ // Appium server to run with
112
+ // --allow-insecure=uiautomator2:chromedriver_autodownload. The
113
+ // download lands in the Doc Detective cache so later runs reuse it.
114
+ "appium:chromedriverAutodownload": true,
115
+ "appium:chromedriverExecutableDir": path.join(cacheDir, MOBILE_CHROMEDRIVER_DIR),
116
+ };
117
+ }
118
+ const capabilities = {
119
+ platformName: "iOS",
120
+ "appium:automationName": "XCUITest",
121
+ browserName: "Safari",
122
+ "appium:udid": udid,
123
+ "appium:newCommandTimeout": 600,
124
+ "wdio:enforceWebDriverClassic": true,
125
+ };
126
+ // The first-ever XCUITest session cold-builds WebDriverAgent via
127
+ // xcodebuild (~10 min on CI). App surfaces carry an authored startSurface
128
+ // timeout for this; a mobile-web session has no step to author one on, so
129
+ // the default ceiling matches the generous one the apps-ios fixtures use.
130
+ const effectiveTimeout = timeout ?? 900000;
131
+ capabilities["appium:wdaLaunchTimeout"] = Math.max(effectiveTimeout, 120000);
132
+ capabilities["appium:wdaConnectionTimeout"] = Math.max(effectiveTimeout, 120000);
133
+ // Same opt-in derived-data sharing as iOS app sessions (see appSurface.ts
134
+ // for the caching contract).
135
+ const derivedDataPath = process.env.DOC_DETECTIVE_IOS_WDA_DERIVED_DATA_PATH;
136
+ if (derivedDataPath && derivedDataPath.trim()) {
137
+ capabilities["appium:derivedDataPath"] = derivedDataPath.trim();
138
+ }
139
+ return capabilities;
140
+ }
141
+ //# sourceMappingURL=mobileBrowser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mobileBrowser.js","sourceRoot":"","sources":["../../../src/core/tests/mobileBrowser.ts"],"names":[],"mappings":"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"}
@@ -1,10 +1,4 @@
1
- export { isMobileTargetPlatform, mobileContextSkipReason };
1
+ export { isMobileTargetPlatform };
2
2
  type MobileTarget = "android" | "ios";
3
3
  declare function isMobileTargetPlatform(platform: unknown): MobileTarget | null;
4
- declare function mobileContextSkipReason({ platform, }: {
5
- platform: MobileTarget;
6
- }): {
7
- level: "warning" | "info";
8
- reason: string;
9
- };
10
4
  //# sourceMappingURL=mobilePlatform.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"mobilePlatform.d.ts","sourceRoot":"","sources":["../../../src/core/tests/mobilePlatform.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,CAAC;AAE3D,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,CAAC;AAGtC,iBAAS,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAGtE;AASD,iBAAS,uBAAuB,CAAC,EAC/B,QAAQ,GACT,EAAE;IACD,QAAQ,EAAE,YAAY,CAAC;CACxB,GAAG;IAAE,KAAK,EAAE,SAAS,GAAG,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAahD"}
1
+ {"version":3,"file":"mobilePlatform.d.ts","sourceRoot":"","sources":["../../../src/core/tests/mobilePlatform.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAElC,KAAK,YAAY,GAAG,SAAS,GAAG,KAAK,CAAC;AAGtC,iBAAS,sBAAsB,CAAC,QAAQ,EAAE,OAAO,GAAG,YAAY,GAAG,IAAI,CAGtE"}
@@ -1,37 +1,15 @@
1
1
  // Native app surfaces phase A3: the `android`/`ios` target platforms. Unlike
2
2
  // desktop platforms (where host == target), a mobile platform names the
3
3
  // TARGET a context runs against and is gated by host *capability*, not host
4
- // identity. As of A4, native app contexts can pass on both mobile targets
5
- // when the host is capable. The remaining mobile-target skip reason this
6
- // module composes is mobile browser testing (A5), which is still gated on both
7
- // android and ios. The reason composer is pure so it's unit-testable without
8
- // probing an SDK.
9
- export { isMobileTargetPlatform, mobileContextSkipReason };
4
+ // identity. Native app contexts (A3/A4) and mobile-web browser contexts (A5)
5
+ // both run on capable hosts; the browser-side decisions (support matrix,
6
+ // device-fixed config rejection, mixed-context deferral) live in
7
+ // mobileBrowser.ts.
8
+ export { isMobileTargetPlatform };
10
9
  // Classify a context platform as a mobile target, or null for desktop / junk.
11
10
  function isMobileTargetPlatform(platform) {
12
11
  if (platform === "android" || platform === "ios")
13
12
  return platform;
14
13
  return null;
15
14
  }
16
- // Compose the SKIP reason (and log level) for the one mobile-context case still
17
- // gated by a later phase: a mobile-web (browser) step on either target — mobile
18
- // browsers land in A5. Native app contexts (no browser step) are NOT routed
19
- // here; they pass through their platform's context preflight (androidContext-
20
- // Preflight / iosContextPreflight), which capability-gates and runs them. This
21
- // composer is only ever called for a mobile-browser context, so it branches on
22
- // the target platform alone.
23
- function mobileContextSkipReason({ platform, }) {
24
- const roadmap = "docs/design/native-app-surfaces.md";
25
- if (platform === "ios") {
26
- return {
27
- level: "warning",
28
- reason: `Skipping context on 'ios': mobile browser testing on iOS lands in phase A5 of the native app roadmap (${roadmap}). Native iOS app tests run on capable macOS hosts.`,
29
- };
30
- }
31
- // android + a browser step: mobile-web testing on Android is phase A5.
32
- return {
33
- level: "warning",
34
- reason: `Skipping context on 'android': mobile browser testing on Android lands in phase A5 of the native app roadmap (${roadmap}). Native Android app tests (no browser steps) run today.`,
35
- };
36
- }
37
15
  //# sourceMappingURL=mobilePlatform.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mobilePlatform.js","sourceRoot":"","sources":["../../../src/core/tests/mobilePlatform.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,0EAA0E;AAC1E,yEAAyE;AACzE,+EAA+E;AAC/E,6EAA6E;AAC7E,kBAAkB;AAElB,OAAO,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,CAAC;AAI3D,8EAA8E;AAC9E,SAAS,sBAAsB,CAAC,QAAiB;IAC/C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC;AAED,gFAAgF;AAChF,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,+EAA+E;AAC/E,+EAA+E;AAC/E,6BAA6B;AAC7B,SAAS,uBAAuB,CAAC,EAC/B,QAAQ,GAGT;IACC,MAAM,OAAO,GAAG,oCAAoC,CAAC;IACrD,IAAI,QAAQ,KAAK,KAAK,EAAE,CAAC;QACvB,OAAO;YACL,KAAK,EAAE,SAAS;YAChB,MAAM,EAAE,yGAAyG,OAAO,qDAAqD;SAC9K,CAAC;IACJ,CAAC;IACD,uEAAuE;IACvE,OAAO;QACL,KAAK,EAAE,SAAS;QAChB,MAAM,EAAE,iHAAiH,OAAO,2DAA2D;KAC5L,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"mobilePlatform.js","sourceRoot":"","sources":["../../../src/core/tests/mobilePlatform.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,wEAAwE;AACxE,4EAA4E;AAC5E,6EAA6E;AAC7E,yEAAyE;AACzE,iEAAiE;AACjE,oBAAoB;AAEpB,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAIlC,8EAA8E;AAC9E,SAAS,sBAAsB,CAAC,QAAiB;IAC/C,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,KAAK,KAAK;QAAE,OAAO,QAAQ,CAAC;IAClE,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,43 @@
1
+ export { directionToPoints, fractionsToPixels, surfaceToAbsolutePixels, performMovement, performElementPress, getBrowserViewportRect, };
2
+ export type { MovementPoint, MovementRect, SwipeDirection };
3
+ type SwipeDirection = "up" | "down" | "left" | "right";
4
+ type MovementPoint = {
5
+ x: number;
6
+ y: number;
7
+ };
8
+ type MovementRect = {
9
+ x: number;
10
+ y: number;
11
+ width: number;
12
+ height: number;
13
+ };
14
+ export declare const MOVEMENT_INSET = 0.1;
15
+ export declare const DEFAULT_SWIPE_DISTANCE = 0.5;
16
+ export declare const DEFAULT_SWIPE_DURATION = 500;
17
+ declare function directionToPoints(direction: SwipeDirection, distance?: number): {
18
+ from: MovementPoint;
19
+ to: MovementPoint;
20
+ };
21
+ declare function fractionsToPixels(rect: MovementRect, point: MovementPoint): {
22
+ x: number;
23
+ y: number;
24
+ };
25
+ declare function surfaceToAbsolutePixels(rect: MovementRect, point: MovementPoint): {
26
+ x: number;
27
+ y: number;
28
+ };
29
+ declare function performMovement({ driver, from, to, duration, pointerType, }: {
30
+ driver: any;
31
+ from: MovementPoint;
32
+ to: MovementPoint;
33
+ duration?: number;
34
+ pointerType?: "mouse" | "touch";
35
+ }): Promise<void>;
36
+ declare function performElementPress({ driver, element, button, duration, }: {
37
+ driver: any;
38
+ element: any;
39
+ button?: string;
40
+ duration: number;
41
+ }): Promise<void>;
42
+ declare function getBrowserViewportRect(driver: any): Promise<MovementRect>;
43
+ //# sourceMappingURL=movement.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"movement.d.ts","sourceRoot":"","sources":["../../../src/core/tests/movement.ts"],"names":[],"mappings":"AAeA,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,uBAAuB,EACvB,eAAe,EACf,mBAAmB,EACnB,sBAAsB,GACvB,CAAC;AACF,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,CAAC;AAE5D,KAAK,cAAc,GAAG,IAAI,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AACvD,KAAK,aAAa,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAC9C,KAAK,YAAY,GAAG;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC;AAK5E,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAC1C,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAM1C,iBAAS,iBAAiB,CACxB,SAAS,EAAE,cAAc,EACzB,QAAQ,GAAE,MAA+B,GACxC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,EAAE,EAAE,aAAa,CAAA;CAAE,CAe5C;AAED,iBAAS,iBAAiB,CACxB,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,aAAa,GACnB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAK1B;AAKD,iBAAS,uBAAuB,CAC9B,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,aAAa,GACnB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAK1B;AAOD,iBAAe,eAAe,CAAC,EAC7B,MAAM,EACN,IAAI,EACJ,EAAE,EACF,QAAiC,EACjC,WAAqB,GACtB,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,aAAa,CAAC;IACpB,EAAE,EAAE,aAAa,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC;CACjC,GAAG,OAAO,CAAC,IAAI,CAAC,CAShB;AAMD,iBAAe,mBAAmB,CAAC,EACjC,MAAM,EACN,OAAO,EACP,MAAe,EACf,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,OAAO,EAAE,GAAG,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;CAClB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUhB;AAED,iBAAe,sBAAsB,CAAC,MAAM,EAAE,GAAG,GAAG,OAAO,CAAC,YAAY,CAAC,CAMxE"}
@@ -0,0 +1,92 @@
1
+ // The shared coordinate-movement engine (phase A6). `swipe` is the movement
2
+ // subset of `dragAndDrop`: dragAndDrop locates two elements and moves between
3
+ // them; swipe moves between two points (authored directly, or computed from a
4
+ // direction shorthand). Both concepts meet here — dragAndDrop's future
5
+ // app-surface branch calls performMovement with element-center fractions.
6
+ //
7
+ // Directional shorthands travel as 0-1 fractions of a rect ({x, y, width,
8
+ // height}); authored point-to-point coordinates are literal pixels relative
9
+ // to the surface's top-left (the context/viewport pixel convention). Both
10
+ // convert to absolute pixels before the engine moves anything, so the engine
11
+ // stays driver-agnostic and unit-testable with a fake driver.
12
+ // Functions are hoisted, so the grouped export lists only them; the constants
13
+ // export inline at their declarations (a top-of-file `export {}` referencing
14
+ // a later `const` trips use-before-declaration analysis).
15
+ export { directionToPoints, fractionsToPixels, surfaceToAbsolutePixels, performMovement, performElementPress, getBrowserViewportRect, };
16
+ // Directional swipes keep away from the outer 10% of the surface so a
17
+ // full-length swipe can't trigger a system edge gesture (Android back/home).
18
+ // Explicit point-to-point coordinates are the author's own and aren't inset.
19
+ export const MOVEMENT_INSET = 0.1;
20
+ export const DEFAULT_SWIPE_DISTANCE = 0.5;
21
+ export const DEFAULT_SWIPE_DURATION = 500;
22
+ // A direction is the virtual finger's motion: swiping up moves content up,
23
+ // revealing content further down the page. The from/to pair is centered on
24
+ // the surface and clamped to the inset box, so the maximum effective travel
25
+ // is 1 - 2 * MOVEMENT_INSET.
26
+ function directionToPoints(direction, distance = DEFAULT_SWIPE_DISTANCE) {
27
+ const clamp = (value) => Math.min(1 - MOVEMENT_INSET, Math.max(MOVEMENT_INSET, value));
28
+ const near = clamp(0.5 - distance / 2);
29
+ const far = clamp(0.5 + distance / 2);
30
+ switch (direction) {
31
+ case "up":
32
+ return { from: { x: 0.5, y: far }, to: { x: 0.5, y: near } };
33
+ case "down":
34
+ return { from: { x: 0.5, y: near }, to: { x: 0.5, y: far } };
35
+ case "left":
36
+ return { from: { x: far, y: 0.5 }, to: { x: near, y: 0.5 } };
37
+ case "right":
38
+ return { from: { x: near, y: 0.5 }, to: { x: far, y: 0.5 } };
39
+ }
40
+ }
41
+ function fractionsToPixels(rect, point) {
42
+ return {
43
+ x: Math.round(rect.x + point.x * rect.width),
44
+ y: Math.round(rect.y + point.y * rect.height),
45
+ };
46
+ }
47
+ // Offset an author-supplied pixel point (relative to the surface's top-left)
48
+ // into the coordinate space the driver expects (absolute, per the window
49
+ // rect's origin — zero for mobile screens and browser viewports).
50
+ function surfaceToAbsolutePixels(rect, point) {
51
+ return {
52
+ x: Math.round(rect.x + point.x),
53
+ y: Math.round(rect.y + point.y),
54
+ };
55
+ }
56
+ // One pointer movement through the wdio W3C actions builder: move to the
57
+ // start, press, a short settle pause (so touch drivers register the press as
58
+ // a drag rather than a tap), a timed move to the end, release. `from`/`to`
59
+ // are absolute pixels — callers convert fractions (fractionsToPixels) or
60
+ // surface-relative author pixels (surfaceToAbsolutePixels) first.
61
+ async function performMovement({ driver, from, to, duration = DEFAULT_SWIPE_DURATION, pointerType = "mouse", }) {
62
+ await driver
63
+ .action("pointer", { parameters: { pointerType } })
64
+ .move({ x: Math.round(from.x), y: Math.round(from.y) })
65
+ .down()
66
+ .pause(50)
67
+ .move({ duration, x: Math.round(to.x), y: Math.round(to.y) })
68
+ .up()
69
+ .perform();
70
+ }
71
+ // Press-and-hold a located element through the W3C actions builder (browser
72
+ // long-press, and the Mac2 desktop path). Device web contexts (XCUITest web,
73
+ // phase A5) reject the actions endpoint — like non-left buttons, this is
74
+ // desktop-browser-only until those contexts grow actions support.
75
+ async function performElementPress({ driver, element, button = "left", duration, }) {
76
+ const buttonIndex = { left: 0, middle: 1, right: 2 }[button] ?? 0;
77
+ await driver
78
+ .action("pointer", { parameters: { pointerType: "mouse" } })
79
+ .move({ origin: element })
80
+ .down({ button: buttonIndex })
81
+ .pause(duration)
82
+ .up({ button: buttonIndex })
83
+ .perform();
84
+ }
85
+ async function getBrowserViewportRect(driver) {
86
+ const [width, height] = await driver.execute(() => [
87
+ window.innerWidth,
88
+ window.innerHeight,
89
+ ]);
90
+ return { x: 0, y: 0, width, height };
91
+ }
92
+ //# sourceMappingURL=movement.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"movement.js","sourceRoot":"","sources":["../../../src/core/tests/movement.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export { swipeSurface };
2
+ declare function swipeSurface({ config, step, driver, appSession, }: {
3
+ config: any;
4
+ step: any;
5
+ driver: any;
6
+ appSession?: any;
7
+ }): Promise<any>;
8
+ //# sourceMappingURL=swipe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swipe.d.ts","sourceRoot":"","sources":["../../../src/core/tests/swipe.ts"],"names":[],"mappings":"AAqBA,OAAO,EAAE,YAAY,EAAE,CAAC;AAiCxB,iBAAe,YAAY,CAAC,EAC1B,MAAM,EACN,IAAI,EACJ,MAAM,EACN,UAAU,GACX,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC;IACV,MAAM,EAAE,GAAG,CAAC;IACZ,UAAU,CAAC,EAAE,GAAG,CAAC;CAClB,gBAkIA"}
@@ -0,0 +1,158 @@
1
+ // The swipe step (phase A6): the movement subset of dragAndDrop — a pointer
2
+ // movement between two points, authored directly (from/to pixels relative to
3
+ // the surface's top-left) or via the direction shorthand (fractions). Valid
4
+ // on app and browser surfaces; a process has no screen to swipe. Pure
5
+ // execution: no implicit assertions, like goTo.
6
+ import { validate } from "../../common/src/validate.js";
7
+ import { parseSurfaceRef, reinterpretForSessions, switchToSurface, } from "./browserSurface.js";
8
+ import { resolveAppSurfaceRef, ensureAppForeground } from "./appSurface.js";
9
+ import { APP_GESTURES } from "./appGestures.js";
10
+ import { directionToPoints, performMovement, getBrowserViewportRect, DEFAULT_SWIPE_DISTANCE, DEFAULT_SWIPE_DURATION, } from "./movement.js";
11
+ export { swipeSurface };
12
+ // Normalize the three schema forms into one gesture shape. The directional
13
+ // forms keep `direction`/`distance` (adapters with a native directional
14
+ // gesture use them as-is); point-to-point carries `from`/`to`.
15
+ function normalizeSwipe(swipe) {
16
+ if (typeof swipe === "string") {
17
+ return {
18
+ direction: swipe,
19
+ distance: DEFAULT_SWIPE_DISTANCE,
20
+ duration: DEFAULT_SWIPE_DURATION,
21
+ };
22
+ }
23
+ if (swipe.from && swipe.to) {
24
+ return {
25
+ from: swipe.from,
26
+ to: swipe.to,
27
+ duration: swipe.duration ?? DEFAULT_SWIPE_DURATION,
28
+ };
29
+ }
30
+ return {
31
+ direction: swipe.direction,
32
+ distance: swipe.distance ?? DEFAULT_SWIPE_DISTANCE,
33
+ duration: swipe.duration ?? DEFAULT_SWIPE_DURATION,
34
+ };
35
+ }
36
+ async function swipeSurface({ config, step, driver, appSession, }) {
37
+ const result = {
38
+ status: "PASS",
39
+ description: "Swiped the surface.",
40
+ outputs: {},
41
+ assertions: [],
42
+ };
43
+ // Validate step payload
44
+ const isValidStep = validate({ schemaKey: "step_v3", object: step });
45
+ if (!isValidStep.valid) {
46
+ result.status = "FAIL";
47
+ result.description = `Invalid step definition: ${isValidStep.errors}`;
48
+ return result;
49
+ }
50
+ step = isValidStep.object;
51
+ const surface = typeof step.swipe === "object" ? step.swipe.surface : undefined;
52
+ const gesture = normalizeSwipe(step.swipe);
53
+ result.outputs = {
54
+ ...(gesture.direction !== undefined && { direction: gesture.direction }),
55
+ ...(gesture.distance !== undefined && { distance: gesture.distance }),
56
+ ...(gesture.from !== undefined && { from: gesture.from, to: gesture.to }),
57
+ duration: gesture.duration,
58
+ };
59
+ // App-surface branch: an app registry hit is authoritative for its name.
60
+ const appRef = resolveAppSurfaceRef(surface, appSession);
61
+ if (appRef) {
62
+ if (appRef.error) {
63
+ result.status = "FAIL";
64
+ result.description = appRef.error;
65
+ return result;
66
+ }
67
+ if (appRef.window !== undefined) {
68
+ result.status = "FAIL";
69
+ result.description =
70
+ "Window selectors on app surfaces land in a later part of this phase; act on the app's active window for now (omit `window`).";
71
+ return result;
72
+ }
73
+ const switched = await ensureAppForeground(appRef.entry, appSession);
74
+ if (switched.error) {
75
+ result.status = "FAIL";
76
+ result.description = switched.error;
77
+ return result;
78
+ }
79
+ const platform = appRef.entry.platform ?? "windows";
80
+ const gestures = APP_GESTURES[platform];
81
+ if (!gestures) {
82
+ result.status = "FAIL";
83
+ result.description = `swipe isn't implemented for the "${platform}" app platform.`;
84
+ return result;
85
+ }
86
+ try {
87
+ await gestures.swipe(appRef.entry.driver, gesture);
88
+ }
89
+ catch (error) {
90
+ result.status = "FAIL";
91
+ result.description = `Couldn't swipe the app surface: ${error?.message ?? error}`;
92
+ return result;
93
+ }
94
+ result.description = `Swiped the app surface "${appRef.entry.name}".`;
95
+ return result;
96
+ }
97
+ // Everything else resolves to a browser surface: swipe's schema restricts
98
+ // bare strings to engine keywords and has NO process branch (a background
99
+ // process has no screen to swipe — the kind is unrepresentable, per the
100
+ // byEngineName precedent), so the process kind can't reach this point.
101
+ const resolved = reinterpretForSessions(driver, parseSurfaceRef(surface));
102
+ if (resolved.kind === "unsupported") {
103
+ // An { app: … } reference in a context with no app session lands here.
104
+ result.status = "FAIL";
105
+ result.description = `The surface names an app, but no app session is active in this context. Open the app first with startSurface.`;
106
+ return result;
107
+ }
108
+ if (resolved.kind === "browser") {
109
+ const switched = await switchToSurface(driver, surface);
110
+ if (!switched.ok) {
111
+ result.status = "FAIL";
112
+ result.description = switched.message;
113
+ return result;
114
+ }
115
+ driver = switched.driver ?? driver;
116
+ }
117
+ if (!driver) {
118
+ result.status = "FAIL";
119
+ result.description = `swipe needs a surface to act on in an app-only context. Name the app surface: { "swipe": { "direction": "up", "surface": { "app": "…" } } }.`;
120
+ return result;
121
+ }
122
+ try {
123
+ if (gesture.from && gesture.to) {
124
+ // Point-to-point: a real pointer drag (sliders, canvases, maps).
125
+ // Authored pixels are viewport-relative, which is what the W3C
126
+ // viewport-origin actions expect — no conversion needed.
127
+ await performMovement({
128
+ driver,
129
+ from: gesture.from,
130
+ to: gesture.to,
131
+ duration: gesture.duration,
132
+ pointerType: "mouse",
133
+ });
134
+ }
135
+ else {
136
+ // Directional: scroll the page. A mouse drag on a web page selects text
137
+ // instead of scrolling, so the finger-motion semantics map onto
138
+ // scrollBy: swiping up moves content up, revealing content below.
139
+ const rect = await getBrowserViewportRect(driver);
140
+ const { from, to } = directionToPoints(gesture.direction, gesture.distance);
141
+ const dx = Math.round((from.x - to.x) * rect.width);
142
+ const dy = Math.round((from.y - to.y) * rect.height);
143
+ await driver.execute(
144
+ /* c8 ignore next 3 - runs inside the browser via driver.execute() */
145
+ (x, y) => {
146
+ window.scrollBy({ left: x, top: y, behavior: "auto" });
147
+ }, dx, dy);
148
+ }
149
+ }
150
+ catch (error) {
151
+ result.status = "FAIL";
152
+ result.description = `Couldn't swipe the browser surface: ${error?.message ?? error}`;
153
+ return result;
154
+ }
155
+ result.description = "Swiped the browser surface.";
156
+ return result;
157
+ }
158
+ //# sourceMappingURL=swipe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"swipe.js","sourceRoot":"","sources":["../../../src/core/tests/swipe.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,11 @@
1
- export { typeKeys, translateProcessKeys, resolveSurface, resolveInputDelay };
1
+ export { typeKeys, translateProcessKeys, splitKeyRuns, resolveSurface, resolveInputDelay, };
2
+ declare function splitKeyRuns(keys: string[], platform: "android" | "ios"): Array<{
3
+ kind: "text";
4
+ text: string;
5
+ } | {
6
+ kind: "token";
7
+ token: string;
8
+ }>;
2
9
  declare const _processKeyMap: Record<string, string>;
3
10
  export { _processKeyMap };
4
11
  declare function resolveInputDelay(inputDelay: unknown): number;
@@ -1 +1 @@
1
- {"version":3,"file":"typeKeys.d.ts","sourceRoot":"","sources":["../../../src/core/tests/typeKeys.ts"],"names":[],"mappings":"AAwBA,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC;AAK7E,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY1C,CAAC;AAKF,OAAO,EAAE,cAAc,EAAE,CAAC;AAM1B,iBAAS,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAEtD;AAMD,iBAAS,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAuCtD;AAWD,iBAAS,cAAc,CAAC,OAAO,EAAE,GAAG,+CAEnC;AAsMD,iBAAe,QAAQ,CAAC,EACtB,MAAM,EACN,IAAI,EACJ,MAAM,EACN,eAAe,EACf,UAAU,GACX,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC;IACV,MAAM,EAAE,GAAG,CAAC;IACZ,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,GAAG,CAAC;CAClB,gBAgUA"}
1
+ {"version":3,"file":"typeKeys.d.ts","sourceRoot":"","sources":["../../../src/core/tests/typeKeys.ts"],"names":[],"mappings":"AA+BA,OAAO,EACL,QAAQ,EACR,oBAAoB,EACpB,YAAY,EACZ,cAAc,EACd,iBAAiB,GAClB,CAAC;AAQF,iBAAS,YAAY,CACnB,IAAI,EAAE,MAAM,EAAE,EACd,QAAQ,EAAE,SAAS,GAAG,KAAK,GAC1B,KAAK,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAAG;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAsC1E;AAKD,QAAA,MAAM,cAAc,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAY1C,CAAC;AAKF,OAAO,EAAE,cAAc,EAAE,CAAC;AAM1B,iBAAS,iBAAiB,CAAC,UAAU,EAAE,OAAO,GAAG,MAAM,CAEtD;AAMD,iBAAS,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAuCtD;AAWD,iBAAS,cAAc,CAAC,OAAO,EAAE,GAAG,+CAEnC;AAsMD,iBAAe,QAAQ,CAAC,EACtB,MAAM,EACN,IAAI,EACJ,MAAM,EACN,eAAe,EACf,UAAU,GACX,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,IAAI,EAAE,GAAG,CAAC;IACV,MAAM,EAAE,GAAG,CAAC;IACZ,eAAe,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACnC,UAAU,CAAC,EAAE,GAAG,CAAC;CAClB,gBAmXA"}