Mind is Software

Ying’s thoughts about software and business

Angular Test Notes

This is a study note of Angular test based on the official document

1 Jasmin Introduction

Jasmine is a standalone bahavior-driven development framework for testing JavaScript code.

1.1 Basic Concepts

A suite of tests are grouped into a suite. Jasmine uses describe('description string', function() { ...}) to define a suite. Suites can be nested. A single test is called a spec and is defined using it('description string', function() {...}).

Inside a spec, expectations are built with the function expect that takes an actual value that is value returned from testing code. Then it is chained with a Matcher function that takes a expected value.

1.2 Matchers

A matcher implements a boolean comparison between the actual value and the expected value. It reports the comparison result to Jasmine. Use a not to negative the matcher assertaion.

The following are frequently used matchers:

expect(instance).toBe(instance); // Performs an `===` comparison
expect(number).toBeGreaterThan(number); // Expects it to be greater than the given number
expect(number).toBeLessThan(number); // Expects it to be less than the given number
expect(array).toContain(member); // Expects the element to be present in the array
expect(function).toThrow(e); // Expect the function to throw a certain error
expect(mixed).toBeDefined(); // Expects it to be defined
expect(mixed).toBeFalsy(); // Expects it to be false when cast to a boolean value
expect(mixed).toBeNull(); // Expects it to be null
expect(mixed).toBeTruthy(); // Expects it to be true when cast to a boolean value
expect(mixed).toBeUndefined(); // Expects it to be undefined
expect(string).toContain(substring); // Expects the substring to be present in the string
expect(mixed).toEqual(mixed); // Less strict than toBe() can check equality of simple variables and objects
expect(mixed).toMatch(pattern); // Expects it to match the regex pattern

1.3 this and Disable Tests

Use beforeEach, afterEach inside a suite to define setup and teardown code for each spec. Each spec’s beforeEach/it/afterEach share the same this instance.

use xdescribe and xit to disable a suite and make a spec pending.

1.4 Spies

Jasmine provides double functions called spies that can stub any function and tracks calls. A spy only exists in the describe or it block in which it is defined.

Call spyOn(obj, 'method-name') then check that the method is called via expect(obj.method-name).toHaveBeenCalled() or expect(obj.method-name).toHaveBeenCalledWith(p1, 'p2').

Use and.callThrough() to track a call and delegate to the actual implementation. Use and.returnValue(fake-value) to return a fake value. Use and.callFake(function(args) {...}) to call a fake function. and.throwError(value) throw a specified value as an error. and.stub() sets the original stubbing behavior. Use calls.any, calls.count, calls.allArgs, calls.all, calls.mostRecent, calls.first and calls.reset to check calling status.

2 Service Tests

2.1 Direct Test

It’s easy to unit test a service by directly creating the service and calling its methods.

To test a synchrounous method, use (done: DoneFn) => { // test logic followed by calling done() }.

2.2 Test with Fake Dependencies

There are several options to test a service with dependencies:

  • directly create a dependency
  • use a fake dependency
  • use a fake object
  • use a spy object let serviceSpy = jasmine.createSpyObj('service-name', ['method-name']); serviceSpy.method-name.and.returnValue(stubValue). Then you can check that the fake method is called by checking serviceSpy.method-name.calls.count().

2.3 Test with Injection

The TestBed creates a dynamically-constructed Angular test module that emulates an @NgModule. The TestBed.configureTestingModule() takes most of the properties (such as {providers: [ValueService]}) of an @NgModule. Then get the service using TestBed.get(ValueService).

3. Protractor

Protractor by default uses the Jasmine test framework as its test interface. It has a webdriver-manager tool that runs an instance of a Selenium server (WebDriver). Selenium-WebDriver automates browsers by making direct calls to the browser using each browser’s native support for automation. It supports locating UI elements by ID, class, tag, name, link text, partial link text, and css selector. It can get text values, click elements, select/deselect options, navigate to locations, access cookies, and perform a drag and drop.

Commonly used methods include element(by.id(...)), element.all(by.css(...)), element(by.css(...)), browser.wait(protractor.ExpectedConditions.urlContains('path'), browser.wait(protractor.ExpectedConditions.stalenessOf(clickBlockElement)), element.sendKeys('....'), element.click().