Create API with NestJS using TDD approach, part 3!!
joedev090

joedev090 @joedev090

About: A enthusiastac software developer with more experience in the frontend side. Fanatic to create a clean code and the best practices of web/mobile technology prefered angular, react.

Location:
Quito, Ecuador
Joined:
Apr 18, 2021

Create API with NestJS using TDD approach, part 3!!

Publish Date: Aug 8
0 0

Hey Coders!!!

Let's continue with the last part of my project on NestJS using TDD approach.

Remember the core concepts!

  1. Write a Failing Test:
    The first step in the TDD cycle is to write a test for a small piece of functionality that you want to implement

  2. Write Minimal Code to Pass the Test:
    The next step is to write the minimal amount of code necessary to make the test pass

  3. Refactor the Code:
    Once the test is passing, the final step is to refactor the code to improve its structure and readability.

This cycle, often referred to as "Red-Green-Refactor," ensures that you always have a working version of your code and that all parts of your codebase are covered by tests.

We have to add the removed functionality, so let's write our tests for the service in
src/properties/test/properties.service.spec.ts

// remove
  describe('remove', () => {
    it('should remove a property', async () => {
      const mockProperty = {
        id: 1,
        name: 'Test Property',
        description: 'Test Description',
        location: 'Test Location',
        imageUrl: 'http://example.com/image.jpg',
        unitsAvailable: 5,
        hasWifi: true,
        hasLaundry: false,
      };

      // Mockeamos la búsqueda de la propiedad
      jest.spyOn(repository, 'findOne').mockResolvedValue(mockProperty);
      // Mockeamos la eliminación
      jest.spyOn(repository, 'remove').mockResolvedValue(mockProperty);

      const result = await service.remove(1);

      expect(result).toEqual(mockProperty);
      expect(repository.findOne).toHaveBeenCalledWith({ where: { id: 1 } });
      expect(repository.remove).toHaveBeenCalledWith(mockProperty);
    });

    it('should throw NotFoundException if property does not exist', async () => {
      // Mockeamos que la propiedad no se encuentra
      jest.spyOn(repository, 'findOne').mockResolvedValue(null);

      await expect(service.remove(999)).rejects.toThrow(NotFoundException);
      expect(repository.findOne).toHaveBeenCalledWith({ where: { id: 999 } });
      expect(repository.remove).not.toHaveBeenCalled();
    });
  });
Enter fullscreen mode Exit fullscreen mode

Using the Tdd approach, run the test with

npm run test

We will check some issues, we are missing the function, that is the next part will be adding in properties.service.ts

async remove(id: number): Promise<Property> {
        const propertyToRemove = await this.propertiesRepository.findOne({ where: { id } });
        if (!propertyToRemove) {
            throw new NotFoundException(`Property with ID ${id} not found.`);
        }
        await this.propertiesRepository.remove(propertyToRemove);
        return propertyToRemove;
    }
Enter fullscreen mode Exit fullscreen mode

After this we run the tests again with npm run test.

We will have one issue, we are missing the remove part in the mockRepository on the beforeEach part.

beforeEach(async () => {
    const mockRepository = {
      find: jest.fn().mockResolvedValue([]),
      findOne: jest.fn().mockImplementation((options) =>
        options.where.id === 999
          ? Promise.resolve(null)
          : Promise.resolve({
              id: 1,
              name: 'Test Property',
              description: 'Test Description',
              location: 'Test Location',
              imageUrl: 'http://example.com/image.jpg',
              unitsAvailable: 5,
              hasWifi: true,
              hasLaundry: false,
            }),
      ),
      create: jest.fn().mockImplementation((dto) => dto),
      save: jest
        .fn()
        .mockImplementation((property) =>
          Promise.resolve({ id: 1, ...property }),
        ),
      remove: jest.fn().mockImplementation((property) =>
        Promise.resolve(property),
      ),
    };

    const module: TestingModule = await Test.createTestingModule({
      providers: [
        PropertiesService,
        {
          provide: getRepositoryToken(Property),
          useValue: mockRepository,
        },
      ],
    }).compile();

    service = module.get<PropertiesService>(PropertiesService);
    repository = module.get<Repository<Property>>(getRepositoryToken(Property));
  });
Enter fullscreen mode Exit fullscreen mode

Then run the tests

npm run test

Wuhuuuu!!! we have only to add the controller part.

Let's work on this, the next part is creating the tests for the controller

In src/properties/test/properties.controller.spec.ts

We will add this code

describe('remove', () => {
      it('should remove a property', async () => {
          const mockProperty = {
              id: 1,
              name: 'Test Property',
              description: 'Test Description',
              location: 'Test Location',
              imageUrl: 'http://example.com/image.jpg',
              unitsAvailable: 5,
              hasWifi: true,
              hasLaundry: false,
          };

          // Mockeamos la función remove del servicio
          (service.remove as jest.Mock).mockResolvedValue(mockProperty);

          const result = await controller.remove(1);

          expect(result).toEqual(mockProperty);
          expect(service.remove).toHaveBeenCalledWith(1);
      });
  });
Enter fullscreen mode Exit fullscreen mode

We learned from the previous function, so let's add the part in the mockRepository in the same file

remove: jest.fn().mockImplementation((id: number) =>
        Promise.resolve({ id }),
      ),
Enter fullscreen mode Exit fullscreen mode

We know if we run the testing, it will fail.

npm run test

We are missing the remove function in

src/properties/properties.controller.ts

@Delete(':id')
  async remove(@Param('id') id: number): Promise<Property> {
    return this.propertiesService.remove(id);
  }
Enter fullscreen mode Exit fullscreen mode

And then after running npm run test

All test are passed

Mmmmmm

We are missing our last part, adding swagger to see our project like this:

that is one task for you...

I will share the final version on my github of the project and also the third part with each step of this tutorial.

I enjoyed a lot to do this tutorial, the TDD approach is a way of programming and it has a lot of benefits (also some cons), but it is one of the best way to have your project always ready to run with no problems!!!

See you Coders, if this post is useful for you, please like and share it! :)

Github Last Part:
https://github.com/joeaspiazudeveloper/nestjs-houselocation-tdd/tree/final-part-removeRest

Github Completed CRUD properties with Swagger
https://github.com/joeaspiazudeveloper/properties-api-nestjs

Comments 0 total

    Add comment