@nguyenmv2/buy-button
Version:
BuyButton.js allows merchants to build Shopify interfaces into any website
192 lines (153 loc) • 6.45 kB
JavaScript
import {trapFocus, removeTrapFocus} from '../../src/utils/focus';
describe('Focus utils', () => {
let node;
let firstEl;
let middleEl;
let lastEl;
beforeEach(() => {
node = document.createElement('div');
firstEl = document.createElement('button');
middleEl = document.createElement('input');
lastEl = document.createElement('select');
node.appendChild(firstEl);
node.appendChild(middleEl);
node.appendChild(lastEl);
document.body.appendChild(node);
});
afterEach(() => {
document.body.removeChild(node);
});
describe('trapFocus', () => {
it('focuses the first element', () => {
const focusSpy = sinon.spy();
firstEl.focus = focusSpy;
trapFocus(node);
assert.calledOnce(focusSpy);
});
describe('Focus events', () => {
let addEventListenerSpy;
let removeEventListenerSpy;
beforeEach(() => {
addEventListenerSpy = sinon.spy();
removeEventListenerSpy = sinon.spy();
node.addEventListener = addEventListenerSpy;
node.removeEventListener = removeEventListenerSpy;
trapFocus(node);
});
it('adds focusin and focusout event handlers', () => {
assert.calledTwice(addEventListenerSpy);
assert.calledWith(addEventListenerSpy.firstCall, 'focusout');
assert.calledWith(addEventListenerSpy.secondCall, 'focusin');
});
it('adds a keydown event listener if the focusin event handler is called on the first focusable element', () => {
const mockEvent = {
target: firstEl,
};
addEventListenerSpy.getCall(1).args[1](mockEvent);
assert.calledThrice(addEventListenerSpy);
assert.calledWith(addEventListenerSpy.thirdCall, 'keydown');
});
it('adds a keydown event listener if the focusin event handler is called on the last focusable element', () => {
const mockEvent = {
target: lastEl,
};
addEventListenerSpy.getCall(1).args[1](mockEvent);
assert.calledThrice(addEventListenerSpy);
assert.calledWith(addEventListenerSpy.thirdCall, 'keydown');
});
it('does not add a keydown event listener if the focusin event handler is called on a focusable element that is not first or last', () => {
const mockEvent = {
target: middleEl,
};
addEventListenerSpy.getCall(1).args[1](mockEvent);
assert.calledTwice(addEventListenerSpy);
});
it('removes the keydown event if the focusout event handle is called', () => {
removeEventListenerSpy.resetHistory();
addEventListenerSpy.getCall(0).args[1]();
assert.calledOnce(removeEventListenerSpy);
assert.calledWith(removeEventListenerSpy.firstCall, 'keydown');
});
});
describe('removeTrapFocus call', () => {
it('removes the focusin, focusout, and keydown event handlers from the node provided if they currently exist', () => {
trapFocus(node);
const removeEventListenerSpy = sinon.spy();
node.removeEventListener = removeEventListenerSpy;
trapFocus(node);
assert.calledThrice(removeEventListenerSpy);
assert.calledWith(removeEventListenerSpy.firstCall, 'focusin');
assert.calledWith(removeEventListenerSpy.secondCall, 'focusout');
assert.calledWith(removeEventListenerSpy.thirdCall, 'keydown');
});
});
describe('Keydown event', () => {
let addEventListenerSpy;
let preventDefaultSpy;
let focusinHandler;
let keydownHandler;
beforeEach(() => {
preventDefaultSpy = sinon.spy();
addEventListenerSpy = sinon.spy(node, 'addEventListener');
trapFocus(node);
focusinHandler = addEventListenerSpy.getCall(1).args[1];
});
describe('First element', () => {
beforeEach(() => {
focusinHandler({
target: firstEl,
});
keydownHandler = addEventListenerSpy.getCall(2).args[1];
});
it('focuses the last element if shift+tab is pressed when focused on the first element', () => {
const focusSpy = sinon.spy();
lastEl.focus = focusSpy;
keydownHandler({keyCode: 9, shiftKey: true, target: firstEl, preventDefault: preventDefaultSpy});
assert.calledOnce(focusSpy);
assert.calledOnce(preventDefaultSpy);
});
it('does not focus the last element if a non shift+tab key is pressed when focused on the first element', () => {
const focusSpy = sinon.spy();
lastEl.focus = focusSpy;
keydownHandler({keyCode: 10, shiftKey: true, target: firstEl, preventDefault: preventDefaultSpy});
assert.notCalled(focusSpy);
assert.notCalled(preventDefaultSpy);
});
});
describe('Last element', () => {
beforeEach(() => {
focusinHandler({
target: lastEl,
});
keydownHandler = addEventListenerSpy.getCall(2).args[1];
});
it('focuses the first element if tab is pressed when focused on the last element', () => {
const focusSpy = sinon.spy();
firstEl.focus = focusSpy;
keydownHandler({keyCode: 9, shiftKey: false, target: lastEl, preventDefault: preventDefaultSpy});
assert.calledOnce(focusSpy);
assert.calledOnce(preventDefaultSpy);
});
it('does not focus the first element if a non tab key is pressed when focused on the last element', () => {
const focusSpy = sinon.spy();
firstEl.focus = focusSpy;
keydownHandler({keyCode: 10, shiftKey: false, target: lastEl, preventDefault: preventDefaultSpy});
assert.notCalled(focusSpy);
assert.notCalled(preventDefaultSpy);
});
});
});
});
describe('removeTrapFocus', () => {
it('removes the focusin, focusout, and keydown event handlers from the node provided', () => {
trapFocus(node);
const removeEventListenerSpy = sinon.spy();
node.removeEventListener = removeEventListenerSpy;
removeTrapFocus(node);
assert.calledThrice(removeEventListenerSpy);
assert.calledWith(removeEventListenerSpy.firstCall, 'focusin');
assert.calledWith(removeEventListenerSpy.secondCall, 'focusout');
assert.calledWith(removeEventListenerSpy.thirdCall, 'keydown');
});
});
});