Show Flow errors in `yarn test` (as a Jest reporter) (#6617)

This commit is contained in:
Kumar McMillan 2018-10-15 15:02:23 -05:00 коммит произвёл GitHub
Родитель 2486ad79f8
Коммит c2c0fcafae
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
4 изменённых файлов: 133 добавлений и 3 удалений

Просмотреть файл

@ -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;