@serenity-js/core 3.25.4 → 3.26.0
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 +26 -0
- package/lib/events/actor/ActorEntersStage.d.ts +17 -0
- package/lib/events/actor/ActorEntersStage.d.ts.map +1 -0
- package/lib/events/actor/ActorEntersStage.js +29 -0
- package/lib/events/actor/ActorEntersStage.js.map +1 -0
- package/lib/events/actor/ActorStageExitAttempted.d.ts +19 -0
- package/lib/events/actor/ActorStageExitAttempted.d.ts.map +1 -0
- package/lib/events/actor/ActorStageExitAttempted.js +29 -0
- package/lib/events/actor/ActorStageExitAttempted.js.map +1 -0
- package/lib/events/actor/ActorStageExitCompleted.d.ts +20 -0
- package/lib/events/actor/ActorStageExitCompleted.d.ts.map +1 -0
- package/lib/events/actor/ActorStageExitCompleted.js +30 -0
- package/lib/events/actor/ActorStageExitCompleted.js.map +1 -0
- package/lib/events/actor/ActorStageExitFailed.d.ts +17 -0
- package/lib/events/actor/ActorStageExitFailed.d.ts.map +1 -0
- package/lib/events/actor/ActorStageExitFailed.js +25 -0
- package/lib/events/actor/ActorStageExitFailed.js.map +1 -0
- package/lib/events/actor/ActorStageExitStarts.d.ts +20 -0
- package/lib/events/actor/ActorStageExitStarts.d.ts.map +1 -0
- package/lib/events/actor/ActorStageExitStarts.js +32 -0
- package/lib/events/actor/ActorStageExitStarts.js.map +1 -0
- package/lib/events/actor/index.d.ts +6 -0
- package/lib/events/actor/index.d.ts.map +1 -0
- package/lib/events/actor/index.js +22 -0
- package/lib/events/actor/index.js.map +1 -0
- package/lib/events/index.d.ts +1 -0
- package/lib/events/index.d.ts.map +1 -1
- package/lib/events/index.js +1 -0
- package/lib/events/index.js.map +1 -1
- package/lib/screenplay/Actor.d.ts +8 -1
- package/lib/screenplay/Actor.d.ts.map +1 -1
- package/lib/screenplay/Actor.js +14 -10
- package/lib/screenplay/Actor.js.map +1 -1
- package/lib/screenplay/SerialisedActor.d.ts +9 -0
- package/lib/screenplay/SerialisedActor.d.ts.map +1 -0
- package/lib/screenplay/SerialisedActor.js +3 -0
- package/lib/screenplay/SerialisedActor.js.map +1 -0
- package/lib/screenplay/abilities/Ability.d.ts +39 -0
- package/lib/screenplay/abilities/Ability.d.ts.map +1 -1
- package/lib/screenplay/abilities/Ability.js +65 -0
- package/lib/screenplay/abilities/Ability.js.map +1 -1
- package/lib/screenplay/abilities/AbilityType.d.ts +5 -1
- package/lib/screenplay/abilities/AbilityType.d.ts.map +1 -1
- package/lib/screenplay/abilities/SerialisedAbility.d.ts +10 -0
- package/lib/screenplay/abilities/SerialisedAbility.d.ts.map +1 -0
- package/lib/screenplay/abilities/SerialisedAbility.js +3 -0
- package/lib/screenplay/abilities/SerialisedAbility.js.map +1 -0
- package/lib/screenplay/abilities/index.d.ts +1 -0
- package/lib/screenplay/abilities/index.d.ts.map +1 -1
- package/lib/screenplay/abilities/index.js +1 -0
- package/lib/screenplay/abilities/index.js.map +1 -1
- package/lib/screenplay/index.d.ts +1 -0
- package/lib/screenplay/index.d.ts.map +1 -1
- package/lib/screenplay/index.js +1 -0
- package/lib/screenplay/index.js.map +1 -1
- package/lib/screenplay/notes/TakeNotes.d.ts +2 -1
- package/lib/screenplay/notes/TakeNotes.d.ts.map +1 -1
- package/lib/screenplay/notes/TakeNotes.js +8 -0
- package/lib/screenplay/notes/TakeNotes.js.map +1 -1
- package/lib/screenplay/time/abilities/ScheduleWork.d.ts +2 -1
- package/lib/screenplay/time/abilities/ScheduleWork.d.ts.map +1 -1
- package/lib/screenplay/time/abilities/ScheduleWork.js +8 -0
- package/lib/screenplay/time/abilities/ScheduleWork.js.map +1 -1
- package/lib/screenplay/time/models/Clock.d.ts +2 -0
- package/lib/screenplay/time/models/Clock.d.ts.map +1 -1
- package/lib/screenplay/time/models/Clock.js +5 -0
- package/lib/screenplay/time/models/Clock.js.map +1 -1
- package/lib/screenplay/time/models/Scheduler.d.ts +2 -0
- package/lib/screenplay/time/models/Scheduler.d.ts.map +1 -1
- package/lib/screenplay/time/models/Scheduler.js +6 -0
- package/lib/screenplay/time/models/Scheduler.js.map +1 -1
- package/lib/stage/Stage.d.ts +6 -7
- package/lib/stage/Stage.d.ts.map +1 -1
- package/lib/stage/Stage.js +15 -5
- package/lib/stage/Stage.js.map +1 -1
- package/package.json +5 -5
- package/src/events/actor/ActorEntersStage.ts +32 -0
- package/src/events/actor/ActorStageExitAttempted.ts +34 -0
- package/src/events/actor/ActorStageExitCompleted.ts +34 -0
- package/src/events/actor/ActorStageExitFailed.ts +27 -0
- package/src/events/actor/ActorStageExitStarts.ts +35 -0
- package/src/events/actor/index.ts +5 -0
- package/src/events/index.ts +1 -0
- package/src/screenplay/Actor.ts +19 -28
- package/src/screenplay/SerialisedActor.ts +9 -0
- package/src/screenplay/abilities/Ability.ts +73 -0
- package/src/screenplay/abilities/AbilityType.ts +8 -1
- package/src/screenplay/abilities/SerialisedAbility.ts +10 -0
- package/src/screenplay/abilities/index.ts +1 -0
- package/src/screenplay/index.ts +1 -0
- package/src/screenplay/notes/TakeNotes.ts +10 -1
- package/src/screenplay/time/abilities/ScheduleWork.ts +11 -2
- package/src/screenplay/time/models/Clock.ts +7 -1
- package/src/screenplay/time/models/Scheduler.ts +9 -0
- package/src/stage/Stage.ts +50 -25
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ensure, isDefined, type JSONObject } from 'tiny-types';
|
|
2
|
+
|
|
3
|
+
import { CorrelationId, Name } from '../../model';
|
|
4
|
+
import { Timestamp } from '../../screenplay';
|
|
5
|
+
import { AsyncOperationCompleted } from '../AsyncOperationCompleted';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Emitted when an [`Actor`](https://serenity-js.org/api/core/class/Actor/) and its abilities
|
|
9
|
+
* are correctly [released](https://serenity-js.org/api/core/interface/Discardable/) either
|
|
10
|
+
* upon the [`SceneFinishes`](https://serenity-js.org/api/core-events/class/SceneFinishes/) event
|
|
11
|
+
* for actors initialised within the scope of a test scenario,
|
|
12
|
+
* or upon the [`TestRunFinishes`](https://serenity-js.org/api/core-events/class/TestRunFinishes/) event
|
|
13
|
+
* for actors initialised within the scope of a test suite.
|
|
14
|
+
*
|
|
15
|
+
* @group Events
|
|
16
|
+
*/
|
|
17
|
+
export class ActorStageExitCompleted extends AsyncOperationCompleted {
|
|
18
|
+
static fromJSON(o: JSONObject): ActorStageExitCompleted {
|
|
19
|
+
return new ActorStageExitCompleted(
|
|
20
|
+
CorrelationId.fromJSON(o.correlationId as string),
|
|
21
|
+
Name.fromJSON(o.actor as string),
|
|
22
|
+
Timestamp.fromJSON(o.timestamp as string),
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
correlationId: CorrelationId,
|
|
28
|
+
public readonly actor: Name,
|
|
29
|
+
timestamp?: Timestamp,
|
|
30
|
+
) {
|
|
31
|
+
super(correlationId, timestamp);
|
|
32
|
+
ensure('actor', actor, isDefined());
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { JSONObject } from 'tiny-types';
|
|
2
|
+
|
|
3
|
+
import { ErrorSerialiser } from '../../errors';
|
|
4
|
+
import { CorrelationId } from '../../model';
|
|
5
|
+
import { Timestamp } from '../../screenplay';
|
|
6
|
+
import { AsyncOperationFailed } from '../AsyncOperationFailed';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Emitted when [releasing](https://serenity-js.org/api/core/interface/Discardable/) an
|
|
10
|
+
* [`Actor`](https://serenity-js.org/api/core/class/Actor/) or its abilities
|
|
11
|
+
* resulted in an error either
|
|
12
|
+
* upon the [`SceneFinishes`](https://serenity-js.org/api/core-events/class/SceneFinishes/) event
|
|
13
|
+
* for actors initialised within the scope of a test scenario,
|
|
14
|
+
* or upon the [`TestRunFinishes`](https://serenity-js.org/api/core-events/class/TestRunFinishes/) event
|
|
15
|
+
* for actors initialised within the scope of a test suite.
|
|
16
|
+
*
|
|
17
|
+
* @group Events
|
|
18
|
+
*/
|
|
19
|
+
export class ActorStageExitFailed extends AsyncOperationFailed {
|
|
20
|
+
static fromJSON(o: JSONObject): ActorStageExitFailed {
|
|
21
|
+
return new ActorStageExitFailed(
|
|
22
|
+
ErrorSerialiser.deserialise(o.error as string),
|
|
23
|
+
CorrelationId.fromJSON(o.correlationId as string),
|
|
24
|
+
Timestamp.fromJSON(o.timestamp as string),
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { JSONObject } from 'tiny-types';
|
|
2
|
+
import { ensure, isDefined } from 'tiny-types';
|
|
3
|
+
|
|
4
|
+
import { CorrelationId } from '../../model';
|
|
5
|
+
import { type SerialisedActor, Timestamp } from '../../screenplay';
|
|
6
|
+
import { DomainEvent } from '../DomainEvent';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Emitted upon the [`SceneFinishes`](https://serenity-js.org/api/core-events/class/SceneFinishes/) and
|
|
10
|
+
* [`TestRunFinishes`](https://serenity-js.org/api/core-events/class/TestRunFinishes/) events
|
|
11
|
+
* to notify the [stage crew members](https://serenity-js.org/api/core/interface/StageCrewMember/)
|
|
12
|
+
* about the final state of the [actors](https://serenity-js.org/api/core/class/Actor/) and their abilities
|
|
13
|
+
* before they're [released](https://serenity-js.org/api/core/interface/Discardable/).
|
|
14
|
+
*
|
|
15
|
+
* @group Events
|
|
16
|
+
*/
|
|
17
|
+
export class ActorStageExitStarts extends DomainEvent {
|
|
18
|
+
static fromJSON(o: JSONObject): ActorStageExitStarts {
|
|
19
|
+
return new ActorStageExitStarts(
|
|
20
|
+
CorrelationId.fromJSON(o.sceneId as string),
|
|
21
|
+
o.actor as unknown as SerialisedActor,
|
|
22
|
+
Timestamp.fromJSON(o.timestamp as string),
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
constructor(
|
|
27
|
+
public readonly sceneId: CorrelationId,
|
|
28
|
+
public readonly actor: SerialisedActor,
|
|
29
|
+
timestamp?: Timestamp,
|
|
30
|
+
) {
|
|
31
|
+
super(timestamp);
|
|
32
|
+
ensure('sceneId', sceneId, isDefined());
|
|
33
|
+
ensure('actor', actor, isDefined());
|
|
34
|
+
}
|
|
35
|
+
}
|
package/src/events/index.ts
CHANGED
|
@@ -2,6 +2,7 @@ export * from './ActivityFinished';
|
|
|
2
2
|
export * from './ActivityRelatedArtifactArchived';
|
|
3
3
|
export * from './ActivityRelatedArtifactGenerated';
|
|
4
4
|
export * from './ActivityStarts';
|
|
5
|
+
export * from './actor';
|
|
5
6
|
export * from './ArtifactArchived';
|
|
6
7
|
export * from './ArtifactGenerated';
|
|
7
8
|
export * from './AsyncOperationAborted';
|
package/src/screenplay/Actor.ts
CHANGED
|
@@ -1,26 +1,17 @@
|
|
|
1
1
|
import { ConfigurationError, TestCompromisedError } from '../errors';
|
|
2
2
|
import { ActivityRelatedArtifactGenerated } from '../events';
|
|
3
3
|
import { ValueInspector } from '../io';
|
|
4
|
-
import type { Artifact} from '../model';
|
|
4
|
+
import type { Artifact } from '../model';
|
|
5
5
|
import { Name, } from '../model';
|
|
6
6
|
import type { Stage } from '../stage';
|
|
7
|
-
import type {
|
|
8
|
-
|
|
9
|
-
CanHaveAbilities,
|
|
10
|
-
Discardable,
|
|
11
|
-
Initialisable,
|
|
12
|
-
UsesAbilities
|
|
13
|
-
} from './abilities';
|
|
14
|
-
import {
|
|
15
|
-
Ability,
|
|
16
|
-
AnswerQuestions,
|
|
17
|
-
PerformActivities
|
|
18
|
-
} from './abilities';
|
|
7
|
+
import type { AbilityType, CanHaveAbilities, Discardable, Initialisable, UsesAbilities } from './abilities';
|
|
8
|
+
import { Ability, AnswerQuestions, PerformActivities } from './abilities';
|
|
19
9
|
import type { PerformsActivities } from './activities';
|
|
20
10
|
import type { Activity } from './Activity';
|
|
21
11
|
import type { Answerable } from './Answerable';
|
|
22
12
|
import type { CollectsArtifacts } from './artifacts';
|
|
23
13
|
import type { AnswersQuestions } from './questions';
|
|
14
|
+
import type { SerialisedActor } from './SerialisedActor';
|
|
24
15
|
import type { TellsTime, Timestamp } from './time';
|
|
25
16
|
|
|
26
17
|
/**
|
|
@@ -217,6 +208,19 @@ export class Actor implements PerformsActivities,
|
|
|
217
208
|
return `Actor(name=${ this.name }, abilities=[${ abilities.join(', ') }])`;
|
|
218
209
|
}
|
|
219
210
|
|
|
211
|
+
/**
|
|
212
|
+
* Returns a JSON representation of the actor and its current state.
|
|
213
|
+
*
|
|
214
|
+
* The purpose of this method is to enable reporting the state of the actor in a human-readable format,
|
|
215
|
+
* rather than to serialise and deserialise the actor itself.
|
|
216
|
+
*/
|
|
217
|
+
toJSON(): SerialisedActor {
|
|
218
|
+
return {
|
|
219
|
+
name: this.name,
|
|
220
|
+
abilities: Array.from(this.abilities.values()).map(ability => ability.toJSON())
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
220
224
|
private initialiseAbilities(): Promise<void> {
|
|
221
225
|
return this.findAbilitiesOfType<Initialisable>('initialise', 'isInitialised')
|
|
222
226
|
.filter(ability => !ability.isInitialised())
|
|
@@ -243,9 +247,7 @@ export class Actor implements PerformsActivities,
|
|
|
243
247
|
}
|
|
244
248
|
|
|
245
249
|
private findAbilityTo<T extends Ability>(doSomething: AbilityType<T>): T | undefined {
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return this.abilities.get(abilityType) as T;
|
|
250
|
+
return this.abilities.get(doSomething.abilityType()) as T;
|
|
249
251
|
}
|
|
250
252
|
|
|
251
253
|
private acquireAbility(ability: Ability): void {
|
|
@@ -253,18 +255,7 @@ export class Actor implements PerformsActivities,
|
|
|
253
255
|
throw new ConfigurationError(`Custom abilities must extend Ability from '@serenity-js/core'. Received ${ ValueInspector.typeOf(ability) }`);
|
|
254
256
|
}
|
|
255
257
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
this.abilities.set(abilityType, ability);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
private mostGenericTypeOf<Generic_Ability extends Ability, Specific_Ability extends Generic_Ability>(
|
|
262
|
-
abilityType: AbilityType<Specific_Ability>
|
|
263
|
-
): AbilityType<Generic_Ability> {
|
|
264
|
-
const parentType = Object.getPrototypeOf(abilityType);
|
|
265
|
-
return !parentType || parentType === Ability
|
|
266
|
-
? abilityType
|
|
267
|
-
: this.mostGenericTypeOf(parentType)
|
|
258
|
+
this.abilities.set(ability.abilityType(), ability);
|
|
268
259
|
}
|
|
269
260
|
|
|
270
261
|
/**
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { AbilityType } from './AbilityType';
|
|
2
|
+
import type { SerialisedAbility } from './SerialisedAbility';
|
|
2
3
|
import type { UsesAbilities } from './UsesAbilities';
|
|
3
4
|
|
|
4
5
|
/**
|
|
@@ -404,4 +405,76 @@ export abstract class Ability {
|
|
|
404
405
|
): A {
|
|
405
406
|
return actor.abilityTo(this) as A;
|
|
406
407
|
}
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Returns a JSON representation of the ability and its current state, if available.
|
|
411
|
+
* The purpose of this method is to enable reporting the state of the ability in a human-readable format,
|
|
412
|
+
* rather than to serialise and deserialise the ability itself.
|
|
413
|
+
*/
|
|
414
|
+
toJSON(): SerialisedAbility {
|
|
415
|
+
const abilityClass = this.constructor.name;
|
|
416
|
+
const abilityType = this.abilityType().name;
|
|
417
|
+
|
|
418
|
+
if (abilityClass !== abilityType) {
|
|
419
|
+
return {
|
|
420
|
+
class: abilityClass,
|
|
421
|
+
type: abilityType,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
return {
|
|
425
|
+
type: abilityType,
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
/**
|
|
430
|
+
* Returns the most abstract type of this Ability class,
|
|
431
|
+
* specifically the first class in the inheritance hierarchy that directly extends the `Ability` class.
|
|
432
|
+
*
|
|
433
|
+
* ```ts
|
|
434
|
+
* import { Ability } from '@serenity-js/core';
|
|
435
|
+
*
|
|
436
|
+
* class MyAbility extends Ability {}
|
|
437
|
+
* class MySpecialisedAbility extends MyAbility {}
|
|
438
|
+
*
|
|
439
|
+
* MyAbility.abilityType(); // returns MyAbility
|
|
440
|
+
* MySpecialisedAbility.abilityType(); // returns MyAbility
|
|
441
|
+
* ```
|
|
442
|
+
*/
|
|
443
|
+
static abilityType(): AbilityType<Ability> {
|
|
444
|
+
return Ability.abilityTypeOf(this);
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* Returns the most abstract type of this Ability instance,
|
|
449
|
+
* specifically the first class in the inheritance hierarchy that directly extends the `Ability` class.
|
|
450
|
+
*
|
|
451
|
+
* ```ts
|
|
452
|
+
* import { Ability } from '@serenity-js/core';
|
|
453
|
+
*
|
|
454
|
+
* class MyAbility extends Ability {}
|
|
455
|
+
* class MySpecialisedAbility extends MyAbility {}
|
|
456
|
+
*
|
|
457
|
+
* new MyAbility().abilityType(); // returns MyAbility
|
|
458
|
+
* new MySpecialisedAbility().abilityType(); // returns MyAbility
|
|
459
|
+
* ```
|
|
460
|
+
*/
|
|
461
|
+
abilityType(): AbilityType<Ability> {
|
|
462
|
+
return Ability.abilityTypeOf(this.constructor as AbilityType<Ability>);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
private static abilityTypeOf(abilityType: AbilityType<Ability>): AbilityType<Ability> {
|
|
466
|
+
const abilityTypes = Ability.ancestorTypes(abilityType);
|
|
467
|
+
return [
|
|
468
|
+
...abilityTypes,
|
|
469
|
+
abilityType
|
|
470
|
+
][0];
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
private static ancestorTypes(abilityType: AbilityType<Ability>, ancestors: Array<AbilityType<Ability>> = []): Array<AbilityType<Ability>> {
|
|
474
|
+
const parentType = Object.getPrototypeOf(abilityType);
|
|
475
|
+
|
|
476
|
+
return ! parentType || parentType === Ability
|
|
477
|
+
? ancestors
|
|
478
|
+
: this.ancestorTypes(parentType, [ parentType, ...ancestors ]);
|
|
479
|
+
}
|
|
407
480
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Ability } from './Ability';
|
|
2
|
+
import type { UsesAbilities } from './UsesAbilities';
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* An interface describing the static access method that every [`Ability`](https://serenity-js.org/api/core/class/Ability/) class
|
|
@@ -43,4 +44,10 @@ import type { Ability } from './Ability';
|
|
|
43
44
|
* @group Abilities
|
|
44
45
|
*/
|
|
45
46
|
export type AbilityType<A extends Ability> =
|
|
46
|
-
(abstract new (... args: any[]) => A)
|
|
47
|
+
(abstract new (... args: any[]) => A) & {
|
|
48
|
+
as<S extends Ability>(
|
|
49
|
+
this: AbilityType<S>,
|
|
50
|
+
actor: UsesAbilities
|
|
51
|
+
): S;
|
|
52
|
+
abilityType(): AbilityType<Ability>
|
|
53
|
+
};
|
package/src/screenplay/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export * from './Optional';
|
|
|
12
12
|
export * from './Question';
|
|
13
13
|
export * from './questions';
|
|
14
14
|
export * from './RecursivelyAnswered';
|
|
15
|
+
export * from './SerialisedActor';
|
|
15
16
|
export * from './Task';
|
|
16
17
|
export * from './time';
|
|
17
18
|
export * from './WithAnswerableProperties';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Ability } from '../abilities';
|
|
1
|
+
import { Ability, type SerialisedAbility } from '../abilities';
|
|
2
2
|
import { Notepad } from './Notepad';
|
|
3
3
|
|
|
4
4
|
/**
|
|
@@ -254,4 +254,13 @@ export class TakeNotes<Notes_Type extends Record<any, any>> extends Ability {
|
|
|
254
254
|
constructor(public readonly notepad: Notepad<Notes_Type>) {
|
|
255
255
|
super();
|
|
256
256
|
}
|
|
257
|
+
|
|
258
|
+
toJSON(): SerialisedAbility {
|
|
259
|
+
return {
|
|
260
|
+
...super.toJSON(),
|
|
261
|
+
options: {
|
|
262
|
+
notepad: this.notepad.toJSON(),
|
|
263
|
+
}
|
|
264
|
+
};
|
|
265
|
+
}
|
|
257
266
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { Discardable } from '../../abilities';
|
|
1
|
+
import type { Discardable, SerialisedAbility } from '../../abilities';
|
|
2
2
|
import { Ability } from '../../abilities';
|
|
3
|
-
import type { Clock, DelayedCallback, Duration, RepeatUntilLimits} from '../models';
|
|
3
|
+
import type { Clock, DelayedCallback, Duration, RepeatUntilLimits } from '../models';
|
|
4
4
|
import { Scheduler } from '../models';
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -40,4 +40,13 @@ export class ScheduleWork extends Ability implements Discardable {
|
|
|
40
40
|
discard(): void {
|
|
41
41
|
this.scheduler.stop();
|
|
42
42
|
}
|
|
43
|
+
|
|
44
|
+
override toJSON(): SerialisedAbility {
|
|
45
|
+
return {
|
|
46
|
+
...super.toJSON(),
|
|
47
|
+
options: {
|
|
48
|
+
scheduler: this.scheduler.toJSON(),
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
}
|
|
43
52
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ensure, isDefined } from 'tiny-types';
|
|
1
|
+
import { ensure, isDefined, type JSONObject } from 'tiny-types';
|
|
2
2
|
|
|
3
3
|
import { Duration } from './Duration';
|
|
4
4
|
import { Timestamp } from './Timestamp';
|
|
@@ -24,6 +24,12 @@ export class Clock {
|
|
|
24
24
|
constructor(private readonly checkTime: () => Date = () => new Date()) {
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
+
toJSON(): JSONObject {
|
|
28
|
+
return {
|
|
29
|
+
timeAdjustment: this.timeAdjustment.toJSON(),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
27
33
|
/**
|
|
28
34
|
* Sets the clock ahead to force early resolution of promises
|
|
29
35
|
* returned by [`Clock.waitFor`](https://serenity-js.org/api/core/class/Clock/#waitFor).
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { JSONObject } from 'tiny-types';
|
|
2
|
+
|
|
1
3
|
import { OperationInterruptedError, TimeoutExpiredError } from '../../../errors';
|
|
2
4
|
import type { Clock } from './Clock';
|
|
3
5
|
import type { DelayedCallback } from './DelayedCallback';
|
|
@@ -23,6 +25,13 @@ export class Scheduler {
|
|
|
23
25
|
) {
|
|
24
26
|
}
|
|
25
27
|
|
|
28
|
+
toJSON(): JSONObject {
|
|
29
|
+
return {
|
|
30
|
+
clock: this.clock.toJSON(),
|
|
31
|
+
interactionTimeout: this.interactionTimeout.toJSON(),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
26
35
|
/**
|
|
27
36
|
* Schedules a callback function to be invoked after a delay
|
|
28
37
|
*
|
package/src/stage/Stage.ts
CHANGED
|
@@ -1,22 +1,20 @@
|
|
|
1
1
|
import { ensure, isDefined } from 'tiny-types';
|
|
2
2
|
|
|
3
|
-
import type
|
|
4
|
-
import { ConfigurationError, LogicError, RaiseErrors } from '../errors';
|
|
5
|
-
import type {
|
|
6
|
-
DomainEvent,
|
|
7
|
-
EmitsDomainEvents} from '../events';
|
|
3
|
+
import { ConfigurationError, type ErrorFactory, type ErrorOptions, LogicError, RaiseErrors,type RuntimeError } from '../errors';
|
|
8
4
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
5
|
+
ActorEntersStage,
|
|
6
|
+
ActorStageExitAttempted,
|
|
7
|
+
ActorStageExitCompleted,
|
|
8
|
+
ActorStageExitFailed,
|
|
9
|
+
ActorStageExitStarts,
|
|
10
|
+
type DomainEvent,
|
|
11
|
+
type EmitsDomainEvents,
|
|
12
12
|
SceneFinishes,
|
|
13
13
|
SceneStarts,
|
|
14
14
|
TestRunFinishes
|
|
15
15
|
} from '../events';
|
|
16
|
-
import type
|
|
17
|
-
import {
|
|
18
|
-
import type { Clock, Duration, Timestamp } from '../screenplay';
|
|
19
|
-
import { Actor, ScheduleWork } from '../screenplay';
|
|
16
|
+
import { type ActivityDetails, CorrelationId, Name } from '../model';
|
|
17
|
+
import { Actor, type Clock, type Duration, ScheduleWork, type Timestamp } from '../screenplay';
|
|
20
18
|
import type { ListensToDomainEvents } from '../stage';
|
|
21
19
|
import type { Cast } from './Cast';
|
|
22
20
|
import type { StageManager } from './StageManager';
|
|
@@ -39,7 +37,7 @@ import type { StageManager } from './StageManager';
|
|
|
39
37
|
*/
|
|
40
38
|
export class Stage implements EmitsDomainEvents {
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
public static readonly unknownSceneId = new CorrelationId('unknown')
|
|
43
41
|
|
|
44
42
|
/**
|
|
45
43
|
* Actors instantiated after the scene has started,
|
|
@@ -111,9 +109,6 @@ export class Stage implements EmitsDomainEvents {
|
|
|
111
109
|
]);
|
|
112
110
|
|
|
113
111
|
actor = this.cast.prepare(newActor);
|
|
114
|
-
|
|
115
|
-
// todo this.manager.notifyOf(ActorStarts)
|
|
116
|
-
// todo: map this in Serenity BDD Reporter so that the "cast" is recorded
|
|
117
112
|
}
|
|
118
113
|
catch (error) {
|
|
119
114
|
throw new ConfigurationError(`${ this.typeOf(this.cast) } encountered a problem when preparing actor "${ name }" for stage`, error);
|
|
@@ -123,7 +118,23 @@ export class Stage implements EmitsDomainEvents {
|
|
|
123
118
|
throw new ConfigurationError(`Instead of a new instance of actor "${ name }", ${ this.typeOf(this.cast) } returned ${ actor }`);
|
|
124
119
|
}
|
|
125
120
|
|
|
126
|
-
this.actorsOnStage.set(name, actor)
|
|
121
|
+
this.actorsOnStage.set(name, actor);
|
|
122
|
+
|
|
123
|
+
this.announce(
|
|
124
|
+
new ActorEntersStage(
|
|
125
|
+
this.currentScene,
|
|
126
|
+
actor.toJSON(),
|
|
127
|
+
)
|
|
128
|
+
)
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
if (this.actorsOnBackstage.has(name)) {
|
|
132
|
+
this.announce(
|
|
133
|
+
new ActorEntersStage(
|
|
134
|
+
this.currentScene,
|
|
135
|
+
this.actorsOnBackstage.get(name).toJSON(),
|
|
136
|
+
)
|
|
137
|
+
)
|
|
127
138
|
}
|
|
128
139
|
|
|
129
140
|
this.actorInTheSpotlight = this.instantiatedActorCalled(name);
|
|
@@ -192,6 +203,10 @@ export class Stage implements EmitsDomainEvents {
|
|
|
192
203
|
this.actorsOnStage = this.actorsOnFrontStage;
|
|
193
204
|
}
|
|
194
205
|
|
|
206
|
+
if (event instanceof SceneFinishes || event instanceof TestRunFinishes) {
|
|
207
|
+
this.notifyOfStageExit(this.currentSceneId());
|
|
208
|
+
}
|
|
209
|
+
|
|
195
210
|
this.manager.notifyOf(event);
|
|
196
211
|
|
|
197
212
|
if (event instanceof SceneFinishes) {
|
|
@@ -298,6 +313,16 @@ export class Stage implements EmitsDomainEvents {
|
|
|
298
313
|
: this.actorsOnFrontStage.get(name)
|
|
299
314
|
}
|
|
300
315
|
|
|
316
|
+
private notifyOfStageExit(sceneId: CorrelationId): void {
|
|
317
|
+
for (const actor of this.actorsOnStage.values()) {
|
|
318
|
+
this.announce(new ActorStageExitStarts(
|
|
319
|
+
sceneId,
|
|
320
|
+
actor.toJSON(),
|
|
321
|
+
this.currentTime(),
|
|
322
|
+
));
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
|
|
301
326
|
private async dismiss(activeActors: Map<string, Actor>): Promise<void> {
|
|
302
327
|
const actors = Array.from(activeActors.values());
|
|
303
328
|
|
|
@@ -311,10 +336,9 @@ export class Stage implements EmitsDomainEvents {
|
|
|
311
336
|
const actorsToDismiss = new Map<Actor, CorrelationId>(actors.map(actor => [actor, CorrelationId.create()]));
|
|
312
337
|
|
|
313
338
|
for (const [ actor, correlationId ] of actorsToDismiss) {
|
|
314
|
-
this.announce(new
|
|
315
|
-
new Name(this.constructor.name),
|
|
316
|
-
new Description(`Dismissing ${ actor.name }...`),
|
|
339
|
+
this.announce(new ActorStageExitAttempted(
|
|
317
340
|
correlationId,
|
|
341
|
+
new Name(actor.name),
|
|
318
342
|
this.currentTime(),
|
|
319
343
|
));
|
|
320
344
|
}
|
|
@@ -324,13 +348,14 @@ export class Stage implements EmitsDomainEvents {
|
|
|
324
348
|
try {
|
|
325
349
|
await actor.dismiss();
|
|
326
350
|
|
|
327
|
-
this.announce(new
|
|
328
|
-
correlationId,
|
|
329
|
-
this.currentTime(),
|
|
330
|
-
));
|
|
351
|
+
this.announce(new ActorStageExitCompleted(correlationId, new Name(actor.name), this.currentTime()));
|
|
331
352
|
}
|
|
332
353
|
catch (error) {
|
|
333
|
-
this.announce(new
|
|
354
|
+
this.announce(new ActorStageExitFailed(
|
|
355
|
+
error,
|
|
356
|
+
correlationId,
|
|
357
|
+
this.currentTime()
|
|
358
|
+
));
|
|
334
359
|
}
|
|
335
360
|
}
|
|
336
361
|
|