mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[sprout] QoL: use cli args, report pretty results
--- - Added sprout to Github Actions by updating `yarn test` command - Added cli args (`filter` and `sync`) - use chalk to make results nicer ✨ Tested locally: <img width="900" alt="Screenshot 2023-08-14 at 6 04 28 PM" src="https://github.com/facebook/react-forget/assets/34200447/b5481bbc-6a50-40c6-a85f-d2443130dd2a">
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rimraf dist && tsc",
|
||||
"test": "yarn jest && yarn snap:build && yarn snap",
|
||||
"test": "yarn jest && yarn snap:build && yarn snap && yarn sprout:build && yarn sprout",
|
||||
"jest": "tsc && ts-node \"$(yarn --silent which jest)\"",
|
||||
"snap": "node ../snap/dist/main.js",
|
||||
"sprout": "node ../sprout/dist/main.js",
|
||||
|
||||
@@ -6,8 +6,8 @@ Currently, Sprout runs each fixture with a known set of inputs and annotations.
|
||||
Sprout is currently WIP and only executes files listed in `src/SproutOnlyFilterTodoRemove.ts`.
|
||||
|
||||
### Milestones:
|
||||
- [✅] Render fixtures with React runtime / `testing-library/react`.
|
||||
- [ ] Make Sprout CLI -runnable and report results in process exit code.
|
||||
- [x] Render fixtures with React runtime / `testing-library/react`.
|
||||
- [x] Make Sprout CLI -runnable and report results in process exit code.
|
||||
After this point:
|
||||
- Sprout can be enabled by default and added to the Github Actions pipeline.
|
||||
- `SproutOnlyFilterTodoRemove` can be renamed to `SproutSkipFilter`.
|
||||
|
||||
@@ -5,13 +5,17 @@
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
import chalk from "chalk";
|
||||
import { TestFixture } from "fixture-test-utils";
|
||||
import { getFixtures, readTestFilter } from "fixture-test-utils";
|
||||
import { Worker } from "jest-worker";
|
||||
import process from "process";
|
||||
import * as readline from "readline";
|
||||
import * as RunnerWorker from "./runner-worker";
|
||||
import yargs from "yargs";
|
||||
import { hideBin } from "yargs/helpers";
|
||||
import SproutOnlyFilterTodoRemove from "./SproutOnlyFilterTodoRemove";
|
||||
import { FILTER_FILENAME } from "fixture-test-utils";
|
||||
|
||||
const WORKER_PATH = require.resolve("./runner-worker");
|
||||
readline.emitKeypressEvents(process.stdin);
|
||||
@@ -31,11 +35,27 @@ process.on("SIGTERM", function () {
|
||||
});
|
||||
|
||||
type RunnerOptions = {
|
||||
useFilter: boolean;
|
||||
filter: boolean;
|
||||
sync: boolean;
|
||||
useTodoFilter: boolean;
|
||||
};
|
||||
|
||||
const opts: RunnerOptions = yargs
|
||||
.boolean("sync")
|
||||
.describe(
|
||||
"sync",
|
||||
"Run compiler in main thread (instead of using worker threads or subprocesses). Defaults to false."
|
||||
)
|
||||
.default("sync", false)
|
||||
.boolean("filter")
|
||||
.describe(
|
||||
"filter",
|
||||
`Evaluate fixtures in filter mode ("${FILTER_FILENAME}")\n`
|
||||
)
|
||||
.default("filter", false)
|
||||
.help("help")
|
||||
.strict()
|
||||
.parseSync(hideBin(process.argv));
|
||||
|
||||
function logsEqual(a: Array<string>, b: Array<string>) {
|
||||
if (a.length !== b.length) {
|
||||
return false;
|
||||
@@ -43,33 +63,93 @@ function logsEqual(a: Array<string>, b: Array<string>) {
|
||||
return a.every((val, idx) => val === b[idx]);
|
||||
}
|
||||
|
||||
function reportResults(results: Array<[string, RunnerWorker.TestResult]>) {
|
||||
function reportResults(
|
||||
results: Array<[string, RunnerWorker.TestResult]>
|
||||
): boolean {
|
||||
const failures: Array<[string, RunnerWorker.TestResult]> = [];
|
||||
|
||||
for (const [fixtureName, result] of results) {
|
||||
if (result.unexpectedError !== null) {
|
||||
console.log(`ERROR ${fixtureName}: ${result.unexpectedError}`);
|
||||
console.log(
|
||||
chalk.red.inverse.bold(" FAIL ") + " " + chalk.dim(fixtureName)
|
||||
);
|
||||
failures.push([fixtureName, result]);
|
||||
continue;
|
||||
}
|
||||
const { forgetResult, nonForgetResult } = result;
|
||||
if (forgetResult.kind === "UnexpectedError") {
|
||||
console.log(`ERROR ${fixtureName}: ${forgetResult.value}`);
|
||||
} else if (nonForgetResult.kind === "UnexpectedError") {
|
||||
console.log(`ERROR ${fixtureName}: ${nonForgetResult.value}`);
|
||||
} else if (
|
||||
if (
|
||||
forgetResult.kind === "UnexpectedError" ||
|
||||
nonForgetResult.kind === "UnexpectedError" ||
|
||||
forgetResult.kind !== nonForgetResult.kind ||
|
||||
forgetResult.value !== nonForgetResult.value ||
|
||||
!logsEqual(forgetResult.logs, nonForgetResult.logs)
|
||||
) {
|
||||
console.log(
|
||||
`FAIL ${fixtureName}: Difference in forget and non-forget results. \nExpected result: ${JSON.stringify(
|
||||
forgetResult,
|
||||
undefined,
|
||||
2
|
||||
)}\nFound: ${JSON.stringify(nonForgetResult, undefined, 2)}`
|
||||
chalk.red.inverse.bold(" FAIL ") + " " + chalk.dim(fixtureName)
|
||||
);
|
||||
failures.push([fixtureName, result]);
|
||||
} else {
|
||||
console.log(`PASS ${fixtureName}`);
|
||||
console.log(
|
||||
chalk.green.inverse.bold(" PASS ") + " " + chalk.dim(fixtureName)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if (failures.length !== 0) {
|
||||
console.log("\n" + chalk.red.bold("Failures:") + "\n");
|
||||
|
||||
for (const [fixtureName, result] of failures) {
|
||||
console.log(chalk.red.bold("FAIL:") + " " + fixtureName);
|
||||
|
||||
if (result.unexpectedError !== null) {
|
||||
console.log(
|
||||
chalk.red("Unexpected error when building fixture:") +
|
||||
` ${result.unexpectedError}`
|
||||
);
|
||||
continue;
|
||||
}
|
||||
const { forgetResult, nonForgetResult } = result;
|
||||
if (forgetResult.kind === "UnexpectedError") {
|
||||
console.log(
|
||||
chalk.red(
|
||||
"Unexpected error when evaluating Forget-transformed fixture:"
|
||||
) + ` ${forgetResult.value}`
|
||||
);
|
||||
}
|
||||
if (nonForgetResult.kind === "UnexpectedError") {
|
||||
console.log(
|
||||
chalk.red("Unexpected error when evaluating original fixture:") +
|
||||
` ${nonForgetResult.value}`
|
||||
);
|
||||
}
|
||||
const hasUnexpectedError =
|
||||
forgetResult.kind === "UnexpectedError" ||
|
||||
nonForgetResult.kind === "UnexpectedError";
|
||||
if (
|
||||
!hasUnexpectedError &&
|
||||
(forgetResult.kind !== nonForgetResult.kind ||
|
||||
forgetResult.value !== nonForgetResult.value ||
|
||||
!logsEqual(forgetResult.logs, nonForgetResult.logs))
|
||||
) {
|
||||
console.log(
|
||||
chalk.red("Difference in forget and non-forget results.") +
|
||||
`\nExpected result: ${JSON.stringify(
|
||||
forgetResult,
|
||||
undefined,
|
||||
2
|
||||
)}\nFound: ${JSON.stringify(nonForgetResult, undefined, 2)}`
|
||||
);
|
||||
failures.push([fixtureName, result]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
console.log(
|
||||
`${results.length} Tests, ${results.length - failures.length} Passed, ${
|
||||
failures.length
|
||||
} Failed`
|
||||
);
|
||||
return failures.length === 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -82,16 +162,14 @@ export async function main(opts: RunnerOptions): Promise<void> {
|
||||
worker.getStderr().pipe(process.stderr);
|
||||
worker.getStdout().pipe(process.stdout);
|
||||
|
||||
const testFilter = opts.useFilter ? await readTestFilter() : null;
|
||||
const testFilter = opts.filter ? await readTestFilter() : null;
|
||||
let allFixtures: Map<string, TestFixture> = getFixtures(testFilter);
|
||||
|
||||
if (opts.useTodoFilter) {
|
||||
allFixtures = new Map(
|
||||
Array.from(allFixtures.entries()).filter(([filename, _]) =>
|
||||
SproutOnlyFilterTodoRemove.has(filename)
|
||||
)
|
||||
);
|
||||
}
|
||||
allFixtures = new Map(
|
||||
Array.from(allFixtures.entries()).filter(([filename, _]) =>
|
||||
SproutOnlyFilterTodoRemove.has(filename)
|
||||
)
|
||||
);
|
||||
|
||||
const validFixtures = new Map();
|
||||
for (const [name, fixture] of allFixtures) {
|
||||
@@ -118,10 +196,8 @@ export async function main(opts: RunnerOptions): Promise<void> {
|
||||
}
|
||||
}
|
||||
|
||||
reportResults(results);
|
||||
process.exit(0);
|
||||
const isSuccess = reportResults(results);
|
||||
process.exit(isSuccess ? 0 : 1);
|
||||
}
|
||||
|
||||
main({ useFilter: false, sync: true, useTodoFilter: true }).catch((error) =>
|
||||
console.error(error)
|
||||
);
|
||||
main(opts).catch((error) => console.error(error));
|
||||
|
||||
Reference in New Issue
Block a user