Skip to content

Commit

Permalink
fix: improving types and linter
Browse files Browse the repository at this point in the history
closes #127
  • Loading branch information
satanTime committed May 22, 2020
1 parent 830cf1d commit 8176fa5
Show file tree
Hide file tree
Showing 67 changed files with 433 additions and 132 deletions.
61 changes: 61 additions & 0 deletions e2e/control-value-accessor-form-control/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { CommonModule } from '@angular/common';
import { Component, forwardRef, NgModule } from '@angular/core';
import { ControlValueAccessor, FormControl, NG_VALUE_ACCESSOR, ReactiveFormsModule } from '@angular/forms';

@Component({
selector: 'target',
template: '<control [formControl]="control"></control>',
})
export class TargetComponent {
public readonly control = new FormControl();
}

@Component({
providers: [
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ControlComponent),
},
],
selector: 'control',
template: '',
})
export class ControlComponent implements ControlValueAccessor {
public isDisabled = false;
public value: any;
public change: any = () => undefined;

changeTouch(): void {
this.touch();
}

changeValue(obj: any): void {
this.change(obj);
}

registerOnChange(fn: any): void {
this.change = fn;
}

registerOnTouched(fn: any): void {
this.touch = fn;
}

setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}

public touch: any = () => undefined;

writeValue(obj: any): void {
this.value = obj;
}
}

@NgModule({
declarations: [TargetComponent, ControlComponent],
exports: [TargetComponent],
imports: [CommonModule, ReactiveFormsModule],
})
export class TargetModule {}
113 changes: 113 additions & 0 deletions e2e/control-value-accessor-form-control/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
import { ReactiveFormsModule } from '@angular/forms';

import { MockBuilder } from '../../lib/mock-builder';
import { MockComponent } from '../../lib/mock-component';
import { MockHelper } from '../../lib/mock-helper';
import { MockRender } from '../../lib/mock-render';

import { ControlComponent, TargetComponent, TargetModule } from './fixtures';

// a real case to check possible behavior.
describe('control-value-accessor-form-control:real', () => {
beforeEach(() => MockBuilder(TargetComponent).keep(TargetModule));

it('respects our formControl', () => {
const fixture = MockRender(TargetComponent, {}, false);
const mock = MockHelper.findOrFail(fixture.debugElement, ControlComponent).componentInstance;
spyOn(mock, 'writeValue').and.callThrough();
spyOn(mock, 'setDisabledState').and.callThrough();
fixture.detectChanges();

// tslint:disable-next-line:no-null-keyword
expect(mock.writeValue).toHaveBeenCalledWith(null);
expect(mock.setDisabledState).not.toHaveBeenCalled();
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

// checking via original component
fixture.point.componentInstance.control.setValue('test1');
expect(mock.writeValue).toHaveBeenCalledWith('test1');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

fixture.point.componentInstance.control.setValue('test2');
expect(mock.writeValue).toHaveBeenCalledWith('test2');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

// checking that touch works
mock.changeTouch();
expect(fixture.point.componentInstance.control.touched).toBeTruthy();

// checking that reset works
fixture.point.componentInstance.control.markAsUntouched();
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

// checking that disabled works
fixture.point.componentInstance.control.disable();
expect(mock.setDisabledState).toHaveBeenCalledWith(true);
fixture.point.componentInstance.control.enable();
expect(mock.setDisabledState).toHaveBeenCalledWith(false);

// changeValue doesn't trigger anything else but the callback. Therefore it doesn't render new value.
// It only updates the original control's value.
mock.changeValue('test3');
expect(mock.writeValue).not.toHaveBeenCalledWith('test3');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();
expect(fixture.point.componentInstance.control.value).toBe('test3');
});
});

// a way that ensures that a mocked component behaves the same way as real one.
describe('control-value-accessor-form-control:mock', () => {
beforeEach(() => MockBuilder(TargetComponent, TargetModule).keep(ReactiveFormsModule));

it('respects our formControl', () => {
const fixture = MockRender(TargetComponent, {}, false);
const mock = MockHelper.findOrFail(fixture.debugElement, MockComponent(ControlComponent)).componentInstance;
spyOn(mock, 'writeValue').and.callThrough();
spyOn(mock, 'setDisabledState').and.callThrough();
spyOn(mock, 'registerOnChange').and.callThrough();
spyOn(mock, 'registerOnTouched').and.callThrough();
fixture.detectChanges();

// tslint:disable-next-line:no-null-keyword
expect(mock.writeValue).toHaveBeenCalledWith(null);
expect(mock.setDisabledState).not.toHaveBeenCalled();
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

// checking via original component
fixture.point.componentInstance.control.setValue('test1');
expect(mock.writeValue).toHaveBeenCalledWith('test1');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

fixture.point.componentInstance.control.setValue('test2');
expect(mock.writeValue).toHaveBeenCalledWith('test2');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();

// checking that touch works
mock.__simulateTouch();
expect(fixture.point.componentInstance.control.touched).toBeTruthy();
fixture.point.componentInstance.control.markAsUntouched();
expect(fixture.point.componentInstance.control.touched).toBeFalsy();
// a way through a spy
MockHelper.mockService<jasmine.Spy>(mock, 'registerOnTouched').calls.first().args[0]();
expect(fixture.point.componentInstance.control.touched).toBeTruthy();
fixture.point.componentInstance.control.markAsUntouched();

// checking that disabled works
fixture.point.componentInstance.control.disable();
expect(mock.setDisabledState).toHaveBeenCalledWith(true);
fixture.point.componentInstance.control.enable();
expect(mock.setDisabledState).toHaveBeenCalledWith(false);

// changeValue doesn't trigger anything else but the callback. Therefore it doesn't render new value.
// It only updates the original control's value.
mock.__simulateChange('test3');
expect(mock.writeValue).not.toHaveBeenCalledWith('test3');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();
expect(fixture.point.componentInstance.control.value).toBe('test3');
// a way through a spy
MockHelper.mockService<jasmine.Spy>(mock, 'registerOnChange').calls.first().args[0]('test4');
expect(mock.writeValue).not.toHaveBeenCalledWith('test4');
expect(fixture.point.componentInstance.control.touched).toBeFalsy();
expect(fixture.point.componentInstance.control.value).toBe('test4');
});
});
70 changes: 70 additions & 0 deletions e2e/control-value-accessor-ng-model/fixtures.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { CommonModule } from '@angular/common';
import { Component, forwardRef, NgModule } from '@angular/core';
import { ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';

@Component({
selector: 'target',
template: '<control [ngModel]="value" (ngModelChange)="value = $event" [disabled]="disabled"></control>',
})
export class TargetComponent {
public disabled = false;
public realValue: null | string = null; // tslint:disable-line:no-null-keyword

public get value(): null | string {
return this.realValue;
}

public set value(value: null | string) {
this.realValue = value;
}
}

@Component({
providers: [
{
multi: true,
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => ControlComponent),
},
],
selector: 'control',
template: '',
})
export class ControlComponent implements ControlValueAccessor {
public isDisabled = false;
public value: any;
public change: any = () => undefined;

changeTouch(): void {
this.touch();
}

changeValue(obj: any): void {
this.change(obj);
}

registerOnChange(fn: any): void {
this.change = fn;
}

registerOnTouched(fn: any): void {
this.touch = fn;
}

setDisabledState(isDisabled: boolean): void {
this.isDisabled = isDisabled;
}

public touch: any = () => undefined;

writeValue(obj: any): void {
this.value = obj;
}
}

@NgModule({
declarations: [TargetComponent, ControlComponent],
exports: [TargetComponent],
imports: [CommonModule, FormsModule],
})
export class TargetModule {}
135 changes: 135 additions & 0 deletions e2e/control-value-accessor-ng-model/test.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import { FormsModule, NgModel } from '@angular/forms';

import { MockBuilder } from '../../lib/mock-builder';
import { MockComponent } from '../../lib/mock-component';
import { MockHelper } from '../../lib/mock-helper';
import { MockRender } from '../../lib/mock-render';

import { ControlComponent, TargetComponent, TargetModule } from './fixtures';

// a real case to check possible behavior.
describe('control-value-accessor-ng-model:real', () => {
beforeEach(() => MockBuilder(TargetComponent).keep(TargetModule));

it('respects our ngModel', async () => {
const fixture = MockRender(TargetComponent, {}, false);
const mockElement = MockHelper.findOrFail(fixture.debugElement, ControlComponent);
const mock = mockElement.componentInstance;
spyOn(mock, 'writeValue').and.callThrough();
spyOn(mock, 'setDisabledState').and.callThrough();
const ngModel = MockHelper.getDirectiveOrFail(mockElement, NgModel);
fixture.detectChanges();
await fixture.whenStable();

// tslint:disable-next-line:no-null-keyword
expect(mock.writeValue).toHaveBeenCalledWith(null);
expect(mock.setDisabledState).not.toHaveBeenCalled();
expect(ngModel.touched).toBeFalsy();

// checking via original component
fixture.point.componentInstance.value = 'test1';
fixture.detectChanges();
await fixture.whenStable();
expect(mock.writeValue).toHaveBeenCalledWith('test1');
expect(ngModel.touched).toBeFalsy();

fixture.point.componentInstance.value = 'test2';
fixture.detectChanges();
await fixture.whenStable();
expect(mock.writeValue).toHaveBeenCalledWith('test2');
expect(ngModel.touched).toBeFalsy();

// checking that touch works
mock.changeTouch();
expect(ngModel.touched).toBeTruthy();

// checking that reset works
ngModel.control.markAsUntouched();
expect(ngModel.touched).toBeFalsy();

// checking that disabled works
fixture.point.componentInstance.disabled = true;
fixture.detectChanges();
await fixture.whenStable();
expect(mock.setDisabledState).toHaveBeenCalledWith(true);
fixture.point.componentInstance.disabled = false;
fixture.detectChanges();
await fixture.whenStable();
expect(mock.setDisabledState).toHaveBeenCalledWith(false);

// changeValue doesn't trigger anything else but the callback. Therefore it doesn't render new value.
// It only updates the original control's value.
mock.changeValue('test3');
expect(mock.writeValue).not.toHaveBeenCalledWith('test3');
expect(ngModel.touched).toBeFalsy();
expect(fixture.point.componentInstance.value).toBe('test3');
});
});

// a way that ensures that a mocked component behaves the same way as real one.
describe('control-value-accessor-ng-model:mock', () => {
beforeEach(() => MockBuilder(TargetComponent, TargetModule).keep(FormsModule));

it('respects our ngModel', async () => {
const fixture = MockRender(TargetComponent, {}, false);
const mockElement = MockHelper.findOrFail(fixture.debugElement, MockComponent(ControlComponent));
const mock = mockElement.componentInstance;
spyOn(mock, 'writeValue').and.callThrough();
spyOn(mock, 'setDisabledState').and.callThrough();
spyOn(mock, 'registerOnChange').and.callThrough();
spyOn(mock, 'registerOnTouched').and.callThrough();
const ngModel = MockHelper.getDirectiveOrFail(mockElement, NgModel);
fixture.detectChanges();
await fixture.whenStable();

// tslint:disable-next-line:no-null-keyword
expect(mock.writeValue).toHaveBeenCalledWith(null);
expect(mock.setDisabledState).not.toHaveBeenCalled();
expect(ngModel.touched).toBeFalsy();

// checking via original component
fixture.point.componentInstance.value = 'test1';
fixture.detectChanges();
await fixture.whenStable();
expect(mock.writeValue).toHaveBeenCalledWith('test1');
expect(ngModel.touched).toBeFalsy();

fixture.point.componentInstance.value = 'test2';
fixture.detectChanges();
await fixture.whenStable();
expect(mock.writeValue).toHaveBeenCalledWith('test2');
expect(ngModel.touched).toBeFalsy();

// checking that touch works
mock.__simulateTouch();
expect(ngModel.touched).toBeTruthy();
ngModel.control.markAsUntouched();
expect(ngModel.touched).toBeFalsy();
// a way through a spy
MockHelper.mockService<jasmine.Spy>(mock, 'registerOnTouched').calls.first().args[0]();
expect(ngModel.touched).toBeTruthy();
ngModel.control.markAsUntouched();

// checking that disabled works
fixture.point.componentInstance.disabled = true;
fixture.detectChanges();
await fixture.whenStable();
expect(mock.setDisabledState).toHaveBeenCalledWith(true);
fixture.point.componentInstance.disabled = false;
fixture.detectChanges();
await fixture.whenStable();
expect(mock.setDisabledState).toHaveBeenCalledWith(false);

// changeValue doesn't trigger anything else but the callback. Therefore it doesn't render new value.
// It only updates the original control's value.
mock.__simulateChange('test3');
expect(mock.writeValue).not.toHaveBeenCalledWith('test3');
expect(ngModel.touched).toBeFalsy();
expect(fixture.point.componentInstance.value).toBe('test3');
// a way through a spy
MockHelper.mockService<jasmine.Spy>(mock, 'registerOnChange').calls.first().args[0]('test4');
expect(mock.writeValue).not.toHaveBeenCalledWith('test4');
expect(ngModel.touched).toBeFalsy();
expect(ngModel.value).toBe('test4');
});
});
2 changes: 0 additions & 2 deletions e2e/exports-only/fixtures.components.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// tslint:disable:max-classes-per-file

import { Component } from '@angular/core';

@Component({
Expand Down
2 changes: 0 additions & 2 deletions e2e/exports-only/fixtures.modules.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// tslint:disable:max-classes-per-file

import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';

Expand Down
Loading

0 comments on commit 8176fa5

Please sign in to comment.