Eu tenho uma diretiva AngularJS que tem um templateUrl
definido. Estou tentando testá-lo com Jasmine.
Meu Jasmine JavaScript parece com o seguinte, por recomendação do presente :
describe('module: my.module', function () {
beforeEach(module('my.module'));
describe('my-directive directive', function () {
var scope, $compile;
beforeEach(inject(function (_$rootScope_, _$compile_, $injector) {
scope = _$rootScope_;
$compile = _$compile_;
$httpBackend = $injector.get('$httpBackend');
$httpBackend.whenGET('path/to/template.html').passThrough();
}));
describe('test', function () {
var element;
beforeEach(function () {
element = $compile(
'<my-directive></my-directive>')(scope);
angular.element(document.body).append(element);
});
afterEach(function () {
element.remove();
});
it('test', function () {
expect(element.html()).toBe('asdf');
});
});
});
});
Quando executo isso no meu erro de especificação do Jasmine, recebo o seguinte erro:
TypeError: Object #<Object> has no method 'passThrough'
Tudo o que eu quero é que o templateUrl seja carregado como está - eu não quero usar respond
. Eu acredito que isso pode estar relacionado a ele usando ngMock em vez de ngMockE2E . Se esse é o culpado, como eu uso o último em vez do primeiro?
Desde já, obrigado!
.passThrough();
dessa maneira, mas com base nos documentos, você tentou algo como:$httpBackend.expectGET('path/to/template.html'); // do action here $httpBackend.flush();
Eu acho que isso se encaixa melhor no seu uso - você não deseja capturar a solicitação, ou sejawhenGet()
, mas verifique se ela é enviada e, na verdade, Envie isto?expectGET
envia pedidos ... pelo menos fora da caixa. Nos documentos, o exemplo deles/auth.py
tem um$httpBackend.when
antes das chamadas$httpBackend.expectGET
e$httpBackend.flush
.expectGet
é apenas verificar se uma solicitação foi tentada.$httpBackend
mock para realmente usar a URL fornecida na diretivatemplateUrl
e ir buscá-la. Eu penseipassThrough
que faria isso. Você conhece uma maneira diferente de fazer isso?Respostas:
Você está certo de que está relacionado ao ngMock. O módulo ngMock é carregado automaticamente para cada teste Angular e inicializa a simulação
$httpBackend
para lidar com qualquer uso do$http
serviço, o que inclui a busca de modelos. O sistema de modelo tenta carregar o modelo$http
e ele se torna uma "solicitação inesperada" para a simulação.O que você precisa é uma maneira de pré-carregar os modelos
$templateCache
para que eles já estejam disponíveis quando o Angular solicitar, sem usar$http
.A solução preferida: Karma
Se você estiver usando o Karma para executar seus testes (e deveria), você pode configurá-lo para carregar os modelos para você com o pré - processador ng-html2js . Ng-html2js lê os arquivos HTML que você especificar e os converte em um módulo Angular que pré-carrega o arquivo
$templateCache
.Etapa 1: habilite e configure o pré-processador em seu
karma.conf.js
Se você estiver usando o Yeoman para montar seu aplicativo, essa configuração funcionará
Etapa 2: use o módulo em seus testes
Para um exemplo completo, veja este exemplo canônico do guru de teste angular Vojta Jina . Inclui uma configuração inteira: configuração, modelos e testes do karma.
Uma Solução Não-Karma
Se você não usa o Karma por qualquer motivo (eu tive um processo de compilação inflexível no aplicativo herdado) e está apenas testando em um navegador, descobri que você pode contornar a aquisição do ngMock
$httpBackend
usando um XHR bruto para buscar o modelo de verdade e insira-o no$templateCache
. Essa solução é muito menos flexível, mas faz o trabalho por enquanto.Sério, no entanto. Use Karma . Demora um pouco de trabalho para configurar, mas permite executar todos os seus testes, em vários navegadores ao mesmo tempo, na linha de comando. Assim, você pode tê-lo como parte do seu sistema de integração contínua e / ou torná-lo uma tecla de atalho do seu editor. Muito melhor do que alt-tab-refresh-ad-infinitum.
fonte
preprocessors
padrão de arquivo (por exemplo"path/to/templates/**/*.html"
) para afiles
seçãokarma.conf.js
.false
parâmetro para aopen
chamada do XHR para torná-lo síncrono. Se você não fizer isso, a execução continuará alegremente e começará a executar seus testes, sem ter o modelo carregado. Isso leva você de volta ao mesmo problema: 1) A solicitação de modelo acaba. 2) O teste começa a executar. 3) O teste compila uma diretiva e o modelo ainda não está carregado. 4) Angular solicita o modelo por meio de seu$http
serviço, que é ridicularizado. 5) O$http
serviço simulado reclama: "solicitação inesperada".npm install --save-dev karma-ng-html2js-preprocessor
) e adicioná-lo à seção de plugins do seukarma.conf.js
, de acordo com stackoverflow.com/a/19077966/859631 .O que acabei fazendo foi obter o cache do modelo e colocar a visualização lá. Eu não tenho controle sobre não usar o ngMock, ao que parece:
fonte
Este problema inicial pode ser resolvido adicionando o seguinte:
Isso ocorre porque ele tenta encontrar $ httpBackend no módulo ngMock por padrão e não está cheio.
fonte
A solução que cheguei precisa de jasmine-jquery.js e um servidor proxy.
Eu segui estes passos:
adicione jasmine-jquery.js aos seus arquivos
adicione um servidor proxy que servirá seus equipamentos
Nas suas especificações
Descreva ('MySpec', function () {var $ scope, template; jasmine.getFixtures (). fixturesPath = 'public / parcials /'; // caminho personalizado para que você possa servir o modelo real usado no aplicativo beforeEach (function () {template = angular.element ('');
});
Execute um servidor no diretório raiz do seu aplicativo
python -m SimpleHTTPServer 3502
Execute karma.
Demorei um pouco para descobrir isso, tendo que pesquisar muitos posts, acho que a documentação sobre isso deve ser mais clara, pois é uma questão tão importante.
fonte
localhost/base/specs
e adicionar um servidor proxy aopython -m SimpleHTTPServer 3502
executá-lo. Senhor, você é um gênio!Minha solução:
test/karma-utils.js
:karma.config.js
:o teste:
fonte
static
, por exemplo,beforeEach(preloadTemplate(static_url +'seed/partials/beChartDropdown.html'));
obrigado!Se você estiver usando o Grunt, poderá usar modelos grunt-angulares. Ele carrega seus modelos no templateCache e é transparente à sua configuração de especificações.
Minha configuração de amostra:
fonte
Resolvi o mesmo problema de uma maneira um pouco diferente da solução escolhida.
Primeiro, instalei e configurei o plug - in ng-html2js para o karma. No arquivo karma.conf.js:
Depois carreguei o módulo criado no beforeEach. No seu arquivo Spec.js:
Então usei $ templateCache.get para armazená-lo em uma variável. No seu arquivo Spec.js:
Finalmente, eu testei desta maneira. No seu arquivo Spec.js:
fonte
Para carregar o html de modelo dinamicamente no $ templateCache, você pode usar o pré-processador de karma html2js, conforme explicado aqui
isso se resume a adicionar modelos ' .html' aos seus arquivos no arquivo conf.js. e também pré-processadores = {' .html': 'html2js'};
E use
no seu arquivo de teste js
fonte
Uncaught SyntaxError: Unexpected token <
se você estiver usando o Karma, considere usar o karma-ng-html2js-preprocessor para pré-compilar seus modelos HTML externos e evitar que o Angular tente obtê- los por HTTP durante a execução do teste. Eu lutei com isso por alguns dos nossos - no meu caso, os caminhos parciais do templateUrl resolvidos durante a execução normal do aplicativo, mas não durante os testes - devido a diferenças nas estruturas de aplicativo versus diretório de teste.
fonte
Se você estiver usando o jasmine-maven-plugin junto com o RequireJS, poderá usar o plug - in de texto para carregar o conteúdo do modelo em uma variável e, em seguida, colocá-lo no cache do modelo.
fonte
Se você usar requirejs em seus testes, poderá usar o plug-in 'text' para extrair o modelo html e colocá-lo no $ templateCache.
fonte
Eu resolvo esse problema com a compilação de todos os modelos para o template templatecache. Estou usando gole, você pode encontrar uma solução semelhante para grunhido também. Meu templateUrls em diretivas, modais parece
Adicionar um novo pacote npm no meu package.json
"gulp-angular-templatecache": "1.*"
No arquivo gulp, adicione templatecache e uma nova tarefa:
var templateCache = require('gulp-angular-templatecache'); ... ... gulp.task('compileTemplates', function () { gulp.src([ './app/templates/**/*.html' ]).pipe(templateCache('templates.js', { transformUrl: function (url) { return '/templates/' + url; } })) .pipe(gulp.dest('wwwroot/assets/js')); });
Adicione todos os arquivos js em index.html
<script src="/assets/js/lib.js"></script> <script src="/assets/js/app.js"></script> <script src="/assets/js/templates.js"></script>
Aproveitar!
fonte