|
1 | 1 | import { CourseMother } from '../domain/CourseMother'; |
2 | 2 | import { CreateCourseRequestMother } from './CreateCourseRequestMother'; |
3 | 3 | import { CourseCreatedDomainEventMother } from '../domain/CourseCreatedDomainEventMother'; |
4 | | -import { CourseRepository } from '../../../../../src/Contexts/Mooc/Courses/domain/CourseRepository'; |
5 | | -import { EventBus } from '../../../../../src/Contexts/Shared/domain/EventBus'; |
6 | 4 | 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 { DomainEvent } from '../../../../../src/Contexts/Shared/domain/DomainEvent'; |
10 | | -import { CourseId } from '../../../../../src/Contexts/Mooc/Shared/domain/Courses/CourseId'; |
| 5 | +import CourseRepositoryDouble from '../doubles/CourseRepositoryDouble'; |
| 6 | +import EventBusDouble from '../doubles/EventBusDouble'; |
11 | 7 |
|
12 | 8 | let repository: CourseRepositoryDouble; |
13 | | -let bus: EventBusDouble; |
| 9 | +let eventBus: EventBusDouble; |
14 | 10 | let creator: CourseCreator; |
15 | 11 |
|
16 | 12 | describe('Course Creator', () => { |
17 | 13 | beforeEach(() => { |
18 | 14 | repository = new CourseRepositoryDouble(); |
19 | | - bus = new EventBusDouble(); |
20 | | - creator = new CourseCreator(repository, bus); |
| 15 | + eventBus = new EventBusDouble(); |
| 16 | + creator = new CourseCreator(repository, eventBus); |
21 | 17 | }); |
22 | 18 |
|
23 | 19 | it('should create a valid course', async () => { |
24 | 20 | const request = CreateCourseRequestMother.random(); |
25 | | - const expectedCourse = CourseMother.fromRequest(request); |
26 | | - const expectedEvent = CourseCreatedDomainEventMother.fromCourse(expectedCourse); |
27 | 21 |
|
28 | 22 | await creator.run(request); |
29 | 23 |
|
30 | | - shouldSave(expectedCourse); |
31 | | - shouldPublishDomainEvent(expectedEvent); |
| 24 | + const expectedCourse = CourseMother.fromRequest(request); |
| 25 | + repository.assertLastSavedCourseIs(expectedCourse); |
| 26 | + |
| 27 | + const expectedEvent = CourseCreatedDomainEventMother.fromCourse(expectedCourse); |
| 28 | + eventBus.assertLastPublishedEventIs(expectedEvent); |
32 | 29 | }); |
33 | 30 | }); |
34 | | - |
35 | | -const shouldSave = (course: Course) => { |
36 | | - // I am not sure at all if we should remove the recorded events before comparing |
37 | | - // I have done it to prevent the tests to fail if the courses have different events |
38 | | - // or events with different ids |
39 | | - expect(course).toMatchObject(repository.getLastSavedCourseWithoutRecordedEvents()); |
40 | | -}; |
41 | | - |
42 | | -const shouldPublishDomainEvent = (event: CourseCreatedDomainEvent) => { |
43 | | - expect(bus.hasPublishedLastEvent(event)).toBe(true); |
44 | | -}; |
45 | | - |
46 | | -class EventBusDouble implements EventBus { |
47 | | - private spy = jest.fn(); |
48 | | - publish(events: DomainEvent[]): void { |
49 | | - this.spy(events); |
50 | | - } |
51 | | - |
52 | | - hasPublishedLastEvent(event: DomainEvent) { |
53 | | - const eventArg: DomainEvent[] = this.spy.mock.calls[0][0]; |
54 | | - return this.isSimilarTo(event, eventArg[0]); |
55 | | - } |
56 | | - |
57 | | - private isSimilarTo(event1: DomainEvent, event2: DomainEvent) { |
58 | | - const event1Data = this.getDomainAttributes(event1); |
59 | | - const event1DataKeys = Object.keys(event1Data); |
60 | | - const event2Data = this.getDomainAttributes(event2); |
61 | | - const event2DataKeys = Object.keys(event2Data); |
62 | | - |
63 | | - if (event1DataKeys.length !== event2DataKeys.length) { |
64 | | - return false; |
65 | | - } |
66 | | - // We are considering that all the info in the event are key: stringValue but |
67 | | - // the value may be an object and then the following comparation is not correct |
68 | | - return event1DataKeys.every(key => event1Data[key] === event2Data[key]); |
69 | | - } |
70 | | - |
71 | | - // I am not satisfied with the following "any" |
72 | | - private getDomainAttributes(event: DomainEvent): any { |
73 | | - const { eventId, occurredOn, ...data } = event; |
74 | | - |
75 | | - return data; |
76 | | - } |
77 | | -} |
78 | | - |
79 | | -class CourseRepositoryDouble implements CourseRepository { |
80 | | - private spySave: jest.Mock = jest.fn(); |
81 | | - |
82 | | - async save(course: Course) { |
83 | | - this.spySave(course); |
84 | | - } |
85 | | - |
86 | | - getLastSavedCourseWithoutRecordedEvents() { |
87 | | - const lastSavedCourse = repository.spySave.mock.calls[0][0]; |
88 | | - return new Course(lastSavedCourse.id, lastSavedCourse.name, lastSavedCourse.duration); |
89 | | - } |
90 | | - |
91 | | - async search(id: CourseId) { |
92 | | - return null; |
93 | | - } |
94 | | -} |
0 commit comments