Escreva testes de aceitação e testes de componentes para código Ember no Discourse

Os testes automatizados são uma ótima maneira de proteger seu código contra regressões futuras. Muitas pessoas já sabem como fazer isso em nossa base de código Rails com rspec, mas o lado do Javascript pode ser um pouco misterioso para alguns.

Felizmente, hoje em dia é bem fácil adicionar testes básicos ao seu código Ember!

Testes de Componentes

No tutorial anterior desta série, adicionamos um componente chamado fancy-snack para exibir nosso lanche com um fundo em fade. Vamos escrever um teste para ele. Crie o seguinte arquivo:

test/javascripts/components/snack-test.js

import componentTest from "helpers/component-test";

moduleForComponent("fancy-snack", { integration: true });

componentTest("test the rendering", {
  template: "{{fancy-snack snack=testSnack}}",

  setup() {
    this.set("testSnack", {
      name: "Potato Chips",
      description: "Now with extra trans fat!",
    });
  },

  test(assert) {
    assert.equal(this.$(".fancy-snack-title h1").text(), "Potato Chips");
    assert.equal(
      this.$(".fancy-snack-description p").text(),
      "Now with extra trans fat!"
    );
  },
});

Para executar o teste, abra seu navegador no servidor de desenvolvimento em /qunit?module=component%3Afancy-snack. O navegador então executará os testes de componente e exibirá algo como “2 asserções de 2 passaram, 0 falharam.”

Note que, na página /qunit, você pode executar outros testes. Basta selecionar um novo teste no menu suspenso Module no topo da tela.

Vamos analisar o teste para entender como ele funciona.

A linha template diz ao Ember como queremos inserir nosso componente. É exatamente a mesma marcação que você usaria para colocar o componente em um template Handlebars, então deve ser familiar:

template: '{{fancy-snack snack=testSnack}}',

Note que estamos passando testSnack como o parâmetro snack. Isso é definido no método setup():

setup() {
  this.set('testSnack', {
    name: 'Potato Chips',
    description: 'Now with extra trans fat!'
  });
},

Apenas inseri alguns dados fictícios. Isso é tudo o que precisamos fazer para que o Ember renderize o componente. Finalmente, temos algumas asserções no método test():

test(assert) {
  assert.equal(this.$('.fancy-snack-title h1').text(), 'Potato Chips');
  assert.equal(this.$('.fancy-snack-description p').text(), 'Now with extra trans fat!');
}

Se você usar this.$(), terá acesso a um seletor jQuery no seu template. As asserções aqui usam esse seletor para obter o valor do título do lanche e da descrição do lanche e compará-los com o que esperamos. Se os valores coincidirem, as asserções passarão e nosso teste estará funcionando corretamente.

Vale ressaltar que você não precisa testar tudo em um componente como este. Use seu discernimento e tente identificar quais partes do seu código podem quebrar ou causar confusão para outros desenvolvedores no futuro. Se você testar muitas coisas no seu template, pode ser difícil para alguém no futuro modificar o código. Comece pequeno, testando as coisas mais óbvias, e com o tempo você vai pegar o jeito.

Testes de Aceitação

Testes de aceitação são frequentemente mais fáceis de escrever e podem ser mais poderosos que testes de componentes, pois testam sua aplicação da mesma forma que um usuário faria em seu navegador. Eu costumo começar com testes de aceitação e, se estiver criando um componente complexo, adiciono testes específicos para ele também.

Veja como podemos escrever um teste de aceitação que visita a rota /admin/snack e confirma que o lanche foi renderizado:

test/javascripts/acceptance/snack-test.js

import { acceptance } from "helpers/qunit-helpers";
acceptance("Snack");

test("Visit Page", function (assert) {
  visit("/admin/snack");
  andThen(() => {
    assert.ok(exists(".fancy-snack-title"), "the snack title is present");
  });
});

O test() neste caso quase lê como inglês! O primeiro comando diz para visitar a URL /admin/snack. Depois disso, há um método andThen(). Esse método é necessário para garantir que todo o trabalho em segundo plano seja concluído antes que os testes continuem. Como Javascript e código Ember são assíncronos, precisamos garantir que o Ember tenha concluído tudo o que precisa antes que nossas asserções sejam executadas. Por fim, ele verifica se o elemento .fancy-snack-title está presente.

No entanto, se você executar este teste acessando /qunit?module=Acceptance%3A%20Snack, verá que o teste falhará devido a um erro de AJAX.

Se você se lembra, nosso código inclui tanto o lado Rails quanto o lado Javascript, que realiza uma requisição AJAX para obter seus dados. O teste de aceitação executou o lado Javascript, mas não soube como obter os dados do Rails.

Para corrigir isso, precisamos adicionar uma resposta fictícia, usando a excelente biblioteca pretender. Abra o arquivo test/javascripts/helpers/create-pretender.js e procure pela linha que diz:

this.get("/admin/plugins", () => response({ plugins: [] }));

Logo abaixo dela, adicione uma linha para retornar um objeto de lanche fictício para nosso teste de aceitação funcionar:

this.get("/admin/snack.json", () => {
  return response({ name: "snack name", description: "snack description" });
});

Você pode ler o código acima como “para qualquer requisição a /admin/snack.json, responda com a seguinte response.”

Se você atualizar a URL /qunit?module=Acceptance%3A%20Snack, seu teste de aceitação deve obter seus dados via pretender e os testes devem passar.

Para onde ir a partir daqui

Você pode tentar desenvolver uma pequena funcionalidade e adicionar testes para garantir que ela funcione. Você até pode tentar usar TDD criando seus testes antes de escrever qualquer código no front-end. Dependendo do que você está trabalhando e de suas preferências pessoais, pode achar essa uma maneira mais agradável de proceder. Boa sorte e bom código :slight_smile:


Este documento está sob controle de versão - sugira alterações no GitHub.

15 curtidas

My prior experience in writing qunit tests was based on the other howto

i.e. “acceptance” was simply

acceptance("Purple Tentacle", { loggedIn: true });

I have seen in other plugins where the test code contained “fake” JSON to test against. I wasn’t sure if that would be as good as testing against “real” data, so I wanted to avoid doing it that way.

The six tests passed, but I got a couple of rather angry looking “unhandled request” errors.

After finding an example of some “setup” code, I tried it and it solved the errors.

It works, but I’m not really sure why, nor why it’s needed for some but not for the majority of plugins I’ve seen that have qunit tests.

3 curtidas

For a long time we weren’t great with testing plugins, so not many people followed our example and added tests.

You are right to add a response using pretender to handle AJAX calls.

4 curtidas

Apenas uma observação de que o caminho /qunit está obsoleto. Agora é /tests. Levei um tempo para descobrir isso :slight_smile:

1 curtida