Publié le 09/26/2017, rédigé par Chloé MAHALIN

@Angular/cli

Séparer les tests du code

Prérequis, installation de @angular-cli.

Objectif

Nous allons séparer, dans notre projet, les tests du code qui sera livré. Ceci afin de :

Nous allons reproduire l'arborescence ci-dessous :

myProject
    |
    |____src/
    |     |
    |     |____app/     <== Le code qui sera livré
    |     |
    |     |____test/    <== Les tests
    |
    |____package.json
    |____karma.conf.json
    ...

1ère étape : Déplacer le fichier de test racine

Le lancement de tous les tests unitaires se fait depuis le fichier test.ts, qui se trouve par défaut dans src/.

Après avoir créé le dossier test dans src/, je déplace le fichier test.ts depuis src/ vers src/test/.

AVANT :

myProject
    |
    |____src/
    |     |
    |     |____app/
    |     |
    |     |____test/
    |     |
    |     |____test.ts
    |
    |____package.json
    |____karma.conf.json
    ...

APRES :

myProject
    |
    |____src/
    |     |
    |     |____app/
    |     |
    |     |____test/
    |            |____test.ts
    |
    |____package.json
    |____karma.conf.json
    ...

Le contenu du fichier test.ts indique que toutes les classes dans le dossier local './' et qui respectent la convention *.spec.ts sont des tests :

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

Comme le fichier test.ts est la racine de tous les tests et que nous avons indiqué l'emplacement des tests dans le dossier local src/test/, il faut maintenant indiquer à la conf que le fichier test.ts n'est plus là ou il était...

2ème étape : Indiquer à la conf le nouvel emplacement du fichier test.ts

C'est karma qui est en charge du lancement des tests unitaires, c'est donc lui qui connait l'emplacement du fichier test.ts !

Allons remplacer les paths dans les propriétés files et préprocessors :

karma.conf.js - AVANT :

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
      require('karma-jasmine'),...
    ],
    ...
    files: [
      { pattern: './src/test.ts', watched: false }
    ],
    preprocessors: {
      './src/test.ts': ['@angular/cli']
    },
    ...
  });
};

karma.conf.js - APRES :

module.exports = function (config) {
  config.set({
    basePath: '',
    frameworks: ['jasmine', '@angular/cli'],
    plugins: [
      require('karma-jasmine'),...
    ],
    ...
    files: [
      { pattern: './src/test/test.ts', watched: false }   // <=== Nouveau chemin vers le nouveau dossier de test
    ],
    preprocessors: {
      './src/test/test.ts': ['@angular/cli']              // <=== Nouveau chemin vers le nouveau dossier de test
    },
    ...
  });
};

je vous masque une partie du fichier karma.conf.js, pour ne focaliser que sur l'essentiel.

Bon ça ne suffit pas, @Angular/cli définit une partie de sa conf dans son fichier .angular-cli.json, situé à la racine du projet.

3ème étape : Mettre à jour la conf @Angular/cli pour indiquer le nouvel emplacement des tests

.angular-cli.json - AVANT :

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "toto"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test.ts",
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
  ]
}

.angular-cli.json - APRES :

{
  "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
  "project": {
    "name": "toto"
  },
  "apps": [
    {
      "root": "src",
      "outDir": "dist",
      "assets": [
        "assets",
        "favicon.ico"
      ],
      "index": "index.html",
      "main": "main.ts",
      "polyfills": "polyfills.ts",
      "test": "test/test.ts",               //  <=== On change le chemin vers les tests ici.
      "tsconfig": "tsconfig.app.json",
      "testTsconfig": "tsconfig.spec.json",
      "prefix": "app",
      "styles": [
        "styles.css"
      ],
      "scripts": [],
      "environmentSource": "environments/environment.ts",
      "environments": {
        "dev": "environments/environment.ts",
        "prod": "environments/environment.prod.ts"
      }
    }
   ]
    ...
  ]
}

Quand on regarde un peu plus le contenu du fichier .angular-cli.json, on se rend compte que la configuration du compilateur typescript est différente selon que l'on gère le code ou les tests :

"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",

4ème étape : Mettre à jour la conf typescript pour pointer vers le nouveau dossier de test

4.1 : Exclure les tests de la transpilation du code

La conf de la transpilation pour le code est définie dans le fichier tsconfig.app.json, qui se trouve dans src/ :

tsconfig.app.json - AVANT :

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "module": "es2015",
    "baseUrl": "",
    "types": []
  },
  "exclude": [
    "test.ts",
    "**/*.spec.ts"
  ]
}

Ce fichier exclue de son scope le fichier test.ts et les fichiers dont le nom ressemble à *.spec.ts. Nous allons lui dire d'ignorer le dossier src/test/ directement :

tsconfig.app.json - APRES :

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/app",
    "module": "es2015",
    "baseUrl": "",
    "types": []
  },
  "exclude": [
    "test/**/*",            // <==== On exclue le dossier test et son contenu
    "**/*.spec.ts"          // <==== Dans le cas ou un test traine encore dans le code, on l'écarte du scope.
  ]
}

4.2 : Inclure les tests pour la transpilation des tests

La conf de la transpilation pour les tests est définie dans le fichier tsconfig.spec.json, qui se trouve dans src/ :

tsconfig.spec.json - AVANT :

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/spec",
    "module": "commonjs",
    "target": "es5",
    "baseUrl": "",
    "types": [
      "jasmine",
      "node"
    ]
  },
  "files": [
    "test.ts"
  ],
  "include": [
    "**/*.spec.ts",
    "**/*.d.ts"
  ]
}

Ce fichier part du fichier test.ts et inclue tous les fichiers dont le nom ressemble à *.spec.ts. Nous allons simplement redéfinir les chemins vers les différents fichiers :

tsconfig.spec.json - APRES :

{
  "extends": "../tsconfig.json",
  "compilerOptions": {
    "outDir": "../out-tsc/spec",
    "module": "commonjs",
    "target": "es5",
    "baseUrl": "",
    "types": [
      "jasmine",
      "node"
    ]
  },
  "files": [
    "test/test.ts"          // <=== On corrige l'emplacement du fichier test.ts
  ],
  "include": [
    "test/**/*.spec.ts",    // <=== On corrige l'emplacement des fichiers de test
    "test/**/*.d.ts"        // <=== On corrige l'emplacement des fichiers de test
  ]
}

Vous remarquerez que l'on ne transpilera jamais les fichiers de tests qui ne se trouvent pas dans le dossier test. Une convention bien pensée doit être respectée !

j'espère que cet article vous aura été utile !