creevey 0.7.39 → 0.9.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 (102) hide show
  1. package/CHANGELOG.md +12 -2
  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 -2
  6. package/lib/cjs/client/addon/preset.js +1 -0
  7. package/lib/cjs/client/addon/readyForCapture.js +12 -0
  8. package/lib/cjs/client/addon/utils.js +1 -41
  9. package/lib/cjs/client/addon/withCreevey.js +313 -41
  10. package/lib/cjs/client/shared/components/ImagesView/BlendView.js +3 -3
  11. package/lib/cjs/client/shared/components/ImagesView/SideBySideView.js +3 -3
  12. package/lib/cjs/client/shared/components/ImagesView/SlideView.js +4 -3
  13. package/lib/cjs/client/shared/components/ImagesView/SwapView.js +3 -3
  14. package/lib/cjs/client/shared/helpers.js +1 -1
  15. package/lib/cjs/client/web/1.js +2 -2
  16. package/lib/cjs/client/web/2.js +1 -1
  17. package/lib/cjs/client/web/main.js +6 -6
  18. package/lib/cjs/index.js +27 -9
  19. package/lib/cjs/server/config.js +7 -3
  20. package/lib/cjs/server/extract.js +11 -4
  21. package/lib/cjs/server/index.js +2 -4
  22. package/lib/cjs/server/loaders/babel/register.js +2 -1
  23. package/lib/cjs/server/master/index.js +3 -9
  24. package/lib/cjs/server/master/master.js +1 -0
  25. package/lib/cjs/server/master/pool.js +29 -29
  26. package/lib/cjs/server/master/server.js +75 -3
  27. package/lib/cjs/server/messages.js +124 -12
  28. package/lib/cjs/server/parser.js +85 -0
  29. package/lib/cjs/server/selenium/browser.js +119 -21
  30. package/lib/cjs/server/selenium/selenoid.js +1 -1
  31. package/lib/cjs/server/stories.js +49 -58
  32. package/lib/cjs/server/storybook/entry.js +5 -4
  33. package/lib/cjs/server/storybook/helpers.js +11 -3
  34. package/lib/cjs/server/storybook/providers/browser.js +78 -0
  35. package/lib/cjs/server/storybook/providers/hybrid.js +79 -0
  36. package/lib/cjs/server/storybook/{nodejs-provider.js → providers/nodejs.js} +42 -18
  37. package/lib/cjs/server/utils.js +32 -2
  38. package/lib/cjs/server/worker/helpers.js +2 -6
  39. package/lib/cjs/server/worker/worker.js +15 -3
  40. package/lib/cjs/shared.js +107 -0
  41. package/lib/cjs/types.js +5 -0
  42. package/lib/esm/client/addon/Manager.js +3 -3
  43. package/lib/esm/client/addon/preset.js +1 -0
  44. package/lib/esm/client/addon/readyForCapture.js +5 -0
  45. package/lib/esm/client/addon/utils.js +1 -33
  46. package/lib/esm/client/addon/withCreevey.js +303 -41
  47. package/lib/esm/client/shared/components/ImagesView/BlendView.js +2 -3
  48. package/lib/esm/client/shared/components/ImagesView/SideBySideView.js +2 -3
  49. package/lib/esm/client/shared/components/ImagesView/SlideView.js +3 -3
  50. package/lib/esm/client/shared/components/ImagesView/SwapView.js +2 -3
  51. package/lib/esm/client/shared/helpers.js +1 -1
  52. package/lib/esm/index.js +6 -3
  53. package/lib/esm/server/config.js +7 -5
  54. package/lib/esm/server/extract.js +8 -4
  55. package/lib/esm/server/index.js +2 -3
  56. package/lib/esm/server/loaders/babel/register.js +3 -2
  57. package/lib/esm/server/master/index.js +4 -10
  58. package/lib/esm/server/master/master.js +1 -0
  59. package/lib/esm/server/master/pool.js +31 -31
  60. package/lib/esm/server/master/server.js +73 -5
  61. package/lib/esm/server/messages.js +118 -12
  62. package/lib/esm/server/parser.js +63 -0
  63. package/lib/esm/server/selenium/browser.js +116 -23
  64. package/lib/esm/server/selenium/selenoid.js +1 -1
  65. package/lib/esm/server/stories.js +51 -58
  66. package/lib/esm/server/storybook/entry.js +4 -4
  67. package/lib/esm/server/storybook/helpers.js +9 -3
  68. package/lib/esm/server/storybook/providers/browser.js +61 -0
  69. package/lib/esm/server/storybook/providers/hybrid.js +63 -0
  70. package/lib/esm/server/storybook/{nodejs-provider.js → providers/nodejs.js} +40 -18
  71. package/lib/esm/server/utils.js +29 -2
  72. package/lib/esm/server/worker/helpers.js +2 -6
  73. package/lib/esm/server/worker/worker.js +16 -4
  74. package/lib/esm/shared.js +76 -0
  75. package/lib/esm/types.js +3 -0
  76. package/lib/types/client/addon/preset.d.ts +2 -0
  77. package/lib/types/client/addon/readyForCapture.d.ts +6 -0
  78. package/lib/types/client/addon/utils.d.ts +1 -5
  79. package/lib/types/client/addon/withCreevey.d.ts +13 -2
  80. package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +2 -2
  81. package/lib/types/index.d.ts +2 -1
  82. package/lib/types/server/config.d.ts +1 -1
  83. package/lib/types/server/master/master.d.ts +1 -0
  84. package/lib/types/server/master/pool.d.ts +1 -0
  85. package/lib/types/server/master/server.d.ts +1 -1
  86. package/lib/types/server/messages.d.ts +12 -2
  87. package/lib/types/server/parser.d.ts +12 -0
  88. package/lib/types/server/selenium/browser.d.ts +5 -2
  89. package/lib/types/server/stories.d.ts +1 -2
  90. package/lib/types/server/storybook/entry.d.ts +13 -9
  91. package/lib/types/server/storybook/helpers.d.ts +1 -0
  92. package/lib/types/server/storybook/providers/browser.d.ts +4 -0
  93. package/lib/types/server/storybook/providers/hybrid.d.ts +4 -0
  94. package/lib/types/server/storybook/providers/nodejs.d.ts +9 -0
  95. package/lib/types/server/utils.d.ts +2 -0
  96. package/lib/types/server/worker/helpers.d.ts +2 -1
  97. package/lib/types/shared.d.ts +16 -0
  98. package/lib/types/types.d.ts +33 -4
  99. package/package.json +28 -18
  100. package/storybook-static/stories.json +4 -513
  101. package/types/mocha.d.ts +1 -0
  102. package/lib/types/server/storybook/nodejs-provider.d.ts +0 -5
@@ -2,15 +2,15 @@
2
2
  import path from 'path';
3
3
  import { isWorker, isMaster } from 'cluster';
4
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, isStorybookVersionLessThan } from './helpers';
9
- import { logger } from '../logger';
10
- import { flatStories } from '../stories';
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
11
 
12
12
  async function initStorybookEnvironment() {
13
- // @ts-ignore
13
+ // @ts-expect-error There is no @types/global-jsdom package
14
14
  (await import('global-jsdom')).default(undefined, {
15
15
  url: 'http://localhost'
16
16
  }); // NOTE Cutoff `jsdom` part from userAgent, because storybook check enviroment and create events channel if runs in browser
@@ -28,7 +28,7 @@ async function initStorybookEnvironment() {
28
28
  if (isWorker) logger.warn = noop; // NOTE: disable logger for 5.x storybook
29
29
 
30
30
  logger.debug = noop;
31
- return import('./entry');
31
+ return import('../entry');
32
32
  }
33
33
 
34
34
  function watchStories(channel, watcher, initialFiles) {
@@ -39,7 +39,7 @@ function watchStories(channel, watcher, initialFiles) {
39
39
  watcher.on('change', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
40
40
  watcher.on('unlink', filePath => storiesByFiles.set(path.isAbsolute(filePath) ? filePath : `./${filePath.replace(/\\/g, '/')}`, []));
41
41
  return data => {
42
- const stories = isStorybookVersionLessThan(6) ? data.stories : flatStories(data);
42
+ const stories = isStorybookVersionLessThan(6) || isStorybookVersionGreaterThan(6, 3) ? data.stories : denormalizeStoryParameters(data);
43
43
  const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
44
44
  const addedFiles = Array.from(files).filter(filePath => !watchingFiles.has(filePath));
45
45
  const removedFiles = Array.from(watchingFiles).filter(filePath => !files.has(filePath));
@@ -84,13 +84,14 @@ async function loadStoriesDirectly(config, {
84
84
  debug
85
85
  }) {
86
86
  const {
87
- toRequireContext
87
+ toRequireContext,
88
+ normalizeStoriesEntry
88
89
  } = await importStorybookCoreCommon();
89
90
  const {
90
91
  addParameters,
91
92
  configure
92
- } = await import('./entry');
93
- const requireContext = await (await import('../loaders/babel/register')).default(config, debug);
93
+ } = await import('../entry');
94
+ const requireContext = await (await import('../../loaders/babel/register')).default(config, debug);
94
95
 
95
96
  const preview = (() => {
96
97
  try {
@@ -103,12 +104,16 @@ async function loadStoriesDirectly(config, {
103
104
  const {
104
105
  stories
105
106
  } = await importStorybookConfig();
106
- const contexts = stories.map(input => {
107
+ const contexts = stories.map(entry => {
108
+ const normalizedEntry = isStorybookVersionLessThan(6, 4) ? entry : normalizeStoriesEntry(entry, {
109
+ configDir: config.storybookDir,
110
+ workingDir: process.cwd()
111
+ });
107
112
  const {
108
113
  path: storiesPath,
109
114
  recursive,
110
115
  match
111
- } = toRequireContext(input);
116
+ } = toRequireContext(normalizedEntry);
112
117
  watcher === null || watcher === void 0 ? void 0 : watcher.add(path.resolve(config.storybookDir, storiesPath));
113
118
  return () => requireContext(storiesPath, recursive, new RegExp(match));
114
119
  });
@@ -162,7 +167,8 @@ async function loadStoriesDirectly(config, {
162
167
  void startStorybook();
163
168
  });
164
169
  void startStorybook();
165
- }
170
+ } // TODO Do we need to support multiple storybooks here?
171
+
166
172
 
167
173
  export async function loadStories(config, {
168
174
  watch,
@@ -175,16 +181,16 @@ export async function loadStories(config, {
175
181
  } = storybookApi;
176
182
  channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
177
183
  channel.on('storiesUpdated', storiesListener);
178
- let watcher = null;
184
+ let watcher;
179
185
  if (watch) watcher = chokidar.watch([], {
180
186
  ignoreInitial: true
181
187
  });
182
188
  const loadPromise = new Promise(resolve => {
183
189
  channel.once(Events.SET_STORIES, data => {
184
- const stories = isStorybookVersionLessThan(6) ? data.stories : flatStories(data);
190
+ const stories = isStorybookVersionLessThan(6) || isStorybookVersionGreaterThan(6, 3) ? data.stories : denormalizeStoryParameters(data);
185
191
  const files = new Set(Object.values(stories).map(story => story.parameters.fileName));
186
192
  if (watcher) channel.on(Events.SET_STORIES, watchStories(channel, watcher, files));
187
- resolve(data);
193
+ resolve(stories);
188
194
  });
189
195
  });
190
196
  if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
@@ -192,4 +198,20 @@ export async function loadStories(config, {
192
198
  debug
193
199
  });
194
200
  return loadPromise;
201
+ }
202
+ export async function extractStoriesData(config, {
203
+ watch,
204
+ debug
205
+ }) {
206
+ const storybookApi = await initStorybookEnvironment();
207
+ const Events = await importStorybookCoreEvents();
208
+ const {
209
+ channel
210
+ } = storybookApi;
211
+ channel.removeAllListeners(Events.CURRENT_STORY_WAS_SET);
212
+ const loadPromise = new Promise(resolve => channel.once(Events.SET_STORIES, resolve));
213
+ if (config.useWebpackToExtractTests) loadStoriesFromBundle(watch);else void loadStoriesDirectly(config, {
214
+ debug
215
+ });
216
+ return loadPromise;
195
217
  }
@@ -1,4 +1,4 @@
1
- import { createWriteStream, existsSync, readFileSync, unlink } from 'fs';
1
+ import { createWriteStream, existsSync, readFileSync, readdirSync, unlink } from 'fs';
2
2
  import cluster from 'cluster';
3
3
  import { isDefined, noop, isFunction } from '../types';
4
4
  import { emitShutdownMessage, sendShutdownMessage } from './messages';
@@ -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,
@@ -116,4 +138,9 @@ export function removeProps(obj, propPath) {
116
138
  if (typeof prop == 'string') delete obj[prop];
117
139
  if (isFunction(prop)) Object.keys(obj).filter(prop).forEach(key => delete obj[key]);
118
140
  }
141
+ }
142
+ export function readDirRecursive(dirPath) {
143
+ return [].concat(...readdirSync(dirPath, {
144
+ withFileTypes: true
145
+ }).map(dirent => dirent.isDirectory() ? readDirRecursive(`${dirPath}/${dirent.name}`) : [`${dirPath}/${dirent.name}`]));
119
146
  }
@@ -47,14 +47,10 @@ function removeTestOrSuite(testOrSuite) {
47
47
 
48
48
  export async function addTestsFromStories(rootSuite, config, {
49
49
  browser,
50
- watch,
51
- debug
50
+ ...options
52
51
  }) {
53
52
  const mochaTestsById = new Map();
54
- const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, {
55
- watch,
56
- debug
57
- }, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
53
+ const tests = await loadTestsFromStories([browser], listener => config.storiesProvider(config, options, listener), testsDiff => Object.entries(testsDiff).forEach(([id, newTest]) => {
58
54
  const oldTest = mochaTestsById.get(id);
59
55
  mochaTestsById.delete(id);
60
56
  if (oldTest) removeTestOrSuite(oldTest);
@@ -8,7 +8,7 @@ import { Key, until } from 'selenium-webdriver';
8
8
  import { isImageError } from '../../types';
9
9
  import { subscribeOn, emitTestMessage, emitWorkerMessage } from '../messages';
10
10
  import chaiImage from './chai-image';
11
- import { getBrowser, switchStory } from '../selenium';
11
+ import { closeBrowser, getBrowser, switchStory } from '../selenium';
12
12
  import { CreeveyReporter, TeamcityReporter } from './reporter';
13
13
  import { addTestsFromStories } from './helpers';
14
14
  import { logger } from '../logger';
@@ -49,6 +49,7 @@ export default async function worker(config, options) {
49
49
  let retries = 0;
50
50
  let images = {};
51
51
  let error = undefined;
52
+ const screenshots = [];
52
53
  const testScope = [];
53
54
 
54
55
  function runHandler(failures) {
@@ -173,13 +174,23 @@ export default async function worker(config, options) {
173
174
 
174
175
  mocha.cleanReferencesAfterRun(false);
175
176
  chai.use(chaiImage(getExpected, config.diffOptions));
177
+ if ((await getBrowser(config, options.browser)) == null) return;
176
178
  await addTestsFromStories(mocha.suite, config, {
177
179
  browser: options.browser,
178
180
  watch: options.ui,
179
- debug: options.debug
181
+ debug: options.debug,
182
+ port: options.port
180
183
  });
181
- const browserConfig = config.browsers[options.browser];
182
- const browser = await getBrowser(config, browserConfig);
184
+
185
+ try {
186
+ var _await$getBrowser;
187
+
188
+ await ((_await$getBrowser = await getBrowser(config, options.browser)) === null || _await$getBrowser === void 0 ? void 0 : _await$getBrowser.getCurrentUrl());
189
+ } catch (_) {
190
+ await closeBrowser();
191
+ }
192
+
193
+ const browser = await getBrowser(config, options.browser);
183
194
  const sessionId = (_await$browser$getSes = await (browser === null || browser === void 0 ? void 0 : browser.getSession())) === null || _await$browser$getSes === void 0 ? void 0 : _await$browser$getSes.getId();
184
195
  if (browser == null) return;
185
196
  const interval = setInterval(() => void browser.getCurrentUrl().then(url => {
@@ -194,6 +205,7 @@ export default async function worker(config, options) {
194
205
  this.expect = chai.expect;
195
206
  this.browserName = options.browser;
196
207
  this.testScope = testScope;
208
+ this.screenshots = screenshots;
197
209
  });
198
210
  mocha.suite.beforeEach(switchStory);
199
211
  subscribeOn('test', message => {
@@ -0,0 +1,76 @@
1
+ import { mapValues, mergeWith, cloneDeepWith } 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 _globalParameters$cre, _kindParameters$story, _kindParameters$story2;
17
+
18
+ storyData.parameters.creevey = combineParameters((_globalParameters$cre = globalParameters.creevey) !== null && _globalParameters$cre !== void 0 ? _globalParameters$cre : {}, (_kindParameters$story = (_kindParameters$story2 = kindParameters[storyData.kind]) === null || _kindParameters$story2 === void 0 ? void 0 : _kindParameters$story2.creevey) !== null && _kindParameters$story !== void 0 ? _kindParameters$story : {}, storyData.parameters.creevey);
19
+ return storyData;
20
+ });
21
+ };
22
+ export const isSerializedRegExp = exp => {
23
+ return typeof exp === 'object' && exp !== null && Reflect.get(exp, '__regexp') === true;
24
+ };
25
+ export const serializeRegExp = exp => {
26
+ const {
27
+ source,
28
+ flags
29
+ } = exp;
30
+ return {
31
+ __regexp: true,
32
+ source,
33
+ flags
34
+ };
35
+ };
36
+ export const deserializeRegExp = ({
37
+ source,
38
+ flags
39
+ }) => {
40
+ return new RegExp(source, flags);
41
+ };
42
+ export const serializeRawStories = stories => {
43
+ return mapValues(stories, storyData => {
44
+ const creevey = storyData.parameters.creevey;
45
+
46
+ if ((creevey === null || creevey === void 0 ? void 0 : creevey.skip) !== undefined) {
47
+ creevey.skip = cloneDeepWith(creevey.skip, value => {
48
+ if (value instanceof RegExp) {
49
+ return serializeRegExp(value);
50
+ }
51
+
52
+ return undefined;
53
+ });
54
+ }
55
+
56
+ return storyData;
57
+ });
58
+ };
59
+ export const deserializeRawStories = stories => {
60
+ return mapValues(stories, deserializeStory);
61
+ };
62
+ export const deserializeStory = story => {
63
+ const creevey = story.parameters.creevey;
64
+
65
+ if ((creevey === null || creevey === void 0 ? void 0 : creevey.skip) !== undefined) {
66
+ creevey.skip = cloneDeepWith(creevey.skip, value => {
67
+ if (isSerializedRegExp(value)) {
68
+ return deserializeRegExp(value);
69
+ }
70
+
71
+ return undefined;
72
+ });
73
+ }
74
+
75
+ return story;
76
+ };
package/lib/esm/types.js CHANGED
@@ -29,6 +29,9 @@ export function isProcessMessage(message) {
29
29
  export function isWorkerMessage(message) {
30
30
  return isProcessMessage(message) && message.scope == 'worker';
31
31
  }
32
+ export function isStoriesMessage(message) {
33
+ return isProcessMessage(message) && message.scope == 'stories';
34
+ }
32
35
  export function isTestMessage(message) {
33
36
  return isProcessMessage(message) && message.scope == 'test';
34
37
  }
@@ -3,12 +3,14 @@ import { Configuration } from 'webpack';
3
3
  export declare function config(entry?: string[]): string[];
4
4
  export declare function managerEntries(entry?: string[]): string[];
5
5
  declare global {
6
+ const __CREEVEY_SERVER_HOST__: string;
6
7
  const __CREEVEY_SERVER_PORT__: number;
7
8
  const __CREEVEY_CLIENT_PORT__: number | null;
8
9
  }
9
10
  export interface CreeveyAddonOptions {
10
11
  creeveyConfigPath?: string;
11
12
  creeveyPreExtract?: string;
13
+ creeveyHost?: string;
12
14
  creeveyPort?: number;
13
15
  clientPort?: number;
14
16
  configType: string;
@@ -0,0 +1,6 @@
1
+ declare global {
2
+ interface Window {
3
+ __CREEVEY_SET_READY_FOR_CAPTURE__?: () => void;
4
+ }
5
+ }
6
+ export declare function readyForCapture(): void;
@@ -1,6 +1,2 @@
1
- import { Parameters } from '@storybook/api';
2
- import { SetStoriesPayload } from '@storybook/api/dist/ts3.9/lib/stories';
3
- import { StoriesRaw, TestStatus } from '../../types';
1
+ import { TestStatus } from '../../types';
4
2
  export declare function getEmojiByTestStatus(status: TestStatus | undefined, skip?: string | boolean): string;
5
- export declare const combineParameters: (...parameterSets: Parameters[]) => Parameters;
6
- export declare const denormalizeStoryParameters: ({ globalParameters, kindParameters, stories, }: SetStoriesPayload) => StoriesRaw;
@@ -1,13 +1,24 @@
1
+ import type { PreviewWeb } from '@storybook/preview-web';
2
+ import type { AnyFramework } from '@storybook/csf';
3
+ import type { StoryStore } from '@storybook/client-api';
1
4
  import { MakeDecoratorResult, Channel } from '@storybook/addons';
2
- import { StorybookGlobals } from '../../types';
5
+ import { CaptureOptions, StoriesRaw, StorybookGlobals } from '../../types';
3
6
  declare global {
4
7
  interface Window {
5
- __CREEVEY_SELECT_STORY__: (storyId: string, kind: string, name: string, shouldWaitForReady: boolean, callback: (error?: string) => void) => void;
8
+ __CREEVEY_SERVER_HOST__: string;
9
+ __CREEVEY_SERVER_PORT__: number;
10
+ __CREEVEY_WORKER_ID__: number;
11
+ __CREEVEY_GET_STORIES__: () => Promise<StoriesRaw | void>;
12
+ __CREEVEY_SELECT_STORY__: (storyId: string, kind: string, name: string, shouldWaitForReady: boolean, callback: (response: [error?: string | null, isCaptureCalled?: boolean]) => void) => void;
6
13
  __CREEVEY_UPDATE_GLOBALS__: (globals: StorybookGlobals) => void;
7
14
  __CREEVEY_INSERT_IGNORE_STYLES__: (ignoreElements: string[]) => HTMLStyleElement;
8
15
  __CREEVEY_REMOVE_IGNORE_STYLES__: (ignoreStyles: HTMLStyleElement) => void;
16
+ __CREEVEY_HAS_PLAY_COMPLETED_YET__: (callback: (isPlayCompleted: boolean) => void) => void;
9
17
  __CREEVEY_SET_READY_FOR_CAPTURE__?: () => void;
10
18
  __STORYBOOK_ADDONS_CHANNEL__: Channel;
19
+ __STORYBOOK_STORY_STORE__: StoryStore<AnyFramework>;
20
+ __STORYBOOK_PREVIEW__: PreviewWeb<AnyFramework>;
11
21
  }
12
22
  }
13
23
  export declare function withCreevey(): MakeDecoratorResult;
24
+ export declare function capture(options?: CaptureOptions): Promise<void>;
@@ -4,7 +4,7 @@ import { Theme } from '@storybook/theming';
4
4
  export interface SuiteLinkProps {
5
5
  title: string;
6
6
  suite: CreeveySuite;
7
- 'data-tid'?: string;
7
+ 'data-testid'?: string;
8
8
  }
9
9
  export declare const Container: React.SFC<import("emotion-theming/types/helper").AddOptionalTo<Pick<React.ClassAttributes<HTMLDivElement> & React.HTMLAttributes<HTMLDivElement> & Pick<{
10
10
  theme: Theme;
@@ -30,4 +30,4 @@ export declare const Button: React.SFC<import("emotion-theming/types/helper").Ad
30
30
  export declare const SuiteContainer: import("@emotion/styled-base").StyledComponent<React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement>, {
31
31
  padding: number;
32
32
  }, Theme>;
33
- export declare function SuiteLink({ title, suite, 'data-tid': dataTid }: SuiteLinkProps): JSX.Element;
33
+ export declare function SuiteLink({ title, suite, 'data-testid': dataTid }: SuiteLinkProps): JSX.Element;
@@ -1,3 +1,4 @@
1
1
  /// <reference types="../../types/chai" />
2
2
  export * from './types';
3
- export * from './client/addon/withCreevey';
3
+ // export * from './client/addon/withCreevey';
4
+ export * from './server/parser';
@@ -1,4 +1,4 @@
1
1
  import { Config, Options } from '../types';
2
2
  export declare const defaultBrowser = "chrome";
3
- export declare const defaultConfig: Omit<Config, 'gridUrl' | 'storiesProvider'>;
3
+ export declare const defaultConfig: Omit<Config, 'gridUrl' | 'storiesProvider' | 'testDir'>;
4
4
  export declare function readConfig(options: Options): Promise<Config>;
@@ -3,4 +3,5 @@ import Runner from './runner';
3
3
  export default function master(config: Config, options: {
4
4
  watch: boolean;
5
5
  debug: boolean;
6
+ port: number;
6
7
  }): Promise<Runner>;
@@ -26,5 +26,6 @@ export default class Pool extends EventEmitter {
26
26
  private exitHandler;
27
27
  private gracefullyKill;
28
28
  private shouldRetry;
29
+ private handleTestResult;
29
30
  private subscribe;
30
31
  }
@@ -1,2 +1,2 @@
1
1
  import { CreeveyApi } from './api';
2
- export default function server(reportDir: string, port: number): (api: CreeveyApi) => void;
2
+ export default function server(reportDir: string, port: number, ui: boolean): (api: CreeveyApi) => void;
@@ -1,18 +1,28 @@
1
1
  /// <reference types="webpack-env" />
2
2
  /// <reference types="node" />
3
3
  import cluster from 'cluster';
4
- import { WorkerMessage, TestMessage, WebpackMessage, DockerMessage, WorkerHandler, TestHandler, WebpackHandler, DockerHandler, ShutdownHandler } from '../types';
4
+ import { WorkerMessage, StoriesMessage, TestMessage, WebpackMessage, DockerMessage, WorkerHandler, StoriesHandler, TestHandler, WebpackHandler, DockerHandler, ShutdownHandler } from '../types';
5
5
  export declare function emitWorkerMessage(message: WorkerMessage): boolean;
6
+ export declare function emitStoriesMessage(message: StoriesMessage): boolean;
6
7
  export declare function emitTestMessage(message: TestMessage): boolean;
7
8
  export declare function emitWebpackMessage(message: WebpackMessage): boolean;
8
9
  export declare function emitDockerMessage(message: DockerMessage): boolean;
9
10
  export declare function emitShutdownMessage(): boolean;
11
+ export declare function sendStoriesMessage(target: NodeJS.Process | cluster.Worker, message: StoriesMessage): void;
10
12
  export declare function sendTestMessage(target: NodeJS.Process | cluster.Worker, message: TestMessage): void;
11
13
  export declare function sendDockerMessage(target: NodeJS.Process | cluster.Worker, message: DockerMessage): void;
12
14
  export declare function sendShutdownMessage(target: NodeJS.Process | cluster.Worker): void;
13
15
  export declare function subscribeOn(scope: 'worker', handler: WorkerHandler): () => void;
16
+ export declare function subscribeOn(scope: 'stories', handler: StoriesHandler): () => void;
14
17
  export declare function subscribeOn(scope: 'test', handler: TestHandler): () => void;
15
18
  export declare function subscribeOn(scope: 'webpack', handler: WebpackHandler): () => void;
16
19
  export declare function subscribeOn(scope: 'docker', handler: DockerHandler): () => void;
17
20
  export declare function subscribeOn(scope: 'shutdown', handler: ShutdownHandler): () => void;
18
- export declare function subscribeOn(scope: 'worker' | 'test' | 'webpack' | 'docker' | 'shutdown', handler: WorkerHandler | TestHandler | WebpackHandler | DockerHandler | ShutdownHandler): () => void;
21
+ export declare function subscribeOn(scope: 'worker' | 'stories' | 'test' | 'webpack' | 'docker' | 'shutdown', handler: WorkerHandler | StoriesHandler | TestHandler | WebpackHandler | DockerHandler | ShutdownHandler): () => void;
22
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'worker', handler: WorkerHandler): () => void;
23
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'stories', handler: StoriesHandler): () => void;
24
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'test', handler: TestHandler): () => void;
25
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'webpack', handler: WebpackHandler): () => void;
26
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'docker', handler: DockerHandler): () => void;
27
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'shutdown', handler: ShutdownHandler): () => void;
28
+ export declare function subscribeOnWorker(worker: cluster.Worker, scope: 'worker' | 'stories' | 'test' | 'webpack' | 'docker' | 'shutdown', handler: WorkerHandler | StoriesHandler | TestHandler | WebpackHandler | DockerHandler | ShutdownHandler): () => void;
@@ -0,0 +1,12 @@
1
+ import { CreeveyStoryParams, CreeveyTestFunction } from '../types';
2
+ export declare type CreeveyParamsByStoryId = {
3
+ [storyId: string]: CreeveyStoryParams;
4
+ };
5
+ export default function parse(files: string[]): Promise<CreeveyParamsByStoryId>;
6
+ declare const setStoryParameters: (params: CreeveyStoryParams) => void;
7
+ export declare const kind: (title: string, kindFn: () => void) => void;
8
+ export declare const story: (title: string, storyFn: (arg: {
9
+ setStoryParameters: (params: CreeveyStoryParams) => void;
10
+ }) => void) => void;
11
+ export declare const test: (title: string, testFn: CreeveyTestFunction) => void;
12
+ export {};
@@ -1,6 +1,6 @@
1
1
  import { Context } from 'mocha';
2
2
  import { WebDriver } from 'selenium-webdriver';
3
- import { BrowserConfig, Config, StorybookGlobals } from '../../types';
3
+ import { Config, StorybookGlobals, StoriesRaw } from '../../types';
4
4
  declare global {
5
5
  interface Window {
6
6
  __CREEVEY_RESTORE_SCROLL__?: () => void;
@@ -9,6 +9,9 @@ declare global {
9
9
  __CREEVEY_REMOVE_IGNORE_STYLES__: (ignoreStyles: HTMLStyleElement) => void;
10
10
  }
11
11
  }
12
+ export declare function takeScreenshot(browser: WebDriver, captureElement?: string | null, ignoreElements?: string | string[] | null): Promise<string>;
12
13
  export declare function updateStorybookGlobals(browser: WebDriver, globals: StorybookGlobals): Promise<void>;
13
- export declare function getBrowser(config: Config, browserConfig: BrowserConfig): Promise<WebDriver | null>;
14
+ export declare function loadStoriesFromBrowser(port: number): Promise<StoriesRaw>;
15
+ export declare function getBrowser(config: Config, name: string): Promise<WebDriver | null>;
16
+ export declare function closeBrowser(): Promise<void>;
14
17
  export declare function switchStory(this: Context): Promise<void>;
@@ -1,6 +1,5 @@
1
1
  import type { StoriesRaw, ServerTest, StoryInput, SetStoriesData } from '../types';
2
- export declare function flatStories({ globalParameters, kindParameters, stories }: SetStoriesData): StoriesRaw;
3
- export declare function loadTestsFromStories(browsers: string[], provider: (storiesListener: (stories: Map<string, StoryInput[]>) => void) => Promise<SetStoriesData>, update?: (testsDiff: Partial<{
2
+ export declare function loadTestsFromStories(browsers: string[], provider: (storiesListener: (stories: Map<string, StoryInput[]>) => void) => Promise<StoriesRaw>, update?: (testsDiff: Partial<{
4
3
  [id: string]: ServerTest;
5
4
  }>) => void): Promise<Partial<{
6
5
  [id: string]: ServerTest;
@@ -1,14 +1,18 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="webpack-env" />
3
3
  import type { StoryApi } from '@storybook/addons';
4
- export declare const channel: import("@storybook/channels").Channel;
5
- export declare const clientApi: import("@storybook/core").ClientApi;
6
- export declare const forceReRender: () => void;
4
+ import type { Channel } from '@storybook/channels';
5
+ declare const start: typeof import("@storybook/core").start;
6
+ export declare const channel: Channel;
7
+ declare type ClientApi = ReturnType<typeof start>['clientApi'];
8
+ export declare const clientApi: ClientApi;
9
+ export declare const forceReRender: (() => never) | (() => void);
7
10
  export declare const storiesOf: (kind: string, m: NodeModule) => StoryApi;
8
11
  export declare const configure: (...args: unknown[]) => unknown;
9
- export declare const addDecorator: (decorator: import("@storybook/addons").DecoratorFunction<unknown>) => void;
10
- export declare const addParameters: (parameters: import("@storybook/addons").Parameters) => void;
11
- export declare const clearDecorators: () => void;
12
- export declare const setAddon: (addon: any) => void;
13
- export declare const getStorybook: () => import("@storybook/client-api").GetStorybookKind[];
14
- export declare const raw: () => import("@storybook/client-api").PublishedStoreItem[];
12
+ export declare const addDecorator: ClientApi['addDecorator'];
13
+ export declare const addParameters: ClientApi['addParameters'];
14
+ export declare const clearDecorators: ClientApi['clearDecorators'];
15
+ export declare const setAddon: (() => never) | ((addon: any) => void);
16
+ export declare const getStorybook: ClientApi['getStorybook'];
17
+ export declare const raw: ClientApi['raw'];
18
+ export {};
@@ -14,6 +14,7 @@ export declare function hasDocsAddon(): boolean;
14
14
  export declare function hasSvelteCSFAddon(): boolean;
15
15
  export declare function getStorybookVersion(): string;
16
16
  export declare function isStorybookVersionLessThan(major: number, minor?: number): boolean;
17
+ export declare function isStorybookVersionGreaterThan(major: number, minor?: number): boolean;
17
18
  export declare function isStorybookVersion(major: number, minor?: number): boolean;
18
19
  export declare function getStorybookFramework(): string;
19
20
  export declare const storybookConfigRef: {
@@ -0,0 +1,4 @@
1
+ import type { Config, StoriesRaw, StoryInput } from '../../../types';
2
+ export declare function loadStories(_config: Config, { port }: {
3
+ port: number;
4
+ }, storiesListener: (stories: Map<string, StoryInput[]>) => void): Promise<StoriesRaw>;
@@ -0,0 +1,4 @@
1
+ import type { Config, StoriesRaw, StoryInput } from '../../../types';
2
+ export declare function loadStories(_config: Config, { port }: {
3
+ port: number;
4
+ }, storiesListener: (stories: Map<string, StoryInput[]>) => void): Promise<StoriesRaw>;
@@ -0,0 +1,9 @@
1
+ import type { StoryInput, SetStoriesData, Config, StoriesRaw } from '../../../types';
2
+ export declare function loadStories(config: Config, { watch, debug }: {
3
+ watch: boolean;
4
+ debug: boolean;
5
+ }, storiesListener: (stories: Map<string, StoryInput[]>) => void): Promise<StoriesRaw>;
6
+ export declare function extractStoriesData(config: Config, { watch, debug }: {
7
+ watch: boolean;
8
+ debug: boolean;
9
+ }): Promise<SetStoriesData>;
@@ -4,6 +4,7 @@ export declare const isShuttingDown: {
4
4
  };
5
5
  export declare const LOCALHOST_REGEXP: RegExp;
6
6
  export declare const extensions: string[];
7
+ export declare const skipOptionKeys: string[];
7
8
  export declare function shouldSkip(browser: string, meta: {
8
9
  kind: string;
9
10
  story: string;
@@ -16,3 +17,4 @@ export declare function testsToImages(tests: (TestData | undefined)[]): Set<stri
16
17
  export declare const isInsideDocker: boolean;
17
18
  export declare const downloadBinary: (downloadUrl: string, destination: string) => Promise<void>;
18
19
  export declare function removeProps(obj: Record<string, unknown>, propPath: (string | ((key: string) => boolean))[]): void;
20
+ export declare function readDirRecursive(dirPath: string): string[];
@@ -1,7 +1,8 @@
1
1
  import { Suite } from 'mocha';
2
2
  import { Config } from '../../types';
3
- export declare function addTestsFromStories(rootSuite: Suite, config: Config, { browser, watch, debug }: {
3
+ export declare function addTestsFromStories(rootSuite: Suite, config: Config, { browser, ...options }: {
4
4
  browser: string;
5
5
  watch: boolean;
6
6
  debug: boolean;
7
+ port: number;
7
8
  }): Promise<void>;
@@ -0,0 +1,16 @@
1
+ import { Parameters } from '@storybook/api';
2
+ import { SetStoriesData, StoriesRaw, StoryInput } from './types';
3
+ export declare const combineParameters: (...parameterSets: Parameters[]) => Parameters;
4
+ export declare const denormalizeStoryParameters: ({ globalParameters, kindParameters, stories, }: SetStoriesData) => StoriesRaw;
5
+ interface SerializedRegExp {
6
+ __regexp: true;
7
+ source: string;
8
+ flags: string;
9
+ }
10
+ export declare const isSerializedRegExp: (exp: unknown) => exp is SerializedRegExp;
11
+ export declare const serializeRegExp: (exp: RegExp) => SerializedRegExp;
12
+ export declare const deserializeRegExp: ({ source, flags }: SerializedRegExp) => RegExp;
13
+ export declare const serializeRawStories: (stories: StoriesRaw) => StoriesRaw;
14
+ export declare const deserializeRawStories: (stories: StoriesRaw) => StoriesRaw;
15
+ export declare const deserializeStory: (story: StoryInput) => StoryInput;
16
+ export {};