creevey 0.10.0-beta.4 → 0.10.0-beta.40

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 (211) hide show
  1. package/README.md +19 -41
  2. package/dist/client/addon/components/Addon.js +17 -7
  3. package/dist/client/addon/components/Addon.js.map +1 -1
  4. package/dist/client/addon/components/Panel.js +2 -2
  5. package/dist/client/addon/components/Panel.js.map +1 -1
  6. package/dist/client/addon/components/Tools.js +17 -7
  7. package/dist/client/addon/components/Tools.js.map +1 -1
  8. package/dist/client/addon/withCreevey.d.ts +2 -1
  9. package/dist/client/addon/withCreevey.js +11 -1
  10. package/dist/client/addon/withCreevey.js.map +1 -1
  11. package/dist/client/shared/components/ImagesView/BlendView.d.ts +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.d.ts +1 -1
  15. package/dist/client/shared/components/ImagesView/SideBySideView.js +17 -7
  16. package/dist/client/shared/components/ImagesView/SideBySideView.js.map +1 -1
  17. package/dist/client/shared/components/ImagesView/SlideView.d.ts +1 -1
  18. package/dist/client/shared/components/ImagesView/SlideView.js +17 -7
  19. package/dist/client/shared/components/ImagesView/SlideView.js.map +1 -1
  20. package/dist/client/shared/components/ImagesView/SwapView.d.ts +1 -1
  21. package/dist/client/shared/components/ImagesView/SwapView.js +29 -7
  22. package/dist/client/shared/components/ImagesView/SwapView.js.map +1 -1
  23. package/dist/client/shared/components/PageHeader/ImagePreview.d.ts +1 -1
  24. package/dist/client/shared/components/PageHeader/ImagePreview.js +1 -0
  25. package/dist/client/shared/components/PageHeader/ImagePreview.js.map +1 -1
  26. package/dist/client/shared/components/PageHeader/PageHeader.js +20 -8
  27. package/dist/client/shared/components/PageHeader/PageHeader.js.map +1 -1
  28. package/dist/client/shared/components/ResultsPage.d.ts +1 -1
  29. package/dist/client/shared/components/ResultsPage.js +43 -13
  30. package/dist/client/shared/components/ResultsPage.js.map +1 -1
  31. package/dist/client/shared/creeveyClientApi.js +8 -1
  32. package/dist/client/shared/creeveyClientApi.js.map +1 -1
  33. package/dist/client/shared/helpers.d.ts +1 -3
  34. package/dist/client/shared/helpers.js +4 -19
  35. package/dist/client/shared/helpers.js.map +1 -1
  36. package/dist/client/web/CreeveyApp.js +42 -14
  37. package/dist/client/web/CreeveyApp.js.map +1 -1
  38. package/dist/client/web/CreeveyContext.d.ts +5 -0
  39. package/dist/client/web/CreeveyContext.js +20 -7
  40. package/dist/client/web/CreeveyContext.js.map +1 -1
  41. package/dist/client/web/CreeveyLoader.js +2 -2
  42. package/dist/client/web/CreeveyLoader.js.map +1 -1
  43. package/dist/client/web/CreeveyView/SideBar/Search.js +19 -9
  44. package/dist/client/web/CreeveyView/SideBar/Search.js.map +1 -1
  45. package/dist/client/web/CreeveyView/SideBar/SideBar.js +18 -7
  46. package/dist/client/web/CreeveyView/SideBar/SideBar.js.map +1 -1
  47. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js +60 -7
  48. package/dist/client/web/CreeveyView/SideBar/SideBarFooter.js.map +1 -1
  49. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js +17 -7
  50. package/dist/client/web/CreeveyView/SideBar/SideBarHeader.js.map +1 -1
  51. package/dist/client/web/CreeveyView/SideBar/SuiteLink.d.ts +2 -2
  52. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js +18 -10
  53. package/dist/client/web/CreeveyView/SideBar/SuiteLink.js.map +1 -1
  54. package/dist/client/web/CreeveyView/SideBar/TestLink.js +18 -10
  55. package/dist/client/web/CreeveyView/SideBar/TestLink.js.map +1 -1
  56. package/dist/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +1 -1
  57. package/dist/client/web/CreeveyView/SideBar/TestsStatus.d.ts +1 -1
  58. package/dist/client/web/KeyboardEventsContext.d.ts +1 -8
  59. package/dist/client/web/KeyboardEventsContext.js +79 -64
  60. package/dist/client/web/KeyboardEventsContext.js.map +1 -1
  61. package/dist/client/web/assets/index-B0Xv0lOY.js +802 -0
  62. package/dist/client/web/index.html +1 -1
  63. package/dist/client/web/index.js +17 -7
  64. package/dist/client/web/index.js.map +1 -1
  65. package/dist/client/web/themes.d.ts +2 -0
  66. package/dist/client/web/themes.js +22 -0
  67. package/dist/client/web/themes.js.map +1 -0
  68. package/dist/creevey.js +16 -9
  69. package/dist/creevey.js.map +1 -1
  70. package/dist/index.d.ts +1 -0
  71. package/dist/server/config.d.ts +1 -1
  72. package/dist/server/config.js +27 -5
  73. package/dist/server/config.js.map +1 -1
  74. package/dist/server/connection.d.ts +3 -0
  75. package/dist/server/connection.js +28 -0
  76. package/dist/server/connection.js.map +1 -0
  77. package/dist/server/docker.d.ts +1 -1
  78. package/dist/server/docker.js +56 -32
  79. package/dist/server/docker.js.map +1 -1
  80. package/dist/server/index.js +64 -11
  81. package/dist/server/index.js.map +1 -1
  82. package/dist/server/logger.d.ts +2 -1
  83. package/dist/server/logger.js +7 -3
  84. package/dist/server/logger.js.map +1 -1
  85. package/dist/server/master/api.js +1 -1
  86. package/dist/server/master/api.js.map +1 -1
  87. package/dist/server/master/pool.d.ts +4 -3
  88. package/dist/server/master/pool.js +13 -66
  89. package/dist/server/master/pool.js.map +1 -1
  90. package/dist/server/master/queue.d.ts +13 -0
  91. package/dist/server/master/queue.js +71 -0
  92. package/dist/server/master/queue.js.map +1 -0
  93. package/dist/server/master/runner.d.ts +3 -0
  94. package/dist/server/master/runner.js +76 -10
  95. package/dist/server/master/runner.js.map +1 -1
  96. package/dist/server/master/server.js +1 -1
  97. package/dist/server/master/server.js.map +1 -1
  98. package/dist/server/master/start.js +13 -11
  99. package/dist/server/master/start.js.map +1 -1
  100. package/dist/server/playwright/docker-file.d.ts +1 -1
  101. package/dist/server/playwright/docker-file.js +15 -6
  102. package/dist/server/playwright/docker-file.js.map +1 -1
  103. package/dist/server/playwright/docker.d.ts +2 -1
  104. package/dist/server/playwright/docker.js +10 -2
  105. package/dist/server/playwright/docker.js.map +1 -1
  106. package/dist/server/playwright/index-source.mjs +16 -0
  107. package/dist/server/playwright/internal.d.ts +6 -6
  108. package/dist/server/playwright/internal.js +143 -91
  109. package/dist/server/playwright/internal.js.map +1 -1
  110. package/dist/server/playwright/webdriver.d.ts +1 -1
  111. package/dist/server/playwright/webdriver.js +5 -8
  112. package/dist/server/playwright/webdriver.js.map +1 -1
  113. package/dist/server/providers/browser.js +6 -4
  114. package/dist/server/providers/browser.js.map +1 -1
  115. package/dist/server/providers/hybrid.js +1 -1
  116. package/dist/server/providers/hybrid.js.map +1 -1
  117. package/dist/server/reporter.d.ts +4 -19
  118. package/dist/server/reporter.js +30 -21
  119. package/dist/server/reporter.js.map +1 -1
  120. package/dist/server/selenium/internal.d.ts +3 -4
  121. package/dist/server/selenium/internal.js +127 -108
  122. package/dist/server/selenium/internal.js.map +1 -1
  123. package/dist/server/selenium/selenoid.js +8 -6
  124. package/dist/server/selenium/selenoid.js.map +1 -1
  125. package/dist/server/selenium/webdriver.d.ts +1 -1
  126. package/dist/server/selenium/webdriver.js +5 -9
  127. package/dist/server/selenium/webdriver.js.map +1 -1
  128. package/dist/server/telemetry.js +2 -2
  129. package/dist/server/testsFiles/parser.js +45 -5
  130. package/dist/server/testsFiles/parser.js.map +1 -1
  131. package/dist/server/utils.d.ts +19 -1
  132. package/dist/server/utils.js +87 -8
  133. package/dist/server/utils.js.map +1 -1
  134. package/dist/server/webdriver.d.ts +5 -4
  135. package/dist/server/webdriver.js +23 -10
  136. package/dist/server/webdriver.js.map +1 -1
  137. package/dist/server/worker/chai-image.d.ts +1 -2
  138. package/dist/server/worker/chai-image.js +4 -3
  139. package/dist/server/worker/chai-image.js.map +1 -1
  140. package/dist/server/worker/context.d.ts +3 -0
  141. package/dist/server/worker/context.js +15 -0
  142. package/dist/server/worker/context.js.map +1 -0
  143. package/dist/server/worker/match-image.d.ts +4 -4
  144. package/dist/server/worker/match-image.js +7 -4
  145. package/dist/server/worker/match-image.js.map +1 -1
  146. package/dist/server/worker/start.js +45 -73
  147. package/dist/server/worker/start.js.map +1 -1
  148. package/dist/shared/index.d.ts +1 -1
  149. package/dist/types.d.ts +40 -8
  150. package/dist/types.js +2 -0
  151. package/dist/types.js.map +1 -1
  152. package/docs/cli.md +12 -0
  153. package/docs/config.md +179 -165
  154. package/docs/storybook.md +60 -0
  155. package/docs/tests.md +50 -45
  156. package/package.json +64 -63
  157. package/src/client/addon/components/Panel.tsx +2 -2
  158. package/src/client/addon/withCreevey.ts +10 -2
  159. package/src/client/shared/components/ImagesView/SwapView.tsx +18 -0
  160. package/src/client/shared/components/PageHeader/ImagePreview.tsx +1 -0
  161. package/src/client/shared/components/PageHeader/PageHeader.tsx +4 -2
  162. package/src/client/shared/components/ResultsPage.tsx +31 -8
  163. package/src/client/shared/creeveyClientApi.ts +9 -1
  164. package/src/client/shared/helpers.ts +4 -24
  165. package/src/client/web/CreeveyApp.tsx +27 -8
  166. package/src/client/web/CreeveyContext.tsx +9 -0
  167. package/src/client/web/CreeveyLoader.tsx +1 -1
  168. package/src/client/web/CreeveyView/SideBar/Search.tsx +3 -3
  169. package/src/client/web/CreeveyView/SideBar/SideBar.tsx +1 -0
  170. package/src/client/web/CreeveyView/SideBar/SideBarFooter.tsx +37 -6
  171. package/src/client/web/CreeveyView/SideBar/SuiteLink.tsx +3 -5
  172. package/src/client/web/CreeveyView/SideBar/TestLink.tsx +2 -4
  173. package/src/client/web/KeyboardEventsContext.tsx +61 -73
  174. package/src/client/web/themes.ts +24 -0
  175. package/src/creevey.ts +16 -10
  176. package/src/server/config.ts +28 -6
  177. package/src/server/connection.ts +26 -0
  178. package/src/server/docker.ts +63 -34
  179. package/src/server/index.ts +72 -14
  180. package/src/server/logger.ts +6 -2
  181. package/src/server/master/api.ts +1 -1
  182. package/src/server/master/pool.ts +23 -59
  183. package/src/server/master/queue.ts +77 -0
  184. package/src/server/master/runner.ts +94 -10
  185. package/src/server/master/server.ts +1 -1
  186. package/src/server/master/start.ts +16 -11
  187. package/src/server/playwright/docker-file.ts +18 -6
  188. package/src/server/playwright/docker.ts +16 -3
  189. package/src/server/playwright/index-source.mjs +16 -0
  190. package/src/server/playwright/internal.ts +182 -111
  191. package/src/server/playwright/webdriver.ts +6 -9
  192. package/src/server/providers/browser.ts +6 -4
  193. package/src/server/providers/hybrid.ts +1 -1
  194. package/src/server/reporter.ts +37 -34
  195. package/src/server/selenium/internal.ts +131 -116
  196. package/src/server/selenium/selenoid.ts +8 -6
  197. package/src/server/selenium/webdriver.ts +6 -10
  198. package/src/server/telemetry.ts +2 -2
  199. package/src/server/testsFiles/parser.ts +52 -4
  200. package/src/server/utils.ts +97 -9
  201. package/src/server/webdriver.ts +24 -16
  202. package/src/server/worker/chai-image.ts +4 -4
  203. package/src/server/worker/context.ts +14 -0
  204. package/src/server/worker/match-image.ts +12 -8
  205. package/src/server/worker/start.ts +49 -86
  206. package/src/shared/index.ts +1 -1
  207. package/src/types.ts +44 -8
  208. package/types/global.d.ts +1 -0
  209. package/.yarnrc.yml +0 -1
  210. package/chromatic.config.json +0 -5
  211. package/dist/client/web/assets/index-DkmZfG9C.js +0 -591
@@ -11,15 +11,34 @@ import {
11
11
  TestStatus,
12
12
  ServerTest,
13
13
  TestMeta,
14
+ TEST_EVENTS,
15
+ FakeSuite,
16
+ FakeTest,
14
17
  } from '../../types.js';
15
18
  import Pool from './pool.js';
19
+ import { WorkerQueue } from './queue.js';
20
+ import { getTestPath } from '../utils.js';
21
+
22
+ // NOTE: This is workaround to fix parallel tests running with mocha-junit-reporter
23
+ let isJUnit = false;
24
+
25
+ class FakeRunner extends EventEmitter {
26
+ public stats = {
27
+ duration: 0,
28
+ failures: 0,
29
+ pending: 0,
30
+ };
31
+ }
16
32
 
17
33
  export default class Runner extends EventEmitter {
18
34
  private failFast: boolean;
19
35
  private screenDir: string;
20
36
  private reportDir: string;
21
37
  private browsers: string[];
38
+ private scheduler: WorkerQueue;
22
39
  private pools: Record<string, Pool> = {};
40
+ private fakeRunner: FakeRunner;
41
+ private config: Config;
23
42
  tests: Partial<Record<string, ServerTest>> = {};
24
43
  public get isRunning(): boolean {
25
44
  return Object.values(this.pools).some((pool) => pool.isRunning);
@@ -27,12 +46,25 @@ export default class Runner extends EventEmitter {
27
46
  constructor(config: Config, gridUrl?: string) {
28
47
  super();
29
48
 
49
+ this.config = config;
30
50
  this.failFast = config.failFast;
31
51
  this.screenDir = config.screenDir;
32
52
  this.reportDir = config.reportDir;
53
+ this.scheduler = new WorkerQueue(config.useWorkerQueue);
33
54
  this.browsers = Object.keys(config.browsers);
55
+
56
+ const runner = new FakeRunner();
57
+ const Reporter = config.reporter;
58
+
59
+ if (Reporter.name == 'MochaJUnitReporter') {
60
+ isJUnit = true;
61
+ }
62
+
63
+ new Reporter(runner, { reporterOptions: config.reporterOptions });
64
+ this.fakeRunner = runner;
65
+
34
66
  this.browsers
35
- .map((browser) => (this.pools[browser] = new Pool(config, browser, gridUrl)))
67
+ .map((browser) => (this.pools[browser] = new Pool(this.scheduler, config, browser, gridUrl)))
36
68
  .map((pool) => pool.on('test', this.handlePoolMessage));
37
69
  }
38
70
 
@@ -42,22 +74,76 @@ export default class Runner extends EventEmitter {
42
74
 
43
75
  if (!test) return;
44
76
  const { browser, testName, storyPath, storyId } = test;
77
+
78
+ const fakeSuite: FakeSuite = {
79
+ title: test.storyPath.slice(0, -1).join('/'),
80
+ fullTitle: () => fakeSuite.title,
81
+ titlePath: () => [fakeSuite.title],
82
+ tests: [],
83
+ };
84
+
85
+ const fakeTest: FakeTest = {
86
+ parent: fakeSuite,
87
+ title: [test.story.name, testName, browser].filter(isDefined).join('/'),
88
+ fullTitle: () => getTestPath(test).join('/'),
89
+ titlePath: () => getTestPath(test),
90
+ currentRetry: () => result?.retries,
91
+ retires: () => this.config.maxRetries,
92
+ slow: () => 1000,
93
+ creevey: {
94
+ reportDir: this.reportDir,
95
+ sessionId: result?.sessionId ?? id,
96
+ browserName: browser,
97
+ willRetry: (result?.retries ?? 0) < this.config.maxRetries,
98
+ images: result?.images ?? {},
99
+ },
100
+ };
101
+
102
+ fakeSuite.tests.push(fakeTest);
103
+
45
104
  // TODO Handle 'retrying' status
46
105
  test.status = status == 'retrying' ? 'failed' : status;
47
106
  if (!result) {
48
107
  // NOTE: Running status
108
+ this.fakeRunner.emit(TEST_EVENTS.TEST_BEGIN, fakeTest);
49
109
  this.sendUpdate({ tests: { [id]: { id, browser, testName, storyPath, status: test.status, storyId } } });
50
110
  return;
51
111
  }
52
- if (!test.results) {
53
- test.results = [];
54
- }
112
+ test.results ??= [];
55
113
  test.results.push(result);
56
114
 
57
115
  if (status == 'failed') {
58
116
  test.approved = null;
59
117
  }
60
118
 
119
+ const { duration, attachments } = result;
120
+
121
+ fakeTest.duration = duration;
122
+ fakeTest.attachments = attachments;
123
+ fakeTest.state = result.status === 'failed' ? 'failed' : 'passed';
124
+ if (duration !== undefined) {
125
+ fakeTest.speed = duration > fakeTest.slow() ? 'slow' : duration / 2 > fakeTest.slow() ? 'medium' : 'fast';
126
+ }
127
+
128
+ if (isJUnit) {
129
+ this.fakeRunner.emit(TEST_EVENTS.SUITE_BEGIN, fakeSuite);
130
+ }
131
+
132
+ if (result.status === 'failed') {
133
+ fakeTest.err = result.error;
134
+ this.fakeRunner.emit(TEST_EVENTS.TEST_FAIL, fakeTest, result.error);
135
+ this.fakeRunner.stats.failures++;
136
+ } else {
137
+ this.fakeRunner.emit(TEST_EVENTS.TEST_PASS, fakeTest);
138
+ this.fakeRunner.stats.duration += duration ?? 0;
139
+ }
140
+
141
+ if (isJUnit) {
142
+ this.fakeRunner.emit(TEST_EVENTS.SUITE_END, fakeSuite);
143
+ }
144
+
145
+ this.fakeRunner.emit(TEST_EVENTS.TEST_END, fakeTest);
146
+
61
147
  this.sendUpdate({
62
148
  tests: {
63
149
  [id]: {
@@ -78,6 +164,7 @@ export default class Runner extends EventEmitter {
78
164
 
79
165
  private handlePoolStop = (): void => {
80
166
  if (!this.isRunning) {
167
+ this.fakeRunner.emit(TEST_EVENTS.RUN_END);
81
168
  this.sendUpdate({ isRunning: false });
82
169
  this.emit('stop');
83
170
  }
@@ -147,6 +234,7 @@ export default class Runner extends EventEmitter {
147
234
  };
148
235
  }, {});
149
236
 
237
+ this.fakeRunner.emit(TEST_EVENTS.RUN_BEGIN);
150
238
  this.browsers.forEach((browser) => {
151
239
  const pool = this.pools[browser];
152
240
  const tests = testsByBrowser[browser];
@@ -198,9 +286,7 @@ export default class Runner extends EventEmitter {
198
286
  if (!image) continue;
199
287
  await this.copyImage(test, name, image.actual);
200
288
 
201
- if (!test.approved) {
202
- test.approved = {};
203
- }
289
+ test.approved ??= {};
204
290
  test.approved[name] = retry;
205
291
  test.status = 'approved';
206
292
 
@@ -224,9 +310,7 @@ export default class Runner extends EventEmitter {
224
310
  if (!result.images) return;
225
311
  const images = result.images[image];
226
312
  if (!images) return;
227
- if (!test.approved) {
228
- test.approved = {};
229
- }
313
+ test.approved ??= {};
230
314
  const { browser, testName, storyPath, storyId } = test;
231
315
 
232
316
  await this.copyImage(test, image, images.actual);
@@ -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);
@@ -14,13 +14,14 @@ import { sendScreenshotsCount } from '../telemetry.js';
14
14
  const importMetaUrl = pathToFileURL(__filename).href;
15
15
 
16
16
  async function copyStatics(reportDir: string): Promise<void> {
17
- const clientDir = path.join(path.dirname(fileURLToPath(importMetaUrl)), '../../client/web');
18
- const files = (await readdir(clientDir, { withFileTypes: true }))
19
- .filter((dirent) => dirent.isFile() && !dirent.name.endsWith('.d.ts') && !dirent.name.endsWith('.tsx'))
17
+ const clientDir = path.join(path.dirname(fileURLToPath(importMetaUrl)), '../../../dist/client/web');
18
+ const assets = (await readdir(path.join(clientDir, 'assets'), { withFileTypes: true }))
19
+ .filter((dirent) => dirent.isFile())
20
20
  .map((dirent) => dirent.name);
21
- await mkdir(reportDir, { recursive: true });
22
- for (const file of files) {
23
- await copyFile(path.join(clientDir, file), path.join(reportDir, file));
21
+ await mkdir(path.join(reportDir, 'assets'), { recursive: true });
22
+ await copyFile(path.join(clientDir, 'index.html'), path.join(reportDir, 'index.html'));
23
+ for (const asset of assets) {
24
+ await copyFile(path.join(clientDir, 'assets', asset), path.join(reportDir, 'assets', asset));
24
25
  }
25
26
  }
26
27
 
@@ -42,7 +43,10 @@ function outputUnnecessaryImages(imagesDir: string, images: Set<string>): void {
42
43
  .map((imagePath) => path.posix.relative(imagesDir, imagePath))
43
44
  .filter((imagePath) => !images.has(imagePath));
44
45
  if (unnecessaryImages.length > 0) {
45
- logger.warn('We found unnecessary screenshot images, those can be safely removed:\n', unnecessaryImages.join('\n'));
46
+ logger().warn(
47
+ 'We found unnecessary screenshot images, those can be safely removed:\n',
48
+ unnecessaryImages.join('\n'),
49
+ );
46
50
  }
47
51
  }
48
52
 
@@ -81,10 +85,10 @@ export async function start(
81
85
 
82
86
  if (options.ui) {
83
87
  resolveApi(creeveyApi(runner));
84
- logger.info(`Started on http://localhost:${options.port}`);
88
+ logger().info(`Started on http://localhost:${options.port}`);
85
89
  } else {
86
90
  if (Object.values(runner.status.tests).filter((test) => test && !test.skip).length == 0) {
87
- logger.warn("Don't have any tests to run");
91
+ logger().warn("Don't have any tests to run");
88
92
 
89
93
  void shutdownWorkers().then(() => process.exit());
90
94
  return;
@@ -101,10 +105,11 @@ export async function start(
101
105
  void sendScreenshotsCount(config, options, runner.status)
102
106
  .catch((reason: unknown) => {
103
107
  const error = reason instanceof Error ? (reason.stack ?? reason.message) : (reason as string);
104
- logger.warn(`Can't send telemetry: ${error}`);
108
+ logger().warn(`Can't send telemetry: ${error}`);
105
109
  })
106
110
  .finally(() => {
107
- void shutdownWorkers().then(() => process.exit());
111
+ // NOTE: Take some time to kill processes
112
+ void shutdownWorkers().then(() => setTimeout(() => process.exit(), 500));
108
113
  });
109
114
  });
110
115
  // TODO grep
@@ -1,8 +1,12 @@
1
+ import { readFile } from 'fs/promises';
2
+ import { pathToFileURL } from 'url';
1
3
  import semver from 'semver';
2
4
  import { exec } from 'shelljs';
3
5
 
6
+ const importMetaUrl = pathToFileURL(__filename).href;
7
+
4
8
  // TODO Support custom docker images
5
- export function playwrightDockerFile(browser: string, version: string): string {
9
+ export async function playwrightDockerFile(browser: string, version: string): Promise<string> {
6
10
  const sv = semver.coerce(version);
7
11
 
8
12
  let npmRegistry;
@@ -12,23 +16,31 @@ export function playwrightDockerFile(browser: string, version: string): string {
12
16
  /* noop */
13
17
  }
14
18
 
15
- return `
16
- FROM mcr.microsoft.com/playwright:v${sv?.format() ?? version}
19
+ const indexJs = await readFile(new URL('./index-source.mjs', importMetaUrl), 'utf-8');
20
+
21
+ const dockerfile = `
22
+ FROM node:lts
17
23
 
18
24
  WORKDIR /creevey
19
25
 
20
26
  RUN echo "{ \\"type\\": \\"module\\" }" > package.json && \\
21
- echo "import { ${browser} as browser } from 'playwright-core';" >> index.js && \\
22
- echo "const ws = await browser.launchServer({ port: 4444, wsPath: 'creevey' })" >> index.js && \\${
27
+ ${indexJs
28
+ .split('\n')
29
+ .map((line) => ` echo "${line.replace(/"/g, '\\"')}" >> index.js && \\`)
30
+ .join('\n')}
31
+ ${
23
32
  npmRegistry
24
33
  ? `
25
34
  echo "registry=${npmRegistry}" > .npmrc && \\`
26
35
  : ''
27
36
  }
28
- npm i playwright-core${sv ? `@${sv.format()}` : ''}
37
+ npm i playwright-core${sv ? `@${sv.format()}` : ''} && \\
38
+ npx -y playwright${sv ? `@${sv.format()}` : ''} install --with-deps ${browser}
29
39
 
30
40
  EXPOSE 4444
31
41
 
32
42
  ENTRYPOINT [ "node", "./index.js" ]
33
43
  `;
44
+
45
+ return dockerfile.replace(/\\\n\s*\\?\n/g, '\\\n');
34
46
  }
@@ -1,9 +1,17 @@
1
+ import assert from 'assert';
1
2
  import { runImage } from '../docker';
2
3
  import { emitWorkerMessage, subscribeOn } from '../messages';
3
- import { isInsideDocker } from '../utils';
4
+ import { getCreeveyCache, isInsideDocker, resolvePlaywrightBrowserType } from '../utils';
4
5
  import { LOCALHOST_REGEXP } from '../webdriver';
6
+ import type { BrowserConfigObject, Config } from '../../types';
5
7
 
6
- export async function startPlaywrightContainer(imageName: string, debug: boolean): Promise<string> {
8
+ export async function startPlaywrightContainer(
9
+ imageName: string,
10
+ browser: string,
11
+ config: Config,
12
+ debug: boolean,
13
+ ): Promise<string> {
14
+ const { browserName, playwrightOptions } = config.browsers[browser] as BrowserConfigObject;
7
15
  const port = await new Promise<number>((resolve) => {
8
16
  subscribeOn('worker', (message) => {
9
17
  if (message.type == 'port') {
@@ -13,13 +21,18 @@ export async function startPlaywrightContainer(imageName: string, debug: boolean
13
21
  emitWorkerMessage({ type: 'port', payload: { port: -1 } });
14
22
  });
15
23
 
24
+ const cacheDir = await getCreeveyCache();
25
+
26
+ assert(cacheDir, "Couldn't get cache directory");
27
+
16
28
  const host = await runImage(
17
29
  imageName,
18
- [],
30
+ [JSON.stringify({ ...playwrightOptions, browser: resolvePlaywrightBrowserType(browserName) })],
19
31
  {
20
32
  ExposedPorts: { [`${port}/tcp`]: {} },
21
33
  HostConfig: {
22
34
  PortBindings: { ['4444/tcp']: [{ HostPort: `${port}` }] },
35
+ Binds: [`${cacheDir}/${process.pid}:/creevey/traces`],
23
36
  },
24
37
  },
25
38
  debug,
@@ -0,0 +1,16 @@
1
+ import { chromium, firefox, webkit } from 'playwright-core';
2
+
3
+ /** @type import("playwright-core").LaunchOptions & { browser: 'chromium' | 'firefox' | 'webkit' } */
4
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
5
+ const config = JSON.parse(process.argv.slice(2)[0]);
6
+
7
+ const browsers = { chromium, firefox, webkit };
8
+
9
+ const ws = await browsers[config.browser].launchServer({
10
+ ...config,
11
+ port: 4444,
12
+ wsPath: 'creevey',
13
+ tracesDir: 'traces',
14
+ });
15
+
16
+ console.log(config.browser, 'browser server launched on:', ws.wsEndpoint());