Skip to content

Commit

Permalink
domain: notification domain ok, ci: unit tests ok
Browse files Browse the repository at this point in the history
  • Loading branch information
Bruno Fernandes committed Jun 18, 2024
1 parent 84167f5 commit 15f4997
Show file tree
Hide file tree
Showing 11 changed files with 403 additions and 13 deletions.
20 changes: 20 additions & 0 deletions .github/workflows/run-unit-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Run Unit Tests

on: [push]

jobs:
run-unit-tests:
name: Run Unit Tests
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3

- uses: actions/setup-node@v3
with:
node-version: 18
cache: "npm"

- run: npm ci

- run: npm run test
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# FastFeet API - Desafio Rocketseat

[![Typescript Badge](https://img.shields.io/badge/TypeScript-20232A?style=for-the-badge&logo=typescript&logoColor=007acd&link=https://gist.github.com/bruno-valero/302a8b36f8fb5749bd15866b523b315e)](https://gist.github.com/bruno-valero/302a8b36f8fb5749bd15866b523b315e)
[![NodeJS Badge](https://img.shields.io/badge/Node.js-20232A?style=for-the-badge&logo=node.js&logoColor=68a063&link=https://gist.github.com/bruno-valero/9c4167a53b05049712ee0333c5664904)](https://gist.github.com/bruno-valero/9c4167a53b05049712ee0333c5664904)
[![NestJS Badge](https://img.shields.io/badge/Nest.js-20232A?style=for-the-badge&logo=nestjs&logoColor=f00057&link=https://gist.github.com/bruno-valero/9c790eee84ac5cecbf41962c79098f9d)](https://gist.github.com/bruno-valero/9c790eee84ac5cecbf41962c79098f9d)

Nesse desafio desenvolveremos uma API para controle de encomendas de uma transportadora fictícia, a FastFeet.

Confira o enunciado do desafio no [Notion](https://efficient-sloth-d85.notion.site/Desafio-04-a3a2ef9297ad47b1a94f89b197274ffd)
Expand Down
23 changes: 16 additions & 7 deletions src/domain/core/deliveries-and-orders/enterprise/entities/order.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { OrderAttachment } from './order-attachment'
import { OrderAlreadyReturnedError } from '@/core/errors/errors/order-errors/order-already-returned-error copy'
import { OrderNotAwaitingPickupError } from '@/core/errors/errors/order-errors/order-not-awaiting-for-pickup-error'
import { OrderWasNotCollectedError } from '@/core/errors/errors/order-errors/order-was-not-collected-error'
import { OrderCourierCollectedEvent } from '../events/order-courier-collected-event'

export interface OrderProps {
recipientId: UniqueEntityId
Expand Down Expand Up @@ -174,7 +175,7 @@ export class Order extends AggregateRoot<OrderProps> {

const updateOrder = this.update(() => {
this.props.collected = new Date()
this.addDomainEvent(new OrderCourierAcceptedEvent(this))
this.addDomainEvent(new OrderCourierCollectedEvent(this))
}, updatedBy)

return { data: updateOrder }
Expand Down Expand Up @@ -253,14 +254,22 @@ export class Order extends AggregateRoot<OrderProps> {

get actions() {
// adm
const admSetAwaitingPickup = this.admSetAwaitingPickup.bind(this)
const admCollected = this.admCollected.bind(this)
const admReturned = this.admReturned.bind(this)
const admSetAwaitingPickup = this.admSetAwaitingPickup.bind(
this,
) as Order['admSetAwaitingPickup']
const admCollected = this.admCollected.bind(this) as Order['admCollected']
const admReturned = this.admReturned.bind(this) as Order['admReturned']

// courier
const courierAccept = this.courierAccept.bind(this)
const courierReject = this.courierReject.bind(this)
const courierDeliver = this.courierDeliver.bind(this)
const courierAccept = this.courierAccept.bind(
this,
) as Order['courierAccept']
const courierReject = this.courierReject.bind(
this,
) as Order['courierReject']
const courierDeliver = this.courierDeliver.bind(
this,
) as Order['courierDeliver']

return {
courier: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import UniqueEntityId from '@/core/entities/unique-entity-id'
import { OnOrderAwaitingForPickup } from '@/domain/generic/notification/application/subscribers/on-order-awaiting-for-pickup'
import { OnOrderCourierAccepted } from '@/domain/generic/notification/application/subscribers/on-order-courier-accepted'
import {
SendNotificationUseCaseRequest,
SendNotificationUseCaseResponse,
Expand All @@ -18,7 +18,7 @@ let awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
let createNotification = makeSendNotificationUseCase()
let sut: OnOrderAwaitingForPickup // eslint-disable-line
let sut: OnOrderCourierAccepted // eslint-disable-line

let sendNotificationSpy: MockInstance<
[SendNotificationUseCaseRequest],
Expand All @@ -34,7 +34,7 @@ describe('on courier accept order', () => {
})
createNotification = makeSendNotificationUseCase()

sut = new OnOrderAwaitingForPickup(
sut = new OnOrderCourierAccepted(
createOrder.dependencies.ordersRepository,
createNotification.useCase,
)
Expand All @@ -52,7 +52,7 @@ describe('on courier accept order', () => {
requestResponsibleId: adm.id.value,
creationProps: {
address: makeAddress(),
courierId: new UniqueEntityId('123'),
courierId: null,
recipientId: new UniqueEntityId('1188'),
},
})
Expand All @@ -61,6 +61,10 @@ describe('on courier accept order', () => {
await createOrder.dependencies.ordersRepository.findMany()
)[0]

order.actions.courier.courierAccept(new UniqueEntityId('123'), adm.id)

await createOrder.dependencies.ordersRepository.update(order)

await awaitingPickup.useCase.execute({
orderId: order.id.value,
requestResponsibleId: adm.id.value,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import UniqueEntityId from '@/core/entities/unique-entity-id'
import { OnOrderCourierCanceled } from '@/domain/generic/notification/application/subscribers/on-order-courier-canceled'
import {
SendNotificationUseCaseRequest,
SendNotificationUseCaseResponse,
} from '@/domain/generic/notification/application/use-cases/send-notification'
import { makeAdm } from 'test/factories/entities/makeAdm'
import { makeAddress } from 'test/factories/entities/value-objects/makeAddress'
import { makeSendNotificationUseCase } from 'test/factories/use-cases/notification/make-send-notification-use-case'
import { makeCreateOrderUseCase } from 'test/factories/use-cases/order/make-create-order-use-case'
import { makeMarkOrderAsAwaitingForPickupUseCase } from 'test/factories/use-cases/order/make-mark-order-as-awaiting-for-pickup-use-case'
import { waitFor } from 'test/lib/await-for'
import { MockInstance } from 'vitest'

let createOrder = makeCreateOrderUseCase()
let awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
admsRepositoryAlt: createOrder.dependencies.admsRepository,
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
let createNotification = makeSendNotificationUseCase()
let sut: OnOrderCourierCanceled // eslint-disable-line

let sendNotificationSpy: MockInstance<
[SendNotificationUseCaseRequest],
Promise<SendNotificationUseCaseResponse>
>

describe('on courier cancel order', () => {
beforeEach(() => {
createOrder = makeCreateOrderUseCase()
awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
admsRepositoryAlt: createOrder.dependencies.admsRepository,
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
createNotification = makeSendNotificationUseCase()

sut = new OnOrderCourierCanceled(
createOrder.dependencies.ordersRepository,
createNotification.useCase,
)
sendNotificationSpy = vi.spyOn(createNotification.useCase, 'execute')
})

afterAll(() => {})

it('shoud be able to send a notification on courier cancel order', async () => {
await createOrder.dependencies.admsRepository.create(makeAdm())

const adm = (await createOrder.dependencies.admsRepository.findMany())[0]

await createOrder.useCase.execute({
requestResponsibleId: adm.id.value,
creationProps: {
address: makeAddress(),
courierId: new UniqueEntityId('123'),
recipientId: new UniqueEntityId('1188'),
},
})

const order = (
await createOrder.dependencies.ordersRepository.findMany()
)[0]

order.actions.courier.courierReject(adm.id)

await createOrder.dependencies.ordersRepository.update(order)

await awaitingPickup.useCase.execute({
orderId: order.id.value,
requestResponsibleId: adm.id.value,
})

await waitFor(() => {
expect(sendNotificationSpy).toHaveBeenCalled()
})
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
import UniqueEntityId from '@/core/entities/unique-entity-id'
import { OnOrderCourierCollected } from '@/domain/generic/notification/application/subscribers/on-order-courier-collected'
import {
SendNotificationUseCaseRequest,
SendNotificationUseCaseResponse,
} from '@/domain/generic/notification/application/use-cases/send-notification'
import { makeAdm } from 'test/factories/entities/makeAdm'
import { makeAddress } from 'test/factories/entities/value-objects/makeAddress'
import { makeSendNotificationUseCase } from 'test/factories/use-cases/notification/make-send-notification-use-case'
import { makeCreateOrderUseCase } from 'test/factories/use-cases/order/make-create-order-use-case'
import { makeMarkOrderAsAwaitingForPickupUseCase } from 'test/factories/use-cases/order/make-mark-order-as-awaiting-for-pickup-use-case'
import { waitFor } from 'test/lib/await-for'
import { MockInstance } from 'vitest'

let createOrder = makeCreateOrderUseCase()
let awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
admsRepositoryAlt: createOrder.dependencies.admsRepository,
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
let createNotification = makeSendNotificationUseCase()
let sut: OnOrderCourierCollected // eslint-disable-line

let sendNotificationSpy: MockInstance<
[SendNotificationUseCaseRequest],
Promise<SendNotificationUseCaseResponse>
>

describe('on courier collect order', () => {
beforeEach(() => {
createOrder = makeCreateOrderUseCase()
awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
admsRepositoryAlt: createOrder.dependencies.admsRepository,
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
createNotification = makeSendNotificationUseCase()

sut = new OnOrderCourierCollected(
createOrder.dependencies.ordersRepository,
createNotification.useCase,
)
sendNotificationSpy = vi.spyOn(createNotification.useCase, 'execute')
})

afterAll(() => {})

it('shoud be able to send a notification on courier collect order', async () => {
await createOrder.dependencies.admsRepository.create(makeAdm())

const adm = (await createOrder.dependencies.admsRepository.findMany())[0]

await createOrder.useCase.execute({
requestResponsibleId: adm.id.value,
creationProps: {
address: makeAddress(),
courierId: new UniqueEntityId('123'),
recipientId: new UniqueEntityId('1188'),
},
})

const order = (
await createOrder.dependencies.ordersRepository.findMany()
)[0]

order.actions.adm.admSetAwaitingPickup(adm.id)
order.actions.adm.admCollected(adm.id)

await createOrder.dependencies.ordersRepository.update(order)

await awaitingPickup.useCase.execute({
orderId: order.id.value,
requestResponsibleId: adm.id.value,
})

await waitFor(() => {
expect(sendNotificationSpy).toHaveBeenCalled()
})
})
})
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import UniqueEntityId from '@/core/entities/unique-entity-id'
import { DomainEvent } from '@/core/events/domain-event'
import { Order } from '../entities/order'

export class OrderDeliveredEvent implements DomainEvent {
export class OrderCourierCollectedEvent implements DomainEvent {
ocurredAt: Date
private _order: Order

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import UniqueEntityId from '@/core/entities/unique-entity-id'
import { OnOrderCourierDeliver } from '@/domain/generic/notification/application/subscribers/on-order-courier-deliver'
import {
SendNotificationUseCaseRequest,
SendNotificationUseCaseResponse,
} from '@/domain/generic/notification/application/use-cases/send-notification'
import { makeAdm } from 'test/factories/entities/makeAdm'
import { makeAddress } from 'test/factories/entities/value-objects/makeAddress'
import { makeSendNotificationUseCase } from 'test/factories/use-cases/notification/make-send-notification-use-case'
import { makeCreateOrderUseCase } from 'test/factories/use-cases/order/make-create-order-use-case'
import { makeMarkOrderAsAwaitingForPickupUseCase } from 'test/factories/use-cases/order/make-mark-order-as-awaiting-for-pickup-use-case'
import { waitFor } from 'test/lib/await-for'
import { MockInstance } from 'vitest'

let createOrder = makeCreateOrderUseCase()
let awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
admsRepositoryAlt: createOrder.dependencies.admsRepository,
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
let createNotification = makeSendNotificationUseCase()
let sut: OnOrderCourierDeliver // eslint-disable-line

let sendNotificationSpy: MockInstance<
[SendNotificationUseCaseRequest],
Promise<SendNotificationUseCaseResponse>
>

describe('on courier collect order', () => {
beforeEach(() => {
createOrder = makeCreateOrderUseCase()
awaitingPickup = makeMarkOrderAsAwaitingForPickupUseCase({
admsRepositoryAlt: createOrder.dependencies.admsRepository,
ordersRepositoryAlt: createOrder.dependencies.ordersRepository,
})
createNotification = makeSendNotificationUseCase()

sut = new OnOrderCourierDeliver(
createOrder.dependencies.ordersRepository,
createNotification.useCase,
)
sendNotificationSpy = vi.spyOn(createNotification.useCase, 'execute')
})

afterAll(() => {})

it('shoud be able to send a notification on courier collect order', async () => {
await createOrder.dependencies.admsRepository.create(makeAdm())

const adm = (await createOrder.dependencies.admsRepository.findMany())[0]

await createOrder.useCase.execute({
requestResponsibleId: adm.id.value,
creationProps: {
address: makeAddress(),
courierId: new UniqueEntityId('123'),
recipientId: new UniqueEntityId('1188'),
},
})

const order = (
await createOrder.dependencies.ordersRepository.findMany()
)[0]

order.actions.adm.admSetAwaitingPickup(adm.id)
order.actions.adm.admCollected(adm.id)
order.actions.courier.courierDeliver(new UniqueEntityId('123'))

await createOrder.dependencies.ordersRepository.update(order)

await awaitingPickup.useCase.execute({
orderId: order.id.value,
requestResponsibleId: adm.id.value,
})

await waitFor(() => {
expect(sendNotificationSpy).toHaveBeenCalled()
})
})
})
Loading

0 comments on commit 15f4997

Please sign in to comment.