creevey 0.10.0-beta.5 → 0.10.0-beta.7

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 (85) hide show
  1. package/dist/client/web/CreeveyView/SideBar/SideBar.js +1 -0
  2. package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
  3. package/dist/client/web/assets/{index-DkmZfG9C.js → index-DB8lHlJw.js} +2 -2
  4. package/dist/client/web/index.html +1 -1
  5. package/dist/creevey.js +12 -5
  6. package/dist/creevey.js.map +1 -1
  7. package/dist/server/config.js +2 -1
  8. package/dist/server/config.js.map +1 -1
  9. package/dist/server/docker.js +2 -2
  10. package/dist/server/docker.js.map +1 -1
  11. package/dist/server/index.js +4 -4
  12. package/dist/server/index.js.map +1 -1
  13. package/dist/server/logger.d.ts +2 -1
  14. package/dist/server/logger.js +7 -3
  15. package/dist/server/logger.js.map +1 -1
  16. package/dist/server/master/api.js +1 -1
  17. package/dist/server/master/api.js.map +1 -1
  18. package/dist/server/master/pool.d.ts +3 -3
  19. package/dist/server/master/pool.js +10 -65
  20. package/dist/server/master/pool.js.map +1 -1
  21. package/dist/server/master/queue.d.ts +13 -0
  22. package/dist/server/master/queue.js +64 -0
  23. package/dist/server/master/queue.js.map +1 -0
  24. package/dist/server/master/runner.d.ts +1 -0
  25. package/dist/server/master/runner.js +4 -1
  26. package/dist/server/master/runner.js.map +1 -1
  27. package/dist/server/master/server.js +1 -1
  28. package/dist/server/master/server.js.map +1 -1
  29. package/dist/server/master/start.js +4 -4
  30. package/dist/server/master/start.js.map +1 -1
  31. package/dist/server/playwright/internal.js +21 -20
  32. package/dist/server/playwright/internal.js.map +1 -1
  33. package/dist/server/playwright/webdriver.js +1 -1
  34. package/dist/server/playwright/webdriver.js.map +1 -1
  35. package/dist/server/providers/browser.js +2 -1
  36. package/dist/server/providers/browser.js.map +1 -1
  37. package/dist/server/providers/hybrid.js +1 -1
  38. package/dist/server/providers/hybrid.js.map +1 -1
  39. package/dist/server/reporter.js +4 -4
  40. package/dist/server/reporter.js.map +1 -1
  41. package/dist/server/selenium/internal.d.ts +1 -2
  42. package/dist/server/selenium/internal.js +95 -75
  43. package/dist/server/selenium/internal.js.map +1 -1
  44. package/dist/server/selenium/webdriver.js +1 -1
  45. package/dist/server/selenium/webdriver.js.map +1 -1
  46. package/dist/server/utils.d.ts +2 -1
  47. package/dist/server/utils.js +11 -0
  48. package/dist/server/utils.js.map +1 -1
  49. package/dist/server/webdriver.d.ts +2 -3
  50. package/dist/server/webdriver.js +9 -9
  51. package/dist/server/webdriver.js.map +1 -1
  52. package/dist/server/worker/chai-image.d.ts +1 -2
  53. package/dist/server/worker/chai-image.js +4 -3
  54. package/dist/server/worker/chai-image.js.map +1 -1
  55. package/dist/server/worker/start.js +7 -10
  56. package/dist/server/worker/start.js.map +1 -1
  57. package/dist/types.d.ts +6 -2
  58. package/dist/types.js.map +1 -1
  59. package/package.json +30 -30
  60. package/src/client/web/CreeveyView/SideBar/SideBar.tsx +1 -0
  61. package/src/creevey.ts +12 -6
  62. package/src/server/config.ts +2 -1
  63. package/src/server/docker.ts +2 -2
  64. package/src/server/index.ts +4 -4
  65. package/src/server/logger.ts +6 -2
  66. package/src/server/master/api.ts +1 -1
  67. package/src/server/master/pool.ts +18 -58
  68. package/src/server/master/queue.ts +64 -0
  69. package/src/server/master/runner.ts +4 -1
  70. package/src/server/master/server.ts +1 -1
  71. package/src/server/master/start.ts +7 -4
  72. package/src/server/playwright/internal.ts +22 -20
  73. package/src/server/playwright/webdriver.ts +1 -1
  74. package/src/server/providers/browser.ts +2 -1
  75. package/src/server/providers/hybrid.ts +1 -1
  76. package/src/server/reporter.ts +4 -3
  77. package/src/server/selenium/internal.ts +98 -76
  78. package/src/server/selenium/webdriver.ts +1 -1
  79. package/src/server/utils.ts +12 -1
  80. package/src/server/webdriver.ts +9 -15
  81. package/src/server/worker/chai-image.ts +4 -4
  82. package/src/server/worker/start.ts +7 -11
  83. package/src/types.ts +6 -2
  84. package/.yarnrc.yml +0 -1
  85. package/chromatic.config.json +0 -5
@@ -1,18 +1,9 @@
1
- import cluster, { Worker as ClusterWorker } from 'cluster';
1
+ import { Worker as ClusterWorker } from 'cluster';
2
2
  import { EventEmitter } from 'events';
3
- import {
4
- Worker,
5
- Config,
6
- TestResult,
7
- BrowserConfigObject,
8
- WorkerMessage,
9
- TestStatus,
10
- isWorkerMessage,
11
- } from '../../types.js';
12
- import { sendTestMessage, sendShutdownMessage, subscribeOnWorker } from '../messages.js';
13
- import { isShuttingDown } from '../utils.js';
14
-
15
- const FORK_RETRIES = 5;
3
+ import { Worker, Config, TestResult, BrowserConfigObject, TestStatus } from '../../types.js';
4
+ import { sendTestMessage, subscribeOnWorker } from '../messages.js';
5
+ import { gracefullyKill, isShuttingDown } from '../utils.js';
6
+ import { WorkerQueue } from './queue.js';
16
7
 
17
8
  interface WorkerTest {
18
9
  id: string;
@@ -32,6 +23,7 @@ export default class Pool extends EventEmitter {
32
23
  return this.workers.length !== this.freeWorkers.length;
33
24
  }
34
25
  constructor(
26
+ public scheduler: WorkerQueue,
35
27
  config: Config,
36
28
  private browser: string,
37
29
  gridUrl?: string,
@@ -46,10 +38,11 @@ export default class Pool extends EventEmitter {
46
38
 
47
39
  async init(): Promise<void> {
48
40
  const poolSize = Math.max(1, this.config.limit ?? 1);
49
- // TODO Init queue for workers to smooth browser starting load
50
- this.workers = (await Promise.all(Array.from({ length: poolSize }).map(() => this.forkWorker()))).filter(
51
- (workerOrError): workerOrError is Worker => workerOrError instanceof ClusterWorker,
52
- );
41
+ this.workers = (
42
+ await Promise.all(
43
+ Array.from({ length: poolSize }).map(() => this.scheduler.forkWorker(this.browser, this.gridUrl)),
44
+ )
45
+ ).filter((workerOrError): workerOrError is Worker => workerOrError instanceof ClusterWorker);
53
46
  if (this.workers.length != poolSize)
54
47
  throw new Error(`Can't instantiate workers for ${this.browser} due many errors`);
55
48
  this.workers.forEach((worker) => {
@@ -66,7 +59,7 @@ export default class Pool extends EventEmitter {
66
59
  return true;
67
60
  }
68
61
 
69
- stop(): void {
62
+ stop() {
70
63
  if (!this.isRunning) {
71
64
  this.emit('stop');
72
65
  return;
@@ -76,7 +69,7 @@ export default class Pool extends EventEmitter {
76
69
  this.queue = [];
77
70
  }
78
71
 
79
- process(): void {
72
+ process() {
80
73
  const worker = this.getFreeWorker();
81
74
  const test = this.queue.at(0);
82
75
 
@@ -99,7 +92,9 @@ export default class Pool extends EventEmitter {
99
92
 
100
93
  sendTestMessage(worker, { type: 'start', payload: test });
101
94
 
102
- this.process();
95
+ setImmediate(() => {
96
+ this.process();
97
+ });
103
98
  }
104
99
 
105
100
  private sendStatus(message: { id: string; status: TestStatus; result?: TestResult }): void {
@@ -120,36 +115,12 @@ export default class Pool extends EventEmitter {
120
115
  return this.aliveWorkers.filter((worker) => !worker.isRunning);
121
116
  }
122
117
 
123
- private async forkWorker(retry = 0): Promise<Worker | { error: string }> {
124
- if (isShuttingDown.current) return { error: 'Master process is shutting down' };
125
-
126
- cluster.setupPrimary({
127
- args: ['--browser', this.browser, ...(this.gridUrl ? ['--gridUrl', this.gridUrl] : []), ...process.argv.slice(2)],
128
- });
129
- const worker = cluster.fork();
130
- const message = await new Promise((resolve: (value: WorkerMessage) => void) => {
131
- const readyHandler = (message: unknown): void => {
132
- if (!isWorkerMessage(message) || message.type == 'port') return;
133
- worker.off('message', readyHandler);
134
- resolve(message);
135
- };
136
- worker.on('message', readyHandler);
137
- });
138
-
139
- if (message.type != 'error') return worker;
140
-
141
- this.gracefullyKill(worker);
142
-
143
- if (retry == FORK_RETRIES) return message.payload;
144
- return this.forkWorker(retry + 1);
145
- }
146
-
147
118
  private exitHandler(worker: Worker): void {
148
119
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
149
120
  worker.once('exit', async () => {
150
121
  if (isShuttingDown.current) return;
151
122
 
152
- const workerOrError = await this.forkWorker();
123
+ const workerOrError = await this.scheduler.forkWorker(this.browser, this.gridUrl);
153
124
 
154
125
  if (!(workerOrError instanceof ClusterWorker))
155
126
  throw new Error(`Can't instantiate worker for ${this.browser} due many errors`);
@@ -160,17 +131,6 @@ export default class Pool extends EventEmitter {
160
131
  });
161
132
  }
162
133
 
163
- private gracefullyKill(worker: Worker): void {
164
- worker.isShuttingDown = true;
165
- const timeout = setTimeout(() => {
166
- worker.kill();
167
- }, 10000);
168
- worker.on('exit', () => {
169
- clearTimeout(timeout);
170
- });
171
- sendShutdownMessage(worker);
172
- }
173
-
174
134
  private shouldRetry(test: WorkerTest): boolean {
175
135
  return test.retries < this.maxRetries && !this.forcedStop;
176
136
  }
@@ -202,7 +162,7 @@ export default class Pool extends EventEmitter {
202
162
  });
203
163
 
204
164
  if (message.payload.subtype == 'unknown') {
205
- this.gracefullyKill(worker);
165
+ gracefullyKill(worker);
206
166
  }
207
167
 
208
168
  this.handleTestResult(worker, test, { status: 'failed', error: message.payload.error });
@@ -0,0 +1,64 @@
1
+ import cluster from 'cluster';
2
+ import { isWorkerMessage, Worker, WorkerMessage } from '../../types.js';
3
+ import { gracefullyKill, isShuttingDown } from '../utils.js';
4
+
5
+ const FORK_RETRIES = 5;
6
+
7
+ type MaybeWorker = Worker | { error: string };
8
+
9
+ export class WorkerQueue {
10
+ private isProcessing = false;
11
+ private queue: { browser: string; gridUrl?: string; retry: number; resolve: (mw: MaybeWorker) => void }[] = [];
12
+
13
+ // TODO Add concurrency
14
+ constructor(private useQueue: boolean) {}
15
+
16
+ async forkWorker(browser: string, gridUrl?: string, retry = 0): Promise<MaybeWorker> {
17
+ return new Promise<MaybeWorker>((resolve) => {
18
+ this.queue.push({ browser, gridUrl, retry, resolve });
19
+
20
+ void this.process();
21
+ });
22
+ }
23
+
24
+ private async process() {
25
+ if (this.useQueue && this.isProcessing) return;
26
+
27
+ const { browser, gridUrl, retry, resolve } = this.queue.pop() ?? {};
28
+
29
+ if (browser == undefined || retry == undefined || resolve == undefined) return;
30
+
31
+ if (isShuttingDown.current) {
32
+ resolve({ error: 'Master process is shutting down' });
33
+ return;
34
+ }
35
+
36
+ this.isProcessing = true;
37
+
38
+ cluster.setupPrimary({
39
+ args: ['--browser', browser, ...(gridUrl ? ['--gridUrl', gridUrl] : []), ...process.argv.slice(2)],
40
+ });
41
+ const worker = cluster.fork();
42
+ const message = await new Promise((resolve: (value: WorkerMessage) => void) => {
43
+ const readyHandler = (message: unknown): void => {
44
+ if (!isWorkerMessage(message) || message.type == 'port') return;
45
+ worker.off('message', readyHandler);
46
+ resolve(message);
47
+ };
48
+ worker.on('message', readyHandler);
49
+ });
50
+
51
+ if (message.type == 'error') {
52
+ gracefullyKill(worker);
53
+
54
+ if (retry == FORK_RETRIES) resolve(message.payload);
55
+ else this.queue.push({ browser, gridUrl, retry: retry + 1, resolve });
56
+ } else {
57
+ resolve(worker);
58
+ }
59
+
60
+ this.isProcessing = false;
61
+
62
+ setImmediate(() => void this.process());
63
+ }
64
+ }
@@ -13,12 +13,14 @@ import {
13
13
  TestMeta,
14
14
  } from '../../types.js';
15
15
  import Pool from './pool.js';
16
+ import { WorkerQueue } from './queue.js';
16
17
 
17
18
  export default class Runner extends EventEmitter {
18
19
  private failFast: boolean;
19
20
  private screenDir: string;
20
21
  private reportDir: string;
21
22
  private browsers: string[];
23
+ private scheduler: WorkerQueue;
22
24
  private pools: Record<string, Pool> = {};
23
25
  tests: Partial<Record<string, ServerTest>> = {};
24
26
  public get isRunning(): boolean {
@@ -30,9 +32,10 @@ export default class Runner extends EventEmitter {
30
32
  this.failFast = config.failFast;
31
33
  this.screenDir = config.screenDir;
32
34
  this.reportDir = config.reportDir;
35
+ this.scheduler = new WorkerQueue(config.useWorkerQueue);
33
36
  this.browsers = Object.keys(config.browsers);
34
37
  this.browsers
35
- .map((browser) => (this.pools[browser] = new Pool(config, browser, gridUrl)))
38
+ .map((browser) => (this.pools[browser] = new Pool(this.scheduler, config, browser, gridUrl)))
36
39
  .map((pool) => pool.on('test', this.handlePoolMessage));
37
40
  }
38
41
 
@@ -96,7 +96,7 @@ export function start(reportDir: string, port: number, ui: boolean): (api: Creev
96
96
  app.use(mount('/report', serve(reportDir)));
97
97
 
98
98
  wss.on('error', (error) => {
99
- logger.error(error);
99
+ logger().error(error);
100
100
  });
101
101
 
102
102
  server.listen(port);
@@ -42,7 +42,10 @@ function outputUnnecessaryImages(imagesDir: string, images: Set<string>): void {
42
42
  .map((imagePath) => path.posix.relative(imagesDir, imagePath))
43
43
  .filter((imagePath) => !images.has(imagePath));
44
44
  if (unnecessaryImages.length > 0) {
45
- logger.warn('We found unnecessary screenshot images, those can be safely removed:\n', unnecessaryImages.join('\n'));
45
+ logger().warn(
46
+ 'We found unnecessary screenshot images, those can be safely removed:\n',
47
+ unnecessaryImages.join('\n'),
48
+ );
46
49
  }
47
50
  }
48
51
 
@@ -81,10 +84,10 @@ export async function start(
81
84
 
82
85
  if (options.ui) {
83
86
  resolveApi(creeveyApi(runner));
84
- logger.info(`Started on http://localhost:${options.port}`);
87
+ logger().info(`Started on http://localhost:${options.port}`);
85
88
  } else {
86
89
  if (Object.values(runner.status.tests).filter((test) => test && !test.skip).length == 0) {
87
- logger.warn("Don't have any tests to run");
90
+ logger().warn("Don't have any tests to run");
88
91
 
89
92
  void shutdownWorkers().then(() => process.exit());
90
93
  return;
@@ -101,7 +104,7 @@ export async function start(
101
104
  void sendScreenshotsCount(config, options, runner.status)
102
105
  .catch((reason: unknown) => {
103
106
  const error = reason instanceof Error ? (reason.stack ?? reason.message) : (reason as string);
104
- logger.warn(`Can't send telemetry: ${error}`);
107
+ logger().warn(`Can't send telemetry: ${error}`);
105
108
  })
106
109
  .finally(() => {
107
110
  void shutdownWorkers().then(() => process.exit());
@@ -1,5 +1,4 @@
1
1
  import { Browser, BrowserType, Page, chromium, firefox, webkit } from 'playwright-core';
2
- import Logger from 'loglevel';
3
2
  import chalk from 'chalk';
4
3
  import { v4 } from 'uuid';
5
4
  import prefix from 'loglevel-plugin-prefix';
@@ -28,7 +27,7 @@ async function tryConnect(type: BrowserType, gridUrl: string): Promise<Browser |
28
27
  (resolve) =>
29
28
  (timeout = setTimeout(() => {
30
29
  isTimeout = true;
31
- logger.error(`Can't connect to ${type.name()} playwright browser`, error);
30
+ logger().error(`Can't connect to ${type.name()} playwright browser`, error);
32
31
  resolve(null);
33
32
  }, 10000)),
34
33
  ),
@@ -57,13 +56,11 @@ export class InternalBrowser {
57
56
  #sessionId: string = v4();
58
57
  #serverHost: string | null = null;
59
58
  #serverPort: number;
60
- #logger: Logger.Logger;
61
59
  #unsubscribe: () => void = noop;
62
60
  constructor(browser: Browser, page: Page, port: number) {
63
61
  this.#browser = browser;
64
62
  this.#page = page;
65
63
  this.#serverPort = port;
66
- this.#logger = Logger.getLogger(this.#sessionId);
67
64
  this.#unsubscribe = subscribeOn('shutdown', () => {
68
65
  void this.closeBrowser();
69
66
  });
@@ -99,7 +96,12 @@ export class InternalBrowser {
99
96
  if (captureElement) {
100
97
  const element = await this.#page.$(captureElement);
101
98
  if (!element) throw new Error(`Element with selector ${captureElement} not found`);
102
- return element.screenshot({ animations: 'disabled', mask });
99
+
100
+ return element.screenshot({
101
+ animations: 'disabled',
102
+ mask,
103
+ style: ':root { overflow: hidden !important; }',
104
+ });
103
105
  }
104
106
  return this.#page.screenshot({ animations: 'disabled', mask, fullPage: true });
105
107
  }
@@ -113,7 +115,7 @@ export class InternalBrowser {
113
115
  await this.updateBrowserGlobalVariables();
114
116
  await this.resetMousePosition();
115
117
 
116
- this.#logger.debug(`Triggering 'SetCurrentStory' event with storyId ${chalk.magenta(id)}`);
118
+ logger().debug(`Triggering 'SetCurrentStory' event with storyId ${chalk.magenta(id)}`);
117
119
 
118
120
  const result = await this.#page.evaluate<
119
121
  [error?: string | null, isCaptureCalled?: boolean] | null,
@@ -198,13 +200,13 @@ export class InternalBrowser {
198
200
  break;
199
201
 
200
202
  default:
201
- logger.error(
203
+ logger().error(
202
204
  `Unknown browser ${browserConfig.browserName}. Playwright supports browsers: chromium, firefox, webkit`,
203
205
  );
204
206
  }
205
207
  } else {
206
208
  if (browserConfig.browserName != 'chrome') {
207
- logger.error("Playwright's Selenium Grid feature supports only chrome browser");
209
+ logger().error("Playwright's Selenium Grid feature supports only chrome browser");
208
210
  return null;
209
211
  }
210
212
 
@@ -242,7 +244,7 @@ export class InternalBrowser {
242
244
  const error = new Error(`Can't load storybook root page: ${message}`);
243
245
  if (originalError instanceof Error) error.stack = originalError.stack;
244
246
 
245
- logger.error(error);
247
+ logger().error(error);
246
248
 
247
249
  return null;
248
250
  }
@@ -263,10 +265,10 @@ export class InternalBrowser {
263
265
  }) {
264
266
  const sessionId = this.#sessionId;
265
267
 
266
- prefix.apply(this.#logger, {
268
+ prefix.apply(logger(), {
267
269
  format(level) {
268
270
  const levelColor = colors[level.toUpperCase() as keyof typeof colors];
269
- return `[${browserName}:${chalk.gray(sessionId)}] ${levelColor(level)} =>`;
271
+ return `[${browserName}:${chalk.gray(process.pid)}] ${levelColor(level)} => ${chalk.gray(sessionId)}`;
270
272
  },
271
273
  });
272
274
 
@@ -293,30 +295,30 @@ export class InternalBrowser {
293
295
 
294
296
  try {
295
297
  if (resolver) {
296
- this.#logger.debug('Resolving storybook url with custom resolver');
298
+ logger().debug('Resolving storybook url with custom resolver');
297
299
 
298
300
  const resolvedUrl = await resolver();
299
301
 
300
- this.#logger.debug(`Resolver storybook url ${resolvedUrl}`);
302
+ logger().debug(`Resolver storybook url ${resolvedUrl}`);
301
303
 
302
304
  await this.#page.goto(appendIframePath(resolvedUrl));
303
305
  } else {
304
306
  // TODO this.#page.setDefaultNavigationTimeout(10000);
305
- await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url), this.#logger);
307
+ await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
306
308
  }
307
309
  } catch (error) {
308
- this.#logger.error('Failed to resolve storybook URL', error instanceof Error ? error.message : '');
310
+ logger().error('Failed to resolve storybook URL', error instanceof Error ? error.message : '');
309
311
  throw error;
310
312
  }
311
313
  }
312
314
 
313
315
  private async checkUrl(url: string): Promise<boolean> {
314
316
  try {
315
- this.#logger.debug(`Opening ${chalk.magenta(url)} and checking the page source`);
317
+ logger().debug(`Opening ${chalk.magenta(url)} and checking the page source`);
316
318
  const response = await this.#page.goto(url, { waitUntil: 'commit' });
317
319
  const source = await response?.text();
318
320
 
319
- this.#logger.debug(`Checking ${chalk.cyan(`#${storybookRootID}`)} existence on ${chalk.magenta(url)}`);
321
+ logger().debug(`Checking ${chalk.cyan(`#${storybookRootID}`)} existence on ${chalk.magenta(url)}`);
320
322
  return source?.includes(`id="${storybookRootID}"`) ?? false;
321
323
  } catch {
322
324
  return false;
@@ -325,7 +327,7 @@ export class InternalBrowser {
325
327
 
326
328
  private async waitForStorybook(): Promise<void> {
327
329
  // TODO Duplicated code with selenium
328
- this.#logger.debug('Waiting for `setStories` event to make sure that storybook is initiated');
330
+ logger().debug('Waiting for `setStories` event to make sure that storybook is initiated');
329
331
 
330
332
  const isTimeout = await Promise.race([
331
333
  new Promise<boolean>((resolve) => {
@@ -344,7 +346,7 @@ export class InternalBrowser {
344
346
  return false;
345
347
  }, StorybookEvents.SET_GLOBALS);
346
348
  } catch (e: unknown) {
347
- this.#logger.debug('An error has been caught during the script:', e);
349
+ logger().debug('An error has been caught during the script:', e);
348
350
  }
349
351
  } while (wait);
350
352
  return false;
@@ -358,7 +360,7 @@ export class InternalBrowser {
358
360
  private async updateStorybookGlobals(globals?: StorybookGlobals): Promise<void> {
359
361
  if (!globals) return;
360
362
 
361
- this.#logger.debug('Applying storybook globals');
363
+ logger().debug('Applying storybook globals');
362
364
  await this.#page.evaluate((globals: StorybookGlobals) => {
363
365
  window.__CREEVEY_UPDATE_GLOBALS__(globals);
364
366
  }, globals);
@@ -53,7 +53,7 @@ export class PlaywrightWebdriver extends CreeveyWebdriverBase {
53
53
  try {
54
54
  return await import('./internal.js');
55
55
  } catch (error) {
56
- logger.error(error);
56
+ logger().error(error);
57
57
  return null;
58
58
  }
59
59
  })();
@@ -5,6 +5,7 @@ import { isDefined } from '../../types.js';
5
5
  import { logger } from '../logger.js';
6
6
  import { deserializeRawStories } from '../../shared/index.js';
7
7
 
8
+ // TODO Don't have updates from stories
8
9
  export const loadStories: StoriesProvider = async (_config, storiesListener, webdriver) => {
9
10
  if (cluster.isPrimary) {
10
11
  return new Promise<StoriesRaw>((resolve) => {
@@ -17,7 +18,7 @@ export const loadStories: StoriesProvider = async (_config, storiesListener, web
17
18
  if (message.type == 'set') {
18
19
  const { stories, oldTests } = message.payload;
19
20
  if (oldTests.length > 0)
20
- logger.warn(
21
+ logger().warn(
21
22
  `If you use browser stories provider of CSFv3 Storybook feature\n` +
22
23
  `Creevey will not load tests defined in story parameters from following stories:\n` +
23
24
  oldTests.join('\n'),
@@ -54,7 +54,7 @@ async function parseParams(
54
54
 
55
55
  if (listener) {
56
56
  chokidar.watch(testFiles).on('change', (filePath) => {
57
- logger.debug(`changed: ${filePath}`);
57
+ logger().debug(`changed: ${filePath}`);
58
58
 
59
59
  // doesn't work, always returns {} due modules caching
60
60
  // see https://github.com/nodejs/modules/issues/307
@@ -22,16 +22,16 @@ export class CreeveyReporter {
22
22
  // TODO Output in better way, like vitest, maybe
23
23
  constructor(runner: EventEmitter, options: { reporterOptions: { creevey: ReporterOptions } }) {
24
24
  const { sessionId, browserName } = options.reporterOptions.creevey;
25
- const testLogger = Logger.getLogger(browserName);
25
+ const testLogger = Logger.getLogger(sessionId);
26
26
 
27
27
  prefix.apply(testLogger, {
28
28
  format(level) {
29
- return `${testLevels[level]} => (${browserName}:${chalk.gray(sessionId)})`;
29
+ return `[${browserName}:${chalk.gray(process.pid)}] ${testLevels[level]} => ${chalk.gray(sessionId)}`;
30
30
  },
31
31
  });
32
32
 
33
33
  runner.on(TEST_EVENTS.TEST_BEGIN, (test: FakeTest) => {
34
- testLogger.warn(chalk.cyan(test.titlePath().join('/')), chalk.gray(`(${test.duration} ms)`));
34
+ testLogger.warn(chalk.cyan(test.titlePath().join('/')));
35
35
  });
36
36
  runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
37
37
  testLogger.info(chalk.cyan(test.titlePath().join('/')), chalk.gray(`(${test.duration} ms)`));
@@ -39,6 +39,7 @@ export class CreeveyReporter {
39
39
  runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error) => {
40
40
  testLogger.error(
41
41
  chalk.cyan(test.titlePath().join('/')),
42
+ chalk.gray(`(${test.duration} ms)`),
42
43
  '\n ',
43
44
  this.getErrors(
44
45
  error,