@taqwright/taqwright 0.0.24

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 (132) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +108 -0
  3. package/dist/auto-appium.d.ts +12 -0
  4. package/dist/auto-appium.js +77 -0
  5. package/dist/bin/branding.d.ts +6 -0
  6. package/dist/bin/branding.js +22 -0
  7. package/dist/bin/index.d.ts +2 -0
  8. package/dist/bin/index.js +321 -0
  9. package/dist/bin/init.d.ts +26 -0
  10. package/dist/bin/init.js +902 -0
  11. package/dist/bin/inspect.d.ts +9 -0
  12. package/dist/bin/inspect.js +91 -0
  13. package/dist/bin/report-branding.d.ts +2 -0
  14. package/dist/bin/report-branding.js +42 -0
  15. package/dist/branding-assets.d.ts +1 -0
  16. package/dist/branding-assets.js +1 -0
  17. package/dist/capabilities-helpers.d.ts +7 -0
  18. package/dist/capabilities-helpers.js +14 -0
  19. package/dist/capabilities.d.ts +6 -0
  20. package/dist/capabilities.js +86 -0
  21. package/dist/config.d.ts +17 -0
  22. package/dist/config.js +235 -0
  23. package/dist/discovery-setup.d.ts +1 -0
  24. package/dist/discovery-setup.js +61 -0
  25. package/dist/discovery.d.ts +17 -0
  26. package/dist/discovery.js +55 -0
  27. package/dist/docs/configuration.html +376 -0
  28. package/dist/docs/custom-reporters.html +265 -0
  29. package/dist/docs/docker.html +339 -0
  30. package/dist/docs/docs.js +173 -0
  31. package/dist/docs/generating-tests.html +161 -0
  32. package/dist/docs/images/taqwright-html-report.png +0 -0
  33. package/dist/docs/index.html +13 -0
  34. package/dist/docs/installation.html +686 -0
  35. package/dist/docs/parallel.html +271 -0
  36. package/dist/docs/running-tests.html +385 -0
  37. package/dist/docs/styles.css +460 -0
  38. package/dist/docs/writing-tests.html +565 -0
  39. package/dist/doctor.d.ts +33 -0
  40. package/dist/doctor.js +508 -0
  41. package/dist/expect.d.ts +38 -0
  42. package/dist/expect.js +96 -0
  43. package/dist/fixture/artifact-mode.d.ts +2 -0
  44. package/dist/fixture/artifact-mode.js +7 -0
  45. package/dist/fixture/index.d.ts +15 -0
  46. package/dist/fixture/index.js +324 -0
  47. package/dist/images/taqwright-html-report.png +0 -0
  48. package/dist/images/taqwright_favicon.png +0 -0
  49. package/dist/images/taqwright_logo.png +0 -0
  50. package/dist/index.d.ts +9 -0
  51. package/dist/index.js +7 -0
  52. package/dist/inspector/codegen-appium.d.ts +3 -0
  53. package/dist/inspector/codegen-appium.js +228 -0
  54. package/dist/inspector/devices.d.ts +41 -0
  55. package/dist/inspector/devices.js +422 -0
  56. package/dist/inspector/locator-suggester.d.ts +23 -0
  57. package/dist/inspector/locator-suggester.js +539 -0
  58. package/dist/inspector/recorder.d.ts +128 -0
  59. package/dist/inspector/recorder.js +162 -0
  60. package/dist/inspector/server.d.ts +39 -0
  61. package/dist/inspector/server.js +1210 -0
  62. package/dist/inspector/session.d.ts +84 -0
  63. package/dist/inspector/session.js +262 -0
  64. package/dist/inspector/ui.d.ts +1 -0
  65. package/dist/inspector/ui.js +5508 -0
  66. package/dist/keys.d.ts +3 -0
  67. package/dist/keys.js +28 -0
  68. package/dist/locator/index.d.ts +206 -0
  69. package/dist/locator/index.js +1506 -0
  70. package/dist/logger.d.ts +5 -0
  71. package/dist/logger.js +5 -0
  72. package/dist/mobile/index.d.ts +130 -0
  73. package/dist/mobile/index.js +762 -0
  74. package/dist/network/android.d.ts +5 -0
  75. package/dist/network/android.js +87 -0
  76. package/dist/network/ca.d.ts +10 -0
  77. package/dist/network/ca.js +136 -0
  78. package/dist/network/har.d.ts +90 -0
  79. package/dist/network/har.js +101 -0
  80. package/dist/network/host-proxy.d.ts +16 -0
  81. package/dist/network/host-proxy.js +134 -0
  82. package/dist/network/index.d.ts +26 -0
  83. package/dist/network/index.js +105 -0
  84. package/dist/network/ios-sim.d.ts +3 -0
  85. package/dist/network/ios-sim.js +29 -0
  86. package/dist/network/proxy.d.ts +13 -0
  87. package/dist/network/proxy.js +310 -0
  88. package/dist/providers/appium.d.ts +23 -0
  89. package/dist/providers/appium.js +288 -0
  90. package/dist/providers/browserstack/index.d.ts +5 -0
  91. package/dist/providers/browserstack/index.js +77 -0
  92. package/dist/providers/browserstack/utils.d.ts +1 -0
  93. package/dist/providers/browserstack/utils.js +6 -0
  94. package/dist/providers/cloud.d.ts +53 -0
  95. package/dist/providers/cloud.js +117 -0
  96. package/dist/providers/emulator/index.d.ts +8 -0
  97. package/dist/providers/emulator/index.js +47 -0
  98. package/dist/providers/index.d.ts +10 -0
  99. package/dist/providers/index.js +33 -0
  100. package/dist/providers/lambdatest/index.d.ts +28 -0
  101. package/dist/providers/lambdatest/index.js +99 -0
  102. package/dist/providers/lambdatest/utils.d.ts +1 -0
  103. package/dist/providers/lambdatest/utils.js +6 -0
  104. package/dist/providers/local/index.d.ts +9 -0
  105. package/dist/providers/local/index.js +53 -0
  106. package/dist/providers/local-session.d.ts +16 -0
  107. package/dist/providers/local-session.js +55 -0
  108. package/dist/setup/archive.d.ts +2 -0
  109. package/dist/setup/archive.js +43 -0
  110. package/dist/setup/avd.d.ts +12 -0
  111. package/dist/setup/avd.js +103 -0
  112. package/dist/setup/index.d.ts +6 -0
  113. package/dist/setup/index.js +55 -0
  114. package/dist/setup/install-android.d.ts +2 -0
  115. package/dist/setup/install-android.js +70 -0
  116. package/dist/setup/install-appium.d.ts +1 -0
  117. package/dist/setup/install-appium.js +64 -0
  118. package/dist/setup/install-jdk.d.ts +1 -0
  119. package/dist/setup/install-jdk.js +58 -0
  120. package/dist/setup/paths.d.ts +16 -0
  121. package/dist/setup/paths.js +88 -0
  122. package/dist/setup/spawn-tool.d.ts +3 -0
  123. package/dist/setup/spawn-tool.js +11 -0
  124. package/dist/tracer/index.d.ts +34 -0
  125. package/dist/tracer/index.js +687 -0
  126. package/dist/tracer/proxy.d.ts +3 -0
  127. package/dist/tracer/proxy.js +60 -0
  128. package/dist/types/index.d.ts +189 -0
  129. package/dist/types/index.js +6 -0
  130. package/dist/utils.d.ts +2 -0
  131. package/dist/utils.js +37 -0
  132. package/package.json +79 -0
@@ -0,0 +1,84 @@
1
+ import type { ChildProcess } from 'node:child_process';
2
+ import type { Client as WebDriverClient } from 'webdriver';
3
+ import { Platform, type DeviceProvider, type DeviceOrientation } from '../types/index.js';
4
+ import { Recorder, type RecordedAction } from './recorder.js';
5
+ export declare function applyLocalCapabilityDefaults(capabilities: Record<string, unknown>, platformName: string): void;
6
+ export interface AppiumOpts {
7
+ host: string;
8
+ port: number;
9
+ path: string;
10
+ protocol?: 'http' | 'https';
11
+ user?: string;
12
+ key?: string;
13
+ }
14
+ export interface InspectorDefaults {
15
+ project?: string;
16
+ appium: AppiumOpts;
17
+ capabilities: Record<string, unknown>;
18
+ projectRoot?: string;
19
+ testDir?: string;
20
+ recordOnConnect?: boolean;
21
+ }
22
+ export interface CloudConnectRequest {
23
+ provider: 'browserstack' | 'lambdatest';
24
+ user: string;
25
+ key: string;
26
+ platform: 'android' | 'ios';
27
+ deviceName: string;
28
+ osVersion: string;
29
+ orientation?: DeviceOrientation;
30
+ appUrl: string;
31
+ appBundleId?: string;
32
+ capabilities?: Record<string, unknown>;
33
+ projectName?: string;
34
+ }
35
+ export interface ConnectRequest {
36
+ appium?: AppiumOpts;
37
+ capabilities?: Record<string, unknown>;
38
+ cloud?: CloudConnectRequest;
39
+ }
40
+ export declare class InspectorSession {
41
+ readonly defaults: InspectorDefaults;
42
+ driver: WebDriverClient | undefined;
43
+ platform: Platform | undefined;
44
+ appiumProc: ChildProcess | undefined;
45
+ appium: AppiumOpts | undefined;
46
+ lastCapabilities: Record<string, unknown> | undefined;
47
+ activeProvider: DeviceProvider | null;
48
+ readonly recorder: Recorder;
49
+ recording: boolean;
50
+ currentContext: string;
51
+ private aborting;
52
+ private deviceQueue;
53
+ suggestGen: number;
54
+ runExclusive<T>(fn: () => Promise<T>): Promise<T>;
55
+ attached: boolean;
56
+ private resumeResolver;
57
+ private _resumeRequested;
58
+ get resumeRequested(): Promise<void>;
59
+ requestResume(): void;
60
+ recordIf(action: RecordedAction): void;
61
+ listContexts(): Promise<{
62
+ contexts: string[];
63
+ current: string;
64
+ }>;
65
+ switchContext(name: string): Promise<void>;
66
+ constructor(defaults: InspectorDefaults);
67
+ isConnected(): boolean;
68
+ attachDriver(driver: WebDriverClient, platform: Platform, capabilities?: Record<string, unknown>): void;
69
+ ensureAppium(opts: AppiumOpts): Promise<{
70
+ started: boolean;
71
+ alreadyRunning: boolean;
72
+ }>;
73
+ restartAppium(opts: AppiumOpts): Promise<{
74
+ started: boolean;
75
+ alreadyRunning: boolean;
76
+ }>;
77
+ connect(req: ConnectRequest): Promise<void>;
78
+ private connectLocal;
79
+ private connectCloud;
80
+ private abortIfCancelled;
81
+ cancelConnect(): void;
82
+ disconnect(): Promise<void>;
83
+ cleanup(): Promise<void>;
84
+ }
@@ -0,0 +1,262 @@
1
+ import WebDriver from 'webdriver';
2
+ import { Platform, } from '../types/index.js';
3
+ import { isPortOpen } from '../auto-appium.js';
4
+ import { omitLocalEmulatorCaps } from '../capabilities.js';
5
+ import { startAppiumServer, killAppiumOnPort } from '../providers/appium.js';
6
+ import { createDeviceProvider } from '../providers/index.js';
7
+ import { Recorder } from './recorder.js';
8
+ export function applyLocalCapabilityDefaults(capabilities, platformName) {
9
+ if (platformName === 'ios' &&
10
+ !('appium:forceSimulatorSoftwareKeyboardPresence' in capabilities)) {
11
+ capabilities['appium:forceSimulatorSoftwareKeyboardPresence'] = true;
12
+ }
13
+ if (platformName === 'android' && !('appium:chromedriverAutodownload' in capabilities)) {
14
+ capabilities['appium:chromedriverAutodownload'] = true;
15
+ }
16
+ if (platformName === 'android' && !('appium:nativeWebScreenshot' in capabilities)) {
17
+ capabilities['appium:nativeWebScreenshot'] = true;
18
+ }
19
+ }
20
+ export class InspectorSession {
21
+ defaults;
22
+ driver;
23
+ platform;
24
+ appiumProc;
25
+ appium;
26
+ lastCapabilities;
27
+ activeProvider = null;
28
+ recorder = new Recorder();
29
+ recording = false;
30
+ currentContext = 'NATIVE_APP';
31
+ aborting = false;
32
+ deviceQueue = Promise.resolve();
33
+ suggestGen = 0;
34
+ runExclusive(fn) {
35
+ const run = this.deviceQueue.then(fn, fn);
36
+ this.deviceQueue = run.then(() => { }, () => { });
37
+ return run;
38
+ }
39
+ attached = false;
40
+ resumeResolver = null;
41
+ _resumeRequested = null;
42
+ get resumeRequested() {
43
+ if (!this._resumeRequested) {
44
+ this._resumeRequested = new Promise((resolve) => {
45
+ this.resumeResolver = resolve;
46
+ });
47
+ }
48
+ return this._resumeRequested;
49
+ }
50
+ requestResume() {
51
+ this.resumeResolver?.();
52
+ }
53
+ recordIf(action) {
54
+ if (this.recording)
55
+ this.recorder.push(action);
56
+ }
57
+ async listContexts() {
58
+ if (!this.driver)
59
+ throw new Error('not connected');
60
+ const contexts = (await this.driver.getAppiumContexts());
61
+ try {
62
+ this.currentContext = (await this.driver.getAppiumContext());
63
+ }
64
+ catch {
65
+ }
66
+ return { contexts, current: this.currentContext };
67
+ }
68
+ async switchContext(name) {
69
+ if (!this.driver)
70
+ throw new Error('not connected');
71
+ await this.driver.switchAppiumContext(name);
72
+ this.currentContext = name;
73
+ this.recordIf({ kind: 'switchContext', context: name });
74
+ }
75
+ constructor(defaults) {
76
+ this.defaults = defaults;
77
+ this.appium = { ...defaults.appium };
78
+ }
79
+ isConnected() {
80
+ return !!this.driver;
81
+ }
82
+ attachDriver(driver, platform, capabilities) {
83
+ if (this.driver)
84
+ throw new Error('attachDriver: already connected');
85
+ this.driver = driver;
86
+ this.platform = platform;
87
+ this.lastCapabilities = capabilities ?? {};
88
+ this.activeProvider = null;
89
+ this.attached = true;
90
+ this.currentContext = 'NATIVE_APP';
91
+ }
92
+ async ensureAppium(opts) {
93
+ this.appium = opts;
94
+ if (await isPortOpen(opts.host, opts.port)) {
95
+ return { started: false, alreadyRunning: true };
96
+ }
97
+ if (this.appiumProc && !this.appiumProc.killed) {
98
+ for (let i = 0; i < 60; i++) {
99
+ if (await isPortOpen(opts.host, opts.port)) {
100
+ return { started: true, alreadyRunning: false };
101
+ }
102
+ await sleep(500);
103
+ }
104
+ }
105
+ this.appiumProc = await startAppiumServer('inspector', {
106
+ host: opts.host,
107
+ port: opts.port,
108
+ basePath: opts.path,
109
+ });
110
+ return { started: true, alreadyRunning: false };
111
+ }
112
+ async restartAppium(opts) {
113
+ if (this.isConnected()) {
114
+ await this.disconnect().catch(() => { });
115
+ }
116
+ if (this.appiumProc && !this.appiumProc.killed) {
117
+ this.appiumProc.kill();
118
+ }
119
+ this.appiumProc = undefined;
120
+ await killAppiumOnPort(opts.port);
121
+ for (let i = 0; i < 20; i++) {
122
+ if (!(await isPortOpen(opts.host, opts.port)))
123
+ break;
124
+ await sleep(250);
125
+ }
126
+ return this.ensureAppium(opts);
127
+ }
128
+ async connect(req) {
129
+ if (this.driver) {
130
+ throw new Error('already connected — disconnect first');
131
+ }
132
+ this.aborting = false;
133
+ if (req.cloud) {
134
+ await this.connectCloud(req.cloud);
135
+ }
136
+ else {
137
+ if (!req.appium || !req.capabilities) {
138
+ throw new Error('Local connect requires { appium, capabilities }.');
139
+ }
140
+ await this.connectLocal(req.appium, req.capabilities);
141
+ }
142
+ if (this.defaults.recordOnConnect) {
143
+ this.recorder.clear();
144
+ this.recording = true;
145
+ }
146
+ }
147
+ async connectLocal(appium, capabilities) {
148
+ this.appium = appium;
149
+ const platformName = String(capabilities['platformName'] ?? '').toLowerCase();
150
+ this.platform = platformName === 'ios' ? Platform.IOS : Platform.ANDROID;
151
+ applyLocalCapabilityDefaults(capabilities, platformName);
152
+ this.lastCapabilities = capabilities;
153
+ this.activeProvider = null;
154
+ this.driver = await WebDriver.newSession({
155
+ hostname: appium.host,
156
+ port: appium.port,
157
+ path: appium.path,
158
+ protocol: appium.protocol ?? 'http',
159
+ logLevel: 'warn',
160
+ capabilities,
161
+ });
162
+ this.currentContext = 'NATIVE_APP';
163
+ await this.abortIfCancelled();
164
+ }
165
+ async connectCloud(cloud) {
166
+ if (!cloud.appUrl) {
167
+ throw new Error('Cloud connect requires an app URL (bs://… or lt://…).');
168
+ }
169
+ if (!cloud.user || !cloud.key) {
170
+ throw new Error(`${cloud.provider} username + access key are required.`);
171
+ }
172
+ if (cloud.provider === 'browserstack') {
173
+ process.env.BROWSERSTACK_USERNAME = cloud.user;
174
+ process.env.BROWSERSTACK_ACCESS_KEY = cloud.key;
175
+ }
176
+ else {
177
+ process.env.LAMBDATEST_USERNAME = cloud.user;
178
+ process.env.LAMBDATEST_ACCESS_KEY = cloud.key;
179
+ }
180
+ const platform = cloud.platform === 'ios' ? Platform.IOS : Platform.ANDROID;
181
+ const userCloudCaps = omitLocalEmulatorCaps(cloud.capabilities ?? {});
182
+ const permKeys = cloud.provider === 'browserstack'
183
+ ? ['appium:autoGrantPermissions', 'appium:autoAcceptAlerts']
184
+ : ['autoGrantPermissions', 'autoAcceptAlerts'];
185
+ const codegenPermOff = {};
186
+ for (const k of permKeys) {
187
+ if (!(k in userCloudCaps))
188
+ codegenPermOff[k] = false;
189
+ }
190
+ const use = {
191
+ platform,
192
+ device: {
193
+ provider: cloud.provider,
194
+ name: cloud.deviceName,
195
+ osVersion: cloud.osVersion,
196
+ orientation: cloud.orientation ?? 'portrait',
197
+ },
198
+ buildPath: cloud.appUrl,
199
+ appBundleId: cloud.appBundleId,
200
+ capabilities: { ...codegenPermOff, ...userCloudCaps },
201
+ };
202
+ const provider = createDeviceProvider(use, cloud.projectName ?? 'inspector');
203
+ if (provider.globalSetup)
204
+ await provider.globalSetup();
205
+ const handle = await provider.getDevice();
206
+ this.activeProvider = provider;
207
+ this.driver = handle.driver;
208
+ this.platform = platform;
209
+ this.lastCapabilities = userCloudCaps;
210
+ this.currentContext = 'NATIVE_APP';
211
+ await this.abortIfCancelled();
212
+ }
213
+ async abortIfCancelled() {
214
+ if (!this.aborting)
215
+ return;
216
+ await this.disconnect();
217
+ throw new Error('connect cancelled');
218
+ }
219
+ cancelConnect() {
220
+ this.aborting = true;
221
+ if (this.driver)
222
+ void this.disconnect();
223
+ }
224
+ async disconnect() {
225
+ if (!this.driver)
226
+ return;
227
+ if (this.activeProvider?.syncTestDetails) {
228
+ try {
229
+ await this.activeProvider.syncTestDetails({
230
+ status: 'passed',
231
+ reason: 'taqwright inspector ended',
232
+ });
233
+ }
234
+ catch {
235
+ }
236
+ }
237
+ if (!this.attached) {
238
+ try {
239
+ await this.driver.deleteSession();
240
+ }
241
+ catch {
242
+ }
243
+ }
244
+ this.driver = undefined;
245
+ this.platform = undefined;
246
+ this.lastCapabilities = undefined;
247
+ this.activeProvider = null;
248
+ this.attached = false;
249
+ this.recording = false;
250
+ this.currentContext = 'NATIVE_APP';
251
+ }
252
+ async cleanup() {
253
+ await this.disconnect();
254
+ if (this.appiumProc && !this.appiumProc.killed) {
255
+ this.appiumProc.kill();
256
+ this.appiumProc = undefined;
257
+ }
258
+ }
259
+ }
260
+ function sleep(ms) {
261
+ return new Promise((r) => setTimeout(r, ms));
262
+ }