it-swarm-pt.tech

Remover uma chamada de seletor jQuery?

Estou tentando melhorar os testes de unidade do meu JavaScript. Eu tenho o seguinte código:

var categoryVal = $('#category').val();
if (categoryVal === '') { 
    doSomething();
} 

Meu executor de teste não tem o #category entrada na página, então como eu faria o stub/simule o seletor jQuery aqui? Eu olhei a documentação jasmin e sinon , mas não consigo descobrir como fazê-los funcionar aqui, já que seus stubs operam em objetos, que $ não é.

22
swilliams

O problema aqui é que $() é uma função que retorna um objeto com o método val(). Portanto, você deve stub $ () para retornar um objeto stub com o método val.

$ = sinon.stub();
$.withArgs('#category').returns(sinon.stub({val: function(){}}));

Mas o principal erro aqui é permitir que o código que você deseja testar chame a função $ () para criar novas instâncias. Por quê? É prática recomendada não criar novas instâncias em sua classe, mas transmiti-las ao construtor. Digamos que você tenha uma função que obterá um valor de uma entrada, o duplicará e escreverá de volta em outra:

function doubleIt(){
    $('#el2').val(('#el1').val() *2);
}

Neste caso, você cria 2 novos objetos chamando $(). Agora você tem que stub $() para retornar um mock e um stub. Usando o próximo exemplo, você pode evitar isso:

function doubleIt(el1, el2){
    el2.val(el1.val() *2);
}

Enquanto, no primeiro caso, você precisa fazer o stub $ para retornar um stub, no segundo caso você pode facilmente passar um stub e um espião para sua função.

Portanto, o teste de sinon para o segundo ficaria assim:

var el1 =  sinon.stub({val: function(){}});
    el1.returns(2);

var el2 = sinon.spy({val: function(){}}, 'val')

doubleIt(el1, el2)

assert(el2.withArgs(4).calledOnce)

Então, como você não tem elementos de dom aqui, você pode simplesmente testar a lógica de seu aplicativo sem a necessidade de criar o mesmo dom que em seu aplicativo.

35
Andreas Köberle

jQuery usa o motor seletor de css Sizzle sob o capô e foi desacoplado para que haja apenas alguns lugares onde ele se conecta. Você pode interceptar isso para evitar qualquer interação com o dom.

jQuery.find é o importante a ser alterado para responder o que você quiser. O Sinon pode ser usado aqui ou temporariamente desativando a função.

por exemplo

existingEngine = jQuery.find
jQuery.find = function(selector){ console.log(selector) }
$(".test")
//>> ".test"
jQuery.find = existingEngine

você também pode aplicar uma condição de captura específica com um substituto

existingEngine = jQuery.find
jQuery.find = function(selector){
  if(selector=='blah'}{ return "test"; }
  return existingEngine.find.apply(existingEngine, arguments)
}

Em meu trabalho recente, fiz um objeto fictício que responde como um nó dom e o envolvi em um objeto jQuery. Isso responderá a val () corretamente e terá todos os métodos jquery presentes que ele espera. No meu caso, estou simplesmente extraindo valores de um formulário. Se você estiver fazendo uma manipulação real, pode ser necessário ser mais inteligente do que isso, talvez criando um nó dom temporário com jQuery que represente o que você esperava.

obj = {
  value: "blah",
  type: "text",
  nodeName: "input",
}
$(obj).val(); // "blah"
10
tissak

Aqui está um guia muito bom para testar suas visualizações se você estiver usando Backbone.js e Jasmin. Role para baixo até a seção Exibir.

http://tinnedfruit.com/2011/04/26/testing-backbone-apps-with-jasmine-sinon-3.html

É verdade que os stubs operam em objetos. Eu acho que o ponto de criar um esboço de vista assim.

this.todoViewStub = sinon.stub(window, "TodoView")
        .returns(this.todoView);

É apenas para poder posteriormente renderizar a vista.

this.view.render();

Em outras palavras, anexe o div '#category' ao DOM do testrunner, para que $ possa agir sobre ele. Se seu div '#category' não estiver em this.view, então você provavelmente pode apenas criar uma página test.html na qual executa seu teste isolado. Este é um padrão comum no framework Javascript MVC que estou mais acostumado a esse Backbone.

Aqui está um exemplo simples de estrutura de aplicativo JMVC:

/todo
   /models
      todo.js
   /list
      /views
         init.tmpl
         listItem.tmpl
      list.css           
      list.js        (Controller)
      unitTest.js    (Tests for your list.)
      list_test.html (A html for your unit tests to run on.)

Com esta configuração, você pode apenas incluir o div "#category" em seu list_test.html se ainda não o tiver em uma das visualizações.

1
Benny Johansson