Skip to content

Commit 7bd64d8

Browse files
committed
Coding experiments related to custom matchers
1 parent 82898d9 commit 7bd64d8

File tree

3 files changed

+147
-12
lines changed

3 files changed

+147
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"scripts": {
1010
"dev": "NODE_ENV=dev ts-node-dev --ignore-watch node_modules --inspect=0.0.0.0:9267 ./src/apps/mooc_backend/server.ts",
1111
"test": "npm run test:unit && npm run test:features",
12-
"test:unit": "NODE_ENV=test jest",
12+
"test:unit": "NODE_ENV=test jest --watch",
1313
"test:features": "NODE_ENV=test cucumber-js -p default",
1414
"start": "NODE_ENV=production node dist/src/apps/mooc_backend/server",
1515
"build": "npm run build:clean && npm run build:tsc && npm run build:di",

src/Contexts/Mooc/Courses/application/CourseCreator.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,13 @@ export class CourseCreator {
1616
}
1717

1818
async run(request: CreateCourseRequest): Promise<void> {
19-
const course = new Course(
19+
const course = Course.create(
2020
new CourseId(request.id),
2121
new CourseName(request.name),
2222
new CourseDuration(request.duration)
2323
);
2424

2525
await this.repository.save(course);
26-
2726
this.eventBus.publish(course.pullDomainEvents());
2827
}
2928
}
Lines changed: 145 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,164 @@
1-
import { CourseCreator } from '../../../../../src/Contexts/Mooc/Courses/application/CourseCreator';
21
import { CourseMother } from '../domain/CourseMother';
32
import { CreateCourseRequestMother } from './CreateCourseRequestMother';
3+
import { CourseCreatedDomainEventMother } from '../domain/CourseCreatedDomainEventMother';
44
import { CourseRepository } from '../../../../../src/Contexts/Mooc/Courses/domain/CourseRepository';
5-
import { Course } from '../../../../../src/Contexts/Mooc/Courses/domain/Course';
65
import { EventBus } from '../../../../../src/Contexts/Shared/domain/EventBus';
6+
import { CourseCreator } from '../../../../../src/Contexts/Mooc/Courses/application/CourseCreator';
7+
import { Course } from '../../../../../src/Contexts/Mooc/Courses/domain/Course';
8+
import { CourseCreatedDomainEvent } from '../../../../../src/Contexts/Mooc/Courses/domain/CourseCreatedDomainEvent';
9+
import { AssertionError } from 'assert';
10+
import { DomainEvent } from '../../../../../src/Contexts/Shared/domain/DomainEvent';
11+
import { Domain } from 'domain';
712

813
let repository: CourseRepository;
14+
let bus: EventBus;
915
let creator: CourseCreator;
16+
declare global {
17+
namespace jest {
18+
interface Matchers<R> {
19+
toPublish(a: DomainEvent, b: DomainEvent): R;
20+
}
21+
}
22+
}
23+
24+
expect.extend({
25+
toPublish(receivedEvent, expectedEvent) {
26+
const comparator = new DomainEventComparator()
27+
const pass = comparator.isSimilar(receivedEvent, expectedEvent);
28+
if (pass) {
29+
return {
30+
message: () =>
31+
`todo bien`,
32+
pass: true,
33+
};
34+
} else {
35+
return {
36+
message: () =>
37+
`expected ${receivedEvent} to be within range ${expectedEvent}`,
38+
pass: false,
39+
};
40+
}
41+
},
42+
});
1043

1144
const createRepository = (): CourseRepository => ({ save: jest.fn(), search: jest.fn() });
12-
const eventBus = (): EventBus => ({ publish: jest.fn()});
45+
const eventBus = (): EventBusMock => (new EventBusMock());
1346
const shouldSave = (course: Course) => expect(repository.save).toHaveBeenCalledWith(course);
47+
const shouldPublishDomainEvent = (event: CourseCreatedDomainEvent) => expect((bus.publish as jest.Mock);
1448

1549
beforeEach(() => {
1650
repository = createRepository();
17-
creator = new CourseCreator(repository, eventBus());
51+
bus = eventBus();
52+
creator = new CourseCreator(repository, bus);
1853
});
1954

20-
it('should create a valid course', async () => {
21-
const request = CreateCourseRequestMother.random();
55+
describe('Course Creator', () => {
56+
it('should create a valid course', async () => {
57+
const request = CreateCourseRequestMother.random();
2258

23-
const course = CourseMother.fromRequest(request);
59+
const course = CourseMother.fromRequest(request);
60+
const event = CourseCreatedDomainEventMother.fromCourse(course);
2461

25-
await creator.run(request);
62+
await creator.run(request);
2663

27-
shouldSave(course);
64+
//shouldSave(course);
65+
shouldPublishDomainEvent(event);
66+
});
2867
});
68+
class EventBusMock implements EventBus {
69+
private spy = jest.fn();
70+
publish(events: DomainEvent[]): void {
71+
this.spy(events);
72+
}
73+
74+
toHaveBeenCalledWith(event: DomainEvent) {
75+
this.spy.toPublish(event);
76+
const eventArg: DomainEvent[] = this.spy.mock.calls[0][0];
77+
return this.isSimilarTo(event, eventArg[0]);
78+
}
79+
80+
private isSimilarTo(event1: DomainEvent, event2: DomainEvent) {
81+
const event1Data = this.getDomainAttributes(event1);
82+
const event2Data = this.getDomainAttributes(event2);
83+
84+
return expect(event1Data).toMatchObject(event2Data);
85+
}
86+
87+
private getDomainAttributes(event: DomainEvent) {
88+
const { eventId, occurredOn, ...data } = event;
89+
90+
return data;
91+
}
92+
}
93+
94+
class Mock {
95+
toHaveBeenCalledWith(event: DomainEvent) {
96+
const eventArg: DomainEvent[] = this.spy.mock.calls[0][0];
97+
return this.isSimilarTo(event, eventArg[0]);
98+
}
99+
100+
private isSimilarTo(event1: DomainEvent, event2: DomainEvent) {
101+
const event1Data = this.getDomainAttributes(event1);
102+
const event2Data = this.getDomainAttributes(event2);
103+
104+
return expect(event1Data).toMatchObject(event2Data);
105+
}
106+
107+
private getDomainAttributes(event: DomainEvent) {
108+
const { eventId, occurredOn, ...data } = event;
109+
110+
return data;
111+
}
112+
}
113+
114+
interface Comparator<T> {
115+
isSimilar(t1: T, t2: T): void;
116+
}
117+
118+
class DomainEventComparator implements Comparator<DomainEvent> {
119+
isSimilar(event1: DomainEvent, event2: DomainEvent) {
120+
const event1Data = this.getDomainAttributes(event1);
121+
const event2Data = this.getDomainAttributes(event2);
122+
123+
return expect(event1Data).toMatchObject(event2Data);
124+
}
125+
126+
private getDomainAttributes(event: DomainEvent) {
127+
const { eventId, occurredOn, ...data } = event;
128+
129+
return data;
130+
}
131+
}
132+
class DefaultComparator implements Comparator<any> {
133+
isSimilar(event1: any, event2: any) {
134+
return expect(event1).toMatchObject(event1);
135+
}
136+
137+
}
138+
class ComparatorFactory {
139+
static comparators = new Map<string, Comparator<any>>();
140+
141+
static getComparatorFor(object: Object): Comparator<any> {
142+
const name: any = object.constructor.name;
143+
144+
if (ComparatorFactory.comparators.has(name)) {
145+
return ComparatorFactory.comparators.get(name)!;
146+
}
147+
148+
return new DefaultComparator();
149+
}
150+
}
151+
152+
// function areSimilar(obj1: Object, obj2: Object, excludingFields: Array<string>) {
153+
// const obj1WithoutExcludingFields = {};
154+
// const obj2WithoutExcludingFields = {};
155+
156+
// return expect(obj1WithoutExcludingFields).toMatchObject(obj2WithoutExcludingFields);
157+
// }
158+
159+
// function pickProperties(obj: Object, excludingFields: Array<string>) {
160+
// return obj.keys.reduce(function(keyName, value) {
161+
// if (excludingFields.includes(keyName)) {
162+
// }
163+
// }, {});
164+
// }

0 commit comments

Comments
 (0)