@serenity-js/assertions 3.0.0-rc.2 → 3.0.0-rc.22
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 +480 -1
- package/README.md +1 -1
- package/lib/Ensure.d.ts +1 -1
- package/lib/Ensure.js +7 -10
- package/lib/Ensure.js.map +1 -1
- package/lib/expectations/and.d.ts +1 -1
- package/lib/expectations/and.js +6 -6
- package/lib/expectations/and.js.map +1 -1
- package/lib/expectations/contain.d.ts +1 -1
- package/lib/expectations/containAtLeastOneItemThat.d.ts +1 -1
- package/lib/expectations/containAtLeastOneItemThat.js +16 -9
- package/lib/expectations/containAtLeastOneItemThat.js.map +1 -1
- package/lib/expectations/containItemsWhereEachItem.d.ts +1 -1
- package/lib/expectations/containItemsWhereEachItem.js +16 -9
- package/lib/expectations/containItemsWhereEachItem.js.map +1 -1
- package/lib/expectations/index.d.ts +2 -1
- package/lib/expectations/index.js +7 -2
- package/lib/expectations/index.js.map +1 -1
- package/lib/expectations/isCloseTo.d.ts +17 -0
- package/lib/expectations/isCloseTo.js +51 -0
- package/lib/expectations/isCloseTo.js.map +1 -0
- package/lib/expectations/isFalse.js.map +1 -1
- package/lib/expectations/isPresent.d.ts +14 -0
- package/lib/expectations/isPresent.js +50 -0
- package/lib/expectations/isPresent.js.map +1 -0
- package/lib/expectations/isTrue.js.map +1 -1
- package/lib/expectations/matches.d.ts +1 -1
- package/lib/expectations/not.d.ts +1 -1
- package/lib/expectations/not.js +7 -8
- package/lib/expectations/not.js.map +1 -1
- package/lib/expectations/or.d.ts +1 -1
- package/lib/expectations/or.js +17 -12
- package/lib/expectations/or.js.map +1 -1
- package/lib/index.js +5 -1
- package/lib/index.js.map +1 -1
- package/package.json +12 -33
- package/src/Ensure.ts +17 -21
- package/src/expectations/and.ts +19 -18
- package/src/expectations/contain.ts +1 -1
- package/src/expectations/containAtLeastOneItemThat.ts +38 -14
- package/src/expectations/containItemsWhereEachItem.ts +38 -14
- package/src/expectations/index.ts +2 -1
- package/src/expectations/isCloseTo.ts +60 -0
- package/src/expectations/isFalse.ts +1 -1
- package/src/expectations/isPresent.ts +58 -0
- package/src/expectations/isTrue.ts +1 -1
- package/src/expectations/matches.ts +1 -1
- package/src/expectations/not.ts +15 -15
- package/src/expectations/or.ts +28 -25
- package/lib/expectations/property.d.ts +0 -2
- package/lib/expectations/property.js +0 -28
- package/lib/expectations/property.js.map +0 -1
- package/src/expectations/property.ts +0 -33
package/src/expectations/and.ts
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import { AnswersQuestions, Expectation, ExpectationNotMet
|
|
1
|
+
import { Answerable, AnswersQuestions, Expectation, ExpectationNotMet } from '@serenity-js/core';
|
|
2
2
|
import { match } from 'tiny-types';
|
|
3
3
|
|
|
4
|
-
export function and<Actual>(...expectations: Array<Expectation<
|
|
4
|
+
export function and<Actual>(...expectations: Array<Expectation<Actual>>): Expectation<Actual> {
|
|
5
5
|
return new And(expectations);
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* @package
|
|
10
10
|
*/
|
|
11
|
-
class And<Actual> extends Expectation<
|
|
12
|
-
|
|
13
|
-
super(expectations.map(assertion => assertion.toString()).join(' and '));
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
answeredBy(actor: AnswersQuestions): (actual: Actual) => Promise<ExpectationOutcome<any, Actual>> {
|
|
11
|
+
class And<Actual> extends Expectation<Actual> {
|
|
12
|
+
private static readonly Separator = ' and ';
|
|
17
13
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
14
|
+
constructor(private readonly expectations: Array<Expectation<Actual>>) {
|
|
15
|
+
super(
|
|
16
|
+
expectations.map(expectation => expectation.toString()).join(And.Separator),
|
|
17
|
+
(actor: AnswersQuestions, actual: Answerable<Actual>) => {
|
|
18
|
+
return expectations.reduce(
|
|
19
|
+
(previous, current) =>
|
|
20
|
+
previous.then(outcome =>
|
|
21
|
+
match(outcome)
|
|
22
|
+
.when(ExpectationNotMet, o => o)
|
|
23
|
+
.else(_ => actor.answer(current.isMetFor(actual))),
|
|
24
|
+
),
|
|
25
|
+
Promise.resolve(void 0),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
);
|
|
28
29
|
}
|
|
29
30
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Answerable, Expectation } from '@serenity-js/core';
|
|
2
2
|
import { equal } from 'tiny-types/lib/objects';
|
|
3
3
|
|
|
4
|
-
export function contain<Item>(expected: Answerable<Item>): Expectation<Item
|
|
4
|
+
export function contain<Item>(expected: Answerable<Item>): Expectation<Item[]> {
|
|
5
5
|
return Expectation.thatActualShould<Item, Item[]>('contain', expected)
|
|
6
6
|
.soThat((actualValue, expectedValue) => !! ~ actualValue.findIndex(av => equal(av, expectedValue)));
|
|
7
7
|
}
|
|
@@ -1,26 +1,50 @@
|
|
|
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, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
3
2
|
|
|
4
|
-
export function containAtLeastOneItemThat<Actual>(expectation: Expectation<
|
|
3
|
+
export function containAtLeastOneItemThat<Actual>(expectation: Expectation<Actual>): Expectation<Actual[]> {
|
|
5
4
|
return new ContainAtLeastOneItemThatMeetsExpectation(expectation);
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @package
|
|
10
9
|
*/
|
|
11
|
-
class ContainAtLeastOneItemThatMeetsExpectation<
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
class ContainAtLeastOneItemThatMeetsExpectation<Actual> extends Expectation<Actual[]> {
|
|
11
|
+
|
|
12
|
+
private static descriptionFor(expectation: Expectation<any>) {
|
|
13
|
+
return d`contain at least one item that does ${ expectation }`;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
constructor(private readonly expectation: Expectation<Actual>) {
|
|
17
|
+
super(
|
|
18
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
19
|
+
async (actor: AnswersQuestions, actual: Answerable<Actual[]>) => {
|
|
20
|
+
|
|
21
|
+
const items: Actual[] = await actor.answer(actual);
|
|
22
|
+
|
|
23
|
+
if (! items || items.length === 0) {
|
|
24
|
+
return new ExpectationNotMet(
|
|
25
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
26
|
+
undefined,
|
|
27
|
+
items,
|
|
24
28
|
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let outcome: ExpectationOutcome<unknown, Actual>;
|
|
32
|
+
|
|
33
|
+
for (const item of items) {
|
|
34
|
+
|
|
35
|
+
outcome = await actor.answer(expectation.isMetFor(item))
|
|
36
|
+
|
|
37
|
+
if (outcome instanceof ExpectationMet) {
|
|
38
|
+
return new ExpectationMet(
|
|
39
|
+
ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation),
|
|
40
|
+
outcome.expected,
|
|
41
|
+
items
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return new ExpectationNotMet(ContainAtLeastOneItemThatMeetsExpectation.descriptionFor(expectation), outcome.expected, items);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
25
49
|
}
|
|
26
50
|
}
|
|
@@ -1,26 +1,50 @@
|
|
|
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, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
3
2
|
|
|
4
|
-
export function containItemsWhereEachItem<Actual>(expectation: Expectation<
|
|
3
|
+
export function containItemsWhereEachItem<Actual>(expectation: Expectation<Actual>): Expectation<Actual[]> {
|
|
5
4
|
return new ContainItemsWhereEachItemMeetsExpectation(expectation);
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @package
|
|
10
9
|
*/
|
|
11
|
-
class ContainItemsWhereEachItemMeetsExpectation<
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
class ContainItemsWhereEachItemMeetsExpectation<Actual> extends Expectation<Actual[]> {
|
|
11
|
+
|
|
12
|
+
private static descriptionFor(expectation: Expectation<any>) {
|
|
13
|
+
return d`contain items where each item does ${ expectation }`;
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
16
|
+
constructor(private readonly expectation: Expectation<Actual>) {
|
|
17
|
+
super(
|
|
18
|
+
ContainItemsWhereEachItemMeetsExpectation.descriptionFor(expectation),
|
|
19
|
+
async (actor: AnswersQuestions, actual: Answerable<Actual[]>) => {
|
|
20
|
+
|
|
21
|
+
const items: Actual[] = await actor.answer(actual);
|
|
22
|
+
|
|
23
|
+
if (! items || items.length === 0) {
|
|
24
|
+
return new ExpectationNotMet(
|
|
25
|
+
ContainItemsWhereEachItemMeetsExpectation.descriptionFor(expectation),
|
|
26
|
+
undefined,
|
|
27
|
+
items,
|
|
24
28
|
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
let outcome: ExpectationOutcome<unknown, Actual>;
|
|
32
|
+
|
|
33
|
+
for (const item of items) {
|
|
34
|
+
|
|
35
|
+
outcome = await actor.answer(expectation.isMetFor(item))
|
|
36
|
+
|
|
37
|
+
if (outcome instanceof ExpectationNotMet) {
|
|
38
|
+
return new ExpectationNotMet(
|
|
39
|
+
ContainItemsWhereEachItemMeetsExpectation.descriptionFor(expectation),
|
|
40
|
+
outcome.expected,
|
|
41
|
+
items
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return new ExpectationMet(ContainItemsWhereEachItemMeetsExpectation.descriptionFor(expectation), outcome.expected, items);
|
|
47
|
+
}
|
|
48
|
+
);
|
|
25
49
|
}
|
|
26
50
|
}
|
|
@@ -7,12 +7,13 @@ export * from './equals';
|
|
|
7
7
|
export * from './includes';
|
|
8
8
|
export * from './isAfter';
|
|
9
9
|
export * from './isBefore';
|
|
10
|
+
export * from './isCloseTo';
|
|
10
11
|
export * from './isFalse';
|
|
11
12
|
export * from './isGreaterThan';
|
|
12
13
|
export * from './isLessThan';
|
|
14
|
+
export * from './isPresent';
|
|
13
15
|
export * from './isTrue';
|
|
14
16
|
export * from './matches';
|
|
15
17
|
export * from './not';
|
|
16
18
|
export * from './or';
|
|
17
|
-
export * from './property';
|
|
18
19
|
export * from './startsWith';
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Answerable, AnswersQuestions, d, Expectation, ExpectationMet, ExpectationNotMet } from '@serenity-js/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @desc
|
|
5
|
+
* Expectation that the actual value is within a given ± absolute tolerance range of the expected value.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* import { actorCalled } from '@serenity-js/core'
|
|
9
|
+
* import { Ensure, isCloseTo } from '@serenity-js/assertions'
|
|
10
|
+
*
|
|
11
|
+
* await actorCalled('Iris').attemptsTo(
|
|
12
|
+
* Ensure.that(10.123, isCloseTo(10, 0.2))
|
|
13
|
+
* )
|
|
14
|
+
*
|
|
15
|
+
* @param {Answerable<number>} expected
|
|
16
|
+
* @param {Answerable<number>} [absoluteTolerance=1e-9]
|
|
17
|
+
*/
|
|
18
|
+
export function isCloseTo(expected: Answerable<number>, absoluteTolerance: Answerable<number> = 1e-9): Expectation<number> {
|
|
19
|
+
return new IsCloseTo(expected, absoluteTolerance);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @package
|
|
24
|
+
*/
|
|
25
|
+
class IsCloseTo extends Expectation<number> {
|
|
26
|
+
|
|
27
|
+
constructor(
|
|
28
|
+
private readonly expected: Answerable<number>,
|
|
29
|
+
private readonly absoluteTolerance: Answerable<number>,
|
|
30
|
+
) {
|
|
31
|
+
super(
|
|
32
|
+
d`have value close to ${ expected } ±${ absoluteTolerance }`,
|
|
33
|
+
async (actor: AnswersQuestions, actual: Answerable<number>) => {
|
|
34
|
+
|
|
35
|
+
const actualValue: number = await actor.answer(actual);
|
|
36
|
+
const expectedValue: number = await actor.answer(this.expected);
|
|
37
|
+
const tolerance: number = await actor.answer(this.absoluteTolerance);
|
|
38
|
+
|
|
39
|
+
const description = `have value close to ${ expectedValue } ±${ tolerance }`
|
|
40
|
+
|
|
41
|
+
// short-circuit exact equality
|
|
42
|
+
if (actualValue === expectedValue) {
|
|
43
|
+
return new ExpectationMet(description, expectedValue, actualValue);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
if (! (Number.isFinite(actualValue) && Number.isFinite(expectedValue))) {
|
|
47
|
+
return new ExpectationNotMet(description, expectedValue, actualValue);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const difference = Math.abs(actualValue - expectedValue)
|
|
51
|
+
|
|
52
|
+
const isClose = difference <= tolerance;
|
|
53
|
+
|
|
54
|
+
return isClose
|
|
55
|
+
? new ExpectationMet(description, expectedValue, actualValue)
|
|
56
|
+
: new ExpectationNotMet(description, expectedValue, actualValue);
|
|
57
|
+
}
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -3,5 +3,5 @@ import { Expectation } from '@serenity-js/core';
|
|
|
3
3
|
import { equals } from './equals';
|
|
4
4
|
|
|
5
5
|
export function isFalse(): Expectation<boolean> {
|
|
6
|
-
return Expectation.to<boolean>(`equal false`).soThatActual(equals(false));
|
|
6
|
+
return Expectation.to<never, boolean>(`equal false`).soThatActual(equals(false));
|
|
7
7
|
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Answerable, AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, Optional } from '@serenity-js/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @desc
|
|
5
|
+
* Expectation that the `actual` is not undefined or null.
|
|
6
|
+
* Also, for `actual` implementing {@link @serenity-js/core/lib/screenplay~Optional}, that `Optional.isPresent()` returns an {@link @serenity-js/core/lib/screenplay~Answerable}
|
|
7
|
+
* that resolves to `true`
|
|
8
|
+
*
|
|
9
|
+
* @returns {@serenity-js/core/lib/screenplay/questions~Expectation<Answerable<boolean>, Optional>}
|
|
10
|
+
*
|
|
11
|
+
* @see {@link @serenity-js/assertions~Ensure}
|
|
12
|
+
* @see {@link @serenity-js/core/lib/screenplay/questions~Check}
|
|
13
|
+
* @see {@link @serenity-js/core/lib/screenplay/interactions~Wait}
|
|
14
|
+
*/
|
|
15
|
+
export function isPresent<Actual>(): Expectation<Actual> {
|
|
16
|
+
return new IsPresent<Actual>();
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class IsPresent<Actual> extends Expectation<Actual> {
|
|
20
|
+
private static isOptional(value: any): value is Optional {
|
|
21
|
+
return value !== undefined
|
|
22
|
+
&& value !== null
|
|
23
|
+
&& typeof value.isPresent === 'function';
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
private static valueToCheck<A>(actual: Answerable<A>, actor: AnswersQuestions): Answerable<A> {
|
|
27
|
+
if (IsPresent.isOptional(actual)) {
|
|
28
|
+
return actual;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return actor.answer(actual);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
private static async isPresent<A>(value: Answerable<A>, actor: AnswersQuestions): Promise<boolean> {
|
|
35
|
+
if (IsPresent.isOptional(value)) {
|
|
36
|
+
return actor.answer(value.isPresent());
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return value !== undefined
|
|
40
|
+
&& value !== null;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
constructor() {
|
|
44
|
+
super(
|
|
45
|
+
'become present',
|
|
46
|
+
async (actor: AnswersQuestions, actual: Answerable<Actual>) => {
|
|
47
|
+
|
|
48
|
+
const value = await IsPresent.valueToCheck(actual, actor);
|
|
49
|
+
|
|
50
|
+
const result = await IsPresent.isPresent(value, actor);
|
|
51
|
+
|
|
52
|
+
return result
|
|
53
|
+
? new ExpectationMet('become present', undefined, undefined)
|
|
54
|
+
: new ExpectationNotMet('become present', undefined, undefined);
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -3,5 +3,5 @@ import { Expectation } from '@serenity-js/core';
|
|
|
3
3
|
import { equals } from './equals';
|
|
4
4
|
|
|
5
5
|
export function isTrue(): Expectation<boolean> {
|
|
6
|
-
return Expectation.to<boolean>(`equal true`).soThatActual(equals(true));
|
|
6
|
+
return Expectation.to<never, boolean>(`equal true`).soThatActual(equals(true));
|
|
7
7
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Answerable, Expectation } from '@serenity-js/core';
|
|
2
2
|
|
|
3
|
-
export function matches(expected: Answerable<RegExp>): Expectation<
|
|
3
|
+
export function matches(expected: Answerable<RegExp>): Expectation<string> {
|
|
4
4
|
return Expectation.thatActualShould<RegExp, string>('match', expected)
|
|
5
5
|
.soThat((actualValue, expectedValue) => expectedValue.test(actualValue));
|
|
6
6
|
}
|
package/src/expectations/not.ts
CHANGED
|
@@ -1,31 +1,31 @@
|
|
|
1
|
-
import { AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet
|
|
2
|
-
import { match } from 'tiny-types';
|
|
1
|
+
import { Answerable, AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet } from '@serenity-js/core';
|
|
3
2
|
|
|
4
|
-
export function not<
|
|
5
|
-
return new Not<
|
|
3
|
+
export function not<Actual>(assertion: Expectation<Actual>): Expectation<Actual> {
|
|
4
|
+
return new Not<Actual>(assertion);
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* @package
|
|
10
9
|
*/
|
|
11
|
-
class Not<
|
|
10
|
+
class Not<Actual> extends Expectation<Actual> {
|
|
12
11
|
private static flipped(message: string): string {
|
|
13
12
|
return message.startsWith('not ')
|
|
14
13
|
? message.slice(4)
|
|
15
14
|
: `not ${ message }`;
|
|
16
15
|
}
|
|
17
16
|
|
|
18
|
-
constructor(private readonly expectation: Expectation<
|
|
19
|
-
super(
|
|
20
|
-
|
|
17
|
+
constructor(private readonly expectation: Expectation<Actual>) {
|
|
18
|
+
super(
|
|
19
|
+
Not.flipped(expectation.toString()),
|
|
20
|
+
async (actor: AnswersQuestions, actual: Answerable<Actual>) => {
|
|
21
|
+
const subject = Not.flipped(expectation.toString());
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
const outcome = await actor.answer(expectation.isMetFor(actual));
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
.else(o => new ExpectationMet(this.subject, o.expected, o.actual)));
|
|
25
|
+
return outcome instanceof ExpectationNotMet
|
|
26
|
+
? new ExpectationMet(subject, outcome.expected, outcome.actual)
|
|
27
|
+
: new ExpectationNotMet(subject, outcome.expected, outcome.actual);
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
30
|
}
|
|
31
31
|
}
|
package/src/expectations/or.ts
CHANGED
|
@@ -1,41 +1,44 @@
|
|
|
1
|
-
import { AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
1
|
+
import { Answerable, AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, ExpectationOutcome, LogicError } from '@serenity-js/core';
|
|
2
2
|
|
|
3
|
-
export function or<Actual>(...assertions: Array<Expectation<
|
|
3
|
+
export function or<Actual>(...assertions: Array<Expectation<Actual>>): Expectation<Actual> {
|
|
4
4
|
return new Or(assertions);
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* @package
|
|
9
9
|
*/
|
|
10
|
-
class Or<Actual> extends Expectation<
|
|
10
|
+
class Or<Actual> extends Expectation<Actual> {
|
|
11
11
|
private static readonly Separator = ' or ';
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
.map(
|
|
16
|
-
.join(Or.Separator)
|
|
13
|
+
private static descriptionFor<A>(expectations: Array<Expectation<A>>): string {
|
|
14
|
+
return expectations
|
|
15
|
+
.map(expectation => expectation.toString())
|
|
16
|
+
.join(Or.Separator);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
constructor(private readonly expectations: Array<Expectation<Actual>>) {
|
|
20
|
+
super(
|
|
21
|
+
Or.descriptionFor(expectations),
|
|
22
|
+
async (actor: AnswersQuestions, actual: Answerable<Actual>) => {
|
|
23
|
+
if (! expectations || expectations.length === 0) {
|
|
24
|
+
throw new LogicError(`No expectations provided to or()`);
|
|
25
|
+
}
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
previous.then((outcomesSoFar: Array<ExpectationOutcome<any, Actual>>) =>
|
|
25
|
-
current.answeredBy(actor)(actual)
|
|
26
|
-
.then(outcome => outcomesSoFar.concat(outcome)), // todo: should stop on the first met expectation
|
|
27
|
-
),
|
|
28
|
-
Promise.resolve([]),
|
|
29
|
-
).
|
|
30
|
-
then((outcomes: Array<ExpectationOutcome<any, Actual>>) => {
|
|
27
|
+
let outcome: ExpectationOutcome<unknown, Actual>;
|
|
28
|
+
for (const expectation of expectations) {
|
|
29
|
+
outcome = await actor.answer(expectation.isMetFor(actual));
|
|
31
30
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
if (outcome instanceof ExpectationMet) {
|
|
32
|
+
return outcome;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
35
|
|
|
36
|
-
return
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
return new ExpectationNotMet(
|
|
37
|
+
Or.descriptionFor(expectations),
|
|
38
|
+
outcome.expected,
|
|
39
|
+
outcome.actual,
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
);
|
|
40
43
|
}
|
|
41
44
|
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.property = void 0;
|
|
4
|
-
const core_1 = require("@serenity-js/core");
|
|
5
|
-
const io_1 = require("@serenity-js/core/lib/io");
|
|
6
|
-
function property(propertyName, expectation) {
|
|
7
|
-
return new HasProperty(propertyName, expectation);
|
|
8
|
-
}
|
|
9
|
-
exports.property = property;
|
|
10
|
-
/**
|
|
11
|
-
* @package
|
|
12
|
-
*/
|
|
13
|
-
class HasProperty extends core_1.Expectation {
|
|
14
|
-
constructor(propertyName, expectation) {
|
|
15
|
-
super((0, io_1.formatted) `have property ${propertyName} that does ${expectation}`);
|
|
16
|
-
this.propertyName = propertyName;
|
|
17
|
-
this.expectation = expectation;
|
|
18
|
-
}
|
|
19
|
-
answeredBy(actor) {
|
|
20
|
-
return (actual) => this.expectation.answeredBy(actor)(actual[this.propertyName])
|
|
21
|
-
.then((outcome) => {
|
|
22
|
-
return outcome instanceof core_1.ExpectationMet
|
|
23
|
-
? new core_1.ExpectationMet(this.toString(), outcome.expected, actual[this.propertyName])
|
|
24
|
-
: new core_1.ExpectationNotMet(this.toString(), outcome.expected, actual[this.propertyName]);
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
//# sourceMappingURL=property.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"property.js","sourceRoot":"","sources":["../../src/expectations/property.ts"],"names":[],"mappings":";;;AAAA,4CAAyH;AACzH,iDAAqD;AAErD,SAAgB,QAAQ,CACpB,YAAsB,EACtB,WAA+C;IAE/C,OAAO,IAAI,WAAW,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;AACtD,CAAC;AALD,4BAKC;AAED;;GAEG;AACH,MAAM,WAAmD,SAAQ,kBAAqC;IAClG,YACqB,YAAsB,EACtB,WAA+C;QAEhE,KAAK,CAAC,IAAA,cAAS,EAAC,iBAAkB,YAAa,cAAe,WAAY,EAAE,CAAC,CAAC;QAH7D,iBAAY,GAAZ,YAAY,CAAU;QACtB,gBAAW,GAAX,WAAW,CAAoC;IAGpE,CAAC;IAED,UAAU,CAAC,KAAuB;QAE9B,OAAO,CAAC,MAAc,EAAE,EAAE,CACtB,IAAI,CAAC,WAAW,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;aACxD,IAAI,CAAC,CAAC,OAAkD,EAAE,EAAE;YAEzD,OAAO,OAAO,YAAY,qBAAc;gBACpC,CAAC,CAAC,IAAI,qBAAc,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;gBAClF,CAAC,CAAC,IAAI,wBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,OAAO,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,CAAC;QAC9F,CAAC,CAAC,CAAC;IACf,CAAC;CACJ"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { AnswersQuestions, Expectation, ExpectationMet, ExpectationNotMet, ExpectationOutcome } from '@serenity-js/core';
|
|
2
|
-
import { formatted } from '@serenity-js/core/lib/io';
|
|
3
|
-
|
|
4
|
-
export function property<Actual, Property extends keyof Actual>(
|
|
5
|
-
propertyName: Property,
|
|
6
|
-
expectation: Expectation<any, Actual[Property]>,
|
|
7
|
-
): Expectation<Actual[Property], Actual> {
|
|
8
|
-
return new HasProperty(propertyName, expectation);
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* @package
|
|
13
|
-
*/
|
|
14
|
-
class HasProperty<Property extends keyof Actual, Actual> extends Expectation<Actual[Property], Actual> {
|
|
15
|
-
constructor(
|
|
16
|
-
private readonly propertyName: Property,
|
|
17
|
-
private readonly expectation: Expectation<any, Actual[Property]>,
|
|
18
|
-
) {
|
|
19
|
-
super(formatted `have property ${ propertyName } that does ${ expectation }`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
answeredBy(actor: AnswersQuestions): (actual: Actual) => Promise<ExpectationOutcome<Actual[Property], any>> {
|
|
23
|
-
|
|
24
|
-
return (actual: Actual) =>
|
|
25
|
-
this.expectation.answeredBy(actor)(actual[this.propertyName])
|
|
26
|
-
.then((outcome: ExpectationOutcome<any, Actual[Property]>) => {
|
|
27
|
-
|
|
28
|
-
return outcome instanceof ExpectationMet
|
|
29
|
-
? new ExpectationMet(this.toString(), outcome.expected, actual[this.propertyName])
|
|
30
|
-
: new ExpectationNotMet(this.toString(), outcome.expected, actual[this.propertyName]);
|
|
31
|
-
});
|
|
32
|
-
}
|
|
33
|
-
}
|