Core Library for Elm-Spec Runners
This library contains the core logic for running elm-spec suites. Runner applications
can use this library to run elm-spec suites in a particular environment.
For an elm-spec suite to run, some things need to happen in Node and some
things need to happen in a browser.
On the Node side:
1. Create a browser somehow (using JSDOM or Playwright or Puppeteer etc)
2. Prepare some JS that instantiates an ElmContext and a Reporter and uses those to create a SuiteRunner.
3. Bundle this JS (using Browserify, esbuild etc) and evaluate it in the DOM window.
3. Use the Compiler to compile the code and evaluate it in the DOM window.
On the Browser side:
4. Call runAll() on the SuiteRunner to run all the spec programs.
You may import these modules from elm-spec-core:
``
const {
ElmContext,
SuiteRunner,
ProgramRunner
} = require('elm-spec-core')
const Compiler = require('elm-spec-core/compiler')
`
Create an instance:
`process.cwd()
new Compiler({
// Switch to the given directory for compilation; must contain an elm.json file.
// By default, the current working directory is
cwd: './specs',
// Glob that specifies how to find spec modules, relative to the current working directory
// (REQUIRED)
specPath: './*/Spec.elm',
// Path to the elm executable
// By default, the compiler uses the elm executable in the current path
elmPath: './node_modules/.bin/elm',
// Log level
// By default, the compiler prints all log output
// Compiler.LOG_LEVEL.ALL -- will print info and errors
// Compiler.LOG_LEVEL.QUIET -- will only print compiler errors
// Compiler.LOG_LEVEL.SILENT -- will print nothing at all
logLevel: Compiler.LOG_LEVEL.QUIET
})
`
compiler#compile()
Compiles the spec modules into a single string of JavaScript, adds an elm-spec
specific wrapper around the compiled code to facilitate testing, and returns the string.
compiler#status()
Returns the status of the compiler, updated after each call to compile(). Possible values are:
`
// no compilation has occurred
Compiler.STATUS.READY
// no files found to compile
Compiler.STATUS.NO_FILES
// files were found and successfully compiled
Compiler.STATUS.COMPILATION_SUCCEEDED
// files were found but compilation failed
Compiler.STATUS.COMPILATION_FAILED
`
Create an instance:
``
new ElmContext(window)
where window is a reference to the DOM window object belonging to the environment where the
compiled Elm code will be evaluated.
ElmContext#registerFileLoadingCapability(decorator, capability)
Provide a decorator function that ElmContext can use to add a function to the window object. The dectoratordecorator
is a function that takes two arguments: the name of the function and the function itself. The implementation
of should attach the given function to the window object using the given name.
capability in this case is a function that loads a file from the local filesystem. It takes a single argument
like so:
``
{ path: "some path to file", convertToText: true }
How the path is interpreted (what it is relative to, etc) is up to the implementation of the capability.
The capability implementation should return a promise. When convertToText is false it should resolve to:
``
{ path: "the absolute path to the file", buffer: { data: [1, 2, 3] } }
When convertToText is true, it should resolve to:
``
{ path: "the absolute path to the file", text: "the text of the file" }
If there is any problem loading the file, the promise should reject with this object:
``
{ type: "file", path: "the absolute path to the file" }
elmContext#evaluate(callback)
``
elmContext.evaluate((Elm) => {
// do something with the Elm JavaScript object
})
Create an instance:
``
new SuiteRunner(elmContext, reporter, options, version)
where options is:
``
{
// stop the test suite run after the first failure
endOnFailure: true,
}
and version is just used for testing.
suiteRunner#runAll()
Execute all the compiled spec programs, one by one.
suiteRunner#runSegment(segment, totalSegments)
Run only scenarios for the given segment. (eg, 0, 1, 2, ...)
When runAll or runSegment is called, the following event will be emitted:
complete -- an attempt has been made to run all scenarios. When there is an error an object
like so is emitted:
``
{
status: "Error"
}
When all scenarios were able to be executed, an object like so is emitted:
`
{
status: "Ok",
// A summary of the results is provided.
accepted: 1,
rejected: 1,
skipped: 0
}
`
A Reporter is an object with the following functions:
`
{
// Called at the start of a suite run.
// Note: this will be called once for each parallel segment.
startSuite: () => {},
// Called with an Observation after each expectation is evaluated.
record: (observation) => {},
// Called with a Report. If there is an error, the spec suite segment will immediately end.
error: (err) => {},
// Called with a Report.
log: (report) => {},
// Called at the end of the spec suite run.
// Note: this will be called once for each parallel segment.
finish: () => {}
}
`
An object like this:
`
{
// what is being described by the spec
description: 'Some description',
// steps in the scenario script
conditions: [ 'Scenario: Some scenario', 'When something happens', 'it does something' ],
// The outcome of the observation: ACCEPTED, SKIPPED, or REJECTED
summary: 'ACCEPTED',
// If the expectation is rejected, a report that explains why
report: null,
// Absolute path to the file containing the elm-spec program that produced this observation.
modulePath: "/some/path/to/some/elm/SomeSpec.elm"
}
`
An object like this:
``
[
{
statement: "Expected",
detail: "True"
},
{
statement: "to be",
detail: "False"
}
]
Create an instance:
``
new ProgramRunner(app, elmContext, options)
where app is the initialized Elm program to execute, and options is the same options object used by SuiteRunner.
ProgramRunner#hasElmSpecPorts(app)
Check if the app has the expected ports. Returns true or false.
programRunner#run()
Runs the spec program supplied in the constructor.
The following events are emitted:
observation -- emits an Observation object
error -- emits a Report describing the error
log -- emits a Report
complete` -- the spec program run is complete; emits a boolean indicating whether the
next spec program (if any) should be executed. Under some conditions (like an error),
the ProgramRunner will indicate that no more spec programs should be executed.