Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MockBuilder #135

Closed
wants to merge 31 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
4c01049
feat: MockBuilder
satanTime Mar 22, 2020
aa13d7f
Merge pull request #91 from satanTime/issues/44
ike18t Mar 28, 2020
314dcfb
chore(release): 10.0.0-alpha.0
ike18t Mar 28, 2020
67b3d83
fix: never mock ApplicationModule
satanTime Mar 28, 2020
69b7e41
Merge pull request #99 from satanTime/issues/ApplicationComponent
ike18t Mar 28, 2020
f8d6b64
chore(release): 10.0.0-alpha.1
ike18t Mar 28, 2020
554fa34
feat(mock-builder): ApplicationModule providers
satanTime Apr 30, 2020
975894e
Merge pull request #112 from satanTime/issues/ApplicationComponent
ike18t May 9, 2020
146255f
test: assure no leftovers after MockBuilder
satanTime Apr 6, 2020
097c7a9
Merge pull request #105 from satanTime/beta
satanTime May 9, 2020
8ec4629
chore(release): 10.0.0-alpha.2
satanTime May 9, 2020
433b1f8
Merge remote-tracking branch 'upstream/master' into beta
satanTime May 9, 2020
ff0fe96
Merge pull request #113 from satanTime/beta
satanTime May 9, 2020
1e07e82
chore(release): 10.0.0-alpha.3
satanTime May 9, 2020
e84ac12
Merge remote-tracking branch 'upstream/master' into beta
satanTime May 10, 2020
3122990
chore(release): v10.0.0-alpha.4
satanTime May 10, 2020
8825b1d
chore(release): v10.0.0-alpha.5
satanTime May 10, 2020
5897387
fix: skipping all tokens in mocks
satanTime May 14, 2020
85405ba
Merge remote-tracking branch 'upstream/master' into beta
satanTime May 17, 2020
b2646bd
Merge pull request #118 from satanTime/fix/tokens
satanTime May 17, 2020
830cf1d
chore(release): 10.0.0-alpha.6
satanTime May 17, 2020
7a3fe48
fix: better coverage for tokens
satanTime May 21, 2020
8176fa5
fix: improving types and linter
satanTime May 22, 2020
8ff9094
Merge pull request #124 from satanTime/issues/121
satanTime May 23, 2020
771415d
Merge pull request #128 from satanTime/issues/127
satanTime May 23, 2020
744aa7b
Merge remote-tracking branch 'upstream/master' into beta
satanTime May 23, 2020
c966fe9
Merge remote-tracking branch 'upstream/master' into beta
satanTime May 31, 2020
7150020
chore(release): 10.0.0-alpha.7
satanTime May 31, 2020
b70b16e
build: preparation for master merge
satanTime Jun 6, 2020
3df37d8
Merge remote-tracking branch 'upstream/master' into beta
satanTime Jun 6, 2020
9129a20
test: all cases for jest
satanTime Jun 6, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
253 changes: 244 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,33 @@ Tested on:
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.

For an easy start check the [MockBuilder](#mockbuilder) first.

- [jasmine examples](https://github.com/ike18t/ng-mocks/tree/master/examples-jasmine)
- [jest examples](https://github.com/ike18t/ng-mocks/tree/master/examples-jest)

* [jasmine e2e tests](https://github.com/ike18t/ng-mocks/tree/master/tests-jasmine)
* [jest e2e tests](https://github.com/ike18t/ng-mocks/tree/master/tests-jest)

### Sections:

- [MockModule](#mockmodule)
- [MockComponent](#mockcomponents)
- [MockDirective](#mockdirectives)
- [MockPipe](#mockpipes)
- [MockDeclaration](#mockdeclarations)

* [MockBuilder](#mockbuilder) - facilitate creation of a mocked environment
* [MockRender](#mockrender) - facilitate render of components
* [MockHelper](#mockhelper) - facilitate extraction of directives of an element

- [Reactive Forms Components](#mocked-reactive-forms-components)
- [Structural Components](#usage-example-of-structural-directives)
- [Auto Spy](#auto-spy)
- [More examples](#other-examples-of-tests)

---

## MockComponent(s)

- Mocked component with the same selector
Expand All @@ -37,7 +58,8 @@ Or you could use this to mock them out and have the ability to assert on their i
- \_\_simulateTouch - calls `onTouched` on the mocked component bound to a FormControl
- exportAs support

### Usage Example
<details><summary>Click to see <strong>a usage example</strong></summary>
<p>

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -113,7 +135,7 @@ describe('MockComponent', () => {
</dependency-component-selector>
`);

// injected ng-content says as it was.
// injected ng-content stays as it was.
const mockedNgContent = localFixture.point.nativeElement.innerHTML;
expect(mockedNgContent).toContain('<p>inside content</p>');

Expand All @@ -128,14 +150,20 @@ describe('MockComponent', () => {
});
```

</p>
</details>

---

## MockDirective(s)

- Mocked directive with the same selector
- Inputs and Outputs with alias support
- Each directive instance has its own EventEmitter instances for outputs
- exportAs support

### Usage Example of Attribute Directives
<details><summary>Click to see <strong>a usage example</strong> of Attribute Directives</summary>
<p>

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -185,9 +213,13 @@ describe('MockDirective', () => {
});
```

### Usage Example of Structural Directives
</p>
</details>

It's important to render a structural directive first with right context,
<details><summary>Click to see <strong>a usage example</strong> of Structural Directives</summary>
<p>

It's important to render a structural directive first with the right context,
when assertions should be done on its nested elements.

```typescript
Expand Down Expand Up @@ -237,6 +269,11 @@ describe('MockDirective', () => {
});
```

</p>
</details>

---

## MockPipe(s)

- Mocked pipe with the same name.
Expand All @@ -245,7 +282,8 @@ describe('MockDirective', () => {

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.

### Usage Example
<details><summary>Click to see <strong>a usage example</strong></summary>
<p>

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -280,13 +318,19 @@ describe('MockPipe', () => {
});
```

</p>
</details>

---

## Mocked Reactive Forms Components

- Set value on the formControl by calling \_\_simulateChange
- Set touched on the formControl by calling \_\_simulateTouch
- Use the `MockedComponent` type to stay typesafe: `MockedComponent<YourReactiveFormComponent>`

### Usage Example
<details><summary>Click to see <strong>a usage example</strong></summary>
<p>

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -327,10 +371,17 @@ describe('MockReactiveForms', () => {
});
```

</p>
</details>

---

## MockDeclaration(s)

It figures out if it is a component, directive, or pipe and mocks it for you

---

## MockModule

- Mocks all components, directives, and pipes using MockDeclaration
Expand All @@ -339,7 +390,8 @@ 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](https://www.npmjs.com/package/ts-mocks).

### Usage Example
<details><summary>Click to see <strong>a usage example</strong></summary>
<p>

```typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -369,6 +421,179 @@ describe('MockModule', () => {
});
```

</p>
</details>

---

## MockBuilder

The simplest way to mock everything, but not the component for testing is usage of `MockBuilder`.
Check `examples/MockBuilder/` for real examples. It's useful together with [MockRender](#MockRender).

<details><summary>Click to see <strong>a usage example</strong></summary>
<p>

```typescript
import { TestBed } from '@angular/core/testing';
import { MockBuilder, MockRender } from 'ng-mocks';

describe('MockBuilder:simple', () => {
beforeEach(async () => {
const ngModule = MockBuilder(MyComponent, MyModule)
// mocking configuration here
.build();
// now ngModule is
// {
// imports: [MockModule(MyModule)], // but MyComponent wasn't mocked for the testing purposes.
// }
// and we can simply pass it to the TestBed.
return TestBed.configureTestingModule(ngModule).compileComponents();
});

it('should render content ignoring all dependencies', () => {
const fixture = MockRender(MyComponent);
expect(fixture).toBeDefined();
expect(fixture.debugElement.nativeElement.innerHTML).toContain('<div>My Content</div>');
});
});
```

</p>
</details>

<details><summary>Click to see <strong>a detailed information</strong></summary>
<p>

```typescript
import { MockBuilder } from 'ng-mocks';

// Mocks everything in MyModule (imports, declarations, providers)
// but keeps MyComponent as it is.
const ngModule = MockBuilder(MyComponent, MyModule).build();

// The same as code above.
const ngModule = MockBuilder().keep(MyComponent, { export: true }).mock(MyModule).build();

// If we want to keep a module, component, directive, pipe or provider as it is (not mocking).
// We should use .keep.
const ngModule = MockBuilder(MyComponent, MyModule)
.keep(SomeModule)
.keep(SomeComponent)
.keep(SomeDirective)
.keep(SomePipe)
.keep(SomeDependency)
.keep(SomeInjectionToken)
.build();
// If we want to mock something, even a part of a kept module we should use .mock.
const ngModule = MockBuilder(MyComponent, MyModule)
.mock(SomeModule)
.mock(SomeComponent)
.mock(SomeDirective)
.mock(SomePipe)
.mock(SomeDependency)
.mock(SomeInjectionToken)
.build();
// If we want to replace something with something we should use .replace.
// The replacement has to be decorated with the same decorator as the source.
// It's impossible to replace a provider or a service, we should use .provide or .mock for that.
const ngModule = MockBuilder(MyComponent, MyModule)
.replace(HttpClientModule, HttpClientTestingModule)
.replace(SomeComponent, SomeOtherComponent)
.replace(SomeDirective, SomeOtherDirective)
.replace(SomePipe, SomeOtherPipe)
.build();
// For pipes we can set its handler as the 2nd parameter of .mock too.
const ngModule = MockBuilder(MyComponent, MyModule)
.mock(SomePipe, value => 'My Custom Content')
.build();
// If we want to add or replace a provider or a service we should use .provide.
// It has the same interface as a regular provider.
const ngModule = MockBuilder(MyComponent, MyModule)
.provide(MyService)
.provide([SomeService1, SomeService2])
.provide({ provide: SomeComponent3, useValue: anything1 })
.provide({ provide: SOME_TOKEN, useFactory: () => anything2 })
.build();
// If we need to mock, or to use useValue we can use .mock for that.
const ngModule = MockBuilder(MyComponent, MyModule)
.mock(MyService)
.mock(SomeService1)
.mock(SomeService2)
.mock(SomeComponent3, anything1)
.mock(SOME_TOKEN, anything2)
.build();
// Anytime we can change our decision.
// The last action on the same object wins.
const ngModule = MockBuilder(MyComponent, MyModule)
.keep(SomeModule)
.mock(SomeModule)
.keep(SomeModule)
.mock(SomeModule)
.build();
// If we want to test a component, directive or pipe which wasn't exported
// we should mark it as an 'export'.
// Doesn't matter how deep it is. It will be exported to the level of TestingModule.
const ngModule = MockBuilder(MyComponent, MyModule)
.keep(SomeModuleComponentDirectivePipeProvider1, {
export: true,
})
.build();
// By default all definitions (kept and mocked) are added to the TestingModule
// if they are not dependency of another definition.
// Modules are added as imports to the TestingModule.
// Components, Directive, Pipes are added as declarations to the TestingModule.
// Providers and Services are added as providers to the TestingModule.
// If we don't want something to be added to the TestingModule at all
// we should mark it as a 'dependency'.
const ngModule = MockBuilder(MyComponent, MyModule)
.keep(SomeModuleComponentDirectivePipeProvider1, {
dependency: true,
})
.mock(SomeModuleComponentDirectivePipeProvider1, {
dependency: true,
})
.replace(SomeModuleComponentDirectivePipeProvider1, anything1, {
dependency: true,
})
.build();
// Imagine we want to render a structural directive by default.
// Now we can do that via adding a 'render' flag in its config.
const ngModule = MockBuilder(MyComponent, MyModule)
.mock(MyDirective, {
render: true,
})
.build();
// Imagine the directive has own context and variables.
// Then instead of flag we can set its context.
const ngModule = MockBuilder(MyComponent, MyModule)
.mock(MyDirective, {
render: {
$implicit: something1,
variables: { something2: something3 },
},
})
.build();
// If we use ContentChild in a component and we want to render it by default too
// we should use its id for that in the same way as for a mocked directive.
const ngModule = MockBuilder(MyComponent, MyModule)
.mock(MyDirective, {
render: {
blockId: true,
blockWithContext: {
$implicit: something1,
variables: { something2: something3 },
},
},
})
.build();
```

</p>
</details>

---

## MockRender

Provides a simple way to render anything for ease of testing directives, pipes, `@Inputs`, `@Outputs`, `@ContentChild` of a component, etc.
Expand All @@ -386,7 +611,8 @@ It is useful if you want to mock system tokens / services such as `APP_INITIALIZ

And don't forget to call `fixture.detectChanges()` and / or `await fixture.whenStable()` to trigger updates.

### Usage Example
<details><summary>Click to see <strong>a usage example</strong></summary>
<p>

```typescript
import { TestBed } from '@angular/core/testing';
Expand Down Expand Up @@ -455,6 +681,11 @@ describe('MockRender', () => {
});
```

</p>
</details>

---

## ngMocks

ngMocks provides functions to get attribute and structural directives from an element, find components and mock objects.
Expand All @@ -473,6 +704,8 @@ ngMocks provides functions to get attribute and structural directives from an el
* ngMocks.stub(service, methods)
* ngMocks.stub(service, property, 'get' | 'set')

- ngMocks.flushTestBed()

```typescript
// returns attribute or structural directive
// which belongs to current element.
Expand Down Expand Up @@ -580,6 +813,8 @@ In case of jest add it to `src/setupJest.ts`.
import 'ng-mocks/dist/jest';
```

---

## Find an issue or have a request?

Report it as an issue or submit a PR. I'm open to contributions.
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ version: '3'
services:
ng-mocks:
build: ./
command: npm run build && npm run i:a5 && npm run s:a5 && npm run s:test:a5 && npm run test:a5
1 change: 1 addition & 0 deletions e2e/angular5/src/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@ang
import 'ng-mocks/dist/jasmine';

declare const require: any;
jasmine.getEnv().allowRespy(true);

// First, initialize the Angular testing environment.
getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting());
Expand Down
Loading