Run DevTools e2e tests on Circle CI (#23019)
Brian Vaughn committed
Jan 4, 2022 at 10:28 UTC
9724e180045806480d7ef2a50e6a9d70fea98252
2 files changed
+190
.circleci/config.yml
+25
@@ -200,6 +200,28 @@ jobs:
200
- store_artifacts:
201
path: ./build/devtools.tgz
202
203
+ run_devtools_e2e_tests:
204
+ docker: *docker
205
+ environment: *environment
206
+ steps:
207
+ - checkout
208
+ - attach_workspace:
209
+ at: .
210
+ - run: yarn workspaces info | head -n -1 > workspace_info.txt
211
+ - *restore_node_modules
212
+ - run:
213
+ name: Install Packages
214
+ command: yarn --frozen-lockfile --cache-folder ~/.cache/yarn
215
+ - run:
216
+ name: Playwright install deps
217
+ command: |
218
+ npx playwright install
219
+ sudo npx playwright install-deps
220
+ - run:
221
+ environment:
222
+ RELEASE_CHANNEL: experimental
223
+ command: ./scripts/circleci/run_devtools_e2e_tests.js
224
+
225
yarn_lint_build:
226
docker: *docker
227
environment: *environment
@@ -452,6 +474,9 @@ workflows:
474
- build_devtools_and_process_artifacts:
475
requires:
476
- yarn_build_combined
477
+ - run_devtools_e2e_tests:
478
+ requires:
479
+ - build_devtools_and_process_artifacts
480
481
fuzz_tests:
482
unless: << pipeline.parameters.prerelease_commit_sha >>
scripts/circleci/run_devtools_e2e_tests.js
new
+165
@@ -0,0 +1,165 @@
1
+#!/usr/bin/env node
2
+
3
+'use strict';
4
+
5
+const {spawn} = require('child_process');
6
+const {join} = require('path');
7
+
8
+const ROOT_PATH = join(__dirname, '..', '..');
9
+
10
+const inlinePackagePath = join(ROOT_PATH, 'packages', 'react-devtools-inline');
11
+const shellPackagePath = join(ROOT_PATH, 'packages', 'react-devtools-shell');
12
+
13
+let buildProcess = null;
14
+let serverProcess = null;
15
+let testProcess = null;
16
+
17
+function format(loggable) {
18
+ return `${loggable}`
19
+ .split('\n')
20
+ .filter(line => {
21
+ return line.trim() !== '';
22
+ })
23
+ .map(line => ` ${line}`)
24
+ .join('\n');
25
+}
26
+
27
+function logBright(loggable) {
28
+ console.log(`\x1b[1m${loggable}\x1b[0m`);
29
+}
30
+
31
+function logDim(loggable) {
32
+ const formatted = format(loggable, 2);
33
+ if (formatted !== '') {
34
+ console.log(`\x1b[2m${formatted}\x1b[0m`);
35
+ }
36
+}
37
+
38
+function logError(loggable) {
39
+ const formatted = format(loggable, 2);
40
+ if (formatted !== '') {
41
+ console.error(`\x1b[31m${formatted}\x1b[0m`);
42
+ }
43
+}
44
+
45
+function buildInlinePackage() {
46
+ logBright('Building inline packages');
47
+
48
+ buildProcess = spawn('yarn', ['build'], {cwd: inlinePackagePath});
49
+ buildProcess.stdout.on('data', data => {
50
+ logDim(data);
51
+ });
52
+ buildProcess.stderr.on('data', data => {
53
+ if (`${data}`.includes('Warning')) {
54
+ logDim(data);
55
+ } else {
56
+ logError(`Error:\n${data}`);
57
+
58
+ exitWithCode(1);
59
+ }
60
+ });
61
+ buildProcess.on('close', code => {
62
+ logBright('Inline package built');
63
+
64
+ runTestShell();
65
+ });
66
+}
67
+
68
+function runTestShell() {
69
+ const timeoutID = setTimeout(() => {
70
+ // Assume the test shell server failed to start.
71
+ logError('Testing shell server failed to start');
72
+ exitWithCode(1);
73
+ }, 30000);
74
+
75
+ logBright('Starting testing shell server');
76
+
77
+ serverProcess = spawn('yarn', ['start'], {cwd: shellPackagePath});
78
+ serverProcess.stdout.on('data', data => {
79
+ if (`${data}`.includes('Compiled successfully.')) {
80
+ logBright('Testing shell server running');
81
+
82
+ clearTimeout(timeoutID);
83
+
84
+ runEndToEndTests();
85
+ }
86
+ });
87
+ serverProcess.stderr.on('data', data => {
88
+ if (`${data}`.includes('EADDRINUSE')) {
89
+ // Something is occuprying this port;
90
+ // We could kill the process and restart but probably better to prompt the user to do this.
91
+
92
+ logError('Free up the port and re-run tests:');
93
+ logBright(' kill -9 $(lsof -ti:8080)');
94
+
95
+ exitWithCode(1);
96
+ } else if (`${data}`.includes('ERROR')) {
97
+ logError(`Error:\n${data}`);
98
+
99
+ exitWithCode(1);
100
+ } else {
101
+ // Non-fatal stuff like Babel optimization warnings etc.
102
+ logDim(data);
103
+ }
104
+ });
105
+}
106
+
107
+async function runEndToEndTests() {
108
+ logBright('Running e2e tests');
109
+
110
+ testProcess = spawn('yarn', ['test:e2e'], {cwd: inlinePackagePath});
111
+ testProcess.stdout.on('data', data => {
112
+ // Log without formatting because Playwright applies its own formatting.
113
+ const formatted = format(data);
114
+ if (formatted !== '') {
115
+ console.log(formatted);
116
+ }
117
+ });
118
+ testProcess.stderr.on('data', data => {
119
+ // Log without formatting because Playwright applies its own formatting.
120
+ const formatted = format(data);
121
+ if (formatted !== '') {
122
+ console.error(formatted);
123
+ }
124
+
125
+ exitWithCode(1);
126
+ });
127
+ testProcess.on('close', code => {
128
+ logBright(`Tests completed with code: ${code}`);
129
+
130
+ exitWithCode(code);
131
+ });
132
+}
133
+
134
+function exitWithCode(code) {
135
+ if (buildProcess !== null) {
136
+ try {
137
+ logBright('Shutting down build process');
138
+ buildProcess.kill();
139
+ } catch (error) {
140
+ logError(error);
141
+ }
142
+ }
143
+
144
+ if (serverProcess !== null) {
145
+ try {
146
+ logBright('Shutting down shell server process');
147
+ serverProcess.kill();
148
+ } catch (error) {
149
+ logError(error);
150
+ }
151
+ }
152
+
153
+ if (testProcess !== null) {
154
+ try {
155
+ logBright('Shutting down test process');
156
+ testProcess.kill();
157
+ } catch (error) {
158
+ logError(error);
159
+ }
160
+ }
161
+
162
+ process.exit(code);
163
+}
164
+
165
+buildInlinePackage();