Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Circle CI: Run DevTools Playwright e2e tests #23019

Merged
merged 1 commit into from Jan 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
25 changes: 25 additions & 0 deletions .circleci/config.yml
Expand Up @@ -200,6 +200,28 @@ jobs:
- store_artifacts:
path: ./build/devtools.tgz

run_devtools_e2e_tests:
docker: *docker
environment: *environment
steps:
- checkout
- attach_workspace:
at: .
- run: yarn workspaces info | head -n -1 > workspace_info.txt
- *restore_node_modules
- run:
name: Install Packages
command: yarn --frozen-lockfile --cache-folder ~/.cache/yarn
- run:
name: Playwright install deps
command: |
npx playwright install
sudo npx playwright install-deps
- run:
environment:
RELEASE_CHANNEL: experimental
command: ./scripts/circleci/run_devtools_e2e_tests.js

yarn_lint_build:
docker: *docker
environment: *environment
Expand Down Expand Up @@ -452,6 +474,9 @@ workflows:
- build_devtools_and_process_artifacts:
requires:
- yarn_build_combined
- run_devtools_e2e_tests:
requires:
- build_devtools_and_process_artifacts

fuzz_tests:
unless: << pipeline.parameters.prerelease_commit_sha >>
Expand Down
165 changes: 165 additions & 0 deletions scripts/circleci/run_devtools_e2e_tests.js
@@ -0,0 +1,165 @@
#!/usr/bin/env node

'use strict';

const {spawn} = require('child_process');
const {join} = require('path');

const ROOT_PATH = join(__dirname, '..', '..');

const inlinePackagePath = join(ROOT_PATH, 'packages', 'react-devtools-inline');
const shellPackagePath = join(ROOT_PATH, 'packages', 'react-devtools-shell');

let buildProcess = null;
let serverProcess = null;
let testProcess = null;

function format(loggable) {
return `${loggable}`
.split('\n')
.filter(line => {
return line.trim() !== '';
})
.map(line => ` ${line}`)
.join('\n');
}

function logBright(loggable) {
console.log(`\x1b[1m${loggable}\x1b[0m`);
}

function logDim(loggable) {
const formatted = format(loggable, 2);
if (formatted !== '') {
console.log(`\x1b[2m${formatted}\x1b[0m`);
}
}

function logError(loggable) {
const formatted = format(loggable, 2);
if (formatted !== '') {
console.error(`\x1b[31m${formatted}\x1b[0m`);
}
}

function buildInlinePackage() {
logBright('Building inline packages');

buildProcess = spawn('yarn', ['build'], {cwd: inlinePackagePath});
buildProcess.stdout.on('data', data => {
logDim(data);
});
buildProcess.stderr.on('data', data => {
if (`${data}`.includes('Warning')) {
logDim(data);
} else {
logError(`Error:\n${data}`);

exitWithCode(1);
}
});
buildProcess.on('close', code => {
logBright('Inline package built');

runTestShell();
});
}

function runTestShell() {
const timeoutID = setTimeout(() => {
// Assume the test shell server failed to start.
logError('Testing shell server failed to start');
exitWithCode(1);
}, 30000);

logBright('Starting testing shell server');

serverProcess = spawn('yarn', ['start'], {cwd: shellPackagePath});
serverProcess.stdout.on('data', data => {
if (`${data}`.includes('Compiled successfully.')) {
logBright('Testing shell server running');

clearTimeout(timeoutID);

runEndToEndTests();
}
});
serverProcess.stderr.on('data', data => {
if (`${data}`.includes('EADDRINUSE')) {
// Something is occuprying this port;
// We could kill the process and restart but probably better to prompt the user to do this.

logError('Free up the port and re-run tests:');
logBright(' kill -9 $(lsof -ti:8080)');

exitWithCode(1);
} else if (`${data}`.includes('ERROR')) {
logError(`Error:\n${data}`);

exitWithCode(1);
} else {
// Non-fatal stuff like Babel optimization warnings etc.
logDim(data);
}
});
}

async function runEndToEndTests() {
logBright('Running e2e tests');

testProcess = spawn('yarn', ['test:e2e'], {cwd: inlinePackagePath});
testProcess.stdout.on('data', data => {
// Log without formatting because Playwright applies its own formatting.
const formatted = format(data);
if (formatted !== '') {
console.log(formatted);
}
});
testProcess.stderr.on('data', data => {
// Log without formatting because Playwright applies its own formatting.
const formatted = format(data);
if (formatted !== '') {
console.error(formatted);
}

exitWithCode(1);
});
testProcess.on('close', code => {
logBright(`Tests completed with code: ${code}`);

exitWithCode(code);
});
}

function exitWithCode(code) {
if (buildProcess !== null) {
try {
logBright('Shutting down build process');
buildProcess.kill();
} catch (error) {
logError(error);
}
}

if (serverProcess !== null) {
try {
logBright('Shutting down shell server process');
serverProcess.kill();
} catch (error) {
logError(error);
}
}

if (testProcess !== null) {
try {
logBright('Shutting down test process');
testProcess.kill();
} catch (error) {
logError(error);
}
}

process.exit(code);
}

buildInlinePackage();