Como executar apenas uma especificação de teste com angular-cli

143

Eu tenho o projeto Angular2 compilado com Angular-CLI (beta 20).

Existe uma maneira de executar testes em apenas um arquivo de especificação selecionado?

Eu costumava ter um projeto baseado no início rápido do Angular2 e podia adicionar manualmente especificações ao arquivo jasmim. Mas não sei como configurar isso fora dos testes de karma ou como limitar os testes de karma a arquivos específicos com builds de CLI angular.

Zielu
fonte

Respostas:

224

Cada .spec.tsarquivo tem todos os seus testes agrupados em describeblocos como este:

describe('SomeComponent', () => {...}

Você pode executar facilmente apenas esse único bloco, prefixando o describenome da função com f:

fdescribe('SomeComponent', () => {...}

Se você tiver essa função, nenhum outro describebloco será executado. Btw. você pode fazer algo semelhante com it=> fite também há uma versão da "lista negra" - x. Assim:

  • fdescribee fitfaz com que apenas funções marcadas dessa maneira sejam executadas
  • xdescribee xitfaz com que todas as funções marcadas dessa maneira sejam executadas
Tomek Sułkowski
fonte
1
Eu usei o fdescribe no meu arquivo helloworld.component.spec.ts, mas os erros do arquivo app.component.spec.ts também são mostrados.
Master Yoda
1
Isso ocorre porque todo o código está sendo avaliado (caso contrário, ele não saberia que existem descrições dentro de seus testes) - fdescribe limita apenas a execução dos resultados dos testes. Você ainda precisa corrigir erros de sintaxe / texto datilografado em outros arquivos.
Tomek Sułkowski
3
Eu acho que embora o OP aceitou esta resposta a pergunta era efectivamente como apenas para avaliar um arquivo de especificações: P
roberto tomás
4
Esta não é a resposta. @iislucas tem a resposta abaixo.
Ben Racicot
Posso definir algum sinalizador no meu ambiente de IC que falhe ao encontrar fdescribeou xdescribe? Não quero que um revisor desleixado mescle um PR que pule todos os meus testes.
ILikeFood 22/01
80

Configure o test.tsarquivo dentro da srcpasta:

const context = require.context('./', true, /\.spec\.ts$/);

Substitua /\.spec\.ts$/pelo nome do arquivo que você deseja testar. Por exemplo:/app.component\.spec\.ts$/

Isso executará o teste apenas para app.component.spec.ts.

Aish Anu
fonte
8
deve ser a resposta aceita, esta abordagem remove uma carga de saída gumpfy nos logs - fdescribe ao contrário, que é detalhado
danday74
3
solução fácil :) economizou muito tempo.
Detoxic-Soul 19/07/19
Isso corresponderá aos componentes antes de 'app', para que 'product-app.component.spec.ts' ou 'order-app.component.spec.ts' também corresponda. Eu não sou o melhor com regx. Existe uma maneira de segmentar especificamente o 'app.component.spec.ts'?
hanesjw
Eu tentei /^app.component\.spec\.ts$/, mas sem sorte. Parece funcionar em um testador de regex, mas o teste ng não gosta por algum motivo; produz um erro.
585 ha hahajjw
deve ser a resposta recomendada
Anil Vangari
55

Você pode testar apenas um arquivo específico com a CLI Angular (o ngcomando) assim:

ng test --main ./path/to/test.ts

Documentos adicionais estão em https://angular.io/cli/test

Observe que, embora funcione para arquivos de biblioteca independentes, não funcionará para componentes / serviços angulares / etc. Isso ocorre porque os arquivos angulares têm dependências de outros arquivos (principalmente src/test.tsno Angular 7). Infelizmente, a --mainbandeira não aceita vários argumentos.

iislucas
fonte
2
Esta é uma ótima sugestão e funciona. Obrigado! Além disso, vale a pena estar ciente de que, se tentarmos apontar para um component.spec.tsarquivo gerado automaticamente, veremos que os testes nunca começam: Error: AsyncTestZoneSpec is needed for the async() test helper but could not be found. Please make sure that your environment includes zone.js/dist/async-test.js... Tenho certeza de que uma solução alternativa adicional pode ser hackeada, mas é algo a ter em atenção porque a configuração feita dentro src/main.tse suas importações não está disponível neste caso.
Pulkitsinghal 5/05/19
Quando executo testes inteiros usando o comando, ng to teste que estou escrevendo passa, mas quando executo o arquivo específico, ocorre um erro. TypeError: Não é possível ler a propriedade 'getComponentFromError' de null em TestBedViewEngine._initIfNeeded (node_modules/@angular/core/fesm2015/testing.js: 3112: 1) em TestBedViewEngine.get (node_modules/@angular/core/fesm2015/testing.js: 3230: 1) em Function.get (node_modules/@angular/core/fesm2015/testing.js: 2960: 1) no UserContext. <anônimo> (src / app / timebar.service.spec.ts: 14: 45) "
canbax
1
Essa resposta também funciona para o Angular 8. Essa deve ser a resposta aceita, pois executará exatamente um arquivo de especificação de teste.
2
Para o Angular 9, recebo a opção desconhecida "--main" :(
rmcsharry
6

Se você deseja controlar quais arquivos são selecionados na linha de comando, consegui fazer isso no Angular 7.

Em resumo, você precisa instalar @angular-devkit/build-angular:browsere criar um plug-in personalizado do webpack para passar o regex do arquivo de teste. Por exemplo:

angular.json - altere o construtor de teste @angular-devkit/build-angular:browsere defina um arquivo de configuração personalizado:

...

        "test": {
          "builder": "@angular-builders/custom-webpack:browser",
          "options": {
            "customWebpackConfig": {
              "path": "./extra-webpack.config.js"
            },
...

extra-webpack.config.js - crie uma configuração do webpack que leia o regex na linha de comando:

const webpack = require('webpack');
const FILTER = process.env.KARMA_FILTER;
let KARMA_SPEC_FILTER = '/.spec.ts$/';
if (FILTER) {
  KARMA_SPEC_FILTER = `/${FILTER}.spec.ts$/`;
}
module.exports = {
  plugins: [new webpack.DefinePlugin({KARMA_SPEC_FILTER})]
}

test.ts - edita as especificações

...
// Then we find all the tests.
declare const KARMA_CONTEXT_SPEC: any;
const context = require.context('./', true, KARMA_CONTEXT_SPEC);

Em seguida, use o seguinte para substituir o padrão:

KARMA_FILTER='somefile-.*\.spec\.ts$' npm run test

Eu documentei a história aqui , desculpando-me antecipadamente por tipos e links incorretos. Agradeço a resposta acima de @ Aish-Anu por me indicar a direção certa.

6EQUJ5
fonte
4

Isso está funcionando para mim no Angular 7. É baseado na opção --main do comando ng. Não tenho certeza se esta opção não está documentada e está sujeita a alterações, mas funciona para mim. Coloquei uma linha no meu arquivo package.json na seção scripts. Lá, usando a opção --main com o comando ng test, eu especifico o caminho para o arquivo .spec.ts que quero executar. Por exemplo

"test 1": "ng test --main E:/WebRxAngularClient/src/app/test/shared/my-date-utils.spec.ts",

Você pode executar o script como qualquer outro script. Eu o executo no Webstorm clicando em "teste 1" na seção npm.

user2367418
fonte
3

Eu resolvi esse problema usando o grunhido. Eu tenho o script grunhido abaixo. O que o script faz é pegar o parâmetro de linha de comando do teste específico para executar e criar uma cópia de test.ts e colocar esse nome de teste específico lá.

Para executar isso, primeiro instale o grunt-cli usando:

npm install -g grunt-cli

Coloque as dependências grunt abaixo no seu package.json:

"grunt": "^1.0.1",
"grunt-contrib-clean": "^1.0.0",
"grunt-contrib-copy": "^1.0.0",
"grunt-exec": "^2.0.0",
"grunt-string-replace": "^1.3.1"

Para executá-lo, salve o arquivo grunt abaixo como Gruntfile.js na sua pasta raiz. Em seguida, na linha de comando, execute-o como:

grunt --target=app.component

Isso executará app.component.spec.ts.

O arquivo Grunt é como abaixo:

/*
This gruntfile is used to run a specific test in watch mode. Example: To run app.component.spec.ts , the Command is: 
grunt --target=app.component
Do not specific .spec.ts. If no target is specified it will run all tests.
*/
module.exports = function(grunt) {
var target = grunt.option('target') || '';
  // Project configuration.
  grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),
    clean: ['temp.conf.js','src/temp-test.ts'],
    copy: {
      main: {
        files: [
             {expand: false, cwd: '.', src: ['karma.conf.js'], dest: 'temp.conf.js'},
             {expand: false, cwd: '.', src: ['src/test.ts'], dest: 'src/temp-test.ts'}
             ],
      }
    },
    'string-replace': {
          dist: {
            files: {
              'temp.conf.js': 'temp.conf.js',
              'src/temp-test.ts': 'src/temp-test.ts'
            },
            options: {
              replacements: [{
                pattern: /test.ts/ig,
                replacement: 'temp-test.ts'
              },
              {
                pattern: /const context =.*/ig,
                replacement: 'const context = require.context(\'./\', true, /'+target+'\\\.spec\\\.ts$/);'
              }]
            }
        }
    },
    'exec': {
        sleep: {
          //The sleep command is needed here, else webpack compile fails since it seems like the files in the previous step were touched too recently
          command: 'ping 127.0.0.1 -n 4 > nul',
          stdout: true,
          stderr: true
        },
        ng_test: {
          command: 'ng test --config=temp.conf.js',
          stdout: true,
          stderr: true
        }
    }
  });

  // Load the plugin that provides the "uglify" task.
    grunt.loadNpmTasks('grunt-contrib-clean');
    grunt.loadNpmTasks('grunt-contrib-copy');
    grunt.loadNpmTasks('grunt-string-replace');
    grunt.loadNpmTasks('grunt-exec');
  // Default task(s).
  grunt.registerTask('default', ['clean','copy','string-replace','exec']);

};
vanval
fonte
Olhando para a solução aceita, eu não acho que desta forma é recomendado
Drenai
2
@ Brian - minha solução evita a necessidade de modificar o código-fonte e, portanto, evita possíveis erros na verificação do arquivo. Minha solução permite apenas especificar o nome do teste na linha de comando automatizando as etapas manuais.
vanval
Sim, esse é um bom argumento, na verdade. Há uma boa chance de você esquecer de remover o xdescribe ou fdescribe - e seu teste será removido permanentemente!
Drenai
3
@Ryan, você pode instalar / configurar o tslint-jasmine-rules para verificar as chamadas fdescribe / fit / xdescribe / xit e falhar na execução do tslint; se isso fizer parte de uma etapa de pré-confirmação, impede que você verifique acidentalmente nos testes, focados ou desativados.
Neil Menzies
1

Além disso, para pessoas como eu, que estavam procurando uma maneira de executar uma única especificação no Angular e encontraram esse SO.

De acordo com os documentos angulares mais recentes (v9.0.6 no momento da gravação), o ng testcomando tem uma --includeopção em que você pode especificar um diretório de *.spec.(ts|tsx)arquivos ou apenas um único .spec.(ts|tsx)arquivo.

https://angular.io/cli/test

earthican
fonte
0

Apenas pequenas alterações necessárias no test.tsarquivo dentro da pasta src:

const context = require.context('./', true, /test-example\.spec\.ts$/);

Aqui test-exampleestá o nome exato do arquivo que precisamos executar

Da mesma forma, se você precisar testar apenas o arquivo de serviço, poderá substituir o nome do arquivo como "/test-example.service"

madhu srinivas
fonte
0

Isso funcionou para mim em todos os casos:

ng test --include='**/dealer.service.spec.ts'

No entanto, geralmente recebo "TypeError: Não é possível ler a propriedade 'ngModule' nulo" ":

ng test --main src/app/services/dealer.service.spec.ts

Versão do @ angular / cli 10.0.4

PeterB
fonte