DEV Community

Cover image for MSW - Mock Service Worker - Escopo
Diego Souza
Diego Souza

Posted on

MSW - Mock Service Worker - Escopo

No artigo anterior vimos um exemplo de como podemos usar o MSW para interceptar uma requisição HTTP e retornar informações fictícias para usar em testes unitários. Quando fazemos isso é importante termos em mente que a requisição real não é executada, pois ela é interceptada pelo msw.

Neste artigo, vamos ver um exemplo de como deixar as funções do msw em um escopo maior para que os testes - it - levem em conta o mock. Assim, evitamos de a cada teste - it - inserir o código novamente, isto é, o DRY - Don't Repeat Yourself.

Show me the code

Imaginem o seguinte cenário: precisamos criar 2 testes para verificarmos se os dados que estão vindo da API estão corretos e o que fazemos com estes dados estão de acordo com a regra de negócio que definimos. Então, concluímos que a resposta da API deve ser sempre de sucesso, ou seja, HTTP Status Code 2xx - 200, 201, 204...

// getUserInfoGithub.js
import axios from 'axios';

export const getUserInfoGithub = async ({ username }) => {
  const { data } = await axios.get(
     `https://api.github.com/users/${username}`
  );

   return {
      ...data,
      hasTwitter: Boolean(data.twitter_username),
      hasBlog: Boolean(data.blog),
   };
};
Enter fullscreen mode Exit fullscreen mode
const { setupServer } = require('msw/node');
const { rest } = require('msw');

const getUserInfoGithub = require('./getUserInfoGithub');

const endpoint = "https://api.github.com/users/:username";

const createServer = () => 
   setupServer(
      rest.get(endpoint, (request, response, ctx) =>
         response(
            ctx.status(200),
            ctx.json({
               id: 12345678,
               twitter_username: '@TwitterUser',
               blog: 'https://gist.github.com/username',
            })
         )
      )
   );

beforeAll(() => createServer.listen());
afterEach(() => createServer.resetHandlers());
afterAll(() => createServer.close());

describe('Testing User Service', () => {
   it('should return user info twitter username', async () => {
      const response = await getUserInfoGithub('MockUser');

      expect(response.hasTwitter).toBeTruthy();
   });

   it('should return user info link blog', async () => {
      const response = await getUserInfoGithub('MockUser');

      expect(response.hasBlog).toBeTruthy();
   });
});
Enter fullscreen mode Exit fullscreen mode

Sobre o código acima, vamos as explicações:

A diferença desse código para o código do artigo anterior é o use do beforeAll do Jest. Traduzindo, o beforeAll vai executar o código dentro dele antes de todos os testes rodarem. E o código que será executado é a função createServer.

Então, antes do primeiro it executar, o servidor mock será executado e ficará ouvindo - listen - as requisições que serão feitas realmente.

O afterEach significa que depois de cada teste - it - o msw vai limpar ou resetar os manipuladores de requisição para que não afete outros testes unitários do projeto.

E o afterAll determina o que vai acontecer depois que todos os testes forem executados, nesse caso irá limpar todas os mocks que foram abertos e fechar a conexão com o servidor fictício.

Pontos de Atenção

Ao fazermos isso, todos os testes de dentro desse arquivo que na realidade farão uma requisição GET para esse endpoint vão obedecer esse mock. Isso é importante saber, porquê se em algum momento você precisar testar uma resposta HTTP Status Code diferente de 2XX, não vai dar certo. Nesse caso você precisará criar o escopo de outra forma. Segue abaixo as diferenças:

Note que deixamos a variável createServer flexível para ser usada em outros lugares e invocar outros métodos do setupServer. Assim, podemos criar outro teste para testarmos uma resposta diferente de 200 - OK.

it('should return user info link blog', async () => {
   createServer.use(
      rest.get(endpoint, (request, response, ctx) =>
         response(ctx.status(400))
      )
   );

   await expect(getUserInfoGithub('MockUser')).rejects.toThrow();
});
Enter fullscreen mode Exit fullscreen mode

Nesse cenário usamos a função use do setupServer onde conseguimos encadear outro mock, agora com uma resposta diferente, o HTTP Status Code 400 - BAD REQUEST.

E assim conseguimos testar o erro usando o await antes do expect, por se tratar de uma Promise no retorno da função. E o expect estende o método rejects - que lembra o then - para recuperar o retorno.

Diante disso temos os resultados:

Imagem mostrando que todos os testes passaram com 100% de cobertura

Outro ponto de atenção é que esse código que fizemos vai funcionar dentro do escopo desse arquivo de teste unitário. Mas você pode como que escalar ainda mais o escopo dele. Geralmente no projeto, tem um arquivo chamado jest.setup.js ou setupTests.js.

Dentro dele, você pode criar um servidor mock e colocar as requisições que você deseja interceptar para todos os arquivos de testes, como abaixo:

const { setupServer } = require('msw/node');
const { rest } = require('msw');

const createServer = 
   setupServer(
      rest.get(endpoint, (req, res, ctx) => ()),
      rest.post(endpoint, (req, res, ctx) => ()),
      rest.put(endpoint, (req, res, ctx) => ()),
      rest.delete(endpoint, (req, res, ctx) => ()),
   );

beforeAll(() => createServer.listen())
afterEach(() => createServer.resetHandlers())
afterAll(() => createServer.close())
Enter fullscreen mode Exit fullscreen mode

E depois aplicar essa configuração no arquivo jest.config.js:

// jest.config.js
module.exports = {
   setupFilesAfterEnv: ['./jest.setup.js'],
}
Enter fullscreen mode Exit fullscreen mode

Referências

Documentação do MSW

Top comments (0)