Skip to content

Commit 46f86ee

Browse files
committed
Updated VehicleDto
1 parent 849d476 commit 46f86ee

10 files changed

+391
-26
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
import { Test, TestingModule } from '@nestjs/testing';
2+
import { AddressesService } from './addresses.service';
3+
import { getRepositoryToken } from '@nestjs/typeorm';
4+
import { Address } from './entities/address.entity';
5+
import { Repository } from 'typeorm';
6+
import { HttpException, HttpStatus } from '@nestjs/common';
7+
import { CreateAddressDto } from './dto/create-address.dto';
8+
import { UpdateAddressDto } from './dto/update-address.dto';
9+
10+
const mockAddressRepository = () => ({
11+
findOne: jest.fn(),
12+
save: jest.fn(),
13+
update: jest.fn(),
14+
delete: jest.fn(),
15+
});
16+
17+
type MockRepository<T = any> = Partial<Record<keyof Repository<T>, jest.Mock>>;
18+
19+
describe('AddressesService', () => {
20+
let service: AddressesService;
21+
let addressRepository: MockRepository<Address>;
22+
23+
beforeEach(async () => {
24+
const module: TestingModule = await Test.createTestingModule({
25+
providers: [
26+
AddressesService,
27+
{
28+
provide: getRepositoryToken(Address),
29+
useFactory: mockAddressRepository,
30+
},
31+
],
32+
}).compile();
33+
34+
service = module.get<AddressesService>(AddressesService);
35+
addressRepository = module.get<MockRepository<Address>>(
36+
getRepositoryToken(Address)
37+
);
38+
});
39+
40+
describe('create', () => {
41+
it('should create a new address', async () => {
42+
const createAddressDto: CreateAddressDto = {
43+
street: 'ul. Marszałkowska 1',
44+
city: 'Warszawa',
45+
administrativeArea: 'Mazowieckie',
46+
postalCode: '00-001',
47+
country: 'Poland',
48+
};
49+
50+
const savedAddress = { id: 1, ...createAddressDto };
51+
addressRepository.findOne.mockResolvedValue(null);
52+
addressRepository.save.mockResolvedValue(savedAddress);
53+
54+
const result = await service.create(createAddressDto);
55+
expect(result).toEqual(savedAddress);
56+
expect(addressRepository.findOne).toHaveBeenCalledWith({
57+
where: {
58+
street: createAddressDto.street,
59+
city: createAddressDto.city,
60+
administrativeArea: createAddressDto.administrativeArea,
61+
postalCode: createAddressDto.postalCode,
62+
country: createAddressDto.country,
63+
},
64+
});
65+
expect(addressRepository.save).toHaveBeenCalledWith(createAddressDto);
66+
});
67+
68+
it('should throw an error if address already exists', async () => {
69+
const createAddressDto: CreateAddressDto = {
70+
street: 'ul. Marszałkowska 1',
71+
city: 'Warszawa',
72+
administrativeArea: 'Mazowieckie',
73+
postalCode: '00-001',
74+
country: 'Poland',
75+
};
76+
77+
addressRepository.findOne.mockResolvedValue(createAddressDto);
78+
79+
await expect(service.create(createAddressDto)).rejects.toThrow(
80+
new HttpException(
81+
{
82+
status: HttpStatus.CONFLICT,
83+
error: 'Address already exists',
84+
},
85+
HttpStatus.CONFLICT
86+
)
87+
);
88+
});
89+
});
90+
91+
describe('findOne', () => {
92+
it('should return an address if found', async () => {
93+
const address = {
94+
id: 1,
95+
street: 'ul. Marszałkowska 1',
96+
city: 'Warszawa',
97+
administrativeArea: 'Mazowieckie',
98+
postalCode: '00-001',
99+
country: 'Poland',
100+
};
101+
addressRepository.findOne.mockResolvedValue(address);
102+
103+
const result = await service.findOne(1);
104+
expect(result).toEqual(address);
105+
expect(addressRepository.findOne).toHaveBeenCalledWith({
106+
where: { id: 1 },
107+
});
108+
});
109+
110+
it('should throw a NotFoundException if address is not found', async () => {
111+
addressRepository.findOne.mockResolvedValue(null);
112+
113+
await expect(service.findOne(1)).rejects.toThrow(
114+
new HttpException(
115+
{
116+
status: HttpStatus.NOT_FOUND,
117+
error: `Address with id 1 not found`,
118+
},
119+
HttpStatus.NOT_FOUND
120+
)
121+
);
122+
});
123+
});
124+
125+
describe('update', () => {
126+
it('should update an address if found', async () => {
127+
const updateAddressDto: UpdateAddressDto = {
128+
street: 'ul. Marszałkowska 2',
129+
city: 'Warszawa',
130+
administrativeArea: 'Mazowieckie',
131+
postalCode: '00-002',
132+
country: 'Poland',
133+
};
134+
135+
const address = { id: 1, ...updateAddressDto };
136+
addressRepository.findOne.mockResolvedValue(address);
137+
addressRepository.update.mockResolvedValue(address);
138+
139+
const result = await service.update(1, updateAddressDto);
140+
expect(result).toEqual(address);
141+
expect(addressRepository.findOne).toHaveBeenCalledWith({
142+
where: { id: 1 },
143+
});
144+
expect(addressRepository.update).toHaveBeenCalledWith(
145+
1,
146+
updateAddressDto
147+
);
148+
});
149+
150+
it('should throw a NotFoundException if address is not found', async () => {
151+
addressRepository.findOne.mockResolvedValue(null);
152+
153+
await expect(
154+
service.update(1, {} as UpdateAddressDto)
155+
).rejects.toThrow(
156+
new HttpException(
157+
{
158+
status: HttpStatus.NOT_FOUND,
159+
error: `Address with id 1 not found`,
160+
},
161+
HttpStatus.NOT_FOUND
162+
)
163+
);
164+
});
165+
});
166+
167+
describe('remove', () => {
168+
it('should remove an address if found', async () => {
169+
const address = {
170+
id: 1,
171+
street: 'ul. Marszałkowska 1',
172+
city: 'Warszawa',
173+
administrativeArea: 'Mazowieckie',
174+
postalCode: '00-001',
175+
country: 'Poland',
176+
};
177+
addressRepository.findOne.mockResolvedValue(address);
178+
addressRepository.delete.mockResolvedValue(address);
179+
180+
await service.remove(1);
181+
expect(addressRepository.findOne).toHaveBeenCalledWith({
182+
where: { id: 1 },
183+
});
184+
expect(addressRepository.delete).toHaveBeenCalledWith(1);
185+
});
186+
187+
it('should throw a NotFoundException if address is not found', async () => {
188+
const id = 1;
189+
jest.spyOn(addressRepository, 'findOne').mockResolvedValue(null);
190+
191+
await expect(service.remove(id)).rejects.toThrow(
192+
new HttpException(
193+
{
194+
status: HttpStatus.NOT_FOUND,
195+
error: `Address with id ${id} not found`,
196+
},
197+
HttpStatus.NOT_FOUND
198+
)
199+
);
200+
});
201+
});
202+
});

apps/car-rental-backend/src/resources/addresses/addresses.service.ts

+50-5
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ export class AddressesService {
1313
@InjectRepository(Address)
1414
private readonly addressesRepository: Repository<Address>
1515
) {}
16+
1617
async create(createAddressDto: CreateAddressDto): Promise<AddressDto> {
1718
this.logger.log('Checking if address already exists');
1819
const address = await this.addressesRepository.findOne({
@@ -40,14 +41,58 @@ export class AddressesService {
4041
this.logger.log(`Address created with id ${savedAddress.id} created`);
4142
return savedAddress;
4243
}
43-
async findOne(id: number) {
44+
45+
async findOne(id: number): Promise<AddressDto> {
46+
this.logger.log(`Finding address with id ${id}`);
4447
const result = await this.addressesRepository.findOne({ where: { id } });
48+
if (!result) {
49+
this.logger.error(`Address with id ${id} not found`);
50+
throw new HttpException(
51+
{
52+
status: HttpStatus.NOT_FOUND,
53+
error: `Address with id ${id} not found`,
54+
},
55+
HttpStatus.NOT_FOUND
56+
);
57+
}
58+
this.logger.log(`Address with id ${id} found`);
4559
return result;
4660
}
47-
async update(id: number, updateAddressDto: UpdateAddressDto) {
48-
return this.addressesRepository.update(id, updateAddressDto);
61+
62+
async update(id: number, updateAddressDto: UpdateAddressDto): Promise<AddressDto> {
63+
const addressToBeUpdated = await this.findOne(id);
64+
if (!addressToBeUpdated) {
65+
this.logger.error(`Address with id ${id} not found`);
66+
throw new HttpException(
67+
{
68+
status: HttpStatus.NOT_FOUND,
69+
error: `Address with id ${id} not found`,
70+
},
71+
HttpStatus.NOT_FOUND
72+
);
73+
}
74+
this.logger.log(`Updating address with id ${id}`);
75+
await this.addressesRepository.update(id, updateAddressDto);
76+
this.logger.log(`Address with id ${id} updated`);
77+
return this.findOne(id);
4978
}
50-
async remove(id: number) {
51-
return this.addressesRepository.delete(id);
79+
80+
async remove(id: number): Promise<void> {
81+
this.logger.log(`Checking if address with id ${id} exists`);
82+
const address = await this.findOne(id);
83+
if (!address) {
84+
this.logger.error(`Address with id ${id} not found`);
85+
throw new HttpException(
86+
{
87+
status: HttpStatus.NOT_FOUND,
88+
error: `Address with id ${id} not found`,
89+
},
90+
HttpStatus.NOT_FOUND
91+
);
92+
}
93+
this.logger.log(`Address with id ${id} exists`);
94+
this.logger.log(`Deleting address with id ${id}`);
95+
await this.addressesRepository.delete(id);
96+
this.logger.log(`Address with id ${id} deleted`);
5297
}
5398
}

apps/car-rental-backend/src/resources/addresses/dto/address.dto.ts

+2
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,13 @@ export class AddressDto {
88
description: 'The unique identifier of the address.',
99
})
1010
id: number;
11+
1112
@ApiProperty({
1213
example: '2021-09-01T00:00:00.000Z',
1314
description: 'The date and time when the address was created.',
1415
})
1516
createdAt: Date;
17+
1618
@ApiProperty({
1719
example: '2021-09-01T00:00:00.000Z',
1820
description: 'The date and time when the address was last updated.',
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
import { PartialType } from '@nestjs/swagger/dist/type-helpers/partial-type.helper';
2-
import { CreateAddressDto } from './create-address.dto';
2+
import { AddressDto } from './address.dto';
33

4-
export class UpdateAddressDto extends PartialType(CreateAddressDto) {}
4+
export class UpdateAddressDto extends PartialType(AddressDto) {}

apps/car-rental-backend/src/resources/vehicle-brands/vehicle-brands.controller.spec.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Test, TestingModule } from '@nestjs/testing';
22
import { VehicleBrandsController } from './vehicle-brands.controller';
33
import { VehicleBrandsService } from './vehicle-brands.service';
4-
import { PageDto } from '../common/pages/dto/page.dto';
5-
import { PageOptionsDto } from '../common/pages/dto/page-options.dto';
4+
import { PageDto } from '../../common/pages/dto/page.dto';
5+
import { PageOptionsDto } from '../../common/pages/dto/page-options.dto';
66
import { CreateVehicleBrandDto } from './dto/create-vehicle-brand.dto';
77
import { UpdateVehicleBrandDto } from './dto/update-vehicle-brand.dto';
88
import { VehicleBrandDto } from './dto/vehicle-brand.dto';

apps/car-rental-backend/src/resources/vehicle-brands/vehicle-brands.service.spec.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
44
import { Repository, SelectQueryBuilder } from 'typeorm';
55
import { HttpException, HttpStatus } from '@nestjs/common';
66
import { VehicleBrand } from './entities/vehicle-brand.entity';
7-
import { Order } from '../common/constants';
7+
import { Order } from '../../common/constants';
88

99
describe('VehicleBrandsService', () => {
1010
let service: VehicleBrandsService;
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,43 @@
1-
import { OmitType, PartialType } from '@nestjs/swagger';
1+
import { ApiProperty, OmitType, PartialType } from '@nestjs/swagger';
22
import { VehicleDto } from './vehicle.dto';
3+
import { CreateAddressDto } from '../../addresses/dto/create-address.dto';
4+
import { UpdateAddressDto } from '../../addresses/dto/update-address.dto';
5+
import { IsOptional, ValidateNested } from 'class-validator';
6+
import { Type } from 'class-transformer';
37

48
export class UpdateVehicleDto extends PartialType(
5-
OmitType(VehicleDto, ['id', 'createdAt', 'updatedAt'] as const)
6-
) {}
9+
OmitType(VehicleDto, [
10+
'id',
11+
'createdAt',
12+
'updatedAt',
13+
'clientAddress',
14+
] as const)
15+
) {
16+
@ValidateNested()
17+
@IsOptional()
18+
@Type(() => UpdateAddressDto || CreateAddressDto)
19+
@ApiProperty({
20+
description: 'The address of the client who rented the vehicle.',
21+
type: UpdateAddressDto || CreateAddressDto,
22+
examples: [
23+
{
24+
id: 1,
25+
createdAt: '2021-09-01T00:00:00.000Z',
26+
updatedAt: '2021-09-01T00:00:00.000Z',
27+
city: 'Bielsko-Biała',
28+
administrativeArea: 'Śląskie',
29+
postalCode: '43-300',
30+
country: 'Poland',
31+
street: 'ul. Cieszyńska 12',
32+
},
33+
{
34+
city: 'Bielsko-Biała',
35+
administrativeArea: 'Śląskie',
36+
postalCode: '43-300',
37+
country: 'Poland',
38+
street: 'ul. Cieszyńska 12',
39+
},
40+
],
41+
})
42+
clientAddress?: UpdateAddressDto | CreateAddressDto;
43+
}

0 commit comments

Comments
 (0)