Skip to content

Commit 18065d2

Browse files
asynclizcopybara-github
authored andcommitted
test(field): add unit tests
PiperOrigin-RevId: 404675948
1 parent 002ab7f commit 18065d2

File tree

3 files changed

+142
-7
lines changed

3 files changed

+142
-7
lines changed
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import 'jasmine';
8+
9+
import {spyOnAllFunctions} from '../../testing/jasmine';
10+
import {FieldFoundation} from '../lib/foundation';
11+
import {FieldAdapter, LabelType} from '../lib/state';
12+
13+
describe('FieldFoundation', () => {
14+
function setupTest() {
15+
const adapter: FieldAdapter = {
16+
state: {
17+
disabled: false,
18+
error: false,
19+
labelText: '',
20+
focused: false,
21+
populated: false,
22+
required: false,
23+
visibleLabelType: LabelType.RESTING,
24+
}
25+
};
26+
27+
const foundation = new FieldFoundation(adapter);
28+
return {
29+
foundation: spyOnAllFunctions(foundation).and.callThrough(),
30+
adapter: spyOnAllFunctions(adapter).and.callThrough(),
31+
};
32+
}
33+
34+
it('#onDisabledChange() unfocuses field when disabled', () => {
35+
const {foundation, adapter} = setupTest();
36+
foundation.init();
37+
adapter.state.focused = true;
38+
adapter.state.disabled = true;
39+
expect(adapter.state.focused)
40+
.withContext('focused is false after disabled is set to true')
41+
.toBe(false);
42+
});
43+
44+
it('#onFocusedChange() does not allow focus if disabled', () => {
45+
const {foundation, adapter} = setupTest();
46+
foundation.init();
47+
adapter.state.disabled = true;
48+
adapter.state.focused = true;
49+
expect(adapter.state.focused)
50+
.withContext('focused set back to false when disabled')
51+
.toBe(false);
52+
});
53+
54+
it('#updateLayoutAsterisk() sets labelText when label or required changes',
55+
() => {
56+
const {foundation, adapter} = setupTest();
57+
foundation.init();
58+
const labelValue = 'Label';
59+
adapter.state.label = labelValue;
60+
expect(adapter.state.labelText)
61+
.withContext('labelText should equal label when not required')
62+
.toBe(labelValue);
63+
adapter.state.required = true;
64+
expect(adapter.state.labelText)
65+
.withContext(
66+
'labelText should equal label with asterisk when required')
67+
.toBe(`${labelValue}*`);
68+
adapter.state.label = undefined;
69+
expect(adapter.state.labelText)
70+
.withContext(
71+
'labelText should be empty string if label is not provided, even when required')
72+
.toBe('');
73+
});
74+
});

components/field/test/md-field.test.ts

Lines changed: 0 additions & 7 deletions
This file was deleted.

components/testing/jasmine.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/**
2+
* @license
3+
* Copyright 2021 Google LLC
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
import 'jasmine';
8+
9+
/**
10+
* SpyObj with "and" for chaining a group of spies.
11+
*/
12+
export type SpyGroup<T> = jasmine.SpyObj<T>&{
13+
and: SpyGroupAnd<T>;
14+
};
15+
16+
/**
17+
* SpyAnd for group of multiple spies.
18+
*/
19+
export interface SpyGroupAnd<T> {
20+
callThrough(): jasmine.SpyObj<T>;
21+
stub(): jasmine.SpyObj<T>;
22+
}
23+
24+
/**
25+
* A more versatile `spyOnAllFunctions()` that allows chaining `callThrough()`
26+
* and `stub()` for all function spies.
27+
*
28+
* Spies on all functions, including those from the prototype chain (useful for
29+
* class instance objects).
30+
*
31+
* @param obj The object to spy on all functions.
32+
* @return The spied object.
33+
*/
34+
export function spyOnAllFunctions<T extends object>(obj: T) {
35+
const functionKeys = new Set<keyof T>();
36+
let target: object|null = obj;
37+
while (target) {
38+
const keys =
39+
Object.getOwnPropertyNames(target) as Array<keyof typeof target>;
40+
for (const key of keys) {
41+
if (target.hasOwnProperty(key) && typeof target[key] === 'function') {
42+
functionKeys.add(key);
43+
}
44+
}
45+
target = Object.getPrototypeOf(target);
46+
}
47+
for (const key of functionKeys) {
48+
spyOn(obj, key);
49+
}
50+
51+
const spyObj = obj as SpyGroup<T>;
52+
spyObj.and = {
53+
callThrough() {
54+
for (const key of functionKeys) {
55+
(spyObj[key] as jasmine.Spy).and.callThrough();
56+
}
57+
return spyObj;
58+
},
59+
stub() {
60+
for (const key of functionKeys) {
61+
(spyObj[key] as jasmine.Spy).and.stub();
62+
}
63+
return spyObj;
64+
},
65+
};
66+
67+
return spyObj;
68+
}

0 commit comments

Comments
 (0)