* Update value with character value

* Remove .only

* Lowercase character before updating value

* Add cypress tests covering change

* Update logic to affect both select inputs

* Update cypress

* Emphasise remove button focus

* Text change

* Revert "Update cypress"

This reverts commit 81e406de85.

* Remove false positive tests
This commit is contained in:
Josh Johnson 2019-11-22 19:09:45 +00:00 committed by GitHub
parent 85f0b5f9be
commit 67266a3aae
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 176 additions and 40 deletions

View file

@ -5,13 +5,6 @@ describe('Choices - select one', () => {
describe('scenarios', () => {
describe('basic', () => {
beforeEach(() => {
// open dropdown
cy.get('[data-test-hook=basic]')
.find('.choices')
.click();
});
describe('focusing on container', () => {
describe('pressing enter key', () => {
it('toggles the dropdown', () => {
@ -22,7 +15,7 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('not.be.visible');
.should('be.visible');
cy.get('[data-test-hook=basic]')
.find('.choices')
@ -31,42 +24,38 @@ describe('Choices - select one', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible');
.should('not.be.visible');
});
});
});
describe('focusing on text input', () => {
it('displays a dropdown of choices', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('be.visible');
describe('pressing an alpha-numeric key', () => {
it('opens the dropdown and the input value', () => {
const inputValue = 'test';
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown .choices__list')
.children()
.should('have.length', 4)
.each(($choice, index) => {
expect($choice.text().trim()).to.equal(`Choice ${index + 1}`);
});
});
describe('pressing escape', () => {
beforeEach(() => {
cy.get('[data-test-hook=basic]')
.find('.choices__input--cloned')
.type('{esc}');
});
.find('.choices')
.focus()
.type(inputValue);
it('closes the dropdown', () => {
cy.get('[data-test-hook=basic]')
.find('.choices__list--dropdown')
.should('not.be.visible');
.should('be.visible');
cy.get('[data-test-hook=basic]')
.find('.choices__input--cloned')
.should('have.value', inputValue);
});
});
});
describe('selecting choices', () => {
beforeEach(() => {
// open dropdown
cy.get('[data-test-hook=basic]')
.find('.choices')
.click();
});
const selectedChoiceText = 'Choice 1';
it('allows selecting choices from dropdown', () => {
@ -102,6 +91,13 @@ describe('Choices - select one', () => {
});
describe('searching choices', () => {
beforeEach(() => {
// open dropdown
cy.get('[data-test-hook=basic]')
.find('.choices')
.click();
});
describe('on input', () => {
describe('searching by label', () => {
it('displays choices filtered by inputted value', () => {

View file

@ -61,7 +61,7 @@
height: 20px;
width: 20px;
border-radius: 10em;
opacity: 0.5;
opacity: 0.25;
}
.choices[data-type*='select-one'] .choices__button:hover, .choices[data-type*='select-one'] .choices__button:focus {

File diff suppressed because one or more lines are too long

View file

@ -1327,6 +1327,7 @@ class Choices {
const hasActiveDropdown = this.dropdown.isActive;
const hasItems = this.itemList.hasChildren();
const keyString = String.fromCharCode(keyCode);
const wasAlphaNumericChar = /[a-zA-Z0-9-_ ]/.test(keyString);
const {
BACK_KEY,
@ -1340,9 +1341,17 @@ class Choices {
PAGE_DOWN_KEY,
} = KEY_CODES;
// If a user is typing and the dropdown is not active
if (!this._isTextElement && /[a-zA-Z0-9-_ ]/.test(keyString)) {
if (!this._isTextElement && !hasActiveDropdown && wasAlphaNumericChar) {
this.showDropdown();
if (!this.input.isFocussed) {
/*
We update the input value with the pressed key as
the input was not focussed at the time of key press
therefore does not have the value of the key.
*/
this.input.value += keyString.toLowerCase();
}
}
// Map keys to key actions
@ -1358,7 +1367,6 @@ class Choices {
[BACK_KEY]: this._onDeleteKey,
};
// If keycode has a function, run it
if (keyDownActions[keyCode]) {
keyDownActions[keyCode]({
event,
@ -1380,6 +1388,7 @@ class Choices {
// notice. Otherwise hide the dropdown
if (this._isTextElement) {
const canShowDropdownNotice = canAddItem.notice && value;
if (canShowDropdownNotice) {
const dropdownItem = this._getTemplate('notice', canAddItem.notice);
this.dropdown.element.innerHTML = dropdownItem.outerHTML;
@ -1388,8 +1397,8 @@ class Choices {
this.hideDropdown(true);
}
} else {
const userHasRemovedValue =
(keyCode === backKey || keyCode === deleteKey) && !target.value;
const wasRemovalKeyCode = keyCode === backKey || keyCode === deleteKey;
const userHasRemovedValue = wasRemovalKeyCode && !target.value;
const canReactivateChoices = !this._isTextElement && this._isSearching;
const canSearch = this._canSearch && canAddItem.response;
@ -1407,6 +1416,7 @@ class Choices {
_onAKey({ event, hasItems }) {
const { ctrlKey, metaKey } = event;
const hasCtrlDownKeyPressed = ctrlKey || metaKey;
// If CTRL + A or CMD + A have been pressed and there are items to select
if (hasCtrlDownKeyPressed && hasItems) {
this._canSearch = false;

View file

@ -3,7 +3,7 @@ import { spy, stub } from 'sinon';
import sinonChai from 'sinon-chai';
import Choices from './choices';
import { EVENTS, ACTION_TYPES, DEFAULT_CONFIG } from './constants';
import { EVENTS, ACTION_TYPES, DEFAULT_CONFIG, KEY_CODES } from './constants';
import { WrappedSelect, WrappedInput } from './components/index';
chai.use(sinonChai);
@ -2025,5 +2025,135 @@ describe('choices', () => {
});
});
});
describe('_onKeyDown', () => {
beforeEach(() => {
instance.showDropdown = stub();
instance._onAKey = stub();
instance._onEnterKey = stub();
instance._onEscapeKey = stub();
instance._onDirectionKey = stub();
instance._onDeleteKey = stub();
});
const scenarios = [
{
keyCode: KEY_CODES.BACK_KEY,
expectedFunctionCall: '_onDeleteKey',
},
{
keyCode: KEY_CODES.DELETE_KEY,
expectedFunctionCall: '_onDeleteKey',
},
{
keyCode: KEY_CODES.A_KEY,
expectedFunctionCall: '_onAKey',
},
{
keyCode: KEY_CODES.ENTER_KEY,
expectedFunctionCall: '_onEnterKey',
},
{
keyCode: KEY_CODES.UP_KEY,
expectedFunctionCall: '_onDirectionKey',
},
{
keyCode: KEY_CODES.DOWN_KEY,
expectedFunctionCall: '_onDirectionKey',
},
{
keyCode: KEY_CODES.DOWN_KEY,
expectedFunctionCall: '_onDirectionKey',
},
{
keyCode: KEY_CODES.ESC_KEY,
expectedFunctionCall: '_onEscapeKey',
},
];
describe('when called with a keydown event', () => {
scenarios.forEach(({ keyCode, expectedFunctionCall }) => {
describe(`when the keyCode is ${keyCode}`, () => {
it(`calls ${expectedFunctionCall} with the expected arguments`, () => {
const mockEvent = {
keyCode,
};
instance._onKeyDown(mockEvent);
expect(instance[expectedFunctionCall]).to.have.been.calledWith({
event: mockEvent,
activeItems: instance._store.activeItems,
hasActiveDropdown: instance.dropdown.isActive,
hasFocusedInput: instance.input.isFocussed,
hasItems: instance.itemList.hasChildren(),
});
});
});
});
describe('select input', () => {
describe('when the dropdown is not active', () => {
describe('when the key was alpha-numeric', () => {
beforeEach(() => {
instance._isTextElement = false;
instance.dropdown.isActive = false;
});
it('shows the dropdown', () => {
instance._onKeyDown({
keyCode: KEY_CODES.A_KEY,
});
expect(instance.showDropdown).to.have.been.calledWith();
});
describe('when the input is not focussed', () => {
beforeEach(() => {
instance.input.isFocussed = false;
});
it('updates the input value with the character corresponding to the key code', () => {
instance._onKeyDown({
keyCode: KEY_CODES.A_KEY,
});
expect(instance.input.value).to.contain('a');
});
});
describe('when the input is focussed', () => {
beforeEach(() => {
instance.input.isFocussed = true;
});
it('does not update the input value', () => {
instance._onKeyDown({
keyCode: KEY_CODES.A_KEY,
});
expect(instance.input.value).to.not.contain('a');
});
});
});
describe('when the input was not alpha-numeric', () => {
beforeEach(() => {
instance._isTextElement = false;
instance.dropdown.isActive = false;
});
it('does not show the dropdown', () => {
instance._onKeyDown({
keyCode: KEY_CODES.DELETE_KEY,
});
expect(instance.showDropdown).to.not.have.been.called;
});
});
});
});
});
});
});
});

View file

@ -74,7 +74,7 @@ $choices-icon-cross-inverse: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMjEiI
height: 20px;
width: 20px;
border-radius: 10em;
opacity: 0.5;
opacity: 0.25;
&:hover,
&:focus {
opacity: 1;