Skip to content

Commit

Permalink
Merge pull request #106 from satanTime/feat/queries
Browse files Browse the repository at this point in the history
feat: MockHelper with find, findAll and fetch
  • Loading branch information
satanTime authored May 9, 2020
2 parents a319c38 + ecc4ac7 commit b897ab9
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 6 deletions.
12 changes: 10 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -442,10 +442,18 @@ MockHelper provides 3 methods to get attribute and structural directives from an
returns attribute or structural directive which belongs to current element.

`MockHelper.findDirective(fixture.debugElement, Directive)` -
returns first found attribute or structural directive which belongs to current element or any child.
returns the first found attribute or structural directive which belongs to current element or any child.

`MockHelper.findDirectives(fixture.debugElement, Directive)` -
returns all found attribute or structural directives which belong to current element and all its child.
returns an array of all found attribute or structural directives which belong to current element and all its child.

`MockHelper.find(fixture.debugElement, Component)` -
returns a found DebugElement which belongs to the Component with the correctly typed componentInstance or null.

`MockHelper.findAll(fixture.debugElement, Component)` -
returns an array of found DebugElements which belong to the Component with the correctly typed componentInstance.

`getDirective`, `findDirective` and `find` have `OrFail` version that throws an error if the desired element wasn't found.

`MockHelper.mockService(instance, methodName)` -
returns a mocked function / spy of the method. If the method hasn't been mocked yet - mocks it.
Expand Down
106 changes: 103 additions & 3 deletions lib/mock-helper/mock-helper.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// tslint:disable:max-classes-per-file

import { Directive, EventEmitter, Input, Output } from '@angular/core';
import { Component, Directive, EventEmitter, Input, Output } from '@angular/core';
import { async, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';

Expand Down Expand Up @@ -30,10 +30,29 @@ export class ExampleStructuralDirective {
@Input() exampleStructuralDirective = true;
}

@Component({
selector: 'component-a',
template: 'body-a',
})
export class AComponent {
}

@Component({
selector: 'component-b',
template: 'body-b',
})
export class BComponent {
}

describe('MockHelper:getDirective', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [MockDirective(ExampleDirective), MockDirective(ExampleStructuralDirective)],
declarations: [
MockDirective(ExampleDirective),
MockDirective(ExampleStructuralDirective),
AComponent,
BComponent,
],
});
}));

Expand All @@ -57,7 +76,7 @@ describe('MockHelper:getDirective', () => {
expect(elementFromHelper).toBe(element);
});

it('should return right structural directive', () => {
it('should return right structural directive via getDirective', () => {
const fixture = MockRender(`
<div id="example-structural-directive" *exampleStructuralDirective="false">hi</div>
`);
Expand All @@ -83,4 +102,85 @@ describe('MockHelper:getDirective', () => {
// Verification.
expect(elementFromHelper.exampleStructuralDirective).toEqual(false);
});

it('should return right structural directive via getDirectiveOrFail', () => {
const fixture = MockRender(`
<div id="example-structural-directive" *exampleStructuralDirective="false">hi</div>
`);

// we need to render mocked structural directives manually
MockHelper.findDirectives(fixture.debugElement, ExampleStructuralDirective).forEach(
(item: MockedDirective<ExampleStructuralDirective>) => {
item.__render();
}
);
fixture.detectChanges();

// Using helper.
const elementFromHelper = MockHelper.getDirectiveOrFail(
fixture.debugElement.query(By.css('div')),
ExampleStructuralDirective
);

// Verification.
expect(elementFromHelper.exampleStructuralDirective).toEqual(false);
});

it('find selector: T', () => {
const fixture = MockRender(`<component-a></component-a>`);
const componentA = MockHelper.findOrFail(fixture.debugElement, AComponent);
expect(componentA.componentInstance).toEqual(jasmine.any(AComponent));

expect(() => MockHelper.findOrFail(componentA, BComponent))
.toThrowError('Cannot find an element via MockHelper.findOrFail');
});

it('find selector: string', () => {
const fixture = MockRender(`<component-b></component-b>`);
const componentB = MockHelper.findOrFail(fixture.debugElement, 'component-b');
expect(componentB.componentInstance).toEqual(jasmine.any(BComponent));

expect(() => MockHelper.findOrFail(componentB, AComponent))
.toThrowError('Cannot find an element via MockHelper.findOrFail');
});

it('find selector: T', () => {
const fixture = MockRender(`<component-a></component-a>`);
const componentA = MockHelper.find(fixture.debugElement, AComponent);
expect(componentA && componentA.componentInstance).toEqual(jasmine.any(AComponent));

const componentB = MockHelper.find(fixture.debugElement, BComponent);
expect(componentB).toBe(null); // tslint:disable-line:no-null-keyword
});

it('find selector: string', () => {
const fixture = MockRender(`<component-b></component-b>`);
const componentB = MockHelper.find(fixture.debugElement, 'component-b');
expect(componentB && componentB.componentInstance).toEqual(jasmine.any(BComponent));

const componentA = MockHelper.find(fixture.debugElement, 'component-a');
expect(componentA).toBe(null); // tslint:disable-line:no-null-keyword
});

it('findAll selector: T', () => {
const fixture = MockRender(`<component-a></component-a><component-a></component-a>`);
const componentA = MockHelper.findAll(fixture.debugElement, AComponent);
expect(componentA.length).toBe(2); // tslint:disable-line:no-magic-numbers
expect(componentA[0].componentInstance).toEqual(jasmine.any(AComponent));
expect(componentA[1].componentInstance).toEqual(jasmine.any(AComponent));

const componentB = MockHelper.findAll(fixture.debugElement, BComponent);
expect(componentB.length).toBe(0);
});

it('findAll selector: string', () => {
const fixture = MockRender(`<component-b></component-b><component-b></component-b>`);
const componentB = MockHelper.findAll(fixture.debugElement, 'component-b');
expect(componentB.length).toEqual(2); // tslint:disable-line:no-magic-numbers
expect(componentB[0].componentInstance).toEqual(jasmine.any(BComponent));
expect(componentB[0].componentInstance).toEqual(jasmine.any(BComponent));

const componentA = MockHelper.findAll(fixture.debugElement, 'component-a');
expect(componentA.length).toBe(0);
});
});
51 changes: 50 additions & 1 deletion lib/mock-helper/mock-helper.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
/* tslint:disable:variable-name */

import { DebugNode, Type } from '@angular/core';
import { By } from '@angular/platform-browser';

import { DebugElementType } from '../mock-render';
import { MockedFunction, mockServiceHelper } from '../mock-service';

interface INestedNodes extends DebugNode {
Expand All @@ -19,7 +21,28 @@ function nestedCheck<T>(result: T[], node: INestedNodes, callback: (node: INeste
});
}

export const MockHelper = {
export const MockHelper: {
find<T>(debugElement: DebugElementType<any>, component: Type<T>): null | DebugElementType<T>;
find(debugElement: DebugElementType<any>, cssSelector: string): null | DebugElementType<any>;
findAll<T>(debugElement: DebugElementType<any>, component: Type<T>): Array<DebugElementType<T>>;
findAll(debugElement: DebugElementType<any>, cssSelector: string): Array<DebugElementType<any>>;
findDirective<T>(debugNode: DebugNode, directive: Type<T>): undefined | T;
findDirectiveOrFail<T>(debugNode: DebugNode, directive: Type<T>): T;
findDirectives<T>(debugNode: DebugNode, directive: Type<T>): T[];
findOrFail<T>(debugElement: DebugElementType<any>, component: Type<T>): DebugElementType<T>;
findOrFail(debugElement: DebugElementType<any>, cssSelector: string): DebugElementType<any>;
getDirective<T>(debugNode: DebugNode, directive: Type<T>): undefined | T;
getDirectiveOrFail<T>(debugNode: DebugNode, directive: Type<T>): T;
mockService<T = MockedFunction>(instance: any, name: string, style?: 'get' | 'set'): T;
} = {
getDirectiveOrFail: <T>(debugNode: DebugNode, directive: Type<T>): T => {
const result = MockHelper.getDirective(debugNode, directive);
if (!result) {
throw new Error(`Cannot find a directive via MockHelper.getDirectiveOrFail`);
}
return result;
},

getDirective: <T>(debugNode: DebugNode, directive: Type<T>): undefined | T => {
// Looking for related attribute directive.
try {
Expand Down Expand Up @@ -49,6 +72,14 @@ export const MockHelper = {
}
},

findDirectiveOrFail: <T>(debugNode: DebugNode, directive: Type<T>): T => {
const result = MockHelper.findDirective(debugNode, directive);
if (!result) {
throw new Error(`Cannot find a directive via MockHelper.findDirectiveOrFail`);
}
return result;
},

findDirective: <T>(debugNode: DebugNode, directive: Type<T>): undefined | T => {
const result: T[] = [];
nestedCheck<T>(result, debugNode, node => {
Expand All @@ -73,6 +104,24 @@ export const MockHelper = {
return result;
},

findOrFail: (el: DebugElementType<any>, sel: any) => {
const result = MockHelper.find(el, sel);
if (!result) {
throw new Error(`Cannot find an element via MockHelper.findOrFail`);
}
return result;
},

find: (el: DebugElementType<any>, sel: any) => {
const term = typeof sel === 'string' ? By.css(sel) : By.directive(sel);
return el.query(term);
},

findAll: (el: DebugElementType<any>, sel: any) => {
const term = typeof sel === 'string' ? By.css(sel) : By.directive(sel);
return el.queryAll(term);
},

mockService: <T = MockedFunction>(instance: any, name: string, style?: 'get' | 'set'): T =>
mockServiceHelper.mock(instance, name, style),
};

0 comments on commit b897ab9

Please sign in to comment.