@chromatic-com/storybook 0.0.124
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/LICENSE +21 -0
- package/README.md +91 -0
- package/dist/index.d.ts +19 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +13 -0
- package/dist/index.mjs.map +1 -0
- package/dist/manager.mjs +292 -0
- package/dist/manager.mjs.map +1 -0
- package/jest.config.js +5 -0
- package/package.json +161 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Storybook contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Storybook Visual Testing addon
|
|
2
|
+
|
|
3
|
+
The Visual Testing addon enables you to run visual tests on your stories and compare changes with the latest baselines across multiple viewports and browsers to catch UI regressions early in development without leaving Storybook.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
- Chromatic [account configured](https://www.chromatic.com/docs/setup#sign-up) with access to a project
|
|
8
|
+
- Storybook 7.2 or later
|
|
9
|
+
|
|
10
|
+
## Getting Started
|
|
11
|
+
|
|
12
|
+
Run the following command to install the addon and automatically configure it for your project via Storybook's CLI:
|
|
13
|
+
|
|
14
|
+
```shell
|
|
15
|
+
npx storybook add @chromatic-com/storybook
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
Start Storybook and navigate to the Visual Tests panel to run your first visual test with Chromatic!
|
|
19
|
+
|
|
20
|
+
## Configuration
|
|
21
|
+
|
|
22
|
+
By default, the addon offers zero-config support to run visual tests with Storybook and Chromatic. However, you can extend your Storybook configuration file (i.e., `.storybook/main.js|ts`) and provide additional options to control how tests are run. Listed below are the available options and examples of how to use them.
|
|
23
|
+
|
|
24
|
+
| Option | Description |
|
|
25
|
+
| ----------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
|
|
26
|
+
| `buildScriptName` | Optional. Defines the custom Storybook build script <br/> `options: { buildScriptName: 'deploy-storybook' }` |
|
|
27
|
+
| `debug` | Optional. Output verbose debugging information to the console. <br/> `options: { debug: true }` |
|
|
28
|
+
| `projectId` | Automatically configured. Sets the value for the project identifier <br/> `options: { projectId: Project:64cbcde96f99841e8b007d75 }` |
|
|
29
|
+
| `zip` | Recommended for large projects. Configures the addon to deploy your Storybook to Chromatic as a zip file. <br/> `options: { zip: true }` |
|
|
30
|
+
|
|
31
|
+
```ts
|
|
32
|
+
// .storybook/main.ts
|
|
33
|
+
|
|
34
|
+
// Replace your-framework with the framework you are using (e.g., react-webpack5, vue3-vite)
|
|
35
|
+
import type { StorybookConfig } from "@storybook/your-framework";
|
|
36
|
+
|
|
37
|
+
const config: StorybookConfig = {
|
|
38
|
+
framework: "@storybook/your-framework",
|
|
39
|
+
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
|
|
40
|
+
addons: [
|
|
41
|
+
// Other Storybook addons
|
|
42
|
+
"@chromatic-com/storybook",
|
|
43
|
+
{
|
|
44
|
+
name: "@chromatic-com/storybook",
|
|
45
|
+
options: {
|
|
46
|
+
projectId: "Project:64cbcde96f99841e8b007d75",
|
|
47
|
+
buildScriptName: "build-storybook",
|
|
48
|
+
zip: true,
|
|
49
|
+
debug: true,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
export default config;
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Updating the GraphQL schema
|
|
59
|
+
|
|
60
|
+
The addon uses the Chromatic public GraphQL API. We rely on its schema to generate type definitions. The schema needs to be manually updated whenever it changes.
|
|
61
|
+
To update, take https://github.com/chromaui/chromatic/blob/main/lib/schema/public-schema.graphql and save it under `src/gql/public-schema.graphql`.
|
|
62
|
+
|
|
63
|
+
## Troubleshooting
|
|
64
|
+
|
|
65
|
+
### Running Storybook with the addon enabled throws an error
|
|
66
|
+
|
|
67
|
+
When installed, running Storybook may lead to the following error:
|
|
68
|
+
|
|
69
|
+
```shell
|
|
70
|
+
const stringWidth = require('string-width');
|
|
71
|
+
|
|
72
|
+
Error [ERR_REQUIRE_ESM]: require() of ES Module /my-project/node_modules/string-width/index.js is not supported.
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
This is a [known issue](https://github.com/storybookjs/storybook/issues/22431#issuecomment-1630086092) when using an older version of the Yarn package manager (e.g., version 1.x). To solve this issue, you can [upgrade](https://yarnpkg.com/migration/guide) to the latest stable version. However, if you cannot upgrade, adjust your `package.json` file and provide a resolution field to enable the Yarn package manager to install the correct dependencies. In doing so, you may be required to delete your `node_modules` directory and `yarn.lock` file before installing the dependencies again.
|
|
76
|
+
|
|
77
|
+
```json
|
|
78
|
+
"resolutions": {
|
|
79
|
+
"jackspeak": "2.1.1"
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Alternatively, you could use a different package manager ([npm](https://www.npmjs.com/), [pnpm](https://pnpm.io/installation)).
|
|
84
|
+
|
|
85
|
+
## Contributing
|
|
86
|
+
|
|
87
|
+
We welcome contributions to the Storybook Addon Visual Tests! If you're a maintainer, refer to the following [instructions](./Development.md) to set up your development environment with Chromatic.
|
|
88
|
+
|
|
89
|
+
### License
|
|
90
|
+
|
|
91
|
+
[MIT](https://github.com/storybookjs/addon-coverage/blob/main/LICENSE)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { Channel } from '@storybook/channels';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* to load the built addon in this test Storybook
|
|
5
|
+
*/
|
|
6
|
+
declare function managerEntries(entry?: string[]): string[];
|
|
7
|
+
declare function serverChannel(channel: Channel, { configDir, configFile }: {
|
|
8
|
+
configDir: string;
|
|
9
|
+
configFile?: string;
|
|
10
|
+
}): Promise<Channel>;
|
|
11
|
+
declare const config: {
|
|
12
|
+
managerEntries: typeof managerEntries;
|
|
13
|
+
experimental_serverChannel: typeof serverChannel;
|
|
14
|
+
env: (env: Record<string, string>, { configType }: {
|
|
15
|
+
configType: "DEVELOPMENT" | "PRODUCTION";
|
|
16
|
+
}) => Promise<Record<string, string>>;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export { config as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var node = require('chromatic/node');
|
|
4
|
+
var filesize = require('filesize');
|
|
5
|
+
var jsonfile = require('jsonfile');
|
|
6
|
+
|
|
7
|
+
var _=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,e)=>(typeof require<"u"?require:r)[e]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var {CHROMATIC_INDEX_URL:F,CHROMATIC_BASE_URL:T=F||"https://www.chromatic.com",CHROMATIC_API_URL:Q=`${T}/api`}=process.env,c="chromaui/addon-visual-tests",v=`${c}/gitInfo`,y=`${c}/gitInfoError`,D=`${c}/projectInfo`,O=`${c}/startBuild`,B=`${c}/stopBuild`,L=`${c}/localBuildProgress`;var h=t=>f.includes(t),R=t=>["upload","snapshot"].includes(t),f=["initialize","build","upload","verify","snapshot"],b={initialize:{key:"initialize",emoji:"\u{1F680}",renderName:()=>"Initialize build",renderProgress:()=>"Initializing build",renderComplete:()=>"Initialized",estimateDuration:2e3},build:{key:"build",emoji:"\u{1F3D7}",renderName:()=>"Build Storybook",renderProgress:()=>"Building your Storybook...",renderComplete:()=>"Storybook built",estimateDuration:3e4},upload:{key:"upload",emoji:"\u{1F4E1}",renderName:()=>"Publish your Storybook",renderProgress:({stepProgress:t})=>{let{numerator:r,denominator:e}=t.upload;if(!e||!r)return "Uploading files";let{value:o,exponent:n}=filesize.filesize(e,{output:"object",round:1}),{value:i,symbol:a}=filesize.filesize(r,{exponent:n,output:"object",round:1});return `Uploading files (${i}/${o} ${a})`},renderComplete:()=>"Publish complete",estimateDuration:3e4},verify:{key:"verify",emoji:"\u{1F50D}",renderName:()=>"Verify your Storybook",renderProgress:()=>"Verifying contents...",renderComplete:()=>"Storybook verified",estimateDuration:1e4},snapshot:{key:"snapshot",emoji:"\u{1F4F8}",renderName:()=>"Run visual tests",renderProgress:({stepProgress:t})=>{let{numerator:r,denominator:e}=t.snapshot;return e?`Running visual tests (${r}/${e})`:"Running visual tests"},renderComplete:()=>"Tested your stories",estimateDuration:6e4},aborted:{key:"aborted",emoji:"\u270B",renderName:()=>"Build canceled",renderProgress:()=>"Build canceled",renderComplete:()=>"Build canceled",estimateDuration:0},complete:{key:"complete",emoji:"\u{1F389}",renderName:()=>"Visual tests completed!",renderProgress:()=>"Visual tests completed!",renderComplete:()=>"Visual tests completed!",estimateDuration:0},error:{key:"error",emoji:"\u{1F6A8}",renderName:()=>"Build failed",renderProgress:()=>"Build failed",renderComplete:()=>"Build failed",estimateDuration:0}},k={buildProgressPercentage:0,currentStep:f[0],stepProgress:Object.fromEntries(f.map(t=>[t,{}]))};var x=2e3,I,V=(t,r)=>{if(!h(t))throw new Error(`Unknown step: ${t}`);let e=f.map(d=>{let{startedAt:s,completedAt:l}=r?.[d]||{};return s&&l?l-s:b[d].estimateDuration}),o=e.reduce((d,s)=>d+s,0),n=f.indexOf(t),i=e.slice(0,n).reduce((d,s)=>d+s,0),a=i+e[n],u=i/o*100,m=a/o*100;return {...b[t],startPercentage:u,endPercentage:m,stepPercentage:m-u}},S=(t,r)=>({...e},{progress:o,total:n}={})=>{if(clearTimeout(r),!h(e.task))return;if(!t.value)throw new Error("Unexpected missing value for localBuildProgress");let{buildProgressPercentage:i,stepProgress:a,previousBuildProgress:u}=t.value,{startPercentage:m,endPercentage:d,stepPercentage:s}=V(e.task,u),l=m;if(o&&n&&(l+=s*(o/n)),!R(e.task)){let{estimateDuration:g}=b[e.task],G=f.indexOf(e.task);l=Math.max(l,i)+x/g*s,r=setTimeout(()=>{if(!t.value)throw new Error("Unexpected missing value for localBuildProgress");let{currentStep:E}=t.value;h(E)&&f.indexOf(E)<=G&&S(t,r)(e);},x);}a[e.task]={startedAt:Date.now(),...a[e.task],...o&&n&&{numerator:o,denominator:n}},t.value={buildId:e.announcedBuild?.id,branch:e.git?.branch,buildProgressPercentage:Math.min(l,d),currentStep:e.task,stepProgress:a};},A=(t,r)=>(e,o)=>{if(clearTimeout(r),!t.value)throw new Error("Unexpected missing value for localBuildProgress");let{buildProgressPercentage:n,stepProgress:i}=t.value;if(o){t.value={buildId:e.announcedBuild?.id,branch:e.git?.branch,buildProgressPercentage:n,currentStep:I?.signal.aborted?"aborted":"error",stepProgress:i,formattedError:o.formattedError,originalError:o.originalError,previousBuildProgress:i};return}e.task&&h(e.task)&&(i[e.task]={...i[e.task],completedAt:Date.now()}),e.build&&e.task==="snapshot"&&(t.value={buildId:e.announcedBuild?.id,branch:e.git?.branch,buildProgressPercentage:100,currentStep:"complete",stepProgress:i,changeCount:e.build.changeCount,errorCount:e.build.errorCount,previousBuildProgress:i});},N=async(t,r)=>{if(!r.projectId)throw new Error("Missing projectId");if(!r.userToken)throw new Error("Missing userToken");t.value=k;let e;I?.abort(),I=new AbortController,process.env.SB_TESTBUILD="true",await node.run({options:{...r,autoAcceptChanges:!1,exitOnceUploaded:!1,exitZeroOnChanges:!0,forceRebuild:!0,fromCI:!1,isLocalBuild:!0,skip:!1,experimental_onTaskStart:S(t,e),experimental_onTaskProgress:S(t,e),experimental_onTaskComplete:A(t,e),experimental_onTaskError:A(t,e),experimental_abortSignal:I?.signal}});},U=()=>{I?.abort(new Error("Build canceled from Storybook"));};var j="experimental_useSharedState_getValue",P="experimental_useSharedState_setValue",C=new Map,p=class{constructor(r){this.channel=r,this.listeners=[],this.state={},this.channel.on(P,(e,o,n)=>{this.state?.[e]?.index>=n||(this.state[e]={index:n,value:o});}),this.channel.on(j,e=>{let o=this.state[e]?.index??0,n=this.state[e]?.value;this.channel.emit(P,e,n,o);});}get(r){return this.state[r]||this.channel.emit(j,r),this.state[r]?.value}set(r,e){let o=(this.state[r]?.index??0)+1;this.state[r]={index:o,value:e},this.channel.emit(P,r,e,o);}static subscribe(r,e){let o=C.get(r)||new p(e);return C.has(r)||(C.set(r,o),o.channel.on(P,(n,i)=>{n===r&&o.listeners.forEach(a=>a(i));})),{get value(){return o.get(r)},set value(n){o.set(r,n);},on(n,i){if(n!=="change")throw new Error("unsupported event");o.listeners.push(i);},off(n,i){if(n!=="change")throw new Error("unsupported event");let a=o.listeners.indexOf(i);a>=0&&o.listeners.splice(a,1);}}}};async function $(t,r){await jsonfile.writeFile(t,r);}function Y(t=[]){return [...t,_.resolve("./manager.mjs")]}var J=async(t,r,e)=>{let o,n,i,a=async()=>{try{let u=await node.getGitInfo();Object.entries(u).some(([m,d])=>o?.[m]!==d)&&r(u,o),o=u,n=void 0,i=setTimeout(a,t);}catch(u){n?.message!==u.message&&(console.error(`Failed to fetch git info, with error:
|
|
8
|
+
${u}`),e(u)),o=void 0,n=u,i=setTimeout(a,t);}};return a(),()=>clearTimeout(i)};async function q(t,{configDir:r,configFile:e}){let o=await node.getConfiguration(e),{projectId:n}=o,i=p.subscribe(D,t);i.value=n?{projectId:n}:{};let a=n;i.on("change",async({projectId:s}={})=>{if(!s||s===a)return;a=s;let l=e||"chromatic.config.json";try{await $(l,{...o,projectId:s}),i.value={...i.value,written:!0,configFile:l};}catch(g){console.warn(`Failed to update your main configuration:
|
|
9
|
+
|
|
10
|
+
${g}`),i.value={...i.value,written:!1,configFile:l};}});let u=p.subscribe(L,t);t.on(O,async({accessToken:s})=>{let{projectId:l}=i.value||{};try{await N(u,{configFile:e,projectId:l,userToken:s});}catch(g){console.error(`Failed to run Chromatic build, with error:
|
|
11
|
+
${g}`);}}),t.on(B,U);let m=p.subscribe(v,t),d=p.subscribe(y,t);return J(5e3,s=>{d.value=void 0,m.value=s;},s=>{d.value=s;}),t}var X={managerEntries:Y,experimental_serverChannel:q,env:async(t,{configType:r})=>r==="PRODUCTION"?t:{...t,CHROMATIC_BASE_URL:T}},_e=X;
|
|
12
|
+
|
|
13
|
+
module.exports = _e;
|
|
14
|
+
//# sourceMappingURL=out.js.map
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/runChromaticBuild.ts","../src/buildSteps.ts","../src/utils/SharedState.ts","../src/utils/updateChromaticConfig.ts"],"names":["getConfiguration","getGitInfo","CHROMATIC_INDEX_URL","CHROMATIC_BASE_URL","CHROMATIC_API_URL","ADDON_ID","PANEL_ID","SIDEBAR_TOP_ID","SIDEBAR_BOTTOM_ID","ACCESS_TOKEN_KEY","DEV_BUILD_ID_KEY","GIT_INFO","GIT_INFO_ERROR","PROJECT_INFO","IS_OUTDATED","START_BUILD","STOP_BUILD","LOCAL_BUILD_PROGRESS","run","filesize","isKnownStep","taskOrStep","BUILD_STEP_ORDER","hasProgressEvent","task","BUILD_STEP_CONFIG","stepProgress","numerator","denominator","total","exponent","progress","symbol","INITIAL_BUILD_PAYLOAD","step","ESTIMATED_PROGRESS_INTERVAL","abortController","getBuildStepData","previousBuildProgress","stepDurations","startedAt","completedAt","totalDuration","sum","duration","stepIndex","startTime","endTime","startPercentage","endPercentage","onStartOrProgress","localBuildProgress","timeout","ctx","buildProgressPercentage","stepPercentage","newPercentage","estimateDuration","currentStep","onCompleteOrError","error","runChromaticBuild","options","stopChromaticBuild","GET_VALUE","SET_VALUE","instances","SharedState","channel","key","value","index","sharedState","k","v","listener","newValue","event","callback","writeFile","updateChromaticConfig","configFile","configuration","managerEntries","entry","__require","observeGitInfo","interval","errorCallback","prev","prevError","timer","act","gitInfo","e","serverChannel","configDir","initialProjectId","projectInfoState","lastProjectId","projectId","writtenConfigFile","err","userToken","gitInfoState","gitInfoError","info","config","env","configType","src_default"],"mappings":"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","sourcesContent":["/* eslint-disable no-console */\nimport type { Channel } from \"@storybook/channels\";\n// eslint-disable-next-line import/no-unresolved\nimport { getConfiguration, getGitInfo, GitInfo } from \"chromatic/node\";\n\nimport {\n CHROMATIC_BASE_URL,\n GIT_INFO,\n GIT_INFO_ERROR,\n LOCAL_BUILD_PROGRESS,\n PROJECT_INFO,\n START_BUILD,\n STOP_BUILD,\n} from \"./constants\";\nimport { runChromaticBuild, stopChromaticBuild } from \"./runChromaticBuild\";\nimport { GitInfoPayload, LocalBuildProgress, ProjectInfoPayload } from \"./types\";\nimport { SharedState } from \"./utils/SharedState\";\nimport { updateChromaticConfig } from \"./utils/updateChromaticConfig\";\n\n/**\n * to load the built addon in this test Storybook\n */\nfunction managerEntries(entry: string[] = []) {\n return [...entry, require.resolve(\"./manager.mjs\")];\n}\n\n// Polls for changes to the Git state and invokes the callback when it changes.\n// Uses a recursive setTimeout instead of setInterval to avoid overlapping async calls.\nconst observeGitInfo = async (\n interval: number,\n callback: (info: GitInfo, prevInfo?: GitInfo) => void,\n errorCallback: (e: Error) => void\n) => {\n let prev: GitInfo | undefined;\n let prevError: Error | undefined;\n let timer: NodeJS.Timeout | undefined;\n const act = async () => {\n try {\n const gitInfo = await getGitInfo();\n if (Object.entries(gitInfo).some(([key, value]) => prev?.[key as keyof GitInfo] !== value)) {\n callback(gitInfo, prev);\n }\n prev = gitInfo;\n prevError = undefined;\n timer = setTimeout(act, interval);\n } catch (e: any) {\n if (prevError?.message !== e.message) {\n console.error(`Failed to fetch git info, with error:\\n${e}`);\n errorCallback(e);\n }\n prev = undefined;\n prevError = e;\n timer = setTimeout(act, interval);\n }\n };\n act();\n\n return () => clearTimeout(timer);\n};\n\nasync function serverChannel(\n channel: Channel,\n // configDir is the standard storybook flag (-c to the storybook CLI)\n // configFile is the `main.js` option, which should be set by the user to correspond to the\n // chromatic option (-c to the chromatic CLI)\n { configDir, configFile }: { configDir: string; configFile?: string }\n) {\n const configuration = await getConfiguration(configFile);\n const { projectId: initialProjectId } = configuration;\n\n const projectInfoState = SharedState.subscribe<ProjectInfoPayload>(PROJECT_INFO, channel);\n projectInfoState.value = initialProjectId ? { projectId: initialProjectId } : {};\n\n let lastProjectId = initialProjectId;\n projectInfoState.on(\"change\", async ({ projectId } = {}) => {\n if (!projectId || projectId === lastProjectId) return;\n lastProjectId = projectId;\n\n const writtenConfigFile = configFile || \"chromatic.config.json\";\n try {\n await updateChromaticConfig(writtenConfigFile, {\n ...configuration,\n projectId,\n });\n\n projectInfoState.value = {\n ...projectInfoState.value,\n written: true,\n configFile: writtenConfigFile,\n };\n } catch (err) {\n console.warn(`Failed to update your main configuration:\\n\\n ${err}`);\n\n projectInfoState.value = {\n ...projectInfoState.value,\n written: false,\n configFile: writtenConfigFile,\n };\n }\n });\n\n const localBuildProgress = SharedState.subscribe<LocalBuildProgress>(\n LOCAL_BUILD_PROGRESS,\n channel\n );\n\n channel.on(START_BUILD, async ({ accessToken: userToken }) => {\n const { projectId } = projectInfoState.value || {};\n try {\n await runChromaticBuild(localBuildProgress, { configFile, projectId, userToken });\n } catch (e) {\n console.error(`Failed to run Chromatic build, with error:\\n${e}`);\n }\n });\n\n channel.on(STOP_BUILD, stopChromaticBuild);\n\n const gitInfoState = SharedState.subscribe<GitInfoPayload>(GIT_INFO, channel);\n\n const gitInfoError = SharedState.subscribe<Error>(GIT_INFO_ERROR, channel);\n\n observeGitInfo(\n 5000,\n (info) => {\n gitInfoError.value = undefined;\n gitInfoState.value = info;\n },\n (error: Error) => {\n gitInfoError.value = error;\n }\n );\n\n return channel;\n}\n\nconst config = {\n managerEntries,\n experimental_serverChannel: serverChannel,\n env: async (\n env: Record<string, string>,\n { configType }: { configType: \"DEVELOPMENT\" | \"PRODUCTION\" }\n ) => {\n if (configType === \"PRODUCTION\") return env;\n\n return {\n ...env,\n CHROMATIC_BASE_URL,\n };\n },\n};\n\nexport default config;\n","export const {\n CHROMATIC_INDEX_URL,\n CHROMATIC_BASE_URL = CHROMATIC_INDEX_URL || \"https://www.chromatic.com\",\n CHROMATIC_API_URL = `${CHROMATIC_BASE_URL}/api`,\n} = process.env;\n\nexport const ADDON_ID = \"chromaui/addon-visual-tests\";\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const SIDEBAR_TOP_ID = `${ADDON_ID}/sidebarTop`;\nexport const SIDEBAR_BOTTOM_ID = `${ADDON_ID}/sidebarBottom`;\nexport const ACCESS_TOKEN_KEY = `${ADDON_ID}/access-token/${CHROMATIC_BASE_URL}`;\nexport const DEV_BUILD_ID_KEY = `${ADDON_ID}/dev-build-id`;\n\nexport const GIT_INFO = `${ADDON_ID}/gitInfo`;\nexport const GIT_INFO_ERROR = `${ADDON_ID}/gitInfoError`;\nexport const PROJECT_INFO = `${ADDON_ID}/projectInfo`;\nexport const IS_OUTDATED = `${ADDON_ID}/isOutdated`;\nexport const START_BUILD = `${ADDON_ID}/startBuild`;\nexport const STOP_BUILD = `${ADDON_ID}/stopBuild`;\nexport const LOCAL_BUILD_PROGRESS = `${ADDON_ID}/localBuildProgress`;\n","/* eslint-disable no-param-reassign */\n// eslint-disable-next-line import/no-unresolved\nimport { Context, InitialContext, Options, run, TaskName } from \"chromatic/node\";\n\nimport {\n BUILD_STEP_CONFIG,\n BUILD_STEP_ORDER,\n hasProgressEvent,\n INITIAL_BUILD_PAYLOAD,\n isKnownStep,\n} from \"./buildSteps\";\nimport { LocalBuildProgress } from \"./types\";\nimport { SharedState } from \"./utils/SharedState\";\n\nconst ESTIMATED_PROGRESS_INTERVAL = 2000;\n\nlet abortController: AbortController | undefined;\n\nconst getBuildStepData = (\n task: TaskName,\n previousBuildProgress?: LocalBuildProgress[\"previousBuildProgress\"]\n) => {\n if (!isKnownStep(task)) throw new Error(`Unknown step: ${task}`);\n\n const stepDurations = BUILD_STEP_ORDER.map((step) => {\n const { startedAt, completedAt } = previousBuildProgress?.[step] || {};\n return startedAt && completedAt\n ? completedAt - startedAt\n : BUILD_STEP_CONFIG[step].estimateDuration;\n });\n const totalDuration = stepDurations.reduce((sum, duration) => sum + duration, 0);\n\n const stepIndex = BUILD_STEP_ORDER.indexOf(task);\n const startTime = stepDurations.slice(0, stepIndex).reduce((sum, duration) => sum + duration, 0);\n const endTime = startTime + stepDurations[stepIndex];\n\n const startPercentage = (startTime / totalDuration) * 100;\n const endPercentage = (endTime / totalDuration) * 100;\n return {\n ...BUILD_STEP_CONFIG[task],\n startPercentage,\n endPercentage,\n stepPercentage: endPercentage - startPercentage,\n };\n};\n\nexport const onStartOrProgress =\n (\n localBuildProgress: ReturnType<typeof SharedState.subscribe<LocalBuildProgress>>,\n timeout?: ReturnType<typeof setTimeout>\n ) =>\n ({ ...ctx }: Context, { progress, total }: { progress?: number; total?: number } = {}) => {\n clearTimeout(timeout);\n\n if (!isKnownStep(ctx.task)) return;\n\n // We should set this right before starting so it should never be unset during a build.\n if (!localBuildProgress.value) {\n throw new Error(\"Unexpected missing value for localBuildProgress\");\n }\n\n const { buildProgressPercentage, stepProgress, previousBuildProgress } =\n localBuildProgress.value;\n\n const { startPercentage, endPercentage, stepPercentage } = getBuildStepData(\n ctx.task,\n previousBuildProgress\n );\n\n let newPercentage = startPercentage;\n if (progress && total) {\n newPercentage += stepPercentage * (progress / total);\n }\n\n // If the step doesn't have a progress event, simulate one by synthetically updating progress\n if (!hasProgressEvent(ctx.task)) {\n const { estimateDuration } = BUILD_STEP_CONFIG[ctx.task];\n const stepIndex = BUILD_STEP_ORDER.indexOf(ctx.task);\n newPercentage =\n Math.max(newPercentage, buildProgressPercentage) +\n (ESTIMATED_PROGRESS_INTERVAL / estimateDuration) * stepPercentage;\n\n timeout = setTimeout(() => {\n // We should set this right before starting so it should never be unset during a build.\n if (!localBuildProgress.value) {\n throw new Error(\"Unexpected missing value for localBuildProgress\");\n }\n\n // Intentionally reference the present value here (after timeout)\n const { currentStep } = localBuildProgress.value;\n // Only update if we haven't moved on to a later step\n if (isKnownStep(currentStep) && BUILD_STEP_ORDER.indexOf(currentStep) <= stepIndex) {\n onStartOrProgress(localBuildProgress, timeout)(ctx);\n }\n }, ESTIMATED_PROGRESS_INTERVAL);\n }\n\n stepProgress[ctx.task] = {\n startedAt: Date.now(),\n ...stepProgress[ctx.task],\n ...(progress && total && { numerator: progress, denominator: total }),\n };\n\n localBuildProgress.value = {\n buildId: ctx.announcedBuild?.id,\n branch: ctx.git?.branch,\n buildProgressPercentage: Math.min(newPercentage, endPercentage),\n currentStep: ctx.task,\n stepProgress,\n };\n };\n\nexport const onCompleteOrError =\n (\n localBuildProgress: ReturnType<typeof SharedState.subscribe<LocalBuildProgress>>,\n timeout?: ReturnType<typeof setTimeout>\n ) =>\n (\n ctx: Context | InitialContext,\n error?: { formattedError: string; originalError: Error | Error[] }\n ) => {\n clearTimeout(timeout);\n\n // We should set this right before starting so it should never be unset during a build.\n if (!localBuildProgress.value) {\n throw new Error(\"Unexpected missing value for localBuildProgress\");\n }\n\n const { buildProgressPercentage, stepProgress } = localBuildProgress.value;\n\n if (error) {\n localBuildProgress.value = {\n buildId: ctx.announcedBuild?.id,\n branch: ctx.git?.branch,\n buildProgressPercentage,\n currentStep: abortController?.signal.aborted ? \"aborted\" : \"error\",\n stepProgress,\n formattedError: error.formattedError,\n originalError: error.originalError,\n previousBuildProgress: stepProgress,\n };\n return;\n }\n\n if (ctx.task && isKnownStep(ctx.task)) {\n stepProgress[ctx.task] = {\n ...stepProgress[ctx.task],\n completedAt: Date.now(),\n };\n }\n\n if (ctx.build && ctx.task === \"snapshot\") {\n localBuildProgress.value = {\n buildId: ctx.announcedBuild?.id,\n branch: ctx.git?.branch,\n buildProgressPercentage: 100,\n currentStep: \"complete\",\n stepProgress,\n changeCount: ctx.build.changeCount,\n errorCount: ctx.build.errorCount,\n previousBuildProgress: stepProgress,\n };\n }\n };\n\nexport const runChromaticBuild = async (\n localBuildProgress: ReturnType<typeof SharedState.subscribe<LocalBuildProgress>>,\n options: Partial<Options>\n) => {\n if (!options.projectId) throw new Error(\"Missing projectId\");\n if (!options.userToken) throw new Error(\"Missing userToken\");\n\n localBuildProgress.value = INITIAL_BUILD_PAYLOAD;\n\n // Timeout is defined here so it's shared between all handlers\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n abortController?.abort();\n abortController = new AbortController();\n\n process.env.SB_TESTBUILD = \"true\";\n\n await run({\n options: {\n ...options,\n\n // Local changes should never be auto-accepted\n autoAcceptChanges: false,\n // Test results must be awaited to get progress updates\n exitOnceUploaded: false,\n // Don't raise any alarms when changes are found\n exitZeroOnChanges: true,\n // We might want to drop this later and instead record \"uncommitted hashes\" on builds\n forceRebuild: true,\n // This should never be set for local builds\n fromCI: false,\n // Builds initiated from the addon are always considered local\n isLocalBuild: true,\n // Never skip local builds\n skip: false,\n\n experimental_onTaskStart: onStartOrProgress(localBuildProgress, timeout),\n experimental_onTaskProgress: onStartOrProgress(localBuildProgress, timeout),\n experimental_onTaskComplete: onCompleteOrError(localBuildProgress, timeout),\n experimental_onTaskError: onCompleteOrError(localBuildProgress, timeout),\n experimental_abortSignal: abortController?.signal,\n },\n });\n};\n\nexport const stopChromaticBuild = () => {\n abortController?.abort(new Error(\"Build canceled from Storybook\"));\n};\n","// eslint-disable-next-line import/no-unresolved\nimport { TaskName } from \"chromatic/node\";\nimport { filesize } from \"filesize\";\n\nimport { KnownStep, LocalBuildProgress, StepProgressPayload } from \"./types\";\n\nexport const isKnownStep = (\n taskOrStep: TaskName | LocalBuildProgress[\"currentStep\"]\n): taskOrStep is KnownStep => BUILD_STEP_ORDER.includes(taskOrStep as KnownStep);\n\nexport const hasProgressEvent = (task: TaskName) => [\"upload\", \"snapshot\"].includes(task);\n\n// Note this does not include the \"aborted\", \"complete\" and \"error\" steps\nexport const BUILD_STEP_ORDER: KnownStep[] = [\n \"initialize\",\n \"build\",\n \"upload\",\n \"verify\",\n \"snapshot\",\n];\n\nexport const BUILD_STEP_CONFIG: Record<\n LocalBuildProgress[\"currentStep\"],\n {\n key: LocalBuildProgress[\"currentStep\"];\n emoji: string;\n renderName: () => string;\n renderProgress: (payload: LocalBuildProgress) => string;\n renderComplete: () => string;\n estimateDuration: number;\n }\n> = {\n initialize: {\n key: \"initialize\",\n emoji: \"🚀\",\n renderName: () => `Initialize build`,\n renderProgress: () => `Initializing build`,\n renderComplete: () => `Initialized`,\n estimateDuration: 2000,\n },\n build: {\n key: \"build\",\n emoji: \"🏗\",\n renderName: () => `Build Storybook`,\n renderProgress: () => `Building your Storybook...`,\n renderComplete: () => `Storybook built`,\n estimateDuration: 30_000,\n },\n upload: {\n key: \"upload\",\n emoji: \"📡\",\n renderName: () => `Publish your Storybook`,\n renderProgress: ({ stepProgress }) => {\n const { numerator, denominator } = stepProgress.upload;\n if (!denominator || !numerator) return `Uploading files`;\n const { value: total, exponent } = filesize(denominator, {\n output: \"object\",\n round: 1,\n });\n const { value: progress, symbol } = filesize(numerator, {\n exponent,\n output: \"object\",\n round: 1,\n });\n return `Uploading files (${progress}/${total} ${symbol})`;\n },\n renderComplete: () => `Publish complete`,\n estimateDuration: 30_000,\n },\n verify: {\n key: \"verify\",\n emoji: \"🔍\",\n renderName: () => `Verify your Storybook`,\n renderProgress: () => `Verifying contents...`,\n renderComplete: () => `Storybook verified`,\n estimateDuration: 10_000,\n },\n snapshot: {\n key: \"snapshot\",\n emoji: \"📸\",\n renderName: () => `Run visual tests`,\n renderProgress: ({ stepProgress }) => {\n const { numerator, denominator } = stepProgress.snapshot;\n return denominator\n ? `Running visual tests (${numerator}/${denominator})`\n : `Running visual tests`;\n },\n renderComplete: () => `Tested your stories`,\n estimateDuration: 60_000,\n },\n\n // These are special steps that are not part of the build process\n aborted: {\n key: \"aborted\",\n emoji: \"✋\",\n renderName: () => `Build canceled`,\n renderProgress: () => `Build canceled`,\n renderComplete: () => `Build canceled`,\n estimateDuration: 0,\n },\n complete: {\n key: \"complete\",\n emoji: \"🎉\",\n renderName: () => `Visual tests completed!`,\n renderProgress: () => `Visual tests completed!`,\n renderComplete: () => `Visual tests completed!`,\n estimateDuration: 0,\n },\n error: {\n key: \"error\",\n emoji: \"🚨\",\n renderName: () => `Build failed`,\n renderProgress: () => `Build failed`,\n renderComplete: () => `Build failed`,\n estimateDuration: 0,\n },\n};\n\nexport const INITIAL_BUILD_PAYLOAD = {\n buildProgressPercentage: 0,\n currentStep: BUILD_STEP_ORDER[0],\n stepProgress: Object.fromEntries(BUILD_STEP_ORDER.map((step) => [step, {}])) as Record<\n KnownStep,\n StepProgressPayload\n >,\n};\n","import type { Channel } from \"@storybook/channels\";\n\nexport const GET_VALUE = `experimental_useSharedState_getValue`;\nexport const SET_VALUE = `experimental_useSharedState_setValue`;\n\ntype ChannelLike = Pick<Channel, \"emit\" | \"on\" | \"off\">;\n\nconst instances = new Map<string, SharedState>();\n\nexport class SharedState<T = any> {\n channel: ChannelLike;\n\n listeners: ((value: T | undefined) => void)[];\n\n state: { [key: string]: { index: number; value: T | undefined } };\n\n constructor(channel: ChannelLike) {\n this.channel = channel;\n this.listeners = [];\n this.state = {};\n\n this.channel.on(SET_VALUE, (key: string, value: T | undefined, index: number) => {\n if (this.state?.[key]?.index >= index) return;\n this.state[key] = { index, value };\n });\n\n this.channel.on(GET_VALUE, (key: string) => {\n const index = this.state[key]?.index ?? 0;\n const value = this.state[key]?.value;\n this.channel.emit(SET_VALUE, key, value, index);\n });\n }\n\n get(key: string) {\n if (!this.state[key]) this.channel.emit(GET_VALUE, key);\n return this.state[key]?.value;\n }\n\n set(key: string, value: T | undefined) {\n const index = (this.state[key]?.index ?? 0) + 1;\n this.state[key] = { index, value };\n this.channel.emit(SET_VALUE, key, value, index);\n }\n\n static subscribe<T>(key: string, channel: ChannelLike) {\n const sharedState = instances.get(key) || new SharedState(channel);\n\n if (!instances.has(key)) {\n instances.set(key, sharedState);\n sharedState.channel.on(SET_VALUE, (k: string, v: T | undefined) => {\n if (k !== key) return;\n sharedState.listeners.forEach((listener) => listener(v));\n });\n }\n\n return {\n get value(): T | undefined {\n return sharedState.get(key);\n },\n\n set value(newValue: T | undefined) {\n sharedState.set(key, newValue);\n },\n\n on(event: \"change\", callback: (value: T | undefined) => void) {\n if (event !== \"change\") throw new Error(\"unsupported event\");\n sharedState.listeners.push(callback);\n },\n\n off(event: \"change\", callback: (value: T | undefined) => void) {\n if (event !== \"change\") throw new Error(\"unsupported event\");\n const index = sharedState.listeners.indexOf(callback);\n if (index >= 0) sharedState.listeners.splice(index, 1);\n },\n };\n }\n}\n","import type { Configuration } from \"chromatic/node\";\nimport { writeFile } from \"jsonfile\";\n\nexport async function updateChromaticConfig(configFile: string, configuration: Configuration) {\n await writeFile(configFile, configuration);\n}\n"]}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { getConfiguration, run, getGitInfo } from 'chromatic/node';
|
|
2
|
+
import { filesize } from 'filesize';
|
|
3
|
+
import { writeFile } from 'jsonfile';
|
|
4
|
+
|
|
5
|
+
var _=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(r,e)=>(typeof require<"u"?require:r)[e]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw new Error('Dynamic require of "'+t+'" is not supported')});var {CHROMATIC_INDEX_URL:F,CHROMATIC_BASE_URL:T=F||"https://www.chromatic.com",CHROMATIC_API_URL:Q=`${T}/api`}=process.env,c="chromaui/addon-visual-tests",v=`${c}/gitInfo`,y=`${c}/gitInfoError`,D=`${c}/projectInfo`,O=`${c}/startBuild`,B=`${c}/stopBuild`,L=`${c}/localBuildProgress`;var h=t=>f.includes(t),R=t=>["upload","snapshot"].includes(t),f=["initialize","build","upload","verify","snapshot"],b={initialize:{key:"initialize",emoji:"\u{1F680}",renderName:()=>"Initialize build",renderProgress:()=>"Initializing build",renderComplete:()=>"Initialized",estimateDuration:2e3},build:{key:"build",emoji:"\u{1F3D7}",renderName:()=>"Build Storybook",renderProgress:()=>"Building your Storybook...",renderComplete:()=>"Storybook built",estimateDuration:3e4},upload:{key:"upload",emoji:"\u{1F4E1}",renderName:()=>"Publish your Storybook",renderProgress:({stepProgress:t})=>{let{numerator:r,denominator:e}=t.upload;if(!e||!r)return "Uploading files";let{value:o,exponent:n}=filesize(e,{output:"object",round:1}),{value:i,symbol:a}=filesize(r,{exponent:n,output:"object",round:1});return `Uploading files (${i}/${o} ${a})`},renderComplete:()=>"Publish complete",estimateDuration:3e4},verify:{key:"verify",emoji:"\u{1F50D}",renderName:()=>"Verify your Storybook",renderProgress:()=>"Verifying contents...",renderComplete:()=>"Storybook verified",estimateDuration:1e4},snapshot:{key:"snapshot",emoji:"\u{1F4F8}",renderName:()=>"Run visual tests",renderProgress:({stepProgress:t})=>{let{numerator:r,denominator:e}=t.snapshot;return e?`Running visual tests (${r}/${e})`:"Running visual tests"},renderComplete:()=>"Tested your stories",estimateDuration:6e4},aborted:{key:"aborted",emoji:"\u270B",renderName:()=>"Build canceled",renderProgress:()=>"Build canceled",renderComplete:()=>"Build canceled",estimateDuration:0},complete:{key:"complete",emoji:"\u{1F389}",renderName:()=>"Visual tests completed!",renderProgress:()=>"Visual tests completed!",renderComplete:()=>"Visual tests completed!",estimateDuration:0},error:{key:"error",emoji:"\u{1F6A8}",renderName:()=>"Build failed",renderProgress:()=>"Build failed",renderComplete:()=>"Build failed",estimateDuration:0}},k={buildProgressPercentage:0,currentStep:f[0],stepProgress:Object.fromEntries(f.map(t=>[t,{}]))};var x=2e3,I,V=(t,r)=>{if(!h(t))throw new Error(`Unknown step: ${t}`);let e=f.map(d=>{let{startedAt:s,completedAt:l}=r?.[d]||{};return s&&l?l-s:b[d].estimateDuration}),o=e.reduce((d,s)=>d+s,0),n=f.indexOf(t),i=e.slice(0,n).reduce((d,s)=>d+s,0),a=i+e[n],u=i/o*100,m=a/o*100;return {...b[t],startPercentage:u,endPercentage:m,stepPercentage:m-u}},S=(t,r)=>({...e},{progress:o,total:n}={})=>{if(clearTimeout(r),!h(e.task))return;if(!t.value)throw new Error("Unexpected missing value for localBuildProgress");let{buildProgressPercentage:i,stepProgress:a,previousBuildProgress:u}=t.value,{startPercentage:m,endPercentage:d,stepPercentage:s}=V(e.task,u),l=m;if(o&&n&&(l+=s*(o/n)),!R(e.task)){let{estimateDuration:g}=b[e.task],G=f.indexOf(e.task);l=Math.max(l,i)+x/g*s,r=setTimeout(()=>{if(!t.value)throw new Error("Unexpected missing value for localBuildProgress");let{currentStep:E}=t.value;h(E)&&f.indexOf(E)<=G&&S(t,r)(e);},x);}a[e.task]={startedAt:Date.now(),...a[e.task],...o&&n&&{numerator:o,denominator:n}},t.value={buildId:e.announcedBuild?.id,branch:e.git?.branch,buildProgressPercentage:Math.min(l,d),currentStep:e.task,stepProgress:a};},A=(t,r)=>(e,o)=>{if(clearTimeout(r),!t.value)throw new Error("Unexpected missing value for localBuildProgress");let{buildProgressPercentage:n,stepProgress:i}=t.value;if(o){t.value={buildId:e.announcedBuild?.id,branch:e.git?.branch,buildProgressPercentage:n,currentStep:I?.signal.aborted?"aborted":"error",stepProgress:i,formattedError:o.formattedError,originalError:o.originalError,previousBuildProgress:i};return}e.task&&h(e.task)&&(i[e.task]={...i[e.task],completedAt:Date.now()}),e.build&&e.task==="snapshot"&&(t.value={buildId:e.announcedBuild?.id,branch:e.git?.branch,buildProgressPercentage:100,currentStep:"complete",stepProgress:i,changeCount:e.build.changeCount,errorCount:e.build.errorCount,previousBuildProgress:i});},N=async(t,r)=>{if(!r.projectId)throw new Error("Missing projectId");if(!r.userToken)throw new Error("Missing userToken");t.value=k;let e;I?.abort(),I=new AbortController,process.env.SB_TESTBUILD="true",await run({options:{...r,autoAcceptChanges:!1,exitOnceUploaded:!1,exitZeroOnChanges:!0,forceRebuild:!0,fromCI:!1,isLocalBuild:!0,skip:!1,experimental_onTaskStart:S(t,e),experimental_onTaskProgress:S(t,e),experimental_onTaskComplete:A(t,e),experimental_onTaskError:A(t,e),experimental_abortSignal:I?.signal}});},U=()=>{I?.abort(new Error("Build canceled from Storybook"));};var j="experimental_useSharedState_getValue",P="experimental_useSharedState_setValue",C=new Map,p=class{constructor(r){this.channel=r,this.listeners=[],this.state={},this.channel.on(P,(e,o,n)=>{this.state?.[e]?.index>=n||(this.state[e]={index:n,value:o});}),this.channel.on(j,e=>{let o=this.state[e]?.index??0,n=this.state[e]?.value;this.channel.emit(P,e,n,o);});}get(r){return this.state[r]||this.channel.emit(j,r),this.state[r]?.value}set(r,e){let o=(this.state[r]?.index??0)+1;this.state[r]={index:o,value:e},this.channel.emit(P,r,e,o);}static subscribe(r,e){let o=C.get(r)||new p(e);return C.has(r)||(C.set(r,o),o.channel.on(P,(n,i)=>{n===r&&o.listeners.forEach(a=>a(i));})),{get value(){return o.get(r)},set value(n){o.set(r,n);},on(n,i){if(n!=="change")throw new Error("unsupported event");o.listeners.push(i);},off(n,i){if(n!=="change")throw new Error("unsupported event");let a=o.listeners.indexOf(i);a>=0&&o.listeners.splice(a,1);}}}};async function $(t,r){await writeFile(t,r);}function Y(t=[]){return [...t,_.resolve("./manager.mjs")]}var J=async(t,r,e)=>{let o,n,i,a=async()=>{try{let u=await getGitInfo();Object.entries(u).some(([m,d])=>o?.[m]!==d)&&r(u,o),o=u,n=void 0,i=setTimeout(a,t);}catch(u){n?.message!==u.message&&(console.error(`Failed to fetch git info, with error:
|
|
6
|
+
${u}`),e(u)),o=void 0,n=u,i=setTimeout(a,t);}};return a(),()=>clearTimeout(i)};async function q(t,{configDir:r,configFile:e}){let o=await getConfiguration(e),{projectId:n}=o,i=p.subscribe(D,t);i.value=n?{projectId:n}:{};let a=n;i.on("change",async({projectId:s}={})=>{if(!s||s===a)return;a=s;let l=e||"chromatic.config.json";try{await $(l,{...o,projectId:s}),i.value={...i.value,written:!0,configFile:l};}catch(g){console.warn(`Failed to update your main configuration:
|
|
7
|
+
|
|
8
|
+
${g}`),i.value={...i.value,written:!1,configFile:l};}});let u=p.subscribe(L,t);t.on(O,async({accessToken:s})=>{let{projectId:l}=i.value||{};try{await N(u,{configFile:e,projectId:l,userToken:s});}catch(g){console.error(`Failed to run Chromatic build, with error:
|
|
9
|
+
${g}`);}}),t.on(B,U);let m=p.subscribe(v,t),d=p.subscribe(y,t);return J(5e3,s=>{d.value=void 0,m.value=s;},s=>{d.value=s;}),t}var X={managerEntries:Y,experimental_serverChannel:q,env:async(t,{configType:r})=>r==="PRODUCTION"?t:{...t,CHROMATIC_BASE_URL:T}},_e=X;
|
|
10
|
+
|
|
11
|
+
export { _e as default };
|
|
12
|
+
//# sourceMappingURL=out.js.map
|
|
13
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/constants.ts","../src/runChromaticBuild.ts","../src/buildSteps.ts","../src/utils/SharedState.ts","../src/utils/updateChromaticConfig.ts"],"names":["getConfiguration","getGitInfo","CHROMATIC_INDEX_URL","CHROMATIC_BASE_URL","CHROMATIC_API_URL","ADDON_ID","PANEL_ID","SIDEBAR_TOP_ID","SIDEBAR_BOTTOM_ID","ACCESS_TOKEN_KEY","DEV_BUILD_ID_KEY","GIT_INFO","GIT_INFO_ERROR","PROJECT_INFO","IS_OUTDATED","START_BUILD","STOP_BUILD","LOCAL_BUILD_PROGRESS","run","filesize","isKnownStep","taskOrStep","BUILD_STEP_ORDER","hasProgressEvent","task","BUILD_STEP_CONFIG","stepProgress","numerator","denominator","total","exponent","progress","symbol","INITIAL_BUILD_PAYLOAD","step","ESTIMATED_PROGRESS_INTERVAL","abortController","getBuildStepData","previousBuildProgress","stepDurations","startedAt","completedAt","totalDuration","sum","duration","stepIndex","startTime","endTime","startPercentage","endPercentage","onStartOrProgress","localBuildProgress","timeout","ctx","buildProgressPercentage","stepPercentage","newPercentage","estimateDuration","currentStep","onCompleteOrError","error","runChromaticBuild","options","stopChromaticBuild","GET_VALUE","SET_VALUE","instances","SharedState","channel","key","value","index","sharedState","k","v","listener","newValue","event","callback","writeFile","updateChromaticConfig","configFile","configuration","managerEntries","entry","__require","observeGitInfo","interval","errorCallback","prev","prevError","timer","act","gitInfo","e","serverChannel","configDir","initialProjectId","projectInfoState","lastProjectId","projectId","writtenConfigFile","err","userToken","gitInfoState","gitInfoError","info","config","env","configType","src_default"],"mappings":"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","sourcesContent":["/* eslint-disable no-console */\nimport type { Channel } from \"@storybook/channels\";\n// eslint-disable-next-line import/no-unresolved\nimport { getConfiguration, getGitInfo, GitInfo } from \"chromatic/node\";\n\nimport {\n CHROMATIC_BASE_URL,\n GIT_INFO,\n GIT_INFO_ERROR,\n LOCAL_BUILD_PROGRESS,\n PROJECT_INFO,\n START_BUILD,\n STOP_BUILD,\n} from \"./constants\";\nimport { runChromaticBuild, stopChromaticBuild } from \"./runChromaticBuild\";\nimport { GitInfoPayload, LocalBuildProgress, ProjectInfoPayload } from \"./types\";\nimport { SharedState } from \"./utils/SharedState\";\nimport { updateChromaticConfig } from \"./utils/updateChromaticConfig\";\n\n/**\n * to load the built addon in this test Storybook\n */\nfunction managerEntries(entry: string[] = []) {\n return [...entry, require.resolve(\"./manager.mjs\")];\n}\n\n// Polls for changes to the Git state and invokes the callback when it changes.\n// Uses a recursive setTimeout instead of setInterval to avoid overlapping async calls.\nconst observeGitInfo = async (\n interval: number,\n callback: (info: GitInfo, prevInfo?: GitInfo) => void,\n errorCallback: (e: Error) => void\n) => {\n let prev: GitInfo | undefined;\n let prevError: Error | undefined;\n let timer: NodeJS.Timeout | undefined;\n const act = async () => {\n try {\n const gitInfo = await getGitInfo();\n if (Object.entries(gitInfo).some(([key, value]) => prev?.[key as keyof GitInfo] !== value)) {\n callback(gitInfo, prev);\n }\n prev = gitInfo;\n prevError = undefined;\n timer = setTimeout(act, interval);\n } catch (e: any) {\n if (prevError?.message !== e.message) {\n console.error(`Failed to fetch git info, with error:\\n${e}`);\n errorCallback(e);\n }\n prev = undefined;\n prevError = e;\n timer = setTimeout(act, interval);\n }\n };\n act();\n\n return () => clearTimeout(timer);\n};\n\nasync function serverChannel(\n channel: Channel,\n // configDir is the standard storybook flag (-c to the storybook CLI)\n // configFile is the `main.js` option, which should be set by the user to correspond to the\n // chromatic option (-c to the chromatic CLI)\n { configDir, configFile }: { configDir: string; configFile?: string }\n) {\n const configuration = await getConfiguration(configFile);\n const { projectId: initialProjectId } = configuration;\n\n const projectInfoState = SharedState.subscribe<ProjectInfoPayload>(PROJECT_INFO, channel);\n projectInfoState.value = initialProjectId ? { projectId: initialProjectId } : {};\n\n let lastProjectId = initialProjectId;\n projectInfoState.on(\"change\", async ({ projectId } = {}) => {\n if (!projectId || projectId === lastProjectId) return;\n lastProjectId = projectId;\n\n const writtenConfigFile = configFile || \"chromatic.config.json\";\n try {\n await updateChromaticConfig(writtenConfigFile, {\n ...configuration,\n projectId,\n });\n\n projectInfoState.value = {\n ...projectInfoState.value,\n written: true,\n configFile: writtenConfigFile,\n };\n } catch (err) {\n console.warn(`Failed to update your main configuration:\\n\\n ${err}`);\n\n projectInfoState.value = {\n ...projectInfoState.value,\n written: false,\n configFile: writtenConfigFile,\n };\n }\n });\n\n const localBuildProgress = SharedState.subscribe<LocalBuildProgress>(\n LOCAL_BUILD_PROGRESS,\n channel\n );\n\n channel.on(START_BUILD, async ({ accessToken: userToken }) => {\n const { projectId } = projectInfoState.value || {};\n try {\n await runChromaticBuild(localBuildProgress, { configFile, projectId, userToken });\n } catch (e) {\n console.error(`Failed to run Chromatic build, with error:\\n${e}`);\n }\n });\n\n channel.on(STOP_BUILD, stopChromaticBuild);\n\n const gitInfoState = SharedState.subscribe<GitInfoPayload>(GIT_INFO, channel);\n\n const gitInfoError = SharedState.subscribe<Error>(GIT_INFO_ERROR, channel);\n\n observeGitInfo(\n 5000,\n (info) => {\n gitInfoError.value = undefined;\n gitInfoState.value = info;\n },\n (error: Error) => {\n gitInfoError.value = error;\n }\n );\n\n return channel;\n}\n\nconst config = {\n managerEntries,\n experimental_serverChannel: serverChannel,\n env: async (\n env: Record<string, string>,\n { configType }: { configType: \"DEVELOPMENT\" | \"PRODUCTION\" }\n ) => {\n if (configType === \"PRODUCTION\") return env;\n\n return {\n ...env,\n CHROMATIC_BASE_URL,\n };\n },\n};\n\nexport default config;\n","export const {\n CHROMATIC_INDEX_URL,\n CHROMATIC_BASE_URL = CHROMATIC_INDEX_URL || \"https://www.chromatic.com\",\n CHROMATIC_API_URL = `${CHROMATIC_BASE_URL}/api`,\n} = process.env;\n\nexport const ADDON_ID = \"chromaui/addon-visual-tests\";\nexport const PANEL_ID = `${ADDON_ID}/panel`;\nexport const SIDEBAR_TOP_ID = `${ADDON_ID}/sidebarTop`;\nexport const SIDEBAR_BOTTOM_ID = `${ADDON_ID}/sidebarBottom`;\nexport const ACCESS_TOKEN_KEY = `${ADDON_ID}/access-token/${CHROMATIC_BASE_URL}`;\nexport const DEV_BUILD_ID_KEY = `${ADDON_ID}/dev-build-id`;\n\nexport const GIT_INFO = `${ADDON_ID}/gitInfo`;\nexport const GIT_INFO_ERROR = `${ADDON_ID}/gitInfoError`;\nexport const PROJECT_INFO = `${ADDON_ID}/projectInfo`;\nexport const IS_OUTDATED = `${ADDON_ID}/isOutdated`;\nexport const START_BUILD = `${ADDON_ID}/startBuild`;\nexport const STOP_BUILD = `${ADDON_ID}/stopBuild`;\nexport const LOCAL_BUILD_PROGRESS = `${ADDON_ID}/localBuildProgress`;\n","/* eslint-disable no-param-reassign */\n// eslint-disable-next-line import/no-unresolved\nimport { Context, InitialContext, Options, run, TaskName } from \"chromatic/node\";\n\nimport {\n BUILD_STEP_CONFIG,\n BUILD_STEP_ORDER,\n hasProgressEvent,\n INITIAL_BUILD_PAYLOAD,\n isKnownStep,\n} from \"./buildSteps\";\nimport { LocalBuildProgress } from \"./types\";\nimport { SharedState } from \"./utils/SharedState\";\n\nconst ESTIMATED_PROGRESS_INTERVAL = 2000;\n\nlet abortController: AbortController | undefined;\n\nconst getBuildStepData = (\n task: TaskName,\n previousBuildProgress?: LocalBuildProgress[\"previousBuildProgress\"]\n) => {\n if (!isKnownStep(task)) throw new Error(`Unknown step: ${task}`);\n\n const stepDurations = BUILD_STEP_ORDER.map((step) => {\n const { startedAt, completedAt } = previousBuildProgress?.[step] || {};\n return startedAt && completedAt\n ? completedAt - startedAt\n : BUILD_STEP_CONFIG[step].estimateDuration;\n });\n const totalDuration = stepDurations.reduce((sum, duration) => sum + duration, 0);\n\n const stepIndex = BUILD_STEP_ORDER.indexOf(task);\n const startTime = stepDurations.slice(0, stepIndex).reduce((sum, duration) => sum + duration, 0);\n const endTime = startTime + stepDurations[stepIndex];\n\n const startPercentage = (startTime / totalDuration) * 100;\n const endPercentage = (endTime / totalDuration) * 100;\n return {\n ...BUILD_STEP_CONFIG[task],\n startPercentage,\n endPercentage,\n stepPercentage: endPercentage - startPercentage,\n };\n};\n\nexport const onStartOrProgress =\n (\n localBuildProgress: ReturnType<typeof SharedState.subscribe<LocalBuildProgress>>,\n timeout?: ReturnType<typeof setTimeout>\n ) =>\n ({ ...ctx }: Context, { progress, total }: { progress?: number; total?: number } = {}) => {\n clearTimeout(timeout);\n\n if (!isKnownStep(ctx.task)) return;\n\n // We should set this right before starting so it should never be unset during a build.\n if (!localBuildProgress.value) {\n throw new Error(\"Unexpected missing value for localBuildProgress\");\n }\n\n const { buildProgressPercentage, stepProgress, previousBuildProgress } =\n localBuildProgress.value;\n\n const { startPercentage, endPercentage, stepPercentage } = getBuildStepData(\n ctx.task,\n previousBuildProgress\n );\n\n let newPercentage = startPercentage;\n if (progress && total) {\n newPercentage += stepPercentage * (progress / total);\n }\n\n // If the step doesn't have a progress event, simulate one by synthetically updating progress\n if (!hasProgressEvent(ctx.task)) {\n const { estimateDuration } = BUILD_STEP_CONFIG[ctx.task];\n const stepIndex = BUILD_STEP_ORDER.indexOf(ctx.task);\n newPercentage =\n Math.max(newPercentage, buildProgressPercentage) +\n (ESTIMATED_PROGRESS_INTERVAL / estimateDuration) * stepPercentage;\n\n timeout = setTimeout(() => {\n // We should set this right before starting so it should never be unset during a build.\n if (!localBuildProgress.value) {\n throw new Error(\"Unexpected missing value for localBuildProgress\");\n }\n\n // Intentionally reference the present value here (after timeout)\n const { currentStep } = localBuildProgress.value;\n // Only update if we haven't moved on to a later step\n if (isKnownStep(currentStep) && BUILD_STEP_ORDER.indexOf(currentStep) <= stepIndex) {\n onStartOrProgress(localBuildProgress, timeout)(ctx);\n }\n }, ESTIMATED_PROGRESS_INTERVAL);\n }\n\n stepProgress[ctx.task] = {\n startedAt: Date.now(),\n ...stepProgress[ctx.task],\n ...(progress && total && { numerator: progress, denominator: total }),\n };\n\n localBuildProgress.value = {\n buildId: ctx.announcedBuild?.id,\n branch: ctx.git?.branch,\n buildProgressPercentage: Math.min(newPercentage, endPercentage),\n currentStep: ctx.task,\n stepProgress,\n };\n };\n\nexport const onCompleteOrError =\n (\n localBuildProgress: ReturnType<typeof SharedState.subscribe<LocalBuildProgress>>,\n timeout?: ReturnType<typeof setTimeout>\n ) =>\n (\n ctx: Context | InitialContext,\n error?: { formattedError: string; originalError: Error | Error[] }\n ) => {\n clearTimeout(timeout);\n\n // We should set this right before starting so it should never be unset during a build.\n if (!localBuildProgress.value) {\n throw new Error(\"Unexpected missing value for localBuildProgress\");\n }\n\n const { buildProgressPercentage, stepProgress } = localBuildProgress.value;\n\n if (error) {\n localBuildProgress.value = {\n buildId: ctx.announcedBuild?.id,\n branch: ctx.git?.branch,\n buildProgressPercentage,\n currentStep: abortController?.signal.aborted ? \"aborted\" : \"error\",\n stepProgress,\n formattedError: error.formattedError,\n originalError: error.originalError,\n previousBuildProgress: stepProgress,\n };\n return;\n }\n\n if (ctx.task && isKnownStep(ctx.task)) {\n stepProgress[ctx.task] = {\n ...stepProgress[ctx.task],\n completedAt: Date.now(),\n };\n }\n\n if (ctx.build && ctx.task === \"snapshot\") {\n localBuildProgress.value = {\n buildId: ctx.announcedBuild?.id,\n branch: ctx.git?.branch,\n buildProgressPercentage: 100,\n currentStep: \"complete\",\n stepProgress,\n changeCount: ctx.build.changeCount,\n errorCount: ctx.build.errorCount,\n previousBuildProgress: stepProgress,\n };\n }\n };\n\nexport const runChromaticBuild = async (\n localBuildProgress: ReturnType<typeof SharedState.subscribe<LocalBuildProgress>>,\n options: Partial<Options>\n) => {\n if (!options.projectId) throw new Error(\"Missing projectId\");\n if (!options.userToken) throw new Error(\"Missing userToken\");\n\n localBuildProgress.value = INITIAL_BUILD_PAYLOAD;\n\n // Timeout is defined here so it's shared between all handlers\n let timeout: ReturnType<typeof setTimeout> | undefined;\n\n abortController?.abort();\n abortController = new AbortController();\n\n process.env.SB_TESTBUILD = \"true\";\n\n await run({\n options: {\n ...options,\n\n // Local changes should never be auto-accepted\n autoAcceptChanges: false,\n // Test results must be awaited to get progress updates\n exitOnceUploaded: false,\n // Don't raise any alarms when changes are found\n exitZeroOnChanges: true,\n // We might want to drop this later and instead record \"uncommitted hashes\" on builds\n forceRebuild: true,\n // This should never be set for local builds\n fromCI: false,\n // Builds initiated from the addon are always considered local\n isLocalBuild: true,\n // Never skip local builds\n skip: false,\n\n experimental_onTaskStart: onStartOrProgress(localBuildProgress, timeout),\n experimental_onTaskProgress: onStartOrProgress(localBuildProgress, timeout),\n experimental_onTaskComplete: onCompleteOrError(localBuildProgress, timeout),\n experimental_onTaskError: onCompleteOrError(localBuildProgress, timeout),\n experimental_abortSignal: abortController?.signal,\n },\n });\n};\n\nexport const stopChromaticBuild = () => {\n abortController?.abort(new Error(\"Build canceled from Storybook\"));\n};\n","// eslint-disable-next-line import/no-unresolved\nimport { TaskName } from \"chromatic/node\";\nimport { filesize } from \"filesize\";\n\nimport { KnownStep, LocalBuildProgress, StepProgressPayload } from \"./types\";\n\nexport const isKnownStep = (\n taskOrStep: TaskName | LocalBuildProgress[\"currentStep\"]\n): taskOrStep is KnownStep => BUILD_STEP_ORDER.includes(taskOrStep as KnownStep);\n\nexport const hasProgressEvent = (task: TaskName) => [\"upload\", \"snapshot\"].includes(task);\n\n// Note this does not include the \"aborted\", \"complete\" and \"error\" steps\nexport const BUILD_STEP_ORDER: KnownStep[] = [\n \"initialize\",\n \"build\",\n \"upload\",\n \"verify\",\n \"snapshot\",\n];\n\nexport const BUILD_STEP_CONFIG: Record<\n LocalBuildProgress[\"currentStep\"],\n {\n key: LocalBuildProgress[\"currentStep\"];\n emoji: string;\n renderName: () => string;\n renderProgress: (payload: LocalBuildProgress) => string;\n renderComplete: () => string;\n estimateDuration: number;\n }\n> = {\n initialize: {\n key: \"initialize\",\n emoji: \"🚀\",\n renderName: () => `Initialize build`,\n renderProgress: () => `Initializing build`,\n renderComplete: () => `Initialized`,\n estimateDuration: 2000,\n },\n build: {\n key: \"build\",\n emoji: \"🏗\",\n renderName: () => `Build Storybook`,\n renderProgress: () => `Building your Storybook...`,\n renderComplete: () => `Storybook built`,\n estimateDuration: 30_000,\n },\n upload: {\n key: \"upload\",\n emoji: \"📡\",\n renderName: () => `Publish your Storybook`,\n renderProgress: ({ stepProgress }) => {\n const { numerator, denominator } = stepProgress.upload;\n if (!denominator || !numerator) return `Uploading files`;\n const { value: total, exponent } = filesize(denominator, {\n output: \"object\",\n round: 1,\n });\n const { value: progress, symbol } = filesize(numerator, {\n exponent,\n output: \"object\",\n round: 1,\n });\n return `Uploading files (${progress}/${total} ${symbol})`;\n },\n renderComplete: () => `Publish complete`,\n estimateDuration: 30_000,\n },\n verify: {\n key: \"verify\",\n emoji: \"🔍\",\n renderName: () => `Verify your Storybook`,\n renderProgress: () => `Verifying contents...`,\n renderComplete: () => `Storybook verified`,\n estimateDuration: 10_000,\n },\n snapshot: {\n key: \"snapshot\",\n emoji: \"📸\",\n renderName: () => `Run visual tests`,\n renderProgress: ({ stepProgress }) => {\n const { numerator, denominator } = stepProgress.snapshot;\n return denominator\n ? `Running visual tests (${numerator}/${denominator})`\n : `Running visual tests`;\n },\n renderComplete: () => `Tested your stories`,\n estimateDuration: 60_000,\n },\n\n // These are special steps that are not part of the build process\n aborted: {\n key: \"aborted\",\n emoji: \"✋\",\n renderName: () => `Build canceled`,\n renderProgress: () => `Build canceled`,\n renderComplete: () => `Build canceled`,\n estimateDuration: 0,\n },\n complete: {\n key: \"complete\",\n emoji: \"🎉\",\n renderName: () => `Visual tests completed!`,\n renderProgress: () => `Visual tests completed!`,\n renderComplete: () => `Visual tests completed!`,\n estimateDuration: 0,\n },\n error: {\n key: \"error\",\n emoji: \"🚨\",\n renderName: () => `Build failed`,\n renderProgress: () => `Build failed`,\n renderComplete: () => `Build failed`,\n estimateDuration: 0,\n },\n};\n\nexport const INITIAL_BUILD_PAYLOAD = {\n buildProgressPercentage: 0,\n currentStep: BUILD_STEP_ORDER[0],\n stepProgress: Object.fromEntries(BUILD_STEP_ORDER.map((step) => [step, {}])) as Record<\n KnownStep,\n StepProgressPayload\n >,\n};\n","import type { Channel } from \"@storybook/channels\";\n\nexport const GET_VALUE = `experimental_useSharedState_getValue`;\nexport const SET_VALUE = `experimental_useSharedState_setValue`;\n\ntype ChannelLike = Pick<Channel, \"emit\" | \"on\" | \"off\">;\n\nconst instances = new Map<string, SharedState>();\n\nexport class SharedState<T = any> {\n channel: ChannelLike;\n\n listeners: ((value: T | undefined) => void)[];\n\n state: { [key: string]: { index: number; value: T | undefined } };\n\n constructor(channel: ChannelLike) {\n this.channel = channel;\n this.listeners = [];\n this.state = {};\n\n this.channel.on(SET_VALUE, (key: string, value: T | undefined, index: number) => {\n if (this.state?.[key]?.index >= index) return;\n this.state[key] = { index, value };\n });\n\n this.channel.on(GET_VALUE, (key: string) => {\n const index = this.state[key]?.index ?? 0;\n const value = this.state[key]?.value;\n this.channel.emit(SET_VALUE, key, value, index);\n });\n }\n\n get(key: string) {\n if (!this.state[key]) this.channel.emit(GET_VALUE, key);\n return this.state[key]?.value;\n }\n\n set(key: string, value: T | undefined) {\n const index = (this.state[key]?.index ?? 0) + 1;\n this.state[key] = { index, value };\n this.channel.emit(SET_VALUE, key, value, index);\n }\n\n static subscribe<T>(key: string, channel: ChannelLike) {\n const sharedState = instances.get(key) || new SharedState(channel);\n\n if (!instances.has(key)) {\n instances.set(key, sharedState);\n sharedState.channel.on(SET_VALUE, (k: string, v: T | undefined) => {\n if (k !== key) return;\n sharedState.listeners.forEach((listener) => listener(v));\n });\n }\n\n return {\n get value(): T | undefined {\n return sharedState.get(key);\n },\n\n set value(newValue: T | undefined) {\n sharedState.set(key, newValue);\n },\n\n on(event: \"change\", callback: (value: T | undefined) => void) {\n if (event !== \"change\") throw new Error(\"unsupported event\");\n sharedState.listeners.push(callback);\n },\n\n off(event: \"change\", callback: (value: T | undefined) => void) {\n if (event !== \"change\") throw new Error(\"unsupported event\");\n const index = sharedState.listeners.indexOf(callback);\n if (index >= 0) sharedState.listeners.splice(index, 1);\n },\n };\n }\n}\n","import type { Configuration } from \"chromatic/node\";\nimport { writeFile } from \"jsonfile\";\n\nexport async function updateChromaticConfig(configFile: string, configuration: Configuration) {\n await writeFile(configFile, configuration);\n}\n"]}
|