@chromatic-com/cypress 0.12.5 → 0.12.7

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/dist/index.js CHANGED
@@ -5,6 +5,7 @@ var path2 = require('path');
5
5
  var fs = require('fs');
6
6
  var promises = require('fs/promises');
7
7
  var crypto = require('crypto');
8
+ var csf = require('storybook/internal/csf');
8
9
  var analyticsNode = require('@segment/analytics-node');
9
10
 
10
11
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
@@ -3393,7 +3394,7 @@ var logger = process.env.LOG ? console : {
3393
3394
 
3394
3395
  // ../shared/src/resource-archiver/index.ts
3395
3396
  var _ResourceArchiver = class _ResourceArchiver {
3396
- constructor(cdpClient, allowedDomains, httpCredentials) {
3397
+ constructor(cdpClient, allowedDomains, httpCredentials, firstUrl) {
3397
3398
  __publicField(this, "archive", {});
3398
3399
  __publicField(this, "client");
3399
3400
  /**
@@ -3467,6 +3468,7 @@ var _ResourceArchiver = class _ResourceArchiver {
3467
3468
  }, "requestPaused"));
3468
3469
  this.client = cdpClient;
3469
3470
  this.httpCredentials = httpCredentials;
3471
+ this.firstUrl = firstUrl;
3470
3472
  this.assetDomains = (allowedDomains || []).map((domain) => {
3471
3473
  if (domain.startsWith("http")) {
3472
3474
  return domain;
@@ -3526,12 +3528,25 @@ var _ResourceArchiver = class _ResourceArchiver {
3526
3528
  const contentTypeHeader = responseHeaders.find(({ name }) => name.toLowerCase() === "content-type");
3527
3529
  const isFirstRequest = requestUrl.toString() === this.firstUrl.toString();
3528
3530
  if (isRequestFromAllowedDomain && !isFirstRequest) {
3531
+ logger.log("Archiving request", {
3532
+ url: request.url,
3533
+ statusCode: responseStatusCode,
3534
+ statusText: responseStatusText,
3535
+ contentType: contentTypeHeader?.value
3536
+ });
3529
3537
  this.archive[request.url] = {
3530
3538
  statusCode: responseStatusCode,
3531
3539
  statusText: responseStatusText,
3532
3540
  body: Buffer.from(body, base64Encoded ? "base64" : "utf8"),
3533
3541
  contentType: contentTypeHeader?.value
3534
3542
  };
3543
+ } else {
3544
+ logger.log("Skipping archiving of request", {
3545
+ url: request.url,
3546
+ firstUrl: this.firstUrl.toString(),
3547
+ isFirstRequest,
3548
+ isRequestFromAllowedDomain
3549
+ });
3535
3550
  }
3536
3551
  await this.clientSend(request, "Fetch.continueRequest", {
3537
3552
  requestId
@@ -3794,8 +3809,7 @@ var _DOMSnapshot = class _DOMSnapshot {
3794
3809
  const currentSrc = this.mapSrcsetUrls(srcsetValue, sourceMap);
3795
3810
  if (currentSrc) {
3796
3811
  node.attributes.src = currentSrc;
3797
- delete node.attributes.srcset;
3798
- delete node.attributes.sizes;
3812
+ this.removeResponsiveImageAttributes(node.attributes);
3799
3813
  }
3800
3814
  }
3801
3815
  if (node.tagName === "picture") {
@@ -3820,6 +3834,7 @@ var _DOMSnapshot = class _DOMSnapshot {
3820
3834
  const imageElement = node.childNodes.find((childNode) => childNode.type === NodeType.Element && childNode.tagName === "img");
3821
3835
  if (imageElement && imageElement.attributes) {
3822
3836
  imageElement.attributes.src = sourceMap.get(matchingUrl);
3837
+ this.removeResponsiveImageAttributes(imageElement.attributes);
3823
3838
  }
3824
3839
  }
3825
3840
  }
@@ -3854,6 +3869,10 @@ var _DOMSnapshot = class _DOMSnapshot {
3854
3869
  });
3855
3870
  return currentSrc;
3856
3871
  }
3872
+ removeResponsiveImageAttributes(attributes) {
3873
+ delete attributes.srcset;
3874
+ delete attributes.sizes;
3875
+ }
3857
3876
  };
3858
3877
  __name(_DOMSnapshot, "DOMSnapshot");
3859
3878
  var DOMSnapshot = _DOMSnapshot;
@@ -3868,6 +3887,7 @@ __name(viewportToString, "viewportToString");
3868
3887
  var sanitize = /* @__PURE__ */ __name((string) => {
3869
3888
  return string.toLowerCase().replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "-").replace(/[\r\n]/g, "-").replace(/-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
3870
3889
  }, "sanitize");
3890
+ var collapseNewlines = /* @__PURE__ */ __name((title) => title.replace(/[\r\n]+/g, " ").trim(), "collapseNewlines");
3871
3891
 
3872
3892
  // ../shared/src/write-archive/snapshot-files.ts
3873
3893
  var SNAPSHOT_FILE_EXT = "snapshot.json";
@@ -3886,49 +3906,60 @@ function snapshotFileName(snapshotId2, viewport) {
3886
3906
  return fileNameParts.join(".");
3887
3907
  }
3888
3908
  __name(snapshotFileName, "snapshotFileName");
3889
-
3890
- // ../shared/src/write-archive/stories-files.ts
3891
3909
  var STORIES_FILE_EXT = "stories.json";
3910
+ var uniqueId = {
3911
+ value: 1
3912
+ };
3892
3913
  function storiesFileName(testTitle) {
3893
3914
  const fileName = [
3894
- sanitize(testTitle),
3915
+ sanitize(testTitle) + "-" + uniqueId.value++,
3895
3916
  STORIES_FILE_EXT
3896
3917
  ].join(".");
3897
3918
  const maxByteLength = MAX_FILE_NAME_BYTE_LENGTH - 25;
3898
3919
  return truncateFileName(fileName, maxByteLength);
3899
3920
  }
3900
3921
  __name(storiesFileName, "storiesFileName");
3901
- function createStories(title, domSnapshots, chromaticStorybookParams) {
3922
+ function createStories(storyTitle, domSnapshots, chromaticStorybookParams) {
3923
+ const title = collapseNewlines(storyTitle);
3902
3924
  return {
3903
3925
  title,
3904
- stories: Object.entries(domSnapshots).map(([name, { viewport }]) => ({
3905
- name,
3906
- // Viewport addon (Storybook 10+): `parameters.viewport.options` registers sizes; `globals.viewport`
3907
- // selects the active one. See https://storybook.js.org/docs/essentials/viewport#defining-the-viewport-for-a-story
3908
- // `defaultViewport` is not read by SB 10's types but our archive preview uses it as a fetch fallback.
3909
- globals: {
3910
- viewport: viewportToString(viewport)
3911
- },
3912
- parameters: {
3913
- server: {
3914
- id: snapshotId(title, name)
3915
- },
3916
- chromatic: {
3917
- ...chromaticStorybookParams,
3918
- modes: buildStoryModesConfig([
3919
- viewport
3920
- ])
3926
+ stories: Object.entries(domSnapshots).map(([snapshotName, { viewport, parameters }]) => {
3927
+ const name = collapseNewlines(snapshotName);
3928
+ const { chromatic: chromaticParams, ...restParameters } = parameters || {};
3929
+ return {
3930
+ name,
3931
+ // Viewport addon (Storybook 10+): `parameters.viewport.options` registers sizes; `globals.viewport`
3932
+ // selects the active one. See https://storybook.js.org/docs/essentials/viewport#defining-the-viewport-for-a-story
3933
+ // `defaultViewport` is not read by SB 10's types but our archive preview uses it as a fetch fallback.
3934
+ globals: {
3935
+ viewport: viewportToString(viewport)
3921
3936
  },
3922
- viewport: {
3923
- options: buildStoryViewportsConfig([
3924
- viewport
3925
- ]),
3926
- defaultViewport: viewportToString(findDefaultViewport([
3927
- viewport
3928
- ]))
3937
+ parameters: {
3938
+ // Work-around for cases where "あ" in story name would cause Storybook to fail to load the story due to an invalid story ID.
3939
+ // See https://github.com/chromaui/chromatic-e2e/issues/365
3940
+ __id: csf.toId(title, csf.storyNameFromExport(name)),
3941
+ server: {
3942
+ id: snapshotId(title, name)
3943
+ },
3944
+ chromatic: {
3945
+ ...chromaticStorybookParams,
3946
+ ...chromaticParams,
3947
+ modes: buildStoryModesConfig([
3948
+ viewport
3949
+ ])
3950
+ },
3951
+ viewport: {
3952
+ options: buildStoryViewportsConfig([
3953
+ viewport
3954
+ ]),
3955
+ defaultViewport: viewportToString(findDefaultViewport([
3956
+ viewport
3957
+ ]))
3958
+ },
3959
+ ...restParameters
3929
3960
  }
3930
- }
3931
- }))
3961
+ };
3962
+ })
3932
3963
  };
3933
3964
  }
3934
3965
  __name(createStories, "createStories");
@@ -4003,10 +4034,13 @@ async function writeTestResult(e2eTestInfo, domSnapshots, archive, chromaticStor
4003
4034
  const archiveFile = new ArchiveFile(url, response, pageUrl);
4004
4035
  const origSrcPath = archiveFile.originalSrc();
4005
4036
  const fileSystemPath = archiveFile.toFileSystemPath();
4037
+ const responsePath = path2.join(archiveDir, fileSystemPath);
4006
4038
  if (origSrcPath !== fileSystemPath) {
4007
4039
  sourceMap.set(origSrcPath, fileSystemPath);
4008
4040
  }
4009
- await outputFile(path2.join(archiveDir, fileSystemPath), response.body);
4041
+ if (!fs.existsSync(responsePath)) {
4042
+ await outputFile(responsePath, response.body);
4043
+ }
4010
4044
  }));
4011
4045
  await Promise.all(Object.entries(domSnapshots).map(async ([name, domSnapshot]) => {
4012
4046
  const snapshot = new DOMSnapshot(domSnapshot);
package/dist/index.mjs CHANGED
@@ -3,6 +3,7 @@ import path2, { join } from 'path';
3
3
  import { existsSync, mkdirSync } from 'fs';
4
4
  import { writeFile } from 'fs/promises';
5
5
  import { createHash } from 'crypto';
6
+ import { toId, storyNameFromExport } from 'storybook/internal/csf';
6
7
  import { Analytics } from '@segment/analytics-node';
7
8
 
8
9
  var __create = Object.create;
@@ -3386,7 +3387,7 @@ var logger = process.env.LOG ? console : {
3386
3387
 
3387
3388
  // ../shared/src/resource-archiver/index.ts
3388
3389
  var _ResourceArchiver = class _ResourceArchiver {
3389
- constructor(cdpClient, allowedDomains, httpCredentials) {
3390
+ constructor(cdpClient, allowedDomains, httpCredentials, firstUrl) {
3390
3391
  __publicField(this, "archive", {});
3391
3392
  __publicField(this, "client");
3392
3393
  /**
@@ -3460,6 +3461,7 @@ var _ResourceArchiver = class _ResourceArchiver {
3460
3461
  }, "requestPaused"));
3461
3462
  this.client = cdpClient;
3462
3463
  this.httpCredentials = httpCredentials;
3464
+ this.firstUrl = firstUrl;
3463
3465
  this.assetDomains = (allowedDomains || []).map((domain) => {
3464
3466
  if (domain.startsWith("http")) {
3465
3467
  return domain;
@@ -3519,12 +3521,25 @@ var _ResourceArchiver = class _ResourceArchiver {
3519
3521
  const contentTypeHeader = responseHeaders.find(({ name }) => name.toLowerCase() === "content-type");
3520
3522
  const isFirstRequest = requestUrl.toString() === this.firstUrl.toString();
3521
3523
  if (isRequestFromAllowedDomain && !isFirstRequest) {
3524
+ logger.log("Archiving request", {
3525
+ url: request.url,
3526
+ statusCode: responseStatusCode,
3527
+ statusText: responseStatusText,
3528
+ contentType: contentTypeHeader?.value
3529
+ });
3522
3530
  this.archive[request.url] = {
3523
3531
  statusCode: responseStatusCode,
3524
3532
  statusText: responseStatusText,
3525
3533
  body: Buffer.from(body, base64Encoded ? "base64" : "utf8"),
3526
3534
  contentType: contentTypeHeader?.value
3527
3535
  };
3536
+ } else {
3537
+ logger.log("Skipping archiving of request", {
3538
+ url: request.url,
3539
+ firstUrl: this.firstUrl.toString(),
3540
+ isFirstRequest,
3541
+ isRequestFromAllowedDomain
3542
+ });
3528
3543
  }
3529
3544
  await this.clientSend(request, "Fetch.continueRequest", {
3530
3545
  requestId
@@ -3787,8 +3802,7 @@ var _DOMSnapshot = class _DOMSnapshot {
3787
3802
  const currentSrc = this.mapSrcsetUrls(srcsetValue, sourceMap);
3788
3803
  if (currentSrc) {
3789
3804
  node.attributes.src = currentSrc;
3790
- delete node.attributes.srcset;
3791
- delete node.attributes.sizes;
3805
+ this.removeResponsiveImageAttributes(node.attributes);
3792
3806
  }
3793
3807
  }
3794
3808
  if (node.tagName === "picture") {
@@ -3813,6 +3827,7 @@ var _DOMSnapshot = class _DOMSnapshot {
3813
3827
  const imageElement = node.childNodes.find((childNode) => childNode.type === NodeType.Element && childNode.tagName === "img");
3814
3828
  if (imageElement && imageElement.attributes) {
3815
3829
  imageElement.attributes.src = sourceMap.get(matchingUrl);
3830
+ this.removeResponsiveImageAttributes(imageElement.attributes);
3816
3831
  }
3817
3832
  }
3818
3833
  }
@@ -3847,6 +3862,10 @@ var _DOMSnapshot = class _DOMSnapshot {
3847
3862
  });
3848
3863
  return currentSrc;
3849
3864
  }
3865
+ removeResponsiveImageAttributes(attributes) {
3866
+ delete attributes.srcset;
3867
+ delete attributes.sizes;
3868
+ }
3850
3869
  };
3851
3870
  __name(_DOMSnapshot, "DOMSnapshot");
3852
3871
  var DOMSnapshot = _DOMSnapshot;
@@ -3861,6 +3880,7 @@ __name(viewportToString, "viewportToString");
3861
3880
  var sanitize = /* @__PURE__ */ __name((string) => {
3862
3881
  return string.toLowerCase().replace(/[ ’–—―′¿'`~!@#$%^&*()_|+\-=?;:'",.<>\{\}\[\]\\\/]/gi, "-").replace(/[\r\n]/g, "-").replace(/-+/g, "-").replace(/^-+/, "").replace(/-+$/, "");
3863
3882
  }, "sanitize");
3883
+ var collapseNewlines = /* @__PURE__ */ __name((title) => title.replace(/[\r\n]+/g, " ").trim(), "collapseNewlines");
3864
3884
 
3865
3885
  // ../shared/src/write-archive/snapshot-files.ts
3866
3886
  var SNAPSHOT_FILE_EXT = "snapshot.json";
@@ -3879,49 +3899,60 @@ function snapshotFileName(snapshotId2, viewport) {
3879
3899
  return fileNameParts.join(".");
3880
3900
  }
3881
3901
  __name(snapshotFileName, "snapshotFileName");
3882
-
3883
- // ../shared/src/write-archive/stories-files.ts
3884
3902
  var STORIES_FILE_EXT = "stories.json";
3903
+ var uniqueId = {
3904
+ value: 1
3905
+ };
3885
3906
  function storiesFileName(testTitle) {
3886
3907
  const fileName = [
3887
- sanitize(testTitle),
3908
+ sanitize(testTitle) + "-" + uniqueId.value++,
3888
3909
  STORIES_FILE_EXT
3889
3910
  ].join(".");
3890
3911
  const maxByteLength = MAX_FILE_NAME_BYTE_LENGTH - 25;
3891
3912
  return truncateFileName(fileName, maxByteLength);
3892
3913
  }
3893
3914
  __name(storiesFileName, "storiesFileName");
3894
- function createStories(title, domSnapshots, chromaticStorybookParams) {
3915
+ function createStories(storyTitle, domSnapshots, chromaticStorybookParams) {
3916
+ const title = collapseNewlines(storyTitle);
3895
3917
  return {
3896
3918
  title,
3897
- stories: Object.entries(domSnapshots).map(([name, { viewport }]) => ({
3898
- name,
3899
- // Viewport addon (Storybook 10+): `parameters.viewport.options` registers sizes; `globals.viewport`
3900
- // selects the active one. See https://storybook.js.org/docs/essentials/viewport#defining-the-viewport-for-a-story
3901
- // `defaultViewport` is not read by SB 10's types but our archive preview uses it as a fetch fallback.
3902
- globals: {
3903
- viewport: viewportToString(viewport)
3904
- },
3905
- parameters: {
3906
- server: {
3907
- id: snapshotId(title, name)
3908
- },
3909
- chromatic: {
3910
- ...chromaticStorybookParams,
3911
- modes: buildStoryModesConfig([
3912
- viewport
3913
- ])
3919
+ stories: Object.entries(domSnapshots).map(([snapshotName, { viewport, parameters }]) => {
3920
+ const name = collapseNewlines(snapshotName);
3921
+ const { chromatic: chromaticParams, ...restParameters } = parameters || {};
3922
+ return {
3923
+ name,
3924
+ // Viewport addon (Storybook 10+): `parameters.viewport.options` registers sizes; `globals.viewport`
3925
+ // selects the active one. See https://storybook.js.org/docs/essentials/viewport#defining-the-viewport-for-a-story
3926
+ // `defaultViewport` is not read by SB 10's types but our archive preview uses it as a fetch fallback.
3927
+ globals: {
3928
+ viewport: viewportToString(viewport)
3914
3929
  },
3915
- viewport: {
3916
- options: buildStoryViewportsConfig([
3917
- viewport
3918
- ]),
3919
- defaultViewport: viewportToString(findDefaultViewport([
3920
- viewport
3921
- ]))
3930
+ parameters: {
3931
+ // Work-around for cases where "あ" in story name would cause Storybook to fail to load the story due to an invalid story ID.
3932
+ // See https://github.com/chromaui/chromatic-e2e/issues/365
3933
+ __id: toId(title, storyNameFromExport(name)),
3934
+ server: {
3935
+ id: snapshotId(title, name)
3936
+ },
3937
+ chromatic: {
3938
+ ...chromaticStorybookParams,
3939
+ ...chromaticParams,
3940
+ modes: buildStoryModesConfig([
3941
+ viewport
3942
+ ])
3943
+ },
3944
+ viewport: {
3945
+ options: buildStoryViewportsConfig([
3946
+ viewport
3947
+ ]),
3948
+ defaultViewport: viewportToString(findDefaultViewport([
3949
+ viewport
3950
+ ]))
3951
+ },
3952
+ ...restParameters
3922
3953
  }
3923
- }
3924
- }))
3954
+ };
3955
+ })
3925
3956
  };
3926
3957
  }
3927
3958
  __name(createStories, "createStories");
@@ -3996,10 +4027,13 @@ async function writeTestResult(e2eTestInfo, domSnapshots, archive, chromaticStor
3996
4027
  const archiveFile = new ArchiveFile(url, response, pageUrl);
3997
4028
  const origSrcPath = archiveFile.originalSrc();
3998
4029
  const fileSystemPath = archiveFile.toFileSystemPath();
4030
+ const responsePath = join(archiveDir, fileSystemPath);
3999
4031
  if (origSrcPath !== fileSystemPath) {
4000
4032
  sourceMap.set(origSrcPath, fileSystemPath);
4001
4033
  }
4002
- await outputFile(join(archiveDir, fileSystemPath), response.body);
4034
+ if (!existsSync(responsePath)) {
4035
+ await outputFile(responsePath, response.body);
4036
+ }
4003
4037
  }));
4004
4038
  await Promise.all(Object.entries(domSnapshots).map(async ([name, domSnapshot]) => {
4005
4039
  const snapshot = new DOMSnapshot(domSnapshot);
@@ -12,6 +12,9 @@ declare const _default: {
12
12
  renderer: string;
13
13
  };
14
14
  staticDirs: string[];
15
+ features: {
16
+ sidebarOnboardingChecklist: boolean;
17
+ };
15
18
  };
16
19
 
17
20
  export { _default as default };
@@ -47,7 +47,10 @@ var main_default = {
47
47
  },
48
48
  staticDirs: [
49
49
  path2.resolve(archivesDir(DEFAULT_OUTPUT_DIR), "archive")
50
- ]
50
+ ],
51
+ features: {
52
+ sidebarOnboardingChecklist: false
53
+ }
51
54
  };
52
55
 
53
56
  export { main_default as default };
@@ -3,7 +3,13 @@ import { addons } from 'storybook/manager-api';
3
3
  // ../shared/storybook-config/manager.ts
4
4
  addons.setConfig({
5
5
  sidebar: {
6
- // this ensures we use folders at the root-level instead of categories
6
+ // Ensures we use folders at the root-level instead of categories
7
7
  showRoots: false
8
+ },
9
+ layoutCustomisations: {
10
+ // Hide toolbar options that don't make sense in e2e setup
11
+ showToolbar: () => false,
12
+ // Hide bottom panel that's empty in e2e setup
13
+ showPanel: () => false
8
14
  }
9
15
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chromatic-com/cypress",
3
- "version": "0.12.5",
3
+ "version": "0.12.7",
4
4
  "description": "Chromatic Visual Regression Testing for Cypress",
5
5
  "repository": {
6
6
  "type": "git",