diff --git a/.github/workflows/nodejs.yml b/.github/workflows/nodejs.yml index 7d02b002..e14f9378 100644 --- a/.github/workflows/nodejs.yml +++ b/.github/workflows/nodejs.yml @@ -7,12 +7,12 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - node-version: [12.x, 14.x, 16.x] + node-version: [12.x, 14.x, 16.x, 18.x] steps: - name: Checkout repo - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v2 + uses: actions/setup-node@v3 with: node-version: ${{ matrix.node-version }} - name: Build NPM package, run lint analysis and tests @@ -23,7 +23,10 @@ jobs: env: CI: true - name: Code Climate Coverage Action - uses: paambaati/codeclimate-action@v2.6.0 + uses: paambaati/codeclimate-action@v3.0.0 + with: + coverageCommand: npm run coverage + debug: true env: CC_TEST_REPORTER_ID: 6ace5bc20f45a4d3b1d1bd56b37e2ed97c92776e402f4f687bb5ee50853cb51c - name: SonarCloud Scan @@ -33,7 +36,7 @@ jobs: -Dsonar.projectKey=ngarbezza_testy -Dsonar.organization=ngarbezza -Dsonar.projectName=Testy - -Dsonar.projectVersion=6.0.0 + -Dsonar.projectVersion=6.1.0 -Dsonar.javascript.lcov.reportPaths=coverage/lcov.info -Dsonar.coverage.exclusions=tests/** env: diff --git a/.github/workflows/npmpublish.yml b/.github/workflows/npmpublish.yml index 5963507f..99031fa5 100644 --- a/.github/workflows/npmpublish.yml +++ b/.github/workflows/npmpublish.yml @@ -8,8 +8,8 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: 16 - run: npm ci @@ -19,8 +19,8 @@ jobs: needs: build runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 - - uses: actions/setup-node@v1 + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 with: node-version: 16 registry-url: https://registry.npmjs.org/ diff --git a/CHANGELOG.md b/CHANGELOG.md index ad3ecd56..73eed31a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Everything is released :tada: +## [6.1.0] - 2022-07-13 + +### Added + +* [[feature] support for asynchronous tests](https://github.com/ngarbezza/testy/issues/106), thank you +[@JavierGelatti](https://github.com/JavierGelatti) for the [initial implementation](https://github.com/ngarbezza/testy/pull/82)! +Now we can use `async`/`await` in test definitions. + +### Fixed + +* [[bug] before() and after() argument is not validated](https://github.com/ngarbezza/testy/issues/227) + +* [[bug] multiple before() or after() empty blocks can be added to a test suite](https://github.com/ngarbezza/testy/issues/202) + +* [[bug] swallowed/not precise exception when before() or after() fails](https://github.com/ngarbezza/testy/issues/230) + +### Other changes + +* Updates to the dev tools: eslint, github actions, code climate +* Added [10Pines](https://10pines.com) as sponsor: thanks for the support! + ## [6.0.0] - 2021-11-21 ### Breaking changes @@ -294,7 +315,8 @@ readable and extensible. It also includes a huge internal refactor to make the t * Fix passed count at test runner level (no reported issue) -[Unreleased]: https://github.com/ngarbezza/testy/compare/v6.0.0...HEAD +[Unreleased]: https://github.com/ngarbezza/testy/compare/v6.1.0...HEAD +[6.1.0]: https://github.com/ngarbezza/testy/compare/v6.0.0...v6.1.0 [6.0.0]: https://github.com/ngarbezza/testy/compare/v5.1.0...v6.0.0 [5.1.0]: https://github.com/ngarbezza/testy/compare/v5.0.2...v5.1.0 [5.0.2]: https://github.com/ngarbezza/testy/compare/v5.0.1...v5.0.2 diff --git a/README.md b/README.md index 68e8afe0..9f042d4c 100644 --- a/README.md +++ b/README.md @@ -185,6 +185,29 @@ definition of `before()` and `after()` per suite, and they always receive a func }); ``` * **Support for pending tests**: if a test has no body, it will be reported as `[WIP]` and it won't be considered a failure. +* **Support for asynchronous tests**: if the code you are testing has `async` logic, you can `await` inside the test +definition and make assertions later. You can also use it on `before()` and `after()` declarations. Example: + + ```javascript + const { suite, test, assert, before } = require('@pmoo/testy'); + + const promiseOne = async () => Promise.resolve(42); + const promiseTwo = async () => Promise.resolve(21); + + suite('using async & await', () => { + let answerOne; + + before(async () => { + answerOne = await promiseOne(); + }); + + test('comparing results from promises', async () => { + const answerTwo = await promiseTwo(); + assert.that(answerOne).isEqualTo(42); + assert.that(answerTwo).isEqualTo(21); + }); + }); + ``` * **Fail-Fast mode**: if enabled, it stops execution in the first test that fails (or has an error). Remaining tests will be marked as skipped. * **Run tests and suites in random order**: a good test suite does not depend on a particular order. Enabling this setting is a good way to ensure that. * **Strict check for assertions**: if a test does not evaluate any assertion while it is executed, the result is considered an error. Basically, a test with no assertion is considered a "bad" test. diff --git a/README_es.md b/README_es.md index 20b0d721..127a2388 100644 --- a/README_es.md +++ b/README_es.md @@ -177,10 +177,34 @@ _suite_. `before()` y `after()` reciben una función como parámetro y pueden ut }); }); ``` -* **Soporte para tests pendientes**: Un test que no tenga cuerpo, será reportado como pendiente (`[WIP]`) y no se considerará una falla. -* **Modo "fail-fast"**: Cuando está habilitado, se detiene apenas encuentra un test que falle o lance un error. Los tests restantes serán marcados como no ejecutados (_skipped_). -* **Ejecutar tests en orden aleatorio**: Una buena suite de tests no depende de un orden particular de tests para ejecutarse correctamentee. Activando esta configuración es una buena forma de asegurar eso. -* **Chequeo estricto de presencia de aserciones**: Si un test no evalúa ninguna aserción durante su ejecución, el resultado se considera un error. Básicamente, un test que no tiene aserciones es un "mal" test. +* **Soporte para tests pendientes**: un test que no tenga cuerpo, será reportado como pendiente (`[WIP]`) y no se considerará una falla. +* **Soporte para tests asíncronos**: si el código que estás testeando requiere de `async`, es posible hacer `await` +dentro de la definicion del test y luego escribir las aserciones. También es posible hacer llamados asincrónicos en +`before()` y `after()`. Ejemplo: + + ```javascript + const { suite, test, assert, before } = require('@pmoo/testy'); + + const promesaUno = async () => Promise.resolve(42); + const promesaDos = async () => Promise.resolve(21); + + suite('usando async y await', () => { + let respuestaUno; + + before(async () => { + respuestaUno = await promesaUno(); + }); + + test('comparando resultados de promesas', async () => { + const respuestaDos = await promesaDos(); + assert.that(respuestaUno).isEqualTo(42); + assert.that(respuestaDos).isEqualTo(21); + }); + }); + ``` +* **Modo "fail-fast"**: cuando está habilitado, se detiene apenas encuentra un test que falle o lance un error. Los tests restantes serán marcados como no ejecutados (_skipped_). +* **Ejecutar tests en orden aleatorio**: una buena suite de tests no depende de un orden particular de tests para ejecutarse correctamentee. Activando esta configuración es una buena forma de asegurar eso. +* **Chequeo estricto de presencia de aserciones**: si un test no evalúa ninguna aserción durante su ejecución, el resultado se considera un error. Básicamente, un test que no tiene aserciones es un "mal" test. * **Explícitamente marcar un test como fallido o pendiente**: Ejemplos: ```javascript diff --git a/lib/equality_assertion_strategy.js b/lib/equality_assertion_strategy.js index 347b7b25..81497671 100644 --- a/lib/equality_assertion_strategy.js +++ b/lib/equality_assertion_strategy.js @@ -14,7 +14,7 @@ const EqualityAssertionStrategy = { DefaultEquality, ]; }, - + evaluate(actual, expected, criteria) { return this.availableStrategies() .find(strategy => strategy.appliesTo(actual, expected, criteria)) @@ -24,11 +24,11 @@ const EqualityAssertionStrategy = { const BothPartsUndefined = { __proto__: EqualityAssertionStrategy, - + appliesTo(actual, expected) { return isUndefined(actual) && isUndefined(expected); }, - + evaluate() { return { comparisonResult: undefined, @@ -39,11 +39,11 @@ const BothPartsUndefined = { const CustomFunction = { __proto__: EqualityAssertionStrategy, - - appliesTo(actual, expected, criteria) { + + appliesTo(_actual, _expected, criteria) { return isFunction(criteria); }, - + evaluate(actual, expected, criteria) { return { comparisonResult: criteria(actual, expected), @@ -54,11 +54,11 @@ const CustomFunction = { const CustomPropertyName = { __proto__: EqualityAssertionStrategy, - - appliesTo(actual, expected, criteria) { + + appliesTo(_actual, _expected, criteria) { return isString(criteria); }, - + evaluate(actual, expected, criteria) { if (this._comparisonCanBeMade(actual, expected, criteria)) { return this._compareUsingCustomCriteria(actual, expected, criteria); @@ -66,18 +66,18 @@ const CustomPropertyName = { return this._failWithCriteriaNotFoundMessage(criteria); } }, - + _comparisonCanBeMade(actual, expected, criteria) { return respondsTo(actual, criteria) && respondsTo(expected, criteria); }, - + _compareUsingCustomCriteria(actual, expected, criteria) { return { comparisonResult: actual[criteria](expected), additionalFailureMessage: () => I18nMessage.empty(), }; }, - + _failWithCriteriaNotFoundMessage(criteria) { return { comparisonResult: false, @@ -88,11 +88,11 @@ const CustomPropertyName = { const ObjectWithEqualsProperty = { __proto__: EqualityAssertionStrategy, - + appliesTo(actual, _expected) { return respondsTo(actual, 'equals'); }, - + evaluate(actual, expected) { return { comparisonResult: actual.equals(expected), @@ -103,11 +103,11 @@ const ObjectWithEqualsProperty = { const ObjectWithCyclicReference = { __proto__: EqualityAssertionStrategy, - + appliesTo(actual, expected) { return isCyclic(actual) || isCyclic(expected); }, - + evaluate(_actual, _expected) { return { comparisonResult: false, @@ -118,11 +118,11 @@ const ObjectWithCyclicReference = { const DefaultEquality = { __proto__: EqualityAssertionStrategy, - + appliesTo(_actual, _expected) { return true; }, - + evaluate(actual, expected) { return { comparisonResult: deepStrictEqual(actual, expected), diff --git a/lib/test_result.js b/lib/test_result.js index b33430c6..244719bb 100644 --- a/lib/test_result.js +++ b/lib/test_result.js @@ -55,7 +55,7 @@ class TestResult { } class SkippedTest extends TestResult { - static canHandle(test, context) { + static canHandle(_test, context) { return context.failFastMode.hasFailed(); } diff --git a/package-lock.json b/package-lock.json index 51962097..a2ac57d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@pmoo/testy", - "version": "6.0.0", + "version": "6.1.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@pmoo/testy", - "version": "6.0.0", + "version": "6.1.0", "license": "MIT", "bin": { "testy": "bin/testy_cli.js" diff --git a/package.json b/package.json index b58215ee..b9ce8a86 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@pmoo/testy", - "version": "6.0.0", + "version": "6.1.0", "description": "A minimal testing framework, for educational purposes.", "homepage": "https://ngarbezza.github.io/testy/", "repository": { diff --git a/tests/core/assertions/equality_assertions_test.js b/tests/core/assertions/equality_assertions_test.js index 0c8e0dc7..794ac5ee 100644 --- a/tests/core/assertions/equality_assertions_test.js +++ b/tests/core/assertions/equality_assertions_test.js @@ -8,31 +8,31 @@ const { I18nMessage, I18n } = require('../../../lib/i18n'); suite('equality assertions', () => { test('isEqualTo pass with equal primitive objects', async() => { - const result = await resultOfATestWith(assert => assert.that(42).isEqualTo(42)); + const result = await resultOfATestWith(asserter => asserter.that(42).isEqualTo(42)); expectSuccess(result); }); test('isEqualTo fails with different primitive objects', async() => { - const result = await resultOfATestWith(assert => assert.that(42).isEqualTo(21)); + const result = await resultOfATestWith(asserter => asserter.that(42).isEqualTo(21)); expectFailureOn(result, I18nMessage.of('equality_assertion_be_equal_to', '42', '21')); }); test('isEqualTo passes with boxed and unboxed numbers', async() => { - const result = await resultOfATestWith(assert => assert.that(42).isEqualTo((42))); + const result = await resultOfATestWith(asserter => asserter.that(42).isEqualTo((42))); expectSuccess(result); }); test('isEqualTo passes with arrays in the same order', async() => { - const result = await resultOfATestWith(assert => assert.that([1, 2, 3]).isEqualTo([1, 2, 3])); + const result = await resultOfATestWith(asserter => asserter.that([1, 2, 3]).isEqualTo([1, 2, 3])); expectSuccess(result); }); test('isEqualTo fails with arrays in different order', async() => { - const result = await resultOfATestWith(assert => assert.that([1, 2, 3]).isEqualTo([1, 3, 2])); + const result = await resultOfATestWith(asserter => asserter.that([1, 2, 3]).isEqualTo([1, 3, 2])); expectFailureOn(result, I18nMessage.of('equality_assertion_be_equal_to', '[ 1, 2, 3 ]', '[ 1, 3, 2 ]')); }); @@ -42,7 +42,7 @@ suite('equality assertions', () => { const objectOne = { a: 'a', b: { b1: 'b1', b2: 'b2' } }; const objectTwo = { a: 'a', b: { b1: 'b1', b2: 'b2' } }; /* eslint-enable id-length */ - const result = await resultOfATestWith(assert => assert.that(objectOne).isEqualTo(objectTwo)); + const result = await resultOfATestWith(asserter => asserter.that(objectOne).isEqualTo(objectTwo)); expectSuccess(result); }); @@ -52,7 +52,7 @@ suite('equality assertions', () => { const objectOne = { a: 'a', b: { b1: 'b1', b2: 'b2' } }; const objectTwo = { a: 'a', b: { b1: 'b1', b2: '' } }; /* eslint-enable id-length */ - const result = await resultOfATestWith(assert => assert.that(objectOne).isEqualTo(objectTwo)); + const result = await resultOfATestWith(asserter => asserter.that(objectOne).isEqualTo(objectTwo)); expectFailureOn(result, I18nMessage.of('equality_assertion_be_equal_to', "{ a: 'a', b: { b1: 'b1', b2: 'b2' } }", "{ a: 'a', b: { b1: 'b1', b2: '' } }")); }); @@ -62,7 +62,7 @@ suite('equality assertions', () => { const objectOne = { a: 'a', b: 'b' }; const objectTwo = { a: 'a', b: 'b', c: 'c' }; /* eslint-enable id-length */ - const result = await resultOfATestWith(assert => assert.that(objectOne).isEqualTo(objectTwo)); + const result = await resultOfATestWith(asserter => asserter.that(objectOne).isEqualTo(objectTwo)); expectFailureOn(result, I18nMessage.of('equality_assertion_be_equal_to', "{ a: 'a', b: 'b' }", "{ a: 'a', b: 'b', c: 'c' }")); }); @@ -72,7 +72,7 @@ suite('equality assertions', () => { const objectOne = { a: 'a', b: 'b', c: 'c' }; const objectTwo = { a: 'a', b: 'b' }; /* eslint-enable id-length */ - const result = await resultOfATestWith(assert => assert.that(objectOne).isEqualTo(objectTwo)); + const result = await resultOfATestWith(asserter => asserter.that(objectOne).isEqualTo(objectTwo)); expectFailureOn(result, I18nMessage.of('equality_assertion_be_equal_to', "{ a: 'a', b: 'b', c: 'c' }", "{ a: 'a', b: 'b' }")); }); @@ -82,7 +82,7 @@ suite('equality assertions', () => { const objectOne = { a: 'a', b: 'b' }; const objectTwo = { a: 'a', b: 'b' }; /* eslint-enable id-length */ - const result = await resultOfATestWith(assert => assert.areEqual(objectOne, objectTwo, 'notFound')); + const result = await resultOfATestWith(asserter => asserter.areEqual(objectOne, objectTwo, 'notFound')); const assertionMessage = I18nMessage.of('equality_assertion_be_equal_to', "{ a: 'a', b: 'b' }", "{ a: 'a', b: 'b' }"); const additionalMessage = I18nMessage.of('equality_assertion_failed_due_to_missing_property', 'notFound'); @@ -94,7 +94,7 @@ suite('equality assertions', () => { const objectOne = { a: 'a', b: 'b1', myEqualMessage: () => true }; const objectTwo = { a: 'a', b: 'b2', myEqualMessage: () => true }; /* eslint-enable id-length */ - const result = await resultOfATestWith(assert => assert.areEqual(objectOne, objectTwo, 'myEqualMessage')); + const result = await resultOfATestWith(asserter => asserter.areEqual(objectOne, objectTwo, 'myEqualMessage')); expectSuccess(result); }); @@ -110,7 +110,7 @@ suite('equality assertions', () => { } const objectOne = new AClass(); const objectTwo = new AClass(); - const result = await resultOfATestWith(assert => assert.areEqual(objectOne, objectTwo, 'myEqualMessage')); + const result = await resultOfATestWith(asserter => asserter.areEqual(objectOne, objectTwo, 'myEqualMessage')); expectSuccess(result); }); @@ -126,29 +126,29 @@ suite('equality assertions', () => { } const objectOne = new AClass(1); const objectTwo = new AClass(2); - const result = await resultOfATestWith(assert => assert.areEqual(objectOne, objectTwo)); + const result = await resultOfATestWith(asserter => asserter.areEqual(objectOne, objectTwo)); expectSuccess(result); }); test('isEqualTo fails when comparing undefined with an object', async() => { - const resultOne = await resultOfATestWith(assert => assert.areEqual(undefined, {})); - const resultTwo = await resultOfATestWith(assert => assert.areEqual({}, undefined)); + const resultOne = await resultOfATestWith(asserter => asserter.areEqual(undefined, {})); + const resultTwo = await resultOfATestWith(asserter => asserter.areEqual({}, undefined)); expectFailureOn(resultOne, I18nMessage.of('equality_assertion_be_equal_to', 'undefined', '{}')); expectFailureOn(resultTwo, I18nMessage.of('equality_assertion_be_equal_to', '{}', 'undefined')); }); test('isEqualTo fails when comparing null with an object', async() => { - const resultOne = await resultOfATestWith(assert => assert.areEqual(null, {})); - const resultTwo = await resultOfATestWith(assert => assert.areEqual({}, null)); + const resultOne = await resultOfATestWith(asserter => asserter.areEqual(null, {})); + const resultTwo = await resultOfATestWith(asserter => asserter.areEqual({}, null)); expectFailureOn(resultOne, I18nMessage.of('equality_assertion_be_equal_to', 'null', '{}')); expectFailureOn(resultTwo, I18nMessage.of('equality_assertion_be_equal_to', '{}', 'null')); }); test('isEqualTo fails if both parts are undefined', async() => { - const result = await resultOfATestWith(assert => assert.areEqual(undefined, undefined)); + const result = await resultOfATestWith(asserter => asserter.areEqual(undefined, undefined)); expectFailureOn(result, I18nMessage.of('equality_assertion_failed_due_to_undetermination')); }); @@ -157,7 +157,7 @@ suite('equality assertions', () => { return 'circular!'; } }; objectOne.self = objectOne; - const result = await resultOfATestWith(assert => assert.areEqual(objectOne, objectOne)); + const result = await resultOfATestWith(asserter => asserter.areEqual(objectOne, objectOne)); const assertionMessage = I18nMessage.of('equality_assertion_be_equal_to', 'circular!', 'circular!'); const additionalMessage = I18nMessage.of('equality_assertion_failed_due_to_circular_references'); @@ -165,12 +165,12 @@ suite('equality assertions', () => { }); test('isNotEqualTo fails if both parts are undefined', async() => { - const result = await resultOfATestWith(assert => assert.that(undefined).isNotEqualTo(undefined)); + const result = await resultOfATestWith(asserter => asserter.that(undefined).isNotEqualTo(undefined)); expectFailureOn(result, I18nMessage.of('equality_assertion_failed_due_to_undetermination')); }); test('displays equality failure messages with all depth', async() => { - const result = await resultOfATestWith(assert => assert.that({ a1: { a2: { a3: { a4: true } } } }).isEqualTo({ a1: { a2: { a3: { a4: false } } } })); + const result = await resultOfATestWith(asserter => asserter.that({ a1: { a2: { a3: { a4: true } } } }).isEqualTo({ a1: { a2: { a3: { a4: false } } } })); const actualFailureMessageInEnglish = result.failureMessage().expressedIn(I18n.default()); assert.that(actualFailureMessageInEnglish).isEqualTo('Expected { a1: { a2: { a3: { a4: true } } } } to be equal to { a1: { a2: { a3: { a4: false } } } }'); }); diff --git a/tests/core/test_runner_test.js b/tests/core/test_runner_test.js index aee44f93..3bb5f50f 100644 --- a/tests/core/test_runner_test.js +++ b/tests/core/test_runner_test.js @@ -42,10 +42,10 @@ suite('test runner', () => { test('failures count is one with one failed test', async() => { await withRunner(async(runner, asserter) => { - const suite = suiteNamed('with one failure'); + const suiteWithAFailure = suiteNamed('with one failure'); const failingTest = aFailingTest(asserter); - suite.addTest(failingTest); - runner.addSuite(suite); + suiteWithAFailure.addTest(failingTest); + runner.addSuite(suiteWithAFailure); await runner.run(); assert.isTrue(runner.hasErrorsOrFailures()); @@ -66,10 +66,10 @@ suite('test runner', () => { test('errors count is one with an errored test', async() => { await withRunner(async(runner, asserter) => { - const suite = suiteNamed('with one error'); + const suiteWithAnError = suiteNamed('with one error'); const erroredTest = anErroredTest(asserter); - suite.addTest(erroredTest); - runner.addSuite(suite); + suiteWithAnError.addTest(erroredTest); + runner.addSuite(suiteWithAnError); await runner.run(); assert.isTrue(runner.hasErrorsOrFailures()); @@ -80,18 +80,18 @@ suite('test runner', () => { test('counting several errors and failures', async() => { await withRunner(async(runner, asserter) => { - const suite = suiteNamed('with errors and failures'); + const suiteWithAErrorsAndFailures = suiteNamed('with errors and failures'); const errorOne = anErroredTest(asserter); const errorTwo = anErroredTest(asserter); const errorThree = anErroredTest(asserter); const failureOne = aFailingTest(asserter); const failureTwo = aFailingTest(asserter); - suite.addTest(errorOne); - suite.addTest(failureOne); - suite.addTest(errorTwo); - suite.addTest(errorThree); - suite.addTest(failureTwo); - runner.addSuite(suite); + suiteWithAErrorsAndFailures.addTest(errorOne); + suiteWithAErrorsAndFailures.addTest(failureOne); + suiteWithAErrorsAndFailures.addTest(errorTwo); + suiteWithAErrorsAndFailures.addTest(errorThree); + suiteWithAErrorsAndFailures.addTest(failureTwo); + runner.addSuite(suiteWithAErrorsAndFailures); await runner.run(); assert.that(runner.errorsCount()).isEqualTo(3); diff --git a/tests/core/test_suite_test.js b/tests/core/test_suite_test.js index eebb6a9a..71864823 100644 --- a/tests/core/test_suite_test.js +++ b/tests/core/test_suite_test.js @@ -51,32 +51,51 @@ suite('test suite behavior', () => { .raises(new Error(TestSuite.hookWasNotInitializedWithAFunctionErrorMessage(TestSuite.AFTER_HOOK_NAME))); }); - test('after hook can be used', async() => { - let afterTestVar = 10; + test('before() and after() hooks are executed in the right order', async() => { + const hookExecutions = ['start']; mySuite.before(() => { - afterTestVar = 9; + hookExecutions.push('before'); }); mySuite.after(() => { - afterTestVar = 0; + hookExecutions.push('after'); }); mySuite.addTest(passingTest); await runner.run(); - assert.that(afterTestVar).isEqualTo(0); + + assert.that(hookExecutions).includesExactly('start', 'before', 'after'); }); - test('before() and after() can be used asynchronously', async() => { - let afterTestVar = 10; + test('before() and after() on their asynchronous versions are executed in the right order', async() => { + const hookExecutions = ['start']; mySuite.before(async() => { - Promise.resolve(9).then(value => afterTestVar = value); + Promise.resolve('before').then(value => hookExecutions.push(value)); }); mySuite.after(async() => { - Promise.resolve(0).then(value => afterTestVar = value); + Promise.resolve('after').then(value => hookExecutions.push(value)); + }); + mySuite.addTest(passingTest); + await runner.run(); + + assert.that(hookExecutions).includesExactly('start', 'before', 'after'); + }); + + test('before() and after() hooks are executed once per test, no matter the result of each test', async() => { + const hookExecutions = ['start']; + + mySuite.before(() => { + hookExecutions.push('before'); + }); + mySuite.after(() => { + hookExecutions.push('after'); }); mySuite.addTest(passingTest); + mySuite.addTest(failingTest); + mySuite.addTest(erroredTest); await runner.run(); - assert.that(afterTestVar).isEqualTo(0); + + assert.that(hookExecutions).includesExactly('start', 'before', 'after', 'before', 'after', 'before', 'after'); }); test('reporting failures and errors', async() => { diff --git a/tests/core/test_test.js b/tests/core/test_test.js index 1e1673a8..ef37ba1c 100644 --- a/tests/core/test_test.js +++ b/tests/core/test_test.js @@ -47,10 +47,10 @@ suite('tests behavior', () => { }); test('a test fails on the first assertion failed', async() => { - await withRunner(async(runner, assert) => { + await withRunner(async(runner, asserter) => { const test = aTestWithBody(() => { - assert.isNotEmpty([]); - assert.areEqual(2, 3); + asserter.isNotEmpty([]); + asserter.areEqual(2, 3); }); const result = await runSingleTest(runner, test); @@ -60,8 +60,8 @@ suite('tests behavior', () => { }); test('a before() hook that fails makes the test fail', async() => { - await withRunner(async(runner, assert) => { - const test = aTestWithBody(() => assert.isEmpty([])); + await withRunner(async(runner, asserter) => { + const test = aTestWithBody(() => asserter.isEmpty([])); const before = () => { throw 'oops I did it again'; }; @@ -73,8 +73,8 @@ suite('tests behavior', () => { }); test('an after() hook that fails makes the test fail', async() => { - await withRunner(async(runner, assert) => { - const test = aTestWithBody(() => assert.isEmpty([])); + await withRunner(async(runner, asserter) => { + const test = aTestWithBody(() => asserter.isEmpty([])); const after = () => { throw 'oops I did it again'; }; diff --git a/tests/ui/formatter_test.js b/tests/ui/formatter_test.js index 70bfa9ad..7917e93c 100644 --- a/tests/ui/formatter_test.js +++ b/tests/ui/formatter_test.js @@ -26,9 +26,9 @@ suite('formatter', () => { test('display pending status in yellow including reason', async() => { await withRunner(async(runner, _assert, _fail, pending) => { - const test = aTestWithBody(() => pending.dueTo('in a rush')); - await runSingleTest(runner, test); - formatter.displayPendingResult(test); + const pendingTest = aTestWithBody(() => pending.dueTo('in a rush')); + await runSingleTest(runner, pendingTest); + formatter.displayPendingResult(pendingTest); const testResultMessage = '[\u001b[33m\u001b[1mWIP\u001b[0m] \u001b[33mjust a test\u001b[0m'; const pendingReasonMessage = ' => in a rush'; assert.that(fakeConsole.messages()).isEqualTo([testResultMessage, pendingReasonMessage]); @@ -37,9 +37,9 @@ suite('formatter', () => { test('display error status in red when not specifying a reason', async() => { await withRunner(async(runner, _assert, _fail, pending) => { - const test = aTestWithBody(() => pending.dueTo()); - await runSingleTest(runner, test); - formatter.displayErrorResult(test); + const pendingTest = aTestWithBody(() => pending.dueTo()); + await runSingleTest(runner, pendingTest); + formatter.displayErrorResult(pendingTest); const testResultMessage = '[\u001b[31m\u001b[1mERROR\u001b[0m] \u001b[31mjust a test\u001b[0m'; const pendingReasonMessage = ' => In order to mark a test as pending, you need to specify a reason.'; assert.that(fakeConsole.messages()).isEqualTo([testResultMessage, pendingReasonMessage]); @@ -48,9 +48,9 @@ suite('formatter', () => { test('display failure status in red including reason', async() => { await withRunner(async(runner, _assert, fail) => { - const test = aTestWithBody(() => fail.with('I wanted to fail')); - await runSingleTest(runner, test); - formatter.displayFailureResult(test); + const failedTest = aTestWithBody(() => fail.with('I wanted to fail')); + await runSingleTest(runner, failedTest); + formatter.displayFailureResult(failedTest); const testResultMessage = '[\u001b[31m\u001b[1mFAIL\u001b[0m] \u001b[31mjust a test\u001b[0m'; const failureDetailMessage = ' => I wanted to fail'; assert.that(fakeConsole.messages()).isEqualTo([testResultMessage, failureDetailMessage]); @@ -59,9 +59,9 @@ suite('formatter', () => { test('display failure status in red including default explicit failure reason', async() => { await withRunner(async(runner, _assert, fail) => { - const test = aTestWithBody(() => fail.with()); - await runSingleTest(runner, test); - formatter.displayFailureResult(test); + const failedTest = aTestWithBody(() => fail.with()); + await runSingleTest(runner, failedTest); + formatter.displayFailureResult(failedTest); const testResultMessage = '[\u001b[31m\u001b[1mFAIL\u001b[0m] \u001b[31mjust a test\u001b[0m'; const failureDetailMessage = ' => Explicitly failed'; assert.that(fakeConsole.messages()).isEqualTo([testResultMessage, failureDetailMessage]); @@ -70,9 +70,9 @@ suite('formatter', () => { test('display pending status in yellow and no reason if the test is empty', async() => { await withRunner(async runner => { - const test = aPendingTest(); - await runSingleTest(runner, test); - formatter.displayPendingResult(test); + const pendingTest = aPendingTest(); + await runSingleTest(runner, pendingTest); + formatter.displayPendingResult(pendingTest); const testResultMessage = '[\u001b[33m\u001b[1mWIP\u001b[0m] \u001b[33ma work in progress\u001b[0m'; assert.that(fakeConsole.messages()).includesExactly(testResultMessage); });