creevey 0.9.0-beta.1 → 0.9.0-non-webpack.0

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 (267) hide show
  1. package/AUTHORS +15 -15
  2. package/CHANGELOG.md +1275 -1275
  3. package/LICENSE +21 -21
  4. package/README.md +7 -0
  5. package/addon/README.md +3 -0
  6. package/addon/package.json +4 -0
  7. package/docs/config.md +212 -212
  8. package/docs/grid.md +10 -10
  9. package/docs/tests.md +63 -63
  10. package/jest.config.js +6 -0
  11. package/lib/cjs/cli.js +5 -0
  12. package/lib/cjs/client/addon/Manager.js +418 -0
  13. package/lib/cjs/client/addon/components/Addon.js +76 -0
  14. package/lib/cjs/client/addon/components/Icons.js +42 -0
  15. package/lib/cjs/client/addon/components/Panel.js +68 -0
  16. package/lib/cjs/client/addon/components/TestSelect.js +63 -0
  17. package/lib/cjs/client/addon/components/Tools.js +114 -0
  18. package/lib/cjs/client/addon/decorator.js +11 -0
  19. package/lib/cjs/client/addon/index.js +31 -0
  20. package/lib/cjs/client/addon/preset.js +81 -0
  21. package/lib/cjs/client/addon/readyForCapture.js +12 -0
  22. package/lib/cjs/client/addon/register.js +100 -0
  23. package/lib/cjs/client/addon/utils.js +38 -0
  24. package/lib/cjs/client/addon/withCreevey.js +558 -0
  25. package/lib/cjs/client/shared/components/ImagesView/BlendView.js +85 -0
  26. package/lib/cjs/client/shared/components/ImagesView/ImagesView.js +88 -0
  27. package/lib/cjs/client/shared/components/ImagesView/SideBySideView.js +176 -0
  28. package/lib/cjs/client/shared/components/ImagesView/SlideView.js +179 -0
  29. package/lib/cjs/client/shared/components/ImagesView/SwapView.js +110 -0
  30. package/lib/cjs/client/shared/components/ImagesView/index.js +45 -0
  31. package/lib/cjs/client/shared/components/PageFooter/PageFooter.js +46 -0
  32. package/lib/cjs/client/shared/components/PageFooter/Paging.js +98 -0
  33. package/lib/cjs/client/shared/components/PageHeader/ImagePreview.js +78 -0
  34. package/lib/cjs/client/shared/components/PageHeader/PageHeader.js +144 -0
  35. package/lib/cjs/client/shared/components/ResultsPage.js +173 -0
  36. package/lib/cjs/client/shared/creeveyClientApi.js +107 -0
  37. package/lib/cjs/client/shared/helpers.js +482 -0
  38. package/lib/cjs/client/shared/viewMode.js +17 -0
  39. package/lib/cjs/client/web/142.js +2 -0
  40. package/lib/cjs/client/web/142.js.LICENSE.txt +12 -0
  41. package/lib/cjs/client/web/32.js +1 -0
  42. package/lib/cjs/client/web/551.js +1 -0
  43. package/lib/cjs/client/web/566.js +2 -0
  44. package/lib/cjs/client/web/566.js.LICENSE.txt +31 -0
  45. package/lib/cjs/client/web/691.js +2 -0
  46. package/lib/cjs/client/web/691.js.LICENSE.txt +8 -0
  47. package/lib/cjs/client/web/725.js +1 -0
  48. package/lib/cjs/client/web/index.html +19 -0
  49. package/lib/cjs/client/web/main.js +2 -38
  50. package/lib/cjs/client/web/main.js.LICENSE.txt +49 -0
  51. package/lib/cjs/creevey.js +69 -0
  52. package/lib/cjs/index.js +62 -0
  53. package/lib/cjs/server/config.js +96 -0
  54. package/lib/cjs/server/docker.js +146 -0
  55. package/lib/cjs/server/extract.js +50 -0
  56. package/lib/cjs/server/index.js +83 -0
  57. package/lib/cjs/server/loaders/babel/creevey-plugin.js +86 -0
  58. package/lib/cjs/server/loaders/babel/helpers.js +469 -0
  59. package/lib/cjs/server/loaders/babel/register.js +124 -0
  60. package/lib/cjs/server/loaders/hooks/mdx.js +30 -0
  61. package/lib/cjs/server/loaders/hooks/svelte.js +65 -0
  62. package/lib/cjs/server/loaders/webpack/compile.js +293 -0
  63. package/lib/cjs/server/loaders/webpack/creevey-loader.js +179 -0
  64. package/lib/cjs/server/loaders/webpack/dummy-hmr.js +39 -0
  65. package/lib/cjs/server/loaders/webpack/mdx-loader.js +72 -0
  66. package/lib/cjs/server/loaders/webpack/start.js +41 -0
  67. package/lib/cjs/server/logger.js +48 -0
  68. package/lib/cjs/server/master/api.js +71 -0
  69. package/lib/cjs/server/master/index.js +146 -0
  70. package/lib/cjs/server/master/master.js +57 -0
  71. package/lib/cjs/server/master/pool.js +197 -0
  72. package/lib/cjs/server/master/runner.js +281 -0
  73. package/lib/cjs/server/master/server.js +129 -0
  74. package/lib/cjs/server/messages.js +264 -0
  75. package/lib/cjs/server/selenium/browser.js +672 -0
  76. package/lib/cjs/server/selenium/index.js +31 -0
  77. package/lib/cjs/server/selenium/selenoid.js +172 -0
  78. package/lib/cjs/server/stories.js +159 -0
  79. package/lib/cjs/server/storybook/entry.js +70 -0
  80. package/lib/cjs/server/storybook/helpers.js +159 -0
  81. package/lib/cjs/server/storybook/providers/browser.js +74 -0
  82. package/lib/cjs/server/storybook/providers/hybrid.js +84 -0
  83. package/lib/cjs/server/storybook/providers/nodejs.js +239 -0
  84. package/lib/cjs/server/testsFiles/parser.js +72 -0
  85. package/lib/cjs/server/testsFiles/register.js +48 -0
  86. package/lib/cjs/server/update.js +79 -0
  87. package/lib/cjs/server/utils.js +183 -0
  88. package/lib/cjs/server/worker/chai-image.js +142 -0
  89. package/lib/cjs/server/worker/helpers.js +69 -0
  90. package/lib/cjs/server/worker/index.js +15 -0
  91. package/lib/cjs/server/worker/reporter.js +108 -0
  92. package/lib/cjs/server/worker/worker.js +268 -0
  93. package/lib/cjs/shared/index.js +89 -0
  94. package/lib/cjs/shared/serializeRegExp.js +41 -0
  95. package/lib/cjs/types.js +74 -0
  96. package/lib/esm/cli.js +4 -0
  97. package/lib/esm/client/addon/Manager.js +402 -0
  98. package/lib/esm/client/addon/components/Addon.js +58 -0
  99. package/lib/esm/client/addon/components/Icons.js +27 -0
  100. package/lib/esm/client/addon/components/Panel.js +49 -0
  101. package/lib/esm/client/addon/components/TestSelect.js +49 -0
  102. package/lib/esm/client/addon/components/Tools.js +91 -0
  103. package/lib/esm/client/addon/decorator.js +2 -0
  104. package/lib/esm/client/addon/index.js +2 -0
  105. package/lib/esm/client/addon/preset.js +56 -0
  106. package/lib/esm/client/addon/readyForCapture.js +5 -0
  107. package/lib/esm/client/addon/register.js +79 -0
  108. package/lib/esm/client/addon/utils.js +31 -0
  109. package/lib/esm/client/addon/withCreevey.js +534 -0
  110. package/lib/esm/client/shared/components/ImagesView/BlendView.js +63 -0
  111. package/lib/esm/client/shared/components/ImagesView/ImagesView.js +65 -0
  112. package/lib/esm/client/shared/components/ImagesView/SideBySideView.js +151 -0
  113. package/lib/esm/client/shared/components/ImagesView/SlideView.js +154 -0
  114. package/lib/esm/client/shared/components/ImagesView/SwapView.js +88 -0
  115. package/lib/esm/client/shared/components/ImagesView/index.js +5 -0
  116. package/lib/esm/client/shared/components/PageFooter/PageFooter.js +32 -0
  117. package/lib/esm/client/shared/components/PageFooter/Paging.js +84 -0
  118. package/lib/esm/client/shared/components/PageHeader/ImagePreview.js +64 -0
  119. package/lib/esm/client/shared/components/PageHeader/PageHeader.js +120 -0
  120. package/lib/esm/client/shared/components/ResultsPage.js +143 -0
  121. package/lib/esm/client/shared/creeveyClientApi.js +98 -0
  122. package/lib/esm/client/shared/helpers.js +424 -0
  123. package/lib/esm/client/shared/viewMode.js +6 -0
  124. package/lib/esm/creevey.js +54 -0
  125. package/lib/esm/index.js +5 -0
  126. package/lib/esm/server/config.js +73 -0
  127. package/lib/esm/server/docker.js +123 -0
  128. package/lib/esm/server/extract.js +34 -0
  129. package/lib/esm/server/index.js +64 -0
  130. package/lib/esm/server/loaders/babel/creevey-plugin.js +72 -0
  131. package/lib/esm/server/loaders/babel/helpers.js +452 -0
  132. package/lib/esm/server/loaders/babel/register.js +103 -0
  133. package/lib/esm/server/loaders/hooks/mdx.js +15 -0
  134. package/lib/esm/server/loaders/hooks/svelte.js +49 -0
  135. package/lib/esm/server/loaders/webpack/compile.js +270 -0
  136. package/lib/esm/server/loaders/webpack/creevey-loader.js +158 -0
  137. package/lib/esm/server/loaders/webpack/dummy-hmr.js +32 -0
  138. package/lib/esm/server/loaders/webpack/mdx-loader.js +58 -0
  139. package/lib/esm/server/loaders/webpack/start.js +27 -0
  140. package/lib/esm/server/logger.js +20 -0
  141. package/lib/esm/server/master/api.js +60 -0
  142. package/lib/esm/server/master/index.js +125 -0
  143. package/lib/esm/server/master/master.js +38 -0
  144. package/lib/esm/server/master/pool.js +176 -0
  145. package/lib/esm/server/master/runner.js +259 -0
  146. package/lib/esm/server/master/server.js +105 -0
  147. package/lib/esm/server/messages.js +232 -0
  148. package/lib/esm/server/selenium/browser.js +639 -0
  149. package/lib/esm/server/selenium/index.js +2 -0
  150. package/lib/esm/server/selenium/selenoid.js +149 -0
  151. package/lib/esm/server/stories.js +140 -0
  152. package/lib/esm/server/storybook/entry.js +46 -0
  153. package/lib/esm/server/storybook/helpers.js +98 -0
  154. package/lib/esm/server/storybook/providers/browser.js +60 -0
  155. package/lib/esm/server/storybook/providers/hybrid.js +64 -0
  156. package/lib/esm/server/storybook/providers/nodejs.js +217 -0
  157. package/lib/esm/server/testsFiles/parser.js +50 -0
  158. package/lib/esm/server/testsFiles/register.js +35 -0
  159. package/lib/esm/server/update.js +61 -0
  160. package/lib/esm/server/utils.js +142 -0
  161. package/lib/esm/server/worker/chai-image.js +130 -0
  162. package/lib/esm/server/worker/helpers.js +60 -0
  163. package/lib/esm/server/worker/index.js +1 -0
  164. package/lib/esm/server/worker/reporter.js +86 -0
  165. package/lib/esm/server/worker/worker.js +238 -0
  166. package/lib/esm/shared/index.js +66 -0
  167. package/lib/esm/shared/serializeRegExp.js +23 -0
  168. package/lib/esm/types.js +43 -0
  169. package/lib/types/cli.d.ts +1 -1
  170. package/lib/types/client/addon/Manager.d.ts +37 -37
  171. package/lib/types/client/addon/components/Addon.d.ts +8 -8
  172. package/lib/types/client/addon/components/Icons.d.ts +7 -7
  173. package/lib/types/client/addon/components/Panel.d.ts +9 -9
  174. package/lib/types/client/addon/components/TestSelect.d.ts +8 -9
  175. package/lib/types/client/addon/components/Tools.d.ts +6 -6
  176. package/lib/types/client/addon/decorator.d.ts +1 -1
  177. package/lib/types/client/addon/index.d.ts +2 -0
  178. package/lib/types/client/addon/preset.d.ts +23 -24
  179. package/lib/types/client/addon/readyForCapture.d.ts +6 -6
  180. package/lib/types/client/addon/register.d.ts +3 -3
  181. package/lib/types/client/addon/utils.d.ts +2 -2
  182. package/lib/types/client/addon/withCreevey.d.ts +24 -24
  183. package/lib/types/client/shared/components/ImagesView/BlendView.d.ts +3 -3
  184. package/lib/types/client/shared/components/ImagesView/ImagesView.d.ts +24 -25
  185. package/lib/types/client/shared/components/ImagesView/SideBySideView.d.ts +3 -3
  186. package/lib/types/client/shared/components/ImagesView/SlideView.d.ts +3 -3
  187. package/lib/types/client/shared/components/ImagesView/SwapView.d.ts +3 -3
  188. package/lib/types/client/shared/components/ImagesView/index.d.ts +5 -5
  189. package/lib/types/client/shared/components/PageFooter/PageFooter.d.ts +8 -9
  190. package/lib/types/client/shared/components/PageFooter/Paging.d.ts +7 -8
  191. package/lib/types/client/shared/components/PageHeader/ImagePreview.d.ts +12 -12
  192. package/lib/types/client/shared/components/PageHeader/PageHeader.d.ts +16 -17
  193. package/lib/types/client/shared/components/ResultsPage.d.ts +18 -18
  194. package/lib/types/client/shared/creeveyClientApi.d.ts +9 -9
  195. package/lib/types/client/shared/helpers.d.ts +46 -46
  196. package/lib/types/client/shared/viewMode.d.ts +4 -4
  197. package/lib/types/client/web/CreeveyApp.d.ts +11 -12
  198. package/lib/types/client/web/CreeveyContext.d.ts +11 -11
  199. package/lib/types/client/web/CreeveyLoader.d.ts +2 -3
  200. package/lib/types/client/web/CreeveyView/SideBar/Checkbox.d.ts +19 -19
  201. package/lib/types/client/web/CreeveyView/SideBar/Search.d.ts +6 -6
  202. package/lib/types/client/web/CreeveyView/SideBar/SideBar.d.ts +14 -14
  203. package/lib/types/client/web/CreeveyView/SideBar/SideBarHeader.d.ts +12 -13
  204. package/lib/types/client/web/CreeveyView/SideBar/SuiteLink.d.ts +33 -33
  205. package/lib/types/client/web/CreeveyView/SideBar/TestLink.d.ts +7 -8
  206. package/lib/types/client/web/CreeveyView/SideBar/TestStatusIcon.d.ts +10 -10
  207. package/lib/types/client/web/CreeveyView/SideBar/TestsStatus.d.ts +9 -9
  208. package/lib/types/client/web/CreeveyView/SideBar/Toggle.d.ts +6 -6
  209. package/lib/types/client/web/CreeveyView/SideBar/index.d.ts +1 -1
  210. package/lib/types/client/web/KeyboardEventsContext.d.ts +13 -13
  211. package/lib/types/client/web/index.d.ts +4 -4
  212. package/lib/types/creevey.d.ts +1 -1
  213. package/lib/types/index.d.ts +1 -4
  214. package/lib/types/server/config.d.ts +4 -4
  215. package/lib/types/server/docker.d.ts +7 -7
  216. package/lib/types/server/extract.d.ts +2 -2
  217. package/lib/types/server/index.d.ts +2 -2
  218. package/lib/types/server/loaders/babel/creevey-plugin.d.ts +1 -1
  219. package/lib/types/server/loaders/babel/helpers.d.ts +19 -19
  220. package/lib/types/server/loaders/babel/register.d.ts +5 -5
  221. package/lib/types/server/loaders/hooks/mdx.d.ts +1 -1
  222. package/lib/types/server/loaders/hooks/svelte.d.ts +1 -1
  223. package/lib/types/server/loaders/webpack/compile.d.ts +2 -2
  224. package/lib/types/server/loaders/webpack/creevey-loader.d.ts +4 -2
  225. package/lib/types/server/loaders/webpack/dummy-hmr.d.ts +10 -10
  226. package/lib/types/server/loaders/webpack/mdx-loader.d.ts +6 -6
  227. package/lib/types/server/loaders/webpack/start.d.ts +1 -1
  228. package/lib/types/server/logger.d.ts +10 -6
  229. package/lib/types/server/master/api.d.ts +7 -7
  230. package/lib/types/server/master/index.d.ts +3 -3
  231. package/lib/types/server/master/master.d.ts +7 -7
  232. package/lib/types/server/master/pool.d.ts +31 -31
  233. package/lib/types/server/master/runner.d.ts +26 -26
  234. package/lib/types/server/master/server.d.ts +2 -2
  235. package/lib/types/server/messages.d.ts +27 -27
  236. package/lib/types/server/selenium/browser.d.ts +17 -17
  237. package/lib/types/server/selenium/index.d.ts +2 -2
  238. package/lib/types/server/selenium/selenoid.d.ts +3 -3
  239. package/lib/types/server/stories.d.ts +8 -8
  240. package/lib/types/server/storybook/entry.d.ts +18 -18
  241. package/lib/types/server/storybook/helpers.d.ts +24 -24
  242. package/lib/types/server/storybook/providers/browser.d.ts +4 -4
  243. package/lib/types/server/storybook/providers/hybrid.d.ts +4 -4
  244. package/lib/types/server/storybook/providers/nodejs.d.ts +9 -9
  245. package/lib/types/server/testsFiles/parser.d.ts +12 -12
  246. package/lib/types/server/testsFiles/register.d.ts +2 -2
  247. package/lib/types/server/update.d.ts +2 -2
  248. package/lib/types/server/utils.d.ts +20 -20
  249. package/lib/types/server/worker/chai-image.d.ts +6 -6
  250. package/lib/types/server/worker/helpers.d.ts +8 -8
  251. package/lib/types/server/worker/index.d.ts +1 -1
  252. package/lib/types/server/worker/reporter.d.ts +8 -8
  253. package/lib/types/server/worker/worker.d.ts +4 -4
  254. package/lib/types/{shared.d.ts → shared/index.d.ts} +7 -16
  255. package/lib/types/shared/serializeRegExp.d.ts +9 -0
  256. package/lib/types/types.d.ts +490 -489
  257. package/package.json +115 -102
  258. package/preset.js +9 -9
  259. package/types/babel__register.d.ts +1 -1
  260. package/types/chai.d.ts +12 -12
  261. package/types/event-source-polyfill.d.ts +6 -6
  262. package/types/mdx.d.ts +3 -2
  263. package/types/mocha.d.ts +20 -20
  264. package/types/png.d.ts +4 -4
  265. package/lib/cjs/client/web/1.js +0 -13
  266. package/lib/cjs/client/web/2.js +0 -1
  267. package/storybook-static/stories.json +0 -21
@@ -0,0 +1,259 @@
1
+ import path from 'path';
2
+ import { copyFile, mkdir } from 'fs';
3
+ import { promisify } from 'util';
4
+ import { EventEmitter } from 'events';
5
+ import { isDefined } from '../../types';
6
+ import Pool from './pool';
7
+ const copyFileAsync = promisify(copyFile);
8
+ const mkdirAsync = promisify(mkdir);
9
+ export default class Runner extends EventEmitter {
10
+ pools = {};
11
+ tests = {};
12
+
13
+ get isRunning() {
14
+ return Object.values(this.pools).some(pool => pool.isRunning);
15
+ }
16
+
17
+ constructor(config) {
18
+ super();
19
+ this.failFast = config.failFast;
20
+ this.screenDir = config.screenDir;
21
+ this.reportDir = config.reportDir;
22
+ this.browsers = Object.keys(config.browsers);
23
+ this.browsers.map(browser => this.pools[browser] = new Pool(config, browser)).map(pool => pool.on('test', this.handlePoolMessage));
24
+ }
25
+
26
+ handlePoolMessage = message => {
27
+ const {
28
+ id,
29
+ status,
30
+ result
31
+ } = message;
32
+ const test = this.tests[id];
33
+ if (!test) return;
34
+ const {
35
+ browser,
36
+ testName,
37
+ storyPath,
38
+ storyId
39
+ } = test; // TODO Handle 'retrying' status
40
+
41
+ test.status = status == 'retrying' ? 'failed' : status;
42
+
43
+ if (!result) {
44
+ this.sendUpdate({
45
+ tests: {
46
+ [id]: {
47
+ id,
48
+ browser,
49
+ testName,
50
+ storyPath,
51
+ status: test.status,
52
+ storyId
53
+ }
54
+ }
55
+ });
56
+ return;
57
+ }
58
+
59
+ if (!test.results) {
60
+ test.results = [];
61
+ }
62
+
63
+ test.results.push(result);
64
+ this.sendUpdate({
65
+ tests: {
66
+ [id]: {
67
+ id,
68
+ browser,
69
+ testName,
70
+ storyPath,
71
+ status: test.status,
72
+ results: [result],
73
+ storyId
74
+ }
75
+ }
76
+ });
77
+ if (this.failFast && status == 'failed') this.stop();
78
+ };
79
+ handlePoolStop = () => {
80
+ if (!this.isRunning) {
81
+ this.sendUpdate({
82
+ isRunning: false
83
+ });
84
+ this.emit('stop');
85
+ }
86
+ };
87
+
88
+ async init() {
89
+ await Promise.all(Object.values(this.pools).map(pool => pool.init()));
90
+ }
91
+
92
+ updateTests(testsDiff) {
93
+ const tests = {};
94
+ const removedTests = [];
95
+ Object.entries(testsDiff).forEach(([id, newTest]) => {
96
+ const oldTest = this.tests[id];
97
+
98
+ if (newTest) {
99
+ if (oldTest) {
100
+ this.tests[id] = { ...newTest,
101
+ retries: oldTest.retries,
102
+ results: oldTest.results,
103
+ approved: oldTest.approved
104
+ };
105
+ } else this.tests[id] = newTest; // eslint-disable-next-line @typescript-eslint/no-unused-vars
106
+
107
+
108
+ const {
109
+ story,
110
+ fn,
111
+ ...restTest
112
+ } = newTest;
113
+ tests[id] = { ...restTest,
114
+ status: 'unknown'
115
+ };
116
+ } else if (oldTest) {
117
+ const {
118
+ id,
119
+ browser,
120
+ testName,
121
+ storyPath,
122
+ storyId
123
+ } = oldTest;
124
+ removedTests.push({
125
+ id,
126
+ browser,
127
+ testName,
128
+ storyPath,
129
+ storyId
130
+ });
131
+ delete this.tests[id];
132
+ }
133
+ });
134
+ this.sendUpdate({
135
+ tests,
136
+ removedTests
137
+ });
138
+ }
139
+
140
+ start(ids) {
141
+ if (this.isRunning) return;
142
+ const testsToStart = ids.map(id => this.tests[id]).filter(isDefined).filter(test => !test.skip);
143
+ if (testsToStart.length == 0) return;
144
+ this.sendUpdate({
145
+ isRunning: true,
146
+ tests: testsToStart.reduce((update, {
147
+ id,
148
+ storyId,
149
+ browser,
150
+ testName,
151
+ storyPath
152
+ }) => ({ ...update,
153
+ [id]: {
154
+ id,
155
+ browser,
156
+ testName,
157
+ storyPath,
158
+ status: 'pending',
159
+ storyId
160
+ }
161
+ }), {})
162
+ });
163
+ const testsByBrowser = testsToStart.reduce((tests, test) => {
164
+ const {
165
+ id,
166
+ browser,
167
+ testName,
168
+ storyPath
169
+ } = test;
170
+ const restPath = [...storyPath, testName].filter(isDefined);
171
+ test.status = 'pending';
172
+ return { ...tests,
173
+ [browser]: [...(tests[browser] || []), {
174
+ id,
175
+ path: restPath
176
+ }]
177
+ };
178
+ }, {});
179
+ this.browsers.forEach(browser => {
180
+ const pool = this.pools[browser];
181
+ const tests = testsByBrowser[browser];
182
+
183
+ if (tests && tests.length > 0 && pool.start(tests)) {
184
+ pool.once('stop', this.handlePoolStop);
185
+ }
186
+ });
187
+ }
188
+
189
+ stop() {
190
+ if (!this.isRunning) return;
191
+ this.browsers.forEach(browser => this.pools[browser].stop());
192
+ }
193
+
194
+ get status() {
195
+ const tests = {};
196
+ Object.values(this.tests).filter(isDefined) // eslint-disable-next-line @typescript-eslint/no-unused-vars
197
+ .forEach(({
198
+ story,
199
+ fn,
200
+ ...test
201
+ }) => tests[test.id] = test);
202
+ return {
203
+ isRunning: this.isRunning,
204
+ tests,
205
+ browsers: this.browsers
206
+ };
207
+ }
208
+
209
+ async approve({
210
+ id,
211
+ retry,
212
+ image
213
+ }) {
214
+ const test = this.tests[id];
215
+ if (!test || !test.results) return;
216
+ const result = test.results[retry];
217
+ if (!result || !result.images) return;
218
+ const images = result.images[image];
219
+ if (!images) return;
220
+
221
+ if (!test.approved) {
222
+ test.approved = {};
223
+ }
224
+
225
+ const {
226
+ browser,
227
+ testName,
228
+ storyPath
229
+ } = test;
230
+ const restPath = [...storyPath, testName].filter(isDefined);
231
+ const testPath = path.join(...restPath, image == browser ? '' : browser);
232
+ const srcImagePath = path.join(this.reportDir, testPath, images.actual);
233
+ const dstImagePath = path.join(this.screenDir, testPath, `${image}.png`);
234
+ await mkdirAsync(path.join(this.screenDir, testPath), {
235
+ recursive: true
236
+ });
237
+ await copyFileAsync(srcImagePath, dstImagePath);
238
+ test.approved[image] = retry;
239
+ this.sendUpdate({
240
+ tests: {
241
+ [id]: {
242
+ id,
243
+ browser,
244
+ testName,
245
+ storyPath,
246
+ approved: {
247
+ [image]: retry
248
+ },
249
+ storyId: test.storyId
250
+ }
251
+ }
252
+ });
253
+ }
254
+
255
+ sendUpdate(data) {
256
+ this.emit('update', data);
257
+ }
258
+
259
+ }
@@ -0,0 +1,105 @@
1
+ import path from 'path';
2
+ import http from 'http';
3
+ import cluster from 'cluster';
4
+ import Koa from 'koa';
5
+ import cors from '@koa/cors';
6
+ import serve from 'koa-static';
7
+ import mount from 'koa-mount';
8
+ import body from 'koa-bodyparser';
9
+ import WebSocket from 'ws';
10
+ import { emitStoriesMessage, sendStoriesMessage, subscribeOn, subscribeOnWorker } from '../messages';
11
+ import { isDefined, noop } from '../../types';
12
+ import { logger } from '../logger';
13
+ import { deserializeStory } from '../../shared';
14
+ export default function server(reportDir, port, ui) {
15
+ let resolveApi = noop;
16
+ let setStoriesCounter = 0;
17
+ const creeveyApi = new Promise(resolve => resolveApi = resolve);
18
+ const app = new Koa();
19
+ const server = http.createServer(app.callback());
20
+ const wss = new WebSocket.Server({
21
+ server
22
+ });
23
+ app.use(cors());
24
+ app.use(body());
25
+ app.use(async (ctx, next) => {
26
+ if (ctx.method == 'GET' && ctx.path == '/ping') {
27
+ ctx.body = 'pong';
28
+ return;
29
+ }
30
+
31
+ await next();
32
+ });
33
+
34
+ if (ui) {
35
+ app.use(async (_, next) => {
36
+ await creeveyApi;
37
+ await next();
38
+ });
39
+ }
40
+
41
+ app.use(async (ctx, next) => {
42
+ if (ctx.method == 'POST' && ctx.path == '/stories') {
43
+ const {
44
+ setStoriesCounter: counter,
45
+ stories
46
+ } = ctx.request.body;
47
+ if (setStoriesCounter >= counter) return;
48
+ const deserializedStories = stories.map(([file, stories]) => [file, stories.map(deserializeStory)]);
49
+ setStoriesCounter = counter;
50
+ emitStoriesMessage({
51
+ type: 'update',
52
+ payload: deserializedStories
53
+ });
54
+ Object.values(cluster.workers ?? {}).filter(isDefined).filter(worker => worker.isConnected()).forEach(worker => sendStoriesMessage(worker, {
55
+ type: 'update',
56
+ payload: deserializedStories
57
+ }));
58
+ return;
59
+ }
60
+
61
+ await next();
62
+ });
63
+ app.use(async (ctx, next) => {
64
+ if (ctx.method == 'POST' && ctx.path == '/capture') {
65
+ const {
66
+ workerId,
67
+ options
68
+ } = ctx.request.body;
69
+ const worker = Object.values(cluster.workers ?? {}).filter(isDefined).find(worker => worker.process.pid == workerId); // NOTE: Hypothetical case when someone send to us capture req and we don't have a worker with browser session for it
70
+
71
+ if (!worker) return;
72
+ await new Promise(resolve => {
73
+ const unsubscribe = subscribeOnWorker(worker, 'stories', message => {
74
+ if (message.type != 'capture') return;
75
+ unsubscribe();
76
+ resolve();
77
+ });
78
+ sendStoriesMessage(worker, {
79
+ type: 'capture',
80
+ payload: options
81
+ });
82
+ }); // TODO Pass screenshot result to show it in inspector
83
+
84
+ ctx.body = 'Ok';
85
+ return;
86
+ }
87
+
88
+ await next();
89
+ });
90
+ app.use(serve(path.join(__dirname, '../../client/web')));
91
+ app.use(mount('/report', serve(reportDir)));
92
+ wss.on('error', error => logger.error(error));
93
+ server.listen(port);
94
+ subscribeOn('shutdown', () => {
95
+ server.close();
96
+ wss.close();
97
+ });
98
+ void creeveyApi.then(api => {
99
+ api.subscribe(wss);
100
+ wss.on('connection', ws => {
101
+ ws.on('message', message => api.handleMessage(ws, message));
102
+ });
103
+ });
104
+ return resolveApi;
105
+ }
@@ -0,0 +1,232 @@
1
+ import cluster from 'cluster';
2
+
3
+ function emitMessage(message) {
4
+ var _process$send, _process;
5
+
6
+ if (cluster.isWorker && !process.connected) return false;
7
+ return ((_process$send = (_process = process).send) === null || _process$send === void 0 ? void 0 : _process$send.call(_process, message)) ?? // @ts-expect-error: wrong typings `process.emit` return boolean
8
+ process.emit('message', message);
9
+ }
10
+
11
+ export function emitWorkerMessage(message) {
12
+ return emitMessage({
13
+ scope: 'worker',
14
+ ...message
15
+ });
16
+ }
17
+ export function emitStoriesMessage(message) {
18
+ return emitMessage({
19
+ scope: 'stories',
20
+ ...message
21
+ });
22
+ }
23
+ export function emitTestMessage(message) {
24
+ return emitMessage({
25
+ scope: 'test',
26
+ ...message
27
+ });
28
+ }
29
+ export function emitWebpackMessage(message) {
30
+ return emitMessage({
31
+ scope: 'webpack',
32
+ ...message
33
+ });
34
+ }
35
+ export function emitDockerMessage(message) {
36
+ return emitMessage({
37
+ scope: 'docker',
38
+ ...message
39
+ });
40
+ }
41
+ export function emitShutdownMessage() {
42
+ return emitMessage({
43
+ scope: 'shutdown'
44
+ });
45
+ }
46
+
47
+ function createHandlers() {
48
+ return Object.assign(Object.create(null), {
49
+ worker: new Set(),
50
+ stories: new Set(),
51
+ test: new Set(),
52
+ webpack: new Set(),
53
+ docker: new Set(),
54
+ shutdown: new Set()
55
+ });
56
+ }
57
+
58
+ const handlers = createHandlers();
59
+
60
+ const handler = message => {
61
+ switch (message.scope) {
62
+ case 'worker':
63
+ return handlers.worker.forEach(h => h(message));
64
+
65
+ case 'stories':
66
+ return handlers.stories.forEach(h => h(message));
67
+
68
+ case 'test':
69
+ return handlers.test.forEach(h => h(message));
70
+
71
+ case 'webpack':
72
+ return handlers.webpack.forEach(h => h(message));
73
+
74
+ case 'docker':
75
+ return handlers.docker.forEach(h => h(message));
76
+
77
+ case 'shutdown':
78
+ return handlers.shutdown.forEach(h => h(message));
79
+ }
80
+ };
81
+
82
+ process.on('message', handler);
83
+ export function sendStoriesMessage(target, message) {
84
+ var _target$send;
85
+
86
+ (_target$send = target.send) === null || _target$send === void 0 ? void 0 : _target$send.call(target, {
87
+ scope: 'stories',
88
+ ...message
89
+ });
90
+ }
91
+ export function sendTestMessage(target, message) {
92
+ var _target$send2;
93
+
94
+ (_target$send2 = target.send) === null || _target$send2 === void 0 ? void 0 : _target$send2.call(target, {
95
+ scope: 'test',
96
+ ...message
97
+ });
98
+ }
99
+ export function sendDockerMessage(target, message) {
100
+ var _target$send3;
101
+
102
+ (_target$send3 = target.send) === null || _target$send3 === void 0 ? void 0 : _target$send3.call(target, {
103
+ scope: 'docker',
104
+ ...message
105
+ });
106
+ }
107
+ export function sendShutdownMessage(target) {
108
+ var _target$send4;
109
+
110
+ (_target$send4 = target.send) === null || _target$send4 === void 0 ? void 0 : _target$send4.call(target, {
111
+ scope: 'shutdown'
112
+ });
113
+ }
114
+ export function subscribeOn(scope, handler) {
115
+ switch (scope) {
116
+ case 'worker':
117
+ {
118
+ const workerHandler = handler;
119
+ handlers.worker.add(workerHandler);
120
+ return () => handlers.worker.delete(workerHandler);
121
+ }
122
+
123
+ case 'stories':
124
+ {
125
+ const storiesHandler = handler;
126
+ handlers.stories.add(storiesHandler);
127
+ return () => handlers.stories.delete(storiesHandler);
128
+ }
129
+
130
+ case 'test':
131
+ {
132
+ const testHandler = handler;
133
+ handlers.test.add(testHandler);
134
+ return () => handlers.test.delete(testHandler);
135
+ }
136
+
137
+ case 'webpack':
138
+ {
139
+ const webpackHandler = handler;
140
+ handlers.webpack.add(webpackHandler);
141
+ return () => handlers.webpack.delete(webpackHandler);
142
+ }
143
+
144
+ case 'docker':
145
+ {
146
+ const dockerHandler = handler;
147
+ handlers.docker.add(dockerHandler);
148
+ return () => handlers.docker.delete(dockerHandler);
149
+ }
150
+
151
+ case 'shutdown':
152
+ {
153
+ const shutdownHandler = handler;
154
+ handlers.shutdown.add(shutdownHandler);
155
+ return () => handlers.shutdown.delete(shutdownHandler);
156
+ }
157
+ }
158
+ }
159
+ const workers = new Map();
160
+ export function subscribeOnWorker(worker, scope, handler) {
161
+ const workerHandlers = workers.get(worker) ?? createHandlers();
162
+
163
+ if (!workers.has(worker)) {
164
+ workers.set(worker, workerHandlers);
165
+ worker.once('exit', () => workers.delete(worker));
166
+ worker.on('message', message => {
167
+ switch (message.scope) {
168
+ case 'worker':
169
+ return workerHandlers.worker.forEach(h => h(message));
170
+
171
+ case 'stories':
172
+ return workerHandlers.stories.forEach(h => h(message));
173
+
174
+ case 'test':
175
+ return workerHandlers.test.forEach(h => h(message));
176
+
177
+ case 'webpack':
178
+ return workerHandlers.webpack.forEach(h => h(message));
179
+
180
+ case 'docker':
181
+ return workerHandlers.docker.forEach(h => h(message));
182
+
183
+ case 'shutdown':
184
+ return workerHandlers.shutdown.forEach(h => h(message));
185
+ }
186
+ });
187
+ }
188
+
189
+ switch (scope) {
190
+ case 'worker':
191
+ {
192
+ const workerHandler = handler;
193
+ workerHandlers.worker.add(workerHandler);
194
+ return () => workerHandlers.worker.delete(workerHandler);
195
+ }
196
+
197
+ case 'stories':
198
+ {
199
+ const storiesHandler = handler;
200
+ workerHandlers.stories.add(storiesHandler);
201
+ return () => workerHandlers.stories.delete(storiesHandler);
202
+ }
203
+
204
+ case 'test':
205
+ {
206
+ const testHandler = handler;
207
+ workerHandlers.test.add(testHandler);
208
+ return () => workerHandlers.test.delete(testHandler);
209
+ }
210
+
211
+ case 'webpack':
212
+ {
213
+ const webpackHandler = handler;
214
+ workerHandlers.webpack.add(webpackHandler);
215
+ return () => workerHandlers.webpack.delete(webpackHandler);
216
+ }
217
+
218
+ case 'docker':
219
+ {
220
+ const dockerHandler = handler;
221
+ workerHandlers.docker.add(dockerHandler);
222
+ return () => workerHandlers.docker.delete(dockerHandler);
223
+ }
224
+
225
+ case 'shutdown':
226
+ {
227
+ const shutdownHandler = handler;
228
+ workerHandlers.shutdown.add(shutdownHandler);
229
+ return () => workerHandlers.shutdown.delete(shutdownHandler);
230
+ }
231
+ }
232
+ }