@@ -272,7 +356,7 @@ test('adapter.activateBottomLine and adapter.deactivateBottomLine ' +
});
-test('#adapter.isRtl returns true when the root element is in an RTL context' +
+test('adapter#isRtl returns true when the root element is in an RTL context' +
'and false otherwise', () => {
const wrapper = bel`
`;
const {fixture, component} = setupTest();
@@ -285,6 +369,42 @@ test('#adapter.isRtl returns true when the root element is in an RTL context' +
document.body.removeChild(wrapper);
});
+test('adapter#setDisabled sets the select to be disabled', () => {
+ const {component, nativeControl} = setupTest();
+ const adapter = component.getDefaultFoundation().adapter_;
+ assert.isFalse(nativeControl.disabled);
+ adapter.setDisabled(true);
+ assert.isTrue(nativeControl.disabled);
+ adapter.setDisabled(false);
+ assert.isFalse(nativeControl.disabled);
+});
+
+test('adapter#setSelectedIndex sets the select selected index to the index specified', () => {
+ const {component, nativeControl} = setupTest();
+ const adapter = component.getDefaultFoundation().adapter_;
+ adapter.setSelectedIndex(1);
+ assert.equal(nativeControl.selectedIndex, 1);
+ adapter.setSelectedIndex(2);
+ assert.equal(nativeControl.selectedIndex, 2);
+});
+
+test('adapter#notifyChange emits event with index and value', () => {
+ const {component, nativeControl} = setupTest();
+ nativeControl.options[0].selected = false;
+ nativeControl.options[1].selected = true;
+
+ let detail;
+ component.listen(strings.CHANGE_EVENT, (event) => {
+ detail = event.detail;
+ });
+
+ const value = nativeControl.options[1].value;
+ component.getDefaultFoundation().adapter_.notifyChange(value);
+ assert.isDefined(detail);
+ assert.equal(detail.index, 1);
+ assert.equal(detail.value, value);
+});
+
test('instantiates ripple', function() {
if (!supportsCssVariables(window, true)) {
this.skip(); // eslint-disable-line no-invalid-this
@@ -415,11 +535,24 @@ test('adapter#getLabelWidth returns 0 if the label does not exist', () => {
assert.equal(component.getDefaultFoundation().adapter_.getLabelWidth(), 0);
});
-test('change event triggers foundation.handleChange()', () => {
+test(`adapter#setValid applies ${cssClasses.INVALID} properly`, () => {
+ const hasOutline = false;
+ const hasLabel = true;
+ const {component, fixture} = setupTest(hasOutline, hasLabel);
+ const adapter = component.getDefaultFoundation().adapter_;
+
+ adapter.setValid(false);
+ assert.isTrue(fixture.classList.contains(cssClasses.INVALID));
+
+ adapter.setValid(true);
+ assert.isFalse(fixture.classList.contains(cssClasses.INVALID));
+});
+
+test('change event triggers foundation.handleChange(true)', () => {
const {component, nativeControl} = setupTest();
component.foundation_.handleChange = td.func();
domEvents.emit(nativeControl, 'change');
- td.verify(component.foundation_.handleChange(), {times: 1});
+ td.verify(component.foundation_.handleChange(true), {times: 1});
});
test('focus event triggers foundation.handleFocus()', () => {
@@ -441,7 +574,7 @@ test('#destroy removes the change handler', () => {
component.foundation_.handleChange = td.func();
component.destroy();
domEvents.emit(nativeControl, 'change');
- td.verify(component.foundation_.handleChange(), {times: 0});
+ td.verify(component.foundation_.handleChange(true), {times: 0});
});
test('#destroy removes the focus handler', () => {
@@ -498,3 +631,96 @@ test('#destroy removes the mousedown listener', () => {
td.verify(bottomLine.setRippleCenter(200), {times: 0});
});
+
+test('keydown is not added to the native select when initialized', () => {
+ const {component, fixture} = setupTest();
+ component.foundation_.handleKeydown = td.func();
+ document.body.appendChild(fixture);
+ domEvents.emit(fixture.querySelector('.mdc-select__native-control'), 'keydown');
+ td.verify(component.foundation_.handleKeydown(td.matchers.anything()), {times: 0});
+ document.body.removeChild(fixture);
+});
+
+test('#constructor instantiates a leading icon if an icon element is present', () => {
+ const root = getFixture();
+ const component = new MDCSelect(root);
+ assert.instanceOf(component.leadingIcon_, MDCSelectIcon);
+});
+
+test('#constructor instantiates the helper text if present', () => {
+ const hasLabel = true;
+ const hasOutline = false;
+ const hasHelperText = true;
+ const {container, component} = setupTest(hasLabel, hasOutline, hasHelperText);
+
+ assert.instanceOf(component.helperText_, FakeHelperText);
+ document.body.removeChild(container);
+});
+
+test('#constructor instantiates the helper text and passes the helper text foundation to MDCSelectFoundation', () => {
+ const root = getFixture();
+ const container = getHelperTextFixture(root);
+ document.body.appendChild(container);
+ const component = new MDCSelect(root);
+ assert.instanceOf(component.getDefaultFoundation().helperText_, MDCSelectHelperTextFoundation);
+ document.body.removeChild(container);
+});
+
+test('#constructor does not instantiate the helper text if the aria-controls id does not match an element', () => {
+ const containerDiv = getHelperTextFixture();
+ containerDiv.querySelector('.mdc-select-helper-text').id = 'hello-world';
+ document.body.appendChild(containerDiv);
+
+ const component = new MDCSelect(containerDiv.querySelector('.mdc-select'));
+
+ assert.isUndefined(component.helperText_);
+ document.body.removeChild(containerDiv);
+});
+
+test('#destroy destroys the helper text if it exists', () => {
+ const hasLabel = true;
+ const hasOutline = false;
+ const hasHelperText = true;
+ const {container, helperText, component} = setupTest(hasLabel, hasOutline, hasHelperText);
+
+ component.destroy();
+ td.verify(helperText.destroy(), {times: 1});
+ document.body.removeChild(container);
+});
+
+/* eslint-disable mocha/no-skipped-tests, max-len */
+// These are currently skipped due to rAF being improperly cleaned up somewhere in our tests
+test.skip(`MutationObserver adds ${cssClasses.REQUIRED} class to the parent when required attribute is added`, (done) => {
+ const hasLabel = true;
+ const hasOutline = false;
+ const hasHelperText = false;
+ const {fixture, nativeControl} = setupTest(hasLabel, hasOutline, hasHelperText);
+ assert.isFalse(fixture.classList.contains(cssClasses.REQUIRED));
+
+ nativeControl.setAttribute('required', 'true');
+
+ // MutationObservers are queued as microtasks and fire asynchronously
+ setTimeout(() => {
+ assert.isTrue(fixture.classList.contains(cssClasses.REQUIRED));
+ done();
+ }, 0);
+});
+
+test.skip(`MutationObserver removes ${cssClasses.REQUIRED} class from the parent when required attribute is removed`, (done) => {
+ const hasLabel = true;
+ const hasOutline = false;
+ const hasHelperText = false;
+ const {fixture, nativeControl} = setupTest(hasLabel, hasOutline, hasHelperText);
+
+ nativeControl.setAttribute('required', 'true');
+ setTimeout(() => {
+ assert.isTrue(fixture.classList.contains(cssClasses.REQUIRED));
+
+ fixture.querySelector(strings.NATIVE_CONTROL_SELECTOR).removeAttribute('required');
+ setTimeout(() => {
+ assert.isFalse(fixture.classList.contains(cssClasses.REQUIRED));
+ done();
+ }, 0);
+ }, 0);
+});
+/* eslint-enable mocha/no-skipped-tests, max-len */