/*eslint max-lines: 'off'*/
import { TestResult } from './test_result.js';
import { TestResultReporter } from './test_result_reporter.js';
import { Assertion } from './assertion.js';
import { isStringWithContent } from '../utils.js';
import { I18nMessage } from '../i18n/i18n_messages.js';
/**
* I report failures to the [test runner]{@link TestRunner}. The type of failures I report are not from failed
* assertions, but user explicit requests for failures.
*/
class FailureGenerator extends TestResultReporter {
/**
* Makes the current test to explicitly fail, indicating an exceptional scenario.
*
* @example
* fail.with('The code should not reach this point')
*
* @param {string} description A reason to explain why we are explicitly failing.
* @returns {void}
*/
with(description) {
const messageToReport = description || I18nMessage.of('explicitly_failed');
this.reportFailure(messageToReport);
}
}
/**
* I report pending tests to the [test runner]{@link TestRunner}. Those tests will be displayed as WIP.
*/
class PendingMarker extends TestResultReporter {
/**
* Indicates a test is not ready to be evaluated until the end to produce a final result, so it will be reported as a
* [pending result]{@link TestResult.explicitlyMarkedAsPending}. If no reason is provided, an
* [error result]{@link TestResult.error} will be reported instead.
*
* @param {!string} reason A required explanation to indicate why this test is not ready.
* @returns {void}
*/
dueTo(reason) {
if (isStringWithContent(reason)) {
this.report(TestResult.explicitlyMarkedAsPending(reason));
} else {
this.report(TestResult.error(this.#invalidReasonErrorMessage()));
}
}
#invalidReasonErrorMessage() {
return I18nMessage.of('invalid_pending_reason');
}
}
/**
* I am the entry point for generating different types of assertions and reporting their results to the
* [test runner]{@link TestRunner}.
*/
class Asserter extends TestResultReporter {
/**
* Starts an assertion. A call to this method needs to be chained with an expectation, otherwise it does not
* represent a valid assertion.
*
* @example using the {@link isEqualTo} assertion
* assert.that(3 + 4).isEqualTo(7)
*
* @example using the {@link isEmpty} assertion
* assert.that("").isEmpty()
*
* @example using the {@link isNearTo} assertion
* assert.that(0.1 + 0.2).isNearTo(0.3)
*
* @param {*} actual ths object under test.
* @returns {Assertion} sn object that you can use to build an assertion.
*/
that(actual) {
return new Assertion(this._runner, actual);
}
/**
* Expects a given object to be strictly equal to `true`. Other "truthy" values according to Javascript rules
* will be considered not true.
*
* This is a shortcut of the [that]{@link that} syntax followed by a [isTrue]{@link Assertion#isTrue} assertion.
*
* @example
* assert.isTrue(3 < 4)
*
* @example equivalent version
* assert.that(3 < 4).isTrue()
*
* @param {*} actual the object you expect to be `true`.
* @returns {void}
*/
isTrue(actual) {
return this.that(actual).isTrue();
}
/**
* Expects a given object to be strictly equal to `false`. Other "falsey" values according to Javascript rules
* will be considered not true.
*
* This is a shortcut of the {@link that} syntax followed by a [isFalse]{@link Assertion#isFalse} assertion.
*
* @example
* assert.isFalse(4 < 3)
*
* @example equivalent version
* assert.that(4 < 3).isFalse()
*
* @param {*} actual the object you expect to be `false`.
* @returns {void}
*/
isFalse(actual) {
return this.that(actual).isFalse();
}
/**
* Expects the actual object to be strictly equal to `undefined`.
* This is a shortcut of the {@link that} syntax followed by a [isUndefined]{@link Assertion#isUndefined} assertion.
*
* @example
* assert.isUndefined(object.missingProperty)
*
* @example equivalent version
* assert.that(object.missingProperty).isUndefined()
*
* @param {*} actual the object you expect to be `undefined`.
* @returns {void}
*/
isUndefined(actual) {
return this.that(actual).isUndefined();
}
/**
* Expects the actual object to be not strictly equal to `undefined`.
* This is a shortcut of the {@link that} syntax followed by a [isNotUndefined]{@link Assertion#isNotUndefined} assertion.
*
* @example
* assert.isNotUndefined("hello".length)
*
* @example equivalent version
* assert.that("hello".length).isNotUndefined()
*
* @param {*} actual the object you expect to be not `undefined`.
* @returns {void}
*/
isNotUndefined(actual) {
return this.that(actual).isNotUndefined();
}
/**
* Expects the actual object to be strictly equal to `null`.
* This is a shortcut of the [that]{@link that} syntax followed by a [isNull]{@link Assertion#isNull} assertion.
*
* @example
* assert.isNull(null)
*
* @example equivalent version
* assert.that(null).isNull()
*
* @param {*} actual the object you expect to be `null`.
* @returns {void}
*/
isNull(actual) {
return this.that(actual).isNull();
}
/**
* Expects the actual object to be different from `null`.
* This is a shortcut of the [that]{@link that} syntax followed by a [isNotNull]{@link Assertion#isNotNull} assertion.
*
* @example
* assert.isNotNull('something')
*
* @example equivalent version
* assert.that('something').isNotNull()
*
* @param {*} actual the object you expect to be different from `null`.
* @returns {void}
*/
isNotNull(actual) {
return this.that(actual).isNotNull();
}
/**
* Expects two given objects to be equal according to a default or custom criteria.
* This is a shortcut of the [that]{@link that} syntax followed by a [isEqualTo]{@link isEqualTo} assertion.
*
* @example
* assert.areEqual(3 + 4, 7)
*
* @example equivalent version
* assert.that('3' + '4').isEqualTo('34')
*
* @example custom criteria
* assert.areEqual([2, 3], ['x', 'y'], (a, b) => a.length === b.length)
*
* @param {*} actual the object under test.
* @param {*} expected the object that you are expecting the `actual` to be.
* @param {Function} [criteria] a two-argument function to be used to compare `actual` and `expected`. Optional.
*
* @returns {void}
*/
areEqual(actual, expected, criteria) {
return this.that(actual).isEqualTo(expected, criteria);
}
/**
* Expects two given objects to be not equal, according to a default or custom criteria.
* This is a shortcut of the [that]{@link that} syntax followed by a [isNotEqualTo]{@link isNotEqualTo} assertion.
*
* @example
* assert.areNotEqual(3 + 4, 8)
*
* @example equivalent version
* assert.that('3' + '4').isNotEqualTo('7')
*
* @example custom criteria
* assert.areNotEqual([2, 3], ['x'], (a, b) => a.length === b.length)
*
* @param {*} actual the object under test.
* @param {*} expected the object that you are expecting the `actual` to not be equal.
* @param {Function} [criteria] a two-argument function to be used to compare `actual` and `expected`. Optional.
*
* @returns {void}
*/
areNotEqual(actual, expected, criteria) {
return this.that(actual).isNotEqualTo(expected, criteria);
}
/**
* Expects two given objects to be identical, that is, to share the same reference.
* This is a shortcut of the [that]{@link that} syntax followed by a [isIdenticalTo]{@link isEqualTo} assertion.
*
* @example literals
* assert.areIdentical(3, 3)
*
* @example equivalent version
* assert.that(3).isIdenticalTo(3)
*
* @example same reference
* const object = { my: "object" }
* assert.areIdentical(object, object)
*
* @param {*} actual the object under test.
* @param {*} expected the object that you are expecting the `actual` to be.
*
* @returns {void}
*/
areIdentical(actual, expected) {
return this.that(actual).isIdenticalTo(expected);
}
areNotIdentical(actual, expected) {
return this.that(actual).isNotIdenticalTo(expected);
}
/**
* Expects a given object to be an empty collection (arrays, strings, sets and maps).
* This is a shortcut of the [that]{@link that} syntax followed by a [isEmpty]{@link Assertion.isEmpty} assertion.
*
* @example
* assert.isEmpty([])
* assert.isEmpty('')
* assert.isEmpty(new Set())
* assert.isEmpty(new Map())
*
* @example equivalent version
* assert.that('').isEmpty()
*
* @param {*} actual the collection object you expect to be empty.
*
* @returns {void}
*/
isEmpty(actual) {
return this.that(actual).isEmpty();
}
/**
* Expects a given object to be a non-empty collection (arrays, strings, sets and maps).
* This is a shortcut of the [that]{@link that} syntax followed by a [isNotEmpty]{@link Assertion.isNotEmpty} assertion.
*
* @example
* assert.isNotEmpty([42])
* assert.isNotEmpty('hello')
* assert.isNotEmpty(new Set([42]))
* assert.isNotEmpty(new Map([['key', 42]]))
*
* @example equivalent version
* assert.that('hello').isNotEmpty()
*
* @param {*} actual the collection object you expect to be non-empty.
*
* @returns {void}
*/
isNotEmpty(actual) {
return this.that(actual).isNotEmpty();
}
/**
* Expects a given string to match a given regexp.
* This is a shortcut of the [that]{@link that} syntax followed by a [matches]{@link Assertion.matches} assertion.
*
* @example
* assert.isMatching('hello', /[a-z]+/)
*
* @example equivalent version
* assert.that('hello').matches(/[a-z]+/)
*
* @param {String} actual the string you will check against the regex.
* @param {RegExp} regex the regexp you will use to parse the actual string.
*
* @returns {void}
*/
isMatching(actual, regex) {
return this.that(actual).matches(regex);
}
}
export { Asserter, FailureGenerator, PendingMarker };