I have created a basic template application with Angular 6 and I am trying to get Stryker Mutation testing working on it. On a basic home page:
import { Component } from '@angular/core';
/**
* Home Page Definition
*/
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss']
})
export class HomePage {}
I have a basic test file for this page:
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { HomePage } from './home.page';
/**
* Home Page Test File
*/
describe('HomePage', () => {
let component: HomePage;
let fixture: ComponentFixture<HomePage>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [HomePage],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(HomePage);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeDefined();
expect(component).toBeTruthy();
});
it('should be proper component', () => {
expect(component).toBeInstanceOf(HomePage);
});
});
While this passes and tests that the Home page will be created, I still have the .
On the basic home page, the @Component has 3 fields that all generate mutant survivors since they are literal text. I am not sure how to write a test that will kill these mutant survivors.
It does not appear that Stryker has a method to ignore a section of code as an alternate if I cannot write tests to handle the condition.
You can test the component metadata annotations of a component instance which is fine as a starting point when doing TDD (Test-Driven Development), but you should quickly be able to replace it with proper tests which verifies actual behavior.
Note that runtime component metadata will be changed with the upcoming Angular Ivy internal rewrite.
A StackBlitz demonstrating this spec
/* host.page.scss */
:host {
display: block;
font-family: Georgia, serif;
}
<!-- host.page.html -->
<p>app-home works!</p>
// home.page.spec.ts
import { Component, DebugElement } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { HomePage } from './home.page';
type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]
type Omit<T, K extends keyof T> = Pick<T, Diff<keyof T, K>>
type ComponentMetadata = Omit<Component, 'styleUrls' | 'templateUrl'>
@Component({
template: '<app-home></app-home>'
})
class TestHostComponent {}
/**
* Home Page Test File
*/
describe('HomePage', () => {
let component: HomePage;
let debugElement: DebugElement;
let hostFixture: ComponentFixture<TestHostComponent>;
let metadata: ComponentMetadata;
let nativeElement: HTMLElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [
HomePage,
TestHostComponent,
],
}).compileComponents();
}));
beforeEach(() => {
hostFixture = TestBed.createComponent(TestHostComponent);
debugElement = hostFixture.debugElement.query(By.css('app-home'));
component = debugElement.componentInstance;
nativeElement = debugElement.nativeElement;
metadata = component['__proto__'].constructor.__annotations__[0];
hostFixture.detectChanges();
});
it('should create', () => {
expect(component).toBeDefined();
expect(component).toBeTruthy();
});
it('should be proper component', () => {
expect(component instanceof HomePage).toBe(true, 'it must be a HomePage');
});
describe('metadata inspection', () => {
it('should have proper selector', () => {
const { selector } = metadata;
expect(selector).toBe('app-home');
});
it('should have template', () => {
const { template } = metadata;
expect(template).toContain('app-home works!');
});
it('should have styles', () => {
const { styles: [style] } = metadata;
expect(style).toContain('display:block');
expect(style).toContain('font-family:Georgia');
});
});
describe('shallow tests with host component', () => {
it('should have proper selector', () => {
expect(nativeElement.tagName).toMatch(/app\-home/i);
});
it('should have template', () => {
expect(nativeElement.innerText).toContain('app-home works!');
});
it('should have styles', () => {
const styles: CSSStyleDeclaration = getComputedStyle(nativeElement);
expect(styles.display).toBe('block');
expect(styles.fontFamily.startsWith('Georgia'))
.toBe(true, 'it should use the expected font family')
});
});
});