Skip to content

Commit

Permalink
fix: smart injection of NG_VALUE_ACCESSOR
Browse files Browse the repository at this point in the history
closes #157
  • Loading branch information
satanTime committed Jul 11, 2020
1 parent 55a0031 commit ad37bf0
Show file tree
Hide file tree
Showing 54 changed files with 411 additions and 106 deletions.
1 change: 0 additions & 1 deletion e2e/a10es2015ivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a10es2015ivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a10es2015noivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a10es2015noivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a10es5ivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a10es5ivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a10es5noivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a10es5noivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
Empty file.
1 change: 0 additions & 1 deletion e2e/a5es2015/src/app/app.component.html

This file was deleted.

10 changes: 4 additions & 6 deletions e2e/a5es2015/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
title = 'app';
}
export class AppComponent {}
Empty file.
1 change: 0 additions & 1 deletion e2e/a5es5/src/app/app.component.html

This file was deleted.

10 changes: 4 additions & 6 deletions e2e/a5es5/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Component } from '@angular/core';
import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {
title = 'app';
}
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a6es2015/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a6es2015/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a6es5/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a6es5/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a7es2015/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a7es2015/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a7es5/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a7es5/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a8es2015/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a8es2015/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a8es5/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a8es5/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a9es2015ivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a9es2015ivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a9es2015noivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a9es2015noivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a9es5ivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a9es5ivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
1 change: 0 additions & 1 deletion e2e/a9es5noivy/src/app/app.component.html

This file was deleted.

Empty file.
3 changes: 1 addition & 2 deletions e2e/a9es5noivy/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
template: 'ng-mocks',
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class AppComponent {}
25 changes: 12 additions & 13 deletions lib/mock-component/mock-component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import {
ChangeDetectorRef,
Component,
forwardRef,
Optional,
Query,
Self,
TemplateRef,
ViewChild,
ViewContainerRef,
} from '@angular/core';
import { getTestBed } from '@angular/core/testing';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NgControl, NG_VALIDATORS } from '@angular/forms';

import { AbstractType, flatten, getMockedNgDefOf, MockControlValueAccessor, MockOf, Type } from '../common';
import { decorateInputs, decorateOutputs, decorateQueries } from '../common/decorate';
Expand Down Expand Up @@ -110,20 +112,13 @@ export function MockComponent<TComponent>(
template,
};

for (const providerDef of flatten(providers)) {
const provider =
for (const providerDef of flatten(providers || [])) {
const provide =
providerDef && typeof providerDef === 'object' && providerDef.provide ? providerDef.provide : providerDef;
if (options.providers && provider === NG_VALUE_ACCESSOR) {
if (options.providers && provide === NG_VALIDATORS) {
options.providers.push({
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ComponentMock),
});
}
if (options.providers && provider === NG_VALIDATORS) {
options.providers.push({
multi: true,
provide: NG_VALIDATORS,
provide,
useExisting: forwardRef(() => ComponentMock),
});
}
Expand All @@ -134,9 +129,13 @@ export function MockComponent<TComponent>(
@Component(options)
@MockOf(component, outputs)
class ComponentMock extends MockControlValueAccessor implements AfterContentInit {
constructor(changeDetector: ChangeDetectorRef) {
constructor(changeDetector: ChangeDetectorRef, @Self() @Optional() ngControl?: NgControl) {
super();

if (ngControl && !ngControl.valueAccessor) {
ngControl.valueAccessor = this;
}

// Providing method to hide any @ContentChild based on its selector.
(this as any).__hide = (contentChildSelector: string) => {
const key = viewChildRefs.get(contentChildSelector);
Expand Down
35 changes: 21 additions & 14 deletions lib/mock-directive/mock-directive.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
import { core } from '@angular/compiler';
import { Directive, ElementRef, forwardRef, OnInit, Optional, TemplateRef, ViewContainerRef } from '@angular/core';
import {
Directive,
ElementRef,
forwardRef,
OnInit,
Optional,
Self,
TemplateRef,
ViewContainerRef,
} from '@angular/core';
import { getTestBed } from '@angular/core/testing';
import { NG_VALIDATORS, NG_VALUE_ACCESSOR } from '@angular/forms';
import { NgControl, NG_VALIDATORS } from '@angular/forms';

import { AbstractType, flatten, getMockedNgDefOf, MockControlValueAccessor, MockOf, Type } from '../common';
import { decorateInputs, decorateOutputs, decorateQueries } from '../common/decorate';
Expand Down Expand Up @@ -67,20 +76,13 @@ export function MockDirective<TDirective>(directive: Type<TDirective>): Type<Moc
selector,
};

for (const providerDef of flatten(providers)) {
const provider =
for (const providerDef of flatten(providers || [])) {
const provide =
providerDef && typeof providerDef === 'object' && providerDef.provide ? providerDef.provide : providerDef;
if (options.providers && provider === NG_VALUE_ACCESSOR) {
if (options.providers && provide === NG_VALIDATORS) {
options.providers.push({
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => DirectiveMock),
});
}
if (options.providers && provider === NG_VALIDATORS) {
options.providers.push({
multi: true,
provide: NG_VALIDATORS,
provide,
useExisting: forwardRef(() => DirectiveMock),
});
}
Expand All @@ -94,10 +96,15 @@ export function MockDirective<TDirective>(directive: Type<TDirective>): Type<Moc
constructor(
@Optional() element?: ElementRef,
@Optional() template?: TemplateRef<any>,
@Optional() viewContainer?: ViewContainerRef
@Optional() viewContainer?: ViewContainerRef,
@Self() @Optional() ngControl?: NgControl
) {
super();

if (ngControl && !ngControl.valueAccessor) {
ngControl.valueAccessor = this;
}

// Basically any directive on ng-template is treated as structural, even it doesn't control render process.
// In our case we don't if we should render it or not and due to this we do nothing.
(this as any).__element = element;
Expand Down
23 changes: 11 additions & 12 deletions tests/issue-145/components.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,20 +48,19 @@ describe('issue-145', () => {
]);
});

it('ComponentValueAccessor', () => {
// this test was changed due to issue 157: https://github.com/ike18t/ng-mocks/issues/157
it('should skip NG_VALUE_ACCESSOR in mocked component ComponentValueAccessor', () => {
const mock = MockComponent(ComponentValueAccessor);
const { providers } = directiveResolver.resolve(mock);
expect(providers).toEqual([
{
provide: ComponentValueAccessor,
useExisting: jasmine.anything(),
},
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: jasmine.anything(),
},
]);
expect(providers as any).not.toEqual(
jasmine.arrayContaining([
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: jasmine.anything(),
},
])
);
});

it('ComponentValidator', () => {
Expand Down
21 changes: 10 additions & 11 deletions tests/issue-145/directives.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,20 +45,19 @@ describe('issue-145', () => {
]);
});

// this test was changed due to issue 157: https://github.com/ike18t/ng-mocks/issues/157
it('DirectiveValueAccessor', () => {
const mock = MockDirective(DirectiveValueAccessor);
const { providers } = directiveResolver.resolve(mock);
expect(providers).toEqual([
{
provide: DirectiveValueAccessor,
useExisting: jasmine.anything(),
},
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: jasmine.anything(),
},
]);
expect(providers as any).not.toEqual(
jasmine.arrayContaining([
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: jasmine.anything(),
},
])
);
});

it('DirectiveValidator', () => {
Expand Down
Loading

0 comments on commit ad37bf0

Please sign in to comment.