creevey 0.10.0-beta.5 → 0.10.0-beta.6

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 (79) hide show
  1. package/dist/creevey.js +12 -5
  2. package/dist/creevey.js.map +1 -1
  3. package/dist/server/config.js +2 -1
  4. package/dist/server/config.js.map +1 -1
  5. package/dist/server/docker.js +2 -2
  6. package/dist/server/docker.js.map +1 -1
  7. package/dist/server/index.js +4 -4
  8. package/dist/server/index.js.map +1 -1
  9. package/dist/server/logger.d.ts +2 -1
  10. package/dist/server/logger.js +7 -3
  11. package/dist/server/logger.js.map +1 -1
  12. package/dist/server/master/api.js +1 -1
  13. package/dist/server/master/api.js.map +1 -1
  14. package/dist/server/master/pool.d.ts +3 -3
  15. package/dist/server/master/pool.js +10 -65
  16. package/dist/server/master/pool.js.map +1 -1
  17. package/dist/server/master/queue.d.ts +13 -0
  18. package/dist/server/master/queue.js +64 -0
  19. package/dist/server/master/queue.js.map +1 -0
  20. package/dist/server/master/runner.d.ts +1 -0
  21. package/dist/server/master/runner.js +4 -1
  22. package/dist/server/master/runner.js.map +1 -1
  23. package/dist/server/master/server.js +1 -1
  24. package/dist/server/master/server.js.map +1 -1
  25. package/dist/server/master/start.js +4 -4
  26. package/dist/server/master/start.js.map +1 -1
  27. package/dist/server/playwright/internal.js +16 -19
  28. package/dist/server/playwright/internal.js.map +1 -1
  29. package/dist/server/playwright/webdriver.js +1 -1
  30. package/dist/server/playwright/webdriver.js.map +1 -1
  31. package/dist/server/providers/browser.js +1 -1
  32. package/dist/server/providers/browser.js.map +1 -1
  33. package/dist/server/providers/hybrid.js +1 -1
  34. package/dist/server/providers/hybrid.js.map +1 -1
  35. package/dist/server/reporter.js +4 -4
  36. package/dist/server/reporter.js.map +1 -1
  37. package/dist/server/selenium/internal.d.ts +1 -2
  38. package/dist/server/selenium/internal.js +93 -74
  39. package/dist/server/selenium/internal.js.map +1 -1
  40. package/dist/server/selenium/webdriver.js +1 -1
  41. package/dist/server/selenium/webdriver.js.map +1 -1
  42. package/dist/server/utils.d.ts +2 -1
  43. package/dist/server/utils.js +11 -0
  44. package/dist/server/utils.js.map +1 -1
  45. package/dist/server/webdriver.d.ts +2 -3
  46. package/dist/server/webdriver.js +9 -9
  47. package/dist/server/webdriver.js.map +1 -1
  48. package/dist/server/worker/chai-image.d.ts +1 -2
  49. package/dist/server/worker/chai-image.js +4 -3
  50. package/dist/server/worker/chai-image.js.map +1 -1
  51. package/dist/server/worker/start.js +7 -10
  52. package/dist/server/worker/start.js.map +1 -1
  53. package/dist/types.d.ts +6 -2
  54. package/dist/types.js.map +1 -1
  55. package/package.json +1 -1
  56. package/src/creevey.ts +12 -6
  57. package/src/server/config.ts +2 -1
  58. package/src/server/docker.ts +2 -2
  59. package/src/server/index.ts +4 -4
  60. package/src/server/logger.ts +6 -2
  61. package/src/server/master/api.ts +1 -1
  62. package/src/server/master/pool.ts +18 -58
  63. package/src/server/master/queue.ts +64 -0
  64. package/src/server/master/runner.ts +4 -1
  65. package/src/server/master/server.ts +1 -1
  66. package/src/server/master/start.ts +7 -4
  67. package/src/server/playwright/internal.ts +16 -19
  68. package/src/server/playwright/webdriver.ts +1 -1
  69. package/src/server/providers/browser.ts +1 -1
  70. package/src/server/providers/hybrid.ts +1 -1
  71. package/src/server/reporter.ts +4 -3
  72. package/src/server/selenium/internal.ts +96 -75
  73. package/src/server/selenium/webdriver.ts +1 -1
  74. package/src/server/utils.ts +12 -1
  75. package/src/server/webdriver.ts +9 -15
  76. package/src/server/worker/chai-image.ts +4 -4
  77. package/src/server/worker/start.ts +7 -11
  78. package/src/types.ts +6 -2
  79. package/.yarnrc.yml +0 -1
@@ -6,7 +6,7 @@ import { fileURLToPath, pathToFileURL } from 'url';
6
6
  import { createRequire } from 'module';
7
7
  import { register as esmRegister } from 'tsx/esm/api';
8
8
  import { register as cjsRegister } from 'tsx/cjs/api';
9
- import { SkipOptions, SkipOption, isDefined, TestData, noop, ServerTest } from '../types.js';
9
+ import { SkipOptions, SkipOption, isDefined, TestData, noop, ServerTest, Worker } from '../types.js';
10
10
  import { emitShutdownMessage, sendShutdownMessage } from './messages.js';
11
11
 
12
12
  const importMetaUrl = pathToFileURL(__filename).href;
@@ -96,6 +96,17 @@ export async function shutdownWorkers(): Promise<void> {
96
96
  emitShutdownMessage();
97
97
  }
98
98
 
99
+ export function gracefullyKill(worker: Worker): void {
100
+ worker.isShuttingDown = true;
101
+ const timeout = setTimeout(() => {
102
+ worker.kill();
103
+ }, 10000);
104
+ worker.on('exit', () => {
105
+ clearTimeout(timeout);
106
+ });
107
+ sendShutdownMessage(worker);
108
+ }
109
+
99
110
  export async function getCreeveyCache(): Promise<string | undefined> {
100
111
  const { default: findCacheDir } = await import('find-cache-dir');
101
112
  return findCacheDir({ name: 'creevey', cwd: dirname(fileURLToPath(importMetaUrl)) });
@@ -1,7 +1,6 @@
1
- import Logger from 'loglevel';
2
1
  import chalk from 'chalk';
3
2
  import { networkInterfaces } from 'os';
4
- import { logger as defaultLogger } from './logger.js';
3
+ import { logger } from './logger.js';
5
4
  import { Args } from '@storybook/csf';
6
5
  import {
7
6
  isDefined,
@@ -22,16 +21,15 @@ const DOCKER_INTERNAL = 'host.docker.internal';
22
21
  export async function resolveStorybookUrl(
23
22
  storybookUrl: string,
24
23
  checkUrl: (url: string) => Promise<boolean>,
25
- logger: Logger.Logger = defaultLogger,
26
24
  ): Promise<string> {
27
- logger.debug('Resolving storybook url');
25
+ logger().debug('Resolving storybook url');
28
26
  const addresses = getAddresses();
29
27
  // TODO Use Promise.race?
30
28
  for (const ip of addresses) {
31
29
  const resolvedUrl = storybookUrl.replace(LOCALHOST_REGEXP, ip);
32
- logger.debug(`Checking storybook availability on ${chalk.magenta(resolvedUrl)}`);
30
+ logger().debug(`Checking storybook availability on ${chalk.magenta(resolvedUrl)}`);
33
31
  if (await checkUrl(resolvedUrl)) {
34
- logger.debug(`Resolved storybook url ${chalk.magenta(resolvedUrl)}`);
32
+ logger().debug(`Resolved storybook url ${chalk.magenta(resolvedUrl)}`);
35
33
  return resolvedUrl;
36
34
  }
37
35
  }
@@ -75,11 +73,7 @@ export abstract class CreeveyWebdriverBase implements CreeveyWebdriver {
75
73
 
76
74
  abstract afterTest(test: ServerTest): Promise<void>;
77
75
 
78
- async switchStory(
79
- story: StoryInput,
80
- context: BaseCreeveyTestContext,
81
- logger: Logger.Logger,
82
- ): Promise<CreeveyTestContext> {
76
+ async switchStory(story: StoryInput, context: BaseCreeveyTestContext): Promise<CreeveyTestContext> {
83
77
  const { id, title, name, parameters } = story;
84
78
  const {
85
79
  captureElement = `#${storybookRootID}`,
@@ -87,7 +81,7 @@ export abstract class CreeveyWebdriverBase implements CreeveyWebdriver {
87
81
  ignoreElements,
88
82
  } = (parameters.creevey ?? {}) as CreeveyStoryParams;
89
83
 
90
- logger.debug(`Switching to story ${chalk.cyan(title)}/${chalk.cyan(name)} by id ${chalk.magenta(id)}`);
84
+ logger().debug(`Switching to story ${chalk.cyan(title)}/${chalk.cyan(name)} by id ${chalk.magenta(id)}`);
91
85
 
92
86
  let storyPlayResolver: (isCompleted: boolean) => void;
93
87
  let waitForComplete = new Promise<boolean>((resolve) => (storyPlayResolver = resolve));
@@ -108,7 +102,7 @@ export abstract class CreeveyWebdriverBase implements CreeveyWebdriver {
108
102
  const isCaptureCalled = await this.selectStory(id, waitForReady);
109
103
 
110
104
  if (isCaptureCalled) {
111
- logger.debug(`Capturing screenshots from ${chalk.magenta(id)} story's \`play()\` function`);
105
+ logger().debug(`Capturing screenshots from ${chalk.magenta(id)} story's \`play()\` function`);
112
106
  while (!(await waitForComplete)) {
113
107
  waitForComplete = new Promise<boolean>((resolve) => (storyPlayResolver = resolve));
114
108
  }
@@ -116,8 +110,8 @@ export abstract class CreeveyWebdriverBase implements CreeveyWebdriver {
116
110
 
117
111
  unsubscribe();
118
112
 
119
- if (isCaptureCalled) logger.debug(`Story ${chalk.magenta(id)} completed capturing`);
120
- else logger.debug(`Story ${chalk.magenta(id)} ready for capturing`);
113
+ if (isCaptureCalled) logger().debug(`Story ${chalk.magenta(id)} completed capturing`);
114
+ else logger().debug(`Story ${chalk.magenta(id)} ready for capturing`);
121
115
 
122
116
  return Object.assign(
123
117
  {
@@ -1,8 +1,8 @@
1
- import Logger from 'loglevel';
1
+ import { logger } from '../logger';
2
+
2
3
  export default function (
3
4
  matchImage: (image: Buffer, imageName?: string) => Promise<void>,
4
5
  matchImages: (images: Record<string, Buffer>) => Promise<void>,
5
- logger: Logger.Logger,
6
6
  ) {
7
7
  let isWarningShown = false;
8
8
  return function chaiImage({ Assertion }: Chai.ChaiStatic, utils: Chai.ChaiUtils): void {
@@ -11,7 +11,7 @@ export default function (
11
11
  'matchImage',
12
12
  async function (this: Record<string, unknown>, imageName?: string) {
13
13
  if (!isWarningShown) {
14
- logger.warn(
14
+ logger().warn(
15
15
  '`expect(...).to.matchImage()` is deprecated and will be removed in the next major release. Please use `context.matchImage()` instead.',
16
16
  );
17
17
  isWarningShown = true;
@@ -23,7 +23,7 @@ export default function (
23
23
 
24
24
  utils.addMethod(Assertion.prototype, 'matchImages', async function (this: Record<string, unknown>) {
25
25
  if (!isWarningShown) {
26
- logger.warn(
26
+ logger().warn(
27
27
  '`expect(...).to.matchImages()` is deprecated and will be removed in the next major release. Please use `context.matchImages()` instead.',
28
28
  );
29
29
  isWarningShown = true;
@@ -1,6 +1,4 @@
1
1
  import chai from 'chai';
2
- import chalk from 'chalk';
3
- import Logger from 'loglevel';
4
2
  import EventEmitter from 'events';
5
3
  import {
6
4
  BaseCreeveyTestContext,
@@ -86,7 +84,7 @@ function runHandler(browserName: string, images: Partial<Record<string, Images>>
86
84
 
87
85
  async function setupWebdriver(webdriver: CreeveyWebdriver): Promise<[string, CreeveyWebdriver] | undefined> {
88
86
  if ((await webdriver.openBrowser(true)) == null) {
89
- logger.error('Failed to start browser');
87
+ logger().error('Failed to start browser');
90
88
  emitWorkerMessage({
91
89
  type: 'error',
92
90
  payload: { subtype: 'browser', error: 'Failed to start browser' },
@@ -125,8 +123,6 @@ export async function start(browser: string, gridUrl: string, config: Config, op
125
123
 
126
124
  if (!webdriver || !sessionId) return;
127
125
 
128
- const workerLogger = Logger.getLogger(`${browser}:${chalk.gray(sessionId)}`);
129
-
130
126
  const reporterOptions = {
131
127
  ...config.reporterOptions,
132
128
  creevey: {
@@ -150,13 +146,13 @@ export async function start(browser: string, gridUrl: string, config: Config, op
150
146
  const { matchImage, matchImages } = options.odiff
151
147
  ? getOdiffMatchers(imagesContext, config)
152
148
  : await getMatchers(imagesContext, config);
153
- chai.use(chaiImage(matchImage, matchImages, workerLogger));
149
+ chai.use(chaiImage(matchImage, matchImages));
154
150
 
155
151
  const tests = await (async () => {
156
152
  try {
157
153
  return await getTestsFromStories(config, browser, webdriver);
158
154
  } catch (error) {
159
- workerLogger.error('Failed to get tests from stories:', error);
155
+ logger().error('Failed to get tests from stories:', error);
160
156
  emitWorkerMessage({
161
157
  type: 'error',
162
158
  payload: { subtype: 'browser', error: serializeError(error) },
@@ -174,7 +170,7 @@ export async function start(browser: string, gridUrl: string, config: Config, op
174
170
 
175
171
  if (!test) {
176
172
  const error = `Test with id ${message.payload.id} not found`;
177
- workerLogger.error(error);
173
+ logger().error(error);
178
174
  emitWorkerMessage({
179
175
  type: 'error',
180
176
  payload: { subtype: 'test', error },
@@ -235,7 +231,7 @@ export async function start(browser: string, gridUrl: string, config: Config, op
235
231
  }, config.testTimeout),
236
232
  ),
237
233
  (async () => {
238
- const context = await webdriver.switchStory(test.story, baseContext, workerLogger);
234
+ const context = await webdriver.switchStory(test.story, baseContext);
239
235
  await test.fn(context);
240
236
  })(),
241
237
  ]);
@@ -261,7 +257,7 @@ export async function start(browser: string, gridUrl: string, config: Config, op
261
257
 
262
258
  runHandler(baseContext.browserName, imagesContext.images, error);
263
259
  })().catch((error: unknown) => {
264
- workerLogger.error('Unexpected error:', error);
260
+ logger().error('Unexpected error:', error);
265
261
  emitWorkerMessage({
266
262
  type: 'error',
267
263
  payload: { subtype: 'test', error: serializeError(error) },
@@ -269,7 +265,7 @@ export async function start(browser: string, gridUrl: string, config: Config, op
269
265
  });
270
266
  });
271
267
 
272
- workerLogger.info('Browser is ready');
268
+ logger().info('Browser is ready');
273
269
 
274
270
  emitWorkerMessage({ type: 'ready' });
275
271
  }
package/src/types.ts CHANGED
@@ -4,7 +4,6 @@ import type Pixelmatch from 'pixelmatch';
4
4
  import type { ODiffOptions } from 'odiff-bin';
5
5
  import type { expect } from 'chai';
6
6
  import type EventEmitter from 'events';
7
- import type Logger from 'loglevel';
8
7
  import { LaunchOptions } from 'playwright-core';
9
8
  // import type { Browser } from 'playwright-core';
10
9
 
@@ -164,7 +163,7 @@ export interface CreeveyWebdriver {
164
163
  openBrowser(fresh?: boolean): Promise<CreeveyWebdriver | null>;
165
164
  closeBrowser(): Promise<void>;
166
165
  loadStoriesFromBrowser(): Promise<StoriesRaw>;
167
- switchStory(story: StoryInput, context: BaseCreeveyTestContext, logger: Logger.Logger): Promise<CreeveyTestContext>;
166
+ switchStory(story: StoryInput, context: BaseCreeveyTestContext): Promise<CreeveyTestContext>;
168
167
  afterTest(test: ServerTest): Promise<void>;
169
168
  }
170
169
 
@@ -307,6 +306,11 @@ export interface Config {
307
306
  * The `--ui` CLI option ignores this option
308
307
  */
309
308
  failFast: boolean;
309
+ /**
310
+ * Start workers in sequential queue
311
+ * @default false
312
+ */
313
+ useWorkerQueue: boolean;
310
314
  /**
311
315
  * Specify platform for docker images
312
316
  */
package/.yarnrc.yml DELETED
@@ -1 +0,0 @@
1
- nodeLinker: node-modules