diff --git a/README.md b/README.md index a6bba091..0c0f1007 100644 --- a/README.md +++ b/README.md @@ -171,6 +171,16 @@ Define how many times each fuzz-test should run. Defaults to `100`. > [!NOTE] > 100 iterations is pretty low for most fuzz tests – it might not be enough to find edge cases. It’s recommended to use [fuzzWith](https://package.elm-lang.org/packages/elm-explorations/test/latest/Test#fuzzWith) to choose an appropriate number of runs per fuzz test. When developing, increase the number until you don’t get any failures anymore and the test takes a long time. Then lower the number so the test covers enough and runs fast enough to make those who wait not go insane. +### --workers + +Choose how many workers elm-test should use to run tests in parallel. Defaults to the number of “logical CPU cores” of the machine you run the tests on. + + elm-test --workers 4 + +Your computer might say that it has 12 logical CPU cores. Then dividing up the tests between 12 parallel workers is the theoretical optimum for running the tests as quickly as possible. But in practice your tests might run faster with just 4 workers in parallel due to overhead. Play around with it and see what is the fastest for your test suite on your computer! + +To see the number of logical CPU cores on your machine, run `node -p "os.cpus().length"` (it’s also shown in `elm-test --help`). + ### --report Specify which format to use for reporting test results. Valid options are: diff --git a/lib/elm-test.js b/lib/elm-test.js index 91d52cd4..6df25de2 100644 --- a/lib/elm-test.js +++ b/lib/elm-test.js @@ -114,6 +114,8 @@ elm-test "src/**/*Tests.elm" Run tests in files matching the glob `.trim(); +const numberOfLogicalCPUCores = os.cpus().length; + function main() { const dependencyProvider = new DependencyProvider(); @@ -143,6 +145,14 @@ function main() { parsePositiveInteger(1), 100 ) + .addOption( + new Option('--workers ', 'Number of worker threads') + .default( + numberOfLogicalCPUCores, + `number of logical CPU cores, ${numberOfLogicalCPUCores} on this machine` + ) + .argParser(parsePositiveInteger(1)) + ) .addOption( new Option( '--report ', @@ -267,7 +277,7 @@ function main() { const options = program.opts(); const pathToElmBinary = getPathToElmBinary(options['compiler']); const projectRootDir = getProjectRootDir('tests'); - const processes = Math.max(1, os.cpus().length); + const processes = options['workers']; RunTests.runTests( dependencyProvider, projectRootDir, diff --git a/tests/flags.js b/tests/flags.js index 362cf5b3..4880fb23 100644 --- a/tests/flags.js +++ b/tests/flags.js @@ -443,6 +443,41 @@ describe('flags', () => { }); }); + describe('--workers', () => { + it('Should fail if given non-digits', () => { + const runResult = execElmTest([ + '--workers', + '0xaf', + path.join('tests', 'Passing', 'One.elm'), + ]); + + assert.ok(Number.isInteger(runResult.status)); + assert.notStrictEqual(runResult.status, 0); + }); + + it('Should fail if given 0', () => { + const runResult = execElmTest([ + '--workers', + '0', + path.join('tests', 'Passing', 'One.elm'), + ]); + + assert.ok(Number.isInteger(runResult.status)); + assert.notStrictEqual(runResult.status, 0); + }); + + it('Should fail if given a negative integer', () => { + const runResult = execElmTest([ + '--workers', + '-5', + path.join('tests', 'Passing', 'One.elm'), + ]); + + assert.ok(Number.isInteger(runResult.status)); + assert.notStrictEqual(runResult.status, 0); + }); + }); + describe('--compiler', () => { before(() => { const elmExe = path.resolve(which.sync('elm'));