@samitouri / QOS-React-2 / commits / 9724e18004

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();