Skip to content

Commit

Permalink
#46: Way to pass Component to MockRender instead of template.
Browse files Browse the repository at this point in the history
  • Loading branch information
ike18t committed Mar 15, 2019
1 parent 4e975eb commit 42d35e3
Show file tree
Hide file tree
Showing 16 changed files with 197 additions and 8 deletions.
26 changes: 23 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,7 @@ Providers simple way to render anything, change `@Inputs` and `@Outputs` of test
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MockModule, MockRender } from 'ng-mocks';

import { DependencyModule } from './dependency.module';
import { TestedComponent } from './tested.component';

Expand All @@ -390,7 +391,7 @@ describe('MockRender', () => {
});
});

it('renders ', () => {
it('renders template', () => {
const spy = jasmine.createSpy();
const fixture = MockRender(
`
Expand All @@ -410,10 +411,29 @@ describe('MockRender', () => {
// assert on some side effect
const componentInstance = fixture.debugElement.query(By.directive(TestedComponent))
.componentInstance as TestedComponent;
componentInstance.trigger.emit('foo');
componentInstance.trigger.emit('foo1');
expect(componentInstance.value1).toEqual('something1');
expect(componentInstance.value2).toEqual('check');
expect(spy).toHaveBeenCalledWith('foo');
expect(spy).toHaveBeenCalledWith('foo1');
});

it('renders component', () => {
const spy = jasmine.createSpy();
// generates template like:
// <tested [value1]="value1" [value2]="value2" (trigger)="trigger"></tested>
// and returns fixture with a component with properties value1, value2 and empty callback trigger.
const fixture = MockRender(TestedComponent, {
trigger: spy,
value1: 'something2',
});

// assert on some side effect
const componentInstance = fixture.debugElement.query(By.directive(TestedComponent))
.componentInstance as TestedComponent;
componentInstance.trigger.emit('foo2');
expect(componentInstance.value1).toEqual('something2');
expect(componentInstance.value2).toBeUndefined();
expect(spy).toHaveBeenCalledWith('foo2');
});
});
```
Expand Down
100 changes: 100 additions & 0 deletions e2e/on-push/on-push.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import { ChangeDetectionStrategy, Component, DebugElement, Input } from '@angular/core';
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MockRender } from '../../lib/mock-render';

@Component({
changeDetection: ChangeDetectionStrategy.OnPush,
selector: 'item-list',
template: '{{items.length}}',
})
export class ItemListComponent {
@Input() items: string[];
}

/* tslint:disable:max-classes-per-file */
@Component({
selector: 'item-list-wrapper',
template: '<item-list [items]="items"></item-list>',
})
export class ItemListWrapperComponent {
@Input() items: string[];
}
/* tslint:enable:max-classes-per-file */

describe('ChangeDetectionStrategy.OnPush:real', () => {
let wrapper: ComponentFixture<ItemListWrapperComponent>;
let component: DebugElement;

beforeEach(() => {
// const wrapperType = WrapComponent(ItemListComponent);
TestBed.configureTestingModule({
declarations: [
ItemListComponent,
ItemListWrapperComponent,
// wrapperType,
],
});

wrapper = TestBed.createComponent(ItemListWrapperComponent);
wrapper.componentInstance.items = [];
wrapper.detectChanges();

component = wrapper.debugElement.query(By.directive(ItemListComponent));
});

it('should show 0 if no items', () => {
expect(component.nativeElement.innerText).toEqual('0');
});

it('should show 0 if items pushed to array but not changed reference', () => {
wrapper.componentInstance.items.push('demo');
wrapper.detectChanges();

expect(component.nativeElement.innerText).toEqual('0');
});

it('should show 1 if items array changed reference', () => {
wrapper.componentInstance.items = ['demo'];
wrapper.detectChanges();

expect(component.nativeElement.innerText).toEqual('1');
});
});

describe('ChangeDetectionStrategy.OnPush:mock', () => {
let fixture: ComponentFixture<ItemListComponent>;
let component: ItemListComponent;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [
ItemListComponent,
],
});

fixture = MockRender(ItemListComponent, {
items: [],
});
component = fixture.componentInstance;
fixture.detectChanges();
});

it('should show 0 if no items', () => {
expect(fixture.nativeElement.innerText).toEqual('0');
});

it('should show 0 if items pushed to array but not changed reference', () => {
component.items.push('demo');
fixture.detectChanges();

expect(fixture.nativeElement.innerText).toEqual('0');
});

it('should show 1 if items array changed reference', () => {
component.items = ['demo'];
fixture.detectChanges();

expect(fixture.nativeElement.innerText).toEqual('1');
});
});
26 changes: 23 additions & 3 deletions examples/MockRender/MockRender.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MockModule, MockRender } from 'ng-mocks';

import { DependencyModule } from './dependency.module';
import { TestedComponent } from './tested.component';

Expand All @@ -17,7 +18,7 @@ describe('MockRender', () => {
});
});

it('renders ', () => {
it('renders template', () => {
const spy = jasmine.createSpy();
const fixture = MockRender(
`
Expand All @@ -37,9 +38,28 @@ describe('MockRender', () => {
// assert on some side effect
const componentInstance = fixture.debugElement.query(By.directive(TestedComponent))
.componentInstance as TestedComponent;
componentInstance.trigger.emit('foo');
componentInstance.trigger.emit('foo1');
expect(componentInstance.value1).toEqual('something1');
expect(componentInstance.value2).toEqual('check');
expect(spy).toHaveBeenCalledWith('foo');
expect(spy).toHaveBeenCalledWith('foo1');
});

it('renders component', () => {
const spy = jasmine.createSpy();
// generates template like:
// <tested [value1]="value1" [value2]="value2" (trigger)="trigger"></tested>
// and returns fixture with a component with properties value1, value2 and empty callback trigger.
const fixture = MockRender(TestedComponent, {
trigger: spy,
value1: 'something2',
});

// assert on some side effect
const componentInstance = fixture.debugElement.query(By.directive(TestedComponent))
.componentInstance as TestedComponent;
componentInstance.trigger.emit('foo2');
expect(componentInstance.value1).toEqual('something2');
expect(componentInstance.value2).toBeUndefined();
expect(spy).toHaveBeenCalledWith('foo2');
});
});
1 change: 1 addition & 0 deletions lib/common/reflect.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MockDirectiveResolver, MockNgModuleResolver, MockPipeResolver } from '@angular/compiler/testing';

import { JitReflector } from './jit-reflector';

export const jitReflector = new JitReflector();
Expand Down
1 change: 1 addition & 0 deletions lib/mock-component/mock-component.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Component, DebugElement, ViewChild } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
import { By } from '@angular/platform-browser';

import { MockComponent, MockComponents, MockedComponent } from './mock-component';
import { ChildComponent } from './test-components/child-component.component';
import { CustomFormControlComponent } from './test-components/custom-form-control.component';
Expand Down
1 change: 1 addition & 0 deletions lib/mock-component/mock-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {
ViewContainerRef
} from '@angular/core';
import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';

import { MockOf } from '../common';
import { directiveResolver } from '../common/reflect';

Expand Down
1 change: 1 addition & 0 deletions lib/mock-declaration/mock-declaration.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Type } from '@angular/core';

import { jitReflector, pipeResolver } from '../common/reflect';
import { MockComponent } from '../mock-component';
import { MockDirective } from '../mock-directive';
Expand Down
1 change: 1 addition & 0 deletions lib/mock-directive/mock-directive.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FormControl, FormControlDirective } from '@angular/forms';
import { By } from '@angular/platform-browser';
import { MockedDirective, MockHelper } from 'ng-mocks';

import { MockDirective } from './mock-directive';

// tslint:disable:max-classes-per-file
Expand Down
1 change: 1 addition & 0 deletions lib/mock-directive/mock-directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Type,
ViewContainerRef
} from '@angular/core';

import { MockOf } from '../common';
import { directiveResolver } from '../common/reflect';

Expand Down
2 changes: 2 additions & 0 deletions lib/mock-helper/mock-helper.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import { Directive, EventEmitter, Input, Output } from '@angular/core';
import { async, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { MockDirective, MockedDirective } from '../mock-directive';
import { MockRender } from '../mock-render';

import { MockHelper } from './mock-helper';

@Directive({
Expand Down
2 changes: 2 additions & 0 deletions lib/mock-module/mock-module.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import { Component } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { BrowserModule, By } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';

import { MockComponent } from '../mock-component';

import { MockModule } from './mock-module';
import {
AppRoutingModule,
Expand Down
1 change: 1 addition & 0 deletions lib/mock-module/mock-module.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { CommonModule } from '@angular/common';
import { ModuleWithProviders, NgModule, Provider, Type } from '@angular/core';

import { MockOf } from '../common';
import { jitReflector, ngModuleResolver } from '../common/reflect';
import { MockDeclaration } from '../mock-declaration';
Expand Down
1 change: 1 addition & 0 deletions lib/mock-pipe/mock-pipe.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Component, Pipe, PipeTransform } from '@angular/core';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { MockPipe } from './mock-pipe';

@Pipe({ name: 'mockedPipe' })
Expand Down
1 change: 1 addition & 0 deletions lib/mock-pipe/mock-pipe.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Pipe, PipeTransform, Type } from '@angular/core';

import { MockOf } from '../common';
import { pipeResolver } from '../common/reflect';

Expand Down
1 change: 1 addition & 0 deletions lib/mock-render/mock-render.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import createSpy = jasmine.createSpy;
import { TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

import { MockRender } from './mock-render';
import { RenderRealComponent } from './mock-render.fixtures';

Expand Down
39 changes: 37 additions & 2 deletions lib/mock-render/mock-render.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,43 @@
import { Component, Type } from '@angular/core';
import { ComponentFixture, getTestBed, TestBed } from '@angular/core/testing';

export function MockRender<TComponent>(template: string, params?: TComponent): ComponentFixture<TComponent> {
import { directiveResolver } from '../common/reflect';

function MockRender<MComponent, TComponent extends {[key: string]: any}>(
template: string | Type<MComponent>,
params?: TComponent
): ComponentFixture<TComponent> {
let mockedTemplate = '';
if (typeof template === 'string') {
mockedTemplate = template;
} else {
const {inputs, outputs, selector} = directiveResolver.resolve(template);
mockedTemplate += `<${selector}`;
if (inputs) {
inputs.forEach((definition: string) => {
const [property, alias] = definition.split(': ');
if (alias && params && typeof params[alias]) {
mockedTemplate += ` [${alias}]="${alias}"`;
} else if (property && params && typeof params[property]) {
mockedTemplate += ` [${property}]="${property}"`;
}
});
}
if (outputs) {
outputs.forEach((definition: string) => {
const [property, alias] = definition.split(': ');
if (alias && params && typeof params[alias]) {
mockedTemplate += ` (${alias})="${alias}($event)"`;
} else if (property && params && typeof params[property]) {
mockedTemplate += ` (${property})="${property}($event)"`;
}
});
}
mockedTemplate += `></${selector}>`;
}
const options: Component = {
selector: 'mock-render',
template
template: mockedTemplate,
};

// tslint:disable-next-line:no-angle-bracket-type-assertion
Expand All @@ -27,3 +60,5 @@ export function MockRender<TComponent>(template: string, params?: TComponent): C
fixture.detectChanges();
return fixture;
}

export { MockRender };

0 comments on commit 42d35e3

Please sign in to comment.