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.
- package/dist/client/web/CreeveyView/SideBar/SideBar.js +1 -0
- package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
- package/dist/client/web/assets/{index-DkmZfG9C.js → index-DB8lHlJw.js} +2 -2
- package/dist/client/web/index.html +1 -1
- package/dist/creevey.js +12 -5
- package/dist/creevey.js.map +1 -1
- package/dist/server/config.js +2 -1
- package/dist/server/config.js.map +1 -1
- package/dist/server/docker.js +2 -2
- package/dist/server/docker.js.map +1 -1
- package/dist/server/index.js +4 -4
- package/dist/server/index.js.map +1 -1
- package/dist/server/logger.d.ts +2 -1
- package/dist/server/logger.js +7 -3
- package/dist/server/logger.js.map +1 -1
- package/dist/server/master/api.js +1 -1
- package/dist/server/master/api.js.map +1 -1
- package/dist/server/master/pool.d.ts +3 -3
- package/dist/server/master/pool.js +10 -65
- package/dist/server/master/pool.js.map +1 -1
- package/dist/server/master/queue.d.ts +13 -0
- package/dist/server/master/queue.js +64 -0
- package/dist/server/master/queue.js.map +1 -0
- package/dist/server/master/runner.d.ts +1 -0
- package/dist/server/master/runner.js +4 -1
- package/dist/server/master/runner.js.map +1 -1
- package/dist/server/master/server.js +1 -1
- package/dist/server/master/server.js.map +1 -1
- package/dist/server/master/start.js +4 -4
- package/dist/server/master/start.js.map +1 -1
- package/dist/server/playwright/internal.js +21 -20
- package/dist/server/playwright/internal.js.map +1 -1
- package/dist/server/playwright/webdriver.js +1 -1
- package/dist/server/playwright/webdriver.js.map +1 -1
- package/dist/server/providers/browser.js +2 -1
- package/dist/server/providers/browser.js.map +1 -1
- package/dist/server/providers/hybrid.js +1 -1
- package/dist/server/providers/hybrid.js.map +1 -1
- package/dist/server/reporter.js +4 -4
- package/dist/server/reporter.js.map +1 -1
- package/dist/server/selenium/internal.d.ts +1 -2
- package/dist/server/selenium/internal.js +95 -75
- package/dist/server/selenium/internal.js.map +1 -1
- package/dist/server/selenium/webdriver.js +1 -1
- package/dist/server/selenium/webdriver.js.map +1 -1
- package/dist/server/utils.d.ts +2 -1
- package/dist/server/utils.js +11 -0
- package/dist/server/utils.js.map +1 -1
- package/dist/server/webdriver.d.ts +2 -3
- package/dist/server/webdriver.js +9 -9
- package/dist/server/webdriver.js.map +1 -1
- package/dist/server/worker/chai-image.d.ts +1 -2
- package/dist/server/worker/chai-image.js +4 -3
- package/dist/server/worker/chai-image.js.map +1 -1
- package/dist/server/worker/start.js +7 -10
- package/dist/server/worker/start.js.map +1 -1
- package/dist/types.d.ts +6 -2
- package/dist/types.js.map +1 -1
- package/package.json +30 -30
- package/src/client/web/CreeveyView/SideBar/SideBar.tsx +1 -0
- package/src/creevey.ts +12 -6
- package/src/server/config.ts +2 -1
- package/src/server/docker.ts +2 -2
- package/src/server/index.ts +4 -4
- package/src/server/logger.ts +6 -2
- package/src/server/master/api.ts +1 -1
- package/src/server/master/pool.ts +18 -58
- package/src/server/master/queue.ts +64 -0
- package/src/server/master/runner.ts +4 -1
- package/src/server/master/server.ts +1 -1
- package/src/server/master/start.ts +7 -4
- package/src/server/playwright/internal.ts +22 -20
- package/src/server/playwright/webdriver.ts +1 -1
- package/src/server/providers/browser.ts +2 -1
- package/src/server/providers/hybrid.ts +1 -1
- package/src/server/reporter.ts +4 -3
- package/src/server/selenium/internal.ts +98 -76
- package/src/server/selenium/webdriver.ts +1 -1
- package/src/server/utils.ts +12 -1
- package/src/server/webdriver.ts +9 -15
- package/src/server/worker/chai-image.ts +4 -4
- package/src/server/worker/start.ts +7 -11
- package/src/types.ts +6 -2
- package/.yarnrc.yml +0 -1
- package/chromatic.config.json +0 -5
@@ -1,18 +1,9 @@
|
|
1
|
-
import
|
1
|
+
import { Worker as ClusterWorker } from 'cluster';
|
2
2
|
import { EventEmitter } from 'events';
|
3
|
-
import {
|
4
|
-
|
5
|
-
|
6
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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()
|
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()
|
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
|
-
|
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
|
-
|
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
|
|
@@ -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(
|
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
|
-
|
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
|
-
|
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(
|
268
|
+
prefix.apply(logger(), {
|
267
269
|
format(level) {
|
268
270
|
const levelColor = colors[level.toUpperCase() as keyof typeof colors];
|
269
|
-
return `[${browserName}:${chalk.gray(
|
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
|
-
|
298
|
+
logger().debug('Resolving storybook url with custom resolver');
|
297
299
|
|
298
300
|
const resolvedUrl = await resolver();
|
299
301
|
|
300
|
-
|
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)
|
307
|
+
await resolveStorybookUrl(appendIframePath(storybookUrl), (url) => this.checkUrl(url));
|
306
308
|
}
|
307
309
|
} catch (error) {
|
308
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
363
|
+
logger().debug('Applying storybook globals');
|
362
364
|
await this.#page.evaluate((globals: StorybookGlobals) => {
|
363
365
|
window.__CREEVEY_UPDATE_GLOBALS__(globals);
|
364
366
|
}, globals);
|
@@ -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
|
package/src/server/reporter.ts
CHANGED
@@ -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(
|
25
|
+
const testLogger = Logger.getLogger(sessionId);
|
26
26
|
|
27
27
|
prefix.apply(testLogger, {
|
28
28
|
format(level) {
|
29
|
-
return
|
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.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,
|