Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
23629ec
elm-test.js: Organize `require`s
lydell Oct 29, 2020
6f1612f
elm-test.js: Remove dead code
lydell Oct 29, 2020
c13377b
elm-test.js: Remove unnecessary uncaughtException handler
lydell Oct 29, 2020
e4cdcd5
elm-test.js: Replace `var` with `let` and `const`
lydell Oct 29, 2020
e3bd626
elm-test.js: Use arrow functions
lydell Oct 29, 2020
ba9d21d
elm-test.js: Remove unused CLI flag
lydell Oct 29, 2020
5419e73
elm-test.js: WIP Parse CLI arguments in a more structured way
lydell Oct 29, 2020
6572e92
Remove undocumented and rather useless --verbose option
lydell Oct 29, 2020
469482e
Hide compiler Success print
lydell Oct 29, 2020
c7cb303
Fix option parsing
lydell Oct 29, 2020
10e60b7
Parse --flag=value
lydell Oct 30, 2020
937827b
Tests
lydell Oct 30, 2020
d735086
Add some type annotations
lydell Oct 30, 2020
3dd8c8a
Remove unnecessary globifyWithRoot function
lydell Oct 30, 2020
62081dc
Type Report
lydell Oct 30, 2020
9ae34c7
Use type for Report everyhere
lydell Oct 30, 2020
8e83f1f
Don’t require elm to exist in PATH to be able to show help
lydell Oct 30, 2020
b30f848
Improve help text
lydell Oct 30, 2020
53e68a1
Improve error messages
lydell Oct 30, 2020
7bd27a7
Convert to async/await where it improves readability
lydell Oct 30, 2020
d56ef96
Reorder functions slightly for better readability
lydell Oct 30, 2020
8b56a06
Various cleanups
lydell Oct 30, 2020
df6d286
Better description for --compiler
lydell Oct 30, 2020
322b832
Show defaults for all options
lydell Oct 30, 2020
d3c3ade
Fix accidentally flipped condition
lydell Oct 31, 2020
dda50af
Better data field for Error
lydell Oct 31, 2020
ab65696
Move flags parsing to its own file
lydell Oct 31, 2020
1c45531
Reorder and better parameter name
lydell Nov 1, 2020
02aa8c2
Exhaustive check switch:es in elm-test.js
lydell Nov 1, 2020
263f671
Add some more type annotations
lydell Nov 1, 2020
bc3599a
Test negative integers
lydell Nov 1, 2020
9199b63
Comment Prettier/Flow shenanigans
lydell Nov 1, 2020
77110d0
Remove defunct Node.js version check
lydell Nov 1, 2020
814e814
Disallow `--watch=some-value`
lydell Nov 1, 2020
934e029
Use commander instead of custom parsing
lydell Nov 4, 2020
d96a08f
Remove dead code
lydell Nov 4, 2020
b18458e
Consistent error message
lydell Nov 7, 2020
446ff1a
Apply suggestions from code review
lydell Nov 9, 2020
1d2dea5
Post "Apply suggestions from code review" fixes
lydell Nov 9, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
elm-stuff
fixtures
templates
flow-typed
14 changes: 3 additions & 11 deletions elm/src/Test/Runner/Node.elm
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ type alias InitArgs =

type alias RunnerOptions =
{ seed : Int
, runs : Maybe Int
, runs : Int
, report : Report
, globs : List String
, paths : List String
Expand Down Expand Up @@ -385,19 +385,16 @@ run { runs, seed, report, globs, paths, processes } possiblyTests =

else
let
fuzzRuns =
Maybe.withDefault defaultRunCount runs

runners =
Test.Runner.fromTest fuzzRuns (Random.initialSeed seed) (Test.concat tests)
Test.Runner.fromTest runs (Random.initialSeed seed) (Test.concat tests)

wrappedInit =
init
{ initialSeed = seed
, processes = processes
, globs = globs
, paths = paths
, fuzzRuns = fuzzRuns
, fuzzRuns = runs
, runners = runners
, report = report
}
Expand Down Expand Up @@ -437,9 +434,4 @@ If there are – are they exposed?
|> String.replace "%globs" (String.join "\n" globs)


defaultRunCount : Int
defaultRunCount =
100


port receive : (Decode.Value -> msg) -> Sub msg
18 changes: 18 additions & 0 deletions flow-typed/Result.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// @flow

// We can’t use /*:: type Result<Error, Value> = ... */ because of:
// https://github.com/prettier/prettier/issues/2597
//
// Because of the type arguments we can’t use the regular trick of making a type
// annotation instead and then use `typeof Result`. The workaround is to define
// `Result` globally – this file is not included during runtime.
//
// This also lets us use `Result` in several files without having to define it
// multiple times or figure out some way to import types.
//
// If you wonder why we use a weird mix of “real” syntax and comment syntax here
// – it’s because of Prettier again. If you “uncomment” the `<Error, Value>`
// part, Prettier adds `/*::` and `*/` back.
type Result/*:: <Error, Value> */ =
| { tag: 'Ok', value: Value }
| { tag: 'Error', error: Error };
34 changes: 13 additions & 21 deletions lib/Compile.js
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
//@flow

const path = require('path'),
elmCompiler = require('./ElmCompiler'),
ElmCompiler = require('./ElmCompiler'),
spawn = require('cross-spawn'),
packageInfo = require('../package.json');
packageInfo = require('../package.json'),
Report = require('./Report');

function compile(
testFile /*: string */,
dest /*: string */,
verbose /*: boolean */,
pathToElmBinary /*: string */,
report /*: string */
report /*: typeof Report.Report */
) /*: Promise<void> */ {
return new Promise((resolve, reject) => {
const compileProcess = elmCompiler.compile([testFile], {
const compileProcess = ElmCompiler.compile([testFile], {
output: dest,
verbose: verbose,
spawn: spawnCompiler(report),
spawn: spawnCompiler({ ignoreStdout: true }),
pathToElm: pathToElmBinary,
processOpts: processOptsForReporter(report),
});
Expand Down Expand Up @@ -49,18 +48,16 @@ function getTestRootDir(projectRootDir /*: string */) /*: string */ {
function compileSources(
testFilePaths /*: Array<string> */,
projectRootDir /*: string */,
verbose /*: boolean */,
pathToElmBinary /*: string */,
report /*: string */
report /*: typeof Report.Report */
) /*: Promise<void> */ {
return new Promise((resolve, reject) => {
const compilerReport = report === 'json' ? report : undefined;

const compileProcess = elmCompiler.compile(testFilePaths, {
const compileProcess = ElmCompiler.compile(testFilePaths, {
output: '/dev/null',
cwd: projectRootDir,
verbose: verbose,
spawn: spawnCompiler(report),
spawn: spawnCompiler({ ignoreStdout: false }),
pathToElm: pathToElmBinary,
report: compilerReport,
processOpts: processOptsForReporter(report),
Expand All @@ -76,7 +73,7 @@ function compileSources(
});
}

function spawnCompiler(report /*: string */) {
function spawnCompiler({ ignoreStdout }) {
return (
pathToElm /*: string */,
processArgs /*: Array<string> */,
Expand All @@ -85,7 +82,7 @@ function spawnCompiler(report /*: string */) {
const finalOpts = Object.assign({ env: process.env }, processOpts, {
stdio: [
process.stdin,
report === 'console' ? process.stdout : 'ignore',
ignoreStdout ? 'ignore' : process.stdout,
process.stderr,
],
});
Expand All @@ -94,22 +91,17 @@ function spawnCompiler(report /*: string */) {
};
}

function processOptsForReporter(reporter) {
if (isMachineReadableReporter(reporter)) {
function processOptsForReporter(report /*: typeof Report.Report */) {
if (Report.isMachineReadable(report)) {
return { env: process.env, stdio: ['ignore', 'ignore', process.stderr] };
} else {
return { env: process.env };
}
}

function isMachineReadableReporter(reporter /*: string */) /*: boolean */ {
return reporter === 'json' || reporter === 'junit';
}

module.exports = {
compile,
compileSources,
getTestRootDir,
getGeneratedCodeDir,
isMachineReadableReporter,
};
6 changes: 0 additions & 6 deletions lib/ElmCompiler.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ var defaultOptions = {
pathToElm: 'elm',
output: undefined,
report: undefined,
verbose: false,
processOpts: undefined,
};

Expand Down Expand Up @@ -44,10 +43,6 @@ function runCompiler(sources, options) {
options.processOpts
);

if (options.verbose) {
console.log(['Running', pathToElm].concat(processArgs).join(' '));
}

return options.spawn(pathToElm, processArgs, processOpts);
}

Expand Down Expand Up @@ -93,7 +88,6 @@ function compile(
pathToElm?: string,
output?: string,
report?: 'json',
verbose?: boolean,
processOpts?: child_process$spawnOpts,
|} */
) /*: child_process$ChildProcess */ {
Expand Down
22 changes: 11 additions & 11 deletions lib/Generate.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,11 @@ const path = require('path'),
Murmur = require('murmur-hash-js'),
Solve = require('./Solve.js'),
Compile = require('./Compile.js'),
Report = require('./Report.js'),
supportsColor = require('chalk').supportsColor;

void Report;

function prepareCompiledJsFile(
pipeFilename /*: string */,
dest /*: string */
Expand Down Expand Up @@ -195,7 +198,7 @@ function generateElmJson(
function generateMainModule(
fuzz /*: number */,
seed /*: number */,
report /*: string */,
report /*: typeof Report.Report */,
testFileGlobs /*: Array<string> */,
testFilePaths /*: Array<string> */,
testModules /*: Array<{
Expand Down Expand Up @@ -305,20 +308,15 @@ function indentAllButFirstLine(indent, string) {
function makeOptsCode(
fuzz /*: number */,
seed /*: number */,
report /*: string */,
report /*: typeof Report.Report */,
testFileGlobs /*: Array<string> */,
testFilePaths /*: Array<string> */,
processes /*: number */
) /*: string */ {
// TODO: CLI args should be parsed, validated and defaulted properly in elm-test.js.
const finalSeed = isNaN(seed)
? Math.floor(Math.random() * 407199254740991) + 1000
: seed;

return `
{ runs = ${isNaN(fuzz) ? 'Nothing' : `Just ${fuzz}`}
{ runs = ${fuzz}
, report = ${generateElmReportVariant(report)}
, seed = ${finalSeed}
, seed = ${seed}
, processes = ${processes}
, globs =
${indentAllButFirstLine(' ', makeList(testFileGlobs.map(makeElmString)))}
Expand All @@ -328,13 +326,15 @@ function makeOptsCode(
`.trim();
}

function generateElmReportVariant(report) {
function generateElmReportVariant(
report /*: typeof Report.Report */
) /*: string */ {
switch (report) {
case 'json':
return 'JsonReport';
case 'junit':
return 'JUnitReport';
default:
case 'console':
if (supportsColor) {
return 'ConsoleReport UseColor';
} else {
Expand Down
35 changes: 35 additions & 0 deletions lib/Report.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// @flow

// Poor man’s type alias. We can’t use /*:: type Report = ... */ because of:
// https://github.com/prettier/prettier/issues/2597
const Report /*: 'console' | 'json' | 'junit' */ = 'console';

function parse(string /*: string */) /*: Result<string, typeof Report> */ {
switch (string) {
case 'console':
case 'json':
case 'junit':
return { tag: 'Ok', value: string };
default:
return {
tag: 'Error',
error: `unknown reporter: ${string}`,
};
}
}

function isMachineReadable(report /*: typeof Report */) /*: boolean */ {
switch (report) {
case 'json':
case 'junit':
return true;
case 'console':
return false;
}
}

module.exports = {
Report,
parse,
isMachineReadable,
};
52 changes: 30 additions & 22 deletions lib/Supervisor.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@ var chalk = require('chalk'),
fs = require('fs-extra'),
net = require('net'),
child_process = require('child_process'),
split = require('split');
split = require('split'),
// $FlowFixMe: Flow marks this line as an error (and only in this file!) but then it knows the types of `Report` anyway. This is the “error”: Cannot build a typed interface for this module. You should annotate the exports of this module with types. Missing type annotation at declaration of variable `Report`: [signature-verification-failure]
Report = require('./Report');

function run(
elmTestVersion /*: string */,
pipeFilename /*: string */,
format /*: string */,
report /*: typeof Report.Report */,
processes /*: number */,
dest /*: string */,
watch /*: boolean */,
isMachineReadable /*: boolean */
watch /*: boolean */
) /*: Promise<void> */ {
return new Promise(function (resolve) {
var nextResultToPrint = null;
Expand All @@ -29,22 +30,29 @@ function run(
var workers = [];

function printResult(result, exitCode /*: number | void */ = undefined) {
if (format === 'console') {
// todos are objects, and will be shown in the SUMMARY only.
// passed tests are nulls, and should not be printed.
// failed tests are strings.
if (typeof result === 'string') {
const message = makeWindowsSafe(result);
if (exitCode === 1) {
console.error(message);
} else {
console.log(message);
switch (report) {
case 'console':
// todos are objects, and will be shown in the SUMMARY only.
// passed tests are nulls, and should not be printed.
// failed tests are strings.
if (typeof result === 'string') {
const message = makeWindowsSafe(result);
if (exitCode === 1) {
console.error(message);
} else {
console.log(message);
}
}
}
} else if (format === 'json') {
console.log(JSON.stringify(result));
break;

case 'json':
console.log(JSON.stringify(result));
break;

case 'junit':
// JUnit does everything at once in SUMMARY, elsewhere
break;
}
// JUnit does everything at once in SUMMARY, elsewhere
}

function flushResults() {
Expand Down Expand Up @@ -87,7 +95,7 @@ function run(
var result = response.results[index];
results.set(parseInt(index), result);

switch (format) {
switch (report) {
case 'console':
if (result === null) {
// It's a PASS; no need to take any action.
Expand Down Expand Up @@ -156,7 +164,7 @@ function run(

printResult(response.message, response.exitCode);

if (format === 'junit') {
if (report === 'junit') {
var xml = response.message;
var values = Array.from(results.values());

Expand All @@ -178,7 +186,7 @@ function run(
case 'BEGIN':
testsToRun = response.testCount;

if (!isMachineReadable) {
if (!Report.isMachineReadable(report)) {
var headline = 'elm-test ' + elmTestVersion;
var bar = '-'.repeat(headline.length);

Expand Down Expand Up @@ -227,7 +235,7 @@ function run(
// code can be null.
var hasNonZeroExitCode = typeof code === 'number' && code !== 0;

if (watch && !isMachineReadable) {
if (watch && !Report.isMachineReadable(report)) {
if (hasNonZeroExitCode) {
// Queue up complaining about an exception.
// Don't print it immediately, or else it might print N times
Expand Down
Loading