Gathering detailed insights and metrics for ng-jasmine-mocks
Gathering detailed insights and metrics for ng-jasmine-mocks
Gathering detailed insights and metrics for ng-jasmine-mocks
Gathering detailed insights and metrics for ng-jasmine-mocks
ng-mocks
An Angular testing library for creating mock services, components, directives, pipes and modules in unit tests. It provides shallow rendering, precise stubs to fake child dependencies. ng-mocks works with Angular 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
ng-mocks-ng-19
This is a temporary fork until ng-mocks updates to support Angular 19
@bobbyg603/ng-mocks
An Angular testing library for creating mock services, components, directives, pipes and modules in unit tests. It provides shallow rendering, precise stubs to fake child dependencies. ng-mocks works with Angular 5 6 7 8 9 10 11 12 13 14 15 16 17 18, jasm
npm install ng-jasmine-mocks
Typescript
Module System
Node Version
NPM Version
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
1
3
25
Helper function for creating angular mocks for test.
Sure, you could flip a flag on schema errors to make your component dependencies not matter. Or you could use this to mock them out and have the ability to assert on their inputs or emit on an output to assert on a side effect.
ng-content
tags to allow transclusion@ContentChild
is present, then all of them will be wrapped as [data-key="_id_"]
and ng-content
with [data-key="ng-content"]
onChanged
on the mocked component bound to a FormControlonTouched
on the mocked component bound to a FormControl1import { ComponentFixture, TestBed } from '@angular/core/testing'; 2import { By } from '@angular/platform-browser'; 3import { MockComponent, MockedComponent, MockRender } from 'ng-mocks'; 4import { DependencyComponent } from './dependency.component'; 5import { TestedComponent } from './tested.component'; 6 7describe('MockComponent', () => { 8 let fixture: ComponentFixture<TestedComponent>; 9 let component: TestedComponent; 10 11 beforeEach(() => { 12 TestBed.configureTestingModule({ 13 declarations: [ 14 TestedComponent, 15 MockComponent(DependencyComponent), 16 ] 17 }); 18 19 fixture = TestBed.createComponent(TestedComponent); 20 component = fixture.componentInstance; 21 fixture.detectChanges(); 22 }); 23 24 it('should send the correct value to the dependency component input', () => { 25 const mockedComponent = fixture.debugElement 26 .query(By.css('dependency-component-selector')) 27 .componentInstance as DependencyComponent; // casting to retain type safety 28 29 // let's pretend Dependency Component (unmocked) has 'someInput' as an input 30 // the input value will be passed into the mocked component so you can assert on it 31 component.value = 'foo'; 32 fixture.detectChanges(); 33 34 // if you casted mockedComponent as the original component type then this is type safe 35 expect(mockedComponent.someInput).toEqual('foo'); 36 }); 37 38 it('should do something when the dependency component emits on its output', () => { 39 spyOn(component, 'trigger'); 40 const mockedComponent = fixture.debugElement 41 .query(By.directive(DependencyComponent)) 42 .componentInstance as DependencyComponent; // casting to retain type safety 43 44 // again, let's pretend DependencyComponent has an output called 'someOutput' 45 // emit on the output that MockComponent setup when generating the mock of Dependency Component 46 // if you casted mockedComponent as the original component type then this is type safe 47 mockedComponent.someOutput.emit({ 48 payload: 'foo', 49 }); 50 51 // assert on some side effect 52 expect(component.trigger).toHaveBeenCalledWith({ 53 payload: 'foo', 54 }); 55 }); 56 57 it('should render something inside of the dependency component', () => { 58 const localFixture = MockRender(` 59 <dependency-component-selector> 60 <p>inside content</p> 61 </dependency-component-selector> 62 `); 63 // because component does not have any @ContentChild we can access html directly. 64 // assert on some side effect 65 const mockedNgContent = localFixture.debugElement 66 .query(By.directive(DependencyComponent)) 67 .nativeElement.innerHTML; 68 expect(mockedNgContent).toContain('<p>inside content</p>'); 69 }); 70 71 it('should render something inside of the dependency component', () => { 72 const localFixture = MockRender(` 73 <dependency-component-selector> 74 <ng-template #something><p>inside template</p></ng-template> 75 <p>inside content</p> 76 </dependency-component-selector> 77 `); 78 79 // injected ng-content says as it was. 80 const mockedNgContent = localFixture.debugElement 81 .query(By.directive(DependencyComponent)) 82 .nativeElement.innerHTML; 83 expect(mockedNgContent).toContain('<p>inside content</p>'); 84 85 // because component does have @ContentChild we need to render them first with proper context. 86 const mockedElement = localFixture.debugElement.query(By.directive(DependencyComponent)); 87 const mockedComponent: MockedComponent<DependencyComponent> = mockedElement.componentInstance; 88 mockedComponent.__render('something'); 89 localFixture.detectChanges(); 90 91 const mockedNgTemplate = mockedElement.query(By.css('[data-key="something"]')) 92 .nativeElement.innerHTML; 93 expect(mockedNgTemplate).toContain('<p>inside template</p>'); 94 }); 95});
1import { ComponentFixture, TestBed } from '@angular/core/testing'; 2import { By } from '@angular/platform-browser'; 3import { MockDirective, MockHelper } from 'ng-mocks'; 4import { DependencyDirective } from './dependency.directive'; 5import { TestedComponent } from './tested.component'; 6 7describe('MockDirective', () => { 8 let fixture: ComponentFixture<TestedComponent>; 9 let component: TestedComponent; 10 11 beforeEach(() => { 12 TestBed.configureTestingModule({ 13 declarations: [ 14 TestedComponent, 15 MockDirective(DependencyDirective), 16 ] 17 }); 18 19 fixture = TestBed.createComponent(TestedComponent); 20 component = fixture.componentInstance; 21 fixture.detectChanges(); 22 }); 23 24 it('should send the correct value to the dependency component input', () => { 25 component.value = 'foo'; 26 fixture.detectChanges(); 27 28 // let's pretend Dependency Directive (unmocked) has 'someInput' as an input 29 // the input value will be passed into the mocked directive so you can assert on it 30 const mockedDirectiveInstance = MockHelper.getDirective( 31 fixture.debugElement.query(By.css('span')), 32 DependencyDirective, 33 ); 34 expect(mockedDirectiveInstance).toBeTruthy(); 35 if (mockedDirectiveInstance) { 36 expect(mockedDirectiveInstance.someInput).toEqual('foo'); 37 } 38 // assert on some side effect 39 }); 40 41 it('should do something when the dependency directive emits on its output', () => { 42 spyOn(component, 'trigger'); 43 fixture.detectChanges(); 44 45 // again, let's pretend DependencyDirective has an output called 'someOutput' 46 // emit on the output that MockDirective setup when generating the mock of Dependency Directive 47 const mockedDirectiveInstance = MockHelper.getDirective( 48 fixture.debugElement.query(By.css('span')), 49 DependencyDirective, 50 ); 51 expect(mockedDirectiveInstance).toBeTruthy(); 52 if (mockedDirectiveInstance) { 53 mockedDirectiveInstance.someOutput.emit({ 54 payload: 'foo', 55 }); // if you casted mockedDirective as the original component type then this is type safe 56 } 57 // assert on some side effect 58 }); 59});
It's important to render a structural directive first with right context, when assertions should be done on its nested elements.
1import { ComponentFixture, TestBed } from '@angular/core/testing'; 2import { MockDirective, MockedDirective, MockHelper } from 'ng-mocks'; 3import { DependencyDirective } from './dependency.directive'; 4import { TestedComponent } from './tested.component'; 5 6describe('MockDirective', () => { 7 let fixture: ComponentFixture<TestedComponent>; 8 let component: TestedComponent; 9 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 declarations: [ 13 TestedComponent, 14 MockDirective(DependencyDirective), 15 ] 16 }); 17 18 fixture = TestBed.createComponent(TestedComponent); 19 component = fixture.componentInstance; 20 fixture.detectChanges(); 21 }); 22 23 it('should send the correct value to the dependency component input', () => { 24 component.value = 'foo'; 25 fixture.detectChanges(); 26 27 // IMPORTANT: by default structural directives aren't rendered. 28 // Because we can't automatically detect when and with which context they should be rendered. 29 // Usually developer knows context and can render it manually with proper setup. 30 const mockedDirectiveInstance = MockHelper.findDirective( 31 fixture.debugElement, DependencyDirective 32 ) as MockedDirective<DependencyDirective>; 33 fixture.detectChanges(); 34 35 // let's pretend Dependency Directive (unmocked) has 'someInput' as an input 36 // the input value will be passed into the mocked directive so you can assert on it 37 expect(mockedDirectiveInstance).toBeTruthy(); 38 if (mockedDirectiveInstance) { 39 expect(mockedDirectiveInstance.someInput).toEqual('foo'); 40 } 41 // assert on some side effect 42 }); 43});
Personally, I found the best thing to do for assertions is to override the transform to write the args so that I can assert on the arguments.
1import { ComponentFixture, TestBed } from '@angular/core/testing'; 2import { By } from '@angular/platform-browser'; 3import { MockPipe } from 'ng-mocks'; 4import { DependencyPipe } from './dependency.pipe'; 5import { TestedComponent } from './tested.component'; 6 7describe('MockPipe', () => { 8 let fixture: ComponentFixture<TestedComponent>; 9 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 declarations: [ 13 TestedComponent, 14 15 // alternatively you can use MockPipes to mock multiple but you lose the ability to override 16 MockPipe(DependencyPipe, (...args) => JSON.stringify(args)), 17 ] 18 }); 19 20 fixture = TestBed.createComponent(TestedComponent); 21 fixture.detectChanges(); 22 }); 23 24 describe('with transform override', () => { 25 it('should return the result of the provided transform function', () => { 26 expect(fixture.debugElement.query(By.css('span')).nativeElement.innerHTML).toEqual('["foo"]'); 27 }); 28 }); 29});
MockedComponent
type to stay typesafe: MockedComponent<YourReactiveFormComponent>
1import { ComponentFixture, TestBed } from '@angular/core/testing'; 2import { ReactiveFormsModule } from '@angular/forms'; 3import { By } from '@angular/platform-browser'; 4import { MockComponent, MockedComponent } from 'ng-mocks'; 5import { DependencyComponent } from './dependency.component'; 6import { TestedComponent } from './tested.component'; 7 8describe('MockReactiveForms', () => { 9 let fixture: ComponentFixture<TestedComponent>; 10 let component: TestedComponent; 11 12 beforeEach(() => { 13 TestBed.configureTestingModule({ 14 declarations: [ 15 TestedComponent, 16 MockComponent(DependencyComponent), 17 ], 18 imports: [ 19 ReactiveFormsModule, 20 ], 21 }); 22 23 fixture = TestBed.createComponent(TestedComponent); 24 component = fixture.componentInstance; 25 fixture.detectChanges(); 26 }); 27 28 it('should send the correct value to the dependency component input', () => { 29 const mockedReactiveFormComponent = fixture.debugElement 30 .query(By.css('dependency-component-selector')) 31 .componentInstance as MockedComponent<DependencyComponent>; // casting to retain type safety 32 33 mockedReactiveFormComponent.__simulateChange('foo'); 34 expect(component.formControl.value).toBe('foo'); 35 }); 36});
It figures out if it is a component, directive, or pipe and mocks it for you
For providers I typically will use TestBed.get(SomeProvider) and extend it using a library like ts-mocks.
1import { ComponentFixture, TestBed } from '@angular/core/testing'; 2import { MockModule } from 'ng-mocks'; 3import { DependencyModule } from './dependency.module'; 4import { TestedComponent } from './tested.component'; 5 6describe('MockModule', () => { 7 let fixture: ComponentFixture<TestedComponent>; 8 let component: TestedComponent; 9 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 declarations: [ 13 TestedComponent, 14 ], 15 imports: [ 16 MockModule(DependencyModule), 17 ], 18 }); 19 20 fixture = TestBed.createComponent(TestedComponent); 21 component = fixture.componentInstance; 22 fixture.detectChanges(); 23 }); 24 25 it('renders nothing without any error', () => { 26 expect(component).toBeTruthy(); 27 }); 28});
Providers simple way to render anything, change @Inputs
and @Outputs
of testing component, directives etc.
1import { TestBed } from '@angular/core/testing'; 2import { By } from '@angular/platform-browser'; 3import { MockModule, MockRender } from 'ng-mocks'; 4 5import { DependencyModule } from './dependency.module'; 6import { TestedComponent } from './tested.component'; 7 8describe('MockRender', () => { 9 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 declarations: [ 13 TestedComponent, 14 ], 15 imports: [ 16 MockModule(DependencyModule), 17 ], 18 }); 19 }); 20 21 it('renders template', () => { 22 const spy = jasmine.createSpy(); 23 const fixture = MockRender( 24 ` 25 <tested (trigger)="myListener1($event)" [value1]="myParam1" value2="check"> 26 <ng-template #header> 27 something as ng-template 28 </ng-template> 29 something as ng-content 30 </tested> 31 `, 32 { 33 myListener1: spy, 34 myParam1: 'something1', 35 } 36 ); 37 38 // assert on some side effect 39 const componentInstance = fixture.debugElement.query(By.directive(TestedComponent)) 40 .componentInstance as TestedComponent; 41 componentInstance.trigger.emit('foo1'); 42 expect(componentInstance.value1).toEqual('something1'); 43 expect(componentInstance.value2).toEqual('check'); 44 expect(spy).toHaveBeenCalledWith('foo1'); 45 }); 46 47 it('renders component', () => { 48 const spy = jasmine.createSpy(); 49 // generates template like: 50 // <tested [value1]="value1" [value2]="value2" (trigger)="trigger"></tested> 51 // and returns fixture with a component with properties value1, value2 and empty callback trigger. 52 const fixture = MockRender(TestedComponent, { 53 trigger: spy, 54 value1: 'something2', 55 }); 56 57 // assert on some side effect 58 const componentInstance = fixture.debugElement.query(By.directive(TestedComponent)) 59 .componentInstance as TestedComponent; 60 componentInstance.trigger.emit('foo2'); 61 expect(componentInstance.value1).toEqual('something2'); 62 expect(componentInstance.value2).toBeUndefined(); 63 expect(spy).toHaveBeenCalledWith('foo2'); 64 }); 65});
MockHelper provides 3 methods to get attribute and structural directives from an element.
MockHelper.getDirective(fixture.debugElement, Directive)
-
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.
MockHelper.findDirectives(fixture.debugElement, Directive)
returns all found attribute or structural directives which belong to current element and all its child.
More detailed examples can be found in e2e and in examples directories in the repo.
Report it as an issue or submit a PR. I'm open to contributions.
No vulnerabilities found.
No security vulnerabilities found.