@nguyenmv2/buy-button
Version:
BuyButton.js allows merchants to build Shopify interfaces into any website
305 lines (267 loc) • 9.12 kB
JavaScript
import Modal from '../../../src/components/modal';
import View from '../../../src/view';
import * as elementClass from '../../../src/utils/element-class';
import * as focusUtils from '../../../src/utils/focus';
describe('Modal View class', () => {
const props = {
browserFeatures: {},
};
const config = {
node: document.createElement('div'),
};
let modal;
beforeEach(() => {
modal = new Modal(config, props);
});
describe('wrapTemplate', () => {
it('wraps html in a div element with modal class, and wraps modal div within a div with overlay class', () => {
modal = Object.defineProperty(modal, 'classes', {
value: {
modal: {
overlay: 'overlay',
modal: 'modal',
},
},
});
const html = 'html';
const htmlString =
'<div class="overlay"><div class="modal">html</div></div>';
assert.equal(modal.view.wrapTemplate(html), htmlString);
});
});
describe('close', () => {
let removeClassFromElementStub;
let removeTrapFocusStub;
beforeEach(() => {
removeClassFromElementStub = sinon.stub(
elementClass,
'removeClassFromElement'
);
removeTrapFocusStub = sinon.stub(focusUtils, 'removeTrapFocus');
modal.view = Object.defineProperty(modal.view, 'document', {
value: document,
});
});
afterEach(() => {
removeClassFromElementStub.restore();
removeTrapFocusStub.restore();
});
it('sets the modal to not visible', () => {
modal.view.close();
assert.isFalse(modal.isVisible);
});
it('removes "is-active" class from wrapper and document body', () => {
modal.view.wrapper = document.createElement('div');
modal.view.close();
assert.calledWith(
removeClassFromElementStub.getCall(0),
'is-active',
modal.view.wrapper
);
assert.calledWith(
removeClassFromElementStub.getCall(1),
'is-active',
modal.view.document.body
);
});
it('removes "shopify-buy-modal-is-active" class from document body and html element', () => {
modal.view.close();
assert.calledWith(
removeClassFromElementStub.getCall(2),
'shopify-buy-modal-is-active',
document.body
);
assert.calledWith(
removeClassFromElementStub.getCall(3),
'shopify-buy-modal-is-active',
document.getElementsByTagName('html')[0]
);
});
it('removes "is-active" and "is-block" classes from node if iframe does not exist', () => {
modal.view.iframe = null;
modal.view.close();
assert.calledWith(
removeClassFromElementStub.getCall(4),
'is-active',
modal.node
);
assert.calledWith(
removeClassFromElementStub.getCall(5),
'is-block',
modal.node
);
});
it('calls removeTrapFocus with the wrapper', () => {
modal.view.close();
assert.calledOnce(removeTrapFocusStub);
assert.calledWith(removeTrapFocusStub.firstCall, modal.view.wrapper);
});
describe('removing wrapper click event', () => {
it('removes click event from wrapper if wrapper exists', () => {
const removeEventListenerSpy = sinon.spy();
modal.view.wrapper = {
removeEventListener: removeEventListenerSpy,
};
modal.view._closeOnBgClick = sinon.stub();
modal.view.close();
assert.calledOnce(removeEventListenerSpy);
assert.calledWith(removeEventListenerSpy, 'click', sinon.match.func);
});
it('does not remove click event from wrapper if no internal click event is set', () => {
const removeEventListenerSpy = sinon.spy();
modal.view.wrapper = {
removeEventListener: removeEventListenerSpy,
};
modal.view.close();
assert.notCalled(removeEventListenerSpy);
});
});
describe('when iframe exists', () => {
let removeClassSpy;
let addEventListenerSpy;
beforeEach(() => {
removeClassSpy = sinon.spy();
addEventListenerSpy = sinon.spy();
modal.view.iframe = {
removeClass: removeClassSpy,
parent: {
addEventListener: addEventListenerSpy,
},
};
});
it('removes "is-block" class from iframe', () => {
modal.view.close();
assert.calledWith(removeClassSpy.getCall(0), 'is-block');
});
it('adds a transitionend event listener to remove "is-active" class on iframe if browser supports transition', () => {
modal.props.browserFeatures.transition = true;
modal.view.close();
assert.calledOnce(addEventListenerSpy);
assert.calledWith(
addEventListenerSpy,
'transitionend',
sinon.match.func
);
addEventListenerSpy.getCall(0).args[1]();
assert.calledWith(removeClassSpy.getCall(1), 'is-active');
});
it('removes "is-active" class from iframe if browser does not support transition', () => {
modal.props.browserFeatures.transition = false;
modal.view.close();
assert.notCalled(addEventListenerSpy);
assert.calledWith(removeClassSpy.getCall(1), 'is-active');
});
});
});
describe('delegateEvents', () => {
let superDelegateEventsStub;
let addEventListenerSpy;
let closeOnBgClickStub;
beforeEach(() => {
superDelegateEventsStub = sinon.stub(View.prototype, 'delegateEvents');
addEventListenerSpy = sinon.spy();
modal.view.wrapper = {
addEventListener: addEventListenerSpy,
};
closeOnBgClickStub = sinon.stub(modal, 'closeOnBgClick');
modal.view.delegateEvents();
});
afterEach(() => {
superDelegateEventsStub.restore();
closeOnBgClickStub.restore();
});
it('calls super delegateEvents()', () => {
assert.calledOnce(superDelegateEventsStub);
});
it('adds click event listener to wrapper that closes on bg click', () => {
assert.calledOnce(addEventListenerSpy);
assert.calledWith(addEventListenerSpy, 'click', sinon.match.func);
addEventListenerSpy.getCall(0).args[1]();
assert.calledOnce(closeOnBgClickStub);
});
it('sets a local copy of closeOnBgClick function', () => {
assert.isFunction(modal.view._closeOnBgClick);
});
});
describe('render', () => {
let superRenderStub;
let addClassToElementStub;
beforeEach(() => {
superRenderStub = sinon.stub(View.prototype, 'render');
addClassToElementStub = sinon.stub(elementClass, 'addClassToElement');
});
afterEach(() => {
superRenderStub.restore();
addClassToElementStub.restore();
});
it('does not render or add classes if component is not visible', () => {
modal.isVisible = false;
modal.view.render();
assert.notCalled(superRenderStub);
assert.notCalled(addClassToElementStub);
});
describe('when component is visible', () => {
beforeEach(() => {
modal.isVisible = true;
modal.view = Object.defineProperty(modal.view, 'document', {
value: document,
});
});
it('calls super render()', () => {
modal.view.render();
assert.calledOnce(superRenderStub);
});
it('adds "is-active" class to document body and wrapper', () => {
modal.view.wrapper = document.createElement('div');
modal.view.render();
assert.calledWith(
addClassToElementStub.getCall(0),
'is-active',
modal.view.document.body
);
assert.calledWith(
addClassToElementStub.getCall(3),
'is-active',
modal.view.wrapper
);
});
it('adds "shopify-buy-modal-is-active" class to document body and html element', () => {
modal.view.render();
assert.calledWith(
addClassToElementStub.getCall(1),
'shopify-buy-modal-is-active',
document.body
);
assert.calledWith(
addClassToElementStub.getCall(2),
'shopify-buy-modal-is-active',
document.getElementsByTagName('html')[0]
);
});
it('adds "is-active" and "is-block" classes to iframe if iframe exists', () => {
const addClassSpy = sinon.spy();
modal.view.iframe = {
addClass: addClassSpy,
};
modal.view.render();
assert.calledTwice(addClassSpy);
assert.calledWith(addClassSpy.getCall(0), 'is-active');
assert.calledWith(addClassSpy.getCall(1), 'is-block');
});
it('adds "is-active" and "is-block" classes to node if iframe does not exist', () => {
modal.view.iframe = null;
modal.view.render();
assert.calledWith(
addClassToElementStub.getCall(4),
'is-active',
modal.node
);
assert.calledWith(
addClassToElementStub.getCall(5),
'is-block',
modal.node
);
});
});
});
});