@uuv/playwright 1.3.3 → 1.4.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.
package/README.md CHANGED
@@ -1,5 +1,4 @@
1
1
 
2
-
3
2
  # @uuv/runner-playwright
4
3
  <p align="center">
5
4
  <a href="https://e2e-test-quest.github.io/uuv/">
@@ -8,9 +7,6 @@
8
7
  </picture>
9
8
  </a>
10
9
  </p>
11
- <p align="center">
12
- <a href="https://e2e-test-quest.github.io/uuv/"><img src="https://img.shields.io/badge/documentation-black?&style=for-the-badge&logo=github&logoColor=white" alt="documentation"/></a>
13
- </p>
14
10
 
15
11
  <h3 align="center">
16
12
  Test as final user
@@ -35,7 +31,41 @@ Make test writing fast, understandable by any human understanding English or Fre
35
31
  </a><br />
36
32
  </p>
37
33
 
38
- ## What is @uuv/playwright ?
34
+ ## Benefits
35
+ - If used correctly, integrates accessibility from the development stage
36
+ - A living documentation is possible because we propose an unified language for developers and non-developers with a rich dictionary of ready-to-use sentences
37
+ - A wizard that facilitates the writing of tests by suggesting the most accessible sentences
38
+ - Integrates several runtime engines: Cypress / Playwright
39
+ - User-friendly and standardized execution report
40
+ ### <u>Comparison</u>
41
+ | Criteria | Cypress | Playwright | Testing library | UUV |
42
+ |:-: |:-: |:-: |:-: |:-: |
43
+ | User centrism | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
44
+ | Native accessibility | :x: | :heavy_check_mark: | :heavy_check_mark: | :heavy_check_mark: |
45
+ | Easy setup configuration for BDD test | :warning: | :warning: | :heavy_minus_sign: | :heavy_check_mark: |
46
+ | Understandable by everyone <br> (included non dev) | :x: | :x: | :x: | :heavy_check_mark: |
47
+
48
+ ### <u>Syntax example</u>
49
+ With this dom example :
50
+ ```html
51
+ <body>
52
+ <h1>Result<h1>
53
+ </body>
54
+ ```
55
+ we see that the sentence proposed by **UUV is the most understandable** of all
56
+ | Library | Syntax |
57
+ |:--|:--|
58
+ | Cypress | cy.get('result').should('exist') |
59
+ | Playwright| await expect(page.getByTitle('Result')).toHaveCount(1) |
60
+ | Testing library | expect(screen.getByTitle(/Result/i)).toBeTruthy() |
61
+ | UUV | Then I should see a title named "Result"|
62
+
63
+
64
+ ## Documentation
65
+ <a href="https://e2e-test-quest.github.io/uuv/"><img src="https://img.shields.io/badge/documentation-black?&style=for-the-badge&logo=github&logoColor=white" alt="documentation"/></a>
66
+
67
+ ## What is @uuv/playwright?
68
+
39
69
 
40
70
  <p align="center">
41
71
 
@@ -43,20 +73,76 @@ The `@uuv` library (User centric Usecases Validator) is an ecosystem that simpli
43
73
  We can use the playwright engine to run test or cypress with [@uuv/cypress](https://www.npmjs.com/package/@uuv/cypress)
44
74
  </p>
45
75
 
46
- ## Installing
47
76
 
48
- <a href="https://e2e-test-quest.github.io/uuv/docs/getting-started/installation#playwright"><img src="https://img.shields.io/badge/Install%20Playwright%20doc-red?&style=for-the-badge&logo=github&logoColor=white" alt="documentation for install uuv playwright"/></a>
77
+ ## Installation
78
+
49
79
 
80
+ ```bash
81
+ npm install --save-dev @uuv/playwright
82
+ ```
83
+ or
84
+ ```bash
85
+ yarn add -D @uuv/playwright
86
+ ```
87
+ ## Configuration (optional)
50
88
  <a href="https://e2e-test-quest.github.io/uuv/docs/getting-started/configuration"><img src="https://img.shields.io/badge/Configure%20Playwright%20doc-red?&style=for-the-badge&logo=github&logoColor=white" alt="documentation for configure uuv playwright"/></a>
51
89
 
90
+ ## Usage
91
+ ### Write test
92
+ To write your first test, create the file `uuv/e2e/first-test.feature` in the project root with the following content :
93
+ ```gherkin
94
+ Feature: Hello World
95
+
96
+ Scenario: Search - Successful case
97
+ When I visit path "/"
98
+ Then I should see an element with role "heading" and name "My app title"
99
+ ```
100
+
101
+ For more details, please go to the documentation:
52
102
  <a href="https://e2e-test-quest.github.io/uuv/docs/test/first-test"><img src="https://img.shields.io/badge/Write%20test%20doc-red?&style=for-the-badge&logo=github&logoColor=white" alt="documentation for write test"/></a>
53
103
 
104
+ ### Run test
105
+
106
+ #### browser mode
107
+ ```bash
108
+ npx uuv open
109
+ ```
110
+ or
111
+ ```bash
112
+ yarn uuv open
113
+ ```
114
+
115
+ #### headless mode
116
+ ##### without args
117
+ ```bash
118
+ npx uuv e2e
119
+ ```
120
+ or
121
+ ```bash
122
+ yarn uuv e2e
123
+ ```
124
+ ##### with args
125
+ ```bash
126
+ npx uuv e2e --browser=edge --env="{'TAGS':'@mobile'}" --generateHtmlReport
127
+ ```
128
+ or
129
+ ```bash
130
+ yarn uuv e2e --browser=edge --env="{'TAGS':'@mobile'}" --generateHtmlReport
131
+ ```
132
+
133
+ For more details, please go to the documentation:
54
134
  <a href="https://e2e-test-quest.github.io/uuv/docs/test/running-test"><img src="https://img.shields.io/badge/Run%20test%20doc-red?&style=for-the-badge&logo=github&logoColor=white" alt="documentation for run test"/></a>
55
135
 
56
136
  ## License
57
137
 
58
- [<a href="https://www.npmjs.com/package/@uuv/playwright">
59
- <img src="https://img.shields.io/badge/license-Apache%202.0-blue" alt="npm"/>
138
+ [<a href="https://github.com/e2e-test-quest/uuv/blob/main/LICENSE">
139
+ <img src="https://img.shields.io/badge/license-Apache%202.0-blue" alt="apache license"/>
60
140
  </a>](https://www.apache.org/licenses/LICENSE-2.0)
61
141
 
62
- This project is licensed under the terms of the [Apache 2.0 license](https://www.apache.org/licenses/LICENSE-2.0).
142
+ This project is licensed under the terms of the [Apache 2.0 license](https://github.com/e2e-test-quest/uuv/blob/main/LICENSE).
143
+
144
+ ## Authors
145
+
146
+ - [@luifr10](https://github.com/luifr10)
147
+ - [@stanlee974](https://github.com/stanlee974)
148
+
@@ -40,7 +40,6 @@ async function bddGen(tempDir) {
40
40
  }
41
41
  });
42
42
  fs_1.default.writeFileSync(`${tempDir}/${exports.UUVPlaywrightCucumberMapFile}`, JSON.stringify(content, null, 4), { encoding: "utf8" });
43
- console.log("bddgen executed");
44
43
  }
45
44
  catch (err) {
46
45
  console.error(chalk_1.default.red("Something went wrong..."));
@@ -87,7 +86,7 @@ function translateFeatures(tempDir, configDir) {
87
86
  "*******************************/\n\n" +
88
87
  data;
89
88
  fs_1.default.writeFileSync(generatedFile, data);
90
- console.log(`[WRITE] ${generatedFile} written successfully`);
89
+ console.log(chalk_1.default.gray(`[WRITE] ${generatedFile} written successfully`));
91
90
  });
92
91
  }
93
92
  function runPlaywright(mode, configDir, generateHtmlReport = false) {
@@ -100,16 +99,22 @@ function runPlaywright(mode, configDir, generateHtmlReport = false) {
100
99
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
101
100
  // @ts-ignore
102
101
  process.env.CONFIG_DIR = configDir;
103
- console.log(`Running: npx playwright test --project=chromium -c ${configFile} ${mode === "open" ? "--ui" : ""}`);
104
- (0, child_process_1.execSync)(`npx playwright test --project=chromium -c ${configFile} ${mode === "open" ? "--ui" : ""}`, { stdio: "inherit" });
102
+ const command = `npx playwright test --project=chromium -c ${configFile} ${mode === "open" ? "--ui" : ""}`;
103
+ console.log(chalk_1.default.gray(`Running ${command}`));
104
+ (0, child_process_1.execSync)(command, { stdio: "inherit" });
105
105
  }
106
106
  catch (err) {
107
107
  process.exit(-1);
108
108
  }
109
109
  }
110
- async function run(mode, tempDir = "uuv/.features-gen/e2e", configDir = "uuv", generateHtmlReport = false) {
110
+ async function executePreprocessor(tempDir, configDir) {
111
+ console.log("running preprocessor...");
111
112
  await bddGen(tempDir);
112
113
  translateFeatures(tempDir, configDir);
114
+ console.log("preprocessor executed");
115
+ }
116
+ async function run(mode, tempDir = "uuv/.features-gen/e2e", configDir = "uuv", generateHtmlReport = false) {
117
+ await executePreprocessor(tempDir, configDir);
113
118
  runPlaywright(mode, configDir, generateHtmlReport);
114
119
  }
115
120
  exports.run = run;
@@ -1,4 +1,3 @@
1
- /// <reference types="node" />
2
1
  import { FullConfig, FullResult, Suite, TestCase, TestResult } from "@playwright/test/reporter";
3
2
  import { Envelope } from "@cucumber/messages";
4
3
  import { TestStep } from "@playwright/test/types/testReporter";
@@ -6,10 +5,6 @@ export declare enum GeneratedReportType {
6
5
  CONSOLE = "console",
7
6
  HTML = "html"
8
7
  }
9
- interface TestError {
10
- scenario: string;
11
- error: string | Buffer;
12
- }
13
8
  declare class UuvPlaywrightReporterHelper {
14
9
  private UUVPlaywrightCucumberMap;
15
10
  testDir: string;
@@ -21,6 +16,7 @@ declare class UuvPlaywrightReporterHelper {
21
16
  private testStepLocationAndTestStepIdMap;
22
17
  private consoleReportMap;
23
18
  private errors;
19
+ private currentFeatureFile;
24
20
  createTestRunStartedEnvelope(config: FullConfig, suite: Suite, startTimestamp: {
25
21
  seconds: number;
26
22
  nanos: number;
@@ -40,6 +36,8 @@ declare class UuvPlaywrightReporterHelper {
40
36
  }): void;
41
37
  private getTestStepKey;
42
38
  createTestCaseFinishedEnvelope(test: TestCase, result: TestResult, featureFile: string, endTimestamp: any): void;
39
+ private addResultErrors;
40
+ private createTestCaseErrorAttachmentsEnvelope;
43
41
  private initConsoleReportIfNotExists;
44
42
  private updateConsoleReport;
45
43
  createTestRunFinishedEnvelope(result: FullResult): void;
@@ -50,7 +48,7 @@ declare class UuvPlaywrightReporterHelper {
50
48
  };
51
49
  getOriginalFeatureFile(generateFile: string): string | undefined;
52
50
  getCurrentRunningScenario(test: TestCase, featureFile: string): string;
53
- addError(newError: TestError): void;
51
+ private addError;
54
52
  private getStatus;
55
53
  private createEnvelope;
56
54
  private createCucumberNdJsonFile;
@@ -65,5 +63,9 @@ declare class UuvPlaywrightReporterHelper {
65
63
  private generateHtmlReport;
66
64
  private createdDirIfNeeded;
67
65
  private displayConsoleReport;
66
+ logTestBegin(testCase: TestCase, featureFile: string): void;
67
+ logTestEnd(testCase: TestCase, result: TestResult): void;
68
+ private getResultIcon;
69
+ private getTestCaseTitle;
68
70
  }
69
71
  export default UuvPlaywrightReporterHelper;
@@ -48,6 +48,7 @@ class UuvPlaywrightReporterHelper {
48
48
  testStepLocationAndTestStepIdMap = new Map();
49
49
  consoleReportMap = new Map();
50
50
  errors = [];
51
+ currentFeatureFile;
51
52
  createTestRunStartedEnvelope(config, suite, startTimestamp) {
52
53
  this.testDir = config.projects[0].testDir;
53
54
  this.loadUUVPlaywrightCucumberMap();
@@ -121,7 +122,7 @@ class UuvPlaywrightReporterHelper {
121
122
  .find(pickle => pickle.id === pickleId)
122
123
  ?.steps
123
124
  .filter((value, index) => index >= (newIndexStep - 1))
124
- .forEach((pickleStep, index) => {
125
+ .forEach((pickleStep) => {
125
126
  const newTestStepStartedEnvelope = this.createEnvelope({
126
127
  testStepStarted: {
127
128
  testStepId: pickleStep.id,
@@ -164,7 +165,9 @@ class UuvPlaywrightReporterHelper {
164
165
  duration: {
165
166
  seconds: result.duration / 1000,
166
167
  nanos: result.duration * NANOS_IN_MILLISSECOND
167
- }
168
+ },
169
+ // eslint-disable-next-line no-control-regex
170
+ message: step.error?.message?.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "")
168
171
  },
169
172
  timestamp: startTimestamp
170
173
  }
@@ -182,9 +185,10 @@ class UuvPlaywrightReporterHelper {
182
185
  if (result.status === "skipped" || result.status === "failed") {
183
186
  this.createTestStepSkippedEnvelope(test, featureFile, endTimestamp);
184
187
  }
188
+ const testCaseStartedId = this.testCasesAndTestCasesStartedIdMap.get(test.id);
185
189
  const newTestCaseFinishedEnvelope = this.createEnvelope({
186
190
  testCaseFinished: {
187
- testCaseStartedId: this.testCasesAndTestCasesStartedIdMap.get(test.id),
191
+ testCaseStartedId: testCaseStartedId,
188
192
  attempt: result.retry,
189
193
  timestamp: endTimestamp
190
194
  }
@@ -192,8 +196,39 @@ class UuvPlaywrightReporterHelper {
192
196
  currentQuery.update(newTestCaseFinishedEnvelope);
193
197
  this.envelopes.push(newTestCaseFinishedEnvelope);
194
198
  this.updateConsoleReport(featureFile, result);
199
+ this.addResultErrors(result, test, featureFile);
200
+ this.createTestCaseErrorAttachmentsEnvelope(testCaseStartedId, result);
195
201
  }
196
202
  }
203
+ addResultErrors(result, test, featureFile) {
204
+ result.errors.forEach(error => {
205
+ const scenario = this.getCurrentRunningScenario(test, featureFile);
206
+ this.addError({
207
+ scenario: scenario,
208
+ error: error.message
209
+ });
210
+ });
211
+ }
212
+ createTestCaseErrorAttachmentsEnvelope(testCaseStartedId, result) {
213
+ result.attachments.forEach(attachment => {
214
+ if (attachment.path && attachment.path.endsWith("test-failed-1.png")) {
215
+ const attachmentBody = fs_1.default.readFileSync(attachment.path, { encoding: "base64" });
216
+ const failedStep = result.steps.find(step => step.error);
217
+ if (failedStep?.location) {
218
+ const testCaseAttachmentEnvelope = this.createEnvelope({
219
+ attachment: {
220
+ testCaseStartedId: testCaseStartedId,
221
+ testStepId: this.testStepLocationAndTestStepIdMap.get(this.getTestStepKey(failedStep.location)),
222
+ body: attachmentBody,
223
+ contentEncoding: messages_1.AttachmentContentEncoding.BASE64,
224
+ mediaType: attachment.contentType
225
+ }
226
+ });
227
+ this.envelopes.push(testCaseAttachmentEnvelope);
228
+ }
229
+ }
230
+ });
231
+ }
197
232
  initConsoleReportIfNotExists(featureFile) {
198
233
  if (!this.consoleReportMap.get(featureFile)) {
199
234
  this.consoleReportMap.set(featureFile, new ReportOfFeature());
@@ -341,7 +376,7 @@ class UuvPlaywrightReporterHelper {
341
376
  async generateHtmlReport() {
342
377
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
343
378
  // @ts-ignore
344
- const reportDir = `${process.env.CONFIG_DIR}/reports`;
379
+ const reportDir = `${process.env.CONFIG_DIR}/reports/e2e`;
345
380
  const outputMessageFile = `${reportDir}/cucumber-messages.ndjson`;
346
381
  const reportDirHtml = `${reportDir}/html`;
347
382
  const reportDirJson = `${reportDir}/json`;
@@ -368,7 +403,7 @@ class UuvPlaywrightReporterHelper {
368
403
  { field: "file", name: "File" },
369
404
  { field: "passed", name: chalk_1.default.green("Passed") },
370
405
  { field: "skipped", name: chalk_1.default.yellow("Skipped") },
371
- { field: "failed", name: chalk_1.default.red("Failed") }
406
+ { field: "failed", name: chalk_1.default.redBright("Failed") }
372
407
  ]
373
408
  };
374
409
  let index = 1;
@@ -378,7 +413,7 @@ class UuvPlaywrightReporterHelper {
378
413
  file: key,
379
414
  passed: chalk_1.default.green(value.passed),
380
415
  skipped: chalk_1.default.yellow(value.skipped),
381
- failed: chalk_1.default.red(value.failed)
416
+ failed: value.failed ? chalk_1.default.redBright(value.failed) : chalk_1.default.red(value.failed)
382
417
  });
383
418
  index++;
384
419
  });
@@ -396,5 +431,21 @@ class UuvPlaywrightReporterHelper {
396
431
  console.log((0, chalk_table_1.default)(chalkTableOptions, consoleReport));
397
432
  console.log("\n\n");
398
433
  }
434
+ logTestBegin(testCase, featureFile) {
435
+ if (this.currentFeatureFile !== featureFile) {
436
+ console.info(chalk_1.default.blueBright(` Feature: ${featureFile}`));
437
+ this.currentFeatureFile = featureFile;
438
+ }
439
+ }
440
+ logTestEnd(testCase, result) {
441
+ console.info(` ${this.getResultIcon(testCase)} ${this.getTestCaseTitle(testCase, result)}`);
442
+ }
443
+ getResultIcon(testCase) {
444
+ return !testCase.ok() ? chalk_1.default.redBright("\u166D") : chalk_1.default.green("\u2713");
445
+ }
446
+ getTestCaseTitle(testCase, result) {
447
+ const message = `${testCase.title} (${result.duration}ms)`;
448
+ return !testCase.ok() ? chalk_1.default.redBright(message) : chalk_1.default.gray(message);
449
+ }
399
450
  }
400
451
  exports.default = UuvPlaywrightReporterHelper;
@@ -1,12 +1,9 @@
1
- /// <reference types="node" />
2
1
  import { FullConfig, FullResult, Reporter, Suite, TestCase, TestResult } from "@playwright/test/reporter";
3
2
  import { TestError, TestStep } from "@playwright/test/types/testReporter";
4
3
  declare class UuvPlawrightReporter implements Reporter {
5
4
  private helper;
6
- private reporterStaticConsoleLogger;
7
5
  onBegin(config: FullConfig, suite: Suite): void;
8
6
  onError?(error: TestError): void;
9
- onStdErr?(chunk: string | Buffer, test: void | TestCase, result: void | TestResult): void;
10
7
  onTestBegin(test: TestCase, result: TestResult): void;
11
8
  onStepBegin(test: TestCase, result: TestResult, step: TestStep): void;
12
9
  onStepEnd(test: TestCase, result: TestResult, step: TestStep): void;
@@ -5,40 +5,23 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  const uuv_playwright_reporter_helper_1 = __importDefault(require("./uuv-playwright-reporter-helper"));
7
7
  const chalk_1 = __importDefault(require("chalk"));
8
- const draftlog_1 = __importDefault(require("draftlog"));
9
8
  class UuvPlawrightReporter {
10
9
  helper = new uuv_playwright_reporter_helper_1.default();
11
- reporterStaticConsoleLogger;
12
10
  onBegin(config, suite) {
13
11
  const startTimestamp = this.helper.getTimestamp();
14
12
  // console.log(`Starting the run with ${suite.allTests().length} tests`);
15
13
  this.helper.createTestRunStartedEnvelope(config, suite, startTimestamp);
16
- (0, draftlog_1.default)(console).addLineListener(process.stdin);
17
- console.log(chalk_1.default.yellow(`Starting the run with ${suite.allTests().length} tests`));
18
- this.reporterStaticConsoleLogger = console.draft(chalk_1.default.yellow("!!! Fasten seat belt !!!"));
14
+ console.info(chalk_1.default.yellow(`Starting the run with ${suite.allTests().length} tests`));
19
15
  }
20
16
  onError(error) {
21
17
  console.dir(chalk_1.default.red(error));
22
18
  }
23
- onStdErr(chunk, test, result) {
24
- let scenario = "unknown";
25
- if (test?.id !== undefined) {
26
- const featureFile = this.helper.getOriginalFeatureFile(test.location.file);
27
- if (featureFile) {
28
- scenario = this.helper.getCurrentRunningScenario(test, featureFile);
29
- }
30
- }
31
- this.helper.addError({
32
- scenario: scenario,
33
- error: chunk
34
- });
35
- }
36
19
  onTestBegin(test, result) {
37
20
  const startTimestamp = this.helper.getTimestamp(result.startTime);
38
21
  // console.log(`Starting test ${test.title} - ${test.parent.location?.file}`);
39
22
  const featureFile = this.helper.getOriginalFeatureFile(test.location.file);
40
23
  if (featureFile) {
41
- this.reporterStaticConsoleLogger(chalk_1.default.blueBright(`Running > ${this.helper.getCurrentRunningScenario(test, featureFile)}`));
24
+ this.helper.logTestBegin(test, featureFile);
42
25
  this.helper.createTestCaseStartedEnvelope(test, result, featureFile, startTimestamp);
43
26
  }
44
27
  }
@@ -64,12 +47,13 @@ class UuvPlawrightReporter {
64
47
  const featureFile = this.helper.getOriginalFeatureFile(test.location.file);
65
48
  if (featureFile) {
66
49
  this.helper.createTestCaseFinishedEnvelope(test, result, featureFile, endTimestamp);
50
+ this.helper.logTestEnd(test, result);
67
51
  }
68
52
  }
69
53
  async onEnd(result) {
70
54
  // console.debug(`Finished the run: ${result.status}`);
71
55
  this.helper.createTestRunFinishedEnvelope(result);
72
- console.log(chalk_1.default.yellow("End of the tests execution"));
56
+ console.log(chalk_1.default.yellow("End of the tests execution\n"));
73
57
  await this.helper.generateReport(
74
58
  // eslint-disable-next-line @typescript-eslint/ban-ts-comment
75
59
  // @ts-ignore
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@uuv/playwright",
3
- "version": "1.3.3",
3
+ "version": "1.4.0",
4
4
  "type": "commonjs",
5
5
  "author": "Louis Fredice NJAKO MOLOM (https://github.com/luifr10) & Stanley SERVICAL (https://github.com/stanlee974)",
6
6
  "description": "A solution to run E2E tests written in cucumber(BDD) with playwright.",
@@ -41,13 +41,12 @@
41
41
  "dependencies": {
42
42
  "@cucumber/cucumber": "9.1.2",
43
43
  "@playwright/test": "1.33.0",
44
- "@uuv/runner-commons": "1.3.3",
44
+ "@uuv/runner-commons": "1.4.0",
45
45
  "axe-core": "4.7.0",
46
46
  "axe-playwright": "1.2.3",
47
47
  "chalk": "4.1.2",
48
48
  "chalk-table": "^1.0.2",
49
49
  "cucumber-json-report-formatter": "0.1.4",
50
- "draftlog": "1.0.13",
51
50
  "figlet": "1.6.0",
52
51
  "minimist": "1.2.8",
53
52
  "multiple-cucumber-html-reporter": "3.3.0",
@@ -6,11 +6,13 @@ export default defineConfig({
6
6
  fullyParallel: true,
7
7
  forbidOnly: !!process.env.CI,
8
8
  retries: process.env.CI ? 2 : 0,
9
- workers: process.env.CI ? 1 : undefined,
9
+ outputDir: "reports/playwright",
10
+ workers: 1,
10
11
  reporter: "@uuv/playwright/uuv-playwright-reporter",
11
12
  use: {
12
13
  baseURL: "http://localhost:4200",
13
14
  trace: "on-first-retry",
15
+ screenshot: "only-on-failure"
14
16
  },
15
17
 
16
18
  projects: [