@samsara-dev/appwright 0.4.0 → 0.5.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # appwright
2
2
 
3
+ ## 0.5.1
4
+
5
+ ### Patch Changes
6
+
7
+ - d5b7e84: Apply BrowserStack iOS permission settings after the app install by default, using a worker fixture so sessions start with the requested configuration.
8
+
9
+ ## 0.5.0
10
+
11
+ ### Minor Changes
12
+
13
+ - c40123e: Add per-test status syncing for persistentDevice so BrowserStack and LambdaTest sessions reflect test names and outcomes.
14
+
3
15
  ## 0.4.0
4
16
 
5
17
  ### Minor Changes
@@ -1,5 +1,5 @@
1
1
  import type { Client as WebDriverClient } from "webdriver";
2
- import { AppwrightLocator, ExtractType, IosAppSettings, IosPermissionSettings, Platform, TimeoutOptions, VisualTraceConfig } from "../types";
2
+ import { AppwrightLocator, DeviceProvider, ExtractType, IosAppSettings, IosPermissionSettings, Platform, TimeoutOptions, VisualTraceConfig } from "../types";
3
3
  import { z } from "zod";
4
4
  import { LLMModel } from "@empiricalrun/llm";
5
5
  import { TestInfo } from "@playwright/test";
@@ -9,7 +9,20 @@ export declare class Device {
9
9
  private timeoutOpts;
10
10
  private provider;
11
11
  private visualTraceService?;
12
- constructor(webDriverClient: WebDriverClient, bundleId: string | undefined, timeoutOpts: TimeoutOptions, provider: string);
12
+ private deviceProvider?;
13
+ private persistentSyncEnabled;
14
+ private activePersistentKey?;
15
+ constructor(webDriverClient: WebDriverClient, bundleId: string | undefined, timeoutOpts: TimeoutOptions, provider: string, deviceProvider?: DeviceProvider);
16
+ attachDeviceProvider(provider: DeviceProvider): void;
17
+ enablePersistentStatusSync(): void;
18
+ ensurePersistentLifecycle(testInfo: TestInfo): Promise<void>;
19
+ preparePersistentTest(testInfo: TestInfo): Promise<void>;
20
+ finalizePersistentTest(testInfo: TestInfo): Promise<void>;
21
+ private shouldSyncPersistent;
22
+ private persistentKey;
23
+ private mapPlaywrightStatus;
24
+ private failureReason;
25
+ private safeSync;
13
26
  /**
14
27
  * Initialize Visual Trace Service for screenshot capture during test execution
15
28
  */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/device/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/device/index.ts"],"names":[],"mappings":"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"}
@@ -94,11 +94,95 @@ let Device = (() => {
94
94
  timeoutOpts;
95
95
  provider;
96
96
  visualTraceService;
97
- constructor(webDriverClient, bundleId, timeoutOpts, provider) {
97
+ deviceProvider;
98
+ persistentSyncEnabled = false;
99
+ activePersistentKey;
100
+ constructor(webDriverClient, bundleId, timeoutOpts, provider, deviceProvider) {
98
101
  this.webDriverClient = webDriverClient;
99
102
  this.bundleId = bundleId;
100
103
  this.timeoutOpts = timeoutOpts;
101
104
  this.provider = provider;
105
+ this.deviceProvider = deviceProvider;
106
+ }
107
+ attachDeviceProvider(provider) {
108
+ this.deviceProvider = provider;
109
+ }
110
+ enablePersistentStatusSync() {
111
+ this.persistentSyncEnabled = true;
112
+ }
113
+ async ensurePersistentLifecycle(testInfo) {
114
+ if (!this.shouldSyncPersistent()) {
115
+ return;
116
+ }
117
+ await this.preparePersistentTest(testInfo);
118
+ }
119
+ async preparePersistentTest(testInfo) {
120
+ if (!this.shouldSyncPersistent()) {
121
+ return;
122
+ }
123
+ const key = this.persistentKey(testInfo);
124
+ if (this.activePersistentKey === key) {
125
+ return;
126
+ }
127
+ this.activePersistentKey = key;
128
+ await this.safeSync({ name: testInfo.title });
129
+ }
130
+ async finalizePersistentTest(testInfo) {
131
+ if (!this.shouldSyncPersistent()) {
132
+ return;
133
+ }
134
+ const key = this.persistentKey(testInfo);
135
+ if (!this.activePersistentKey) {
136
+ logger_1.logger.warn("finalizePersistentTest called before preparePersistentTest; syncing anyway.");
137
+ }
138
+ else if (this.activePersistentKey !== key) {
139
+ logger_1.logger.warn("finalizePersistentTest received unexpected test key; syncing anyway.");
140
+ }
141
+ const status = this.mapPlaywrightStatus(testInfo.status);
142
+ const reason = status === "failed" ? this.failureReason(testInfo) : undefined;
143
+ await this.safeSync({
144
+ name: testInfo.title,
145
+ status,
146
+ reason,
147
+ });
148
+ this.activePersistentKey = undefined;
149
+ }
150
+ shouldSyncPersistent() {
151
+ return (this.persistentSyncEnabled === true &&
152
+ typeof this.deviceProvider?.syncTestDetails === "function");
153
+ }
154
+ persistentKey(testInfo) {
155
+ return `${testInfo.testId}#${testInfo.retry}`;
156
+ }
157
+ mapPlaywrightStatus(status) {
158
+ switch (status) {
159
+ case "failed":
160
+ case "timedOut":
161
+ case "interrupted":
162
+ return "failed";
163
+ case "passed":
164
+ case "skipped":
165
+ default:
166
+ return "passed";
167
+ }
168
+ }
169
+ failureReason(testInfo) {
170
+ const error = testInfo.errors?.[0];
171
+ if (error?.message) {
172
+ return error.message;
173
+ }
174
+ return testInfo.error?.message;
175
+ }
176
+ async safeSync(details) {
177
+ if (!this.deviceProvider?.syncTestDetails) {
178
+ return;
179
+ }
180
+ try {
181
+ await this.deviceProvider.syncTestDetails(details);
182
+ }
183
+ catch (error) {
184
+ logger_1.logger.warn("Failed to sync test details", error);
185
+ }
102
186
  }
103
187
  /**
104
188
  * Initialize Visual Trace Service for screenshot capture during test execution
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixture/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EAGd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAKnC,KAAK,iBAAiB,GAAG;IACvB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAE/B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,IAAI,uRAyEf,CAAC;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;2BACY,gBAAgB,YAAY,aAAa;;;;;;;EAUtE,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/fixture/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,aAAa,EAMd,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AA2GnC,KAAK,iBAAiB,GAAG;IACvB;;;OAGG;IACH,cAAc,EAAE,cAAc,CAAC;IAE/B;;;;OAIG;IACH,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,KAAK,mBAAmB,GAAG;IACzB,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,eAAO,MAAM,IAAI,uRA6Ff,CAAC;AA8BH;;;;;;;GAOG;AACH,eAAO,MAAM,MAAM;2BACY,gBAAgB,YAAY,aAAa;;;;;;;EAUtE,CAAC"}
@@ -2,9 +2,80 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.expect = exports.test = void 0;
4
4
  const test_1 = require("@playwright/test");
5
+ const types_1 = require("../types");
5
6
  const providers_1 = require("../providers");
6
7
  const workerInfo_1 = require("./workerInfo");
7
8
  const appium_1 = require("../providers/appium");
9
+ const logger_1 = require("../logger");
10
+ const persistentDevicesByWorker = new Map();
11
+ async function applyIosAppSettings(project, device) {
12
+ if (project.use.platform !== types_1.Platform.IOS) {
13
+ return;
14
+ }
15
+ const deviceConfig = project.use.device;
16
+ if (!deviceConfig || deviceConfig.provider !== "browserstack") {
17
+ return;
18
+ }
19
+ const browserStackConfig = deviceConfig;
20
+ const envSettingsJson = process.env.APPWRIGHT_BS_UPDATE_APP_SETTINGS_JSON;
21
+ let settings;
22
+ if (envSettingsJson) {
23
+ try {
24
+ settings = JSON.parse(envSettingsJson);
25
+ }
26
+ catch (error) {
27
+ throw new Error("APPWRIGHT_BS_UPDATE_APP_SETTINGS_JSON is not valid JSON. Provide a valid JSON string.");
28
+ }
29
+ }
30
+ else {
31
+ settings = browserStackConfig.updateAppSettings;
32
+ }
33
+ if (!settings || typeof settings !== "object") {
34
+ return;
35
+ }
36
+ try {
37
+ await device.updateAppSettings(settings);
38
+ const hasPermissions = Object.prototype.hasOwnProperty.call(settings, "Permission Settings");
39
+ const customKeys = Object.keys(settings).filter((key) => key !== "Permission Settings");
40
+ if (hasPermissions || customKeys.length > 0) {
41
+ logger_1.logger.log(`iOS app settings applied before tests: permissions=${hasPermissions}, custom_keys=${customKeys.length}`);
42
+ }
43
+ }
44
+ catch (error) {
45
+ logger_1.logger.warn("Failed to apply iOS app settings in fixture", error);
46
+ }
47
+ }
48
+ function createPersistentContext(device) {
49
+ return {
50
+ device,
51
+ activeOperations: 0,
52
+ };
53
+ }
54
+ async function runWithLifecycle(context, task) {
55
+ context.activeOperations += 1;
56
+ try {
57
+ await task();
58
+ }
59
+ finally {
60
+ context.activeOperations -= 1;
61
+ if (context.activeOperations === 0 && context.resolveIdle) {
62
+ context.resolveIdle();
63
+ context.resolveIdle = undefined;
64
+ context.idlePromise = undefined;
65
+ }
66
+ }
67
+ }
68
+ async function waitForLifecycleToComplete(context) {
69
+ if (context.activeOperations === 0) {
70
+ return;
71
+ }
72
+ if (!context.idlePromise) {
73
+ context.idlePromise = new Promise((resolve) => {
74
+ context.resolveIdle = resolve;
75
+ });
76
+ }
77
+ await context.idlePromise;
78
+ }
8
79
  exports.test = test_1.test.extend({
9
80
  deviceProvider: async ({}, use, testInfo) => {
10
81
  const deviceProvider = (0, providers_1.createDeviceProvider)(testInfo.project);
@@ -24,6 +95,7 @@ exports.test = test_1.test.extend({
24
95
  // Initialize Visual Trace Service for screenshot capture
25
96
  const visualTraceConfig = testInfo.project.use.visualTrace;
26
97
  device.initializeVisualTrace(testInfo, testInfo.retry, visualTraceConfig);
98
+ await applyIosAppSettings(testInfo.project, device);
27
99
  await deviceProvider.syncTestDetails?.({ name: testInfo.title });
28
100
  await use(device);
29
101
  await device.close();
@@ -54,13 +126,52 @@ exports.test = test_1.test.extend({
54
126
  const afterSession = new Date();
55
127
  const workerInfoStore = new workerInfo_1.WorkerInfoStore();
56
128
  await workerInfoStore.saveWorkerStartTime(workerIndex, sessionId, providerName, beforeSession, afterSession);
57
- await use(device);
58
- await workerInfoStore.saveWorkerEndTime(workerIndex, new Date());
59
- await device.close();
129
+ device.attachDeviceProvider(deviceProvider);
130
+ device.enablePersistentStatusSync();
131
+ await applyIosAppSettings(project, device);
132
+ const context = createPersistentContext(device);
133
+ persistentDevicesByWorker.set(workerIndex, context);
134
+ try {
135
+ await use(device);
136
+ }
137
+ finally {
138
+ await waitForLifecycleToComplete(context);
139
+ persistentDevicesByWorker.delete(workerIndex);
140
+ await workerInfoStore.saveWorkerEndTime(workerIndex, new Date());
141
+ await device.close();
142
+ }
60
143
  },
61
144
  { scope: "worker" },
62
145
  ],
63
146
  });
147
+ exports.test.beforeEach(async ({}, testInfo) => {
148
+ const context = persistentDevicesByWorker.get(testInfo.workerIndex);
149
+ if (!context) {
150
+ return;
151
+ }
152
+ await runWithLifecycle(context, async () => {
153
+ try {
154
+ await context.device.preparePersistentTest(testInfo);
155
+ }
156
+ catch (error) {
157
+ logger_1.logger.warn("Failed to prepare persistent test", error);
158
+ }
159
+ });
160
+ });
161
+ exports.test.afterEach(async ({}, testInfo) => {
162
+ const context = persistentDevicesByWorker.get(testInfo.workerIndex);
163
+ if (!context) {
164
+ return;
165
+ }
166
+ await runWithLifecycle(context, async () => {
167
+ try {
168
+ await context.device.finalizePersistentTest(testInfo);
169
+ }
170
+ catch (error) {
171
+ logger_1.logger.warn("Failed to finalize persistent test", error);
172
+ }
173
+ });
174
+ });
64
175
  /**
65
176
  * Function to extend Playwright’s expect assertion capabilities.
66
177
  * This adds a new method `toBeVisible` which checks if an element is visible on the screen.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/browserstack/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAqDtC,qBAAa,0BAA2B,YAAW,cAAc;IAC/D,OAAO,CAAC,cAAc,CAAC,CAA6B;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,OAAO,CAA+B;gBAG5C,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EACrC,WAAW,EAAE,MAAM,GAAG,SAAS;IAU3B,WAAW;IAwDX,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAMlC,OAAO,CAAC,cAAc;YASR,YAAY;YAgBZ,iBAAiB;YAKjB,yBAAyB;WAK1B,aAAa,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAuFlD,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IA2BD,OAAO,CAAC,YAAY;CA2FrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/browserstack/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,eAAe,EACf,cAAc,EAGf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAqDtC,qBAAa,0BAA2B,YAAW,cAAc;IAC/D,OAAO,CAAC,cAAc,CAAC,CAA6B;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,OAAO,CAA+B;gBAG5C,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EACrC,WAAW,EAAE,MAAM,GAAG,SAAS;IAU3B,WAAW;IAwDX,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAMlC,OAAO,CAAC,cAAc;YASR,YAAY;YAiBZ,iBAAiB;YAKjB,yBAAyB;WAK1B,aAAa,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAuFlD,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IA2BD,OAAO,CAAC,YAAY;CAuFrB"}
@@ -110,7 +110,7 @@ class BrowserStackDeviceProvider {
110
110
  const testOptions = {
111
111
  expectTimeout: this.project.use.expectTimeout,
112
112
  };
113
- return new device_1.Device(webDriverClient, bundleId, testOptions, this.project.use.device?.provider);
113
+ return new device_1.Device(webDriverClient, bundleId, testOptions, this.project.use.device?.provider, this);
114
114
  }
115
115
  async getSessionDetails() {
116
116
  const data = await getSessionDetails(this.sessionId);
@@ -273,14 +273,11 @@ class BrowserStackDeviceProvider {
273
273
  updateAppSettings = deviceConfig?.updateAppSettings;
274
274
  }
275
275
  if (updateAppSettings && typeof updateAppSettings === "object") {
276
- // Add to bstack:options as per BrowserStack documentation
277
- bstackOptions.updateAppSettings = updateAppSettings;
278
- // Log for debugging (without exposing sensitive data)
279
- const u = updateAppSettings;
280
- const hasPermissions = !!u["Permission Settings"];
281
- const customKeys = Object.keys(u).filter((k) => k !== "Permission Settings");
276
+ const settings = updateAppSettings;
277
+ const hasPermissions = !!settings["Permission Settings"];
278
+ const customKeys = Object.keys(settings).filter((key) => key !== "Permission Settings");
282
279
  if (hasPermissions || customKeys.length > 0) {
283
- logger_1.logger.log(`iOS app settings configured: permissions=${hasPermissions}, custom_keys=${customKeys.length}`);
280
+ logger_1.logger.log("iOS app settings detected; they will be applied after session start via fixtures.");
284
281
  }
285
282
  }
286
283
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/emulator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI/C,qBAAa,gBAAiB,YAAW,cAAc;IAInD,OAAO,CAAC,OAAO;IAHjB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGT,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EAC7C,WAAW,EAAE,MAAM,GAAG,SAAS;IAS3B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,WAAW;YA8BH,YAAY;YAwBZ,YAAY;CAmC3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/emulator/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAOtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAI/C,qBAAa,gBAAiB,YAAW,cAAc;IAInD,OAAO,CAAC,OAAO;IAHjB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGT,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EAC7C,WAAW,EAAE,MAAM,GAAG,SAAS;IAS3B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,WAAW;YA8BH,YAAY;YAyBZ,YAAY;CAmC3B"}
@@ -49,7 +49,7 @@ Follow the steps mentioned in ${androidSimulatorConfigDocLink} to run test on An
49
49
  const testOptions = {
50
50
  expectTimeout,
51
51
  };
52
- return new device_1.Device(webDriverClient, undefined, testOptions, this.project.use.device?.provider);
52
+ return new device_1.Device(webDriverClient, undefined, testOptions, this.project.use.device?.provider, this);
53
53
  }
54
54
  async createConfig() {
55
55
  const platformName = this.project.use.platform;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/lambdatest/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAoB,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAwDtC,qBAAa,wBAAyB,YAAW,cAAc;IAM3D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,WAAW;IANrB,OAAO,CAAC,cAAc,CAAC,CAA2B;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,WAAW,CAAgC;gBAGzC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EACrC,WAAW,EAAE,MAAM,GAAG,SAAS;IASnC,WAAW;IA8DX,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAMlC,OAAO,CAAC,cAAc;YASR,YAAY;WAeb,aAAa,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA6ElD,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IA0BD,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,YAAY;CA8CrB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/lambdatest/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,eAAe,EAAE,cAAc,EAAoB,MAAM,aAAa,CAAC;AAChF,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAwDtC,qBAAa,wBAAyB,YAAW,cAAc;IAM3D,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,WAAW;IANrB,OAAO,CAAC,cAAc,CAAC,CAA2B;IAClD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,WAAW,CAAgC;gBAGzC,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EACrC,WAAW,EAAE,MAAM,GAAG,SAAS;IASnC,WAAW;IA8DX,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAMlC,OAAO,CAAC,cAAc;YASR,YAAY;WAgBb,aAAa,CACxB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IA6ElD,eAAe,CAAC,OAAO,EAAE;QAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf;IA0BD,OAAO,CAAC,oBAAoB;IAuB5B,OAAO,CAAC,YAAY;CA8CrB"}
@@ -119,7 +119,7 @@ class LambdaTestDeviceProvider {
119
119
  const testOptions = {
120
120
  expectTimeout: this.project.use.expectTimeout,
121
121
  };
122
- return new device_1.Device(webDriverClient, this.appBundleId, testOptions, this.project.use.device?.provider);
122
+ return new device_1.Device(webDriverClient, this.appBundleId, testOptions, this.project.use.device?.provider, this);
123
123
  }
124
124
  static async downloadVideo(sessionId, outputDir, fileName) {
125
125
  const sessionData = await getSessionDetails(sessionId);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAY/C,qBAAa,mBAAoB,YAAW,cAAc;IAItD,OAAO,CAAC,OAAO;IAHjB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGT,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EAC7C,WAAW,EAAE,MAAM,GAAG,SAAS;IAS3B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,WAAW;YAgBH,YAAY;YAyBZ,YAAY;CA6C3B"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/local/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,cAAc,EAIf,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAY/C,qBAAa,mBAAoB,YAAW,cAAc;IAItD,OAAO,CAAC,OAAO;IAHjB,SAAS,CAAC,EAAE,MAAM,CAAC;gBAGT,OAAO,EAAE,WAAW,CAAC,eAAe,CAAC,EAC7C,WAAW,EAAE,MAAM,GAAG,SAAS;IAS3B,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;IAI5B,WAAW;YAgBH,YAAY;YA0BZ,YAAY;CA6C3B"}
@@ -40,7 +40,7 @@ class LocalDeviceProvider {
40
40
  const testOptions = {
41
41
  expectTimeout,
42
42
  };
43
- return new device_1.Device(webDriverClient, bundleId, testOptions, this.project.use.device?.provider);
43
+ return new device_1.Device(webDriverClient, bundleId, testOptions, this.project.use.device?.provider, this);
44
44
  }
45
45
  async createConfig() {
46
46
  const platformName = this.project.use.platform;
@@ -19,6 +19,34 @@ const createDevice = (executeScript = vitest_1.vi.fn()) => {
19
19
  const device = new device_1.Device(webDriverClient, "com.example.app", { expectTimeout: 1_000 }, "emulator");
20
20
  return { device, executeScript };
21
21
  };
22
+ const makeTestInfo = (overrides = {}) => {
23
+ return {
24
+ title: "example test",
25
+ status: "passed",
26
+ errors: [],
27
+ error: undefined,
28
+ testId: "test-id",
29
+ retry: 0,
30
+ workerIndex: 0,
31
+ project: { use: {} },
32
+ ...overrides,
33
+ };
34
+ };
35
+ const createPersistentDevice = () => {
36
+ const { device } = createDevice();
37
+ const syncTestDetails = vitest_1.vi.fn().mockResolvedValue(undefined);
38
+ const provider = {
39
+ getDevice: vitest_1.vi.fn(),
40
+ syncTestDetails,
41
+ };
42
+ device.attachDeviceProvider(provider);
43
+ device.enablePersistentStatusSync();
44
+ return {
45
+ device,
46
+ syncTestDetails,
47
+ provider,
48
+ };
49
+ };
22
50
  (0, vitest_1.describe)("Device", () => {
23
51
  (0, vitest_1.describe)("backgroundApp", () => {
24
52
  (0, vitest_1.test)("backgrounds indefinitely by default", async () => {
@@ -113,4 +141,57 @@ const createDevice = (executeScript = vitest_1.vi.fn()) => {
113
141
  });
114
142
  });
115
143
  });
144
+ (0, vitest_1.describe)("persistent sync", () => {
145
+ (0, vitest_1.test)("preparePersistentTest sends name once per test", async () => {
146
+ const { device, syncTestDetails } = createPersistentDevice();
147
+ const info = makeTestInfo({ title: "My test", testId: "t-1" });
148
+ await device.preparePersistentTest(info);
149
+ await device.preparePersistentTest(info);
150
+ (0, vitest_1.expect)(syncTestDetails).toHaveBeenCalledTimes(1);
151
+ (0, vitest_1.expect)(syncTestDetails).toHaveBeenCalledWith({ name: "My test" });
152
+ });
153
+ (0, vitest_1.test)("finalizePersistentTest maps failed status and reason", async () => {
154
+ const { device, syncTestDetails } = createPersistentDevice();
155
+ const info = makeTestInfo({
156
+ title: "fails",
157
+ status: "failed",
158
+ errors: [{ message: "boom" }],
159
+ testId: "t-2",
160
+ });
161
+ await device.finalizePersistentTest(info);
162
+ (0, vitest_1.expect)(syncTestDetails).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
163
+ name: "fails",
164
+ status: "failed",
165
+ reason: "boom",
166
+ }));
167
+ });
168
+ (0, vitest_1.test)("ensurePersistentLifecycle triggers sync for new tests", async () => {
169
+ const { device, syncTestDetails } = createPersistentDevice();
170
+ const first = makeTestInfo({ title: "first", testId: "first", retry: 0 });
171
+ const second = makeTestInfo({
172
+ title: "second",
173
+ testId: "second",
174
+ retry: 0,
175
+ });
176
+ await device.ensurePersistentLifecycle(first);
177
+ await device.ensurePersistentLifecycle(second);
178
+ (0, vitest_1.expect)(syncTestDetails).toHaveBeenNthCalledWith(1, { name: "first" });
179
+ (0, vitest_1.expect)(syncTestDetails).toHaveBeenNthCalledWith(2, { name: "second" });
180
+ });
181
+ (0, vitest_1.test)("finalizePersistentTest defaults skipped to passed without reason", async () => {
182
+ const { device, syncTestDetails } = createPersistentDevice();
183
+ const info = makeTestInfo({
184
+ title: "skipped test",
185
+ status: "skipped",
186
+ testId: "t-3",
187
+ });
188
+ await device.finalizePersistentTest(info);
189
+ (0, vitest_1.expect)(syncTestDetails).toHaveBeenCalledWith(vitest_1.expect.objectContaining({
190
+ name: "skipped test",
191
+ status: "passed",
192
+ }));
193
+ const payload = syncTestDetails.mock.calls[0][0];
194
+ (0, vitest_1.expect)(payload.reason).toBeUndefined();
195
+ });
196
+ });
116
197
  });
package/dist/utils.d.ts CHANGED
@@ -4,9 +4,11 @@ export declare function boxedStep(target: Function, context: ClassMethodDecorato
4
4
  device?: {
5
5
  takeScreenshot: () => Promise<Buffer>;
6
6
  initializeVisualTrace?: (testInfo: any, retryIndex: number, config?: any) => void;
7
+ ensurePersistentLifecycle?: (testInfo: TestInfo) => Promise<void>;
7
8
  };
8
9
  takeScreenshot?: () => Promise<Buffer>;
9
10
  initializeVisualTrace?: (testInfo: any, retryIndex: number, config?: any) => void;
11
+ ensurePersistentLifecycle?: (testInfo: TestInfo) => Promise<void>;
10
12
  }, ...args: any) => Promise<any>;
11
13
  export declare function validateBuildPath(buildPath: string | undefined, expectedExtension: string): void;
12
14
  export declare function getLatestBuildToolsVersions(versions: string[]): string | undefined;
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAQlD,wBAAgB,SAAS,CACvB,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,2BAA2B,UAG5B;IACJ,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE;QACP,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,qBAAqB,CAAC,EAAE,CACtB,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,GAAG,KACT,IAAI,CAAC;KACX,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,qBAAqB,CAAC,EAAE,CACtB,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,GAAG,KACT,IAAI,CAAC;CACX,WACQ,GAAG,kBAwEf;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,iBAAiB,EAAE,MAAM,QAoB1B;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAuB7E;AAED,wBAAgB,QAAQ,WAEvB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CA2BT;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAST"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,OAAa,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAQlD,wBAAgB,SAAS,CACvB,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,2BAA2B,UAG5B;IACJ,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC3B,MAAM,CAAC,EAAE;QACP,cAAc,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;QACtC,qBAAqB,CAAC,EAAE,CACtB,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,GAAG,KACT,IAAI,CAAC;QACV,yBAAyB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;KACnE,CAAC;IACF,cAAc,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACvC,qBAAqB,CAAC,EAAE,CACtB,QAAQ,EAAE,GAAG,EACb,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAE,GAAG,KACT,IAAI,CAAC;IACV,yBAAyB,CAAC,EAAE,CAAC,QAAQ,EAAE,QAAQ,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CACnE,WACQ,GAAG,kBAgFf;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,GAAG,SAAS,EAC7B,iBAAiB,EAAE,MAAM,QAoB1B;AAED,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,MAAM,EAAE,GACjB,MAAM,GAAG,SAAS,CAEpB;AAED,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAuB7E;AAED,wBAAgB,QAAQ,WAEvB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CA2BT;AAED;;GAEG;AACH,wBAAgB,iCAAiC,CAC/C,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAST"}
package/dist/utils.js CHANGED
@@ -43,6 +43,11 @@ function boxedStep(target, context) {
43
43
  try {
44
44
  const testInfo = test_1.default.info();
45
45
  const device = this.device || this;
46
+ if (device &&
47
+ typeof device.ensurePersistentLifecycle === "function" &&
48
+ testInfo) {
49
+ await device.ensurePersistentLifecycle(testInfo);
50
+ }
46
51
  // Initialize or reinitialize if needed
47
52
  if (device?.initializeVisualTrace && testInfo) {
48
53
  const needsInit = (0, visualTrace_1.needsVisualTraceReinitialization)(testInfo.testId, testInfo.retry);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@samsara-dev/appwright",
3
- "version": "0.4.0",
3
+ "version": "0.5.1",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/",
6
6
  "access": "public"