Skip to content
Permalink
Browse files
fix(assertions): Ensure correct 'actual' and 'expected' values are ca…
…ptured when an Expectation fail

`Ensure` now also emits an AssertionReport artifact to make reporting on failed expectations easier
  • Loading branch information
jan-molak committed Nov 24, 2019
1 parent da3eaa3 commit e503e553f74e0ce2ff07149ebe3363e6bc30302b
Showing with 198 additions and 58 deletions.
  1. +23 −19 packages/assertions/spec/Ensure.spec.ts
  2. +10 −2 packages/assertions/spec/expectations/and.spec.ts
  3. +5 −1 packages/assertions/spec/expectations/contain.spec.ts
  4. +10 −2 packages/assertions/spec/expectations/containAtLeastOneItemThat.spec.ts
  5. +10 −2 packages/assertions/spec/expectations/containItemsWhereEachItem.spec.ts
  6. +5 −1 packages/assertions/spec/expectations/endsWith.spec.ts
  7. +5 −1 packages/assertions/spec/expectations/equals.spec.ts
  8. +5 −1 packages/assertions/spec/expectations/includes.spec.ts
  9. +5 −1 packages/assertions/spec/expectations/isAfter.spec.ts
  10. +5 −1 packages/assertions/spec/expectations/isBefore.spec.ts
  11. +5 −1 packages/assertions/spec/expectations/isGreaterThan.spec.ts
  12. +5 −1 packages/assertions/spec/expectations/isLessThan.spec.ts
  13. +5 −1 packages/assertions/spec/expectations/matches.spec.ts
  14. +55 −11 packages/assertions/spec/expectations/not.spec.ts
  15. +5 −1 packages/assertions/spec/expectations/or.spec.ts
  16. +5 −1 packages/assertions/spec/expectations/property.spec.ts
  17. +5 −1 packages/assertions/spec/expectations/startsWith.spec.ts
  18. +6 −6 packages/assertions/src/Ensure.ts
  19. +3 −3 packages/assertions/src/expectations/property.ts
  20. +7 −0 packages/core/src/model/artifacts/AssertionReport.ts
  21. +7 −0 packages/core/src/model/artifacts/LogEntry.ts
  22. +2 −0 packages/core/src/model/artifacts/index.ts
  23. +5 −1 packages/serenity-bdd/src/stage/serenity-bdd-reporter/strategies/SceneReportingStrategy.ts
@@ -2,7 +2,7 @@ import 'mocha';

import { EventRecorder, expect, PickEvent, stage } from '@integration/testing-tools';
import { Actor, Answerable, AnswersQuestions, AssertionError, LogicError, Question, RuntimeError, Stage, TestCompromisedError } from '@serenity-js/core';
import { ArtifactGenerated } from '@serenity-js/core/lib/events';
import { ActivityRelatedArtifactGenerated } from '@serenity-js/core/lib/events';
import { Name } from '@serenity-js/core/lib/model';
import { given } from 'mocha-testdata';
import { Ensure, equals, Expectation, Outcome } from '../src';
@@ -79,45 +79,49 @@ describe('Ensure', () => {

given([{
description: 'tiny type',
expected: new Name('Alice'),
actual: new Name('Bob'),
expected: 'Name(value=Bob)',
artifact: { expected: 'Name(value=Alice)', actual: 'Name(value=Bob)' },
}, {
description: 'boolean',
actual: true,
expected: 'true',
expected: true,
actual: false,
artifact: { expected: 'true', actual: 'false' },
}, {
description: 'string',
actual: 'name',
expected: `'name'`,
expected: 'name',
actual: 'not-name',
artifact: { expected: `'name'`, actual: `'not-name'` },
}, {
description: 'list',
actual: [{ name: 'Bob' }, { name: 'Alice' }],
expected: `[\n { name: 'Bob' },\n { name: 'Alice' }\n]`,
expected: [{ name: 'Bob' }, { name: 'Alice' }],
actual: [{ name: 'Alice' }],
artifact: { expected: `[\n { name: 'Bob' },\n { name: 'Alice' }\n]`, actual: `[\n { name: 'Alice' }\n]` },
}, {
description: 'promise',
actual: Promise.resolve(true),
expected: `true`,
expected: Promise.resolve(true),
actual: Promise.resolve(false),
artifact: { expected: `true`, actual: `false` },
}, {
description: 'question',
actual: Question.about('some value', actor => 'value'),
expected: `'value'`,
expected: Question.about('some value', actor => true),
actual: Question.about('some value', actor => false),
artifact: { expected: 'true', actual: 'false' },
}]).
/** @test {Ensure.that} */
it('emits an artifact describing the actual value', ({ actual, expected }) => {
it('emits an artifact describing the actual and expected values', ({ actual, expected, artifact }) => {
const recorder = new EventRecorder();
theStage.assign(recorder);

return expect(Enrique.attemptsTo(
Ensure.that(actual, equals(null)), // we don't care about the expectation itself in this test
Ensure.that(actual, equals(expected)), // we don't care about the expectation itself in this test
)).to.be.rejected.then(() =>

PickEvent.from(recorder.events)
.next(ArtifactGenerated, e => e.artifact.map(value => {
expect(value.contentType).to.equal('text/plain');
expect(value.data).to.equal(expected);
.next(ActivityRelatedArtifactGenerated, e => e.artifact.map(value => {
expect(value.expected).to.equal(artifact.expected);
expect(value.actual).to.equal(artifact.actual);
})),
);

});

describe('custom errors', () => {
@@ -21,14 +21,22 @@ describe('and', () => {
it('does not meet the first expectation', () => {
return expect(Astrid.attemptsTo(
Ensure.that('Hello World!', and(startsWith('¡Hola'), endsWith('World!'))),
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to start with '¡Hola'`);
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to start with '¡Hola'`)
.then((error: AssertionError) => {
expect(error.expected.toString()).to.equal('¡Hola');
expect(error.actual).to.equal('Hello World!');
});
});

/** @test {and} */
it('does not meet the second expectation', () => {
return expect(Astrid.attemptsTo(
Ensure.that('Hello World!', and(startsWith('Hello'), endsWith('Mundo!'))),
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to end with 'Mundo!`);
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to end with 'Mundo!`)
.then((error: AssertionError) => {
expect(error.expected.toString()).to.equal('Mundo!');
expect(error.actual).to.equal('Hello World!');
});
});
});

@@ -19,7 +19,11 @@ describe('contain', () => {
it('breaks the actor flow when "actual" does not contain the "expected" text', () => {
return expect(Astrid.attemptsTo(
Ensure.that([ 'Hello', 'World' ], contain('Mundo')),
)).to.be.rejectedWith(AssertionError, `Expected [ 'Hello', 'World' ] to contain 'Mundo'`);
)).to.be.rejectedWith(AssertionError, `Expected [ 'Hello', 'World' ] to contain 'Mundo'`)
.then((error: AssertionError) => {
expect(error.expected.toString()).to.equal('Mundo');
expect(error.actual).to.deep.equal([ 'Hello', 'World' ]);
});
});

/** @test {contains} */
@@ -19,14 +19,22 @@ describe('containAtLeastOneItemThat', () => {
it('breaks the actor flow when "actual" does not include at least one item that meets the expectation', () => {
return expect(Astrid.attemptsTo(
Ensure.that([ 0, 1, 2 ], containAtLeastOneItemThat(equals(7))),
)).to.be.rejectedWith(AssertionError, `Expected [ 0, 1, 2 ] to contain at least one item that does equal 7`);
)).to.be.rejectedWith(AssertionError, `Expected [ 0, 1, 2 ] to contain at least one item that does equal 7`)
.then((error: AssertionError) => {
expect(error.expected).to.equal(7);
expect(error.actual).to.deep.equal([ 0, 1, 2 ]);
});
});

/** @test {containAtLeastOneItemThat} */
it('breaks the actor flow when "actual" is an empty list', () => {
return expect(Astrid.attemptsTo(
Ensure.that([], containAtLeastOneItemThat(equals(42))),
)).to.be.rejectedWith(AssertionError, `Expected [ ] to contain at least one item that does equal 42`);
)).to.be.rejectedWith(AssertionError, `Expected [ ] to contain at least one item that does equal 42`)
.then((error: AssertionError) => {
expect(error.expected).to.equal(null);
expect(error.actual).to.deep.equal([ ]);
});
});

/** @test {atLeastOne} */
@@ -19,14 +19,22 @@ describe('containItemsWhereEachItem', () => {
it('breaks the actor flow when "actual" contains at least one item that does not meet the expectation', () => {
return expect(Astrid.attemptsTo(
Ensure.that([ 7, 7, 2 ], containItemsWhereEachItem(equals(7))),
)).to.be.rejectedWith(AssertionError, `Expected [ 7, 7, 2 ] to contain items where each item does equal 7`);
)).to.be.rejectedWith(AssertionError, `Expected [ 7, 7, 2 ] to contain items where each item does equal 7`)
.then((error: AssertionError) => {
expect(error.expected).to.equal(7);
expect(error.actual).to.deep.equal([ 7, 7, 2 ]);
});
});

/** @test {containItemsWhereEachItem} */
it('breaks the actor flow when "actual" is an empty list', () => {
return expect(Astrid.attemptsTo(
Ensure.that([], containItemsWhereEachItem(equals(42))),
)).to.be.rejectedWith(AssertionError, `Expected [ ] to contain items where each item does equal 42`);
)).to.be.rejectedWith(AssertionError, `Expected [ ] to contain items where each item does equal 42`)
.then((error: AssertionError) => {
expect(error.expected).to.equal(null);
expect(error.actual).to.deep.equal([]);
});
});

/** @test {atLeastOne} */
@@ -19,7 +19,11 @@ describe('endsWith', () => {
it('breaks the actor flow when "actual" does not end with "expected"', () => {
return expect(Astrid.attemptsTo(
Ensure.that('Hello World!', endsWith('Mundo!')),
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to end with 'Mundo!'`);
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to end with 'Mundo!'`)
.then((error: AssertionError) => {
expect(error.expected).to.equal('Mundo!');
expect(error.actual).to.equal('Hello World!');
});
});

/** @test {endsWith} */
@@ -32,7 +32,11 @@ describe('equals', () => {
it('breaks the actor flow when the values of "actual" and "expected" don\'t match', () => {
return expect(Astrid.attemptsTo(
Ensure.that(27, equals(42)),
)).to.be.rejectedWith(AssertionError, 'Expected 27 to equal 42');
)).to.be.rejectedWith(AssertionError, 'Expected 27 to equal 42')
.then((error: AssertionError) => {
expect(error.expected).to.equal(42);
expect(error.actual).to.equal(27);
});
});

/** @test {equals} */
@@ -19,7 +19,11 @@ describe('includes', () => {
it('breaks the actor flow when "actual" does not include the "expected" text', () => {
return expect(Astrid.attemptsTo(
Ensure.that('Hello World!', includes('Mundo')),
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to include 'Mundo'`);
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to include 'Mundo'`)
.then((error: AssertionError) => {
expect(error.expected).to.equal('Mundo');
expect(error.actual).to.equal('Hello World!');
});
});

/** @test {includes} */
@@ -19,7 +19,11 @@ describe('isAfter', () => {
it('breaks the actor flow when "actual" is not after the "expected"', () => {
return expect(Astrid.attemptsTo(
Ensure.that(new Date('1985-01-01'), isAfter(new Date('1995-01-01'))),
)).to.be.rejectedWith(AssertionError, `Expected 1985-01-01T00:00:00.000Z to have value that is after 1995-01-01T00:00:00.000Z`);
)).to.be.rejectedWith(AssertionError, `Expected 1985-01-01T00:00:00.000Z to have value that is after 1995-01-01T00:00:00.000Z`)
.then((error: AssertionError) => {
expect(error.expected).to.deep.equal(new Date('1995-01-01'));
expect(error.actual).to.deep.equal(new Date('1985-01-01'));
});
});

/** @test {isAfter} */
@@ -19,7 +19,11 @@ describe('isBefore', () => {
it('breaks the actor flow when "actual" is not before the "expected"', () => {
return expect(Astrid.attemptsTo(
Ensure.that(new Date('1995-01-01'), isBefore(new Date('1985-01-01'))),
)).to.be.rejectedWith(AssertionError, `Expected 1995-01-01T00:00:00.000Z to have value that is before 1985-01-01T00:00:00.000Z`);
)).to.be.rejectedWith(AssertionError, `Expected 1995-01-01T00:00:00.000Z to have value that is before 1985-01-01T00:00:00.000Z`)
.then((error: AssertionError) => {
expect(error.expected).to.deep.equal(new Date('1985-01-01'));
expect(error.actual).to.deep.equal(new Date('1995-01-01'));
});
});

/** @test {isBefore} */
@@ -19,7 +19,11 @@ describe('isGreaterThan', () => {
it('breaks the actor flow when "actual" is not greater than "expected"', () => {
return expect(Astrid.attemptsTo(
Ensure.that(0, isGreaterThan(2)),
)).to.be.rejectedWith(AssertionError, `Expected 0 to have value greater than 2`);
)).to.be.rejectedWith(AssertionError, `Expected 0 to have value greater than 2`)
.then((error: AssertionError) => {
expect(error.expected).to.equal(2);
expect(error.actual).to.equal(0);
});
});

/** @test {isGreaterThan} */
@@ -19,7 +19,11 @@ describe('isLessThan', () => {
it('breaks the actor flow when "actual" is not less than "expected"', () => {
return expect(Astrid.attemptsTo(
Ensure.that(3, isLessThan(2)),
)).to.be.rejectedWith(AssertionError, `Expected 3 to have value that's less than 2`);
)).to.be.rejectedWith(AssertionError, `Expected 3 to have value that's less than 2`)
.then((error: AssertionError) => {
expect(error.expected).to.equal(2);
expect(error.actual).to.equal(3);
});
});

/** @test {isLessThan} */
@@ -19,7 +19,11 @@ describe('matches', () => {
it('breaks the actor flow when "actual" does not match the "expected"', () => {
return expect(Astrid.attemptsTo(
Ensure.that('Hello World!', matches(/mundo$/gi)),
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to match /mundo$/gi`);
)).to.be.rejectedWith(AssertionError, `Expected 'Hello World!' to match /mundo$/gi`)
.then((error: AssertionError) => {
expect(error.expected.toString()).to.equal('/mundo$/gi');
expect(error.actual).to.equal('Hello World!');
});
});

/** @test {matches} */

0 comments on commit e503e55

Please sign in to comment.