Skip to content

Commit

Permalink
feat: exclude feature for ngMocks.guts
Browse files Browse the repository at this point in the history
# Conflicts:
#	README.md
  • Loading branch information
satanTime committed Oct 30, 2020
1 parent 6e252e8 commit 1886fd1
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 19 deletions.
35 changes: 29 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,9 @@ Then, if someone deletes `AppSearchModule` the test fails too.
Its first parameter accepts things we want to test (avoid mocking) and
the second parameter accepts things we want to mock, if it is a module,
its declarations (guts) will be extracted and mocked except the things
from the first parameter.
from the first parameter, and the third parameter accepts things we want
to exclude at all from the final meta. Any parameter can be `null` if
we need to skip it, or an array if we want to pass several things there.

```typescript
const testModuleMeta = ngMocks.guts(AppBaseComponent, AppBaseModule);
Expand Down Expand Up @@ -1791,7 +1793,7 @@ describe('MockInstance', () => {
`ngMocks` provides functions to get attribute and structural directives from an element, find components and mock objects.

- `ngMocks.guts(TestingDeclaration, ItsModule)`
- `ngMocks.guts([Thing1, Thing2], [ToMock1, ToMock2, ToMock3])`
- `ngMocks.guts([Thing1, Thing2], [ToMock1, ToMock2], [Skip1, Skip2])`

* `ngMocks.get(debugElement, directive, notFoundValue?)`
* `ngMocks.findInstance(debugElement, directive, notFoundValue?)`
Expand Down Expand Up @@ -1824,12 +1826,22 @@ describe('MockInstance', () => {
// The second parameter can be a class or an array of classes
// we want to mock: Modules, Components, Directives, Pipes, Services
// and tokens.
// If there is a module in the second argment, then its guts will be
// The third parameter can be a class or an array of classes
// we want to exclude: Modules, Components, Directives, Pipes, Services
// and tokens.
// If there is a module in the second parameter, then its guts will be
// mocked excluding things from the first parameter.
// Any parameter might be `null` if we need to skip it.
const ngModuleMeta1 = ngMocks.guts(Component, ItsModule);
const ngModuleMeta2 = ngMocks.guts(
[Component1, Component2, Service3],
[ModuleToMock, DirectiveToMock, WhateverToMock]
[ModuleToMock, DirectiveToMock, WhateverToMock],
[ServiceToExclude, DirectiveToExclude]
);
const ngModuleMeta3 = ngMocks.guts(
null,
ModuleToMock,
ComponentToExclude
);

// Returns an attribute or structural directive which belongs to
Expand Down Expand Up @@ -1984,7 +1996,7 @@ This function verifies tokens.

### Usage with 3rd-party libraries

`ngMocks` provides flexibility via [`MockBuilder`](#mockbuilder)
`ngMocks` provides flexibility via [`ngMocks.guts`](#ngmocks) and [`MockBuilder`](#mockbuilder)
that allows developers to use another **Angular testing libraries** for creation of `TestBed`,
and in the same time to **mock all dependencies** via `ngMocks`.

Expand All @@ -1996,7 +2008,18 @@ then to mock everything properly we need:
- mock its module
- export all declarations the module has

This means we need `.exclude`, `.mock` and `exportAll` flag.
if we use [`ngMocks.guts`](#ngmocks) we need to skip the first parameter, pass the module
as the second parameter to export its declaration, and to pass the component as the third one to exclude it.

```typescript
const dependencies = ngMocks.guts(null, MyModule, MyComponent);
const createComponent = createComponentFactory({
component: MyComponent,
...dependencies,
});
```

If we use [`MockBuilder`](#mockbuilder) we need `.exclude`, `.mock` and `exportAll` flag.

```typescript
const dependencies = MockBuilder()
Expand Down
164 changes: 159 additions & 5 deletions lib/mock-helper/mock-helper.guts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
Pipe,
PipeTransform,
} from '@angular/core';
import { isMockedNgDefOf, isNgDef, ngMocks } from 'ng-mocks';
import { getMockedNgDefOf, isMockedNgDefOf, isNgDef, ngMocks } from 'ng-mocks';

const TARGET1 = new InjectionToken('TARGET1');
const TARGET2 = new InjectionToken('TARGET2');
Expand Down Expand Up @@ -100,6 +100,19 @@ class Target2Module {}
})
class Target1Module {}

@NgModule({
declarations: [Target1Pipe, Target1Component, Target1Directive],
imports: [CommonModule, Target2Module],
providers: [
Target1Service,
{
provide: TARGET1,
useValue: 'target1',
},
],
})
class Target1CopyModule {}

@NgModule({
exports: [Target2Module],
imports: [CommonModule, Target2Module],
Expand Down Expand Up @@ -315,16 +328,25 @@ describe('mock-helper.guts', () => {
}
});

it('skips existing module', () => {
const ngModule = ngMocks.guts(Target1Module, [Target1Module, Target1Module]);
it('skips existing kept module', () => {
const ngModule = ngMocks.guts(Target1Module, Target1Module);
expect(ngModule.imports?.length).toEqual(1);
if (ngModule.imports) {
expect(ngModule.imports[0]).toBe(Target1Module);
}
});

it('skips existing mocked module', () => {
const ngModule = ngMocks.guts(null, [Target1Module, Target1CopyModule]);
expect(ngModule.imports?.length).toEqual(2);
if (ngModule.imports) {
expect(ngModule.imports[0]).toBe(CommonModule);
expect(ngModule.imports[1]).toBe(getMockedNgDefOf(Target2Module));
}
});

it('skips 2nd kept module', () => {
const ngModule = ngMocks.guts(Target2Module, [Target1Module, Target1Module]);
const ngModule = ngMocks.guts(Target2Module, [Target1Module, Target1CopyModule]);
expect(ngModule.imports?.length).toEqual(2);
if (ngModule.imports) {
expect(ngModule.imports[0]).toBe(CommonModule);
Expand All @@ -333,7 +355,7 @@ describe('mock-helper.guts', () => {
});

it('skips 2nd mocked module', () => {
const ngModule = ngMocks.guts(TARGET1, [Target1Module, Target1Module]);
const ngModule = ngMocks.guts(TARGET1, [Target1Module, Target1CopyModule]);
expect(ngModule.imports?.length).toEqual(2);
if (ngModule.imports) {
expect(ngModule.imports[0]).toBe(CommonModule);
Expand Down Expand Up @@ -499,6 +521,7 @@ describe('mock-helper.guts', () => {
});
}
});

it('skips 2nd mocked multi token', () => {
const ngModule = ngMocks.guts(TARGET2, [
{
Expand All @@ -514,4 +537,135 @@ describe('mock-helper.guts', () => {
]);
expect(ngModule.providers?.length).toEqual(0);
});

it('excludes 2nd nested kept module', () => {
const ngModule = ngMocks.guts(Target2Module, [Target1Module, Target3Module]);
expect(ngModule).toEqual(
jasmine.objectContaining({
imports: [CommonModule, Target2Module],
})
);
});

it('excludes 2nd mocked kept module', () => {
const ngModule = ngMocks.guts(null, [Target1Module, Target3Module]);
expect(ngModule).toEqual(
jasmine.objectContaining({
imports: [CommonModule, getMockedNgDefOf(Target2Module)],
})
);
});

it('ignores null values', () => {
const ngModule = ngMocks.guts(null, null, null);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('ignores duplicates values', () => {
const ngModule = ngMocks.guts(
[Target1Service, Target1Service],
[Target1Module, Target1Module],
[Target1Pipe, Target1Pipe]
);
expect(ngModule).toEqual({
declarations: [getMockedNgDefOf(Target1Component), getMockedNgDefOf(Target1Directive)],
imports: [CommonModule, getMockedNgDefOf(Target2Module)],
providers: [
Target1Service,
{
provide: TARGET1,
useValue: '',
},
],
});
});

it('excludes mocked providers', () => {
const ngModule = ngMocks.guts(null, Target1Service, Target1Service);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('excludes mocked module with providers', () => {
const ngModule = ngMocks.guts(null, { ngModule: Target1Module, providers: [] }, Target1Module);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('excludes nested mocked module', () => {
const ngModule = ngMocks.guts(null, Target3Module, Target2Module);
expect(ngModule).toEqual({
declarations: [],
imports: [CommonModule],
providers: [],
});
});

it('excludes nested kept module', () => {
const ngModule = ngMocks.guts(Target2Module, Target3Module, Target2Module);
expect(ngModule).toEqual({
declarations: [],
imports: [CommonModule],
providers: [],
});
});

it('excludes mocked module', () => {
const ngModule = ngMocks.guts(null, Target2Module, Target2Module);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('excludes mocked component', () => {
const ngModule = ngMocks.guts(null, Target1Component, Target1Component);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('excludes mocked directive', () => {
const ngModule = ngMocks.guts(null, Target1Directive, Target1Directive);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('excludes mocked pipe', () => {
const ngModule = ngMocks.guts(null, Target1Pipe, Target1Pipe);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});

it('excludes kept declarations', () => {
const ngModule = ngMocks.guts(
[Target1Module, Target1Component, Target1Directive, Target1Pipe, Target1Service, TARGET1],
null,
[Target1Module, Target1Component, Target1Directive, Target1Pipe, Target1Service, TARGET1]
);
expect(ngModule).toEqual({
declarations: [],
imports: [],
providers: [],
});
});
});
Loading

0 comments on commit 1886fd1

Please sign in to comment.