Skip to content

Commit a1723b5

Browse files
committed
tests
1 parent d22683b commit a1723b5

File tree

4 files changed

+196
-6
lines changed

4 files changed

+196
-6
lines changed

.github/CODEOWNERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@
5959
/src/cdk/bidi/** @jelbourn
6060
/src/cdk/coercion/** @jelbourn
6161
/src/cdk/collections/** @jelbourn @crisbeto @andrewseguin
62-
/src/cdl/input/** @mmalerba
62+
/src/cdk/input/** @mmalerba
6363
/src/cdk/keycodes/** @jelbourn
6464
/src/cdk/layout/** @josephperrott
6565
/src/cdk/observers/** @jelbourn @crisbeto

src/cdk/input/_autofill.scss

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616
// Used to generate UIDs for keyframes used to change the input autofill styles.
1717
$cdk-input-autofill-color-frame-count: 0;
1818

19-
// Mixin used to apply custom background and foreground colors to an autofilled input.
20-
// Based on:
21-
// https://stackoverflow.com/questions/2781549/removing-input-background-colour-for-chrome-autocomplete#answer-37432260
19+
// Mixin used to apply custom background and foreground colors to an autofilled input. Based on:
20+
// https://stackoverflow.com/questions/2781549/
21+
// removing-input-background-colour-for-chrome-autocomplete#answer-37432260
2222
@mixin cdk-input-autofill-color($background, $foreground:'') {
2323
@keyframes cdk-input-autofill-color-#{$cdk-input-autofill-color-frame-count} {
2424
to {
@@ -27,11 +27,14 @@ $cdk-input-autofill-color-frame-count: 0;
2727
}
2828
}
2929

30-
&:-webkit-autofill,
30+
&:-webkit-autofill {
31+
animation-name: cdk-input-autofill-color-#{$cdk-input-autofill-color-frame-count};
32+
animation-fill-mode: both;
33+
}
34+
3135
&.cdk-input-autofill-monitored:-webkit-autofill {
3236
animation-name: cdk-input-autofill-start,
3337
cdk-input-autofill-color-#{$cdk-input-autofill-color-frame-count};
34-
animation-fill-mode: both;
3538
}
3639

3740
$cdk-input-autofill-color-frame-count: $cdk-input-autofill-color-frame-count + 1 !global;

src/cdk/input/autofill.spec.ts

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/**
2+
* @license
3+
* Copyright Google LLC All Rights Reserved.
4+
*
5+
* Use of this source code is governed by an MIT-style license that can be
6+
* found in the LICENSE file at https://angular.io/license
7+
*/
8+
9+
import {Component, ElementRef, ViewChild} from '@angular/core';
10+
import {ComponentFixture, inject, TestBed} from '@angular/core/testing';
11+
import {AutofillEvent, AutofillMonitor} from './autofill';
12+
import {InputModule} from './input-module';
13+
import {empty as observableEmpty} from 'rxjs/observable/empty';
14+
15+
describe('AutofillMonitor', () => {
16+
let autofillMonitor: AutofillMonitor;
17+
let fixture: ComponentFixture<Inputs>;
18+
let testComponent: Inputs;
19+
20+
beforeEach(() => {
21+
TestBed.configureTestingModule({
22+
imports: [InputModule],
23+
declarations: [Inputs],
24+
}).compileComponents();
25+
});
26+
27+
beforeEach(inject([AutofillMonitor], (afm: AutofillMonitor) => {
28+
autofillMonitor = afm;
29+
fixture = TestBed.createComponent(Inputs);
30+
testComponent = fixture.componentInstance;
31+
32+
for (const input of [testComponent.input1, testComponent.input2, testComponent.input3]) {
33+
spyOn(input.nativeElement, 'addEventListener');
34+
spyOn(input.nativeElement, 'removeEventListener');
35+
}
36+
37+
fixture.detectChanges();
38+
}));
39+
40+
afterEach(() => {
41+
// Call destroy to make sure we clean up all listeners.
42+
autofillMonitor.ngOnDestroy();
43+
});
44+
45+
it('should add monitored class and listener upon monitoring', () => {
46+
const inputEl = testComponent.input1.nativeElement;
47+
expect(inputEl.addEventListener).not.toHaveBeenCalled();
48+
49+
autofillMonitor.monitor(inputEl);
50+
expect(inputEl.classList).toContain('cdk-input-autofill-monitored');
51+
expect(inputEl.addEventListener).toHaveBeenCalledWith('animationstart', jasmine.any(Function));
52+
});
53+
54+
it('should not add multiple listeners to the same element', () => {
55+
const inputEl = testComponent.input1.nativeElement;
56+
expect(inputEl.addEventListener).not.toHaveBeenCalled();
57+
58+
autofillMonitor.monitor(inputEl);
59+
autofillMonitor.monitor(inputEl);
60+
expect(inputEl.addEventListener).toHaveBeenCalledTimes(1);
61+
});
62+
63+
it('should remove monitored class and listener upon stop monitoring', () => {
64+
const inputEl = testComponent.input1.nativeElement;
65+
autofillMonitor.monitor(inputEl);
66+
expect(inputEl.classList).toContain('cdk-input-autofill-monitored');
67+
expect(inputEl.removeEventListener).not.toHaveBeenCalled();
68+
69+
autofillMonitor.stopMonitoring(inputEl);
70+
expect(inputEl.classList).not.toContain('cdk-input-autofill-monitored');
71+
expect(inputEl.removeEventListener)
72+
.toHaveBeenCalledWith('animationstart', jasmine.any(Function));
73+
});
74+
75+
it('should stop monitoring all monitored elements upon destroy', () => {
76+
const inputEl1 = testComponent.input1.nativeElement;
77+
const inputEl2 = testComponent.input2.nativeElement;
78+
const inputEl3 = testComponent.input3.nativeElement;
79+
autofillMonitor.monitor(inputEl1);
80+
autofillMonitor.monitor(inputEl2);
81+
autofillMonitor.monitor(inputEl3);
82+
expect(inputEl1.removeEventListener).not.toHaveBeenCalled();
83+
expect(inputEl2.removeEventListener).not.toHaveBeenCalled();
84+
expect(inputEl3.removeEventListener).not.toHaveBeenCalled();
85+
86+
autofillMonitor.ngOnDestroy();
87+
expect(inputEl1.removeEventListener).toHaveBeenCalled();
88+
expect(inputEl2.removeEventListener).toHaveBeenCalled();
89+
expect(inputEl3.removeEventListener).toHaveBeenCalled();
90+
});
91+
92+
it('should emit and add filled class upon start animation', () => {
93+
const inputEl = testComponent.input1.nativeElement;
94+
let animationStartCallback: Function = () => {};
95+
let autofillStreamEvent: AutofillEvent | null = null;
96+
inputEl.addEventListener.and.callFake((_, cb) => animationStartCallback = cb);
97+
const autofillStream = autofillMonitor.monitor(inputEl);
98+
autofillStream.subscribe(event => autofillStreamEvent = event);
99+
expect(autofillStreamEvent).toBeNull();
100+
expect(inputEl.classList).not.toContain('cdk-input-autofilled');
101+
102+
animationStartCallback({animationName: 'cdk-input-autofill-start', target: inputEl});
103+
expect(inputEl.classList).toContain('cdk-input-autofilled');
104+
expect(autofillStreamEvent).toEqual({target: inputEl, isAutofilled: true} as any);
105+
});
106+
107+
it('should emit and remove filled class upon end animation', () => {
108+
const inputEl = testComponent.input1.nativeElement;
109+
let animationStartCallback: Function = () => {};
110+
let autofillStreamEvent: AutofillEvent | null = null;
111+
inputEl.addEventListener.and.callFake((_, cb) => animationStartCallback = cb);
112+
const autofillStream = autofillMonitor.monitor(inputEl);
113+
autofillStream.subscribe(event => autofillStreamEvent = event);
114+
animationStartCallback({animationName: 'cdk-input-autofill-start', target: inputEl});
115+
expect(inputEl.classList).toContain('cdk-input-autofilled');
116+
expect(autofillStreamEvent).toEqual({target: inputEl, isAutofilled: true} as any);
117+
118+
animationStartCallback({animationName: 'cdk-input-autofill-end', target: inputEl});
119+
expect(inputEl.classList).not.toContain('cdk-input-autofilled');
120+
expect(autofillStreamEvent).toEqual({target: inputEl, isAutofilled: false} as any);
121+
});
122+
123+
it('should cleanup filled class if monitoring stopped in autofilled state', () => {
124+
const inputEl = testComponent.input1.nativeElement;
125+
let animationStartCallback: Function = () => {};
126+
inputEl.addEventListener.and.callFake((_, cb) => animationStartCallback = cb);
127+
autofillMonitor.monitor(inputEl);
128+
animationStartCallback({animationName: 'cdk-input-autofill-start', target: inputEl});
129+
expect(inputEl.classList).toContain('cdk-input-autofilled');
130+
131+
autofillMonitor.stopMonitoring(inputEl);
132+
expect(inputEl.classlist).not.toContain('cdk-input-autofilled');
133+
});
134+
});
135+
136+
describe('cdkAutofill', () => {
137+
let autofillMonitor: AutofillMonitor;
138+
let fixture: ComponentFixture<InputWithCdkAutofilled>;
139+
let testComponent: InputWithCdkAutofilled;
140+
141+
beforeEach(() => {
142+
TestBed.configureTestingModule({
143+
imports: [InputModule],
144+
declarations: [InputWithCdkAutofilled],
145+
}).compileComponents();
146+
});
147+
148+
beforeEach(inject([AutofillMonitor], (afm: AutofillMonitor) => {
149+
autofillMonitor = afm;
150+
spyOn(autofillMonitor, 'monitor').and.returnValue(observableEmpty());
151+
spyOn(autofillMonitor, 'stopMonitoring');
152+
fixture = TestBed.createComponent(InputWithCdkAutofilled);
153+
testComponent = fixture.componentInstance;
154+
fixture.detectChanges();
155+
}));
156+
157+
it('should monitor host element on init', () => {
158+
expect(autofillMonitor.monitor).toHaveBeenCalledWith(testComponent.input.nativeElement);
159+
});
160+
161+
it('should stop monitoring host element on destroy', () => {
162+
expect(autofillMonitor.stopMonitoring).not.toHaveBeenCalled();
163+
fixture.destroy();
164+
expect(autofillMonitor.stopMonitoring).toHaveBeenCalledWith(testComponent.input.nativeElement);
165+
});
166+
});
167+
168+
@Component({
169+
template: `
170+
<input #input1>
171+
<input #input2>
172+
<input #input3>
173+
`
174+
})
175+
class Inputs {
176+
@ViewChild('input1') input1: ElementRef;
177+
@ViewChild('input2') input2: ElementRef;
178+
@ViewChild('input3') input3: ElementRef;
179+
}
180+
181+
@Component({
182+
template: `<input #input cdkAutofill>`
183+
})
184+
class InputWithCdkAutofilled {
185+
@ViewChild('input') input: ElementRef;
186+
}

src/cdk/input/autofill.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ export class AutofillMonitor implements OnDestroy {
6969
if (info) {
7070
info.unlisten();
7171
element.classList.remove('cdk-input-autofill-monitored');
72+
element.classList.remove('cdk-input-autofilled');
7273
this._monitoredElements.delete(element);
7374
}
7475
}

0 commit comments

Comments
 (0)