Show Flow errors in `yarn test` (as a Jest reporter) (#6617)
This commit is contained in:
Родитель
2486ad79f8
Коммит
c2c0fcafae
12
README.md
12
README.md
|
@ -100,9 +100,17 @@ yarn test-once
|
|||
|
||||
### Flow
|
||||
|
||||
There is limited support for using [Flow](https://flowtype.org/) to check for problems in the source code.
|
||||
There is limited support for using [Flow](https://flowtype.org/) to validate the intention of our program.
|
||||
|
||||
To check for Flow issues during development while you edit files, run:
|
||||
As you run tests you will see a report of Flow errors at the end of the test output:
|
||||
|
||||
yarn test
|
||||
|
||||
If you would like to run tests without Flow checks, set an environment variable:
|
||||
|
||||
NO_FLOW=1 yarn test
|
||||
|
||||
To only check for Flow issues during development while you edit files, run:
|
||||
|
||||
yarn flow:dev
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@ module.exports = {
|
|||
reporters: [
|
||||
'<rootDir>/tests/jest-reporters/fingers-crossed.js',
|
||||
'<rootDir>/tests/jest-reporters/summary.js',
|
||||
'<rootDir>/tests/jest-reporters/flow-check.js',
|
||||
],
|
||||
setupTestFrameworkScriptFile: '<rootDir>/tests/setup.js',
|
||||
testPathIgnorePatterns: [
|
||||
|
|
|
@ -175,7 +175,8 @@
|
|||
"env": {
|
||||
"NODE_ICU_DATA": "./node_modules/full-icu",
|
||||
"NODE_PATH": "./:./src",
|
||||
"NODE_ENV": "test"
|
||||
"NODE_ENV": "test",
|
||||
"NO_FLOW": "1"
|
||||
}
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
/* eslint-disable no-console */
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
const pathToFlowBin = require('flow-bin');
|
||||
|
||||
const NO_FLOW_ENV_VAR = 'NO_FLOW';
|
||||
|
||||
const magicExitCodes = {
|
||||
someFileHadAFlowError: 2,
|
||||
serverAlreadyRunning: 11,
|
||||
};
|
||||
|
||||
function execFlow(commandArgs) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const flow = spawn(pathToFlowBin, commandArgs, {
|
||||
cwd: process.cwd(),
|
||||
});
|
||||
|
||||
const stdout = [];
|
||||
const stderr = [];
|
||||
|
||||
flow.stdout.on('data', (data) => {
|
||||
stdout.push(data);
|
||||
});
|
||||
|
||||
flow.stderr.on('data', (data) => {
|
||||
stderr.push(data);
|
||||
});
|
||||
|
||||
flow.on('error', (error) => {
|
||||
reject(
|
||||
new Error(`Could not execute Flow binary (${pathToFlowBin}): ${error}`),
|
||||
);
|
||||
});
|
||||
|
||||
flow.on('close', (code) => {
|
||||
resolve({ code, stdout: stdout.join(''), stderr: stderr.join('') });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
class FlowCheckReporter {
|
||||
constructor() {
|
||||
this.flowErrorOutput = null;
|
||||
this.displayedSlowStartupMessage = false;
|
||||
}
|
||||
|
||||
isDisabled() {
|
||||
return process.env[NO_FLOW_ENV_VAR] === '1';
|
||||
}
|
||||
|
||||
async onRunStart() {
|
||||
if (this.isDisabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { code, stdout, stderr } = await execFlow(['start']);
|
||||
if (code !== 0 && code !== magicExitCodes.serverAlreadyRunning) {
|
||||
console.error(stdout);
|
||||
console.error(stderr);
|
||||
throw new Error(`'flow start' exited ${code}`);
|
||||
}
|
||||
}
|
||||
|
||||
async onTestStart() {
|
||||
if (this.isDisabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const slowStartUpNotice = setTimeout(() => {
|
||||
if (this.displayedSlowStartupMessage) {
|
||||
return;
|
||||
}
|
||||
console.log('Flow: hold on a sec while the server starts 💅');
|
||||
console.log('');
|
||||
this.displayedSlowStartupMessage = true;
|
||||
}, 800);
|
||||
|
||||
const { code, stdout, stderr } = await execFlow([
|
||||
'status',
|
||||
'--color',
|
||||
'always',
|
||||
]);
|
||||
|
||||
clearTimeout(slowStartUpNotice);
|
||||
|
||||
if (code === 0) {
|
||||
// All good.
|
||||
this.flowErrorOutput = null;
|
||||
} else if (code === magicExitCodes.someFileHadAFlowError) {
|
||||
this.flowErrorOutput = stdout;
|
||||
// We ignore stderr here because it contains messages like
|
||||
// 'Server is handling a request (starting up)'
|
||||
} else {
|
||||
console.error(stdout);
|
||||
console.error(stderr);
|
||||
throw new Error(`'flow status' exited ${code}`);
|
||||
}
|
||||
}
|
||||
|
||||
getLastError() {
|
||||
if (this.isDisabled()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
console.log('');
|
||||
if (this.flowErrorOutput) {
|
||||
console.log(this.flowErrorOutput.trim());
|
||||
console.log(
|
||||
`Set ${NO_FLOW_ENV_VAR}=1 in the environment to disable Flow checks`,
|
||||
);
|
||||
return new Error('Flow errors');
|
||||
}
|
||||
console.log('Flow: no errors 🌈 ✨');
|
||||
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = FlowCheckReporter;
|
Загрузка…
Ссылка в новой задаче