@intuned/runtime-dev 0.0.1-split.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 (87) hide show
  1. package/.babelrc +21 -0
  2. package/.eslintignore +10 -0
  3. package/.eslintrc.js +39 -0
  4. package/.vite/deps_temp_01af7156/package.json +3 -0
  5. package/.vscode/extensions.json +3 -0
  6. package/.vscode/launch.json +102 -0
  7. package/.vscode/settings.json +12 -0
  8. package/WebTemplate/accessKeyHelpers.ts +28 -0
  9. package/WebTemplate/api.ts +139 -0
  10. package/WebTemplate/app.ts +18 -0
  11. package/WebTemplate/controllers/async.ts +138 -0
  12. package/WebTemplate/controllers/authSessions/check.ts +68 -0
  13. package/WebTemplate/controllers/authSessions/create.ts +128 -0
  14. package/WebTemplate/controllers/authSessions/index.ts +41 -0
  15. package/WebTemplate/controllers/authSessions/killOperation.ts +35 -0
  16. package/WebTemplate/controllers/authSessions/resumeOperation.ts +80 -0
  17. package/WebTemplate/controllers/authSessions/store.ts +14 -0
  18. package/WebTemplate/controllers/controllers.ts +73 -0
  19. package/WebTemplate/controllers/runApi/helpers.ts +220 -0
  20. package/WebTemplate/controllers/runApi/index.ts +68 -0
  21. package/WebTemplate/controllers/runApi/types.ts +13 -0
  22. package/WebTemplate/controllers/traces.ts +151 -0
  23. package/WebTemplate/features.ts +8 -0
  24. package/WebTemplate/headers.ts +6 -0
  25. package/WebTemplate/index.playwright.ts +47 -0
  26. package/WebTemplate/index.vanilla.ts +44 -0
  27. package/WebTemplate/jobs.ts +356 -0
  28. package/WebTemplate/shutdown.ts +64 -0
  29. package/WebTemplate/utils.ts +294 -0
  30. package/bin/intuned-api-run +2 -0
  31. package/bin/intuned-auth-session-check +2 -0
  32. package/bin/intuned-auth-session-create +2 -0
  33. package/bin/intuned-auth-session-load +2 -0
  34. package/bin/intuned-auth-session-refresh +2 -0
  35. package/bin/intuned-browser-save-state +2 -0
  36. package/bin/intuned-browser-start +2 -0
  37. package/bin/intuned-build +2 -0
  38. package/bin/intuned-ts-check +2 -0
  39. package/package.json +133 -0
  40. package/playwright.config.ts +48 -0
  41. package/src/commands/api/run.ts +225 -0
  42. package/src/commands/auth-sessions/load.ts +42 -0
  43. package/src/commands/auth-sessions/run-check.ts +70 -0
  44. package/src/commands/auth-sessions/run-create.ts +124 -0
  45. package/src/commands/browser/save-state.ts +22 -0
  46. package/src/commands/browser/start-browser.ts +17 -0
  47. package/src/commands/build.ts +125 -0
  48. package/src/commands/common/browserUtils.ts +80 -0
  49. package/src/commands/common/getDefaultExportFromFile.ts +13 -0
  50. package/src/commands/common/getFirstLineNumber.test.ts +274 -0
  51. package/src/commands/common/getFirstLineNumber.ts +146 -0
  52. package/src/commands/common/sendMessageToClient.ts +8 -0
  53. package/src/commands/common/utils/fileUtils.ts +25 -0
  54. package/src/commands/common/utils/settings.ts +23 -0
  55. package/src/commands/common/utils/webTemplate.ts +46 -0
  56. package/src/commands/testing/saveVisibleHtml.ts +29 -0
  57. package/src/commands/ts-check.ts +88 -0
  58. package/src/common/Logger/Logger/index.ts +64 -0
  59. package/src/common/Logger/Logger/types.ts +9 -0
  60. package/src/common/Logger/index.ts +64 -0
  61. package/src/common/Logger/types.ts +9 -0
  62. package/src/common/assets/browser_scripts.js +2214 -0
  63. package/src/common/asyncLocalStorage/index.ts +29 -0
  64. package/src/common/cleanEnvironmentVariables.ts +13 -0
  65. package/src/common/constants.ts +1 -0
  66. package/src/common/contextStorageStateHelpers.ts +71 -0
  67. package/src/common/getPlaywrightConstructs.ts +283 -0
  68. package/src/common/jwtTokenManager.ts +111 -0
  69. package/src/common/settingsSchema.ts +16 -0
  70. package/src/common/telemetry.ts +49 -0
  71. package/src/index.ts +14 -0
  72. package/src/runtime/RunError.ts +16 -0
  73. package/src/runtime/downloadDirectory.ts +14 -0
  74. package/src/runtime/enums.d.ts +11 -0
  75. package/src/runtime/enums.ts +11 -0
  76. package/src/runtime/executionHelpers.test.ts +70 -0
  77. package/src/runtime/export.d.ts +202 -0
  78. package/src/runtime/extendPayload.ts +22 -0
  79. package/src/runtime/extendTimeout.ts +32 -0
  80. package/src/runtime/index.ts +8 -0
  81. package/src/runtime/requestMoreInfo.ts +40 -0
  82. package/src/runtime/runInfo.ts +19 -0
  83. package/template.tsconfig.json +14 -0
  84. package/tsconfig.eslint.json +5 -0
  85. package/tsconfig.json +24 -0
  86. package/typedoc.json +49 -0
  87. package/vite.config.ts +17 -0
@@ -0,0 +1,294 @@
1
+ import * as playwright from "@intuned/playwright-core";
2
+ import { Handler, Response } from "@tinyhttp/app";
3
+ import { cleanEnvironmentVariables } from "@intuned/runtime/dist/common/cleanEnvironmentVariables";
4
+ import { AUTH_SESSIONS_FOLDER_NAME } from "@intuned/runtime/dist/common/constants";
5
+ import { Page, BrowserContext } from "@intuned/playwright-core";
6
+ import * as path from "path";
7
+ import { getExecutionContext } from "@intuned/runtime";
8
+ import { setTimeout } from "timers/promises";
9
+
10
+ export class FunctionNotFoundError extends Error {
11
+ functionName: string;
12
+ path: string;
13
+ constructor(functionName: string, path: string) {
14
+ const message = `function ${functionName} not found in ${path}`;
15
+ super(message);
16
+ this.functionName = functionName;
17
+ this.path = path;
18
+ this.name = "FunctionNotFound";
19
+ Object.setPrototypeOf(this, FunctionNotFoundError.prototype);
20
+ }
21
+ }
22
+
23
+ export async function callFunction(
24
+ folderName: string,
25
+ functionName: string,
26
+ args: any[]
27
+ ) {
28
+ // cleanup environment variables before running the user code
29
+ cleanEnvironmentVariables();
30
+
31
+ const path = `./${folderName}/${functionName}.ts`;
32
+
33
+ const functionNameParts = functionName.split("/");
34
+ const functionNameDepth = functionNameParts.length;
35
+
36
+ // string literals should be inline
37
+ // currently we support only 5 levels of depth
38
+ // rollup dynamic import does not support multiple levels of dynamic imports so we need to specify the possible paths explicitly
39
+ try {
40
+ let imported: any = undefined;
41
+ switch (functionNameDepth) {
42
+ case 1:
43
+ imported = await import(`./${folderName}/${functionNameParts[0]}.ts`);
44
+ break;
45
+ case 2:
46
+ imported = await import(
47
+ `./${folderName}/${functionNameParts[0]}/${functionNameParts[1]}.ts`
48
+ );
49
+ break;
50
+ case 3:
51
+ imported = await import(
52
+ `./${folderName}/${functionNameParts[0]}/${functionNameParts[1]}/${functionNameParts[2]}.ts`
53
+ );
54
+ break;
55
+ case 4:
56
+ imported = await import(
57
+ `./${folderName}/${functionNameParts[0]}/${functionNameParts[1]}/${functionNameParts[2]}/${functionNameParts[3]}.ts`
58
+ );
59
+ break;
60
+ case 5:
61
+ imported = await import(
62
+ `./${folderName}/${functionNameParts[0]}/${functionNameParts[1]}/${functionNameParts[2]}/${functionNameParts[3]}/${functionNameParts[4]}.ts`
63
+ );
64
+ break;
65
+ default:
66
+ throw new Error(
67
+ "intuned supports maximum 5 levels of depth in the api folder"
68
+ );
69
+ }
70
+ return await imported?.default(...args);
71
+ } catch (error: any) {
72
+ if (error.message.includes("Unknown variable dynamic import")) {
73
+ throw new FunctionNotFoundError(functionName, path);
74
+ }
75
+ throw error;
76
+ }
77
+ }
78
+
79
+ export function getIsRetryableError(error: any) {
80
+ if (error?.message) {
81
+ return error.message.includes("ERR_NETWORK_CHANGED");
82
+ }
83
+ return false;
84
+ }
85
+
86
+ export function getErrorResponse(error: any): {
87
+ status: number;
88
+ body: any;
89
+ } {
90
+ if (error instanceof FunctionNotFoundError) {
91
+ return {
92
+ status: 404,
93
+ body: {
94
+ message: error.message,
95
+ error: error.name,
96
+ },
97
+ };
98
+ }
99
+ if (error instanceof playwright.errors.TimeoutError) {
100
+ return {
101
+ status: 500,
102
+ body: { message: error.message, error: error.name },
103
+ };
104
+ }
105
+ /**
106
+ * here we use error.constructor.name instead of error instanceof RunError
107
+ * this is because the error is thrown by importing the runner from the api code on intuned app
108
+ * the definition of class RunError which is imported from here is different than the class RunError
109
+ * imported from the user.
110
+ */
111
+ if (error.constructor.name === "RunError") {
112
+ return {
113
+ status: 200,
114
+ body: {
115
+ status: error.options.status_code ?? 500,
116
+ message: error.message,
117
+ error: error.options.error_code ?? error.name,
118
+ intunedOptions: error.options,
119
+ },
120
+ };
121
+ }
122
+ return {
123
+ status: 500,
124
+ body: { error: error?.name ?? error, message: error?.message },
125
+ };
126
+ }
127
+
128
+ export function handlePlaywrightExecutionError(error: any, res: Response) {
129
+ const { status, body } = getErrorResponse(error);
130
+ return res.status(status).json(body);
131
+ }
132
+
133
+ type EventTraceEvent = {
134
+ type: "event";
135
+ time: number;
136
+ class: string;
137
+ method: string;
138
+ params: any;
139
+ pageId?: string;
140
+ };
141
+
142
+ type AppHandlerParams = Parameters<Handler>;
143
+
144
+ export function errorRetryMiddleware(handler: Handler) {
145
+ return async (...args: AppHandlerParams) => {
146
+ let attempts = 1;
147
+ const [req, res, next] = args;
148
+ // eslint-disable-next-line no-constant-condition
149
+ while (true) {
150
+ try {
151
+ await handler(req, res, next);
152
+ break;
153
+ } catch (error) {
154
+ console.log(error?.name, error?.message);
155
+ if (!getIsRetryableError(error) || attempts >= 3) {
156
+ return handlePlaywrightExecutionError(error, res);
157
+ }
158
+ attempts++;
159
+ }
160
+ }
161
+ };
162
+ }
163
+
164
+ export async function checkAuthSessionWithRetries(
165
+ page: Page,
166
+ context: BrowserContext,
167
+ retries = 3
168
+ ): Promise<boolean> {
169
+ if (retries === 0) {
170
+ return false;
171
+ }
172
+
173
+ let tryNumber = 0;
174
+
175
+ while (retries > tryNumber) {
176
+ const result: boolean = await callFunction(
177
+ AUTH_SESSIONS_FOLDER_NAME,
178
+ "check" as string,
179
+ [page, context]
180
+ );
181
+ if (result) return true;
182
+
183
+ tryNumber++;
184
+ }
185
+
186
+ return false;
187
+ }
188
+
189
+ export function getTraceFilePath(runId: string, attemptNumber?: string) {
190
+ const fileName = `${runId}${attemptNumber ? `_${attemptNumber}` : ""}`;
191
+ return path.join(process.env.TRACES_DIRECTORY ?? "", `${fileName}.zip`);
192
+ }
193
+
194
+ export interface ProxyConfig {
195
+ username: string;
196
+ server: string;
197
+ password: string;
198
+ }
199
+
200
+ export function proxyToUrl(proxy: ProxyConfig) {
201
+ const url = new URL(proxy.server);
202
+ url.username = proxy.username;
203
+ url.password = proxy.password;
204
+ return url.toString();
205
+ }
206
+
207
+ export function isJobRunMachine() {
208
+ return process.env.JOB_ID && process.env.JOB_RUN_ID;
209
+ }
210
+
211
+ export function isHeadless() {
212
+ return process.env.INTUNED_PLAYWRIGHT_HEADLESS !== "0";
213
+ }
214
+
215
+ export abstract class AsyncRunEndpointController {
216
+ private static activeRequests: Set<string> = new Set();
217
+
218
+ static isRunning(taskToken: string) {
219
+ return this.activeRequests.has(taskToken);
220
+ }
221
+
222
+ static addRequest(taskToken: string) {
223
+ this.activeRequests.add(taskToken);
224
+ }
225
+
226
+ static removeRequest(taskToken: string) {
227
+ this.activeRequests.delete(taskToken);
228
+ }
229
+
230
+ static get activeRequestsCount() {
231
+ return this.activeRequests.size;
232
+ }
233
+ }
234
+
235
+ export async function waitWithExtendableTimeout<T>({
236
+ initialTimeout,
237
+ promise,
238
+ abortController,
239
+ }: {
240
+ initialTimeout: number;
241
+ promise: Promise<T>;
242
+ abortController?: AbortController;
243
+ }): Promise<
244
+ | {
245
+ timedOut: true;
246
+ }
247
+ | {
248
+ timedOut: false;
249
+ result: T;
250
+ }
251
+ > {
252
+ const context = getExecutionContext()!;
253
+ if (context.timeoutInfo) {
254
+ context.timeoutInfo.timeoutTimestamp = Date.now() + initialTimeout;
255
+ }
256
+ const timerSymbol = Symbol("timer");
257
+ if (!context) {
258
+ const result = await Promise.race([
259
+ promise,
260
+ setTimeout(initialTimeout, timerSymbol),
261
+ ]);
262
+ if (result === timerSymbol) {
263
+ abortController?.abort("Timed out");
264
+ return { timedOut: true };
265
+ }
266
+ return { timedOut: false, result };
267
+ }
268
+
269
+ let taskTimeout = initialTimeout;
270
+ while (true as boolean) {
271
+ const result = await Promise.race([
272
+ promise,
273
+ setTimeout(taskTimeout, timerSymbol),
274
+ ]);
275
+
276
+ if (result !== timerSymbol) {
277
+ break;
278
+ }
279
+
280
+ const remainingTime =
281
+ (context.timeoutInfo?.timeoutTimestamp ?? 0) - Date.now();
282
+ if (remainingTime < 0) {
283
+ abortController?.abort("Timed out");
284
+ return { timedOut: true };
285
+ }
286
+
287
+ taskTimeout = remainingTime;
288
+ }
289
+
290
+ return {
291
+ timedOut: false,
292
+ result: await promise,
293
+ };
294
+ }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/api/run.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/auth-sessions/run-check.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/auth-sessions/run-create.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/auth-sessions/load.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/auth-sessions/run-refresh.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/browser/save-state.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/browser/start-browser.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/build.js");
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ require("../dist/commands/ts-check.js");
package/package.json ADDED
@@ -0,0 +1,133 @@
1
+ {
2
+ "name": "@intuned/runtime-dev",
3
+ "version": "0.0.1-split.0",
4
+ "description": "Intuned runtime",
5
+ "exports": {
6
+ ".": "./dist/index.js",
7
+ "./runtime": "./dist/runtime/index.js",
8
+ "./dist/common/settingsSchema": "./dist/common/settingsSchema.js",
9
+ "./dist/common/contextStorageStateHelpers": "./dist/common/contextStorageStateHelpers.js",
10
+ "./dist/common/telemetry": "./dist/common/telemetry.js",
11
+ "./dist/common/jwtTokenManager": "./dist/common/jwtTokenManager.js",
12
+ "./dist/common/asyncLocalStorage": "./dist/common/asyncLocalStorage/index.js",
13
+ "./dist/common/cleanEnvironmentVariables": "./dist/common/cleanEnvironmentVariables.js",
14
+ "./dist/common/constants": "./dist/common/constants.js"
15
+ },
16
+ "author": "Intuned Team",
17
+ "license": "MIT",
18
+ "scripts": {
19
+ "intuned-api-run": "vite-node ./src/commands/api/run.ts",
20
+ "intuned-browser-save-state": "vite-node ./src/commands/browser/save-state.ts",
21
+ "intuned-browser-start": "vite-node ./src/commands/browser/start-browser.ts",
22
+ "intuned-build": "yarn prepublishOnly && vite-node ./src/commands/build.ts",
23
+ "intuned-auth-session-check": "vite-node ./src/commands/auth/run-check.ts",
24
+ "intuned-auth-session-create": "vite-node ./src/commands/auth/run-create.ts",
25
+ "intuned-auth-session-refresh": "vite-node ./src/commands/auth/run-refresh.ts",
26
+ "intuned-auth-session-load": "vite-node ./src/commands/auth/load.ts",
27
+ "intuned-ts-check": "yarn prepublishOnly && vite-node ./src/commands/ts-check.ts",
28
+ "save-html": "vite-node ./src/commands/testing/saveVisibleHtml.ts",
29
+ "build": "rm -rf dist && tsc -p tsconfig.json && yarn copy-dts && babel src --out-dir dist --extensions '.ts' && cp -r ./src/common/assets dist/common/assets",
30
+ "test": "vitest run",
31
+ "test:watch": "vitest",
32
+ "e2e": "yarn playwright test --config ./playwright.config.ts",
33
+ "clean-declarations": "find ./types-package -name \"*.d.ts\" -type f -delete",
34
+ "lint": "eslint .",
35
+ "fix": "eslint . --fix",
36
+ "generate-docs": "./scripts/generate-docs.sh",
37
+ "build-browser-scripts": "rollup -c ./src/common/browserScripts/rollup.config.mjs",
38
+ "copy-dts": "copyfiles -u 1 \"src/**/*.d.ts\" dist"
39
+ },
40
+ "bin": {
41
+ "intuned-api-run": "./bin/intuned-api-run",
42
+ "intuned-auth-session-create": "./bin/intuned-auth-session-create",
43
+ "intuned-auth-session-refresh": "./bin/intuned-auth-session-refresh",
44
+ "intuned-auth-session-load": "./bin/intuned-auth-session-load",
45
+ "intuned-auth-session-check": "./bin/intuned-auth-session-check",
46
+ "intuned-build": "./bin/intuned-build",
47
+ "intuned-browser-start": "./bin/intuned-browser-start",
48
+ "intuned-browser-save-state": "./bin/intuned-browser-save-state",
49
+ "intuned-ts-check": "./bin/intuned-ts-check"
50
+ },
51
+ "dependencies": {
52
+ "@intuned/playwright": "^1.44.1-4",
53
+ "@intuned/playwright-core": "^1.44.1-4",
54
+ "@rollup/plugin-commonjs": "^25.0.2",
55
+ "@rollup/plugin-dynamic-import-vars": "^2.0.4",
56
+ "@rollup/plugin-json": "^6.0.0",
57
+ "@rollup/plugin-node-resolve": "^15.1.0",
58
+ "@rollup/plugin-typescript": "^11.1.2",
59
+ "@tinyhttp/app": "^2.1.0",
60
+ "@types/async-retry": "^1.4.8",
61
+ "@types/fs-extra": "^11.0.1",
62
+ "@types/lodash": "^4.14.200",
63
+ "@types/node": "^20.4.1",
64
+ "applicationinsights": "^2.9.2",
65
+ "async-retry": "^1.3.3",
66
+ "chalk": "^4.1.2",
67
+ "commander": "^11.0.0",
68
+ "cross-fetch": "^4.0.0",
69
+ "dotenv": "^16.3.1",
70
+ "express": "4.20.0",
71
+ "fastify": "^4.19.2",
72
+ "file-type": "16.5.4",
73
+ "fs-extra": "^11.3.0",
74
+ "https-proxy-agent": "^7.0.5",
75
+ "image-size": "^1.1.1",
76
+ "jsonwebtoken": "^9.0.2",
77
+ "lodash": "^4.17.21",
78
+ "milliparsec": "^2.3.0",
79
+ "ms": "^2.1.3",
80
+ "nanoid": "3",
81
+ "neverthrow": "^6.1.0",
82
+ "playwright-extra": "^4.3.6",
83
+ "prettier": "^2.8.0",
84
+ "promptly": "^3.2.0",
85
+ "read-chunk": "^3.2.0",
86
+ "rollup": "^3.26.2",
87
+ "source-map": "^0.7.4",
88
+ "stack-utils": "^2.0.6",
89
+ "ts-morph": "^21.0.1",
90
+ "ts-node": "^10.9.1",
91
+ "tslib": "^2.6.0",
92
+ "typescript": "^5.1.6",
93
+ "wait-on": "^7.2.0",
94
+ "zod": "^3.21.4",
95
+ "zod-validation-error": "^3.0.3"
96
+ },
97
+ "devDependencies": {
98
+ "@babel/cli": "^7.23.4",
99
+ "@babel/core": "^7.23.7",
100
+ "@babel/plugin-transform-export-namespace-from": "^7.24.1",
101
+ "@babel/preset-env": "^7.23.7",
102
+ "@babel/preset-typescript": "^7.23.3",
103
+ "@jest/globals": "^29.6.2",
104
+ "@ngneat/falso": "^7.2.0",
105
+ "@types/jest": "^29.5.3",
106
+ "@types/jsdom": "^21.1.1",
107
+ "@types/promptly": "^3.0.4",
108
+ "@types/wait-on": "^5.3.4",
109
+ "@typescript-eslint/eslint-plugin": "^5.47.1",
110
+ "@typescript-eslint/parser": "^7.5.0",
111
+ "@vitest/ui": "^1.1.3",
112
+ "babel-plugin-macros": "^3.1.0",
113
+ "babel-preset-minify": "^0.5.2",
114
+ "copyfiles": "^2.4.1",
115
+ "dts-bundle-generator": "^8.0.1",
116
+ "eslint": "7.32.0",
117
+ "eslint-config-prettier": "^8.3.0",
118
+ "eslint-plugin-deprecation": "^1.3.3",
119
+ "eslint-plugin-prettier": "^4.2.1",
120
+ "msw": "^2.1.2",
121
+ "typedoc": "^0.25.13",
122
+ "typedoc-plugin-frontmatter": "^1.0.0",
123
+ "typedoc-plugin-markdown": "^4.0.2",
124
+ "typedoc-plugin-remove-references": "^0.0.6",
125
+ "vite": "^5.2.14",
126
+ "vite-node": "^1.1.3",
127
+ "vite-plugin-babel-macros": "^1.0.6",
128
+ "vitest": "^1.1.3"
129
+ },
130
+ "peerDependencies": {
131
+ "@intuned/runtime": "0.0.1"
132
+ }
133
+ }
@@ -0,0 +1,48 @@
1
+ import { defineConfig, devices } from "@intuned/playwright-test";
2
+
3
+ /**
4
+ * Read environment variables from file.
5
+ * https://github.com/motdotla/dotenv
6
+ */
7
+ // require('dotenv').config();
8
+
9
+ /**
10
+ * See https://playwright.dev/docs/test-configuration.
11
+ */
12
+ export default defineConfig({
13
+ testDir: "./e2e-tests",
14
+ /* Run tests in files in parallel */
15
+ fullyParallel: true,
16
+ /* Fail the build on CI if you accidentally left test.only in the source code. */
17
+ forbidOnly: !!process.env.CI,
18
+ /* Retry on CI only */
19
+ retries: process.env.CI ? 2 : 0,
20
+ /* Opt out of parallel tests on CI. */
21
+ workers: process.env.CI ? 1 : undefined,
22
+ /* Reporter to use. See https://playwright.dev/docs/test-reporters */
23
+ reporter: "html",
24
+ /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */
25
+ use: {
26
+ /* Base URL to use in actions like `await page.goto('/')`. */
27
+ // baseURL: 'http://127.0.0.1:3000',
28
+
29
+ /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */
30
+ trace: "on-first-retry",
31
+ // headless: false,
32
+ },
33
+
34
+ /* Configure projects for major browsers */
35
+ projects: [
36
+ {
37
+ name: "chromium",
38
+ use: { ...devices["Desktop Chrome"] },
39
+ },
40
+ ],
41
+
42
+ /* Run your local dev server before starting the tests */
43
+ // webServer: {
44
+ // command: 'npm run start',
45
+ // url: 'http://127.0.0.1:3000',
46
+ // reuseExistingServer: !process.env.CI,
47
+ // },
48
+ });