251

I have Angular2 project build with Angular-CLI (beta 20).

Is there a way to run tests against only one selected spec file?

I used to have a project based on Angular2 quick start, and I could manually add specs to jasmine file. But I don't know how to set this up outside of karma testing or how to limit karma tests to specific files with Angular-CLI builds.

Zielu
  • 8,312
  • 4
  • 28
  • 41

16 Answers16

337

Each of your .spec.ts file have all its tests grouped in describe block like this:

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

You can easily run just this single block, by prefixing the describe function name with f:

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

If you have such function, no other describe blocks will run. Btw. you can do similar thing with it => fit and there is also a "blacklist" version - x. So:

  • fdescribe and fit causes only functions marked this way to run
  • xdescribe and xit causes all but functions marked this way to run
Tomek Sułkowski
  • 7,081
  • 2
  • 17
  • 15
  • 2
    I have used fdescribe in my helloworld.component.spec.ts file but the errors of app.component.spec.ts file are also shown. – Master Yoda May 24 '18 at 09:22
  • 2
    That's because all the code is being evaluated (otherwise it would not know that there ARE fdescribes within your tests) - fdescribe only limits tests results execution. You stil need to fix syntax / typescript errors in other files. – Tomek Sułkowski May 24 '18 at 18:31
  • 8
    I think although the OP accepted this answer the question was acutally how to only evaluate one spec file :P – roberto tomás Jun 28 '19 at 12:28
  • 24
    This is not the answer. @iislucas has the answer below. – Ben Racicot Aug 12 '19 at 15:47
  • 1
    Can I set some flag in my CI environment that will fail on encountering `fdescribe` or `xdescribe`? I don't want a sloppy reviewer (me) to merge a PR that skips all my tests. – ILikeFood Jan 22 '20 at 18:28
  • note that in Jasmine 3.0 there will be an "incomplete" status instead of a "passing" status when using fit and fdescribe as per their warning: `ERROR: 'DEPRECATION: fit and fdescribe will cause your suite to report an 'incomplete' status in Jasmine 3.0'`. Also, docs are here: [focused describe](https://jasmine.github.io/api/3.0/global.html#fdescribe) – Danny Jan 24 '20 at 20:42
  • this unfortunately doesn't work for agular + jest (NX workspace). At least for me.. – George Knap Oct 12 '20 at 10:23
129

Configure test.ts file inside src folder:

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

Replace /\.spec\.ts$/ with the file name you want to test. For example: /app.component\.spec\.ts$/

This will run test only for app.component.spec.ts.

rink.attendant.6
  • 44,500
  • 61
  • 101
  • 156
Aish Anu
  • 1,552
  • 1
  • 8
  • 10
  • 13
    should be accepted answer, this approach removes a load of gumpfy output in the logs - unlike fdescribe which is verbose – danday74 Jun 08 '18 at 10:25
  • 4
    easy solution :) saved a lot of time. – Denny Mathew Jul 19 '18 at 22:43
  • This will match components with anything before the 'app' so 'product-app.component.spec.ts' or 'order-app.component.spec.ts' would also be a match. I'm not the greatest with regx. Is there a way to specifically target the 'app.component.spec.ts'? – hanesjw Mar 01 '19 at 20:01
  • 1
    I tried /^app.component\.spec\.ts$/ but no luck. Seems to work in a regex tester but ng test doesn't like it for some reason; produces an error. – hanesjw Mar 01 '19 at 20:23
  • should be the recommended answer – Anil Vangari May 08 '19 at 16:42
  • Is there a way to set the filename to be used from the outside? In Angular 8 `ng test` blocks unknown options. Environment Variables would be a possibility, but I don't see how i would be able to access them in test.ts – Marlaqk Jan 07 '20 at 07:24
  • I always look for this comment every time I want to execute one spec file. Thanks – shaikhspear Jun 16 '20 at 20:38
  • Is it possible to somehow specify not a single file, but a folder? So that all the tests in this folder or in any child folders would run. – manymanymore Jan 13 '21 at 08:38
  • 1
    It has stopped working after updating to angular 15. Any idea why? ```typescript const context = require.context('./', true, /\.spec\.ts$/); ``` It gives this error after running the test command - ```shell An error was thrown in afterAll Uncaught TypeError: __webpack_require__(...).context is not a function TypeError: __webpack_require__(...).context is not a function ``` – Himanshu Dec 08 '22 at 09:46
124

You can test only specific file with the Angular CLI (the ng command) like this:

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

Further docs are at https://angular.io/cli/test

Note that while this works for standalone library files, it will not work for angular components/services/etc. This is because angular files have dependencies on other files (namely src/test.ts in Angular 7). Sadly the --main flag doesn't take multiple arguments.

iislucas
  • 2,111
  • 1
  • 14
  • 4
  • 4
    This is a great suggestion and it works. Thank you! In addition its worth being aware that if we try and point it at an auto-generated `component.spec.ts` file, we will see that the tests never kick off: `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` ... I'm sure further workaround can be hacked together but it is something to be aware of because the setup done within `src/main.ts` and its imports is not available in this case. – pulkitsinghal May 05 '19 at 16:09
  • When I run whole tests using command `ng t` the test I'm writing passes but when I run the specific file it gives error. TypeError: Cannot read property 'getComponentFromError' of null at TestBedViewEngine._initIfNeeded (node_modules/@angular/core/fesm2015/testing.js:3112:1) at TestBedViewEngine.get (node_modules/@angular/core/fesm2015/testing.js:3230:1) at Function.get (node_modules/@angular/core/fesm2015/testing.js:2960:1) at UserContext. (src/app/timebar.service.spec.ts:14:45)" – canbax Aug 09 '19 at 12:01
  • 2
    This answer works for Angular 8 too. This should be the accepted answer because it will run exactly one test spec file. –  Nov 30 '19 at 21:03
  • 6
    For Angular 9 I get unknown option "--main" :( – rmcsharry May 10 '20 at 16:38
  • 3
    Had the same issue than @pulkitsinghal `Error: AsyncTestZoneSpec is needed for the async()`, but changing `--main` by `--include` in the command solved the error and executed just that test. – Mariano Ruiz Dec 02 '20 at 18:53
  • This has to be the most accepted answer because it is more convenient to just use command line – Adel Ben Hamadi Jan 17 '23 at 15:38
69

This worked for me in every case:

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

However, I usually got "TypeError: Cannot read property 'ngModule' of null" for this:

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

Version of @angular/cli 10.0.4

PeterB
  • 960
  • 6
  • 8
  • 3
    FYI: It is even possible to use more sophisticated wildcards. Just make sure that you address `*.spec.ts` in any case. E.g. to run only tests of the folders shared or search inside src/app, use `ng test --include='src/app/{shared,search}/*.spec.ts'`. – Thomas Praxl Aug 30 '20 at 09:54
  • You may also need to specify the karma config file like `--karma-config karma.conf.js`, otherwise it will try to load the config file from `src/` rather than the root path. – Wing Sep 05 '20 at 00:05
  • This worked like a charm on Angular CLI: 9.1.13 ... Thank you!! – Brendan Sluke Mar 12 '21 at 21:26
  • Interesting, that it does not work for me on Windows 10. – PeterB Nov 18 '21 at 19:26
27

use --include

it's work with --include

ng test --include src/app/path-to-component/path-component.component.spec.ts

I tried --main but it shows all fail results while it's not. I think --main will change the main test.ts file.

Mansour Alnasser
  • 4,446
  • 5
  • 40
  • 51
9

In a bash terminal I like to use the double dash. Using VS Code, you can right click on the spec file in the explorer, or on the open tab. Then select 'Copy Relative Path'. Run the command below pasting the relative path in from the clipboard.

npm t -- --include relative/path/to/file.spec.ts

The double dash signals the end of your command options for npm t and passes anything after that to the next command which is pointing to ng t. It's doesn't require any modification and quickly gives desired results.

Matt Woodruff
  • 116
  • 1
  • 3
8

If you want to be able to control which files are selected from the command line, I managed to do this for Angular 7.

In summary, you need to install @angular-devkit/build-angular:browser and then create a custom webpack plugin to pass the test file regex through. For example:

angular.json - change the test builder from @angular-devkit/build-angular:browser and set a custom config file:

...

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

extra-webpack.config.js - create a webpack configuration that reads the regex from the command line:

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 - edit the spec

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

Then use as follows to override the default:

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

I documented the backstory here, apologies in advance for types and mis-links. Credit to the answer above by @Aish-Anu for pointing me in the right direction.

6EQUJ5
  • 3,142
  • 1
  • 21
  • 29
7

A simple way to do this is to start the describe and all it with f.

fdescribe('testecomponente', () => {
  fit('should create', () => {
    //your code 
  }
  
}
  
Raphael Souza
  • 717
  • 6
  • 5
5

This is working for me in Angular 7. It is based on the --main option of the ng command. I am not sure if this option is undocumented and possibly subject to change, but it works for me. I put a line in my package.json file in scripts section. There using the --main option of with the ng test command, I specify the path to the .spec.ts file I want to execute. For example

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

You can run the script as you run any such script. I run it in Webstorm by clicking on "test 1" in the npm section.

user2367418
  • 196
  • 1
  • 5
3

I solved this problem for myself using grunt. I have the grunt script below. What the script does is takes the command line parameter of the specific test to run and creates a copy of test.ts and puts this specific test name in there.

To run this, first install grunt-cli using:

npm install -g grunt-cli

Put the below grunt dependencies in your 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"

To run it save the below grunt file as Gruntfile.js in your root folder. Then from command line run it as:

grunt --target=app.component

This will run app.component.spec.ts.

Grunt file is as below:

/*
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
  • 997
  • 1
  • 9
  • 19
  • Looking at the accepted solution, I don't think this way is recommended – Drenai Dec 17 '17 at 17:18
  • 2
    @Brian - my solution avoids having to modify source code and hence prevents potential mistakes in checking in the file. My solution enables just specifying the test name on command line by automating the manual steps. – vanval Dec 20 '17 at 01:04
  • Yeah, that's a good point actually. There is a good chance that you could forget to remove the xdescribe or fdescribe - and your test will be permantely removed! – Drenai Dec 20 '17 at 13:16
  • 3
    @Ryan you can install/configure tslint-jasmine-rules to check for fdescribe/fit/xdescribe/xit calls and fail your tslint run; if this is part of a precommit step it prevents you accidentally checking in your tests either focused or disabled. – Neil Menzies Apr 25 '18 at 14:19
3

Adding to this for people like me who were searching for a way to run a single spec in Angular and found this SO.

According to the latest Angular docs (v9.0.6 at time of writing), the ng test command has an --include option where you can specify a directory of *.spec.(ts|tsx) files or just a single .spec.(ts|tsx) file itself.

https://angular.io/cli/test

astronomotrous
  • 431
  • 1
  • 3
  • 12
1

Just small change need in test.ts file inside src folder:

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

Here, test-example is the exact file name which we need to run

In the same way, if you need to test the service file only you can replace the filename like "/test-example.service"

Aboodz
  • 1,549
  • 12
  • 23
1

Adding this answer for people like me who are searching for an easy way with some kind of extension:

If you use VS code like me you can simply install Jest Runner extension and you can easily run/ debug one test case.

0

If you are working in a project that uses monorepo architecture then you must write the project's name after script in the command line. For example:

ng test MyProject1Name -- --include='myComponent.component.spec.ts'
0

For JetBrains WebStorm Users Only

I don't have ng installed globally so cannot run ng test ... from the command line. And I can't install it either as it could mess up with my existing codebase's Angular version. I am using JetBrains WebStorm IDE and in it you can just right click the spec file and run the test.

enter image description here

Varun Sharma
  • 2,591
  • 8
  • 45
  • 63
-1

From angular-cli you can run this command and the test will include only that spec file which you want to.

ng test --includes path of spec file