Comment exécuter une seule spécification de test avec angular-cli

143

J'ai un projet Angular2 construit avec Angular-CLI (beta 20).

Existe-t-il un moyen d'exécuter des tests sur un seul fichier de spécifications sélectionné?

J'avais un projet basé sur le démarrage rapide Angular2, et je pouvais ajouter manuellement des spécifications au fichier jasmine. Mais je ne sais pas comment configurer cela en dehors des tests de karma ou comment limiter les tests de karma à des fichiers spécifiques avec des versions Angular-CLI.

Zielu
la source

Réponses:

224

Chacun de vos .spec.tsfichiers a tous ses tests regroupés en describebloc comme ceci:

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

Vous pouvez facilement exécuter uniquement ce bloc unique, en préfixant le describenom de la fonction avec f:

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

Si vous avez une telle fonction, aucun autre describebloc ne fonctionnera. Btw. vous pouvez faire la même chose avec it=> fitet il existe également une version "liste noire" - x. Alors:

  • fdescribeet fitprovoque uniquement l' exécution des fonctions marquées de cette façon
  • xdescribeet xitfait exécuter toutes les fonctions sauf les fonctions marquées de cette façon
Tomek Sułkowski
la source
1
J'ai utilisé fdescribe dans mon fichier helloworld.component.spec.ts mais les erreurs du fichier app.component.spec.ts sont également affichées.
Master Yoda
1
C'est parce que tout le code est en cours d'évaluation (sinon il ne saurait pas qu'il y a des fdescribes dans vos tests) - fdescribe ne limite que l'exécution des résultats des tests. Vous devez toujours corriger les erreurs de syntaxe / dactylographie dans d'autres fichiers.
Tomek Sułkowski
3
Je pense que bien que l'OP ait accepté cette réponse, la question était de savoir comment évaluer un seul fichier de spécifications: P
roberto tomás
4
Ce n'est pas la réponse. @iislucas a la réponse ci-dessous.
Ben Racicot
Puis - je mettre un certain drapeau dans mon environnement de CI qui échouera à la rencontre fdescribeou xdescribe? Je ne veux pas qu'un critique bâclé (moi) fusionne un PR qui saute tous mes tests.
ILikeFood le
82

Configurer le test.tsfichier dans le srcdossier:

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

Remplacez /\.spec\.ts$/par le nom de fichier que vous souhaitez tester. Par exemple:/app.component\.spec\.ts$/

Cela exécutera le test uniquement pour app.component.spec.ts.

Aish Anu
la source
8
devrait être acceptée réponse, cette approche supprime une charge de sortie gumpfy dans les journaux - contrairement à fdescribe qui est verbeux
danday74
3
solution facile :) économisé beaucoup de temps.
Detoxic-Soul
Cela fera correspondre les composants avec tout ce qui se trouve avant «app», donc «product-app.component.spec.ts» ou «order-app.component.spec.ts» serait également une correspondance. Je ne suis pas le meilleur avec regx. Existe-t-il un moyen de cibler spécifiquement «app.component.spec.ts»?
hanesjw
J'ai essayé /^app.component\.spec\.ts$/ mais pas de chance. Semble fonctionner dans un testeur de regex mais ng test ne l'aime pas pour une raison quelconque; produit une erreur.
hanesjw
devrait être la réponse recommandée
Anil Vangari
55

Vous pouvez tester uniquement un fichier spécifique avec la CLI angulaire (la ngcommande) comme ceci:

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

D'autres documents sont disponibles sur https://angular.io/cli/test

Notez que bien que cela fonctionne pour les fichiers de bibliothèque autonomes, cela ne fonctionnera pas pour les composants angulaires / services / etc. En effet, les fichiers angulaires ont des dépendances sur d'autres fichiers (notamment src/test.tsdans Angular 7). Malheureusement, le --maindrapeau ne prend pas plusieurs arguments.

iislucas
la source
2
C'est une excellente suggestion et cela fonctionne. Je vous remercie! De plus, il vaut la peine de savoir que si nous essayons de le pointer vers un component.spec.tsfichier généré automatiquement , nous verrons que les tests ne démarrent jamais: 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... Je suis sûr que d'autres solutions de contournement peuvent être piratées ensemble, mais il faut être conscient de parce que la configuration effectuée dans src/main.tset ses importations ne sont pas disponibles dans ce cas.
pulkitsinghal
Lorsque j'exécute des tests entiers en utilisant la commande, ng tle test que j'écris réussit, mais lorsque j'exécute le fichier spécifique, cela donne une erreur. TypeError: impossible de lire la propriété 'getComponentFromError' de null à TestBedViewEngine._initIfNeeded (node_modules/@angular/core/fesm2015/testing.js: 3112: 1) à TestBedViewEngine.get (node_modules/@angular.j201s) 3230: 1) sur Function.get (node_modules/@angular/core/fesm2015/testing.js: 2960: 1) sur UserContext. <anonyme> (src / app / timebar.service.spec.ts: 14: 45) "
canbax
1
Cette réponse fonctionne également pour Angular 8. Cela devrait être la réponse acceptée car elle exécutera exactement un fichier de spécification de test.
2
Pour Angular 9, j'obtiens l'option inconnue "--main" :(
rmcsharry
6

Si vous voulez pouvoir contrôler quels fichiers sont sélectionnés à partir de la ligne de commande, j'ai réussi à le faire pour Angular 7.

En résumé, vous devez installer @angular-devkit/build-angular:browserpuis créer un plugin webpack personnalisé pour passer le fichier de test regex. Par exemple:

angular.json - changez le générateur de test @angular-devkit/build-angular:browseret définissez un fichier de configuration personnalisé:

...

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

extra-webpack.config.js - crée une configuration webpack qui lit l'expression régulière à partir de la ligne de commande:

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 - modifier la spécification

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

Ensuite, utilisez comme suit pour remplacer la valeur par défaut:

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

J'ai documenté la trame de fond ici , des excuses à l'avance pour les types et les mauvais liens. Merci à la réponse ci-dessus par @ Aish-Anu pour m'avoir pointé dans la bonne direction.

6EQUJ5
la source
4

Cela fonctionne pour moi dans Angular 7. Il est basé sur l'option --main de la commande ng. Je ne sais pas si cette option est non documentée et peut-être sujette à changement, mais cela fonctionne pour moi. J'ai mis une ligne dans mon fichier package.json dans la section scripts. Là, en utilisant l'option --main de avec la commande ng test, je spécifie le chemin d'accès au fichier .spec.ts que je veux exécuter. Par exemple

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

Vous pouvez exécuter le script lorsque vous exécutez un tel script. Je l'exécute dans Webstorm en cliquant sur "test 1" dans la section npm.

user2367418
la source
3

J'ai résolu ce problème pour moi-même en utilisant grunt. J'ai le script grunt ci-dessous. Ce que fait le script, c'est de prendre le paramètre de ligne de commande du test spécifique à exécuter, de créer une copie de test.ts et d'y placer ce nom de test spécifique.

Pour l'exécuter, installez d'abord grunt-cli en utilisant:

npm install -g grunt-cli

Mettez les dépendances grunt ci-dessous dans votre 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"

Pour l'exécuter, enregistrez le fichier grunt ci-dessous sous le nom Gruntfile.js dans votre dossier racine. Ensuite, à partir de la ligne de commande, exécutez-le comme:

grunt --target=app.component

Cela exécutera app.component.spec.ts.

Le fichier Grunt est comme ci-dessous:

/*
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
la source
En regardant la solution acceptée, je ne pense pas que cette méthode soit recommandée
Drenai
2
@Brian - ma solution évite d'avoir à modifier le code source et évite ainsi les erreurs potentielles lors de l'archivage du fichier. Ma solution permet simplement de spécifier le nom du test en ligne de commande en automatisant les étapes manuelles.
vanval
Ouais, c'est un bon point en fait. Il y a de fortes chances que vous oubliez de supprimer xdescribe ou fdescribe - et votre test sera définitivement supprimé!
Drenai
3
@Ryan vous pouvez installer / configurer tslint-jasmine-rules pour vérifier les appels fdescribe / fit / xdescribe / xit et échouer votre exécution de tslint; si cela fait partie d'une étape de pré-validation, cela vous empêche d'enregistrer accidentellement vos tests soit focalisés, soit désactivés.
Neil Menzies
1

Ajout à cela pour les gens comme moi qui cherchaient un moyen d'exécuter une seule spécification dans Angular et ont trouvé ce SO.

Selon la dernière documentation Angular (v9.0.6 au moment de l'écriture), la ng testcommande a une --includeoption où vous pouvez spécifier un répertoire de *.spec.(ts|tsx)fichiers ou juste un seul .spec.(ts|tsx)fichier lui-même.

https://angular.io/cli/test

terrien
la source
0

Juste un petit changement nécessaire dans le test.tsfichier dans le dossier src:

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

Voici test-examplele nom exact du fichier dont nous avons besoin pour exécuter

De la même manière, si vous avez besoin de tester le fichier de service uniquement, vous pouvez remplacer le nom de fichier comme "/test-example.service"

madhu srinivas
la source
0

Cela a fonctionné pour moi dans tous les cas:

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

Cependant, j'ai généralement "TypeError: Cannot read property 'ngModule' of null" pour ceci:

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

Version de @ angular / cli 10.0.4

PeterB
la source