@applitools/eyes-playwright 1.38.1 → 1.39.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/CHANGELOG.md CHANGED
@@ -1,5 +1,106 @@
1
1
  # Changelog
2
2
 
3
+ ## [1.39.0](https://github.com/Applitools-Dev/sdk/compare/js/eyes-playwright@1.38.2...js/eyes-playwright@1.39.0) (2025-08-05)
4
+
5
+
6
+ ### Features
7
+
8
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
9
+
10
+
11
+ ### Dependencies
12
+
13
+ * @applitools/utils bumped to 1.11.0
14
+ #### Features
15
+
16
+ * improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
17
+ * make utils.general.guid crypto secured ([#3137](https://github.com/Applitools-Dev/sdk/issues/3137)) ([775df08](https://github.com/Applitools-Dev/sdk/commit/775df08307e41402a6603812205bc857bd3f936e))
18
+ * @applitools/logger bumped to 2.2.1
19
+
20
+ * @applitools/dom-snapshot bumped to 4.13.1
21
+
22
+ * @applitools/socket bumped to 1.3.1
23
+
24
+ * @applitools/req bumped to 1.8.1
25
+
26
+ * @applitools/image bumped to 1.2.1
27
+
28
+ * @applitools/dom-capture bumped to 11.6.1
29
+
30
+ * @applitools/driver bumped to 1.23.1
31
+
32
+ * @applitools/spec-driver-webdriver bumped to 1.4.1
33
+
34
+ * @applitools/spec-driver-selenium bumped to 1.7.1
35
+
36
+ * @applitools/spec-driver-playwright bumped to 1.7.1
37
+
38
+ * @applitools/spec-driver-puppeteer bumped to 1.6.1
39
+
40
+ * @applitools/screenshoter bumped to 3.12.1
41
+
42
+ * @applitools/nml-client bumped to 1.11.1
43
+
44
+ * @applitools/tunnel-client bumped to 1.10.2
45
+
46
+ * @applitools/ufg-client bumped to 1.17.1
47
+
48
+ * @applitools/core-base bumped to 1.27.1
49
+
50
+ * @applitools/ec-client bumped to 1.12.2
51
+
52
+ * @applitools/core bumped to 4.44.2
53
+
54
+ * @applitools/eyes bumped to 1.36.0
55
+ #### Features
56
+
57
+ * improve configuration handling ([#3130](https://github.com/Applitools-Dev/sdk/issues/3130)) ([def7be1](https://github.com/Applitools-Dev/sdk/commit/def7be1dd07460f49142cddfe55203baa884e6c3))
58
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
59
+
60
+
61
+
62
+ * @applitools/test-server bumped to 1.3.0
63
+ #### Features
64
+
65
+ * release java ([7bc39e6](https://github.com/Applitools-Dev/sdk/commit/7bc39e679eab27a19322ca4b121177da7437c106))
66
+
67
+
68
+
69
+
70
+ ## [1.38.2](https://github.com/Applitools-Dev/sdk/compare/js/eyes-playwright@1.38.1...js/eyes-playwright@1.38.2) (2025-07-23)
71
+
72
+
73
+ ### Bug Fixes
74
+
75
+ * blob reporter results saving ([#3108](https://github.com/Applitools-Dev/sdk/issues/3108)) ([d542241](https://github.com/Applitools-Dev/sdk/commit/d542241a971f03c4a42f55a54ae159ef807186e0))
76
+
77
+
78
+ ### Dependencies
79
+
80
+ * @applitools/nml-client bumped to 1.10.0
81
+ #### Features
82
+
83
+ * android multi target | AD-9868 ([#2943](https://github.com/Applitools-Dev/sdk/issues/2943)) ([808aa21](https://github.com/Applitools-Dev/sdk/commit/808aa21e489c3562b93006e2e26ff7ffbb743dd6))
84
+
85
+
86
+
87
+ * @applitools/core-base bumped to 1.26.0
88
+ #### Features
89
+
90
+ * batch properties limit | FLD-3174 ([#3080](https://github.com/Applitools-Dev/sdk/issues/3080)) ([feb9e79](https://github.com/Applitools-Dev/sdk/commit/feb9e79d79f5eab3c58eac2b4ef3c15a562f079c))
91
+ * @applitools/core bumped to 4.43.0
92
+ #### Features
93
+
94
+ * android multi target | AD-9868 ([#2943](https://github.com/Applitools-Dev/sdk/issues/2943)) ([808aa21](https://github.com/Applitools-Dev/sdk/commit/808aa21e489c3562b93006e2e26ff7ffbb743dd6))
95
+ * batch properties limit | FLD-3174 ([#3080](https://github.com/Applitools-Dev/sdk/issues/3080)) ([feb9e79](https://github.com/Applitools-Dev/sdk/commit/feb9e79d79f5eab3c58eac2b4ef3c15a562f079c))
96
+
97
+
98
+
99
+ * @applitools/ec-client bumped to 1.11.1
100
+
101
+ * @applitools/eyes bumped to 1.35.3
102
+
103
+
3
104
  ## [1.38.1](https://github.com/Applitools-Dev/sdk/compare/js/eyes-playwright@1.38.0...js/eyes-playwright@1.38.1) (2025-07-15)
4
105
 
5
106
 
@@ -26,6 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.InternalData = void 0;
27
27
  const fs = __importStar(require("fs"));
28
28
  const path = __importStar(require("path"));
29
+ const os = __importStar(require("os"));
29
30
  const playwrightPath = require.resolve('playwright');
30
31
  const HtmlReporter = require(path.join(path.dirname(playwrightPath), '/lib/reporters/html')).default;
31
32
  const pluginsFile = require.resolve('../../dist/fixture/reportRenderer.js');
@@ -45,8 +46,13 @@ const createInjectedScript = (testResultsMap) => `
45
46
  class EyesReporter extends HtmlReporter {
46
47
  constructor(options) {
47
48
  super(options);
49
+ this.stdoutData = '';
48
50
  this.applitoolsIdentifiersAndFolders = [];
49
51
  }
52
+ onStdOut(chunk) {
53
+ // Capture stdout data for blob reporter scenarios
54
+ this.stdoutData += chunk.toString();
55
+ }
50
56
  onTestEnd(test, result) {
51
57
  var _a;
52
58
  (_a = super.onTestEnd) === null || _a === void 0 ? void 0 : _a.call(this, test, result);
@@ -74,7 +80,7 @@ class EyesReporter extends HtmlReporter {
74
80
  await super.onEnd(result);
75
81
  const testResultsMap = {};
76
82
  for (const applitoolsIdentifierAndFolder of this.applitoolsIdentifiersAndFolders) {
77
- const content = await exports.InternalData.consume(applitoolsIdentifierAndFolder);
83
+ const content = await exports.InternalData.consume(applitoolsIdentifierAndFolder, this.stdoutData);
78
84
  if (content) {
79
85
  testResultsMap[content.key] = content.data;
80
86
  }
@@ -90,7 +96,17 @@ class EyesReporter extends HtmlReporter {
90
96
  }
91
97
  }
92
98
  exports.default = EyesReporter;
99
+ const defaultDataDirectory = path.join(os.tmpdir(), 'eyes-playwright-data');
93
100
  exports.InternalData = {
101
+ determineDirectory(testInfo) {
102
+ var _a;
103
+ const blobReporter = testInfo.config.reporter.find(r => r[0].includes('blob'));
104
+ const customOutputDir = (_a = blobReporter === null || blobReporter === void 0 ? void 0 : blobReporter[1]) === null || _a === void 0 ? void 0 : _a.outputDir;
105
+ return customOutputDir ? path.join(customOutputDir, 'eyes-report-files') : defaultDataDirectory;
106
+ },
107
+ hasBlobReporter(testInfo) {
108
+ return testInfo.config.reporter.some(r => r[0].includes('blob'));
109
+ },
94
110
  async write({ testInfo, data }) {
95
111
  const [applitoolsIdentifier, folder] = testInfo.attachments
96
112
  .find(a => a.name === 'applitoolsIdentifier')
@@ -99,29 +115,66 @@ exports.InternalData = {
99
115
  .map(s => s.trim())
100
116
  .filter(Boolean); // if the directory is not specified, it will be empty
101
117
  const key = `${testInfo.testId}--${testInfo.retry}`;
102
- this.ensureFolder(folder);
103
- await fs.promises.writeFile(this.getPathForInternalId(applitoolsIdentifier, folder), JSON.stringify({ key, data }));
118
+ if (this.hasBlobReporter(testInfo)) {
119
+ // Use stdout approach for blob reporter scenarios
120
+ // eslint-disable-next-line no-console
121
+ console.log(`EYES_DATA:${applitoolsIdentifier}:${JSON.stringify({ key, data })}`);
122
+ }
123
+ else {
124
+ // Use file approach for direct reporter scenarios
125
+ const targetFolder = folder || this.determineDirectory(testInfo);
126
+ this.ensureFolder(targetFolder);
127
+ await fs.promises.writeFile(this.getPathForInternalId(applitoolsIdentifier, targetFolder), JSON.stringify({ key, data }));
128
+ }
104
129
  },
105
- async consume(applitoolsIdentifierAndFolder) {
130
+ async consume(applitoolsIdentifierAndFolder, stdoutData) {
106
131
  const [name, folder] = applitoolsIdentifierAndFolder
107
132
  .split('|')
108
133
  .map(s => s.trim())
109
134
  .filter(Boolean); // if the directory is not specified, it will be empty
110
- const filepath = this.getPathForInternalId(name, folder);
111
- try {
112
- const content = await fs.promises.readFile(filepath, 'utf-8').then(JSON.parse);
113
- return content;
135
+ // Try stdout data first (for blob reporter scenarios), then fall back to files
136
+ if (stdoutData) {
137
+ // Parse from stdout for blob reporter scenarios
138
+ const results = this.parseStdoutLine(name, stdoutData);
139
+ // Return the last result if multiple exist, or undefined if none
140
+ return results.length > 0 ? results[results.length - 1] : undefined;
141
+ }
142
+ else {
143
+ // Read from file for direct reporter scenarios
144
+ const targetFolder = folder || defaultDataDirectory;
145
+ const filepath = this.getPathForInternalId(name, targetFolder);
146
+ try {
147
+ const content = await fs.promises.readFile(filepath, 'utf-8').then(JSON.parse);
148
+ return content;
149
+ }
150
+ catch (err) {
151
+ // TODO no eyes results for test - this is ok, could be that no visual tests occurred for this playwright test
152
+ }
114
153
  }
115
- catch (err) {
116
- // TODO no eyes results for test - this is ok, could be that no visual tests occurred for this playwright test
154
+ },
155
+ parseStdoutLine(identifier, stdoutData) {
156
+ const lines = stdoutData.split('\n');
157
+ const eyesLines = lines.filter(line => line.startsWith(`EYES_DATA:${identifier}:`));
158
+ const results = [];
159
+ for (const eyesLine of eyesLines) {
160
+ const jsonPart = eyesLine.replace(`EYES_DATA:${identifier}:`, '');
161
+ try {
162
+ const parsed = JSON.parse(jsonPart);
163
+ results.push(parsed);
164
+ }
165
+ catch (err) {
166
+ // Skip invalid JSON lines
167
+ continue;
168
+ }
117
169
  }
170
+ return results;
118
171
  },
119
- ensureFolder(folderPath = path.join('blob-report', 'eyes-report-files')) {
172
+ ensureFolder(folderPath = defaultDataDirectory) {
120
173
  if (!fs.existsSync(folderPath)) {
121
174
  fs.mkdirSync(folderPath, { recursive: true });
122
175
  }
123
176
  },
124
- getPathForInternalId(applitoolsIdentifier, folderPath = path.join('blob-report', 'eyes-report-files')) {
177
+ getPathForInternalId(applitoolsIdentifier, folderPath = defaultDataDirectory) {
125
178
  return path.join(folderPath, applitoolsIdentifier);
126
179
  },
127
180
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@applitools/eyes-playwright",
3
- "version": "1.38.1",
3
+ "version": "1.39.0",
4
4
  "description": "Applitools Eyes SDK for Playwright",
5
5
  "keywords": [
6
6
  "eyes-playwright",
@@ -59,9 +59,9 @@
59
59
  "up:framework": "echo \"$(jq '.devDependencies.playwright = $ENV.APPLITOOLS_FRAMEWORK_VERSION' ./package.json)\" > ./package.json"
60
60
  },
61
61
  "dependencies": {
62
- "@applitools/eyes": "1.35.2",
63
- "@applitools/spec-driver-playwright": "1.6.1",
64
- "@applitools/utils": "1.9.0",
62
+ "@applitools/eyes": "1.36.0",
63
+ "@applitools/spec-driver-playwright": "1.7.1",
64
+ "@applitools/utils": "1.11.0",
65
65
  "@inquirer/prompts": "7.0.1",
66
66
  "chalk": "4.1.2",
67
67
  "yargs": "17.7.2"
package/types/index.d.ts CHANGED
@@ -470,7 +470,7 @@ export type ConfigurationPlain = {
470
470
  baselineEnvName?: undefined | string;
471
471
  batch?: undefined | BatchInfoPlain;
472
472
  branchName?: undefined | string;
473
- browsersInfo?: undefined | Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { iosDeviceInfo: { deviceName: "iPhone X" | "iPhone 14 Plus" | "iPhone 14 Pro" | "iPhone XR" | "iPhone 11" | "iPhone 11 Pro Max" | "iPhone 11 Pro" | "iPhone SE (2nd generation)" | "iPhone SE (3rd generation)" | "iPhone Xs" | "iPhone 12" | "iPhone 12 mini" | "iPhone 12 Pro Max" | "iPhone 12 Pro" | "iPhone 13" | "iPhone 13 mini" | "iPhone 13 Pro Max" | "iPhone 13 Pro" | "iPhone 14" | "iPhone 14 Pro Max" | "iPhone 8" | "iPhone 8 Plus" | "iPhone Xs Max"; }; })>;
473
+ browsersInfo?: undefined | Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | IOSMultiDeviceInfo)>;
474
474
  captureStatusBar?: undefined | boolean;
475
475
  compareWithParentBranch?: undefined | boolean;
476
476
  concurrentSessions?: undefined | number;
@@ -564,9 +564,9 @@ export class Configuration implements Required<ConfigurationPlain> {
564
564
  set branchName(branchName: string);
565
565
  getBranchName(): string;
566
566
  setBranchName(branchName: string): Configuration;
567
- get browsersInfo(): Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { iosDeviceInfo: { deviceName: "iPhone X" | "iPhone 14 Plus" | "iPhone 14 Pro" | "iPhone XR" | "iPhone 11" | "iPhone 11 Pro Max" | "iPhone 11 Pro" | "iPhone SE (2nd generation)" | "iPhone SE (3rd generation)" | "iPhone Xs" | "iPhone 12" | "iPhone 12 mini" | "iPhone 12 Pro Max" | "iPhone 12 Pro" | "iPhone 13" | "iPhone 13 mini" | "iPhone 13 Pro Max" | "iPhone 13 Pro" | "iPhone 14" | "iPhone 14 Pro Max" | "iPhone 8" | "iPhone 8 Plus" | "iPhone Xs Max"; }; })>;
568
- set browsersInfo(browsersInfo: Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { iosDeviceInfo: { deviceName: "iPhone X" | "iPhone 14 Plus" | "iPhone 14 Pro" | "iPhone XR" | "iPhone 11" | "iPhone 11 Pro Max" | "iPhone 11 Pro" | "iPhone SE (2nd generation)" | "iPhone SE (3rd generation)" | "iPhone Xs" | "iPhone 12" | "iPhone 12 mini" | "iPhone 12 Pro Max" | "iPhone 12 Pro" | "iPhone 13" | "iPhone 13 mini" | "iPhone 13 Pro Max" | "iPhone 13 Pro" | "iPhone 14" | "iPhone 14 Pro Max" | "iPhone 8" | "iPhone 8 Plus" | "iPhone Xs Max"; }; })>);
569
- getBrowsersInfo(): Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { iosDeviceInfo: { deviceName: "iPhone X" | "iPhone 14 Plus" | "iPhone 14 Pro" | "iPhone XR" | "iPhone 11" | "iPhone 11 Pro Max" | "iPhone 11 Pro" | "iPhone SE (2nd generation)" | "iPhone SE (3rd generation)" | "iPhone Xs" | "iPhone 12" | "iPhone 12 mini" | "iPhone 12 Pro Max" | "iPhone 12 Pro" | "iPhone 13" | "iPhone 13 mini" | "iPhone 13 Pro Max" | "iPhone 13 Pro" | "iPhone 14" | "iPhone 14 Pro Max" | "iPhone 8" | "iPhone 8 Plus" | "iPhone Xs Max"; }; })>;
567
+ get browsersInfo(): Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | IOSMultiDeviceInfo)>;
568
+ set browsersInfo(browsersInfo: Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | IOSMultiDeviceInfo)>);
569
+ getBrowsersInfo(): Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | IOSMultiDeviceInfo)>;
570
570
  setBrowsersInfo(browsersInfo: Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { deviceName: DeviceNamePlain; screenOrientation?: undefined | ScreenOrientationPlain; })>): Configuration;
571
571
  addBrowsers(...browsersInfo: Array<(DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { deviceName: DeviceNamePlain; screenOrientation?: undefined | ScreenOrientationPlain; })>): Configuration;
572
572
  addBrowser(browserInfo: (DesktopBrowserInfo | ChromeEmulationInfo | IOSDeviceInfo | { deviceName: DeviceNamePlain; screenOrientation?: undefined | ScreenOrientationPlain; })): Configuration;
@@ -575,6 +575,7 @@ export class Configuration implements Required<ConfigurationPlain> {
575
575
  addMultiDeviceTarget(deviceName: "iPhone X"): Configuration;
576
576
  addMultiDeviceTarget(deviceName: "iPhone 14 Plus"): Configuration;
577
577
  addMultiDeviceTarget(deviceName: "iPhone 14 Pro"): Configuration;
578
+ addMultiDeviceTarget(deviceName: "iPhone 15 Pro"): Configuration;
578
579
  addMultiDeviceTarget(deviceName: "iPhone XR"): Configuration;
579
580
  addMultiDeviceTarget(deviceName: "iPhone 11"): Configuration;
580
581
  addMultiDeviceTarget(deviceName: "iPhone 11 Pro Max"): Configuration;
@@ -592,6 +593,18 @@ export class Configuration implements Required<ConfigurationPlain> {
592
593
  addMultiDeviceTarget(deviceName: "iPhone 13 Pro"): Configuration;
593
594
  addMultiDeviceTarget(deviceName: "iPhone 14"): Configuration;
594
595
  addMultiDeviceTarget(deviceName: "iPhone 14 Pro Max"): Configuration;
596
+ addMultiDeviceTarget(deviceName: "iPhone 15"): Configuration;
597
+ addMultiDeviceTarget(deviceName: "iPhone 15 Pro Max"): Configuration;
598
+ addMultiDeviceTarget(deviceName: "iPhone 15 Plus"): Configuration;
599
+ addMultiDeviceTarget(deviceName: "iPhone 16"): Configuration;
600
+ addMultiDeviceTarget(deviceName: "iPhone 16 Pro Max"): Configuration;
601
+ addMultiDeviceTarget(deviceName: "iPhone 16 Pro"): Configuration;
602
+ addMultiDeviceTarget(deviceName: "iPhone 16 Plus"): Configuration;
603
+ addMultiDeviceTarget(deviceName: "iPhone SE (1st generation)"): Configuration;
604
+ addMultiDeviceTarget(deviceName: "iPhone 6"): Configuration;
605
+ addMultiDeviceTarget(deviceName: "iPhone 6 Plus"): Configuration;
606
+ addMultiDeviceTarget(deviceName: "iPhone 7"): Configuration;
607
+ addMultiDeviceTarget(deviceName: "iPhone 7 Plus"): Configuration;
595
608
  addMultiDeviceTarget(deviceName: "iPhone 8"): Configuration;
596
609
  addMultiDeviceTarget(deviceName: "iPhone 8 Plus"): Configuration;
597
610
  addMultiDeviceTarget(deviceName: "iPhone Xs Max"): Configuration;
@@ -1615,6 +1628,7 @@ export class Region implements Required<RegionPlain> {
1615
1628
  export type DesktopBrowserInfo = { name?: undefined | BrowserTypePlain; width: number; height: number; };
1616
1629
  export type ChromeEmulationInfo = { chromeEmulationInfo: { deviceName: DeviceNamePlain; screenOrientation?: undefined | ScreenOrientationPlain; }; };
1617
1630
  export type IOSDeviceInfo = { iosDeviceInfo: { deviceName: IosDeviceNamePlain; iosVersion?: undefined | IosVersionPlain; screenOrientation?: undefined | ScreenOrientationPlain; }; };
1631
+ export type IOSMultiDeviceInfo = { iosDeviceInfo: { deviceName: "iPhone X" | "iPhone 14 Plus" | "iPhone 14 Pro" | "iPhone 15 Pro" | "iPhone XR" | "iPhone 11" | "iPhone 11 Pro Max" | "iPhone 11 Pro" | "iPhone SE (2nd generation)" | "iPhone SE (3rd generation)" | "iPhone Xs" | "iPhone 12" | "iPhone 12 mini" | "iPhone 12 Pro Max" | "iPhone 12 Pro" | "iPhone 13" | "iPhone 13 mini" | "iPhone 13 Pro Max" | "iPhone 13 Pro" | "iPhone 14" | "iPhone 14 Pro Max" | "iPhone 15" | "iPhone 15 Pro Max" | "iPhone 15 Plus" | "iPhone 16" | "iPhone 16 Pro Max" | "iPhone 16 Pro" | "iPhone 16 Plus" | "iPhone SE (1st generation)" | "iPhone 6" | "iPhone 6 Plus" | "iPhone 7" | "iPhone 7 Plus" | "iPhone 8" | "iPhone 8 Plus" | "iPhone Xs Max"; }; };
1618
1632
  export type RunnerOptionsPlain = { testConcurrency?: undefined | number; fetchConcurrency?: undefined | number; removeDuplicateTests?: undefined | boolean; maskLog?: undefined | boolean; };
1619
1633
  export class RunnerOptionsFluent {
1620
1634
  testConcurrency(concurrency: number): RunnerOptionsFluent;