ng-mocks 13.5.2 → 14.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,8 +1,8 @@
1
- [![chat on gitter](https://img.shields.io/gitter/room/ike18t/ng-mocks)](https://gitter.im/ng-mocks/community)
2
- [![npm version](https://img.shields.io/npm/v/ng-mocks)](https://www.npmjs.com/package/ng-mocks)
3
- [![build status](https://img.shields.io/circleci/build/github/ike18t/ng-mocks/master)](https://app.circleci.com/pipelines/github/ike18t/ng-mocks?branch=master)
4
- [![coverage status](https://img.shields.io/coveralls/github/ike18t/ng-mocks/master)](https://coveralls.io/github/ike18t/ng-mocks?branch=master)
5
- [![language grade](https://img.shields.io/lgtm/grade/javascript/g/ike18t/ng-mocks)](https://lgtm.com/projects/g/ike18t/ng-mocks/context:javascript)
1
+ [<img src="https://img.shields.io/gitter/room/ike18t/ng-mocks" alt="chat on gitter" width="90" height="20" />](https://gitter.im/ng-mocks/community)
2
+ [<img src="https://img.shields.io/npm/v/ng-mocks" alt="npm version" width="88" height="20" />](https://www.npmjs.com/package/ng-mocks)
3
+ [<img src="https://img.shields.io/circleci/build/github/ike18t/ng-mocks/master" alt="build status" width="88" height="20" />](https://app.circleci.com/pipelines/github/ike18t/ng-mocks?branch=master)
4
+ [<img src="https://img.shields.io/coveralls/github/ike18t/ng-mocks/master" alt="coverage status" width="104" height="20" />](https://coveralls.io/github/ike18t/ng-mocks?branch=master)
5
+ [<img src="https://img.shields.io/lgtm/grade/javascript/g/ike18t/ng-mocks" alt="language grade" width="138" height="20" />](https://lgtm.com/projects/g/ike18t/ng-mocks/context:javascript)
6
6
 
7
7
  # Mock components, services and more out of annoying dependencies for simplification of Angular testing
8
8
 
@@ -1,8 +1,10 @@
1
+ import { CommonModule } from '@angular/common';
1
2
  import {
2
3
  Component,
3
4
  ContentChild,
4
5
  EventEmitter,
5
6
  Input,
7
+ NgModule,
6
8
  Output,
7
9
  TemplateRef,
8
10
  } from '@angular/core';
@@ -33,18 +35,24 @@ class DependencyComponent {
33
35
  ></app-child>
34
36
  `,
35
37
  })
36
- class TestedComponent {
38
+ class MyComponent {
37
39
  public value = '';
38
40
  public trigger = (obj: any) => obj;
39
41
  }
40
42
 
43
+ @NgModule({
44
+ imports: [CommonModule],
45
+ declarations: [MyComponent, DependencyComponent],
46
+ })
47
+ class ItsModule {}
48
+
41
49
  describe('MockComponent', () => {
42
50
  beforeEach(() => {
43
- return MockBuilder(TestedComponent).mock(DependencyComponent);
51
+ return MockBuilder(MyComponent, ItsModule);
44
52
  });
45
53
 
46
54
  it('sends the correct value to the child input', () => {
47
- const fixture = MockRender(TestedComponent);
55
+ const fixture = MockRender(MyComponent);
48
56
  const component = fixture.point.componentInstance;
49
57
 
50
58
  // The same as
@@ -58,7 +66,7 @@ describe('MockComponent', () => {
58
66
  ).componentInstance;
59
67
 
60
68
  // Let's pretend that DependencyComponent has 'someInput' as
61
- // an input. TestedComponent sets its value via
69
+ // an input. MyComponent sets its value via
62
70
  // `[someInput]="value"`. The input's value will be passed into
63
71
  // the mock component so we can assert on it.
64
72
  component.value = 'foo';
@@ -69,7 +77,7 @@ describe('MockComponent', () => {
69
77
  });
70
78
 
71
79
  it('does something on an emit of the child component', () => {
72
- const fixture = MockRender(TestedComponent);
80
+ const fixture = MockRender(MyComponent);
73
81
  const component = fixture.point.componentInstance;
74
82
 
75
83
  // The same as
@@ -80,7 +88,7 @@ describe('MockComponent', () => {
80
88
  const mockComponent = ngMocks.findInstance(DependencyComponent);
81
89
 
82
90
  // Again, let's pretend DependencyComponent has an output
83
- // called 'someOutput'. TestedComponent listens on the output via
91
+ // called 'someOutput'. MyComponent listens on the output via
84
92
  // `(someOutput)="trigger($event)"`.
85
93
  // Let's install a spy and trigger the output.
86
94
  ngMocks.stubMember(
@@ -3,6 +3,7 @@ import {
3
3
  Directive,
4
4
  EventEmitter,
5
5
  Input,
6
+ NgModule,
6
7
  Output,
7
8
  } from '@angular/core';
8
9
 
@@ -29,18 +30,24 @@ class DependencyDirective {
29
30
  ></span>
30
31
  `,
31
32
  })
32
- class TestedComponent {
33
+ class MyComponent {
33
34
  public value = '';
34
35
  public trigger = () => undefined;
35
36
  }
36
37
 
38
+ @NgModule({
39
+ declarations: [MyComponent, DependencyDirective],
40
+ })
41
+ class ItsModule {}
42
+
37
43
  describe('MockDirective:Attribute', () => {
38
44
  beforeEach(() => {
39
- return MockBuilder(TestedComponent).mock(DependencyDirective);
45
+ // DependencyDirective is a declaration in ItsModule.
46
+ return MockBuilder(MyComponent, ItsModule);
40
47
  });
41
48
 
42
49
  it('sends the correct value to the input', () => {
43
- const fixture = MockRender(TestedComponent);
50
+ const fixture = MockRender(MyComponent);
44
51
  const component = fixture.point.componentInstance;
45
52
 
46
53
  // The same as
@@ -54,7 +61,7 @@ describe('MockDirective:Attribute', () => {
54
61
  );
55
62
 
56
63
  // Let's pretend DependencyDirective has 'someInput'
57
- // as an input. TestedComponent sets its value via
64
+ // as an input. MyComponent sets its value via
58
65
  // `[someInput]="value"`. The input's value will be passed into
59
66
  // the mock directive so we can assert on it.
60
67
  component.value = 'foo';
@@ -65,7 +72,7 @@ describe('MockDirective:Attribute', () => {
65
72
  });
66
73
 
67
74
  it('does something on an emit of the child directive', () => {
68
- const fixture = MockRender(TestedComponent);
75
+ const fixture = MockRender(MyComponent);
69
76
  const component = fixture.point.componentInstance;
70
77
 
71
78
  // The same as
@@ -79,7 +86,7 @@ describe('MockDirective:Attribute', () => {
79
86
  );
80
87
 
81
88
  // Again, let's pretend DependencyDirective has an output called
82
- // 'someOutput'. TestedComponent listens on the output via
89
+ // 'someOutput'. MyComponent listens on the output via
83
90
  // `(someOutput)="trigger()"`.
84
91
  // Let's install a spy and trigger the output.
85
92
  ngMocks.stubMember(
@@ -33,7 +33,7 @@ class TargetComponent {
33
33
  @NgModule({
34
34
  declarations: [TargetComponent, DependencyDirective],
35
35
  })
36
- class TargetModule {}
36
+ class ItsModule {}
37
37
 
38
38
  describe('MockDirective:Structural', () => {
39
39
  // IMPORTANT: by default structural directives are not rendered.
@@ -41,7 +41,8 @@ describe('MockDirective:Structural', () => {
41
41
  // Usually a developer knows the context and can render it
42
42
  // manually with proper setup.
43
43
  beforeEach(() => {
44
- return MockBuilder(TargetComponent, TargetModule).mock(
44
+ // DependencyDirective is a declaration in ItsModule.
45
+ return MockBuilder(TargetComponent, ItsModule).mock(
45
46
  DependencyDirective,
46
47
  {
47
48
  // render: true, // <-- a flag to render the directive by default
@@ -1,4 +1,4 @@
1
- import { Component, forwardRef } from '@angular/core';
1
+ import { Component, forwardRef, NgModule } from '@angular/core';
2
2
  import {
3
3
  ControlValueAccessor,
4
4
  FormsModule,
@@ -33,18 +33,27 @@ class DependencyComponent implements ControlValueAccessor {
33
33
  selector: 'tested',
34
34
  template: ` <app-child [(ngModel)]="value"></app-child> `,
35
35
  })
36
- class TestedComponent {
36
+ class MyComponent {
37
37
  public value: any;
38
38
  }
39
39
 
40
+ @NgModule({
41
+ imports: [FormsModule],
42
+ declarations: [MyComponent, DependencyComponent],
43
+ })
44
+ class ItsModule {}
45
+
40
46
  describe('MockForms', () => {
41
47
  // Helps to reset customizations after each test.
42
48
  MockInstance.scope();
43
49
 
44
50
  beforeEach(() => {
45
- return MockBuilder(TestedComponent)
46
- .mock(DependencyComponent)
47
- .keep(FormsModule);
51
+ // DependencyComponent is a declaration in ItsModule.
52
+ return (
53
+ MockBuilder(MyComponent, ItsModule)
54
+ // FormsModule is an import in ItsModule.
55
+ .keep(FormsModule)
56
+ );
48
57
  });
49
58
 
50
59
  it('sends the correct value to the mock form component', async () => {
@@ -61,7 +70,7 @@ describe('MockForms', () => {
61
70
  // the spy via MockInstance before the render.
62
71
  MockInstance(DependencyComponent, 'writeValue', writeValue);
63
72
 
64
- const fixture = MockRender(TestedComponent);
73
+ const fixture = MockRender(MyComponent);
65
74
  // FormsModule needs fixture.whenStable()
66
75
  // right after MockRender to install all hooks.
67
76
  await fixture.whenStable();
@@ -1,7 +1,9 @@
1
+ import { CommonModule } from '@angular/common';
1
2
  import {
2
3
  AfterViewInit,
3
4
  Component,
4
5
  Injector,
6
+ NgModule,
5
7
  ViewChild,
6
8
  } from '@angular/core';
7
9
  import { Observable, Subject } from 'rxjs';
@@ -39,11 +41,17 @@ class RealComponent implements AfterViewInit {
39
41
  }
40
42
  }
41
43
 
44
+ @NgModule({
45
+ imports: [CommonModule],
46
+ declarations: [RealComponent, ChildComponent],
47
+ })
48
+ class ItsModule {}
49
+
42
50
  describe('MockInstance', () => {
43
51
  // A normal setup of the TestBed, TargetComponent will be replaced
44
52
  // with its mock object.
45
53
  // Do not forget to return the promise of MockBuilder.
46
- beforeEach(() => MockBuilder(RealComponent).mock(ChildComponent));
54
+ beforeEach(() => MockBuilder(RealComponent, ItsModule));
47
55
 
48
56
  beforeEach(() => {
49
57
  // Because TargetComponent is replaced with its mock object,
@@ -42,18 +42,25 @@ class DependencyModule {}
42
42
  ></app-child>
43
43
  `,
44
44
  })
45
- class TestedComponent {
45
+ class MyComponent {
46
46
  public value = '';
47
47
  public trigger = () => undefined;
48
48
  }
49
49
 
50
+ @NgModule({
51
+ imports: [DependencyModule],
52
+ declarations: [MyComponent],
53
+ })
54
+ class ItsModule {}
55
+
50
56
  describe('MockModule', () => {
51
57
  beforeEach(() => {
52
- return MockBuilder(TestedComponent).mock(DependencyModule);
58
+ // DependencyModule is an import of ItsModule.
59
+ return MockBuilder(MyComponent, ItsModule);
53
60
  });
54
61
 
55
- it('renders TestedComponent with its dependencies', () => {
56
- const fixture = MockRender(TestedComponent);
62
+ it('renders MyComponent with its dependencies', () => {
63
+ const fixture = MockRender(MyComponent);
57
64
  const component = fixture.point.componentInstance;
58
65
 
59
66
  expect(component).toBeTruthy();
@@ -23,7 +23,7 @@ class TargetComponent {}
23
23
  @NgModule({
24
24
  declarations: [TargetComponent, DependencyPipe],
25
25
  })
26
- class TargetModule {}
26
+ class ItsModule {}
27
27
 
28
28
  // A fake transform function.
29
29
  const fakeTransform = (...args: string[]) => JSON.stringify(args);
@@ -39,9 +39,10 @@ describe('MockPipe', () => {
39
39
  // const spy = jest.fn().mockImplementation(fakeTransform);
40
40
 
41
41
  beforeEach(() => {
42
- return MockBuilder(TargetComponent, TargetModule).mock(
43
- DependencyPipe,
44
- spy,
42
+ return (
43
+ MockBuilder(TargetComponent, ItsModule)
44
+ // DependencyPipe is a declaration in ItsModule
45
+ .mock(DependencyPipe, spy)
45
46
  );
46
47
  });
47
48
 
@@ -1,4 +1,4 @@
1
- import { Component, forwardRef } from '@angular/core';
1
+ import { Component, forwardRef, NgModule } from '@angular/core';
2
2
  import {
3
3
  ControlValueAccessor,
4
4
  FormControl,
@@ -34,18 +34,24 @@ class DependencyComponent implements ControlValueAccessor {
34
34
  selector: 'tested',
35
35
  template: ' <app-child [formControl]="formControl"></app-child> ',
36
36
  })
37
- class TestedComponent {
37
+ class MyComponent {
38
38
  public readonly formControl = new FormControl();
39
39
  }
40
40
 
41
+ @NgModule({
42
+ imports: [ReactiveFormsModule],
43
+ declarations: [MyComponent, DependencyComponent],
44
+ })
45
+ class ItsModule {}
46
+
41
47
  describe('MockReactiveForms', () => {
42
48
  // Helps to reset MockInstance customizations after each test.
43
49
  MockInstance.scope();
44
50
 
45
51
  beforeEach(() => {
46
- return MockBuilder(TestedComponent)
47
- .mock(DependencyComponent)
48
- .keep(ReactiveFormsModule);
52
+ return MockBuilder(MyComponent, ItsModule).keep(
53
+ ReactiveFormsModule,
54
+ );
49
55
  });
50
56
 
51
57
  it('sends the correct value to the mock form component', () => {
@@ -62,7 +68,7 @@ describe('MockReactiveForms', () => {
62
68
  // the spy via MockInstance before the render.
63
69
  MockInstance(DependencyComponent, 'writeValue', writeValue);
64
70
 
65
- const fixture = MockRender(TestedComponent);
71
+ const fixture = MockRender(MyComponent);
66
72
  const component = fixture.point.componentInstance;
67
73
 
68
74
  // During initialization it should be called
@@ -37,7 +37,7 @@ class DependencyModule {}
37
37
  ></app-child>
38
38
  `,
39
39
  })
40
- class TestedComponent {
40
+ class MyComponent {
41
41
  @Output() public readonly trigger = new EventEmitter();
42
42
  @Input() public value1 = 'default1';
43
43
  @Input() public value2 = 'default2';
@@ -45,7 +45,7 @@ class TestedComponent {
45
45
 
46
46
  describe('MockRender', () => {
47
47
  // Do not forget to return the promise of MockBuilder.
48
- beforeEach(() => MockBuilder(TestedComponent, DependencyModule));
48
+ beforeEach(() => MockBuilder(MyComponent, DependencyModule));
49
49
 
50
50
  it('renders template', () => {
51
51
  const spy =
@@ -93,7 +93,7 @@ describe('MockRender', () => {
93
93
  // Generates a template like:
94
94
  // <tested [value1]="value1" [value2]="value2"
95
95
  // (trigger)="trigger"></tested>.
96
- const fixture = MockRender(TestedComponent, {
96
+ const fixture = MockRender(MyComponent, {
97
97
  trigger: spy,
98
98
  value1: 'something2',
99
99
  });
@@ -1,6 +1,6 @@
1
1
  import { Component, Injectable } from '@angular/core';
2
2
 
3
- import { MockBuilder, MockRender } from 'ng-mocks';
3
+ import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
4
4
 
5
5
  // A simple service, might have contained more logic,
6
6
  // but it is redundant for the test demonstration.
@@ -31,9 +31,9 @@ describe('TestProviderInComponent', () => {
31
31
  // to access the service.
32
32
  const fixture = MockRender(TargetComponent);
33
33
 
34
- // The root element is fixture.point and it is the TargetComponent
35
- // with its injector for extracting internal services.
36
- const service = fixture.point.injector.get(TargetService);
34
+ // The component's element is fixture.point.
35
+ // Now we can use ngMocks.get to extract internal services.
36
+ const service = ngMocks.get(fixture.point, TargetService);
37
37
 
38
38
  // Here we go, now we can assert everything about the service.
39
39
  expect(service.value).toEqual('target');
@@ -49,26 +49,30 @@ describe('TestProviderInDirective', () => {
49
49
  beforeEach(() => MockBuilder(TargetService, TargetDirective));
50
50
 
51
51
  it('has access to the service via a directive', () => {
52
- // Let's render a div with the directive. It provides a point
53
- // to access the service.
54
- const fixture = MockRender('<div target></div>');
52
+ // Let's render a div with the directive.
53
+ MockRender('<div target></div>');
55
54
 
56
- // The root element is fixture.point and it has access to the
57
- // context of the directive. Its injector can extract the service.
58
- const service = fixture.point.injector.get(TargetService);
55
+ // Let's find the debugElement with the directive.
56
+ // Please note, that we use ngMocks.find here.
57
+ const el = ngMocks.find(TargetDirective);
58
+
59
+ // Let's extract the service.
60
+ const service = ngMocks.get(el, TargetService);
59
61
 
60
62
  // Here we go, now we can assert everything about the service.
61
63
  expect(service.value).toEqual(true);
62
64
  });
63
65
 
64
66
  it('has access to the service via a structural directive', () => {
65
- // Let's render a div with the directive. It provides a point to
66
- // access the service.
67
- const fixture = MockRender('<div *target></div>');
67
+ // Let's render a div with the directive.
68
+ MockRender('<div *target></div>');
69
+
70
+ // Let's find the debugNode with the directive.
71
+ // Please note, that we use ngMocks.reveal here.
72
+ const node = ngMocks.reveal(TargetDirective);
68
73
 
69
- // The root element is fixture.point and it has access to the
70
- // context of the directive. Its injector can extract the service.
71
- const service = fixture.point.injector.get(TargetService);
74
+ // Let's extract the service.
75
+ const service = ngMocks.get(node, TargetService);
72
76
 
73
77
  // Here we go, now we can assert everything about the service.
74
78
  expect(service.value).toEqual(true);
@@ -60,8 +60,9 @@ class TargetModule {}
60
60
 
61
61
  describe('TestRoute:Route', () => {
62
62
  beforeEach(() => {
63
- return MockBuilder(RouterModule, TargetModule).keep(
64
- RouterTestingModule.withRoutes([]),
63
+ return MockBuilder(
64
+ [RouterModule, RouterTestingModule.withRoutes([])],
65
+ TargetModule,
65
66
  );
66
67
  });
67
68
 
@@ -111,9 +112,14 @@ describe('TestRoute:Component', () => {
111
112
  // RouterTestingModule.withRoutes([]), yes yes, with empty routes
112
113
  // to have tools for testing.
113
114
  beforeEach(() => {
114
- return MockBuilder(TargetComponent, TargetModule)
115
- .keep(RouterModule)
116
- .keep(RouterTestingModule.withRoutes([]));
115
+ return MockBuilder(
116
+ [
117
+ TargetComponent,
118
+ RouterModule,
119
+ RouterTestingModule.withRoutes([]),
120
+ ],
121
+ TargetModule,
122
+ );
117
123
  });
118
124
 
119
125
  it('navigates between pages', fakeAsync(() => {
@@ -127,8 +133,8 @@ describe('TestRoute:Component', () => {
127
133
  tick(); // is needed for rendering of the current route.
128
134
  }
129
135
 
130
- // By default our routes do not have a component.
131
- // Therefore non of them should be rendered.
136
+ // By default, our routes do not have a component.
137
+ // Therefore, none of them should be rendered.
132
138
  expect(location.path()).toEqual('/');
133
139
  expect(() => ngMocks.find(Target1Component)).toThrow();
134
140
  expect(() => ngMocks.find(Target2Component)).toThrow();
@@ -115,10 +115,10 @@ describe('TestRoutingGuard', () => {
115
115
  // to have tools for testing. And the last thing is to exclude
116
116
  // `NG_MOCKS_GUARDS` to remove all other guards.
117
117
  beforeEach(() => {
118
- return MockBuilder(LoginGuard, TargetModule)
119
- .exclude(NG_MOCKS_GUARDS)
120
- .keep(RouterModule)
121
- .keep(RouterTestingModule.withRoutes([]));
118
+ return MockBuilder(
119
+ [LoginGuard, RouterModule, RouterTestingModule.withRoutes([])],
120
+ TargetModule,
121
+ ).exclude(NG_MOCKS_GUARDS);
122
122
  });
123
123
 
124
124
  // It is important to run routing tests in fakeAsync.
@@ -88,9 +88,14 @@ describe('TestRoutingResolver', () => {
88
88
  // add RouterTestingModule.withRoutes([]), yes yes, with empty
89
89
  // routes to have tools for testing.
90
90
  beforeEach(() => {
91
- return MockBuilder(DataResolver, TargetModule)
92
- .keep(RouterModule)
93
- .keep(RouterTestingModule.withRoutes([]));
91
+ return MockBuilder(
92
+ [
93
+ DataResolver,
94
+ RouterModule,
95
+ RouterTestingModule.withRoutes([]),
96
+ ],
97
+ TargetModule,
98
+ );
94
99
  });
95
100
 
96
101
  // It is important to run routing tests in fakeAsync.
@@ -0,0 +1,87 @@
1
+ import {
2
+ Component,
3
+ Input,
4
+ NgModule,
5
+ Pipe,
6
+ PipeTransform,
7
+ VERSION,
8
+ } from '@angular/core';
9
+
10
+ import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
11
+
12
+ // A simple standalone pipe we are going to mock.
13
+ @Pipe({
14
+ name: 'standalone',
15
+ standalone: true,
16
+ } as never)
17
+ class StandalonePipe implements PipeTransform {
18
+ transform(value: string | null): string {
19
+ return `${value}:${this.constructor.name}`;
20
+ }
21
+ }
22
+
23
+ // A simple dependency component we are going to mock.
24
+ @Component({
25
+ selector: 'dependency',
26
+ template: '<ng-content></ng-content>',
27
+ })
28
+ class DependencyComponent {
29
+ @Input() public readonly name: string | null = null;
30
+ }
31
+
32
+ // A module which declares and exports the dependency component.
33
+ @NgModule({
34
+ declarations: [DependencyComponent],
35
+ exports: [DependencyComponent],
36
+ })
37
+ class DependencyModule {}
38
+
39
+ // A standalone component we are going to test.
40
+ @Component({
41
+ selector: 'standalone',
42
+ template: `<dependency [name]="name">{{
43
+ name | standalone
44
+ }}</dependency>`,
45
+ standalone: true,
46
+ imports: [DependencyModule, StandalonePipe],
47
+ } as never)
48
+ class StandaloneComponent {
49
+ @Input() public readonly name: string | null = null;
50
+ }
51
+
52
+ describe('TestStandaloneComponent', () => {
53
+ if (Number.parseInt(VERSION.major, 10) < 14) {
54
+ it('needs a14', () => {
55
+ // pending('Need Angular > 5');
56
+ expect(true).toBeTruthy();
57
+ });
58
+
59
+ return;
60
+ }
61
+
62
+ beforeEach(() => {
63
+ return MockBuilder(StandaloneComponent);
64
+ });
65
+
66
+ it('renders dependencies', () => {
67
+ const fixture = MockRender(StandaloneComponent, {
68
+ name: 'test',
69
+ });
70
+
71
+ // asserting that we passed the input
72
+ const dependencyComponent = ngMocks.findInstance(
73
+ DependencyComponent,
74
+ );
75
+ expect(dependencyComponent.name).toEqual('test');
76
+
77
+ // asserting how we called the pipe
78
+ const standalonePipe = ngMocks.findInstance(StandalonePipe);
79
+ // it's possible because of autoSpy.
80
+ expect(standalonePipe.transform).toHaveBeenCalledWith('test');
81
+
82
+ // or asserting the generated html
83
+ expect(ngMocks.formatHtml(fixture)).toEqual(
84
+ '<standalone ng-reflect-name="test"><dependency ng-reflect-name="test"></dependency></standalone>',
85
+ );
86
+ });
87
+ });
@@ -0,0 +1,68 @@
1
+ import {
2
+ Directive,
3
+ Injectable,
4
+ Input,
5
+ OnInit,
6
+ VERSION,
7
+ } from '@angular/core';
8
+
9
+ import { MockBuilder, MockRender, ngMocks } from 'ng-mocks';
10
+
11
+ // @TODO remove with A5 support
12
+ const injectableRootServiceArgs = [
13
+ {
14
+ providedIn: 'root',
15
+ } as never,
16
+ ];
17
+
18
+ // A root service we want to mock.
19
+ @Injectable(...injectableRootServiceArgs)
20
+ class RootService {
21
+ trigger(name: string | null) {
22
+ // does something very cool
23
+
24
+ return name;
25
+ }
26
+ }
27
+
28
+ // A standalone directive we are going to test.
29
+ @Directive({
30
+ selector: 'standalone',
31
+ standalone: true,
32
+ } as never)
33
+ class StandaloneDirective implements OnInit {
34
+ @Input() public readonly name: string | null = null;
35
+
36
+ constructor(public readonly rootService: RootService) {}
37
+
38
+ ngOnInit(): void {
39
+ this.rootService.trigger(this.name);
40
+ }
41
+ }
42
+
43
+ describe('TestStandaloneDirective', () => {
44
+ if (Number.parseInt(VERSION.major, 10) < 14) {
45
+ it('needs a14', () => {
46
+ // pending('Need Angular > 5');
47
+ expect(true).toBeTruthy();
48
+ });
49
+
50
+ return;
51
+ }
52
+
53
+ beforeEach(() => {
54
+ return MockBuilder(StandaloneDirective);
55
+ });
56
+
57
+ it('renders dependencies', () => {
58
+ // Rendering the directive.
59
+ MockRender(StandaloneDirective, {
60
+ name: 'test',
61
+ });
62
+
63
+ // Asserting that StandaloneDirective calls RootService.trigger.
64
+ const rootService = ngMocks.findInstance(RootService);
65
+ // it's possible because of autoSpy.
66
+ expect(rootService.trigger).toHaveBeenCalledWith('test');
67
+ });
68
+ });