main
js 200 lines 4.71 KB
Raw
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 const reactVersion = process.argv[2];
10 const inlinePackagePath = join(ROOT_PATH, 'packages', 'react-devtools-inline');
11 const shellPackagePath = join(ROOT_PATH, 'packages', 'react-devtools-shell');
12 const playwrightArtifactsPath = join(ROOT_PATH, 'tmp', 'playwright-artifacts');
13
14 const {SUCCESSFUL_COMPILATION_MESSAGE} = require(
15 join(shellPackagePath, 'constants.js')
16 );
17
18 let buildProcess = null;
19 let serverProcess = null;
20 let testProcess = null;
21
22 function format(loggable) {
23 return `${loggable}`
24 .split('\n')
25 .filter(line => {
26 return line.trim() !== '';
27 })
28 .map(line => ` ${line}`)
29 .join('\n');
30 }
31
32 function logBright(loggable) {
33 console.log(`\x1b[1m${loggable}\x1b[0m`);
34 }
35
36 function logDim(loggable) {
37 const formatted = format(loggable, 2);
38 if (formatted !== '') {
39 console.log(`\x1b[2m${formatted}\x1b[0m`);
40 }
41 }
42
43 function logError(loggable) {
44 const formatted = format(loggable, 2);
45 if (formatted !== '') {
46 console.error(`\x1b[31m${formatted}\x1b[0m`);
47 }
48 }
49
50 function buildInlinePackage() {
51 logBright('Building inline packages');
52
53 buildProcess = spawn('yarn', ['build'], {cwd: inlinePackagePath});
54 buildProcess.stdout.on('data', data => {
55 logDim(data);
56 });
57 buildProcess.stderr.on('data', data => {
58 if (
59 `${data}`.includes('Warning') ||
60 // E.g. [BABEL] Note: The code generator has deoptimised the styling of * as it exceeds the max of 500KB.
61 `${data}`.includes('[BABEL] Note')
62 ) {
63 logDim(data);
64 } else {
65 logError(`Error:\n${data}`);
66
67 exitWithCode(1);
68 }
69 });
70 buildProcess.on('close', code => {
71 logBright('Inline package built');
72
73 runTestShell();
74 });
75 }
76
77 function runTestShell() {
78 const timeoutID = setTimeout(() => {
79 // Assume the test shell server failed to start.
80 logError('Testing shell server failed to start');
81 exitWithCode(1);
82 }, 60 * 1000);
83
84 logBright('Starting testing shell server');
85
86 if (!reactVersion) {
87 serverProcess = spawn('yarn', ['start'], {cwd: shellPackagePath});
88 } else {
89 serverProcess = spawn('yarn', ['start'], {
90 cwd: shellPackagePath,
91 env: {...process.env, REACT_VERSION: reactVersion},
92 });
93 }
94
95 serverProcess.stdout.on('data', data => {
96 if (`${data}`.includes(SUCCESSFUL_COMPILATION_MESSAGE)) {
97 logBright('Testing shell server running');
98
99 clearTimeout(timeoutID);
100
101 runEndToEndTests();
102 }
103 });
104
105 serverProcess.stderr.on('data', data => {
106 if (`${data}`.includes('EADDRINUSE')) {
107 // Something is occupying this port;
108 // We could kill the process and restart but probably better to prompt the user to do this.
109
110 logError('Free up the port and re-run tests:');
111 logBright(' kill -9 $(lsof -ti:8080)');
112
113 exitWithCode(1);
114 } else if (`${data}`.includes('ERROR')) {
115 logError(`Error:\n${data}`);
116
117 exitWithCode(1);
118 } else {
119 // Non-fatal stuff like Babel optimization warnings etc.
120 logDim(data);
121 }
122 });
123 }
124
125 async function runEndToEndTests() {
126 logBright('Running e2e tests');
127 if (!reactVersion) {
128 testProcess = spawn(
129 'yarn',
130 ['test:e2e', `--output=${playwrightArtifactsPath}`],
131 {
132 cwd: inlinePackagePath,
133 }
134 );
135 } else {
136 testProcess = spawn(
137 'yarn',
138 ['test:e2e', `--output=${playwrightArtifactsPath}`],
139 {
140 cwd: inlinePackagePath,
141 env: {...process.env, REACT_VERSION: reactVersion},
142 }
143 );
144 }
145
146 testProcess.stdout.on('data', data => {
147 // Log without formatting because Playwright applies its own formatting.
148 const formatted = format(data);
149 if (formatted !== '') {
150 console.log(formatted);
151 }
152 });
153 testProcess.stderr.on('data', data => {
154 // Log without formatting because Playwright applies its own formatting.
155 const formatted = format(data);
156 if (formatted !== '') {
157 console.error(formatted);
158 }
159
160 exitWithCode(1);
161 });
162 testProcess.on('close', code => {
163 logBright(`Tests completed with code: ${code}`);
164
165 exitWithCode(code);
166 });
167 }
168
169 function exitWithCode(code) {
170 if (buildProcess !== null) {
171 try {
172 logBright('Shutting down build process');
173 buildProcess.kill();
174 } catch (error) {
175 logError(error);
176 }
177 }
178
179 if (serverProcess !== null) {
180 try {
181 logBright('Shutting down shell server process');
182 serverProcess.kill();
183 } catch (error) {
184 logError(error);
185 }
186 }
187
188 if (testProcess !== null) {
189 try {
190 logBright('Shutting down test process');
191 testProcess.kill();
192 } catch (error) {
193 logError(error);
194 }
195 }
196
197 process.exit(code);
198 }
199
200 buildInlinePackage();