creevey 0.10.0-beta.2 → 0.10.0-beta.21

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 (179) hide show
  1. package/dist/client/addon/components/Addon.js +17 -7
  2. package/dist/client/addon/components/Addon.js.map +1 -1
  3. package/dist/client/addon/components/Panel.js +2 -2
  4. package/dist/client/addon/components/Panel.js.map +1 -1
  5. package/dist/client/addon/components/Tools.js +17 -7
  6. package/dist/client/addon/components/Tools.js.map +1 -1
  7. package/dist/client/addon/controller.js +4 -5
  8. package/dist/client/addon/controller.js.map +1 -1
  9. package/dist/client/addon/withCreevey.d.ts +1 -0
  10. package/dist/client/addon/withCreevey.js +19 -34
  11. package/dist/client/addon/withCreevey.js.map +1 -1
  12. package/dist/client/shared/components/ImagesView/BlendView.js +17 -7
  13. package/dist/client/shared/components/ImagesView/BlendView.js.map +1 -1
  14. package/dist/client/shared/components/ImagesView/SideBySideView.js +17 -7
  15. package/dist/client/shared/components/ImagesView/SideBySideView.js.map +1 -1
  16. package/dist/client/shared/components/ImagesView/SlideView.js +17 -7
  17. package/dist/client/shared/components/ImagesView/SlideView.js.map +1 -1
  18. package/dist/client/shared/components/ImagesView/SwapView.js +29 -7
  19. package/dist/client/shared/components/ImagesView/SwapView.js.map +1 -1
  20. package/dist/client/shared/components/PageHeader/ImagePreview.js +1 -0
  21. package/dist/client/shared/components/PageHeader/ImagePreview.js.map +1 -1
  22. package/dist/client/shared/components/PageHeader/PageHeader.js +17 -7
  23. package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
  24. package/dist/client/shared/components/ResultsPage.js +40 -12
  25. package/dist/client/shared/components/ResultsPage.js.map +1 -1
  26. package/dist/client/shared/creeveyClientApi.js +8 -1
  27. package/dist/client/shared/creeveyClientApi.js.map +1 -1
  28. package/dist/client/shared/helpers.d.ts +0 -2
  29. package/dist/client/shared/helpers.js +0 -17
  30. package/dist/client/shared/helpers.js.map +1 -1
  31. package/dist/client/web/CreeveyApp.js +41 -14
  32. package/dist/client/web/CreeveyApp.js.map +1 -1
  33. package/dist/client/web/CreeveyContext.d.ts +5 -0
  34. package/dist/client/web/CreeveyContext.js +20 -7
  35. package/dist/client/web/CreeveyContext.js.map +1 -1
  36. package/dist/client/web/CreeveyLoader.js +2 -2
  37. package/dist/client/web/CreeveyLoader.js.map +1 -1
  38. package/dist/client/web/CreeveyView/SideBar/Search.js +19 -9
  39. package/dist/client/web/CreeveyView/SideBar/Search.js.map +1 -1
  40. package/dist/client/web/CreeveyView/SideBar/SideBar.js +18 -7
  41. package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
  42. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +60 -7
  43. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
  44. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +17 -7
  45. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
  46. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +18 -10
  47. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
  48. package/dist/client/web/CreeveyView/SideBar/TestLink.js +18 -10
  49. package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
  50. package/dist/client/web/KeyboardEventsContext.d.ts +1 -8
  51. package/dist/client/web/KeyboardEventsContext.js +79 -64
  52. package/dist/client/web/KeyboardEventsContext.js.map +1 -1
  53. package/dist/client/web/assets/{index-DkmZfG9C.js → index-iytWuaD6.js} +104 -104
  54. package/dist/client/web/index.html +1 -1
  55. package/dist/client/web/index.js +17 -7
  56. package/dist/client/web/index.js.map +1 -1
  57. package/dist/client/web/themes.d.ts +2 -0
  58. package/dist/client/web/themes.js +22 -0
  59. package/dist/client/web/themes.js.map +1 -0
  60. package/dist/creevey.js +13 -5
  61. package/dist/creevey.js.map +1 -1
  62. package/dist/index.d.ts +1 -0
  63. package/dist/server/config.js +5 -4
  64. package/dist/server/config.js.map +1 -1
  65. package/dist/server/docker.js +37 -20
  66. package/dist/server/docker.js.map +1 -1
  67. package/dist/server/index.js +36 -7
  68. package/dist/server/index.js.map +1 -1
  69. package/dist/server/logger.d.ts +2 -1
  70. package/dist/server/logger.js +7 -3
  71. package/dist/server/logger.js.map +1 -1
  72. package/dist/server/master/api.js +1 -1
  73. package/dist/server/master/api.js.map +1 -1
  74. package/dist/server/master/pool.d.ts +3 -3
  75. package/dist/server/master/pool.js +10 -63
  76. package/dist/server/master/pool.js.map +1 -1
  77. package/dist/server/master/queue.d.ts +13 -0
  78. package/dist/server/master/queue.js +64 -0
  79. package/dist/server/master/queue.js.map +1 -0
  80. package/dist/server/master/runner.d.ts +1 -0
  81. package/dist/server/master/runner.js +4 -1
  82. package/dist/server/master/runner.js.map +1 -1
  83. package/dist/server/master/server.js +1 -1
  84. package/dist/server/master/server.js.map +1 -1
  85. package/dist/server/master/start.js +10 -9
  86. package/dist/server/master/start.js.map +1 -1
  87. package/dist/server/playwright/docker-file.d.ts +2 -1
  88. package/dist/server/playwright/docker-file.js +6 -4
  89. package/dist/server/playwright/docker-file.js.map +1 -1
  90. package/dist/server/playwright/internal.d.ts +3 -3
  91. package/dist/server/playwright/internal.js +50 -44
  92. package/dist/server/playwright/internal.js.map +1 -1
  93. package/dist/server/playwright/webdriver.d.ts +1 -1
  94. package/dist/server/playwright/webdriver.js +1 -1
  95. package/dist/server/playwright/webdriver.js.map +1 -1
  96. package/dist/server/providers/browser.js +6 -4
  97. package/dist/server/providers/browser.js.map +1 -1
  98. package/dist/server/providers/hybrid.js +1 -1
  99. package/dist/server/providers/hybrid.js.map +1 -1
  100. package/dist/server/reporter.js +13 -9
  101. package/dist/server/reporter.js.map +1 -1
  102. package/dist/server/selenium/internal.d.ts +3 -4
  103. package/dist/server/selenium/internal.js +127 -91
  104. package/dist/server/selenium/internal.js.map +1 -1
  105. package/dist/server/selenium/selenoid.js +2 -2
  106. package/dist/server/selenium/selenoid.js.map +1 -1
  107. package/dist/server/selenium/webdriver.d.ts +1 -1
  108. package/dist/server/selenium/webdriver.js +1 -1
  109. package/dist/server/selenium/webdriver.js.map +1 -1
  110. package/dist/server/telemetry.js +7 -3
  111. package/dist/server/telemetry.js.map +1 -1
  112. package/dist/server/utils.d.ts +16 -1
  113. package/dist/server/utils.js +31 -3
  114. package/dist/server/utils.js.map +1 -1
  115. package/dist/server/webdriver.d.ts +3 -4
  116. package/dist/server/webdriver.js +10 -9
  117. package/dist/server/webdriver.js.map +1 -1
  118. package/dist/server/worker/chai-image.d.ts +1 -2
  119. package/dist/server/worker/chai-image.js +4 -3
  120. package/dist/server/worker/chai-image.js.map +1 -1
  121. package/dist/server/worker/match-image.d.ts +4 -4
  122. package/dist/server/worker/match-image.js +7 -4
  123. package/dist/server/worker/match-image.js.map +1 -1
  124. package/dist/server/worker/start.js +24 -14
  125. package/dist/server/worker/start.js.map +1 -1
  126. package/dist/shared/index.d.ts +1 -1
  127. package/dist/types.d.ts +32 -13
  128. package/dist/types.js +13 -1
  129. package/dist/types.js.map +1 -1
  130. package/package.json +55 -59
  131. package/src/client/addon/components/Panel.tsx +2 -2
  132. package/src/client/addon/controller.ts +13 -6
  133. package/src/client/addon/withCreevey.ts +27 -13
  134. package/src/client/shared/components/ImagesView/SwapView.tsx +18 -0
  135. package/src/client/shared/components/PageHeader/ImagePreview.tsx +1 -0
  136. package/src/client/shared/components/ResultsPage.tsx +28 -7
  137. package/src/client/shared/creeveyClientApi.ts +9 -1
  138. package/src/client/shared/helpers.ts +0 -22
  139. package/src/client/web/CreeveyApp.tsx +26 -8
  140. package/src/client/web/CreeveyContext.tsx +9 -0
  141. package/src/client/web/CreeveyLoader.tsx +1 -1
  142. package/src/client/web/CreeveyView/SideBar/Search.tsx +3 -3
  143. package/src/client/web/CreeveyView/SideBar/SideBar.tsx +1 -0
  144. package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +37 -6
  145. package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +3 -5
  146. package/src/client/web/CreeveyView/SideBar/TestLink.tsx +2 -4
  147. package/src/client/web/KeyboardEventsContext.tsx +61 -73
  148. package/src/client/web/themes.ts +24 -0
  149. package/src/creevey.ts +13 -6
  150. package/src/server/config.ts +5 -4
  151. package/src/server/docker.ts +41 -23
  152. package/src/server/index.ts +39 -9
  153. package/src/server/logger.ts +6 -2
  154. package/src/server/master/api.ts +1 -1
  155. package/src/server/master/pool.ts +18 -56
  156. package/src/server/master/queue.ts +64 -0
  157. package/src/server/master/runner.ts +4 -1
  158. package/src/server/master/server.ts +1 -1
  159. package/src/server/master/start.ts +13 -9
  160. package/src/server/playwright/docker-file.ts +7 -4
  161. package/src/server/playwright/internal.ts +70 -51
  162. package/src/server/playwright/webdriver.ts +2 -2
  163. package/src/server/providers/browser.ts +6 -4
  164. package/src/server/providers/hybrid.ts +1 -1
  165. package/src/server/reporter.ts +15 -9
  166. package/src/server/selenium/internal.ts +133 -96
  167. package/src/server/selenium/selenoid.ts +2 -2
  168. package/src/server/selenium/webdriver.ts +2 -2
  169. package/src/server/telemetry.ts +7 -3
  170. package/src/server/utils.ts +37 -4
  171. package/src/server/webdriver.ts +11 -16
  172. package/src/server/worker/chai-image.ts +4 -4
  173. package/src/server/worker/match-image.ts +12 -8
  174. package/src/server/worker/start.ts +25 -16
  175. package/src/shared/index.ts +1 -1
  176. package/src/types.ts +35 -15
  177. package/types/global.d.ts +1 -0
  178. package/.yarnrc.yml +0 -1
  179. package/chromatic.config.json +0 -5
@@ -1,15 +1,28 @@
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';
6
- import { SET_GLOBALS, STORY_RENDERED, UPDATE_STORY_ARGS } from '@storybook/core-events';
7
- import { BrowserConfigObject, Config, Options, StoriesRaw, StoryInput, StorybookGlobals, noop } from '../../types';
5
+ import {
6
+ BrowserConfigObject,
7
+ Config,
8
+ Options,
9
+ StoriesRaw,
10
+ StoryInput,
11
+ StorybookEvents,
12
+ StorybookGlobals,
13
+ noop,
14
+ } from '../../types';
8
15
  import { subscribeOn } from '../messages';
9
16
  import { appendIframePath, getAddresses, LOCALHOST_REGEXP, resolveStorybookUrl, storybookRootID } from '../webdriver';
10
- import { isShuttingDown, runSequence } from '../utils';
17
+ import { isShuttingDown, resolvePlaywrightBrowserType, runSequence } from '../utils';
11
18
  import { colors, logger } from '../logger';
12
- import { Args } from '@storybook/csf';
19
+ import type { Args } from '@storybook/csf';
20
+
21
+ const browsers = {
22
+ chromium,
23
+ firefox,
24
+ webkit,
25
+ };
13
26
 
14
27
  async function tryConnect(type: BrowserType, gridUrl: string): Promise<Browser | null> {
15
28
  let timeout: NodeJS.Timeout | null = null;
@@ -20,7 +33,7 @@ async function tryConnect(type: BrowserType, gridUrl: string): Promise<Browser |
20
33
  (resolve) =>
21
34
  (timeout = setTimeout(() => {
22
35
  isTimeout = true;
23
- logger.error(`Can't connect to ${type.name()} playwright browser`, error);
36
+ logger().error(`Can't connect to ${type.name()} playwright browser`, error);
24
37
  resolve(null);
25
38
  }, 10000)),
26
39
  ),
@@ -49,13 +62,13 @@ export class InternalBrowser {
49
62
  #sessionId: string = v4();
50
63
  #serverHost: string | null = null;
51
64
  #serverPort: number;
52
- #logger: Logger.Logger;
65
+ #storybookGlobals?: StorybookGlobals;
53
66
  #unsubscribe: () => void = noop;
54
- constructor(browser: Browser, page: Page, port: number) {
67
+ constructor(browser: Browser, page: Page, port: number, storybookGlobals?: StorybookGlobals) {
55
68
  this.#browser = browser;
56
69
  this.#page = page;
57
70
  this.#serverPort = port;
58
- this.#logger = Logger.getLogger(this.#sessionId);
71
+ this.#storybookGlobals = storybookGlobals;
59
72
  this.#unsubscribe = subscribeOn('shutdown', () => {
60
73
  void this.closeBrowser();
61
74
  });
@@ -91,7 +104,12 @@ export class InternalBrowser {
91
104
  if (captureElement) {
92
105
  const element = await this.#page.$(captureElement);
93
106
  if (!element) throw new Error(`Element with selector ${captureElement} not found`);
94
- return element.screenshot({ animations: 'disabled', mask });
107
+
108
+ return element.screenshot({
109
+ animations: 'disabled',
110
+ mask,
111
+ style: ':root { overflow: hidden !important; }',
112
+ });
95
113
  }
96
114
  return this.#page.screenshot({ animations: 'disabled', mask, fullPage: true });
97
115
  }
@@ -102,10 +120,11 @@ export class InternalBrowser {
102
120
 
103
121
  async selectStory(id: string, waitForReady = false): Promise<boolean> {
104
122
  // NOTE: Global variables might be reset after hot reload. I think it's workaround, maybe we need better solution
123
+ await this.updateStorybookGlobals();
105
124
  await this.updateBrowserGlobalVariables();
106
125
  await this.resetMousePosition();
107
126
 
108
- this.#logger.debug(`Triggering 'SetCurrentStory' event with storyId ${chalk.magenta(id)}`);
127
+ logger().debug(`Triggering 'SetCurrentStory' event with storyId ${chalk.magenta(id)}`);
109
128
 
110
129
  const result = await this.#page.evaluate<
111
130
  [error?: string | null, isCaptureCalled?: boolean] | null,
@@ -140,7 +159,7 @@ export class InternalBrowser {
140
159
  });
141
160
  });
142
161
  },
143
- [story.id, updatedArgs, UPDATE_STORY_ARGS, STORY_RENDERED] as const,
162
+ [story.id, updatedArgs, StorybookEvents.UPDATE_STORY_ARGS, StorybookEvents.STORY_RENDERED] as const,
144
163
  );
145
164
  }
146
165
 
@@ -167,26 +186,28 @@ export class InternalBrowser {
167
186
  options: Options,
168
187
  ): Promise<InternalBrowser | null> {
169
188
  const browserConfig = config.browsers[browserName] as BrowserConfigObject;
170
- const { storybookUrl: address = config.storybookUrl, viewport, _storybookGlobals } = browserConfig;
189
+ const {
190
+ storybookUrl: address = config.storybookUrl,
191
+ viewport,
192
+ _storybookGlobals,
193
+ seleniumCapabilities,
194
+ playwrightOptions,
195
+ } = browserConfig;
171
196
 
172
197
  let browser: Browser | null = null;
173
198
 
174
- // TODO Support Selenium Grid 4
175
- switch (browserConfig.browserName) {
176
- case 'chromium':
177
- browser = await tryConnect(chromium, gridUrl);
178
- break;
179
- case 'firefox':
180
- browser = await tryConnect(firefox, gridUrl);
181
- break;
182
- case 'webkit':
183
- browser = await tryConnect(webkit, gridUrl);
184
- break;
185
-
186
- default:
187
- throw new Error(
188
- `Unknown browser ${browserConfig.browserName}. Playwright supports browsers: chromium, firefox, webkit`,
189
- );
199
+ if (new URL(gridUrl).protocol === 'ws:') {
200
+ browser = await tryConnect(browsers[resolvePlaywrightBrowserType(browserConfig.browserName)], gridUrl);
201
+ } else {
202
+ if (browserConfig.browserName != 'chrome') {
203
+ logger().error("Playwright's Selenium Grid feature supports only chrome browser");
204
+ return null;
205
+ }
206
+
207
+ process.env.SELENIUM_REMOTE_URL = gridUrl;
208
+ process.env.SELENIUM_REMOTE_CAPABILITIES = JSON.stringify(seleniumCapabilities);
209
+
210
+ browser = await chromium.launch(playwrightOptions);
190
211
  }
191
212
 
192
213
  if (!browser) {
@@ -197,7 +218,7 @@ export class InternalBrowser {
197
218
 
198
219
  // TODO Add debug output
199
220
 
200
- const internalBrowser = new InternalBrowser(browser, page, options.port);
221
+ const internalBrowser = new InternalBrowser(browser, page, options.port, _storybookGlobals);
201
222
 
202
223
  try {
203
224
  if (isShuttingDown.current) return null;
@@ -205,7 +226,6 @@ export class InternalBrowser {
205
226
  browserName,
206
227
  viewport,
207
228
  storybookUrl: address,
208
- storybookGlobals: _storybookGlobals,
209
229
  resolveStorybookUrl: config.resolveStorybookUrl,
210
230
  });
211
231
 
@@ -217,7 +237,7 @@ export class InternalBrowser {
217
237
  const error = new Error(`Can't load storybook root page: ${message}`);
218
238
  if (originalError instanceof Error) error.stack = originalError.stack;
219
239
 
220
- logger.error(error);
240
+ logger().error(error);
221
241
 
222
242
  return null;
223
243
  }
@@ -227,32 +247,29 @@ export class InternalBrowser {
227
247
  browserName,
228
248
  viewport,
229
249
  storybookUrl,
230
- storybookGlobals,
231
250
  resolveStorybookUrl,
232
251
  }: {
233
252
  browserName: string;
234
253
  viewport?: { width: number; height: number };
235
254
  storybookUrl: string;
236
- storybookGlobals?: StorybookGlobals;
237
255
  resolveStorybookUrl?: () => Promise<string>;
238
256
  }) {
239
257
  const sessionId = this.#sessionId;
240
258
 
241
- prefix.apply(this.#logger, {
259
+ prefix.apply(logger(), {
242
260
  format(level) {
243
261
  const levelColor = colors[level.toUpperCase() as keyof typeof colors];
244
- return `[${browserName}:${chalk.gray(sessionId)}] ${levelColor(level)} =>`;
262
+ return `[${browserName}:${chalk.gray(process.pid)}] ${levelColor(level)} => ${chalk.gray(sessionId)}`;
245
263
  },
246
264
  });
247
265
 
248
- this.#page.setDefaultNavigationTimeout(10000);
249
266
  this.#page.setDefaultTimeout(60000);
250
267
 
251
268
  return await runSequence(
252
269
  [
253
270
  () => this.openStorybookPage(storybookUrl, resolveStorybookUrl),
254
271
  () => this.waitForStorybook(),
255
- () => this.updateStorybookGlobals(storybookGlobals),
272
+ () => this.updateStorybookGlobals(),
256
273
  () => this.resolveCreeveyHost(),
257
274
  () => this.updateBrowserGlobalVariables(),
258
275
  () => this.resizeViewport(viewport),
@@ -269,29 +286,30 @@ export class InternalBrowser {
269
286
 
270
287
  try {
271
288
  if (resolver) {
272
- this.#logger.debug('Resolving storybook url with custom resolver');
289
+ logger().debug('Resolving storybook url with custom resolver');
273
290
 
274
291
  const resolvedUrl = await resolver();
275
292
 
276
- this.#logger.debug(`Resolver storybook url ${resolvedUrl}`);
293
+ logger().debug(`Resolver storybook url ${resolvedUrl}`);
277
294
 
278
295
  await this.#page.goto(appendIframePath(resolvedUrl));
279
296
  } else {
280
- await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url), this.#logger);
297
+ // TODO this.#page.setDefaultNavigationTimeout(10000);
298
+ await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
281
299
  }
282
300
  } catch (error) {
283
- this.#logger.error('Failed to resolve storybook URL', error instanceof Error ? error.message : '');
301
+ logger().error('Failed to resolve storybook URL', error instanceof Error ? error.message : '');
284
302
  throw error;
285
303
  }
286
304
  }
287
305
 
288
306
  private async checkUrl(url: string): Promise<boolean> {
289
307
  try {
290
- this.#logger.debug(`Opening ${chalk.magenta(url)} and checking the page source`);
308
+ logger().debug(`Opening ${chalk.magenta(url)} and checking the page source`);
291
309
  const response = await this.#page.goto(url, { waitUntil: 'commit' });
292
310
  const source = await response?.text();
293
311
 
294
- this.#logger.debug(`Checking ${chalk.cyan(`#${storybookRootID}`)} existence on ${chalk.magenta(url)}`);
312
+ logger().debug(`Checking ${chalk.cyan(`#${storybookRootID}`)} existence on ${chalk.magenta(url)}`);
295
313
  return source?.includes(`id="${storybookRootID}"`) ?? false;
296
314
  } catch {
297
315
  return false;
@@ -300,7 +318,7 @@ export class InternalBrowser {
300
318
 
301
319
  private async waitForStorybook(): Promise<void> {
302
320
  // TODO Duplicated code with selenium
303
- this.#logger.debug('Waiting for `setStories` event to make sure that storybook is initiated');
321
+ logger().debug('Waiting for `setStories` event to make sure that storybook is initiated');
304
322
 
305
323
  const isTimeout = await Promise.race([
306
324
  new Promise<boolean>((resolve) => {
@@ -317,9 +335,9 @@ export class InternalBrowser {
317
335
  if (typeof window.__STORYBOOK_ADDONS_CHANNEL__ == 'undefined') return true;
318
336
  if (window.__STORYBOOK_ADDONS_CHANNEL__.last(SET_GLOBALS) == undefined) return true;
319
337
  return false;
320
- }, SET_GLOBALS);
338
+ }, StorybookEvents.SET_GLOBALS);
321
339
  } catch (e: unknown) {
322
- this.#logger.debug('An error has been caught during the script:', e);
340
+ logger().debug('An error has been caught during the script:', e);
323
341
  }
324
342
  } while (wait);
325
343
  return false;
@@ -330,13 +348,13 @@ export class InternalBrowser {
330
348
  if (isTimeout) throw new Error('Failed to wait `setStories` event');
331
349
  }
332
350
 
333
- private async updateStorybookGlobals(globals?: StorybookGlobals): Promise<void> {
334
- if (!globals) return;
351
+ private async updateStorybookGlobals(): Promise<void> {
352
+ if (!this.#storybookGlobals) return;
335
353
 
336
- this.#logger.debug('Applying storybook globals');
354
+ logger().debug('Applying storybook globals');
337
355
  await this.#page.evaluate((globals: StorybookGlobals) => {
338
356
  window.__CREEVEY_UPDATE_GLOBALS__(globals);
339
- }, globals);
357
+ }, this.#storybookGlobals);
340
358
  }
341
359
 
342
360
  private async resolveCreeveyHost(): Promise<void> {
@@ -367,6 +385,7 @@ export class InternalBrowser {
367
385
  private async updateBrowserGlobalVariables() {
368
386
  await this.#page.evaluate(
369
387
  ([workerId, creeveyHost, creeveyPort]) => {
388
+ window.__CREEVEY_ENV__ = true;
370
389
  window.__CREEVEY_WORKER_ID__ = workerId;
371
390
  window.__CREEVEY_SERVER_HOST__ = creeveyHost ?? 'localhost';
372
391
  window.__CREEVEY_SERVER_PORT__ = creeveyPort;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="../../../types/playwright-context" />
2
- import { Args } from '@storybook/csf';
2
+ import type { Args } from '@storybook/csf';
3
3
  import { Config, Options, ServerTest, StoriesRaw, StoryInput } from '../../types';
4
4
  import { logger } from '../logger';
5
5
  import { subscribeOn } from '../messages';
@@ -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,13 +18,13 @@ 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'),
24
25
  );
25
26
  unsubscribe();
26
- resolve(stories);
27
+ resolve(deserializeRawStories(stories));
27
28
  }
28
29
  });
29
30
  sendStoriesMessage(worker, { type: 'get' });
@@ -36,10 +37,11 @@ export const loadStories: StoriesProvider = async (_config, storiesListener, web
36
37
  } else {
37
38
  subscribeOn('stories', (message) => {
38
39
  if (message.type == 'get')
39
- emitStoriesMessage({ type: 'set', payload: { stories, oldTests: storiesWithOldTests } });
40
+ emitStoriesMessage({ type: 'set', payload: { stories: rawStories, oldTests: storiesWithOldTests } });
40
41
  if (message.type == 'update') storiesListener(new Map(message.payload));
41
42
  });
42
- const stories = deserializeRawStories((await webdriver?.loadStoriesFromBrowser()) ?? {});
43
+ const rawStories = (await webdriver?.loadStoriesFromBrowser()) ?? {};
44
+ const stories = deserializeRawStories(rawStories);
43
45
 
44
46
  const storiesWithOldTests: string[] = [];
45
47
 
@@ -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,23 +22,24 @@ 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('/')));
34
+ testLogger.warn(chalk.cyan(test.fullTitle()));
35
35
  });
36
36
  runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
37
- testLogger.info(chalk.cyan(test.titlePath().join('/')));
37
+ testLogger.info(chalk.cyan(test.fullTitle()), chalk.gray(`(${test.duration} ms)`));
38
38
  });
39
39
  runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error) => {
40
40
  testLogger.error(
41
- chalk.cyan(test.titlePath().join('/')),
41
+ chalk.cyan(test.fullTitle()),
42
+ chalk.gray(`(${test.duration} ms)`),
42
43
  '\n ',
43
44
  this.getErrors(
44
45
  error,
@@ -76,7 +77,11 @@ export class TeamcityReporter {
76
77
  const reporterOptions = options.reporterOptions.creevey;
77
78
 
78
79
  runner.on(TEST_EVENTS.TEST_BEGIN, (test: FakeTest) => {
79
- console.log(`##teamcity[testStarted name='${this.escape(test.title)}' flowId='${process.pid}']`);
80
+ console.log(`##teamcity[testStarted name='${this.escape(test.fullTitle())}' flowId='${process.pid}']`);
81
+ });
82
+
83
+ runner.on(TEST_EVENTS.TEST_PASS, (test: FakeTest) => {
84
+ console.log(`##teamcity[testFinished name='${this.escape(test.fullTitle())}' flowId='${process.pid}']`);
80
85
  });
81
86
 
82
87
  runner.on(TEST_EVENTS.TEST_FAIL, (test: FakeTest, error: Error) => {
@@ -84,6 +89,7 @@ export class TeamcityReporter {
84
89
  if (!image) return;
85
90
  const filePath = test
86
91
  .titlePath()
92
+ .slice(0, -1)
87
93
  .concat(name == browserName ? [] : [browserName])
88
94
  .map(this.escape)
89
95
  .join('/');
@@ -97,7 +103,7 @@ export class TeamcityReporter {
97
103
  );
98
104
  console.log(
99
105
  `##teamcity[testMetadata testName='${this.escape(
100
- test.title,
106
+ test.fullTitle(),
101
107
  )}' type='image' value='report/${filePath}/${fileName}' flowId='${process.pid}']`,
102
108
  );
103
109
  });
@@ -107,10 +113,10 @@ export class TeamcityReporter {
107
113
  // https://teamcity-support.jetbrains.com/hc/en-us/community/posts/207216829-Count-test-as-successful-if-at-least-one-try-is-successful?page=1#community_comment_207394125
108
114
 
109
115
  if (reporterOptions.willRetry)
110
- console.log(`##teamcity[testFinished name='${this.escape(test.title)}' flowId='${process.pid}']`);
116
+ console.log(`##teamcity[testFinished name='${this.escape(test.fullTitle())}' flowId='${process.pid}']`);
111
117
  else
112
118
  console.log(
113
- `##teamcity[testFailed name='${this.escape(test.title)}' message='${this.escape(
119
+ `##teamcity[testFailed name='${this.escape(test.fullTitle())}' message='${this.escape(
114
120
  error.message,
115
121
  )}' details='${this.escape(error.stack ?? '')}' flowId='${process.pid}']`,
116
122
  );