The original link

After years of Angular front-end development, I never had the guts to unit test the front end. One reason is that the front end is user friendly and difficult to test, and the other reason is that the time pressure of the project doesn’t have the energy to unit test. This leads to hands-on testing as soon as the business changes during front-end development. Time-consuming and untechnical, it makes me question my life. Recently, I took a look at Angular unit testing. Angular actually has its own unit testing tool: Karma + Jasmine:

  • Karma: Karma is an automated test management tool designed for testing JavaScript code. It monitors file changes and automatically executes tests.
  • Jasmine: A framework for writing Javascript tests.

First test case

When the Angular app is created, Karma and Jasmine dependencies are added to the package.json file:

"Karma", "~ 1.7.1", "karma - chrome - the launcher" : "~ 2.2.0", "karma - coverage - Istanbul - the reporter" : "~ 2.0.0", "karma - jasmine" : "~ 1.1.1", "karma - jasmine - HTML - reporter" : "^ 0.2.2",Copy the code

Those who do back-end testing probably already know the roles of these components:

  • Karma: Karma core component
  • Karma-chrome-launcher: A Chrome launcher, where tests are performed on Chrome
  • Karma – Coverage – Istanbul reporter: Coverage report
  • Karma-jasmine: Jasmine core component
  • Karma-jasmine -html-reporter: HTML test report

In the SRC directory you will see two files named karma. Conf. js and test.ts.

Karma. Conf. js: configuration file of karma.

  • Frameworks: The testing frameworks used, in this case Jasmine

  • Port: indicates the port used for the test

  • AutoWatch: Whether to automatically detect test code changes and automatically execute tests

  • Plugins: Plugins used to test, consistent with package.json files

  • F you need to use another browser, you need to install the browser emitter through NPM and set it in plugins and here, for example using Safari: f.

    npm install karma-safari-launcher --save-dev
    
    plugins: [
        require('karma-safari-launcher')
    ]
    browsers: ['Safari'],
    Copy the code

Test.ts: test entry file that initializes the test environment and specifies all test files

In the app directory, you’ll also find a file called app.component.spec.ts. This is a Jasmine test that looks like this:

import { TestBed, async } from '@angular/core/testing';
import { AppComponent } from './app.component';
// Test entry. Parameters are test name and method
describe('AppComponent', () = > {// Setup for each test
  beforeEach(async((a)= > {
    TestBed.configureTestingModule({
      declarations: [
        AppComponent  
      ],
    }).compileComponents();
  }));

  // Test case
  it('should create the app'.async((a)= > {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    expect(app).toBeTruthy();
  }));

  it(`should have as title 'test-demo'`.async((a)= > {
    const fixture = TestBed.createComponent(AppComponent);
    const app = fixture.debugElement.componentInstance;
    // Assert that the expected value meets the requirement
    expect(app.title).toEqual('test-demo');
  }));

  it('should render title in a h1 tag'.async((a)= > {
    const fixture = TestBed.createComponent(AppComponent);
    fixture.detectChanges();
    const compiled = fixture.debugElement.nativeElement;
    // Get page elements via querySelector
    expect(compiled.querySelector('h1').textContent).toContain('Welcome to test-demo! ');
  }));

  // TearDown for each test case
  afterEach(function() {
    // Clear test data
  });
});

Copy the code

The above code uses Jasmine’s syntax. For more on Jasmine, see the JavaScript Unit Testing Framework: Jasmine Primer. I won’t repeat it here.

Run: ng test to see the test report of the above file:

In addition, you can click a test to execute it separately in the test report. The report is as follows:

Fill in the pit

For Pipe, Service, Router, etc., see the Angular documentation to highlight the various pits encountered during testing.

No provider ***

When testing, if the component under test needs another third-party component, servcie, or PIPE and is not imported, it will get a No Provider error. The solution is simple: import imports or Provider in beforeEach:

beforeEach(async((a)= > {
    TestBed.configureTestingModule({
      declarations: [
        // Declare it here].imports: [
        // introduce here].providers: [
        // introduce here].schemas: [CUSTOM_ELEMENTS_SCHEMA],
    })
      .compileComponents();
  }));
Copy the code

The request timeout

During development, TimeOut errors often occur in asynchronous requests due to network reasons. The usual solution is to set the upper limit of TimeOut time and make humanized hints for TimeOut errors. The TimeOut error also occurs when testing:

it('#loadBalance for BCT should return real value'.async () => {
  jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000000; . })Copy the code

Or set the TimeOut time uniformly in BeforeEach:

describe("my async specs".function() {
    var originalTimeout;
    beforeEach(function() {
      originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
      jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000000; }); . afterEach(function() {
      jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
    });
  });
Copy the code

Define test Environment

Angular provides different environments for development and production by default, and we can also set up Enviroment for testing.

Create environment.test.ts under SRC /environment and modify angular.json:

"architect":{
    "test":{
        ...
        "configurations": {
            "test": {
              "fileReplacements": [
                {
                  "replace": "src/environments/environment.ts",
                  "with": "src/environments/environment.test.ts"
                }
              ]
            }
          }
    }
}
Copy the code

Modify package.json file:

"scripts": {
  "test": "ng test --configuration=test",
}
Copy the code

Run the following command:

NPM test or ng test --configuration=testCopy the code

The test is executed using the configuration in the environment.test.ts file.

Test data rollback

Those of you who have done Grails development know that after unit tests, integration tests, the test data in the database is wiped from the configuration file. AfterEach (LocalStorage, SessionStorage); afterEach (LocalStorage, SessionStorage);

describe("my async specs".function() {
  
  afterEach(function() {
    // Clear the test data here
  });
});
Copy the code

With StoryBook

Earlier I posted a post titled StoryBook In Action. StoryBook is also used to test components. How is it different from Karma+Jasmine?

Both can be tested:

  1. Pipe
  2. Servcie
  3. Component

StoryBook is untestable, Karma + Jasmine is testable:

  1. Router
  2. Component interface element attributes, Input, Output

Karma + What Jasmine can’t do, StoryBook can do:

  1. Component Interactive testing
  2. Component management
  3. Writing component documentation

As can be seen from the above, Storybook focuses on black box testing, while Karma + Jasmine focuses on white box testing. There is no one strong or weak in Storybook. Only by making full use of their strengths and avoiding their weaknesses, can front-end testing be more perfect and front-end bugs be killed at the development stage.

Some front-end testing insights

Although front-end development work is tedious and it is also the place where customers have the most challenges, it does not mean that front-end only has pages and no architecture. The reason why Angular unit tests used to be so difficult was that they were all pages. In the end, there is no architecture, and all the code is in components, copied and pasted as fast as possible to catch up. As a result, unfortunately, it was difficult to maintain the code in the later period, and even a single change required human flesh testing. Despite the time spent, the developers didn’t grow. When I got into Angular front-end testing, test-driven development came to mind again. Good code is easy to test, whether it’s on the front end or the back end. Front-end developers need to pay attention not only to the ease of use and beauty of the page, but also to the front-end architecture, and an easy-to-test architecture is the best weapon.

Reference documentation

  1. StoryBook combat
  2. JavaScript unit Testing Framework: A primer on Jasmine
  3. Introduction of Karma
  4. Angular documentation – Test chapters