creevey 0.7.37 → 0.8.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (130) hide show
  1. package/CHANGELOG.md +30 -5
  2. package/README.md +1 -1
  3. package/docs/config.md +37 -5
  4. package/docs/grid.md +2 -1
  5. package/lib/cjs/client/addon/Manager.js +3 -1
  6. package/lib/cjs/client/addon/utils.js +1 -41
  7. package/lib/cjs/client/addon/withCreevey.js +11 -13
  8. package/lib/cjs/client/web/1.js +2 -2
  9. package/lib/cjs/client/web/2.js +1 -1
  10. package/lib/cjs/client/web/main.js +6 -6
  11. package/lib/cjs/index.js +14 -1
  12. package/lib/cjs/server/config.js +3 -0
  13. package/lib/cjs/server/extract.js +7 -3
  14. package/lib/cjs/server/loaders/babel/register.js +2 -1
  15. package/lib/cjs/server/loaders/webpack/compile.js +3 -19
  16. package/lib/cjs/server/loaders/webpack/creevey-loader.js +1 -1
  17. package/lib/cjs/server/master/master.js +3 -5
  18. package/lib/cjs/server/selenium/browser.js +25 -11
  19. package/lib/cjs/server/selenium/selenoid.js +1 -1
  20. package/lib/cjs/server/stories.js +20 -226
  21. package/lib/cjs/server/storybook/entry.js +5 -4
  22. package/lib/cjs/server/storybook/helpers.js +40 -4
  23. package/lib/cjs/server/storybook/nodejs-provider.js +220 -0
  24. package/lib/cjs/server/utils.js +25 -2
  25. package/lib/cjs/server/worker/helpers.js +8 -9
  26. package/lib/cjs/server/worker/worker.js +1 -2
  27. package/lib/cjs/shared.js +35 -0
  28. package/lib/esm/client/addon/Manager.js +3 -2
  29. package/lib/esm/client/addon/utils.js +1 -33
  30. package/lib/esm/client/addon/withCreevey.js +1 -1
  31. package/lib/esm/index.js +3 -1
  32. package/lib/esm/server/config.js +4 -1
  33. package/lib/esm/server/extract.js +7 -3
  34. package/lib/esm/server/loaders/babel/register.js +3 -2
  35. package/lib/esm/server/loaders/webpack/compile.js +4 -20
  36. package/lib/esm/server/loaders/webpack/creevey-loader.js +1 -1
  37. package/lib/esm/server/master/master.js +3 -5
  38. package/lib/esm/server/selenium/browser.js +22 -7
  39. package/lib/esm/server/selenium/selenoid.js +1 -1
  40. package/lib/esm/server/stories.js +23 -219
  41. package/lib/esm/server/storybook/entry.js +4 -4
  42. package/lib/esm/server/storybook/helpers.js +36 -4
  43. package/lib/esm/server/storybook/nodejs-provider.js +200 -0
  44. package/lib/esm/server/utils.js +23 -1
  45. package/lib/esm/server/worker/helpers.js +8 -9
  46. package/lib/esm/server/worker/worker.js +1 -2
  47. package/lib/esm/shared.js +22 -0
  48. package/lib/types/cli.d.ts +1 -1
  49. package/lib/types/client/addon/Manager.d.ts +37 -37
  50. package/lib/types/client/addon/components/Addon.d.ts +8 -8
  51. package/lib/types/client/addon/components/Icons.d.ts +7 -7
  52. package/lib/types/client/addon/components/Panel.d.ts +9 -9
  53. package/lib/types/client/addon/components/TestSelect.d.ts +9 -9
  54. package/lib/types/client/addon/components/Tools.d.ts +6 -6
  55. package/lib/types/client/addon/decorator.d.ts +1 -1
  56. package/lib/types/client/addon/preset.d.ts +22 -22
  57. package/lib/types/client/addon/register.d.ts +3 -3
  58. package/lib/types/client/addon/utils.d.ts +2 -6
  59. package/lib/types/client/addon/withCreevey.d.ts +13 -46
  60. package/lib/types/client/shared/components/ImagesView/BlendView.d.ts +3 -3
  61. package/lib/types/client/shared/components/ImagesView/ImagesView.d.ts +25 -25
  62. package/lib/types/client/shared/components/ImagesView/SideBySideView.d.ts +3 -3
  63. package/lib/types/client/shared/components/ImagesView/SlideView.d.ts +3 -3
  64. package/lib/types/client/shared/components/ImagesView/SwapView.d.ts +3 -3
  65. package/lib/types/client/shared/components/ImagesView/index.d.ts +5 -5
  66. package/lib/types/client/shared/components/PageFooter/PageFooter.d.ts +9 -9
  67. package/lib/types/client/shared/components/PageFooter/Paging.d.ts +8 -8
  68. package/lib/types/client/shared/components/PageHeader/ImagePreview.d.ts +12 -12
  69. package/lib/types/client/shared/components/PageHeader/PageHeader.d.ts +17 -17
  70. package/lib/types/client/shared/components/ResultsPage.d.ts +18 -18
  71. package/lib/types/client/shared/creeveyClientApi.d.ts +9 -9
  72. package/lib/types/client/shared/helpers.d.ts +46 -46
  73. package/lib/types/client/shared/viewMode.d.ts +4 -4
  74. package/lib/types/client/web/CreeveyApp.d.ts +12 -12
  75. package/lib/types/client/web/CreeveyContext.d.ts +11 -11
  76. package/lib/types/client/web/CreeveyLoader.d.ts +3 -3
  77. package/lib/types/client/web/CreeveyView/SideBar/Checkbox.d.ts +19 -19
  78. package/lib/types/client/web/CreeveyView/SideBar/Search.d.ts +6 -6
  79. package/lib/types/client/web/CreeveyView/SideBar/SideBar.d.ts +14 -14
  80. package/lib/types/client/web/CreeveyView/SideBar/SideBarHeader.d.ts +13 -13
  81. package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +33 -33
  82. package/lib/types/client/web/CreeveyView/SideBar/TestLink.d.ts +8 -8
  83. package/lib/types/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +10 -10
  84. package/lib/types/client/web/CreeveyView/SideBar/TestsStatus.d.ts +9 -9
  85. package/lib/types/client/web/CreeveyView/SideBar/Toggle.d.ts +6 -6
  86. package/lib/types/client/web/CreeveyView/SideBar/index.d.ts +1 -1
  87. package/lib/types/client/web/KeyboardEventsContext.d.ts +13 -13
  88. package/lib/types/client/web/index.d.ts +4 -4
  89. package/lib/types/creevey.d.ts +1 -1
  90. package/lib/types/server/config.d.ts +4 -4
  91. package/lib/types/server/docker.d.ts +7 -7
  92. package/lib/types/server/extract.d.ts +2 -2
  93. package/lib/types/server/index.d.ts +2 -2
  94. package/lib/types/server/loaders/babel/creevey-plugin.d.ts +1 -1
  95. package/lib/types/server/loaders/babel/helpers.d.ts +19 -19
  96. package/lib/types/server/loaders/babel/register.d.ts +5 -5
  97. package/lib/types/server/loaders/hooks/mdx.d.ts +1 -1
  98. package/lib/types/server/loaders/hooks/svelte.d.ts +1 -1
  99. package/lib/types/server/loaders/webpack/compile.d.ts +2 -2
  100. package/lib/types/server/loaders/webpack/creevey-loader.d.ts +2 -2
  101. package/lib/types/server/loaders/webpack/dummy-hmr.d.ts +10 -10
  102. package/lib/types/server/loaders/webpack/mdx-loader.d.ts +6 -6
  103. package/lib/types/server/loaders/webpack/start.d.ts +1 -1
  104. package/lib/types/server/logger.d.ts +6 -6
  105. package/lib/types/server/master/api.d.ts +7 -7
  106. package/lib/types/server/master/index.d.ts +3 -3
  107. package/lib/types/server/master/master.d.ts +6 -6
  108. package/lib/types/server/master/pool.d.ts +30 -30
  109. package/lib/types/server/master/runner.d.ts +26 -26
  110. package/lib/types/server/master/server.d.ts +2 -2
  111. package/lib/types/server/messages.d.ts +18 -18
  112. package/lib/types/server/selenium/browser.d.ts +14 -14
  113. package/lib/types/server/selenium/index.d.ts +2 -2
  114. package/lib/types/server/selenium/selenoid.d.ts +3 -3
  115. package/lib/types/server/stories.d.ts +8 -13
  116. package/lib/types/server/storybook/entry.d.ts +18 -14
  117. package/lib/types/server/storybook/helpers.d.ts +24 -22
  118. package/lib/types/server/storybook/nodejs-provider.d.ts +5 -0
  119. package/lib/types/server/update.d.ts +2 -2
  120. package/lib/types/server/utils.d.ts +19 -18
  121. package/lib/types/server/worker/chai-image.d.ts +6 -6
  122. package/lib/types/server/worker/helpers.d.ts +7 -7
  123. package/lib/types/server/worker/index.d.ts +1 -1
  124. package/lib/types/server/worker/reporter.d.ts +8 -8
  125. package/lib/types/server/worker/worker.d.ts +4 -4
  126. package/lib/types/shared.d.ts +4 -0
  127. package/lib/types/types.d.ts +459 -431
  128. package/package.json +53 -48
  129. package/types/mocha.d.ts +1 -0
  130. package/storybook-static/stories.json +0 -530
@@ -1,15 +1,11 @@
1
1
  import path from 'path';
2
2
  import { mkdirSync, writeFileSync } from 'fs';
3
- import { isWorker, isMaster } from 'cluster';
4
3
  import { createHash } from 'crypto';
5
- import chokidar from 'chokidar';
6
- import { isDefined, isFunction, isObject, noop } from '../types';
7
- import { shouldSkip, getCreeveyCache, removeProps } from './utils';
8
- import { mergeWith } from 'lodash';
9
- import { subscribeOn } from './messages';
10
- import { importStorybookClientLogger, importStorybookConfig, importStorybookCoreCommon, importStorybookCoreEvents, isStorybookVersionLessThan } from './storybook/helpers';
11
- import { logger } from './logger';
12
- export let storybookApi = null;
4
+ import { mapValues, pick } from 'lodash';
5
+ import { isDefined, isFunction, isObject } from '../types';
6
+ import { shouldSkip, removeProps } from './utils';
7
+ import { isStorybookVersionGreaterThan, isStorybookVersionLessThan } from './storybook/helpers';
8
+ import { denormalizeStoryParameters } from '../shared';
13
9
 
14
10
  function storyTestFabric(delay, testFn) {
15
11
  return async function storyTest() {
@@ -83,214 +79,9 @@ function convertStories(browsers, stories) {
83
79
  return tests;
84
80
  }
85
81
 
86
- async function initStorybookEnvironment() {
87
- // eslint-disable-next-line @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
88
- (await import('jsdom-global')).default(undefined, {
89
- url: 'http://localhost'
90
- }); // NOTE Cutoff `jsdom` part from userAgent, because storybook check enviroment and create events channel if runs in browser
91
- // https://github.com/storybookjs/storybook/blob/v5.2.8/lib/core/src/client/preview/start.js#L98
92
- // Example: "Mozilla/5.0 (linux) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/15.2.1"
93
-
94
- Object.defineProperty(window.navigator, 'userAgent', {
95
- value: window.navigator.userAgent.split(' ').filter(token => !token.startsWith('jsdom')).join(' ')
96
- }); // TODO Look at creevey debug flag
97
-
98
- const {
99
- logger
100
- } = await importStorybookClientLogger(); // NOTE: Disable duplication warnings for >=6.2 storybook
101
-
102
- if (isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
103
-
104
- logger.debug = noop;
105
- return import('./storybook/entry');
106
- }
107
-
108
- function watchStories(channel, watcher, initialFiles) {
109
- const watchingFiles = initialFiles;
110
- let storiesByFiles = new Map();
111
- subscribeOn('shutdown', () => void watcher.close());
112
- watcher.add(Array.from(watchingFiles));
113
- watcher.on('change', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
114
- watcher.on('unlink', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
115
- return data => {
116
- const stories = isStorybookVersionLessThan(6) ? data.stories : flatStories(data);
117
- const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
118
- const addedFiles = Array.from(files).filter(filePath => !watchingFiles.has(filePath));
119
- const removedFiles = Array.from(watchingFiles).filter(filePath => !files.has(filePath));
120
- watcher.add(addedFiles);
121
- addedFiles.forEach(filePath => {
122
- watchingFiles.add(filePath);
123
- storiesByFiles.set(filePath, []);
124
- });
125
- removedFiles.forEach(filePath => watchingFiles.delete(filePath));
126
- Object.values(stories).forEach(story => {
127
- var _storiesByFiles$get;
128
-
129
- return (_storiesByFiles$get = storiesByFiles.get(story.parameters.fileName)) === null || _storiesByFiles$get === void 0 ? void 0 : _storiesByFiles$get.push(story);
130
- });
131
- channel.emit('storiesUpdated', storiesByFiles);
132
- storiesByFiles = new Map();
133
- };
134
- } // TODO use the storybook version, after the fix of skip option API
135
-
136
-
137
- function flatStories({
138
- globalParameters,
139
- kindParameters,
140
- stories
141
- }) {
142
- Object.values(stories).forEach(story => {
143
- // NOTE: Copy-paste merge parameters from storybook
144
- story.parameters = mergeWith({}, globalParameters, kindParameters[story.kind], story.parameters, (objValue, srcValue) => Array.isArray(objValue) ? objValue.concat(srcValue) : undefined);
145
- });
146
- return stories;
147
- }
148
-
149
- function loadStoriesFromBundle(watch) {
150
- const bundlePath = path.join(getCreeveyCache(), 'storybook/main.js');
151
-
152
- if (watch) {
153
- subscribeOn('webpack', message => {
154
- if (message.type != 'rebuild succeeded') return;
155
- Object.values(global.__CREEVEY_HMR_DATA__).filter(({
156
- callback
157
- }) => callback).forEach(({
158
- data,
159
- callback
160
- }) => callback(data));
161
- delete require.cache[bundlePath];
162
- import(bundlePath);
163
- });
164
- }
165
-
166
- import(bundlePath);
167
- }
168
-
169
- async function loadStoriesDirectly(config, {
170
- watcher,
171
- debug
172
- }) {
173
- const {
174
- toRequireContext
175
- } = await importStorybookCoreCommon();
176
- const {
177
- addParameters,
178
- configure
179
- } = await import('./storybook/entry');
180
- const requireContext = await (await import('./loaders/babel/register')).default(config, debug);
181
-
182
- const preview = (() => {
183
- try {
184
- return require.resolve(`${config.storybookDir}/preview`);
185
- } catch (_) {
186
- /* noop */
187
- }
188
- })();
189
-
190
- const {
191
- stories
192
- } = await importStorybookConfig();
193
- const contexts = stories.map(input => {
194
- const {
195
- path: storiesPath,
196
- recursive,
197
- match
198
- } = toRequireContext(input);
199
- watcher === null || watcher === void 0 ? void 0 : watcher.add(path.resolve(config.storybookDir, storiesPath));
200
- return () => requireContext(storiesPath, recursive, new RegExp(match));
201
- });
202
-
203
- let disposeCallback = data => void data;
204
-
205
- Object.assign(module, {
206
- hot: {
207
- data: {},
208
-
209
- accept() {
210
- /* noop */
211
- },
212
-
213
- dispose(callback) {
214
- disposeCallback = callback;
215
- }
216
-
217
- }
218
- });
219
-
220
- async function startStorybook() {
221
- if (preview) {
222
- const {
223
- parameters,
224
- globals,
225
- globalTypes
226
- } = await import(preview);
227
- if (parameters) addParameters(parameters);
228
- if (globals) addParameters({
229
- globals
230
- });
231
- if (globalTypes) addParameters({
232
- globalTypes
233
- });
234
- }
235
-
236
- try {
237
- configure(contexts.map(ctx => ctx()), module, false);
238
- } catch (error) {
239
- if (isMaster) logger.error(error);
240
- }
241
- }
242
-
243
- watcher === null || watcher === void 0 ? void 0 : watcher.add(config.storybookDir);
244
- watcher === null || watcher === void 0 ? void 0 : watcher.on('all', (_event, filename) => {
245
- var _module$hot;
246
-
247
- disposeCallback((_module$hot = module.hot) === null || _module$hot === void 0 ? void 0 : _module$hot.data);
248
- delete require.cache[filename];
249
- void startStorybook();
250
- });
251
- void startStorybook();
252
- }
253
-
254
- async function loadStorybook(config, {
255
- watch,
256
- debug
257
- }, storiesListener) {
258
- storybookApi = await initStorybookEnvironment();
259
- const Events = await importStorybookCoreEvents();
260
- const {
261
- channel
262
- } = storybookApi;
263
- channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
264
- channel.on('storiesUpdated', storiesListener);
265
- let watcher = null;
266
- if (watch) watcher = chokidar.watch([], {
267
- ignoreInitial: true
268
- });
269
- const loadPromise = new Promise(resolve => {
270
- channel.once(Events.SET_STORIES, data => {
271
- const stories = isStorybookVersionLessThan(6) ? data.stories : flatStories(data);
272
- const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
273
- if (watcher) channel.on(Events.SET_STORIES, watchStories(channel, watcher, files));
274
- resolve(stories);
275
- });
276
- });
277
- if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
278
- watcher,
279
- debug
280
- });
281
- return loadPromise;
282
- }
283
-
284
- export async function loadTestsFromStories(config, browsers, {
285
- watch = false,
286
- debug = false,
287
- update
288
- }) {
82
+ export async function loadTestsFromStories(browsers, provider, update) {
289
83
  const testIdsByFiles = new Map();
290
- const stories = await loadStorybook(config, {
291
- debug,
292
- watch
293
- }, storiesByFiles => {
84
+ const data = await provider(storiesByFiles => {
294
85
  const testsDiff = {};
295
86
  Array.from(storiesByFiles.entries()).forEach(([filename, stories]) => {
296
87
  var _testIdsByFiles$get$f, _testIdsByFiles$get;
@@ -304,6 +95,7 @@ export async function loadTestsFromStories(config, browsers, {
304
95
  });
305
96
  update === null || update === void 0 ? void 0 : update(testsDiff);
306
97
  });
98
+ const stories = isStorybookVersionLessThan(6) || isStorybookVersionGreaterThan(6, 3) ? data.stories : denormalizeStoryParameters(data);
307
99
  const tests = convertStories(browsers, stories);
308
100
  Object.values(tests).filter(isDefined).forEach(({
309
101
  id,
@@ -321,11 +113,23 @@ export async function loadTestsFromStories(config, browsers, {
321
113
  });
322
114
  return tests;
323
115
  }
324
- export function saveStoriesJson(extract) {
325
- var _storybookApi, _storiesData$stories;
116
+ export function saveStoriesJson(storiesData, extract) {
117
+ var _storiesData$stories;
326
118
 
327
119
  const outputDir = typeof extract == 'boolean' ? 'storybook-static' : extract;
328
- const storiesData = (_storybookApi = storybookApi) === null || _storybookApi === void 0 ? void 0 : _storybookApi.clientApi.store().getStoriesJsonData(); // TODO Fix args stories
120
+
121
+ if (!isStorybookVersionLessThan(6)) {
122
+ // NOTE Copy-pasted from Storybook's `getStoriesJsonData` method
123
+ const allowed = ['fileName', 'docsOnly', 'framework', '__id', '__isArgsStory'];
124
+ storiesData.globalParameters = pick(storiesData.globalParameters, allowed); // @ts-expect-error ignore error
125
+
126
+ storiesData.kindParameters = mapValues(storiesData.kindParameters, v => pick(v, allowed)); // @ts-expect-error ignore error
127
+
128
+ storiesData.stories = mapValues(storiesData.stories, v => ({ ...pick(v, ['id', 'name', 'kind', 'story']),
129
+ parameters: pick(v.parameters, allowed)
130
+ }));
131
+ } // TODO Fix args stories
132
+
329
133
 
330
134
  removeProps(storiesData !== null && storiesData !== void 0 ? storiesData : {}, ['stories', () => true, 'parameters', '__isArgsStory']);
331
135
  Object.values((_storiesData$stories = storiesData === null || storiesData === void 0 ? void 0 : storiesData.stories) !== null && _storiesData$stories !== void 0 ? _storiesData$stories : {}).forEach(story => isObject(story) && 'parameters' in story && isObject(story.parameters) && delete story.parameters.__isArgsStory);
@@ -1,5 +1,6 @@
1
1
  var _api$channel, _api$context;
2
2
 
3
+ import { addons } from '@storybook/addons';
3
4
  import { getStorybookFramework, isStorybookVersionLessThan, resolveFromStorybook } from './helpers';
4
5
  const framework = getStorybookFramework(); // eslint-disable-next-line @typescript-eslint/no-var-requires
5
6
 
@@ -8,10 +9,8 @@ const core = require(resolveFromStorybook('@storybook/core')); //@ts-expect-erro
8
9
 
9
10
 
10
11
  const start = isStorybookVersionLessThan(6, 2) ? core.default.start : core.start;
11
- const api = start(() => void 0); //@ts-expect-error: 6.x has { channel }, but 5.x has { context: { channel } }
12
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
13
-
14
- export const channel = (_api$channel = api.channel) !== null && _api$channel !== void 0 ? _api$channel : (_api$context = api.context) === null || _api$context === void 0 ? void 0 : _api$context.channel;
12
+ const api = start(() => void 0);
13
+ export const channel = isStorybookVersionLessThan(6, 4) ? (_api$channel = api.channel) !== null && _api$channel !== void 0 ? _api$channel : (_api$context = api.context) === null || _api$context === void 0 ? void 0 : _api$context.channel : addons.getChannel();
15
14
  export const clientApi = api.clientApi;
16
15
  export const forceReRender = api.forceReRender;
17
16
  export const storiesOf = (kind, m) => {
@@ -23,6 +22,7 @@ export const configure = (...args) => {
23
22
  if (isStorybookVersionLessThan(5, 2)) {
24
23
  //NOTE: Storybook <= 5.1 pass args as is
25
24
  //@ts-expect-error: ignore it
25
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
26
26
  return api.configApi.configure(...args);
27
27
  }
28
28
 
@@ -45,16 +45,22 @@ export function isStorybookVersionLessThan(major, minor) {
45
45
  const [sbMajor, sbMinor] = ((_process$env$__CREEVE = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE !== void 0 ? _process$env$__CREEVE : getStorybookVersion()).split('.');
46
46
  return Number(sbMajor) < major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) < minor;
47
47
  }
48
- export function isStorybookVersion(major, minor) {
48
+ export function isStorybookVersionGreaterThan(major, minor) {
49
49
  var _process$env$__CREEVE2;
50
50
 
51
51
  const [sbMajor, sbMinor] = ((_process$env$__CREEVE2 = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE2 !== void 0 ? _process$env$__CREEVE2 : getStorybookVersion()).split('.');
52
+ return Number(sbMajor) > major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) > minor;
53
+ }
54
+ export function isStorybookVersion(major, minor) {
55
+ var _process$env$__CREEVE3;
56
+
57
+ const [sbMajor, sbMinor] = ((_process$env$__CREEVE3 = process.env.__CREEVEY_STORYBOOK_VERSION__) !== null && _process$env$__CREEVE3 !== void 0 ? _process$env$__CREEVE3 : getStorybookVersion()).split('.');
52
58
  return Number(sbMajor) == major || minor != undefined && Number(sbMajor) == major && Number(sbMinor) == minor;
53
59
  }
54
60
  export function getStorybookFramework() {
55
- var _process$env$__CREEVE3;
61
+ var _process$env$__CREEVE4;
56
62
 
57
- const framework = (_process$env$__CREEVE3 = process.env.__CREEVEY_STORYBOOK_FRAMEWORK__) !== null && _process$env$__CREEVE3 !== void 0 ? _process$env$__CREEVE3 : supportedFrameworks.find(framework => {
63
+ const framework = (_process$env$__CREEVE4 = process.env.__CREEVEY_STORYBOOK_FRAMEWORK__) !== null && _process$env$__CREEVE4 !== void 0 ? _process$env$__CREEVE4 : supportedFrameworks.find(framework => {
58
64
  try {
59
65
  return require.resolve(resolveFromStorybook(`@storybook/${framework}`));
60
66
  } catch (_) {
@@ -70,5 +76,31 @@ export const storybookConfigRef = {
70
76
  }
71
77
  };
72
78
  export async function importStorybookConfig() {
73
- return storybookConfigRef.current = (await import(require.resolve(`${storybookDirRef.current}/main`))).default;
79
+ const configPath = `${storybookDirRef.current}/main`;
80
+
81
+ try {
82
+ return storybookConfigRef.current = (await import(require.resolve(configPath))).default;
83
+ } catch (_) {
84
+ const storybookUtilsPath = isStorybookVersionLessThan(6, 2) ? '@storybook/core/dist/server/utils' : '@storybook/core-common/dist/cjs/utils';
85
+ const serverRequireModule = isStorybookVersionLessThan(6, 2) ? 'server-require' : 'interpret-require'; // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
86
+
87
+ const {
88
+ getInterpretedFile
89
+ } = await import(resolveFromStorybook(`${storybookUtilsPath}/interpret-files`)); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
90
+
91
+ const {
92
+ default: serverRequireFallback,
93
+ serverRequire = serverRequireFallback
94
+ } = await import(resolveFromStorybook(`${storybookUtilsPath}/${serverRequireModule}`)); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
95
+
96
+ const mainConfigFile = isStorybookVersionLessThan(6, 1) ? configPath : // eslint-disable-next-line @typescript-eslint/no-unsafe-call
97
+ getInterpretedFile(configPath); // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call
98
+
99
+ return storybookConfigRef.current = serverRequire(mainConfigFile);
100
+ }
101
+ }
102
+ export async function isCSFv3Enabled() {
103
+ var _await$importStoryboo, _await$importStoryboo2, _await$importStoryboo3;
104
+
105
+ return (_await$importStoryboo = (_await$importStoryboo2 = await importStorybookConfig()) === null || _await$importStoryboo2 === void 0 ? void 0 : (_await$importStoryboo3 = _await$importStoryboo2.features) === null || _await$importStoryboo3 === void 0 ? void 0 : _await$importStoryboo3.previewCsfV3) !== null && _await$importStoryboo !== void 0 ? _await$importStoryboo : false;
74
106
  }
@@ -0,0 +1,200 @@
1
+ /* eslint-disable @typescript-eslint/no-var-requires, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-call,@typescript-eslint/no-unsafe-member-access,@typescript-eslint/ban-ts-comment */
2
+ import path from 'path';
3
+ import { isWorker, isMaster } from 'cluster';
4
+ import chokidar from 'chokidar';
5
+ import { noop } from '../../types';
6
+ import { getCreeveyCache } from '../utils';
7
+ import { subscribeOn } from '../messages';
8
+ import { importStorybookClientLogger, importStorybookConfig, importStorybookCoreCommon, importStorybookCoreEvents, isStorybookVersionGreaterThan, isStorybookVersionLessThan } from './helpers';
9
+ import { logger } from '../logger';
10
+ import { denormalizeStoryParameters } from '../../shared';
11
+
12
+ async function initStorybookEnvironment() {
13
+ // @ts-ignore
14
+ (await import('global-jsdom')).default(undefined, {
15
+ url: 'http://localhost'
16
+ }); // NOTE Cutoff `jsdom` part from userAgent, because storybook check enviroment and create events channel if runs in browser
17
+ // https://github.com/storybookjs/storybook/blob/v5.2.8/lib/core/src/client/preview/start.js#L98
18
+ // Example: "Mozilla/5.0 (linux) AppleWebKit/537.36 (KHTML, like Gecko) jsdom/15.2.1"
19
+
20
+ Object.defineProperty(window.navigator, 'userAgent', {
21
+ value: window.navigator.userAgent.split(' ').filter(token => !token.startsWith('jsdom')).join(' ')
22
+ }); // TODO Look at creevey debug flag
23
+
24
+ const {
25
+ logger
26
+ } = await importStorybookClientLogger(); // NOTE: Disable duplication warnings for >=6.2 storybook
27
+
28
+ if (isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
29
+
30
+ logger.debug = noop;
31
+ return import('./entry');
32
+ }
33
+
34
+ function watchStories(channel, watcher, initialFiles) {
35
+ const watchingFiles = initialFiles;
36
+ let storiesByFiles = new Map();
37
+ subscribeOn('shutdown', () => void watcher.close());
38
+ watcher.add(Array.from(watchingFiles));
39
+ watcher.on('change', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
40
+ watcher.on('unlink', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
41
+ return data => {
42
+ const stories = isStorybookVersionLessThan(6) || isStorybookVersionGreaterThan(6, 3) ? data.stories : denormalizeStoryParameters(data);
43
+ const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
44
+ const addedFiles = Array.from(files).filter(filePath => !watchingFiles.has(filePath));
45
+ const removedFiles = Array.from(watchingFiles).filter(filePath => !files.has(filePath));
46
+ watcher.add(addedFiles);
47
+ addedFiles.forEach(filePath => {
48
+ watchingFiles.add(filePath);
49
+ storiesByFiles.set(filePath, []);
50
+ });
51
+ removedFiles.forEach(filePath => watchingFiles.delete(filePath));
52
+ Object.values(stories).forEach(story => {
53
+ var _storiesByFiles$get;
54
+
55
+ return (_storiesByFiles$get = storiesByFiles.get(story.parameters.fileName)) === null || _storiesByFiles$get === void 0 ? void 0 : _storiesByFiles$get.push(story);
56
+ });
57
+ channel.emit('storiesUpdated', storiesByFiles);
58
+ storiesByFiles = new Map();
59
+ };
60
+ }
61
+
62
+ function loadStoriesFromBundle(watch) {
63
+ const bundlePath = path.join(getCreeveyCache(), 'storybook/main.js');
64
+
65
+ if (watch) {
66
+ subscribeOn('webpack', message => {
67
+ if (message.type != 'rebuild succeeded') return;
68
+ Object.values(global.__CREEVEY_HMR_DATA__).filter(({
69
+ callback
70
+ }) => callback).forEach(({
71
+ data,
72
+ callback
73
+ }) => callback(data));
74
+ delete require.cache[bundlePath];
75
+ import(bundlePath);
76
+ });
77
+ }
78
+
79
+ import(bundlePath);
80
+ }
81
+
82
+ async function loadStoriesDirectly(config, {
83
+ watcher,
84
+ debug
85
+ }) {
86
+ const {
87
+ toRequireContext,
88
+ normalizeStoriesEntry
89
+ } = await importStorybookCoreCommon();
90
+ const {
91
+ addParameters,
92
+ configure
93
+ } = await import('./entry');
94
+ const requireContext = await (await import('../loaders/babel/register')).default(config, debug);
95
+
96
+ const preview = (() => {
97
+ try {
98
+ return require.resolve(`${config.storybookDir}/preview`);
99
+ } catch (_) {
100
+ /* noop */
101
+ }
102
+ })();
103
+
104
+ const {
105
+ stories
106
+ } = await importStorybookConfig();
107
+ const contexts = stories.map(entry => {
108
+ const normalizedEntry = isStorybookVersionLessThan(6, 4) ? entry : normalizeStoriesEntry(entry, {
109
+ configDir: config.storybookDir,
110
+ workingDir: process.cwd()
111
+ });
112
+ const {
113
+ path: storiesPath,
114
+ recursive,
115
+ match
116
+ } = toRequireContext(normalizedEntry);
117
+ watcher === null || watcher === void 0 ? void 0 : watcher.add(path.resolve(config.storybookDir, storiesPath));
118
+ return () => requireContext(storiesPath, recursive, new RegExp(match));
119
+ });
120
+
121
+ let disposeCallback = data => void data;
122
+
123
+ Object.assign(module, {
124
+ hot: {
125
+ data: {},
126
+
127
+ accept() {
128
+ /* noop */
129
+ },
130
+
131
+ dispose(callback) {
132
+ disposeCallback = callback;
133
+ }
134
+
135
+ }
136
+ });
137
+
138
+ async function startStorybook() {
139
+ if (preview) {
140
+ const {
141
+ parameters,
142
+ globals,
143
+ globalTypes
144
+ } = await import(preview);
145
+ if (parameters) addParameters(parameters);
146
+ if (globals) addParameters({
147
+ globals
148
+ });
149
+ if (globalTypes) addParameters({
150
+ globalTypes
151
+ });
152
+ }
153
+
154
+ try {
155
+ configure(contexts.map(ctx => ctx()), module, false);
156
+ } catch (error) {
157
+ if (isMaster) logger.error(error);
158
+ }
159
+ }
160
+
161
+ watcher === null || watcher === void 0 ? void 0 : watcher.add(config.storybookDir);
162
+ watcher === null || watcher === void 0 ? void 0 : watcher.on('all', (_event, filename) => {
163
+ var _module$hot;
164
+
165
+ disposeCallback((_module$hot = module.hot) === null || _module$hot === void 0 ? void 0 : _module$hot.data);
166
+ delete require.cache[filename];
167
+ void startStorybook();
168
+ });
169
+ void startStorybook();
170
+ }
171
+
172
+ export async function loadStories(config, {
173
+ watch,
174
+ debug
175
+ }, storiesListener) {
176
+ const storybookApi = await initStorybookEnvironment();
177
+ const Events = await importStorybookCoreEvents();
178
+ const {
179
+ channel
180
+ } = storybookApi;
181
+ channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
182
+ channel.on('storiesUpdated', storiesListener);
183
+ let watcher = null;
184
+ if (watch) watcher = chokidar.watch([], {
185
+ ignoreInitial: true
186
+ });
187
+ const loadPromise = new Promise(resolve => {
188
+ channel.once(Events.SET_STORIES, data => {
189
+ const stories = isStorybookVersionLessThan(6) || isStorybookVersionGreaterThan(6, 3) ? data.stories : denormalizeStoryParameters(data);
190
+ const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
191
+ if (watcher) channel.on(Events.SET_STORIES, watchStories(channel, watcher, files));
192
+ resolve(data);
193
+ });
194
+ });
195
+ if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
196
+ watcher,
197
+ debug
198
+ });
199
+ return loadPromise;
200
+ }
@@ -9,6 +9,7 @@ export const isShuttingDown = {
9
9
  };
10
10
  export const LOCALHOST_REGEXP = /(localhost|127\.0\.0\.1)/i;
11
11
  export const extensions = ['.js', '.jsx', '.ts', '.tsx'];
12
+ export const skipOptionKeys = ['in', 'kinds', 'stories', 'tests', 'reason'];
12
13
 
13
14
  function matchBy(pattern, value) {
14
15
  return typeof pattern == 'string' && pattern == value || Array.isArray(pattern) && pattern.includes(value) || pattern instanceof RegExp && pattern.test(value) || !isDefined(pattern);
@@ -20,9 +21,30 @@ export function shouldSkip(browser, meta, skipOptions, test) {
20
21
  }
21
22
 
22
23
  if (Array.isArray(skipOptions)) {
23
- return skipOptions.map(skipOption => shouldSkip(browser, meta, skipOption, test)).find(Boolean) || false;
24
+ for (const skip of skipOptions) {
25
+ const reason = shouldSkip(browser, meta, skip, test);
26
+ if (reason) return reason;
27
+ }
28
+
29
+ return false;
30
+ }
31
+
32
+ let hasSkipOptionKeys = false;
33
+
34
+ for (const skipKey in skipOptions) {
35
+ if (skipOptionKeys.includes(skipKey)) {
36
+ hasSkipOptionKeys = true;
37
+ continue;
38
+ }
39
+
40
+ const reason = shouldSkip(browser, meta, {
41
+ reason: skipKey,
42
+ ...skipOptions[skipKey]
43
+ }, test);
44
+ if (reason) return reason;
24
45
  }
25
46
 
47
+ if (!hasSkipOptionKeys) return false;
26
48
  const {
27
49
  in: browsers,
28
50
  kinds,
@@ -51,15 +51,14 @@ export async function addTestsFromStories(rootSuite, config, {
51
51
  debug
52
52
  }) {
53
53
  const mochaTestsById = new Map();
54
- const tests = await loadTestsFromStories(config, [browser], {
54
+ const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, {
55
55
  watch,
56
- debug,
57
- update: testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
58
- const oldTest = mochaTestsById.get(id);
59
- mochaTestsById.delete(id);
60
- if (oldTest) removeTestOrSuite(oldTest);
61
- if (newTest) mochaTestsById.set(id, addTest(rootSuite, newTest));
62
- })
63
- });
56
+ debug
57
+ }, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
58
+ const oldTest = mochaTestsById.get(id);
59
+ mochaTestsById.delete(id);
60
+ if (oldTest) removeTestOrSuite(oldTest);
61
+ if (newTest) mochaTestsById.set(id, addTest(rootSuite, newTest));
62
+ }));
64
63
  Object.values(tests).filter(isDefined).forEach(test => mochaTestsById.set(test.id, addTest(rootSuite, test)));
65
64
  }
@@ -22,8 +22,7 @@ async function getStat(filePath) {
22
22
  try {
23
23
  return await statAsync(filePath);
24
24
  } catch (error) {
25
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
26
- if (error.code === 'ENOENT') {
25
+ if (typeof error == 'object' && error && error.code === 'ENOENT') {
27
26
  return null;
28
27
  }
29
28
 
@@ -0,0 +1,22 @@
1
+ import { mapValues, mergeWith } from 'lodash';
2
+ // NOTE: Copy-paste from storybook/api
3
+ export const combineParameters = (...parameterSets) => // eslint-disable-next-line @typescript-eslint/no-unsafe-return
4
+ mergeWith({}, ...parameterSets, (_, srcValue) => {
5
+ // Treat arrays as scalars:
6
+ if (Array.isArray(srcValue)) return srcValue;
7
+ return undefined;
8
+ }); // NOTE: Copy-paste from storybook/api
9
+
10
+ export const denormalizeStoryParameters = ({
11
+ globalParameters,
12
+ kindParameters,
13
+ stories
14
+ }) => {
15
+ return mapValues(stories, storyData => {
16
+ var _kindParameters$story;
17
+
18
+ return { ...storyData,
19
+ parameters: combineParameters(globalParameters, (_kindParameters$story = kindParameters[storyData.kind]) !== null && _kindParameters$story !== void 0 ? _kindParameters$story : {}, storyData.parameters)
20
+ };
21
+ });
22
+ };
@@ -1 +1 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env node