# Remaining service tests

Inside the <mark style="color:blue;">`describe()`</mark> for the <mark style="color:blue;">`findOne()`</mark> method, we may then have another <mark style="color:blue;">`describe()`</mark> below the previous one for when a <mark style="color:blue;">`user`</mark> is **not found**. What we'll do:

* Have an <mark style="color:blue;">`exception`</mark> representing this situation
* Make the <mark style="color:blue;">`repository`</mark> method return a <mark style="color:red;">rejected</mark> promise with this <mark style="color:blue;">`exception`</mark>
* Check if the <mark style="color:blue;">`exception`</mark> was propagated

```typescript
describe('otherwise', () => {
  it('should propagate the exception', async () => {
    const id = 1;

    const exception = new NotFoundException('User not found');
    repository.findOneByOrFail.mockRejectedValueOnce(exception);

    let error: Error;

    try {
      await service.findOne(id);
    } catch (err) {
      error = err;
    }

    expect(error).toBe(exception);
  });
});
```

Alright, now for <mark style="color:blue;">`findAll()`</mark>. This one will be quite simple, we:

* Create an array with <mark style="color:blue;">`expectedUsers`</mark>
* Make the <mark style="color:blue;">`find()`</mark> method of the <mark style="color:blue;">`repository`</mark> return them
* Check if the obtained <mark style="color:blue;">`users`</mark> match the <mark style="color:blue;">`expectedUsers`</mark>

```typescript
describe('findAll', () => {
  it('should return an array of users', async () => {
    const expectedUsers = [genUser(1), genUser(2)];

    repository.find.mockResolvedValueOnce(expectedUsers);

    const users = await service.findAll();

    expect(users).toBe(expectedUsers);
  });
});
```

For <mark style="color:blue;">`create()`</mark>, let's:

* Have a fake <mark style="color:blue;">`createUserDto`</mark> and an <mark style="color:blue;">`expectedUser`</mark> with the contents of this DTO
* Make the <mark style="color:blue;">`create()`</mark> and <mark style="color:blue;">`save()`</mark> methods of the <mark style="color:blue;">`repository`</mark> return them, respectively
* Check if the result matches the expectation

```typescript
describe('when no errors occur', () => {
  it('should create a user', async () => {
    const id = 1;
    const createUserDto = genCreateDto();
    const expectedUser = genUser(id, createUserDto);
  
    repository.create.mockReturnValueOnce(createUserDto as User);
    repository.save.mockResolvedValueOnce(expectedUser);
  
    const user = await service.create(createUserDto);
  
    expect(user).toBe(expectedUser);
  });
});
```

It should also propagate <mark style="color:blue;">`exceptions`</mark>, so let's test this too.

```typescript
describe('otherwise', () => {
  it('should propagate exceptions', async () => {
    const createUserDto = genCreateDto();
  
    const exception = new ConflictException('Error creating user');
    repository.create.mockReturnValueOnce(createUserDto as User);
    repository.save.mockRejectedValueOnce(exception);
  
    let error: Error;
  
    try {
      await service.create(createUserDto);
    } catch (err) {
      error = err;
    }
  
    expect(error).toBe(exception);
  });
});
```

For <mark style="color:blue;">`update()`</mark>, we:

* Have an <mark style="color:blue;">`existingUser`</mark>, a fake <mark style="color:blue;">`updateUserDto`</mark> and an <mark style="color:blue;">`expectedUser`</mark>, which receives the contents of the <mark style="color:blue;">`existingUser`</mark> and then, of the <mark style="color:blue;">`updateUserDto`</mark> over them
* Have <mark style="color:blue;">`preload()`</mark> and <mark style="color:blue;">`save()`</mark> return the <mark style="color:blue;">`expectedUsed`</mark>
* Perform the assertion, as usual

```typescript
describe('when user exists', () => {
  it('should update the user', async () => {
    const id = 1;
    const existingUser = genUser(id);
    const updateUserDto = genUpdateDto();
    const expectedUser = {
      ...existingUser,
      ...updateUserDto,
    } as User;

    repository.preload.mockResolvedValueOnce(expectedUser);
    repository.save.mockResolvedValueOnce(expectedUser);

    const user = await service.update(id, updateUserDto);

    expect(user).toBe(expectedUser);
  });
});
```

And also check in the case of an <mark style="color:blue;">`exception`</mark>. Remember that, in this case, it's the <mark style="color:blue;">`service`</mark> itself that throws it and not the <mark style="color:blue;">`repository`</mark>. There is no need to mock the return of the <mark style="color:blue;">`repository`</mark> methods here because they don't return anything by default. So, when <mark style="color:blue;">`preload()`</mark> returns <mark style="color:blue;">undefined</mark>, the exception will be thrown, similarly to when the <mark style="color:blue;">`user`</mark> is not found.

```typescript
describe('otherwise', () => {
  it('should throw the adequate exception', async () => {
    const id = 1;
    const updateUserDto = genUpdateDto();

    const exception = new NotFoundException('User not found');

    let error: Error;

    try {
      await service.update(id, updateUserDto);
    } catch (err) {
      error = err;
    }

    expect(error).toEqual(exception);
  });
});
```

{% hint style="info" %}
Here, <mark style="color:blue;">`toEqual()`</mark> is used instead of <mark style="color:blue;">`toBe()`</mark> because, remember that the <mark style="color:blue;">`exception`</mark> has a **composite type**. With primitive types only the value matters, but for composite types the reference is also important. So, as in this case it's not this exact <mark style="color:blue;">`exception`</mark> that will be thrown, but another one that is identical to it, we need to use <mark style="color:blue;">`toEqual()`</mark> to check if our <mark style="color:blue;">`exception`</mark> here has the same shape of the one being thrown, whereas using <mark style="color:blue;">`toBe()`</mark> would check if they are the exact same <mark style="color:blue;">`exception`</mark>, which is not the case here.
{% endhint %}

In the case of <mark style="color:blue;">`remove()`</mark>, we have an interesting difference. Here, we call the <mark style="color:blue;">`findOne()`</mark> method of the <mark style="color:blue;">`service`</mark> itself. It would be interesting to mock it here, as we don't want to have its actual functionality, as it is not the focus of this test. But how could we achieve this, as it is a method from the actual <mark style="color:blue;">`service`</mark> and not from a mock? This can be done with the <mark style="color:blue;">`spyOn()`</mark> function from Jest. It allows for applying a mocked implementation to a "normal" method through the following form:

```typescript
describe('when user exists', () => {
  it('should remove the user', async () => {
    const id = 1;
    const expectedUser = genUser(id);

    jest.spyOn(service, 'findOne').mockResolvedValueOnce(expectedUser);
    repository.remove.mockResolvedValueOnce(expectedUser);

    const user = await service.remove(id);

    expect(user).toBe(expectedUser);
  });
});
```

We can do the same in the case of an <mark style="color:blue;">`exception`</mark>.

```typescript
describe('otherwise', () => {
  it('should propagate the exception', async () => {
    const id = 1;

    const exception = new NotFoundException('User not found');
    jest.spyOn(service, 'findOne').mockRejectedValueOnce(exception);

    let error: Error;

    try {
      await service.remove(id);
    } catch (err) {
      error = err;
    }

    expect(error).toBe(exception);
  });
});
```

And we're done! Let's then proceed to the tests for the <mark style="color:blue;">`UsersController`</mark>. They will be quite simple.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://kinesis-school-of-programming.gitbook.io/nestjs-unleashed/extra-module-6-automated-testing/unit-tests/remaining-service-tests.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
