I'm currently developing my own custom CQRS library and I've encountered an issue where a specific field is not being set correctly. The problem appears to be within classes that extend my AggregateRoot abstract class. Take a look at the following TypeScript code snippet:
import Entity from "./entity";
import Event from "./event";
export enum AggregateRootConstructionTypes {
Create,
Load
}
type CreateConstructorParams = {
type: AggregateRootConstructionTypes.Create,
createParams?: any;
}
type LoadConstructorParams = {
type: AggregateRootConstructionTypes.Load,
history: Event[]
}
type AggregateRootConstructorParams = CreateConstructorParams | LoadConstructorParams;
abstract class AggregateRoot extends Entity {
private _events: Event[] = [];
private _version: number = -1;
get domainEvents(): Event[] {
return this._events;
}
get version(): number {
return this._version;
}
addDomainEvent(event: Event): void {
this._events.push(event);
}
clearEvents(): void {
this._events.splice(0, this._events.length);
}
protected apply(event: Event): void {
this._events.push(event);
this._version++;
this.when(event);
}
protected abstract when(event: Event): void;
protected abstract create(input: any): void;
protected loadFromHistory(history: Event[]): void {
history.forEach((event) => {
this.when(event);
this._version++;
});
}
constructor(params: AggregateRootConstructorParams) {
super();
if (params.type === AggregateRootConstructionTypes.Create) {
this.create(params.createParams);
} else {
this.loadFromHistory(params.history);
}
}
}
export default AggregateRoot;
The discrepancy can be seen in the following test scenario:
import AggregateRoot, {AggregateRootConstructionTypes} from "./aggregate-root";
import Event from "./event";
describe('AggregateRoot', () => {
class CreatedEvent extends Event {}
class ExtendedAggregateRoot extends AggregateRoot {
create() {
const createdEvent = new CreatedEvent();
this.apply(createdEvent);
}
someState: number = 0;
private handleCreatedEvent() {
this.someState = 1;
}
protected when(event: Event) {
if (event instanceof CreatedEvent) {
this.handleCreatedEvent();
}
}
}
describe('when applying an event', () => {
it('should update the version, register an event, and trigger the handler in the when() function', () => {
const EAR = new ExtendedAggregateRoot({ type: AggregateRootConstructionTypes.Create });
expect(EAR.version).toEqual(0);
expect(EAR.domainEvents).toHaveLength(1);
expect(EAR.someState).toEqual(1); // ----------> this line fails
});
});
});
In the final expect statement, the test fails. I am seeking assistance in understanding why this occurs. Despite logging data throughout the process, it seems that 'someState' is unexpectedly set to 1 but upon evaluation, it remains at 0. I suspect there may be an issue with the execution context in my coding structure, however, isolating the exact cause has proven challenging. Any insights or guidance would be greatly appreciated.