unitTest ReferenceThe unitTest object implements an internal self-test function. It is similar to Jest, but it relies on ordinary JavaScipt operators instead of learning a new vocabulary of testing operators.
The unitTest object creates and controls tests. Tests are created using the unitTest.create() function. This takes a test title and a test function as arguments. The test function is called when the test is run and is passed a single argument, test, that is a sub-test function. When the test function is called, it calls test(subTestTitle) to create a sub-test object. the sub-test object takes chained methods to execute the test and determine the results. Here's an example of a test for Ptable interpolation:
unitTest.create('Ptable', (test) => {
// test simple Ptsble interpolation
const table = new Ptable({
title: "Simple Table",
inputs: [{key:'parm1'}],
a: [
{p:0, v:0},
{p:10, v:10},
]
});
test(`Simple table: interpolate: value`)
.isValue(table.interpolate({parm1: 4.6}), 4.6);
test(`Simple table: interpolate: passed rndMult`)
.isValue(table.interpolate({parm1: 4.6}, {rndMult:1}), 5);
});
The title passed to unitTest.create()documents the test series, and the title passed to each test() invocation documents each sub-test. The isValue method asserts that the computed value in the first argument is the same as in the second argument.
Unit tests are typically created at load time and test the module they are associated with.
Some tests may test functions that work asynchronously. In that case the test sub-test function can take a Promise as an argument. The Promise then runs the sub-test function when it has results. This feature can be user to, for example, test fetching from a server.
The sub-test function returns an instance of the Test class. The Test class has a set of assertion methods that determine the success or failure of each sub-test. The methods can be extended or overridden by passing a sub-class of Test as the third argument to unitTest.create() function. The base set of methods are:
pass()fail(message)message.assert(isOk, message)isOk is true. If not, the test fails with message.isValue(value, requiredValue)value is equal to (===) requiredValue. If not, the test fails.isNotValue(value, requiredValue)value is not equal to (!==) requiredValue. If not, the test fails.isApprox(value, requiredValue, error)value is equal to requiredValue within ± error. If not, the test fails.isSvValue(idOrSv, requiredValue)idOrSv is equal to (===) requiredValue. If not, the test fails.isNotSvValue(value, requiredValue)idOrSv is not equal to (!==) requiredValue. If not, the test fails.isSvApprox(value, requiredValue, error)idOrSv is equal to requiredValue within ± error. If not, the test fails.isSvValid(idOrSv)idOrSv is valid. If not, the test fails.throwsError(fn, checkErrFn)fn throw an error and that the error is correct according to checkErrFn.Methods other than pass() and fail() must eventually call pass() or fail() to declare the test end state.
Each call to unitTest.create() registers a group of tests under its title. The tests are not run until later. Calling unitTest.runOne(title) will run a test that matches the title and returns a Promise that resolves with the test results. The app's state is reset to default values before the test is run to put the app in a consistent state. The resolved value is an object that contains a title, result, and results properties that contain the test title. either pass or fail, and a Map of sub-test results, respectively. In the Map, the key is the sub-test title and the value is an object containing a message. If the message is empty, the sub-test passed.
Calling the unitTest.runAll() function runs all tests and returns a Promise that resolves with the results. The app's state is saved before and restored after the tests are run. In addition, storing the state locally or in the cloud is disabled while the test is running.
The tests are run by chaining the Promise returned by calling unitTest.runOne() for each test. The test Promise resolves when the chain of Promises resolves.
The unitTest.renderResults() function displays the results in a standard format. The results can be summarized or detailed. If all tests pass, the summarized results only display that all have passed. If any test fails, the test, the sub-test, and its message are displayed. In the detailed presentation, the results of all tests and sub-tests are displayed.
unitTest methodsunitTest.create()unitTest.create(title, fn)
unitTest.create(title, fn, type)
Creates a new test with title. The fn argument is a function to call to run the test. The test function takes a single test argument which is also a function. The test function calls the test to initiate each sub-test, passing a string that describes the sub-test as an argument. The test function returns an instance of the Test class. The sub-test must then call one of the Test instance methods to check the test conditions. All methods eventually invoke the pass() or fail(message) to declare the test result.
Once created, the units tests are executed by calling unitTest.runOne() to run a specified test or unitTest.runAll() to run all tests.
titlefntesttest(title), where title is the title of the sub-test. The function creates a sub-test with title and returns an instance or subclass of the Test class.type (optional)Test to return from the sub-test function. If omitted, defaults to Test. The subclass can override Test methods or add new ones. All methods must eventually result in a call to the pass() or fail() method in the superclass.unitTest.getTests()unitTest.getTests()
Returns an array of all the created test titles.
An array of strings.
unitTest.renderResults()unitTest.renderResults(results)
unitTest.renderResults(results, isDetailed)
Returns a Template displaying the results. By default, only a simple pass indication is presented if all tests pass. Otherwise, failed test titles, their sub-test titles, and their associated error messages are listed.
If detatiled is present and truthy, the results of all test and sub-test are presented.
resultsunitTest.runAll().isDetailed (optional)unitTest.renderResults() will display all results, including passed tests.unitTest.runAll()unitTest.runAll()
unitTest.runAll(showProgressFn)
Calling the unitTest.runAll() function will run all registered tests serially. It returns a Promise that resolves with the test results. The results are an array of the objects returned by unitTest.runOne() function. The function does the following:
ctl.doSync() to synchronize the Model.storage.getState() to get the current state saved in the local device storage.storage.disable() to disable saving state in storage during the test run.unitest.getTests() function to get the list of registered tests.progressFn argument was passed to unitTest.runOne(), if calls the progressFn function, passing the title of the test about to be run. The progressFn can use the title to update a state variable that displays the progress.unitTest.runOne() function to run the test.unitTest.runAll() function does the following:ctl.setSavedState() to to restore the state saves at the start of the run.ctl.doSync() to synchronize the Model.storage.enable() to enable saving state to storage.ctl.save() to synchronize the Model.unitTest.runOne() during the test.showProgressFn (optional)A Promise that resolves with the test results. The results value is an array of objects returned by unitTest.runOne() function.
unitTest.runOne()unitTest.runOne(title)
Calling the unitTest.runOne() function will run a test that matches the title passed as an argument. The function returns a Promise that resolves with the test results. While executing the Promise, unitTest.runOne() does the following:
ctl.resetAppValues() to reset all the state variables to their default values.ctl.doSync() to synchronize the Model.try block to catch exceptions.unitTest.runOne() resolves with a value that is an object containing the following properties:titleresult'pass' or 'fail'.resultsmessage property. If the value of the message property has content, then the sub-test has failed, and the value is the error message. Otherwise, the sub-test has passed. If the title for the sub-test was not unique within the test, then a number is added to the end of the title to make it unique.titleTest classnew Test(doneFn)
The Test constructor builds an instance whose methods are used to make assertions about the results of a sub-test. The instance is used as a return value from the te sub-test function passed to each test. A subclass can be used as well.
The doneFn argument is a function prepared by unitTest.runOne(). The test assertion methods call doneFn with a single message argument to record the results of the test. If the message is empty, the test has passed. In the Test class only the pass() and fail() methods call doneFn. All the other methods call pass() or fail() to record results.
doneFnmessage argument and records the message as the results of the sub-test. The test is considered to have passed if the message is empty.pass()pass()
This method records that the sub-test has passed.
fail()fail(message)
This method records that the sub-test has failed with the error message message.
messageassert()assert(isOk, message)
This method records that the sub-test has failed with the error message message is isOk is falsey. Otherwise, it records that the sub-test has passed.
isOkisOk is truthy.messageisOk failed.isValue()isValue(value, requiredValue)
This method records that the sub-test has passed if value is equal to (using ===) requiredValue. Otherwise, it records that the sub-test has failed, with a message indicating that both values did not match.
valuerequiredValuevalue === requiredValue.isNotValue()isNotValue(value, requiredValue)
This method records that the sub-test has passed if value is not equal to (using !==) requiredValue. Otherwise, it records that the sub-test has failed, with a message indicating that both values matched.
valuerequiredValuevalue !== requiredValue.isApprox()isApprox(value, requiredValue, error)
This method records that the sub-test has passed if value is within ± error of requiredValue. Otherwise, it records that the sub-test has failed, with a message indicating that value was not within the required interval.
valuerequiredValueerrorMath.abs(value - requiredValue) <= error + [EPSILON](#../utilities/numericfunctions#epsilon).isSvValue()isSvValue(idOrSv, requiredValue)
This method records that the sub-test has passed if the value in the state variable or the state variable identified by SV.getSv(idOrSv).value is equal to (using ===) requiredValue. Otherwise, it records that the sub-test has failed, with a message indicating that both values did not match.
idOrSvrequiredValueSV.getSv(idOrSv) === requiredValue.isNotSvValue()isNotSvValue(idOrSv, requiredValue)
This method records that the sub-test has passed if SV.getSv(idOrSv).value is not equal to (using !==) requiredValue. Otherwise, it records that the sub-test has failed, with a message indicating that both values matched.
idOrSvrequiredValueSV.getSv(idOrSv) !== requiredValue.isSvApprox()isSvApprox(idOrSv, requiredValue, error)
This method records that the sub-test has passed if SV.getSv(idOrSv).value is within ± error of requiredValue. Otherwise, it records that the sub-test has failed, with a message indicating that value was not within the required interval.
valuerequiredValueerrorMath.abs(SV.getSv(idOrSv).value - requiredValue) <= error + [EPSILON](#../utilities/numericfunctions#epsilon).isSvValid()isSvValid(idOrSv)
This method records that the sub-test has passed if SV.getSv(idOrSv).isValid() is true. Otherwise, it records that the sub-test has failed, with a message indicating that the state variable does not contain a valid value.
idOrSvthrowsError()throwsError(fn)
throwsError(fn, checkErrFn)
This method records that the sub-test has passed if calling fn() results in a thrown error and either checkErrorFn is omitted or calling checkErrorFn(error) passing the received error returns an empty message string. Otherwise, it records that the sub-test has failed, with a message indicating that calling the function did not result in a thrown error or the non-empty message returned by calling checkErrorFn(error).
fncheckErrFn (optional)