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
@@ -5,7 +5,7 @@ import { addHook } from 'pirates';
5
5
  import { isDefined } from '../../../types';
6
6
  import { extensions } from '../../utils';
7
7
  import plugin from './creevey-plugin';
8
- import { hasDocsAddon, hasSvelteCSFAddon } from '../../storybook/helpers';
8
+ import { hasDocsAddon, hasSvelteCSFAddon, isStorybookVersionLessThan } from '../../storybook/helpers';
9
9
  let parents = null;
10
10
  let story = null; //@ts-expect-error private field doesn't have types
11
11
  // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-assignment
@@ -69,7 +69,8 @@ function getRequireContext(rootDir) {
69
69
  }
70
70
 
71
71
  export default async function register(config, debug = false) {
72
- const requireContext = getRequireContext(config.storybookDir);
72
+ const rootDir = isStorybookVersionLessThan(6, 4) ? config.storybookDir : process.cwd();
73
+ const requireContext = getRequireContext(rootDir);
73
74
  const preview = resolve(config.storybookDir, 'preview');
74
75
  if (hasDocsAddon()) await (await import('../hooks/mdx')).addMDXHook(() => story);
75
76
  if (hasSvelteCSFAddon()) await (await import('../hooks/svelte')).addSvelteHook(() => story); // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
@@ -1,10 +1,10 @@
1
1
  import path from 'path';
2
- import { writeFileSync, copyFile, readdir, mkdir, readdirSync, existsSync } from 'fs';
2
+ import { writeFileSync, copyFile, readdir, mkdir, existsSync } from 'fs';
3
3
  import { promisify } from 'util';
4
4
  import master from './master';
5
5
  import creeveyApi from './api';
6
6
  import { isDefined } from '../../types';
7
- import { shutdown, shutdownWorkers, testsToImages } from '../utils';
7
+ import { shutdown, shutdownWorkers, testsToImages, readDirRecursive } from '../utils';
8
8
  import { subscribeOn } from '../messages';
9
9
  import { logger } from '../logger';
10
10
  const copyFileAsync = promisify(copyFile);
@@ -37,12 +37,6 @@ function reportDataModule(data) {
37
37
  `;
38
38
  }
39
39
 
40
- function readDirRecursive(dirPath) {
41
- return [].concat(...readdirSync(dirPath, {
42
- withFileTypes: true
43
- }).map(dirent => dirent.isDirectory() ? readDirRecursive(`${dirPath}/${dirent.name}`) : [`${dirPath}/${dirent.name}`]));
44
- }
45
-
46
40
  function outputUnnecessaryImages(imagesDir, images) {
47
41
  if (!existsSync(imagesDir)) return;
48
42
  const unnecessaryImages = readDirRecursive(imagesDir).map(imagePath => path.posix.relative(imagesDir, imagePath)).filter(imagePath => !images.has(imagePath));
@@ -86,9 +80,9 @@ export default async function (config, options, resolveApi) {
86
80
  });
87
81
  runner = await master(config, {
88
82
  watch: options.ui,
89
- debug: options.debug
83
+ debug: options.debug,
84
+ port: options.port
90
85
  });
91
- await runner.init();
92
86
 
93
87
  if (options.saveReport) {
94
88
  await copyStatics(config.reportDir);
@@ -27,6 +27,7 @@ export default async function master(config, options) {
27
27
  } catch (error) {// Ignore error
28
28
  }
29
29
 
30
+ await runner.init();
30
31
  const tests = await loadTestsFromStories(Object.keys(config.browsers), listener => config.storiesProvider(config, options, listener), testsDiff => {
31
32
  runner.updateTests(testsDiff);
32
33
  saveTestsJson(runner.tests, config.reportDir);
@@ -2,8 +2,8 @@ function _defineProperty(obj, key, value) { if (key in obj) { Object.definePrope
2
2
 
3
3
  import cluster from 'cluster';
4
4
  import { EventEmitter } from 'events';
5
- import { isWorkerMessage, isTestMessage } from '../../types';
6
- import { sendTestMessage, sendShutdownMessage } from '../messages';
5
+ import { isWorkerMessage } from '../../types';
6
+ import { sendTestMessage, sendShutdownMessage, subscribeOnWorker } from '../messages';
7
7
  import { isShuttingDown } from '../utils';
8
8
  const FORK_RETRIES = 5;
9
9
  export default class Pool extends EventEmitter {
@@ -151,37 +151,37 @@ export default class Pool extends EventEmitter {
151
151
  return test.retries < this.maxRetries && !this.forcedStop;
152
152
  }
153
153
 
154
+ handleTestResult(worker, test, result) {
155
+ const shouldRetry = result.status == 'failed' && this.shouldRetry(test);
156
+
157
+ if (shouldRetry) {
158
+ test.retries += 1;
159
+ this.queue[this.failFast ? 'unshift' : 'push'](test);
160
+ }
161
+
162
+ this.sendStatus({
163
+ id: test.id,
164
+ status: shouldRetry ? 'retrying' : result.status,
165
+ result
166
+ });
167
+ worker.isRunning = false;
168
+ setImmediate(() => this.process());
169
+ }
170
+
154
171
  subscribe(worker, test) {
155
- worker.once('message', message => {
156
- if (!isWorkerMessage(message) && !isTestMessage(message)) return;
157
- if (message.type != 'end' && message.type != 'error') return;
158
- let result;
159
-
160
- if (message.type == 'error') {
161
- this.gracefullyKill(worker);
162
- result = {
163
- status: 'failed',
164
- ...message.payload
165
- };
166
- } else {
167
- result = message.payload;
168
- }
169
-
170
- const shouldRetry = result.status == 'failed' && this.shouldRetry(test);
171
-
172
- if (shouldRetry) {
173
- test.retries += 1;
174
- this.queue[this.failFast ? 'unshift' : 'push'](test);
175
- }
176
-
177
- this.sendStatus({
178
- id: test.id,
179
- status: shouldRetry ? 'retrying' : result.status,
180
- result
172
+ const subscriptions = [subscribeOnWorker(worker, 'worker', message => {
173
+ if (message.type != 'error') return;
174
+ subscriptions.forEach(unsubscribe => unsubscribe());
175
+ this.gracefullyKill(worker);
176
+ this.handleTestResult(worker, test, {
177
+ status: 'failed',
178
+ ...message.payload
181
179
  });
182
- worker.isRunning = false;
183
- this.process();
184
- });
180
+ }), subscribeOnWorker(worker, 'test', message => {
181
+ if (message.type != 'end') return;
182
+ subscriptions.forEach(unsubscribe => unsubscribe());
183
+ this.handleTestResult(worker, test, message.payload);
184
+ })];
185
185
  }
186
186
 
187
187
  }
@@ -1,22 +1,90 @@
1
1
  import path from 'path';
2
2
  import http from 'http';
3
+ import cluster from 'cluster';
3
4
  import Koa from 'koa';
5
+ import cors from '@koa/cors';
4
6
  import serve from 'koa-static';
5
7
  import mount from 'koa-mount';
8
+ import body from 'koa-bodyparser';
6
9
  import WebSocket from 'ws';
7
- import { subscribeOn } from '../messages';
8
- import { noop } from '../../types';
10
+ import { emitStoriesMessage, sendStoriesMessage, subscribeOn, subscribeOnWorker } from '../messages';
11
+ import { isDefined, noop } from '../../types';
9
12
  import { logger } from '../logger';
10
- export default function server(reportDir, port) {
13
+ import { deserializeStory } from '../../shared';
14
+ export default function server(reportDir, port, ui) {
11
15
  let resolveApi = noop;
16
+ let setStoriesCounter = 0;
12
17
  const creeveyApi = new Promise(resolve => resolveApi = resolve);
13
18
  const app = new Koa();
14
19
  const server = http.createServer(app.callback());
15
20
  const wss = new WebSocket.Server({
16
21
  server
17
22
  });
18
- app.use(async (_, next) => {
19
- await creeveyApi;
23
+ app.use(cors());
24
+ app.use(body());
25
+ app.use(async (ctx, next) => {
26
+ if (ctx.method == 'GET' && ctx.path == '/ping') {
27
+ ctx.body = 'pong';
28
+ return;
29
+ }
30
+
31
+ await next();
32
+ });
33
+
34
+ if (ui) {
35
+ app.use(async (_, next) => {
36
+ await creeveyApi;
37
+ await next();
38
+ });
39
+ }
40
+
41
+ app.use(async (ctx, next) => {
42
+ if (ctx.method == 'POST' && ctx.path == '/stories') {
43
+ const {
44
+ setStoriesCounter: counter,
45
+ stories
46
+ } = ctx.request.body;
47
+ if (setStoriesCounter >= counter) return;
48
+ const deserializedStories = stories.map(([file, stories]) => [file, stories.map(deserializeStory)]);
49
+ setStoriesCounter = counter;
50
+ emitStoriesMessage({
51
+ type: 'update',
52
+ payload: deserializedStories
53
+ });
54
+ Object.values(cluster.workers).filter(isDefined).filter(worker => worker.isConnected()).forEach(worker => sendStoriesMessage(worker, {
55
+ type: 'update',
56
+ payload: deserializedStories
57
+ }));
58
+ return;
59
+ }
60
+
61
+ await next();
62
+ });
63
+ app.use(async (ctx, next) => {
64
+ if (ctx.method == 'POST' && ctx.path == '/capture') {
65
+ const {
66
+ workerId,
67
+ options
68
+ } = ctx.request.body;
69
+ const worker = Object.values(cluster.workers).filter(isDefined).find(worker => worker.process.pid == workerId); // NOTE: Hypothetical case when someone send to us capture req and we don't have a worker with browser session for it
70
+
71
+ if (!worker) return;
72
+ await new Promise(resolve => {
73
+ const unsubscribe = subscribeOnWorker(worker, 'stories', message => {
74
+ if (message.type != 'capture') return;
75
+ unsubscribe();
76
+ resolve();
77
+ });
78
+ sendStoriesMessage(worker, {
79
+ type: 'capture',
80
+ payload: options
81
+ });
82
+ }); // TODO Pass screenshot result to show it in inspector
83
+
84
+ ctx.body = 'Ok';
85
+ return;
86
+ }
87
+
20
88
  await next();
21
89
  });
22
90
  app.use(serve(path.join(__dirname, '../../client/web')));
@@ -14,6 +14,12 @@ export function emitWorkerMessage(message) {
14
14
  ...message
15
15
  });
16
16
  }
17
+ export function emitStoriesMessage(message) {
18
+ return emitMessage({
19
+ scope: 'stories',
20
+ ...message
21
+ });
22
+ }
17
23
  export function emitTestMessage(message) {
18
24
  return emitMessage({
19
25
  scope: 'test',
@@ -37,19 +43,28 @@ export function emitShutdownMessage() {
37
43
  scope: 'shutdown'
38
44
  });
39
45
  }
40
- const handlers = Object.assign(Object.create(null), {
41
- worker: new Set(),
42
- test: new Set(),
43
- webpack: new Set(),
44
- docker: new Set(),
45
- shutdown: new Set()
46
- });
46
+
47
+ function createHandlers() {
48
+ return Object.assign(Object.create(null), {
49
+ worker: new Set(),
50
+ stories: new Set(),
51
+ test: new Set(),
52
+ webpack: new Set(),
53
+ docker: new Set(),
54
+ shutdown: new Set()
55
+ });
56
+ }
57
+
58
+ const handlers = createHandlers();
47
59
 
48
60
  const handler = message => {
49
61
  switch (message.scope) {
50
62
  case 'worker':
51
63
  return handlers.worker.forEach(h => h(message));
52
64
 
65
+ case 'stories':
66
+ return handlers.stories.forEach(h => h(message));
67
+
53
68
  case 'test':
54
69
  return handlers.test.forEach(h => h(message));
55
70
 
@@ -65,26 +80,34 @@ const handler = message => {
65
80
  };
66
81
 
67
82
  process.on('message', handler);
68
- export function sendTestMessage(target, message) {
83
+ export function sendStoriesMessage(target, message) {
69
84
  var _target$send;
70
85
 
71
86
  (_target$send = target.send) === null || _target$send === void 0 ? void 0 : _target$send.call(target, {
72
- scope: 'test',
87
+ scope: 'stories',
73
88
  ...message
74
89
  });
75
90
  }
76
- export function sendDockerMessage(target, message) {
91
+ export function sendTestMessage(target, message) {
77
92
  var _target$send2;
78
93
 
79
94
  (_target$send2 = target.send) === null || _target$send2 === void 0 ? void 0 : _target$send2.call(target, {
80
- scope: 'docker',
95
+ scope: 'test',
81
96
  ...message
82
97
  });
83
98
  }
84
- export function sendShutdownMessage(target) {
99
+ export function sendDockerMessage(target, message) {
85
100
  var _target$send3;
86
101
 
87
102
  (_target$send3 = target.send) === null || _target$send3 === void 0 ? void 0 : _target$send3.call(target, {
103
+ scope: 'docker',
104
+ ...message
105
+ });
106
+ }
107
+ export function sendShutdownMessage(target) {
108
+ var _target$send4;
109
+
110
+ (_target$send4 = target.send) === null || _target$send4 === void 0 ? void 0 : _target$send4.call(target, {
88
111
  scope: 'shutdown'
89
112
  });
90
113
  }
@@ -97,6 +120,13 @@ export function subscribeOn(scope, handler) {
97
120
  return () => handlers.worker.delete(workerHandler);
98
121
  }
99
122
 
123
+ case 'stories':
124
+ {
125
+ const storiesHandler = handler;
126
+ handlers.stories.add(storiesHandler);
127
+ return () => handlers.stories.delete(storiesHandler);
128
+ }
129
+
100
130
  case 'test':
101
131
  {
102
132
  const testHandler = handler;
@@ -125,4 +155,80 @@ export function subscribeOn(scope, handler) {
125
155
  return () => handlers.shutdown.delete(shutdownHandler);
126
156
  }
127
157
  }
158
+ }
159
+ const workers = new Map();
160
+ export function subscribeOnWorker(worker, scope, handler) {
161
+ var _workers$get;
162
+
163
+ const workerHandlers = (_workers$get = workers.get(worker)) !== null && _workers$get !== void 0 ? _workers$get : createHandlers();
164
+
165
+ if (!workers.has(worker)) {
166
+ workers.set(worker, workerHandlers);
167
+ worker.once('exit', () => workers.delete(worker));
168
+ worker.on('message', message => {
169
+ switch (message.scope) {
170
+ case 'worker':
171
+ return workerHandlers.worker.forEach(h => h(message));
172
+
173
+ case 'stories':
174
+ return workerHandlers.stories.forEach(h => h(message));
175
+
176
+ case 'test':
177
+ return workerHandlers.test.forEach(h => h(message));
178
+
179
+ case 'webpack':
180
+ return workerHandlers.webpack.forEach(h => h(message));
181
+
182
+ case 'docker':
183
+ return workerHandlers.docker.forEach(h => h(message));
184
+
185
+ case 'shutdown':
186
+ return workerHandlers.shutdown.forEach(h => h(message));
187
+ }
188
+ });
189
+ }
190
+
191
+ switch (scope) {
192
+ case 'worker':
193
+ {
194
+ const workerHandler = handler;
195
+ workerHandlers.worker.add(workerHandler);
196
+ return () => workerHandlers.worker.delete(workerHandler);
197
+ }
198
+
199
+ case 'stories':
200
+ {
201
+ const storiesHandler = handler;
202
+ workerHandlers.stories.add(storiesHandler);
203
+ return () => workerHandlers.stories.delete(storiesHandler);
204
+ }
205
+
206
+ case 'test':
207
+ {
208
+ const testHandler = handler;
209
+ workerHandlers.test.add(testHandler);
210
+ return () => workerHandlers.test.delete(testHandler);
211
+ }
212
+
213
+ case 'webpack':
214
+ {
215
+ const webpackHandler = handler;
216
+ workerHandlers.webpack.add(webpackHandler);
217
+ return () => workerHandlers.webpack.delete(webpackHandler);
218
+ }
219
+
220
+ case 'docker':
221
+ {
222
+ const dockerHandler = handler;
223
+ workerHandlers.docker.add(dockerHandler);
224
+ return () => workerHandlers.docker.delete(dockerHandler);
225
+ }
226
+
227
+ case 'shutdown':
228
+ {
229
+ const shutdownHandler = handler;
230
+ workerHandlers.shutdown.add(shutdownHandler);
231
+ return () => workerHandlers.shutdown.delete(shutdownHandler);
232
+ }
233
+ }
128
234
  }
@@ -0,0 +1,63 @@
1
+ import { toId, storyNameFromExport } from '@storybook/csf';
2
+ export default async function parse(files) {
3
+ result = {}; // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
4
+
5
+ (await import('@babel/register')).default({
6
+ babelrc: false,
7
+ rootMode: 'upward-optional',
8
+ ignore: [/node_modules/],
9
+ extensions: ['.js', '.jsx', '.ts', '.tsx'],
10
+ plugins: [['@babel/plugin-transform-runtime']],
11
+ presets: ['@babel/preset-typescript', ['@babel/preset-env', {
12
+ targets: {
13
+ node: '10'
14
+ }
15
+ }]]
16
+ });
17
+ await Promise.all(files.map(async file => import(file)));
18
+ return result;
19
+ }
20
+ let result = {};
21
+ let kindTitle = '';
22
+ let storyTitle = '';
23
+ let storyParams = null;
24
+
25
+ const setStoryParameters = params => {
26
+ storyParams = params;
27
+ };
28
+
29
+ const getStoryId = (kindTitle, storyTitle) => {
30
+ return toId(kindTitle, storyNameFromExport(storyTitle));
31
+ };
32
+
33
+ export const kind = (title, kindFn) => {
34
+ kindTitle = title;
35
+ kindFn();
36
+ kindTitle = '';
37
+ };
38
+ export const story = (title, storyFn) => {
39
+ var _result$storyId;
40
+
41
+ storyTitle = title;
42
+ storyParams = null;
43
+ storyFn({
44
+ setStoryParameters
45
+ });
46
+ const storyId = getStoryId(kindTitle, storyTitle);
47
+ result[storyId] = Object.assign({}, storyParams, {
48
+ tests: (_result$storyId = result[storyId]) === null || _result$storyId === void 0 ? void 0 : _result$storyId.tests
49
+ });
50
+ storyTitle = '';
51
+ storyParams = null;
52
+ };
53
+ export const test = (title, testFn) => {
54
+ const storyId = getStoryId(kindTitle, storyTitle);
55
+
56
+ if (!result[storyId]) {
57
+ result[storyId] = {};
58
+ }
59
+
60
+ result[storyId].tests = Object.assign({}, result[storyId].tests, {
61
+ [title]: testFn
62
+ });
63
+ };