Skip to content
This repository was archived by the owner on Jan 13, 2025. It is now read-only.

Commit 1eb2949

Browse files
test(select): Add Jasmine foundation tests. (#5560)
* Project import generated by Copybara. PiperOrigin-RevId: 293150169 * Remove Mocha tests * Remove import * Fix TS compiler err * Revert package-lock Co-authored-by: Material Web Copybara Robot <[email protected]>
1 parent 5ff3380 commit 1eb2949

File tree

7 files changed

+1056
-916
lines changed

7 files changed

+1056
-916
lines changed

karma.conf.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ const istanbulInstrumenterLoader = {
9797
/notched-outline\/.*$/,
9898
/radio\/.*$/,
9999
/ripple\/.*$/,
100+
/select\/.*$/,
100101
/slider\/.*$/,
101102
/snackbar\/.*$/,
102103
/switch\/.*$/,
@@ -197,6 +198,7 @@ const jasmineConfig = {
197198
'packages/!(mdc-notched-outline)/**/*',
198199
'packages/!(mdc-radio)/**/*',
199200
'packages/!(mdc-ripple)/**/*',
201+
'packages/!(mdc-select)/**/*',
200202
'packages/!(mdc-slider)/**/*',
201203
'packages/!(mdc-snackbar)/**/*',
202204
'packages/!(mdc-switch)/**/*',
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google Inc.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
import {verifyDefaultAdapter} from '../../../../testing/helpers/foundation';
25+
import {setUpFoundationTest} from '../../../../testing/helpers/setup';
26+
import {MDCSelectHelperTextFoundation} from '../foundation';
27+
28+
const {cssClasses, strings} = MDCSelectHelperTextFoundation;
29+
30+
describe('MDCSelectHelperTextFoundation', () => {
31+
it('exports cssClasses', () => {
32+
expect(MDCSelectHelperTextFoundation.cssClasses).toEqual(cssClasses);
33+
});
34+
35+
it('exports strings', () => {
36+
expect(MDCSelectHelperTextFoundation.strings).toEqual(strings);
37+
});
38+
39+
it('defaultAdapter returns a complete adapter implementation', () => {
40+
verifyDefaultAdapter(MDCSelectHelperTextFoundation, [
41+
'addClass',
42+
'removeClass',
43+
'hasClass',
44+
'setAttr',
45+
'removeAttr',
46+
'setContent',
47+
]);
48+
});
49+
50+
const setupTest =
51+
() => {
52+
const {foundation, mockAdapter} =
53+
setUpFoundationTest(MDCSelectHelperTextFoundation);
54+
return {foundation, mockAdapter};
55+
}
56+
57+
it('#setContent sets the content of the helper text element', () => {
58+
const {foundation, mockAdapter} = setupTest();
59+
foundation.setContent('foo');
60+
expect(mockAdapter.setContent).toHaveBeenCalledWith('foo');
61+
});
62+
63+
it('#setPersistent toggles the persistent class', () => {
64+
const {foundation, mockAdapter} = setupTest();
65+
foundation.setPersistent(true);
66+
expect(mockAdapter.addClass)
67+
.toHaveBeenCalledWith(cssClasses.HELPER_TEXT_PERSISTENT);
68+
foundation.setPersistent(false);
69+
expect(mockAdapter.removeClass)
70+
.toHaveBeenCalledWith(cssClasses.HELPER_TEXT_PERSISTENT);
71+
});
72+
73+
it('#setValidation toggles the validation class', () => {
74+
const {foundation, mockAdapter} = setupTest();
75+
foundation.setValidation(true);
76+
expect(mockAdapter.addClass)
77+
.toHaveBeenCalledWith(cssClasses.HELPER_TEXT_VALIDATION_MSG);
78+
foundation.setValidation(false);
79+
expect(mockAdapter.removeClass)
80+
.toHaveBeenCalledWith(cssClasses.HELPER_TEXT_VALIDATION_MSG);
81+
});
82+
83+
it('#showToScreenReader removes aria-hidden from helperText', () => {
84+
const {foundation, mockAdapter} = setupTest();
85+
foundation.showToScreenReader();
86+
expect(mockAdapter.removeAttr).toHaveBeenCalledWith('aria-hidden');
87+
});
88+
89+
it('#setValidity adds role="alert" to helper text if input is invalid and helper text is being used ' +
90+
'as a validation message',
91+
() => {
92+
const {foundation, mockAdapter} = setupTest();
93+
const inputIsValid = false;
94+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_PERSISTENT)
95+
.and.returnValue(false);
96+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_VALIDATION_MSG)
97+
.and.returnValue(true);
98+
foundation.setValidity(inputIsValid);
99+
expect(mockAdapter.setAttr).toHaveBeenCalledWith('role', 'alert');
100+
});
101+
102+
it('#setValidity removes role="alert" if input is valid', () => {
103+
const {foundation, mockAdapter} = setupTest();
104+
const inputIsValid = true;
105+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_PERSISTENT)
106+
.and.returnValue(false);
107+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_VALIDATION_MSG)
108+
.and.returnValue(true);
109+
foundation.setValidity(inputIsValid);
110+
expect(mockAdapter.removeAttr).toHaveBeenCalledWith('role');
111+
});
112+
113+
it('#setValidity sets aria-hidden="true" on helper text by default', () => {
114+
const {foundation, mockAdapter} = setupTest();
115+
const inputIsValid = true;
116+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_PERSISTENT)
117+
.and.returnValue(false);
118+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_VALIDATION_MSG)
119+
.and.returnValue(false);
120+
foundation.setValidity(inputIsValid);
121+
expect(mockAdapter.setAttr).toHaveBeenCalledWith('aria-hidden', 'true');
122+
});
123+
124+
it('#setValidity does not set aria-hidden on helper text when it is persistent',
125+
() => {
126+
const {foundation, mockAdapter} = setupTest();
127+
const inputIsValid = true;
128+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_PERSISTENT)
129+
.and.returnValue(true);
130+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_VALIDATION_MSG)
131+
.and.returnValue(false);
132+
foundation.setValidity(inputIsValid);
133+
expect(mockAdapter.setAttr)
134+
.not.toHaveBeenCalledWith('aria-hidden', 'true');
135+
});
136+
137+
it('#setValidity does not set aria-hidden if input is invalid and helper text is validation message',
138+
() => {
139+
const {foundation, mockAdapter} = setupTest();
140+
const inputIsValid = false;
141+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_PERSISTENT)
142+
.and.returnValue(false);
143+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_VALIDATION_MSG)
144+
.and.returnValue(true);
145+
foundation.setValidity(inputIsValid);
146+
expect(mockAdapter.setAttr)
147+
.not.toHaveBeenCalledWith('aria-hidden', 'true');
148+
});
149+
150+
it('#setValidity sets aria-hidden=true if input is valid and helper text is validation message',
151+
() => {
152+
const {foundation, mockAdapter} = setupTest();
153+
const inputIsValid = true;
154+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_PERSISTENT)
155+
.and.returnValue(false);
156+
mockAdapter.hasClass.withArgs(cssClasses.HELPER_TEXT_VALIDATION_MSG)
157+
.and.returnValue(true);
158+
foundation.setValidity(inputIsValid);
159+
expect(mockAdapter.setAttr).toHaveBeenCalledWith('aria-hidden', 'true');
160+
});
161+
});
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* @license
3+
* Copyright 2020 Google Inc.
4+
*
5+
* Permission is hereby granted, free of charge, to any person obtaining a copy
6+
* of this software and associated documentation files (the "Software"), to deal
7+
* in the Software without restriction, including without limitation the rights
8+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
* copies of the Software, and to permit persons to whom the Software is
10+
* furnished to do so, subject to the following conditions:
11+
*
12+
* The above copyright notice and this permission notice shall be included in
13+
* all copies or substantial portions of the Software.
14+
*
15+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21+
* THE SOFTWARE.
22+
*/
23+
24+
25+
import {verifyDefaultAdapter} from '../../../../testing/helpers/foundation';
26+
import {setUpFoundationTest} from '../../../../testing/helpers/setup';
27+
import {strings} from '../constants';
28+
import {MDCSelectIconFoundation} from '../foundation';
29+
30+
describe('MDCSelectIconFoundation', () => {
31+
it('exports strings', () => {
32+
expect(MDCSelectIconFoundation.strings).toEqual(strings);
33+
});
34+
35+
it('defaultAdapter returns a complete adapter implementation', () => {
36+
verifyDefaultAdapter(MDCSelectIconFoundation, [
37+
'getAttr',
38+
'setAttr',
39+
'removeAttr',
40+
'setContent',
41+
'registerInteractionHandler',
42+
'deregisterInteractionHandler',
43+
'notifyIconAction',
44+
]);
45+
});
46+
47+
const setupTest =
48+
() => {
49+
const {foundation, mockAdapter} =
50+
setUpFoundationTest(MDCSelectIconFoundation);
51+
return {foundation, mockAdapter};
52+
}
53+
54+
it('#init adds event listeners', () => {
55+
const {foundation, mockAdapter} = setupTest();
56+
foundation.init();
57+
58+
expect(mockAdapter.registerInteractionHandler)
59+
.toHaveBeenCalledWith('click', jasmine.any(Function));
60+
expect(mockAdapter.registerInteractionHandler)
61+
.toHaveBeenCalledWith('keydown', jasmine.any(Function));
62+
});
63+
64+
it('#destroy removes event listeners', () => {
65+
const {foundation, mockAdapter} = setupTest();
66+
foundation.destroy();
67+
68+
expect(mockAdapter.deregisterInteractionHandler)
69+
.toHaveBeenCalledWith('click', jasmine.any(Function));
70+
expect(mockAdapter.deregisterInteractionHandler)
71+
.toHaveBeenCalledWith('keydown', jasmine.any(Function));
72+
});
73+
74+
it('#setDisabled sets icon tabindex to -1 and removes role when set to true if icon initially had a tabindex',
75+
() => {
76+
const {foundation, mockAdapter} = setupTest();
77+
mockAdapter.getAttr.withArgs('tabindex').and.returnValue('1');
78+
foundation.init();
79+
80+
foundation.setDisabled(true);
81+
expect(mockAdapter.setAttr).toHaveBeenCalledWith('tabindex', '-1');
82+
expect(mockAdapter.removeAttr).toHaveBeenCalledWith('role');
83+
});
84+
85+
it('#setDisabled does not change icon tabindex or role when set to true if icon initially had no tabindex',
86+
() => {
87+
const {foundation, mockAdapter} = setupTest();
88+
mockAdapter.getAttr.withArgs('tabindex').and.returnValue(null);
89+
foundation.init();
90+
91+
foundation.setDisabled(true);
92+
expect(mockAdapter.setAttr)
93+
.not.toHaveBeenCalledWith('tabindex', jasmine.any(String));
94+
expect(mockAdapter.removeAttr).not.toHaveBeenCalledWith('role');
95+
});
96+
97+
it('#setDisabled restores icon tabindex and role when set to false if icon initially had a tabindex',
98+
() => {
99+
const {foundation, mockAdapter} = setupTest();
100+
const expectedTabIndex = '1';
101+
mockAdapter.getAttr.withArgs('tabindex')
102+
.and.returnValue(expectedTabIndex);
103+
foundation.init();
104+
105+
foundation.setDisabled(false);
106+
expect(mockAdapter.setAttr)
107+
.toHaveBeenCalledWith('tabindex', expectedTabIndex);
108+
expect(mockAdapter.setAttr)
109+
.toHaveBeenCalledWith('role', strings.ICON_ROLE);
110+
});
111+
112+
it('#setDisabled does not change icon tabindex or role when set to false if icon initially had no tabindex',
113+
() => {
114+
const {foundation, mockAdapter} = setupTest();
115+
mockAdapter.getAttr.withArgs('tabindex').and.returnValue(null);
116+
foundation.init();
117+
118+
foundation.setDisabled(false);
119+
expect(mockAdapter.setAttr)
120+
.not.toHaveBeenCalledWith('tabindex', jasmine.any(String));
121+
expect(mockAdapter.setAttr)
122+
.not.toHaveBeenCalledWith('role', jasmine.any(String));
123+
});
124+
125+
it('#setAriaLabel updates the aria-label', () => {
126+
const {foundation, mockAdapter} = setupTest();
127+
const ariaLabel = 'Test label';
128+
foundation.init();
129+
130+
foundation.setAriaLabel(ariaLabel);
131+
expect(mockAdapter.setAttr).toHaveBeenCalledWith('aria-label', ariaLabel);
132+
});
133+
134+
it('#setContent updates the text content', () => {
135+
const {foundation, mockAdapter} = setupTest();
136+
const content = 'test';
137+
foundation.init();
138+
139+
foundation.setContent(content);
140+
expect(mockAdapter.setContent).toHaveBeenCalledWith(content);
141+
});
142+
143+
it('on click notifies custom icon event', () => {
144+
const {foundation, mockAdapter} = setupTest();
145+
const evt = {
146+
target: {},
147+
type: 'click',
148+
};
149+
let click;
150+
151+
mockAdapter.registerInteractionHandler
152+
.withArgs('click', jasmine.any(Function))
153+
.and.callFake((_evtType: string, handler: Function) => {
154+
click = handler;
155+
});
156+
157+
foundation.init();
158+
(click as unknown as Function)(evt);
159+
expect(mockAdapter.notifyIconAction).toHaveBeenCalled();
160+
});
161+
});

0 commit comments

Comments
 (0)