@samsara-dev/appwright 0.2.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 (81) hide show
  1. package/.eslintrc.js +4 -0
  2. package/CHANGELOG.md +538 -0
  3. package/LICENSE +202 -0
  4. package/README.md +183 -0
  5. package/dist/bin/index.d.ts +3 -0
  6. package/dist/bin/index.d.ts.map +1 -0
  7. package/dist/bin/index.js +53 -0
  8. package/dist/config.d.ts +4 -0
  9. package/dist/config.d.ts.map +1 -0
  10. package/dist/config.js +65 -0
  11. package/dist/device/index.d.ts +171 -0
  12. package/dist/device/index.d.ts.map +1 -0
  13. package/dist/device/index.js +415 -0
  14. package/dist/fixture/index.d.ts +38 -0
  15. package/dist/fixture/index.d.ts.map +1 -0
  16. package/dist/fixture/index.js +78 -0
  17. package/dist/fixture/workerInfo.d.ts +27 -0
  18. package/dist/fixture/workerInfo.d.ts.map +1 -0
  19. package/dist/fixture/workerInfo.js +87 -0
  20. package/dist/global-setup.d.ts +5 -0
  21. package/dist/global-setup.d.ts.map +1 -0
  22. package/dist/global-setup.js +30 -0
  23. package/dist/index.d.ts +5 -0
  24. package/dist/index.d.ts.map +1 -0
  25. package/dist/index.js +25 -0
  26. package/dist/locator/index.d.ts +25 -0
  27. package/dist/locator/index.d.ts.map +1 -0
  28. package/dist/locator/index.js +296 -0
  29. package/dist/logger.d.ts +9 -0
  30. package/dist/logger.d.ts.map +1 -0
  31. package/dist/logger.js +19 -0
  32. package/dist/providers/appium.d.ts +15 -0
  33. package/dist/providers/appium.d.ts.map +1 -0
  34. package/dist/providers/appium.js +274 -0
  35. package/dist/providers/browserstack/index.d.ts +26 -0
  36. package/dist/providers/browserstack/index.d.ts.map +1 -0
  37. package/dist/providers/browserstack/index.js +272 -0
  38. package/dist/providers/browserstack/utils.d.ts +2 -0
  39. package/dist/providers/browserstack/utils.d.ts.map +1 -0
  40. package/dist/providers/browserstack/utils.js +34 -0
  41. package/dist/providers/emulator/index.d.ts +13 -0
  42. package/dist/providers/emulator/index.d.ts.map +1 -0
  43. package/dist/providers/emulator/index.js +86 -0
  44. package/dist/providers/index.d.ts +5 -0
  45. package/dist/providers/index.d.ts.map +1 -0
  46. package/dist/providers/index.js +31 -0
  47. package/dist/providers/lambdatest/index.d.ts +27 -0
  48. package/dist/providers/lambdatest/index.d.ts.map +1 -0
  49. package/dist/providers/lambdatest/index.js +280 -0
  50. package/dist/providers/lambdatest/utils.d.ts +3 -0
  51. package/dist/providers/lambdatest/utils.d.ts.map +1 -0
  52. package/dist/providers/lambdatest/utils.js +36 -0
  53. package/dist/providers/local/index.d.ts +13 -0
  54. package/dist/providers/local/index.d.ts.map +1 -0
  55. package/dist/providers/local/index.js +86 -0
  56. package/dist/reporter.d.ts +13 -0
  57. package/dist/reporter.d.ts.map +1 -0
  58. package/dist/reporter.js +216 -0
  59. package/dist/tests/locator.spec.d.ts +2 -0
  60. package/dist/tests/locator.spec.d.ts.map +1 -0
  61. package/dist/tests/locator.spec.js +89 -0
  62. package/dist/tests/regex.spec.d.ts +2 -0
  63. package/dist/tests/regex.spec.d.ts.map +1 -0
  64. package/dist/tests/regex.spec.js +19 -0
  65. package/dist/tests/vitest.config.d.mts +3 -0
  66. package/dist/tests/vitest.config.d.mts.map +1 -0
  67. package/dist/tests/vitest.config.mjs +6 -0
  68. package/dist/types/errors.d.ts +7 -0
  69. package/dist/types/errors.d.ts.map +1 -0
  70. package/dist/types/errors.js +15 -0
  71. package/dist/types/index.d.ts +234 -0
  72. package/dist/types/index.d.ts.map +1 -0
  73. package/dist/types/index.js +22 -0
  74. package/dist/utils.d.ts +8 -0
  75. package/dist/utils.d.ts.map +1 -0
  76. package/dist/utils.js +66 -0
  77. package/dist/vision/index.d.ts +64 -0
  78. package/dist/vision/index.d.ts.map +1 -0
  79. package/dist/vision/index.js +106 -0
  80. package/package.json +63 -0
  81. package/tsconfig.json +15 -0
@@ -0,0 +1,216 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ const providers_1 = require("./providers");
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const fluent_ffmpeg_1 = __importDefault(require("fluent-ffmpeg"));
10
+ const ffmpeg_1 = __importDefault(require("@ffmpeg-installer/ffmpeg"));
11
+ const logger_1 = require("./logger");
12
+ const utils_1 = require("./utils");
13
+ const workerInfo_1 = require("./fixture/workerInfo");
14
+ class VideoDownloader {
15
+ downloadPromises = [];
16
+ onBegin() {
17
+ if (fs_1.default.existsSync((0, utils_1.basePath)())) {
18
+ fs_1.default.rmSync((0, utils_1.basePath)(), {
19
+ recursive: true,
20
+ });
21
+ }
22
+ }
23
+ onTestBegin(test, result) {
24
+ logger_1.logger.log(`Starting test: ${test.title} on worker ${result.workerIndex}`);
25
+ const workerInfoStore = new workerInfo_1.WorkerInfoStore();
26
+ void workerInfoStore.saveTestStartTime(result.workerIndex, test.title, new Date());
27
+ }
28
+ onTestEnd(test, result) {
29
+ logger_1.logger.log(`Ending test: ${test.title} on worker ${result.workerIndex}`);
30
+ const sessionIdAnnotation = test.annotations.find(({ type }) => type === "sessionId");
31
+ const providerNameAnnotation = test.annotations.find(({ type }) => type === "providerName");
32
+ // Check if test ran on `device` or on `persistentDevice`
33
+ const isTestUsingDevice = sessionIdAnnotation && providerNameAnnotation;
34
+ if (isTestUsingDevice) {
35
+ // This is a test that ran with the `device` fixture
36
+ const sessionId = sessionIdAnnotation.description;
37
+ const providerName = providerNameAnnotation.description;
38
+ const provider = (0, providers_1.getProviderClass)(providerName);
39
+ this.downloadAndAttachDeviceVideo(test, result, provider, sessionId);
40
+ const otherAnnotations = test.annotations.filter(({ type }) => type !== "sessionId" && type !== "providerName");
41
+ test.annotations = otherAnnotations;
42
+ }
43
+ else {
44
+ // This is a test that ran on `persistentDevice` fixture
45
+ const { workerIndex, duration } = result;
46
+ if (duration <= 0) {
47
+ // Skipped tests
48
+ return;
49
+ }
50
+ test.annotations.push({
51
+ type: "workerInfo",
52
+ description: `Ran on worker #${workerIndex}.`,
53
+ });
54
+ const expectedVideoPath = path_1.default.join((0, utils_1.basePath)(), `worker-${workerIndex}-video.mp4`);
55
+ // The `onTestEnd` is method is called before the worker ends and
56
+ // the worker's `endTime` is saved to disk. We add a 5 secs delay
57
+ // to prevent a harmful race condition.
58
+ const workerDownload = waitFiveSeconds()
59
+ .then(() => getWorkerInfo(workerIndex))
60
+ .then(async (workerInfo) => {
61
+ if (!workerInfo) {
62
+ throw new Error(`Worker info not found for idx: ${workerIndex}`);
63
+ }
64
+ const { providerName, sessionId, endTime } = workerInfo;
65
+ if (!providerName || !sessionId) {
66
+ throw new Error(`Provider name or session id not found for worker: ${workerIndex}`);
67
+ }
68
+ if (!this.providerSupportsVideo(providerName)) {
69
+ return; // Nothing to do here
70
+ }
71
+ if (endTime) {
72
+ // This is the last test in the worker, so let's download the video
73
+ const provider = (0, providers_1.getProviderClass)(providerName);
74
+ const downloaded = await provider.downloadVideo(sessionId, (0, utils_1.basePath)(), `worker-${workerIndex}-video`);
75
+ if (!downloaded) {
76
+ return;
77
+ }
78
+ return this.trimAndAttachPersistentDeviceVideo(test, result, downloaded.path);
79
+ }
80
+ else {
81
+ // This is an intermediate test in the worker, so let's wait for the
82
+ // video file to be found on disk. Once it is, we trim and attach it.
83
+ await waitFor(() => fs_1.default.existsSync(expectedVideoPath));
84
+ return this.trimAndAttachPersistentDeviceVideo(test, result, expectedVideoPath);
85
+ }
86
+ })
87
+ .catch((e) => {
88
+ logger_1.logger.error("Failed to get worker end time:", e);
89
+ });
90
+ this.downloadPromises.push(workerDownload);
91
+ }
92
+ }
93
+ async onEnd() {
94
+ logger_1.logger.log(`Triggered onEnd`);
95
+ await Promise.allSettled(this.downloadPromises);
96
+ }
97
+ async trimAndAttachPersistentDeviceVideo(test, result, workerVideoPath) {
98
+ const workerIdx = result.workerIndex;
99
+ const workerStart = await getWorkerStartTime(workerIdx);
100
+ let pathToAttach = workerVideoPath;
101
+ const testStart = result.startTime;
102
+ if (testStart.getTime() < workerStart.getTime()) {
103
+ // This is the first test for the worker
104
+ // The startTime for the first test in the worker tends to be
105
+ // before worker (session) start time. This would have been manageable
106
+ // if the `duration` included the worker setup time, but the duration only
107
+ // covers the test method execution time.
108
+ // So in this case, we are not going to trim.
109
+ // TODO: We can use the startTime of the second test in the worker
110
+ pathToAttach = workerVideoPath;
111
+ }
112
+ else {
113
+ const trimSkipPoint = (testStart.getTime() - workerStart.getTime()) / 1000;
114
+ const trimmedFileName = `worker-${workerIdx}-trimmed-${test.id}.mp4`;
115
+ try {
116
+ pathToAttach = await trimVideo({
117
+ originalVideoPath: workerVideoPath,
118
+ startSecs: trimSkipPoint,
119
+ durationSecs: result.duration / 1000,
120
+ outputPath: trimmedFileName,
121
+ });
122
+ }
123
+ catch (e) {
124
+ logger_1.logger.error("Failed to trim video:", e);
125
+ test.annotations.push({
126
+ type: "videoError",
127
+ description: `Unable to trim video, attaching full video instead. Test starts at ${trimSkipPoint} secs.`,
128
+ });
129
+ }
130
+ }
131
+ result.attachments.push({
132
+ path: pathToAttach,
133
+ contentType: "video/mp4",
134
+ name: "video",
135
+ });
136
+ }
137
+ downloadAndAttachDeviceVideo(test, result, providerClass, sessionId) {
138
+ const videoFileName = `${test.id}`;
139
+ if (!providerClass.downloadVideo) {
140
+ return;
141
+ }
142
+ const downloadPromise = providerClass
143
+ .downloadVideo(sessionId, (0, utils_1.basePath)(), videoFileName)
144
+ .then((downloadedVideo) => {
145
+ if (!downloadedVideo) {
146
+ return;
147
+ }
148
+ result.attachments.push({
149
+ ...downloadedVideo,
150
+ name: "video",
151
+ });
152
+ return downloadedVideo;
153
+ });
154
+ this.downloadPromises.push(downloadPromise);
155
+ }
156
+ providerSupportsVideo(providerName) {
157
+ const provider = (0, providers_1.getProviderClass)(providerName);
158
+ return !!provider.downloadVideo;
159
+ }
160
+ }
161
+ function waitFor(condition, timeout = 60 * 60 * 1000) {
162
+ return new Promise((resolve, reject) => {
163
+ let interval;
164
+ const timeoutId = setTimeout(() => {
165
+ clearInterval(interval);
166
+ reject(new Error("Timed out waiting for condition"));
167
+ }, timeout);
168
+ interval = setInterval(() => {
169
+ if (condition()) {
170
+ clearInterval(interval);
171
+ clearTimeout(timeoutId);
172
+ resolve();
173
+ }
174
+ }, 500);
175
+ });
176
+ }
177
+ function trimVideo({ originalVideoPath, startSecs, durationSecs, outputPath, }) {
178
+ logger_1.logger.log(`Attemping to trim video: ${originalVideoPath} at start: ${startSecs} and duration: ${durationSecs} to ${outputPath}`);
179
+ const copyName = `draft-for-${outputPath}`;
180
+ const dirPath = path_1.default.dirname(originalVideoPath);
181
+ const copyFullPath = path_1.default.join(dirPath, copyName);
182
+ const fullOutputPath = path_1.default.join(dirPath, outputPath);
183
+ fs_1.default.copyFileSync(originalVideoPath, copyFullPath);
184
+ return new Promise((resolve, reject) => {
185
+ let stdErrs = "";
186
+ (0, fluent_ffmpeg_1.default)(copyFullPath)
187
+ .setFfmpegPath(ffmpeg_1.default.path)
188
+ .setStartTime(startSecs)
189
+ .setDuration(durationSecs)
190
+ .output(fullOutputPath)
191
+ .on("end", () => {
192
+ logger_1.logger.log(`Trimmed video saved at: ${fullOutputPath}`);
193
+ fs_1.default.unlinkSync(copyFullPath);
194
+ resolve(fullOutputPath);
195
+ })
196
+ .on("stderr", (stderrLine) => {
197
+ stdErrs += stderrLine + "\n";
198
+ })
199
+ .on("error", (err) => {
200
+ logger_1.logger.error("ffmpeg error:", err);
201
+ logger_1.logger.error("ffmpeg stderr:", stdErrs);
202
+ reject(err);
203
+ })
204
+ .run();
205
+ });
206
+ }
207
+ async function getWorkerStartTime(idx) {
208
+ const workerInfoStore = new workerInfo_1.WorkerInfoStore();
209
+ return workerInfoStore.getWorkerStartTime(idx);
210
+ }
211
+ async function getWorkerInfo(idx) {
212
+ const workerInfoStore = new workerInfo_1.WorkerInfoStore();
213
+ return workerInfoStore.getWorkerFromDisk(idx);
214
+ }
215
+ const waitFiveSeconds = () => new Promise((resolve) => setTimeout(resolve, 5000));
216
+ exports.default = VideoDownloader;
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=locator.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locator.spec.d.ts","sourceRoot":"","sources":["../../src/tests/locator.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const locator_1 = require("../locator");
5
+ const errors_1 = require("../types/errors");
6
+ (0, vitest_1.test)("isVisible on unknown element", async () => {
7
+ const mockFindElements = vitest_1.vi.fn().mockResolvedValue([]);
8
+ //@ts-ignore
9
+ const wdClientMock = {
10
+ findElements: mockFindElements,
11
+ };
12
+ const locator = new locator_1.Locator(wdClientMock, { expectTimeout: 1_000 }, "//unknown-selector", "xpath");
13
+ const isVisible = await locator.isVisible();
14
+ (0, vitest_1.expect)(isVisible).toBe(false);
15
+ (0, vitest_1.expect)(mockFindElements).toHaveBeenCalledTimes(2);
16
+ });
17
+ (0, vitest_1.test)("isVisible on element that is found but fails displayed check", async () => {
18
+ const mockFindElements = vitest_1.vi.fn().mockResolvedValue([
19
+ {
20
+ "element-6066-11e4-a52e-4f735466cecf": "element-id",
21
+ },
22
+ ]);
23
+ const mockIsElementDisplayed = vitest_1.vi.fn().mockResolvedValue(false);
24
+ //@ts-ignore
25
+ const wdClientMock = {
26
+ findElements: mockFindElements,
27
+ isElementDisplayed: mockIsElementDisplayed,
28
+ };
29
+ const locator = new locator_1.Locator(wdClientMock, { expectTimeout: 1_000 }, "//known-but-hidden-element", "xpath");
30
+ const isVisible = await locator.isVisible();
31
+ (0, vitest_1.expect)(isVisible).toBe(false);
32
+ (0, vitest_1.expect)(mockFindElements).toHaveBeenCalledTimes(2);
33
+ (0, vitest_1.expect)(mockIsElementDisplayed).toHaveBeenCalledTimes(2);
34
+ (0, vitest_1.expect)(mockIsElementDisplayed).toHaveBeenCalledWith("element-id");
35
+ });
36
+ (0, vitest_1.test)("isVisible on element that throws stale element reference", async () => {
37
+ const mockFindElements = vitest_1.vi.fn().mockResolvedValue([
38
+ {
39
+ "element-6066-11e4-a52e-4f735466cecf": "element-id",
40
+ },
41
+ ]);
42
+ const mockIsElementDisplayed = vitest_1.vi.fn().mockImplementation(() => {
43
+ class WebDriverInteralError extends Error {
44
+ constructor(name, ...args) {
45
+ super(...args);
46
+ this.name = name;
47
+ }
48
+ }
49
+ throw new WebDriverInteralError(`random stale element reference random`);
50
+ });
51
+ //@ts-ignore
52
+ const wdClientMock = {
53
+ findElements: mockFindElements,
54
+ isElementDisplayed: mockIsElementDisplayed,
55
+ };
56
+ const locator = new locator_1.Locator(wdClientMock, { expectTimeout: 1_000 }, "//known-element-that-keeps-throwing-stale-element-reference", "xpath");
57
+ const isVisible = await locator.isVisible();
58
+ (0, vitest_1.expect)(isVisible).toBe(false);
59
+ (0, vitest_1.expect)(mockFindElements).toHaveBeenCalledTimes(2);
60
+ (0, vitest_1.expect)(mockIsElementDisplayed).toHaveBeenCalledTimes(2);
61
+ (0, vitest_1.expect)(mockIsElementDisplayed).toHaveBeenCalledWith("element-id");
62
+ });
63
+ (0, vitest_1.test)("waitFor attached state works for hidden element", async () => {
64
+ const mockFindElements = vitest_1.vi.fn().mockResolvedValue([
65
+ {
66
+ "element-6066-11e4-a52e-4f735466cecf": "element-id",
67
+ },
68
+ ]);
69
+ const mockIsElementDisplayed = vitest_1.vi.fn().mockResolvedValue(false);
70
+ //@ts-ignore
71
+ const wdClientMock = {
72
+ findElements: mockFindElements,
73
+ isElementDisplayed: mockIsElementDisplayed,
74
+ };
75
+ const locator = new locator_1.Locator(wdClientMock, { expectTimeout: 1_000 }, "//attached-hidden-element", "xpath");
76
+ (0, vitest_1.expect)(await locator.waitFor("attached")).toBe(true);
77
+ (0, vitest_1.expect)(mockFindElements).toHaveBeenCalledTimes(1);
78
+ (0, vitest_1.expect)(mockIsElementDisplayed).toHaveBeenCalledTimes(0);
79
+ });
80
+ (0, vitest_1.test)("waitFor attached state throws TimeoutError", async () => {
81
+ const mockFindElements = vitest_1.vi.fn().mockResolvedValue([]);
82
+ //@ts-ignore
83
+ const wdClientMock = {
84
+ findElements: mockFindElements,
85
+ };
86
+ const locator = new locator_1.Locator(wdClientMock, { expectTimeout: 1_000 }, "//attached-hidden-element", "xpath");
87
+ await (0, vitest_1.expect)(locator.waitFor("attached")).rejects.toThrowError(errors_1.TimeoutError);
88
+ (0, vitest_1.expect)(mockFindElements).toHaveBeenCalledTimes(2);
89
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=regex.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"regex.spec.d.ts","sourceRoot":"","sources":["../../src/tests/regex.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const vitest_1 = require("vitest");
4
+ const utils_1 = require("../utils");
5
+ (0, vitest_1.test)("longest deterministic group with one group", () => {
6
+ const pattern = /.*(Copy to clipboard)$/;
7
+ const substring = (0, utils_1.longestDeterministicGroup)(pattern);
8
+ (0, vitest_1.expect)(substring).toBe("Copy to clipboard");
9
+ });
10
+ (0, vitest_1.test)("longest deterministic group with no groups", () => {
11
+ const pattern = /.*Copy to clipboard$/;
12
+ const substring = (0, utils_1.longestDeterministicGroup)(pattern);
13
+ (0, vitest_1.expect)(substring).toBe(undefined);
14
+ });
15
+ (0, vitest_1.test)("longest deterministic group with group that has special chars", () => {
16
+ const pattern = /.*(Copy .* to clipboard)$/;
17
+ const substring = (0, utils_1.longestDeterministicGroup)(pattern);
18
+ (0, vitest_1.expect)(substring).toBe(undefined);
19
+ });
@@ -0,0 +1,3 @@
1
+ declare const _default: import("vite").UserConfig;
2
+ export default _default;
3
+ //# sourceMappingURL=vitest.config.d.mts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vitest.config.d.mts","sourceRoot":"","sources":["../../src/tests/vitest.config.mts"],"names":[],"mappings":";AAEA,wBAIG"}
@@ -0,0 +1,6 @@
1
+ import { defineConfig } from "vitest/config";
2
+ export default defineConfig({
3
+ test: {
4
+ exclude: ["example/**", "node_modules/**", "dist/**"],
5
+ },
6
+ });
@@ -0,0 +1,7 @@
1
+ export declare class RetryableError extends Error {
2
+ constructor(message: string);
3
+ }
4
+ export declare class TimeoutError extends Error {
5
+ constructor(message: string);
6
+ }
7
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../src/types/errors.ts"],"names":[],"mappings":"AAAA,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAG5B;AAED,qBAAa,YAAa,SAAQ,KAAK;gBACzB,OAAO,EAAE,MAAM;CAG5B"}
@@ -0,0 +1,15 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TimeoutError = exports.RetryableError = void 0;
4
+ class RetryableError extends Error {
5
+ constructor(message) {
6
+ super(message);
7
+ }
8
+ }
9
+ exports.RetryableError = RetryableError;
10
+ class TimeoutError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ }
14
+ }
15
+ exports.TimeoutError = TimeoutError;
@@ -0,0 +1,234 @@
1
+ import { Device } from "../device";
2
+ import { z } from "zod";
3
+ export type ExtractType<T> = T extends z.ZodType ? z.infer<T> : never;
4
+ export type ActionOptions = {
5
+ timeout: number;
6
+ };
7
+ export type TimeoutOptions = {
8
+ /**
9
+ * The maximum amount of time (in milliseconds) to wait for the condition to be met.
10
+ */
11
+ expectTimeout: number;
12
+ };
13
+ export interface DeviceProvider {
14
+ /**
15
+ * Identifier for the Appium session. Can be undefined if the session was not created.
16
+ */
17
+ sessionId?: string;
18
+ /**
19
+ * Global setup validates the configuration.
20
+ */
21
+ globalSetup?(): Promise<void>;
22
+ /**
23
+ * Returns a device instance.
24
+ */
25
+ getDevice(): Promise<Device>;
26
+ /**
27
+ * Updates test details and test status.
28
+ *
29
+ * @param status of the test
30
+ * @param reason for the test status
31
+ * @param name of the test
32
+ */
33
+ syncTestDetails?: (details: {
34
+ status?: string;
35
+ reason?: string;
36
+ name?: string;
37
+ }) => Promise<void>;
38
+ }
39
+ export type AppwrightConfig = {
40
+ platform: Platform;
41
+ device: DeviceConfig;
42
+ buildPath: string;
43
+ appBundleId: string;
44
+ expectTimeout: number;
45
+ };
46
+ export type DeviceConfig = BrowserStackConfig | LambdaTestConfig | LocalDeviceConfig | EmulatorConfig;
47
+ /**
48
+ * Configuration for devices running on Browserstack.
49
+ */
50
+ export type BrowserStackConfig = {
51
+ provider: "browserstack";
52
+ /**
53
+ * The name of the device to be used on Browserstack.
54
+ * Checkout the list of devices supported by BrowserStack: https://www.browserstack.com/list-of-browsers-and-platforms/app_automate
55
+ * Example: "iPhone 15 Pro Max", "Samsung Galaxy S23 Ultra".
56
+ */
57
+ name: string;
58
+ /**
59
+ * The operating system version of the device to be used on Browserstack.
60
+ * Checkout the list of OS versions supported by BrowserStack: https://www.browserstack.com/list-of-browsers-and-platforms/app_automate
61
+ * Example: "14.0", "15.0".
62
+ */
63
+ osVersion: string;
64
+ /**
65
+ * The orientation of the device on Browserstack.
66
+ * Default orientation is "portrait".
67
+ */
68
+ orientation?: DeviceOrientation;
69
+ /**
70
+ * Whether to enable camera injection on the device.
71
+ * Default is false.
72
+ */
73
+ enableCameraImageInjection?: boolean;
74
+ /**
75
+ * Appium server version to request on BrowserStack.
76
+ * Defaults to Appium 3.1.0. Override if your account requires a different version.
77
+ */
78
+ appiumVersion?: string;
79
+ };
80
+ export type LambdaTestConfig = {
81
+ provider: "lambdatest";
82
+ /**
83
+ * The name of the device to be used on LambdaTest.
84
+ * Checkout the list of devices supported by LambdaTest: https://www.lambdatest.com/list-of-real-devices
85
+ * Example: "iPhone 15 Pro Max", "Galaxy S23 Ultra".
86
+ */
87
+ name: string;
88
+ /**
89
+ * The operating system version of the device to be used on LambdaTest.
90
+ * Checkout the list of OS versions supported by LambdaTest: https://www.lambdatest.com/list-of-real-devices
91
+ * Example: "14.0", "15.0".
92
+ */
93
+ osVersion: string;
94
+ /**
95
+ * The orientation of the device on LambdaTest.
96
+ * Default orientation is "portrait".
97
+ */
98
+ orientation?: DeviceOrientation;
99
+ /**
100
+ * Whether to enable camera injection on the device.
101
+ * Default is false.
102
+ */
103
+ enableCameraImageInjection?: boolean;
104
+ /**
105
+ * Appium server version to request on LambdaTest.
106
+ * Defaults to Appium 3.1.0. Override if your account requires a different version.
107
+ */
108
+ appiumVersion?: string;
109
+ };
110
+ /**
111
+ * Configuration for locally connected physical devices.
112
+ */
113
+ export type LocalDeviceConfig = {
114
+ provider: "local-device";
115
+ name?: string;
116
+ /**
117
+ * The unique device identifier (UDID) of the connected local device.
118
+ */
119
+ udid?: string;
120
+ /**
121
+ * The orientation of the device.
122
+ * Default orientation is "portrait".
123
+ */
124
+ orientation?: DeviceOrientation;
125
+ };
126
+ /**
127
+ * Configuration for running tests on an Android or iOS emulator.
128
+ */
129
+ export type EmulatorConfig = {
130
+ provider: "emulator";
131
+ name?: string;
132
+ osVersion?: string;
133
+ /**
134
+ * The unique device identifier (UDID) of the emulator.
135
+ */
136
+ udid?: string;
137
+ /**
138
+ * The orientation of the emulator.
139
+ * Default orientation is "portrait".
140
+ */
141
+ orientation?: DeviceOrientation;
142
+ };
143
+ export declare enum Platform {
144
+ ANDROID = "android",
145
+ IOS = "ios"
146
+ }
147
+ export declare enum DeviceOrientation {
148
+ PORTRAIT = "portrait",
149
+ LANDSCAPE = "landscape"
150
+ }
151
+ export declare enum ScrollDirection {
152
+ UP = "up",
153
+ DOWN = "down"
154
+ }
155
+ export interface AppwrightLocator {
156
+ /**
157
+ * Taps (clicks) on the element. This method waits for the element to be visible before clicking it.
158
+ *
159
+ * **Usage:**
160
+ * ```js
161
+ * await device.getByText("Submit").tap();
162
+ * ```
163
+ *
164
+ * @param options Use this to override the timeout for this action
165
+ */
166
+ tap(options?: ActionOptions): Promise<void>;
167
+ /**
168
+ * Fills the input element with the given value. This method waits for the element to be visible before filling it.
169
+ *
170
+ * **Usage:**
171
+ * ```js
172
+ * await device.getByText("Search").fill("My query");
173
+ * ```
174
+ *
175
+ * @param value The value to fill in the input field
176
+ * @param options Use this to override the timeout for this action
177
+ */
178
+ fill(value: string, options?: ActionOptions): Promise<void>;
179
+ /**
180
+ * Sends key strokes to the element. This method waits for the element to be visible before sending the key strokes.
181
+ *
182
+ * **Usage:**
183
+ * ```js
184
+ * await device.getByText("Search").sendKeyStrokes("My query");
185
+ * ```
186
+ *
187
+ * @param value The string to send as key strokes.
188
+ * @param options Use this to override the timeout for this action
189
+ */
190
+ sendKeyStrokes(value: string, options?: ActionOptions): Promise<void>;
191
+ /**
192
+ * Wait for the element to be visible or attached, while attempting for the `timeout` duration.
193
+ * Throws TimeoutError if element is not found within the timeout.
194
+ *
195
+ * **Usage:**
196
+ * ```js
197
+ * await device.getByText("Search").waitFor({ state: "visible" });
198
+ * ```
199
+ *
200
+ * @param state The state to wait for
201
+ * @param options Use this to override the timeout for this action
202
+ */
203
+ waitFor(state: "attached" | "visible", options?: ActionOptions): Promise<void>;
204
+ /**
205
+ * Waits for the element to be visible, while attempting for the `timeout` duration.
206
+ * Returns boolean based on the visibility of the element.
207
+ *
208
+ * **Usage:**
209
+ * ```js
210
+ * const isVisible = await device.getByText("Search").isVisible();
211
+ * ```
212
+ *
213
+ * @param options Use this to override the timeout for this action
214
+ */
215
+ isVisible(options?: ActionOptions): Promise<boolean>;
216
+ /**
217
+ * Returns the text content of the element. This method waits for the element to be visible before getting the text.
218
+ *
219
+ * **Usage:**
220
+ * ```js
221
+ * const textContent = await device.getByText("Search").getText();
222
+ * ```
223
+ *
224
+ * @param options Use this to override the timeout for this action
225
+ */
226
+ getText(options?: ActionOptions): Promise<string>;
227
+ scroll(direction: ScrollDirection): Promise<void>;
228
+ }
229
+ export declare enum WebDriverErrors {
230
+ StaleElementReferenceError = "stale element reference"
231
+ }
232
+ export type ElementReference = Record<ElementReferenceId, string>;
233
+ export type ElementReferenceId = "element-6066-11e4-a52e-4f735466cecf";
234
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WebDriverErrors = exports.ScrollDirection = exports.DeviceOrientation = exports.Platform = void 0;
4
+ var Platform;
5
+ (function (Platform) {
6
+ Platform["ANDROID"] = "android";
7
+ Platform["IOS"] = "ios";
8
+ })(Platform || (exports.Platform = Platform = {}));
9
+ var DeviceOrientation;
10
+ (function (DeviceOrientation) {
11
+ DeviceOrientation["PORTRAIT"] = "portrait";
12
+ DeviceOrientation["LANDSCAPE"] = "landscape";
13
+ })(DeviceOrientation || (exports.DeviceOrientation = DeviceOrientation = {}));
14
+ var ScrollDirection;
15
+ (function (ScrollDirection) {
16
+ ScrollDirection["UP"] = "up";
17
+ ScrollDirection["DOWN"] = "down";
18
+ })(ScrollDirection || (exports.ScrollDirection = ScrollDirection = {}));
19
+ var WebDriverErrors;
20
+ (function (WebDriverErrors) {
21
+ WebDriverErrors["StaleElementReferenceError"] = "stale element reference";
22
+ })(WebDriverErrors || (exports.WebDriverErrors = WebDriverErrors = {}));
@@ -0,0 +1,8 @@
1
+ export declare function boxedStep(target: Function, context: ClassMethodDecoratorContext): (this: {
2
+ selector: string | RegExp;
3
+ }, ...args: any) => Promise<any>;
4
+ export declare function validateBuildPath(buildPath: string | undefined, expectedExtension: string): void;
5
+ export declare function getLatestBuildToolsVersions(versions: string[]): string | undefined;
6
+ export declare function longestDeterministicGroup(pattern: RegExp): string | undefined;
7
+ export declare function basePath(): string;
8
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAIA,wBAAgB,SAAS,CACvB,MAAM,EAAE,QAAQ,EAChB,OAAO,EAAE,2BAA2B,UAG5B;IACJ,QAAQ,EAAE,MAAM,GAAG,MAAM,CAAC;CAC3B,WACQ,GAAG,kBAmBf;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"}