DEV Community

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

Posted on

2 1

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

Image of Datadog

Create and maintain end-to-end frontend tests

Learn best practices on creating frontend tests, testing on-premise apps, integrating tests into your CI/CD pipeline, and using Datadog’s testing tunnel.

Download The Guide

Top comments (0)

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay