@serenity-js/assertions 3.0.0-rc.4 → 3.0.0-rc.41
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +72 -1837
- package/README.md +14 -12
- package/lib/Ensure.d.ts +53 -86
- package/lib/Ensure.d.ts.map +1 -0
- package/lib/Ensure.js +81 -130
- package/lib/Ensure.js.map +1 -1
- package/lib/expectations/and.d.ts +22 -1
- package/lib/expectations/and.d.ts.map +1 -0
- package/lib/expectations/and.js +32 -7
- package/lib/expectations/and.js.map +1 -1
- package/lib/expectations/contain.d.ts +27 -2
- package/lib/expectations/contain.d.ts.map +1 -0
- package/lib/expectations/contain.js +25 -5
- package/lib/expectations/contain.js.map +1 -1
- package/lib/expectations/containAtLeastOneItemThat.d.ts +23 -1
- package/lib/expectations/containAtLeastOneItemThat.d.ts.map +1 -0
- package/lib/expectations/containAtLeastOneItemThat.js +39 -10
- package/lib/expectations/containAtLeastOneItemThat.js.map +1 -1
- package/lib/expectations/containItemsWhereEachItem.d.ts +23 -1
- package/lib/expectations/containItemsWhereEachItem.d.ts.map +1 -0
- package/lib/expectations/containItemsWhereEachItem.js +39 -10
- package/lib/expectations/containItemsWhereEachItem.js.map +1 -1
- package/lib/expectations/endsWith.d.ts +22 -2
- package/lib/expectations/endsWith.d.ts.map +1 -0
- package/lib/expectations/endsWith.js +20 -5
- package/lib/expectations/endsWith.js.map +1 -1
- package/lib/expectations/equals.d.ts +28 -2
- package/lib/expectations/equals.d.ts.map +1 -0
- package/lib/expectations/equals.js +26 -5
- package/lib/expectations/equals.js.map +1 -1
- package/lib/expectations/includes.d.ts +22 -2
- package/lib/expectations/includes.d.ts.map +1 -0
- package/lib/expectations/includes.js +20 -5
- package/lib/expectations/includes.js.map +1 -1
- package/lib/expectations/index.d.ts +3 -0
- package/lib/expectations/index.d.ts.map +1 -0
- package/lib/expectations/index.js +7 -1
- package/lib/expectations/index.js.map +1 -1
- package/lib/expectations/isAfter.d.ts +42 -2
- package/lib/expectations/isAfter.d.ts.map +1 -0
- package/lib/expectations/isAfter.js +40 -5
- package/lib/expectations/isAfter.js.map +1 -1
- package/lib/expectations/isBefore.d.ts +42 -2
- package/lib/expectations/isBefore.d.ts.map +1 -0
- package/lib/expectations/isBefore.js +40 -5
- package/lib/expectations/isBefore.js.map +1 -1
- package/lib/expectations/isCloseTo.d.ts +24 -0
- package/lib/expectations/isCloseTo.d.ts.map +1 -0
- package/lib/expectations/isCloseTo.js +37 -0
- package/lib/expectations/isCloseTo.js.map +1 -0
- package/lib/expectations/isFalse.d.ts +19 -0
- package/lib/expectations/isFalse.d.ts.map +1 -0
- package/lib/expectations/isFalse.js +18 -0
- package/lib/expectations/isFalse.js.map +1 -1
- package/lib/expectations/isGreaterThan.d.ts +45 -2
- package/lib/expectations/isGreaterThan.d.ts.map +1 -0
- package/lib/expectations/isGreaterThan.js +43 -5
- package/lib/expectations/isGreaterThan.js.map +1 -1
- package/lib/expectations/isLessThan.d.ts +45 -2
- package/lib/expectations/isLessThan.d.ts.map +1 -0
- package/lib/expectations/isLessThan.js +43 -5
- package/lib/expectations/isLessThan.js.map +1 -1
- package/lib/expectations/isPresent.d.ts +64 -0
- package/lib/expectations/isPresent.d.ts.map +1 -0
- package/lib/expectations/isPresent.js +99 -0
- package/lib/expectations/isPresent.js.map +1 -0
- package/lib/expectations/isTrue.d.ts +19 -0
- package/lib/expectations/isTrue.d.ts.map +1 -0
- package/lib/expectations/isTrue.js +18 -0
- package/lib/expectations/isTrue.js.map +1 -1
- package/lib/expectations/matches.d.ts +22 -2
- package/lib/expectations/matches.d.ts.map +1 -0
- package/lib/expectations/matches.js +20 -5
- package/lib/expectations/matches.js.map +1 -1
- package/lib/expectations/not.d.ts +23 -1
- package/lib/expectations/not.d.ts.map +1 -0
- package/lib/expectations/not.js +33 -12
- package/lib/expectations/not.js.map +1 -1
- package/lib/expectations/or.d.ts +22 -1
- package/lib/expectations/or.d.ts.map +1 -0
- package/lib/expectations/or.js +40 -15
- package/lib/expectations/or.js.map +1 -1
- package/lib/expectations/property.d.ts +61 -1
- package/lib/expectations/property.d.ts.map +1 -0
- package/lib/expectations/property.js +67 -10
- package/lib/expectations/property.js.map +1 -1
- package/lib/expectations/startsWith.d.ts +22 -2
- package/lib/expectations/startsWith.d.ts.map +1 -0
- package/lib/expectations/startsWith.js +20 -5
- package/lib/expectations/startsWith.js.map +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +5 -5
- package/lib/index.js.map +1 -1
- package/package.json +17 -41
- package/src/Ensure.ts +88 -146
- package/src/expectations/and.ts +43 -18
- package/src/expectations/contain.ts +30 -5
- package/src/expectations/containAtLeastOneItemThat.ts +68 -14
- package/src/expectations/containItemsWhereEachItem.ts +68 -14
- package/src/expectations/endsWith.ts +25 -5
- package/src/expectations/equals.ts +31 -5
- package/src/expectations/includes.ts +25 -5
- package/src/expectations/index.ts +2 -0
- package/src/expectations/isAfter.ts +45 -5
- package/src/expectations/isBefore.ts +45 -5
- package/src/expectations/isCloseTo.ts +40 -0
- package/src/expectations/isFalse.ts +18 -0
- package/src/expectations/isGreaterThan.ts +48 -5
- package/src/expectations/isLessThan.ts +48 -5
- package/src/expectations/isPresent.ts +107 -0
- package/src/expectations/isTrue.ts +18 -0
- package/src/expectations/matches.ts +25 -5
- package/src/expectations/not.ts +38 -15
- package/src/expectations/or.ts +51 -26
- package/src/expectations/property.ts +80 -20
- package/src/expectations/startsWith.ts +25 -5
- package/src/index.ts +0 -1
- package/tsconfig.build.json +10 -0
- package/tsconfig.eslint.json +0 -10
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@serenity-js/assertions",
|
|
3
|
-
"version": "3.0.0-rc.
|
|
3
|
+
"version": "3.0.0-rc.41",
|
|
4
4
|
"description": "Screenplay-style assertion library",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Jan Molak",
|
|
@@ -26,58 +26,34 @@
|
|
|
26
26
|
"testing"
|
|
27
27
|
],
|
|
28
28
|
"scripts": {
|
|
29
|
-
"clean": "rimraf
|
|
30
|
-
"
|
|
31
|
-
"
|
|
32
|
-
"test": "nyc --report-dir ../../target/coverage/assertions mocha --config ../../.mocharc.yml 'spec/**/*.spec.*'",
|
|
33
|
-
"compile": "tsc --project tsconfig.json",
|
|
34
|
-
"site": "esdoc -c .esdoc.js"
|
|
29
|
+
"clean": "rimraf '../../target/coverage/assertions'",
|
|
30
|
+
"test": "nyc mocha --config ../../.mocharc.yml 'spec/**/*.spec.*'",
|
|
31
|
+
"compile": "rimraf lib && tsc --project tsconfig.build.json"
|
|
35
32
|
},
|
|
36
33
|
"repository": {
|
|
37
34
|
"type": "git",
|
|
38
|
-
"url": "https://github.com/serenity-js/serenity-js.git"
|
|
35
|
+
"url": "https://github.com/serenity-js/serenity-js.git",
|
|
36
|
+
"directory": "packages/assertions"
|
|
39
37
|
},
|
|
40
38
|
"bugs": {
|
|
41
39
|
"url": "https://github.com/serenity-js/serenity-js/issues"
|
|
42
40
|
},
|
|
43
41
|
"engines": {
|
|
44
|
-
"node": "^14 || ^16",
|
|
42
|
+
"node": "^14 || ^16 || ^18",
|
|
45
43
|
"npm": "^6 || ^7 || ^8"
|
|
46
44
|
},
|
|
47
45
|
"dependencies": {
|
|
48
|
-
"@serenity-js/core": "3.0.0-rc.
|
|
49
|
-
"tiny-types": "^1.
|
|
46
|
+
"@serenity-js/core": "3.0.0-rc.41",
|
|
47
|
+
"tiny-types": "^1.19.0"
|
|
50
48
|
},
|
|
51
49
|
"devDependencies": {
|
|
52
|
-
"@documentation/esdoc-template": "3.0.0",
|
|
53
50
|
"@integration/testing-tools": "3.0.0",
|
|
54
|
-
"@types/chai": "^4.3.
|
|
55
|
-
"@types/mocha": "^
|
|
56
|
-
"mocha": "^
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
"src/**/*.ts"
|
|
63
|
-
],
|
|
64
|
-
"exclude": [
|
|
65
|
-
"src/**/*.d.ts",
|
|
66
|
-
"lib",
|
|
67
|
-
"node_modules",
|
|
68
|
-
"spec"
|
|
69
|
-
],
|
|
70
|
-
"extension": [
|
|
71
|
-
".ts"
|
|
72
|
-
],
|
|
73
|
-
"require": [
|
|
74
|
-
"ts-node/register"
|
|
75
|
-
],
|
|
76
|
-
"reporter": [
|
|
77
|
-
"json"
|
|
78
|
-
],
|
|
79
|
-
"cache": true,
|
|
80
|
-
"all": true
|
|
81
|
-
},
|
|
82
|
-
"gitHead": "126a1cad42bcb1416ca68e62f54bf0d3eb3ea157"
|
|
51
|
+
"@types/chai": "^4.3.4",
|
|
52
|
+
"@types/mocha": "^10.0.1",
|
|
53
|
+
"mocha": "^10.2.0",
|
|
54
|
+
"nyc": "15.1.0",
|
|
55
|
+
"ts-node": "^10.9.1",
|
|
56
|
+
"typescript": "^4.9.4"
|
|
57
|
+
},
|
|
58
|
+
"gitHead": "e74f8f4989f18fe37edde3f8500b2084289d385b"
|
|
83
59
|
}
|
package/src/Ensure.ts
CHANGED
|
@@ -1,202 +1,144 @@
|
|
|
1
1
|
import {
|
|
2
|
+
Activity,
|
|
2
3
|
Answerable,
|
|
3
4
|
AnswersQuestions,
|
|
4
5
|
AssertionError,
|
|
5
6
|
CollectsArtifacts,
|
|
7
|
+
d,
|
|
6
8
|
Expectation,
|
|
7
9
|
ExpectationMet,
|
|
8
10
|
ExpectationNotMet,
|
|
9
|
-
|
|
11
|
+
f,
|
|
10
12
|
Interaction,
|
|
11
13
|
LogicError,
|
|
14
|
+
RaiseErrors,
|
|
12
15
|
RuntimeError,
|
|
13
16
|
UsesAbilities,
|
|
14
17
|
} from '@serenity-js/core';
|
|
15
|
-
import {
|
|
16
|
-
import { inspected } from '@serenity-js/core/lib/io/inspected';
|
|
17
|
-
import { Artifact, AssertionReport, Name } from '@serenity-js/core/lib/model';
|
|
18
|
-
import { match } from 'tiny-types';
|
|
18
|
+
import { FileSystemLocation } from '@serenity-js/core/lib/io';
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
|
-
* @
|
|
22
|
-
*
|
|
21
|
+
* The {@apilink Interaction|interaction} to `Ensure`
|
|
22
|
+
* verifies if the resolved value of the provided {@apilink Answerable}
|
|
23
|
+
* meets the specified {@apilink Expectation}.
|
|
24
|
+
* If not, it throws an {@apilink AssertionError}.
|
|
23
25
|
*
|
|
24
|
-
*
|
|
25
|
-
* state and ensures that its value meets the {@link @serenity-js/core/lib/screenplay/questions~Expectation}s provided.
|
|
26
|
+
* Use `Ensure` to verify the state of the system under test.
|
|
26
27
|
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
29
|
-
*
|
|
28
|
+
* ## Basic usage with static values
|
|
29
|
+
* ```ts
|
|
30
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
31
|
+
* import { Ensure, equals } from '@serenity-js/assertions'
|
|
30
32
|
*
|
|
31
|
-
*
|
|
33
|
+
* await actorCalled('Erica').attemptsTo(
|
|
34
|
+
* Ensure.that('Hello world!', equals('Hello world!'))
|
|
35
|
+
* )
|
|
36
|
+
* ```
|
|
32
37
|
*
|
|
33
|
-
*
|
|
34
|
-
* Ensure.that('Hello world!', equals('Hello world!'))
|
|
35
|
-
* );
|
|
38
|
+
* ## Composing expectations with `and`
|
|
36
39
|
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
+
* ```ts
|
|
41
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
42
|
+
* import { and, Ensure, startsWith, endsWith } from '@serenity-js/assertions'
|
|
40
43
|
*
|
|
41
|
-
*
|
|
44
|
+
* await actorCalled('Erica').attemptsTo(
|
|
45
|
+
* Ensure.that('Hello world!', and(startsWith('Hello'), endsWith('!'))
|
|
46
|
+
* )
|
|
47
|
+
* ```
|
|
42
48
|
*
|
|
43
|
-
*
|
|
44
|
-
* Ensure.that('Hello world!', and(startsWith('Hello'), endsWith('!'))
|
|
45
|
-
* );
|
|
49
|
+
* ## Overriding the type of Error thrown upon assertion failure
|
|
46
50
|
*
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { actorCalled, TestCompromisedError } from '@serenity-js/core'
|
|
53
|
+
* import { and, Ensure, startsWith, endsWith } from '@serenity-js/assertions'
|
|
54
|
+
* import { CallAnApi, GetRequest, LastResponse, Send } from '@serenity-js/rest'
|
|
51
55
|
*
|
|
52
|
-
*
|
|
53
|
-
*
|
|
56
|
+
* await actorCalled('Erica')
|
|
57
|
+
* .whoCan(CallAnApi.at('https://example.com'))
|
|
58
|
+
* .attemptsTo(
|
|
59
|
+
* Send.a(GetRequest.to('/api/health')),
|
|
60
|
+
* Ensure.that(LastResponse.status(), equals(200))
|
|
61
|
+
* .otherwiseFailWith(TestCompromisedError, 'The server is down, please cheer it up!')
|
|
62
|
+
* )
|
|
63
|
+
* ```
|
|
54
64
|
*
|
|
55
|
-
*
|
|
56
|
-
* Send.a(GetRequest.to('/api/health')),
|
|
57
|
-
* Ensure.that(LastResponse.status(), equals(200))
|
|
58
|
-
* .otherwiseFailWith(TestCompromisedError, 'The server is down, please cheer it up!')
|
|
59
|
-
* );
|
|
60
|
-
*
|
|
61
|
-
* @extends {@serenity-js/core/lib/screenplay~Interaction}
|
|
65
|
+
* @group Interactions
|
|
62
66
|
*/
|
|
63
67
|
export class Ensure<Actual> extends Interaction {
|
|
68
|
+
|
|
64
69
|
/**
|
|
70
|
+
* @param {Answerable<Actual_Type>} actual
|
|
71
|
+
* An {@apilink Answerable} describing the actual state of the system.
|
|
65
72
|
*
|
|
66
|
-
* @param {
|
|
67
|
-
* @
|
|
73
|
+
* @param {Expectation<Actual_Type>} expectation
|
|
74
|
+
* An {@apilink Expectation} you expect the `actual` value to meet
|
|
68
75
|
*
|
|
69
|
-
* @returns {Ensure<
|
|
76
|
+
* @returns {Ensure<Actual_Type>}
|
|
70
77
|
*/
|
|
71
|
-
static that<
|
|
72
|
-
return new Ensure(actual, expectation);
|
|
78
|
+
static that<Actual_Type>(actual: Answerable<Actual_Type>, expectation: Expectation<Actual_Type>): Ensure<Actual_Type> {
|
|
79
|
+
return new Ensure(actual, expectation, Activity.callerLocation(5));
|
|
73
80
|
}
|
|
74
81
|
|
|
75
82
|
/**
|
|
76
|
-
* @param
|
|
77
|
-
* @param
|
|
83
|
+
* @param actual
|
|
84
|
+
* @param expectation
|
|
85
|
+
* @param location
|
|
78
86
|
*/
|
|
79
|
-
constructor(
|
|
87
|
+
private constructor(
|
|
80
88
|
protected readonly actual: Answerable<Actual>,
|
|
81
89
|
protected readonly expectation: Expectation<Actual>,
|
|
90
|
+
location: FileSystemLocation,
|
|
82
91
|
) {
|
|
83
|
-
super();
|
|
92
|
+
super(d`#actor ensures that ${ actual } does ${ expectation }`, location);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
95
|
/**
|
|
87
|
-
* @
|
|
88
|
-
* Makes the provided {@link @serenity-js/core/lib/screenplay/actor~Actor}
|
|
89
|
-
* perform this {@link @serenity-js/core/lib/screenplay~Interaction}.
|
|
90
|
-
*
|
|
91
|
-
* @param {UsesAbilities & CollectsArtifacts & AnswersQuestions} actor
|
|
92
|
-
* @returns {Promise<void>}
|
|
93
|
-
*
|
|
94
|
-
* @see {@link @serenity-js/core/lib/screenplay/actor~Actor}
|
|
95
|
-
* @see {@link @serenity-js/core/lib/screenplay/actor~UsesAbilities}
|
|
96
|
-
* @see {@link @serenity-js/core/lib/screenplay/actor~CollectsArtifacts}
|
|
97
|
-
* @see {@link @serenity-js/core/lib/screenplay/actor~AnswersQuestions}
|
|
96
|
+
* @inheritDoc
|
|
98
97
|
*/
|
|
99
|
-
performAs(actor: UsesAbilities & AnswersQuestions & CollectsArtifacts): Promise<void> {
|
|
100
|
-
|
|
101
|
-
actor.answer(this.actual),
|
|
102
|
-
actor.answer(this.expectation),
|
|
103
|
-
]).then(([ actual, expectation ]) =>
|
|
104
|
-
expectation(actual).then(outcome =>
|
|
105
|
-
match<ExpectationOutcome<unknown, Actual>, void>(outcome)
|
|
106
|
-
.when(ExpectationNotMet, o => {
|
|
107
|
-
actor.collect(this.artifactFrom(o.expected, o.actual), new Name(`Assertion Report`));
|
|
98
|
+
async performAs(actor: UsesAbilities & AnswersQuestions & CollectsArtifacts): Promise<void> {
|
|
99
|
+
const outcome = await actor.answer(this.expectation.isMetFor(this.actual));
|
|
108
100
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
.else(o => {
|
|
113
|
-
throw new LogicError(formatted `An Expectation should return an instance of an ExpectationOutcome, not ${ o }`);
|
|
114
|
-
}),
|
|
115
|
-
),
|
|
116
|
-
);
|
|
117
|
-
}
|
|
101
|
+
if (outcome instanceof ExpectationNotMet) {
|
|
102
|
+
const actualDescription = d`${ this.actual }`;
|
|
103
|
+
const message = `Expected ${ actualDescription } to ${ outcome.message }`;
|
|
118
104
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
105
|
+
throw RaiseErrors.as(actor).create(AssertionError, {
|
|
106
|
+
message,
|
|
107
|
+
expectation: outcome.expectation,
|
|
108
|
+
diff: { expected: outcome.expected, actual: outcome.actual },
|
|
109
|
+
location: this.instantiationLocation(),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (! (outcome instanceof ExpectationMet)) {
|
|
114
|
+
throw new LogicError(f`Expectation#isMetFor(actual) should return an instance of an ExpectationOutcome, not ${ outcome }`);
|
|
115
|
+
}
|
|
127
116
|
}
|
|
128
117
|
|
|
129
118
|
/**
|
|
130
|
-
* @
|
|
131
|
-
*
|
|
132
|
-
* the actual value does not meet the expectations set.
|
|
119
|
+
* Overrides the default {@apilink AssertionError} thrown when
|
|
120
|
+
* the actual value does not meet the expectation.
|
|
133
121
|
*
|
|
134
|
-
* @param
|
|
135
|
-
*
|
|
122
|
+
* @param typeOfRuntimeError
|
|
123
|
+
* A constructor function producing a subtype of {@apilink RuntimeError} to throw, e.g. {@apilink TestCompromisedError}
|
|
136
124
|
*
|
|
137
|
-
* @param
|
|
125
|
+
* @param message
|
|
138
126
|
* The message explaining the failure
|
|
139
|
-
*
|
|
140
|
-
* @returns {@serenity-js/core/lib/screenplay~Interaction}
|
|
141
127
|
*/
|
|
142
128
|
otherwiseFailWith(typeOfRuntimeError: new (message: string, cause?: Error) => RuntimeError, message?: string): Interaction {
|
|
143
|
-
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* @desc
|
|
148
|
-
* Maps an {@link @serenity-js/core/lib/screenplay/questions/expectations~ExpectationOutcome} to appropriate {@link @serenity-js/core/lib/errors~RuntimeError}.
|
|
149
|
-
*
|
|
150
|
-
* @param {@serenity-js/core/lib/screenplay/questions/expectations~ExpectationOutcome} outcome
|
|
151
|
-
* @returns {@serenity-js/core/lib/errors~RuntimeError}
|
|
152
|
-
*
|
|
153
|
-
* @protected
|
|
154
|
-
*/
|
|
155
|
-
protected errorForOutcome(outcome: ExpectationOutcome<any, Actual>): RuntimeError {
|
|
156
|
-
return this.asAssertionError(outcome);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
/**
|
|
160
|
-
* @desc
|
|
161
|
-
* Maps an {@link Outcome} to {@link @serenity-js/core/lib/errors~AssertionError}.
|
|
162
|
-
*
|
|
163
|
-
* @param {Outcome} outcome
|
|
164
|
-
* @returns {@serenity-js/core/lib/errors~AssertionError}
|
|
165
|
-
*
|
|
166
|
-
* @protected
|
|
167
|
-
*/
|
|
168
|
-
protected asAssertionError(outcome: ExpectationOutcome<any, Actual>): AssertionError {
|
|
169
|
-
return new AssertionError(
|
|
170
|
-
`Expected ${ formatted`${ this.actual }` } to ${ outcome.message }`,
|
|
171
|
-
outcome.expected,
|
|
172
|
-
outcome.actual,
|
|
173
|
-
);
|
|
174
|
-
}
|
|
129
|
+
const location = this.instantiationLocation();
|
|
175
130
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
131
|
+
return Interaction.where(this.toString(), async actor => {
|
|
132
|
+
try {
|
|
133
|
+
await this.performAs(actor);
|
|
134
|
+
}
|
|
135
|
+
catch (error) {
|
|
136
|
+
throw RaiseErrors.as(actor).create(typeOfRuntimeError, {
|
|
137
|
+
message: message ?? error.message,
|
|
138
|
+
location,
|
|
139
|
+
cause: error
|
|
140
|
+
});
|
|
141
|
+
}
|
|
180
142
|
});
|
|
181
143
|
}
|
|
182
144
|
}
|
|
183
|
-
|
|
184
|
-
/**
|
|
185
|
-
* @package
|
|
186
|
-
*/
|
|
187
|
-
class EnsureOrFailWithCustomError<Actual> extends Ensure<Actual> {
|
|
188
|
-
constructor(
|
|
189
|
-
actual: Answerable<Actual>,
|
|
190
|
-
expectation: Expectation<Actual>,
|
|
191
|
-
private readonly typeOfRuntimeError: new (message: string, cause?: Error) => RuntimeError,
|
|
192
|
-
private readonly message?: string,
|
|
193
|
-
) {
|
|
194
|
-
super(actual, expectation);
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
protected errorForOutcome(outcome: ExpectationOutcome<any, Actual>): RuntimeError {
|
|
198
|
-
const assertionError = this.asAssertionError(outcome);
|
|
199
|
-
|
|
200
|
-
return new this.typeOfRuntimeError(this.message || assertionError.message, assertionError);
|
|
201
|
-
}
|
|
202
|
-
}
|
package/src/expectations/and.ts
CHANGED
|
@@ -1,29 +1,54 @@
|
|
|
1
|
-
import { AnswersQuestions, Expectation, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
2
|
-
import { match } from 'tiny-types';
|
|
1
|
+
import { Answerable, AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Creates an {@apilink Expectation|expectation} that is met when all the `expectations` are met for the given actual value.
|
|
5
|
+
*
|
|
6
|
+
* Use `and` to combine several expectations using logical "and",
|
|
7
|
+
*
|
|
8
|
+
* ## Combining several expectations
|
|
9
|
+
*
|
|
10
|
+
* ```ts
|
|
11
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
12
|
+
* import { Ensure, and, startsWith, endsWith } from '@serenity-js/assertions'
|
|
13
|
+
*
|
|
14
|
+
* await actorCalled('Ester').attemptsTo(
|
|
15
|
+
* Ensure.that('Hello World!', and(startsWith('Hello'), endsWith('!'))),
|
|
16
|
+
* )
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @param expectations
|
|
20
|
+
*
|
|
21
|
+
* @group Expectations
|
|
22
|
+
*/
|
|
23
|
+
export function and<Actual_Type>(...expectations: Array<Expectation<Actual_Type>>): Expectation<Actual_Type> {
|
|
5
24
|
return new And(expectations);
|
|
6
25
|
}
|
|
7
26
|
|
|
8
27
|
/**
|
|
9
28
|
* @package
|
|
10
29
|
*/
|
|
11
|
-
class And<Actual> extends Expectation<
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
30
|
+
class And<Actual> extends Expectation<Actual> {
|
|
31
|
+
private static readonly Separator = ' and ';
|
|
32
|
+
|
|
33
|
+
constructor(private readonly expectations: Array<Expectation<Actual>>) {
|
|
34
|
+
const description = expectations.map(expectation => expectation.toString()).join(And.Separator);
|
|
35
|
+
|
|
36
|
+
super(
|
|
37
|
+
'and',
|
|
38
|
+
description,
|
|
39
|
+
async (actor: AnswersQuestions, actual: Answerable<Actual>) => {
|
|
40
|
+
let outcome: ExpectationOutcome;
|
|
41
|
+
|
|
42
|
+
for (const expectation of expectations) {
|
|
43
|
+
outcome = await actor.answer(expectation.isMetFor(actual))
|
|
15
44
|
|
|
16
|
-
|
|
45
|
+
if (outcome instanceof ExpectationNotMet) {
|
|
46
|
+
return new ExpectationNotMet(description, outcome.expectation, outcome.expected, outcome.actual);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
17
49
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
previous.then(outcome =>
|
|
22
|
-
match(outcome)
|
|
23
|
-
.when(ExpectationNotMet, o => o)
|
|
24
|
-
.else(_ => current.answeredBy(actor)(actual)),
|
|
25
|
-
),
|
|
26
|
-
Promise.resolve(void 0),
|
|
27
|
-
);
|
|
50
|
+
return new ExpectationMet(description, outcome?.expectation, outcome?.expected, outcome?.actual);
|
|
51
|
+
}
|
|
52
|
+
);
|
|
28
53
|
}
|
|
29
54
|
}
|
|
@@ -1,7 +1,32 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { Expectation } from '@serenity-js/core';
|
|
2
2
|
import { equal } from 'tiny-types/lib/objects';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
/**
|
|
5
|
+
* Produces an {@apilink Expectation|expectation} that is met when the actual array of `Item[]` contains
|
|
6
|
+
* at least one `Item` that is equal to the resolved value of `expected`.
|
|
7
|
+
*
|
|
8
|
+
* Note that the equality check performs comparison **by value**
|
|
9
|
+
* using [TinyTypes `equal`](https://github.com/jan-molak/tiny-types/blob/master/src/objects/equal.ts).
|
|
10
|
+
*
|
|
11
|
+
* ## Ensuring that the array contains the given item
|
|
12
|
+
*
|
|
13
|
+
* ```ts
|
|
14
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
15
|
+
* import { Ensure, and, startsWith, endsWith } from '@serenity-js/assertions'
|
|
16
|
+
*
|
|
17
|
+
* const items = [ { name: 'apples' }, { name: 'bananas' } ]
|
|
18
|
+
*
|
|
19
|
+
* await actorCalled('Ester').attemptsTo(
|
|
20
|
+
* Ensure.that(items, contain({ name: 'bananas' })),
|
|
21
|
+
* )
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* @param expected
|
|
25
|
+
*
|
|
26
|
+
* @group Expectations
|
|
27
|
+
*/
|
|
28
|
+
export const contain = Expectation.define(
|
|
29
|
+
'contain', 'contain',
|
|
30
|
+
<Item>(actual: Item[], expected: Item) =>
|
|
31
|
+
actual.some(item => equal(item, expected))
|
|
32
|
+
);
|
|
@@ -1,26 +1,80 @@
|
|
|
1
|
-
import { AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
2
|
-
import { formatted } from '@serenity-js/core/lib/io';
|
|
1
|
+
import { Answerable, AnswersQuestions, d, Expectation, ExpectationDetails, ExpectationMet, ExpectationNotMet, ExpectationOutcome, Unanswered } from '@serenity-js/core';
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Produces an {@apilink Expectation|expectation} that is met when the actual array of `Item[]` contains
|
|
5
|
+
* at least one `Item` for which the `expectation` is met.
|
|
6
|
+
*
|
|
7
|
+
* ## Ensuring that at least one item in an array meets the expectation
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
11
|
+
* import { Ensure, containAtLeastOneItemThat, isGreaterThan } from '@serenity-js/assertions'
|
|
12
|
+
*
|
|
13
|
+
* const items = [ 10, 15, 20 ]
|
|
14
|
+
*
|
|
15
|
+
* await actorCalled('Ester').attemptsTo(
|
|
16
|
+
* Ensure.that(items, containAtLeastOneItemThat(isGreaterThan(18))),
|
|
17
|
+
* )
|
|
18
|
+
* ```
|
|
19
|
+
*
|
|
20
|
+
* @param expectation
|
|
21
|
+
*
|
|
22
|
+
* @group Expectations
|
|
23
|
+
*/
|
|
24
|
+
export function containAtLeastOneItemThat<Item>(expectation: Expectation<Item>): Expectation<Item[]> {
|
|
5
25
|
return new ContainAtLeastOneItemThatMeetsExpectation(expectation);
|
|
6
26
|
}
|
|
7
27
|
|
|
8
28
|
/**
|
|
9
29
|
* @package
|
|
10
30
|
*/
|
|
11
|
-
class ContainAtLeastOneItemThatMeetsExpectation<
|
|
12
|
-
|
|
13
|
-
|
|
31
|
+
class ContainAtLeastOneItemThatMeetsExpectation<Item> extends Expectation<Item[]> {
|
|
32
|
+
|
|
33
|
+
private static descriptionFor(expectation: Expectation<any>) {
|
|
34
|
+
return d`contain at least one item that does ${ expectation }`;
|
|
14
35
|
}
|
|
15
36
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
37
|
+
constructor(private readonly expectation: Expectation<Item>) {
|
|
38
|
+
super(
|
|
39
|
+
'containAtLeastOneItemThat',
|
|
40
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
41
|
+
async (actor: AnswersQuestions, actual: Answerable<Item[]>) => {
|
|
42
|
+
|
|
43
|
+
const items: Item[] = await actor.answer(actual);
|
|
44
|
+
|
|
45
|
+
if (! items || items.length === 0) {
|
|
46
|
+
const unanswered = new Unanswered();
|
|
47
|
+
return new ExpectationNotMet(
|
|
48
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
49
|
+
ExpectationDetails.of('containAtLeastOneItemThat', unanswered),
|
|
50
|
+
unanswered,
|
|
51
|
+
items,
|
|
24
52
|
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
let outcome: ExpectationOutcome;
|
|
56
|
+
|
|
57
|
+
for (const item of items) {
|
|
58
|
+
|
|
59
|
+
outcome = await actor.answer(expectation.isMetFor(item))
|
|
60
|
+
|
|
61
|
+
if (outcome instanceof ExpectationMet) {
|
|
62
|
+
return new ExpectationMet(
|
|
63
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
64
|
+
ExpectationDetails.of('containAtLeastOneItemThat', outcome.expectation),
|
|
65
|
+
outcome.expected,
|
|
66
|
+
items,
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
return new ExpectationNotMet(
|
|
72
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
73
|
+
ExpectationDetails.of('containAtLeastOneItemThat', outcome.expectation),
|
|
74
|
+
outcome.expected,
|
|
75
|
+
items,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
25
79
|
}
|
|
26
80
|
}
|