diff --git a/README.md b/README.md index aecf0a50dd..f8a62328e2 100644 --- a/README.md +++ b/README.md @@ -27,8 +27,8 @@ Or you could use this to mock them out and have the ability to assert on their i ```typescript import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { MockComponent, MockedComponent, MockRender } from 'ng-mocks'; +import { MockComponent, MockedComponent, MockHelper, MockRender } from 'ng-mocks'; + import { DependencyComponent } from './dependency.component'; import { TestedComponent } from './tested.component'; @@ -47,8 +47,11 @@ describe('MockComponent', () => { }); it('should send the correct value to the dependency component input', () => { - const mockedComponent = fixture.debugElement.query(By.css('dependency-component-selector')) - .componentInstance as DependencyComponent; // casting to retain type safety + // the same as fixture.debugElement.query(By.css('dependency-component-selector')).componentInstance + const mockedComponent = MockHelper.findOrFail( + fixture.debugElement, + 'dependency-component-selector' + ).componentInstance; // let's pretend Dependency Component (unmocked) has 'someInput' as an input // the input value will be passed into the mocked component so you can assert on it @@ -61,8 +64,7 @@ describe('MockComponent', () => { it('should do something when the dependency component emits on its output', () => { spyOn(component, 'trigger'); - const mockedComponent = fixture.debugElement.query(By.directive(DependencyComponent)) - .componentInstance as DependencyComponent; // casting to retain type safety + const mockedComponent = MockHelper.findOrFail(fixture.debugElement, DependencyComponent).componentInstance; // again, let's pretend DependencyComponent has an output called 'someOutput' // emit on the output that MockComponent setup when generating the mock of Dependency Component @@ -78,19 +80,20 @@ describe('MockComponent', () => { }); it('should render something inside of the dependency component', () => { - const localFixture = MockRender(` + const localFixture = MockRender(`

inside content

`); + // because component does not have any @ContentChild we can access html directly. // assert on some side effect - const mockedNgContent = localFixture.debugElement.query(By.directive(DependencyComponent)).nativeElement.innerHTML; + const mockedNgContent = localFixture.point.nativeElement.innerHTML; expect(mockedNgContent).toContain('

inside content

'); }); it('should render something inside of the dependency component', () => { - const localFixture = MockRender(` + const localFixture = MockRender>(`

inside template

inside content

@@ -98,16 +101,16 @@ describe('MockComponent', () => { `); // injected ng-content says as it was. - const mockedNgContent = localFixture.debugElement.query(By.directive(DependencyComponent)).nativeElement.innerHTML; + const mockedNgContent = localFixture.point.nativeElement.innerHTML; expect(mockedNgContent).toContain('

inside content

'); // because component does have @ContentChild we need to render them first with proper context. - const mockedElement = localFixture.debugElement.query(By.directive(DependencyComponent)); - const mockedComponent: MockedComponent = mockedElement.componentInstance; + const mockedComponent = localFixture.point.componentInstance; mockedComponent.__render('something'); localFixture.detectChanges(); - const mockedNgTemplate = mockedElement.query(By.css('[data-key="something"]')).nativeElement.innerHTML; + const mockedNgTemplate = MockHelper.findOrFail(localFixture.debugElement, '[data-key="something"]').nativeElement + .innerHTML; expect(mockedNgTemplate).toContain('

inside template

'); }); }); @@ -124,8 +127,8 @@ describe('MockComponent', () => { ```typescript import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { MockDirective, MockHelper } from 'ng-mocks'; + import { DependencyDirective } from './dependency.directive'; import { TestedComponent } from './tested.component'; @@ -149,14 +152,12 @@ describe('MockDirective', () => { // let's pretend Dependency Directive (unmocked) has 'someInput' as an input // the input value will be passed into the mocked directive so you can assert on it - const mockedDirectiveInstance = MockHelper.getDirective( - fixture.debugElement.query(By.css('span')), + const mockedDirectiveInstance = MockHelper.getDirectiveOrFail( + MockHelper.findOrFail(fixture.debugElement, 'span'), DependencyDirective ); - expect(mockedDirectiveInstance).toBeTruthy(); - if (mockedDirectiveInstance) { - expect(mockedDirectiveInstance.someInput).toEqual('foo'); - } + + expect(mockedDirectiveInstance.someInput).toEqual('foo'); // assert on some side effect }); @@ -166,16 +167,13 @@ describe('MockDirective', () => { // again, let's pretend DependencyDirective has an output called 'someOutput' // emit on the output that MockDirective setup when generating the mock of Dependency Directive - const mockedDirectiveInstance = MockHelper.getDirective( - fixture.debugElement.query(By.css('span')), + const mockedDirectiveInstance = MockHelper.getDirectiveOrFail( + MockHelper.findOrFail(fixture.debugElement, 'span'), DependencyDirective ); - expect(mockedDirectiveInstance).toBeTruthy(); - if (mockedDirectiveInstance) { - mockedDirectiveInstance.someOutput.emit({ - payload: 'foo', - }); // if you casted mockedDirective as the original component type then this is type safe - } + mockedDirectiveInstance.someOutput.emit({ + payload: 'foo', + }); // if you casted mockedDirective as the original component type then this is type safe // assert on some side effect }); }); @@ -189,6 +187,7 @@ when assertions should be done on its nested elements. ```typescript import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockDirective, MockedDirective, MockHelper } from 'ng-mocks'; + import { DependencyDirective } from './dependency.directive'; import { TestedComponent } from './tested.component'; @@ -213,7 +212,7 @@ describe('MockDirective', () => { // IMPORTANT: by default structural directives aren't rendered. // Because we can't automatically detect when and with which context they should be rendered. // Usually developer knows context and can render it manually with proper setup. - const mockedDirectiveInstance = MockHelper.findDirective( + const mockedDirectiveInstance = MockHelper.findDirectiveOrFail( fixture.debugElement, DependencyDirective ) as MockedDirective; @@ -227,10 +226,7 @@ describe('MockDirective', () => { // let's pretend Dependency Directive (unmocked) has 'someInput' as an input // the input value will be passed into the mocked directive so you can assert on it - expect(mockedDirectiveInstance).toBeTruthy(); - if (mockedDirectiveInstance) { - expect(mockedDirectiveInstance.someInput).toEqual('foo'); - } + expect(mockedDirectiveInstance.someInput).toEqual('foo'); // assert on some side effect }); }); @@ -248,8 +244,8 @@ Personally, I found the best thing to do for assertions is to override the trans ```typescript import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { MockPipe } from 'ng-mocks'; +import { MockHelper, MockPipe } from 'ng-mocks'; + import { DependencyPipe } from './dependency.pipe'; import { TestedComponent } from './tested.component'; @@ -262,7 +258,7 @@ describe('MockPipe', () => { TestedComponent, // alternatively you can use MockPipes to mock multiple but you lose the ability to override - MockPipe(DependencyPipe, (...args) => JSON.stringify(args)), + MockPipe(DependencyPipe, (...args: string[]) => JSON.stringify(args)), ], }); @@ -272,7 +268,8 @@ describe('MockPipe', () => { describe('with transform override', () => { it('should return the result of the provided transform function', () => { - expect(fixture.debugElement.query(By.css('span')).nativeElement.innerHTML).toEqual('["foo"]'); + const pipeElement = MockHelper.findOrFail(fixture.debugElement, 'span'); + expect(pipeElement.nativeElement.innerHTML).toEqual('["foo"]'); }); }); }); @@ -289,8 +286,8 @@ describe('MockPipe', () => { ```typescript import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; -import { By } from '@angular/platform-browser'; -import { MockComponent, MockedComponent } from 'ng-mocks'; +import { MockComponent, MockedComponent, MockHelper } from 'ng-mocks'; + import { DependencyComponent } from './dependency.component'; import { TestedComponent } from './tested.component'; @@ -310,8 +307,10 @@ describe('MockReactiveForms', () => { }); it('should send the correct value to the dependency component input', () => { - const mockedReactiveFormComponent = fixture.debugElement.query(By.css('dependency-component-selector')) - .componentInstance as MockedComponent; // casting to retain type safety + const mockedReactiveFormComponent = MockHelper.findOrFail>( + fixture.debugElement, + 'dependency-component-selector' + ).componentInstance; mockedReactiveFormComponent.__simulateChange('foo'); expect(component.formControl.value).toBe('foo'); @@ -336,6 +335,7 @@ For providers I typically will use TestBed.get(SomeProvider) and extend it using ```typescript import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockModule } from 'ng-mocks'; + import { DependencyModule } from './dependency.module'; import { TestedComponent } from './tested.component'; @@ -379,7 +379,6 @@ It is useful if you want to mock system tokens / services such as APP_INITIALIZE ```typescript import { TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { MockModule, MockRender } from 'ng-mocks'; import { DependencyModule } from './dependency.module'; @@ -411,8 +410,7 @@ describe('MockRender', () => { ); // assert on some side effect - const componentInstance = fixture.debugElement.query(By.directive(TestedComponent)) - .componentInstance as TestedComponent; + const componentInstance = fixture.point.componentInstance as TestedComponent; componentInstance.trigger.emit('foo1'); expect(componentInstance.value1).toEqual('something1'); expect(componentInstance.value2).toEqual('check'); @@ -504,28 +502,31 @@ const spySet: Spy = MockHelper.mockService(instance, propertyName, 'set'); ```typescript // The example below uses auto spy. -it('mocks getters, setters and methods in a way that jasmine can mock them w/o an issue', () => { - const mock: GetterSetterMethodHuetod = MockService(GetterSetterMethodHuetod); - expect(mock).toBeDefined(); - - // Creating a mock on the getter. - MockHelper.mockService(mock, 'name', 'get').and.returnValue('mock'); - expect(mock.name).toEqual('mock'); - - // Creating a mock on the setter. - MockHelper.mockService(mock, 'name', 'set'); - mock.name = 'mock'; - expect(MockHelper.mockService(mock, 'name', 'set')).toHaveBeenCalledWith('mock'); - - // Creating a mock on the method. - MockHelper.mockService(mock, 'nameMethod').and.returnValue('mock'); - expect(mock.nameMethod('mock')).toEqual('mock'); - expect(MockHelper.mockService(mock, 'nameMethod')).toHaveBeenCalledWith('mock'); - - // Creating a mock on the method that doesn't exist. - MockHelper.mockService(mock, 'fakeMethod').and.returnValue('mock'); - expect((mock as any).fakeMethod('mock')).toEqual('mock'); - expect(MockHelper.mockService(mock, 'fakeMethod')).toHaveBeenCalledWith('mock'); +describe('MockService', () => { + it('mocks getters, setters and methods in a way that jasmine can mock them w/o an issue', () => { + // please note that auto spy should be enabled for this test. + const mock: GetterSetterMethodHuetod = MockService(GetterSetterMethodHuetod); + expect(mock).toBeDefined(); + + // Creating a mock on the getter. + MockHelper.mockService(mock, 'name', 'get').and.returnValue('mock'); + expect(mock.name).toEqual('mock'); + + // Creating a mock on the setter. + MockHelper.mockService(mock, 'name', 'set'); + mock.name = 'mock'; + expect(MockHelper.mockService(mock, 'name', 'set')).toHaveBeenCalledWith('mock'); + + // Creating a mock on the method. + MockHelper.mockService(mock, 'nameMethod').and.returnValue('mock'); + expect(mock.nameMethod('mock')).toEqual('mock'); + expect(MockHelper.mockService(mock, 'nameMethod')).toHaveBeenCalledWith('mock'); + + // Creating a mock on the method that doesn't exist. + MockHelper.mockService(mock, 'fakeMethod').and.returnValue('mock'); + expect((mock as any).fakeMethod('mock')).toEqual('mock'); + expect(MockHelper.mockService(mock, 'fakeMethod')).toHaveBeenCalledWith('mock'); + }); }); ``` diff --git a/examples/MockComponent/MockComponent.spec.ts b/examples/MockComponent/MockComponent.spec.ts index eb9530c5b9..9567b23d22 100644 --- a/examples/MockComponent/MockComponent.spec.ts +++ b/examples/MockComponent/MockComponent.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { MockComponent, MockedComponent, MockRender } from 'ng-mocks'; +import { MockComponent, MockedComponent, MockHelper, MockRender } from 'ng-mocks'; + import { DependencyComponent } from './dependency.component'; import { TestedComponent } from './tested.component'; @@ -19,8 +19,11 @@ describe('MockComponent', () => { }); it('should send the correct value to the dependency component input', () => { - const mockedComponent = fixture.debugElement.query(By.css('dependency-component-selector')) - .componentInstance as DependencyComponent; // casting to retain type safety + // the same as fixture.debugElement.query(By.css('dependency-component-selector')).componentInstance + const mockedComponent = MockHelper.findOrFail( + fixture.debugElement, + 'dependency-component-selector' + ).componentInstance; // let's pretend Dependency Component (unmocked) has 'someInput' as an input // the input value will be passed into the mocked component so you can assert on it @@ -33,8 +36,7 @@ describe('MockComponent', () => { it('should do something when the dependency component emits on its output', () => { spyOn(component, 'trigger'); - const mockedComponent = fixture.debugElement.query(By.directive(DependencyComponent)) - .componentInstance as DependencyComponent; // casting to retain type safety + const mockedComponent = MockHelper.findOrFail(fixture.debugElement, DependencyComponent).componentInstance; // again, let's pretend DependencyComponent has an output called 'someOutput' // emit on the output that MockComponent setup when generating the mock of Dependency Component @@ -50,19 +52,20 @@ describe('MockComponent', () => { }); it('should render something inside of the dependency component', () => { - const localFixture = MockRender(` + const localFixture = MockRender(`

inside content

`); + // because component does not have any @ContentChild we can access html directly. // assert on some side effect - const mockedNgContent = localFixture.debugElement.query(By.directive(DependencyComponent)).nativeElement.innerHTML; + const mockedNgContent = localFixture.point.nativeElement.innerHTML; expect(mockedNgContent).toContain('

inside content

'); }); it('should render something inside of the dependency component', () => { - const localFixture = MockRender(` + const localFixture = MockRender>(`

inside template

inside content

@@ -70,16 +73,16 @@ describe('MockComponent', () => { `); // injected ng-content says as it was. - const mockedNgContent = localFixture.debugElement.query(By.directive(DependencyComponent)).nativeElement.innerHTML; + const mockedNgContent = localFixture.point.nativeElement.innerHTML; expect(mockedNgContent).toContain('

inside content

'); // because component does have @ContentChild we need to render them first with proper context. - const mockedElement = localFixture.debugElement.query(By.directive(DependencyComponent)); - const mockedComponent: MockedComponent = mockedElement.componentInstance; + const mockedComponent = localFixture.point.componentInstance; mockedComponent.__render('something'); localFixture.detectChanges(); - const mockedNgTemplate = mockedElement.query(By.css('[data-key="something"]')).nativeElement.innerHTML; + const mockedNgTemplate = MockHelper.findOrFail(localFixture.debugElement, '[data-key="something"]').nativeElement + .innerHTML; expect(mockedNgTemplate).toContain('

inside template

'); }); }); diff --git a/examples/MockDirective-Attribute/MockDirective.spec.ts b/examples/MockDirective-Attribute/MockDirective.spec.ts index b04947d1ce..7061d3ff90 100644 --- a/examples/MockDirective-Attribute/MockDirective.spec.ts +++ b/examples/MockDirective-Attribute/MockDirective.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { MockDirective, MockHelper } from 'ng-mocks'; + import { DependencyDirective } from './dependency.directive'; import { TestedComponent } from './tested.component'; @@ -24,14 +24,12 @@ describe('MockDirective', () => { // let's pretend Dependency Directive (unmocked) has 'someInput' as an input // the input value will be passed into the mocked directive so you can assert on it - const mockedDirectiveInstance = MockHelper.getDirective( - fixture.debugElement.query(By.css('span')), + const mockedDirectiveInstance = MockHelper.getDirectiveOrFail( + MockHelper.findOrFail(fixture.debugElement, 'span'), DependencyDirective ); - expect(mockedDirectiveInstance).toBeTruthy(); - if (mockedDirectiveInstance) { - expect(mockedDirectiveInstance.someInput).toEqual('foo'); - } + + expect(mockedDirectiveInstance.someInput).toEqual('foo'); // assert on some side effect }); @@ -41,16 +39,13 @@ describe('MockDirective', () => { // again, let's pretend DependencyDirective has an output called 'someOutput' // emit on the output that MockDirective setup when generating the mock of Dependency Directive - const mockedDirectiveInstance = MockHelper.getDirective( - fixture.debugElement.query(By.css('span')), + const mockedDirectiveInstance = MockHelper.getDirectiveOrFail( + MockHelper.findOrFail(fixture.debugElement, 'span'), DependencyDirective ); - expect(mockedDirectiveInstance).toBeTruthy(); - if (mockedDirectiveInstance) { - mockedDirectiveInstance.someOutput.emit({ - payload: 'foo', - }); // if you casted mockedDirective as the original component type then this is type safe - } + mockedDirectiveInstance.someOutput.emit({ + payload: 'foo', + }); // if you casted mockedDirective as the original component type then this is type safe // assert on some side effect }); }); diff --git a/examples/MockDirective-Structural/MockDirective.spec.ts b/examples/MockDirective-Structural/MockDirective.spec.ts index 443e33eb7c..25e91db22b 100644 --- a/examples/MockDirective-Structural/MockDirective.spec.ts +++ b/examples/MockDirective-Structural/MockDirective.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockDirective, MockedDirective, MockHelper } from 'ng-mocks'; + import { DependencyDirective } from './dependency.directive'; import { TestedComponent } from './tested.component'; @@ -24,7 +25,7 @@ describe('MockDirective', () => { // IMPORTANT: by default structural directives aren't rendered. // Because we can't automatically detect when and with which context they should be rendered. // Usually developer knows context and can render it manually with proper setup. - const mockedDirectiveInstance = MockHelper.findDirective( + const mockedDirectiveInstance = MockHelper.findDirectiveOrFail( fixture.debugElement, DependencyDirective ) as MockedDirective; @@ -38,10 +39,7 @@ describe('MockDirective', () => { // let's pretend Dependency Directive (unmocked) has 'someInput' as an input // the input value will be passed into the mocked directive so you can assert on it - expect(mockedDirectiveInstance).toBeTruthy(); - if (mockedDirectiveInstance) { - expect(mockedDirectiveInstance.someInput).toEqual('foo'); - } + expect(mockedDirectiveInstance.someInput).toEqual('foo'); // assert on some side effect }); }); diff --git a/examples/MockModule/MockModule.spec.ts b/examples/MockModule/MockModule.spec.ts index b2cbeaefcc..d514501448 100644 --- a/examples/MockModule/MockModule.spec.ts +++ b/examples/MockModule/MockModule.spec.ts @@ -1,5 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { MockModule } from 'ng-mocks'; + import { DependencyModule } from './dependency.module'; import { TestedComponent } from './tested.component'; diff --git a/examples/MockPipe/MockPipe.spec.ts b/examples/MockPipe/MockPipe.spec.ts index 81bb66b5bc..afd7f5aa39 100644 --- a/examples/MockPipe/MockPipe.spec.ts +++ b/examples/MockPipe/MockPipe.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { MockPipe } from 'ng-mocks'; +import { MockHelper, MockPipe } from 'ng-mocks'; + import { DependencyPipe } from './dependency.pipe'; import { TestedComponent } from './tested.component'; @@ -23,7 +23,8 @@ describe('MockPipe', () => { describe('with transform override', () => { it('should return the result of the provided transform function', () => { - expect(fixture.debugElement.query(By.css('span')).nativeElement.innerHTML).toEqual('["foo"]'); + const pipeElement = MockHelper.findOrFail(fixture.debugElement, 'span'); + expect(pipeElement.nativeElement.innerHTML).toEqual('["foo"]'); }); }); }); diff --git a/examples/MockReactiveForms/MockReactiveForms.spec.ts b/examples/MockReactiveForms/MockReactiveForms.spec.ts index 09aecee980..d16677a42e 100644 --- a/examples/MockReactiveForms/MockReactiveForms.spec.ts +++ b/examples/MockReactiveForms/MockReactiveForms.spec.ts @@ -1,7 +1,7 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ReactiveFormsModule } from '@angular/forms'; -import { By } from '@angular/platform-browser'; -import { MockComponent, MockedComponent } from 'ng-mocks'; +import { MockComponent, MockedComponent, MockHelper } from 'ng-mocks'; + import { DependencyComponent } from './dependency.component'; import { TestedComponent } from './tested.component'; @@ -21,8 +21,10 @@ describe('MockReactiveForms', () => { }); it('should send the correct value to the dependency component input', () => { - const mockedReactiveFormComponent = fixture.debugElement.query(By.css('dependency-component-selector')) - .componentInstance as MockedComponent; // casting to retain type safety + const mockedReactiveFormComponent = MockHelper.findOrFail>( + fixture.debugElement, + 'dependency-component-selector' + ).componentInstance; mockedReactiveFormComponent.__simulateChange('foo'); expect(component.formControl.value).toBe('foo'); diff --git a/examples/MockRender/MockRender.spec.ts b/examples/MockRender/MockRender.spec.ts index 570a5d7f29..537270148b 100644 --- a/examples/MockRender/MockRender.spec.ts +++ b/examples/MockRender/MockRender.spec.ts @@ -1,5 +1,4 @@ import { TestBed } from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; import { MockModule, MockRender } from 'ng-mocks'; import { DependencyModule } from './dependency.module'; @@ -31,8 +30,7 @@ describe('MockRender', () => { ); // assert on some side effect - const componentInstance = fixture.debugElement.query(By.directive(TestedComponent)) - .componentInstance as TestedComponent; + const componentInstance = fixture.point.componentInstance as TestedComponent; componentInstance.trigger.emit('foo1'); expect(componentInstance.value1).toEqual('something1'); expect(componentInstance.value2).toEqual('check'); diff --git a/lib/mock-helper/mock-helper.ts b/lib/mock-helper/mock-helper.ts index 8e0a3308fb..b3a8e8d8e5 100644 --- a/lib/mock-helper/mock-helper.ts +++ b/lib/mock-helper/mock-helper.ts @@ -1,16 +1,12 @@ /* tslint:disable:variable-name unified-signatures */ -import { DebugNode, Type } from '@angular/core'; +import { Type } from '@angular/core'; import { By } from '@angular/platform-browser'; -import { MockedDebugElement } from '../mock-render'; +import { MockedDebugElement, MockedDebugNode } from '../mock-render'; import { MockedFunction, mockServiceHelper } from '../mock-service'; -interface INestedNodes extends DebugNode { - childNodes?: INestedNodes[]; -} - -function nestedCheck(result: T[], node: INestedNodes, callback: (node: INestedNodes) => undefined | T) { +function nestedCheck(result: T[], node: MockedDebugNode, callback: (node: MockedDebugNode) => undefined | T) { const element = callback(node); if (element) { result.push(element); @@ -22,20 +18,20 @@ function nestedCheck(result: T[], node: INestedNodes, callback: (node: INeste } export const MockHelper: { - find(debugElement: MockedDebugElement, component: Type): null | MockedDebugElement; - find(debugElement: MockedDebugElement, cssSelector: string): null | MockedDebugElement; - findAll(debugElement: MockedDebugElement, component: Type): Array>; - findAll(debugElement: MockedDebugElement, cssSelector: string): Array>; - findDirective(debugNode: DebugNode, directive: Type): undefined | T; - findDirectiveOrFail(debugNode: DebugNode, directive: Type): T; - findDirectives(debugNode: DebugNode, directive: Type): T[]; - findOrFail(debugElement: MockedDebugElement, component: Type): MockedDebugElement; - findOrFail(debugElement: MockedDebugElement, cssSelector: string): MockedDebugElement; - getDirective(debugNode: DebugNode, directive: Type): undefined | T; - getDirectiveOrFail(debugNode: DebugNode, directive: Type): T; + find(debugElement: MockedDebugElement, component: Type): null | MockedDebugElement; + find(debugElement: MockedDebugElement, cssSelector: string): null | MockedDebugElement; + findAll(debugElement: MockedDebugElement, component: Type): Array>; + findAll(debugElement: MockedDebugElement, cssSelector: string): Array>; + findDirective(debugNode: MockedDebugNode, directive: Type): undefined | T; + findDirectiveOrFail(debugNode: MockedDebugNode, directive: Type): T; + findDirectives(debugNode: MockedDebugNode, directive: Type): T[]; + findOrFail(debugElement: MockedDebugElement, component: Type): MockedDebugElement; + findOrFail(debugElement: MockedDebugElement, cssSelector: string): MockedDebugElement; + getDirective(debugNode: MockedDebugNode, directive: Type): undefined | T; + getDirectiveOrFail(debugNode: MockedDebugNode, directive: Type): T; mockService(instance: any, name: string, style?: 'get' | 'set'): T; } = { - getDirectiveOrFail: (debugNode: DebugNode, directive: Type): T => { + getDirectiveOrFail: (debugNode: MockedDebugNode, directive: Type): T => { const result = MockHelper.getDirective(debugNode, directive); if (!result) { throw new Error(`Cannot find a directive via MockHelper.getDirectiveOrFail`); @@ -43,7 +39,7 @@ export const MockHelper: { return result; }, - getDirective: (debugNode: DebugNode, directive: Type): undefined | T => { + getDirective: (debugNode: MockedDebugNode, directive: Type): undefined | T => { // Looking for related attribute directive. try { return debugNode.injector.get(directive); @@ -72,7 +68,7 @@ export const MockHelper: { } }, - findDirectiveOrFail: (debugNode: DebugNode, directive: Type): T => { + findDirectiveOrFail: (debugNode: MockedDebugNode, directive: Type): T => { const result = MockHelper.findDirective(debugNode, directive); if (!result) { throw new Error(`Cannot find a directive via MockHelper.findDirectiveOrFail`); @@ -80,7 +76,7 @@ export const MockHelper: { return result; }, - findDirective: (debugNode: DebugNode, directive: Type): undefined | T => { + findDirective: (debugNode: MockedDebugNode, directive: Type): undefined | T => { const result: T[] = []; nestedCheck(result, debugNode, node => { try { @@ -92,7 +88,7 @@ export const MockHelper: { return result.length ? result[0] : undefined; }, - findDirectives: (debugNode: DebugNode, directive: Type): T[] => { + findDirectives: (debugNode: MockedDebugNode, directive: Type): T[] => { const result: T[] = []; nestedCheck(result, debugNode, node => { try { @@ -104,7 +100,7 @@ export const MockHelper: { return result; }, - findOrFail: (el: MockedDebugElement, sel: any) => { + findOrFail: (el: MockedDebugElement, sel: any) => { const result = MockHelper.find(el, sel); if (!result) { throw new Error(`Cannot find an element via MockHelper.findOrFail`); @@ -112,12 +108,12 @@ export const MockHelper: { return result; }, - find: (el: MockedDebugElement, sel: any) => { + find: (el: MockedDebugElement, sel: any) => { const term = typeof sel === 'string' ? By.css(sel) : By.directive(sel); return el.query(term); }, - findAll: (el: MockedDebugElement, sel: any) => { + findAll: (el: MockedDebugElement, sel: any) => { const term = typeof sel === 'string' ? By.css(sel) : By.directive(sel); return el.queryAll(term); }, diff --git a/lib/mock-render/mock-render.ts b/lib/mock-render/mock-render.ts index 4730b142bc..9f441abf8e 100644 --- a/lib/mock-render/mock-render.ts +++ b/lib/mock-render/mock-render.ts @@ -1,34 +1,40 @@ // tslint:disable:unified-signatures -import { Component, DebugElement, Provider, Type } from '@angular/core'; +import { Component, DebugElement, DebugNode, Provider, Type } from '@angular/core'; import { ComponentFixture, getTestBed, TestBed } from '@angular/core/testing'; import { directiveResolver } from '../common/reflect'; // A5 and its TS 2.4 don't support Omit, that's why we need the magic below. // TODO remove it once A5 isn't supported. + +export type DebugNodeField = + | 'context' + | 'injector' + | 'listeners' + | 'nativeNode' + | 'parent' + | 'providerTokens' + | 'references'; + +export type MockedDebugNode = { componentInstance: T } & Pick & { + childNodes?: MockedDebugNode[]; + }; + export type DebugElementField = | 'attributes' - | 'childNodes' | 'children' | 'classes' - | 'context' - | 'injector' - | 'listeners' | 'name' | 'nativeElement' - | 'nativeNode' - | 'parent' | 'properties' - | 'providerTokens' | 'query' | 'queryAll' | 'queryAllNodes' - | 'references' | 'styles' | 'triggerEventHandler'; -export type MockedDebugElement = { componentInstance: T } & Pick; +export type MockedDebugElement = Pick & MockedDebugNode; export interface IMockRenderOptions { detectChanges?: boolean; @@ -49,14 +55,14 @@ function MockRender( // without params we shouldn't autocomplete any keys of any types. function MockRender(template: Type): MockedComponentFixture; -function MockRender( +function MockRender( template: string, params: TComponent, detectChanges?: boolean | IMockRenderOptions -): MockedComponentFixture; +): MockedComponentFixture; // without params we shouldn't autocomplete any keys of any types. -function MockRender(template: string): MockedComponentFixture; +function MockRender(template: string): MockedComponentFixture; function MockRender( template: string | Type, diff --git a/lib/mock-service/mock-service.spec.ts b/lib/mock-service/mock-service.spec.ts index ed387378fa..689d4f642c 100644 --- a/lib/mock-service/mock-service.spec.ts +++ b/lib/mock-service/mock-service.spec.ts @@ -195,6 +195,7 @@ describe('MockService', () => { }); it('mocks getters, setters and methods in a way that jasmine can mock them w/o an issue', () => { + // please note that auto spy should be enabled for this test. const mock: GetterSetterMethodHuetod = MockService(GetterSetterMethodHuetod); expect(mock).toBeDefined();