Angular testing

Tests in general

Testing module

  • depends what you test
createTestComponentFactory({
    component: DocumentsCheckComponent,
    declarations: [DocumentIconComponent],
    providers: [CalculatorService],
    mocks: [SessionService]
    imports: [MaterialModule]
});
const spectator = createService({
    service: AuthService,
    providers: [CalculatorService],
    mocks: [DateService]
});

service:

component:

Services

Testing services

describe("AuthService", () => {

  const spectator = createService({
    service: AuthService,
    mocks: [DateService]
  });

  it("should not be logged in", () => {
    const dateService = spectator.get<DateService>(DateService);
    dateService.isExpired.and.returnValue(true);
    expect(spectator.service.isLoggedIn()).toBeFalsy();
  });
});

Http services

describe('HttpClient testing', () => {
  let http = createHTTPFactory<TodosDataService>(TodosDataService);

  it('can test HttpClient.post', () => {
    let { dataService, controller, expectOne } = http();

    dataService.saveToDo({id: 1}).subscribe();

    const req = expectOne('todos', HTTPMethod.POST);
    expect(req.request.body['id']).toEqual(1);
  });
});

Pipes

Testing pipes

  • just a class with method
describe('HumanizeAccountPipe', () => {
  let pipe: HumanizeAccountPipe;

  beforeEach(() => pipe = new HumanizeAccountPipe());

  it('converts account no to human readable form', () => {
    expect(
      pipe.transform({
        accountNo: '0000000000000123',
        accountBank: '0100'
      })
    ).toBe('123/0100');
  });
});

Component testing

  • whitebox testing
    • access to the component class
  • blackbox testing

Whitebox testing

let spectator: Spectator<ButtonComponent>;
const createComponent = createTestComponentFactory(ButtonComponent);
  
beforeEach(() => spectator = createComponent());

it('should have a success class by default', () => {
    expect(spectator.query('button')).toHaveClass('success');
});

it('should emit the $event on click', () => {
    spectator = createComponent({}, false);
    let output;
    spectator.output<{ type: string }>('click').subscribe(result => output = result);

    spectator.component.onClick({ type: 'click' });
    spectator.detectChanges();
    expect(output).toEqual({ type: 'click' });
});

Blackbox testing

@Component({ selector: 'custom-host', template: '' })
class CustomHostComponent {
  title = 'Custom HostComponent';
}

describe('With Custom Host Component', function () {
  let host: SpectatorWithHost<ZippyComponent, CustomHostComponent>;

  const createHost = createHostComponentFactory({
    component: ZippyComponent,
    host: CustomHostComponent
  });

  it('should display the host component title', () => {
    host = createHost(`<zippy [title]="title"></zippy>`);

    expect(host.query('.zippy__title')).toHaveText('Custom HostComponent');
  });
});

detectChanges

  1. used to initialise component
  2. used when property changes to update DOM​
// whitebox
spectator.detectChanges();

// blackbox
host.detectChanges();

Initial change detection

  • triggers ngOnInit hook
  • by default triggered by Spectator automatically
    • can be disabled
// whitebox
spectator = createComponent({}, false);

// blackbox
host = createHost(
  '<app-applications-header></app-applications-header>',
  false
);

Testing observables

= also @Output()

Subscribe first

  • disable initial change detection
  • subscribe
  • do stuff
let emittedValue!: CommonCheck;
host
 .output<CommonCheck>('checked')
 .subscribe(value => (emittedValue = value));

host.detectChanges();

expect(emittedValue).toEqual(...);

Useful tips

mockComponents

  • when tested component has complicated child components
import { MockComponent } from 'ng-mocks';

describe('DocumentsCheckComponent', () => {
  const createComponent = createTestComponentFactory({
    component: DocumentsCheckComponent,
    declarations: [MockComponent(DocumentIconComponent)],
    imports: [MaterialModule]
  });
)};

Feature flags

const createComponent = createTestComponentFactory({
  component: StepsComponent,
  declarations: [...],
  imports: [...],
  mocks: [...],
  providers: [
    mockFeatureFlagsService({
      'admin-unified-dashboard-blocking-buttons': true,
      'admin-unified-dashboard-phase-3': true
    })
  ]
});
  • ​provide mockFeatureFlagsService

"Type checking requires all properties"

  • PROBLEM: you cannot assign a property because type is complex and you would need to come up with all properties
  • SOLUTION: create object with properties you need and cast to any
component.loan = {
  id: 5
} as any;
Made with Slides.com