@nguyenmv2/buy-button
Version:
BuyButton.js allows merchants to build Shopify interfaces into any website
1,017 lines (863 loc) • 33.8 kB
JavaScript
import ShopifyBuy from '../../src/buybutton';
import UI from '../../src/ui';
import Product from '../../src/components/product';
import Modal from '../../src/components/modal';
import Tracker from '../../src/utils/track';
import ProductSet from '../../src/components/product-set';
import Cart from '../../src/components/cart';
import CartToggle from '../../src/components/toggle';
import * as browserFeatures from '../../src/utils/detect-features';
import * as throttle from '../../src/utils/throttle';
import hostStyles from '../../src/styles/host/host';
import conditionalStyles from '../../src/styles/host/conditional';
import shopFixture from '../fixtures/shop-info';
const DATA_ATTRIBUTE = 'data-shopify-buy-ui';
const config = {
domain: 'buckets-o-stuff.myshopify.com',
storefrontAccessToken: 123,
};
describe('ui class', () => {
let ui;
let script;
let client;
let integrations;
let notifyExceptionSpy;
beforeEach(() => {
notifyExceptionSpy = sinon.spy();
integrations = {
errorReporter: {notifyException: notifyExceptionSpy},
tracker: 'test',
};
client = ShopifyBuy.buildClient(config);
client.config.domain = 'test-domain.myshopify.com';
sinon.stub(client.shop, 'fetchInfo').resolves(shopFixture);
script = document.createElement('script');
script.setAttribute(DATA_ATTRIBUTE, true);
document.body.appendChild(script);
});
afterEach(() => {
document.body.removeChild(script);
});
describe('constructor', () => {
let resizeStub;
let hostClickStub;
let escStub;
let postMessageStub;
let trackPageviewStub;
let appendStyleTagStub;
beforeEach(() => {
resizeStub = sinon.stub(UI.prototype, '_bindResize');
hostClickStub = sinon.stub(UI.prototype, '_bindHostClick');
escStub = sinon.stub(UI.prototype, '_bindEsc');
postMessageStub = sinon.stub(UI.prototype, '_bindPostMessage');
trackPageviewStub = sinon.stub(Tracker.prototype, 'trackPageview');
appendStyleTagStub = sinon.stub(UI.prototype, '_appendStyleTag');
ui = new UI(client, integrations, 'test');
});
afterEach(() => {
resizeStub.restore();
hostClickStub.restore();
escStub.restore();
postMessageStub.restore();
trackPageviewStub.restore();
appendStyleTagStub.restore();
ui = null;
});
it('sets client and domain from client and client.config.domain params', () => {
assert.equal(ui.client, client);
assert.equal(ui.config.domain, client.config.domain);
});
it('creates an empty array for iframeComponents', () => {
assert.deepEqual(ui.iframeComponents, []);
});
it('creates a components object holding empty arrays for product, cart, collection, productSet, modal, and toggle', () => {
const expectedComponentsObj = {
product: [],
cart: [],
collection: [],
productSet: [],
modal: [],
toggle: [],
};
assert.deepEqual(ui.components, expectedComponentsObj);
});
it('creates a componentTypes object for product, cart, collection, productSet, modal, toggle', () => {
const componentTypes = {
product: Product,
cart: Cart,
collection: ProductSet,
productSet: ProductSet,
toggle: CartToggle,
};
assert.deepEqual(ui.componentTypes, componentTypes);
});
it('sets an errorReporter from integrations param', () => {
assert.equal(ui.errorReporter, integrations.errorReporter);
});
it('creates a tracker instance', () => {
assert.instanceOf(ui.tracker, Tracker);
});
it('sets stylesOverrides from params', () => {
assert.equal(ui.styleOverrides, 'test');
});
it('calls tracker.trackPageview()', () => {
assert.calledOnce(trackPageviewStub);
});
it('sets activeEl to null', () => {
assert.equal(ui.activeEl, null);
});
it('calls _appendStyleTag()', () => {
assert.calledOnce(appendStyleTagStub);
});
it('calls private event binding methods', () => {
assert.calledOnce(resizeStub);
assert.calledOnce(hostClickStub);
assert.calledOnce(escStub);
assert.calledWith(escStub, window);
assert.calledOnce(postMessageStub);
});
});
describe('prototype methods', () => {
beforeEach(() => {
ui = new UI(client, integrations);
});
describe('component methods', () => {
describe('createComponent()', () => {
const productConfig = {
id: 123,
options: {},
node: 'test',
};
describe('successful component initialization', () => {
let initStub;
let trackStub;
let queryEntryNodeStub;
beforeEach(() => {
initStub = sinon.stub(Product.prototype, 'init').resolves();
trackStub = sinon.stub(ui, 'trackComponent');
queryEntryNodeStub = sinon.stub(ui, '_queryEntryNode').returns('testNode');
});
afterEach(() => {
initStub.restore();
trackStub.restore();
queryEntryNodeStub.restore();
ui.components.product = [];
});
it('creates new component of type with tracker attached', async () => {
await ui.createComponent('product', productConfig);
assert.equal(1, ui.components.product.length);
assert.instanceOf(ui.components.product[0], Product);
assert.calledOnce(initStub);
assert.calledOnce(trackStub);
assert.equal(trackStub.getCall(0).args[0], 'product');
assert.instanceOf(trackStub.getCall(0).args[1], Product);
});
it('grabs node from _queryEntryNode() if no node is passed in from config', async () => {
productConfig.node = null;
await ui.createComponent('product', productConfig);
assert.calledOnce(queryEntryNodeStub);
assert.equal(productConfig.node, 'testNode');
});
it('returns the component', async () => {
const response = await ui.createComponent('product', productConfig);
assert.instanceOf(response, Product);
});
});
describe('unsuccessful component initialization', () => {
let errorInitStub;
let consoleErrorStub;
const error = {errors: [{message: 'rejected.'}]};
beforeEach(() => {
errorInitStub = sinon.stub(Product.prototype, 'init').rejects(error);
consoleErrorStub = sinon.stub(console, 'error');
});
afterEach(() => {
errorInitStub.restore();
consoleErrorStub.restore();
});
it('catches any error from initialization and notifies errorReporter if it exists', async () => {
await ui.createComponent('product', productConfig);
assert.throws(ui.createComponent, Error);
assert.calledOnce(notifyExceptionSpy);
assert.calledWith(notifyExceptionSpy, error);
});
it('errors out the console with the error', async () => {
await ui.createComponent('product', productConfig);
assert.throws(ui.createComponent, Error);
assert.calledOnce(consoleErrorStub);
assert.calledWith(consoleErrorStub, error);
});
});
});
describe('destroyComponent()', () => {
let destroySpy;
let testCart;
beforeEach(() => {
destroySpy = sinon.spy();
testCart = {
model: {
id: 123,
},
destroy: destroySpy,
};
});
it('destroys component and removes component from components array if the id param matches with the component model\'s id', () => {
ui.components.cart.push(testCart);
assert.equal(ui.components.cart[0].model.id, 123);
ui.destroyComponent('cart', 123);
assert.equal(0, ui.components.cart.length);
assert.calledOnce(destroySpy);
});
});
describe('trackComponent()', () => {
let trackComponentStub;
beforeEach(() => {
trackComponentStub = sinon.stub(Tracker.prototype, 'trackComponent');
});
afterEach(() => {
trackComponentStub.restore();
});
it('tracks each product in set if the component is a productSet', () => {
const productSet = {
trackingInfo: [1, 2, 3],
};
ui.trackComponent('productSet', productSet);
assert.callCount(trackComponentStub, 3);
assert.calledWith(trackComponentStub.getCall(0), 'product', 1);
assert.calledWith(trackComponentStub.getCall(1), 'product', 2);
assert.calledWith(trackComponentStub.getCall(2), 'product', 3);
});
it('tracks component with the given component type if the component is not a productSet', () => {
const component = {
trackingInfo: 'test',
};
ui.trackComponent('testType', component);
assert.calledOnce(trackComponentStub);
assert.calledWith(trackComponentStub, 'testType', 'test');
});
});
});
describe('cart methods', () => {
afterEach(() => {
ui.components.cart = [];
});
describe('createCart()', () => {
let initStub;
let appendChildStub;
beforeEach(() => {
initStub = sinon.stub(Cart.prototype, 'init').resolves('test');
appendChildStub = sinon.stub(document.body, 'appendChild').returns({
parentNode: {
insertBefore: sinon.spy(),
removeChild: sinon.spy(),
},
});
});
afterEach(() => {
initStub.restore();
appendChildStub.restore();
});
describe('when no cart exists', () => {
it('creates a new cart', async () => {
await ui.createCart({options: {}});
assert.equal(1, ui.components.cart.length);
assert.instanceOf(ui.components.cart[0], Cart);
assert.calledOnce(initStub);
});
it('returns the init value', async () => {
const response = await ui.createCart({options: {}});
assert.equal(response, 'test');
});
});
describe('when a cart exists', () => {
let createTogglesStub;
beforeEach(() => {
createTogglesStub = sinon.stub().resolves();
ui.components.cart = [{
toggles: [1, 2],
createToggles: createTogglesStub,
}];
});
it('does not create a second cart', async () => {
await ui.createCart({options: {}});
assert.equal(1, ui.components.cart.length);
assert.notCalled(initStub);
});
it('creates toggles for the first cart if the first cart has less toggles than the config', async () => {
const createCartConfig = {toggles: [1, 2, 3]};
await ui.createCart(createCartConfig);
assert.calledOnce(createTogglesStub);
assert.calledWith(createTogglesStub, createCartConfig);
});
it('does not create toggles for the first cart if the first cart has an equal amount of toggles to the config', async () => {
await ui.createCart({toggles: [1, 2]});
assert.notCalled(createTogglesStub);
});
it('does not create toggles for the first cart if the first cart has more toggles than the config', async () => {
await ui.createCart({toggles: [1]});
assert.notCalled(createTogglesStub);
});
it('returns the first cart', async () => {
const createCartConfig = {toggles: [1, 2, 3]};
const response = await ui.createCart(createCartConfig);
assert.equal(response, ui.components.cart[0]);
});
});
});
describe('closeCart()', () => {
it('closes every visible cart and restores focus after each close', () => {
const closeSpy1 = sinon.spy();
const closeSpy2 = sinon.spy();
const closeSpy3 = sinon.spy();
const restoreFocusStub = sinon.stub(ui, 'restoreFocus');
ui.components.cart = [
{isVisible: true, close: closeSpy1},
{isVisible: true, close: closeSpy2},
{isVisible: false, close: closeSpy3},
];
ui.closeCart();
assert.calledOnce(closeSpy1);
assert.calledOnce(closeSpy2);
assert.notCalled(closeSpy3);
assert.callCount(restoreFocusStub, 2);
restoreFocusStub.restore();
});
});
describe('openCart()', () => {
it('opens every cart', () => {
const openSpy1 = sinon.spy();
const openSpy2 = sinon.spy();
const openSpy3 = sinon.spy();
const openSpy4 = sinon.spy();
ui.components.cart = [
{isVisible: true, open: openSpy1},
{isVisible: true, open: openSpy2},
{isVisible: false, open: openSpy3},
{isVisible: false, open: openSpy4},
];
ui.openCart();
assert.calledOnce(openSpy1);
assert.calledOnce(openSpy2);
assert.calledOnce(openSpy3);
assert.calledOnce(openSpy4);
});
});
describe('toggleCart()', () => {
it('toggles visibility of every cart to visibility param', () => {
const toggleSpy1 = sinon.spy();
const toggleSpy2 = sinon.spy();
const toggleSpy3 = sinon.spy();
ui.components.cart = [
{toggleVisibility: toggleSpy1},
{toggleVisibility: toggleSpy2},
{toggleVisibility: toggleSpy3},
];
ui.toggleCart(true);
assert.calledOnce(toggleSpy1);
assert.calledWith(toggleSpy1, true);
assert.calledOnce(toggleSpy2);
assert.calledWith(toggleSpy2, true);
assert.calledOnce(toggleSpy3);
assert.calledWith(toggleSpy3, true);
});
it('restores focus only if visibility param is false', () => {
const restoreFocusStub = sinon.stub(ui, 'restoreFocus');
ui.toggleCart(true);
assert.notCalled(restoreFocusStub);
ui.toggleCart(false);
assert.calledOnce(restoreFocusStub);
restoreFocusStub.restore();
});
});
});
describe('modal methods', () => {
afterEach(() => {
ui.components.modal = [];
});
describe('createModal()', () => {
let appendChildStub;
beforeEach(() => {
appendChildStub = sinon.stub(document.body, 'appendChild').returns({
parentNode: {
insertBefore: sinon.spy(),
removeChild: sinon.spy(),
},
});
});
afterEach(() => {
appendChildStub.restore();
});
it('creates and returns a new modal if one does not already exist', () => {
const modal = ui.createModal({options: {}});
assert.equal(1, ui.components.modal.length);
assert.instanceOf(ui.components.modal[0], Modal);
assert.instanceOf(modal, Modal);
});
it('does not create a modal and returns first modal if it already exists', () => {
ui.components.modal = [{options: {}}];
const modal = ui.createModal({options: {}});
assert.equal(1, ui.components.modal.length);
assert.equal(modal, ui.components.modal[0]);
});
});
describe('closeModal()', () => {
let restoreFocusStub;
beforeEach(() => {
restoreFocusStub = sinon.stub(ui, 'restoreFocus');
});
afterEach(() => {
restoreFocusStub.restore();
});
it('closes every modal then restores focus once all is done', () => {
const closeSpy1 = sinon.spy();
const closeSpy2 = sinon.spy();
const closeSpy3 = sinon.spy();
ui.components.modal = [
{close: closeSpy1},
{close: closeSpy2},
{close: closeSpy3},
];
ui.closeModal();
assert.calledOnce(closeSpy1);
assert.calledOnce(closeSpy2);
assert.calledOnce(closeSpy3);
assert.calledOnce(restoreFocusStub);
});
it('does not restore focus if there are no modals', () => {
ui.components.modal = [];
ui.closeModal();
assert.notCalled(restoreFocusStub);
});
});
});
describe('setActiveEl()', () => {
it('sets activeEl to element param', () => {
ui.setActiveEl('test');
assert.equal(ui.activeEl, 'test');
});
});
describe('restoreFocus()', () => {
let focusSpy;
beforeEach(() => {
focusSpy = sinon.spy();
ui.activeEl = {focus: focusSpy};
ui = Object.defineProperty(ui, 'modalOpen', {
writable: true,
});
ui = Object.defineProperty(ui, 'cartOpen', {
writable: true,
});
});
it('focuses on activeEl if activeEl exists and both modal and cart are closed', () => {
ui.modalOpen = false;
ui.cartOpen = false;
ui.restoreFocus();
assert.calledOnce(focusSpy);
});
it('does not focus on activeEl if modal is open', () => {
ui.modalOpen = true;
ui.cartOpen = false;
ui.restoreFocus();
assert.notCalled(focusSpy);
});
it('does not focus on activeEl if cart is open', () => {
ui.modalOpen = false;
ui.cartOpen = true;
ui.restoreFocus();
assert.notCalled(focusSpy);
});
});
describe('getters', () => {
describe('modalOpen', () => {
afterEach(() => {
ui.components.modal = [];
});
it('returns true if at least one modal is visible', () => {
ui.components.modal = [
{isVisible: false},
{isVisible: false},
{isVisible: true},
];
assert.equal(ui.modalOpen, true);
});
it('returns false if all modals are not visible', () => {
ui.components.modal = [
{isVisible: false},
{isVisible: false},
{isVisible: false},
];
assert.equal(ui.modalOpen, false);
});
});
describe('cartOpen', () => {
afterEach(() => {
ui.components.cart = [];
});
it('returns true if at least one cart is visible', () => {
ui.components.cart = [
{isVisible: false},
{isVisible: false},
{isVisible: true},
];
assert.equal(ui.cartOpen, true);
});
it('returns false if all carts are not visible', () => {
ui.components.cart = [
{isVisible: false},
{isVisible: false},
{isVisible: false},
];
assert.equal(ui.cartOpen, false);
});
});
describe('componentProps', () => {
it('contains the client', () => {
assert.equal(ui.componentProps.client, ui.client);
});
it('contains createCart()', () => {
const createCartStub = sinon.stub(ui, 'createCart');
ui.componentProps.createCart();
assert.calledOnce(createCartStub);
createCartStub.restore();
});
it('contains closeCart()', () => {
const closeCartStub = sinon.stub(ui, 'closeCart');
ui.componentProps.closeCart();
assert.calledOnce(closeCartStub);
closeCartStub.restore();
});
it('contains toggleCart()', () => {
const toggleCartStub = sinon.stub(ui, 'toggleCart');
ui.componentProps.toggleCart();
assert.calledOnce(toggleCartStub);
toggleCartStub.restore();
});
it('contains createModal()', () => {
const createModalStub = sinon.stub(ui, 'createModal');
ui.componentProps.createModal();
assert.calledOnce(createModalStub);
createModalStub.restore();
});
it('contains closeModal()', () => {
const closeModalStub = sinon.stub(ui, 'closeModal');
ui.componentProps.closeModal();
assert.calledOnce(closeModalStub);
closeModalStub.restore();
});
it('contains setActiveEl()', () => {
const setActiveElStub = sinon.stub(ui, 'setActiveEl');
ui.componentProps.setActiveEl();
assert.calledOnce(setActiveElStub);
setActiveElStub.restore();
});
it('contains destroyComponent()', () => {
const destroyComponentStub = sinon.stub(ui, 'destroyComponent');
ui.componentProps.destroyComponent();
assert.calledOnce(destroyComponentStub);
destroyComponentStub.restore();
});
it('contains tracker', () => {
assert.equal(ui.componentProps.tracker, ui.tracker);
});
it('contains error reporter', () => {
assert.equal(ui.componentProps.errorReporter, ui.errorReporter);
});
it('contains browser features', () => {
assert.equal(ui.componentProps.browserFeatures, browserFeatures.default);
});
});
describe('styleText', () => {
let browserFeaturesStub;
afterEach(() => {
browserFeaturesStub.restore();
});
it('returns string of CSS with host styles and style overrides if browser features include transition, transform, and animation', () => {
browserFeaturesStub = sinon.stub(browserFeatures, 'default').value({
transition: true,
transform: true,
animation: true,
});
assert.equal(ui.styleText, hostStyles + ui.styleOverrides);
});
describe('missing browser features', () => {
let expectedString;
beforeEach(() => {
expectedString = hostStyles + conditionalStyles + ui.styleOverrides;
});
it('returns string of CSS with host styles, conditional styles, and style overrides if browser features does not have transition', () => {
browserFeaturesStub = sinon.stub(browserFeatures, 'default').value({
transition: false,
transform: true,
animation: true,
});
assert.equal(ui.styleText, expectedString);
});
it('returns string of CSS with host styles, conditional styles, and style overrides if browser features does not have transform', () => {
browserFeaturesStub = sinon.stub(browserFeatures, 'default').value({
transition: true,
transform: false,
animation: true,
});
assert.equal(ui.styleText, expectedString);
});
it('returns string of CSS with host styles, conditional styles, and style overrides if browser features does not have animation', () => {
browserFeaturesStub = sinon.stub(browserFeatures, 'default').value({
transition: true,
transform: true,
animation: false,
});
assert.equal(ui.styleText, expectedString);
});
});
});
});
describe('"private" methods', () => {
describe('_queryEntryNode', () => {
let appendToBodyStub;
let createElementStub;
const div = document.createElement('div');
beforeEach(() => {
appendToBodyStub = sinon.stub(ui, '_appendToBody');
createElementStub = sinon.stub(document, 'createElement').returns(div);
});
afterEach(() => {
appendToBodyStub.restore();
createElementStub.restore();
});
it('sets entry to data-shopify-buy-ui script if entry does not exist', () => {
ui.entry = null;
ui._queryEntryNode();
assert.equal(ui.entry, script);
});
it('appends to body if the entry\'s parent node is head', () => {
ui.entry = {
parentNode: {
tagName: 'HEAD',
},
};
ui._queryEntryNode();
assert.calledOnce(appendToBodyStub);
assert.calledWith(appendToBodyStub, div);
});
it('appends to body if the entry\'s parent node is HTML', () => {
ui.entry = {
parentNode: {
tagName: 'HTML',
},
};
ui._queryEntryNode();
assert.calledOnce(appendToBodyStub);
assert.calledWith(appendToBodyStub, div);
});
it('appends to body if there is no entry', () => {
const querySelectorAllStub = sinon.stub(window.document, 'querySelectorAll').returns([null]);
ui.entry = null;
ui._queryEntryNode();
assert.calledOnce(appendToBodyStub);
assert.calledWith(appendToBodyStub, div);
querySelectorAllStub.restore();
});
it('appends to body, removes attribute from entry then calls insertBefore on parentNode if entry\'s parent node is not head or html', () => {
const insertBeforeSpy = sinon.spy();
const removeAttributeSpy = sinon.spy();
ui.entry = {
parentNode: {
tagName: 'not HEAD or HTML',
insertBefore: insertBeforeSpy,
},
removeAttribute: removeAttributeSpy,
};
ui._queryEntryNode();
assert.calledOnce(removeAttributeSpy);
assert.calledWith(removeAttributeSpy, DATA_ATTRIBUTE);
assert.calledOnce(insertBeforeSpy);
assert.calledWith(insertBeforeSpy, div, ui.entry);
});
it('returns the created div', () => {
assert.equal(ui._queryEntryNode(), div);
});
});
describe('_appendToBody', () => {
it('appends element to body', () => {
const appendChildStub = sinon.stub(document.body, 'appendChild');
const pElement = document.createElement('P');
ui._appendToBody(pElement);
assert.calledOnce(appendChildStub);
assert.calledWith(appendChildStub, pElement);
appendChildStub.restore();
});
});
describe('_appendStyleTag', () => {
let styleTag;
let styleTagAppendChildSpy;
beforeEach(() => {
styleTagAppendChildSpy = sinon.spy();
styleTag = {
appendChild: styleTagAppendChildSpy,
};
});
it('appends styletag to document head', () => {
const createElementStub = sinon.stub(document, 'createElement').returns(styleTag);
const headAppendChildStub = sinon.stub(document.head, 'appendChild');
ui._appendStyleTag();
assert.calledOnce(headAppendChildStub);
assert.calledWith(headAppendChildStub, styleTag);
headAppendChildStub.restore();
createElementStub.restore();
});
it('sets styleTag\'s cssText to styleText if styleSheet exists in styleTag', () => {
styleTag.styleSheet = {cssText: {}};
const createElementStub = sinon.stub(document, 'createElement').returns(styleTag);
const headAppendChildStub = sinon.stub(document.head, 'appendChild');
ui._appendStyleTag();
assert.calledOnce(headAppendChildStub);
assert.equal(headAppendChildStub.getCall(0).args[0].styleSheet.cssText, ui.styleText);
headAppendChildStub.restore();
createElementStub.restore();
});
it('appends text node to style tag if stylesheet does not exist', () => {
const createElementStub = sinon.stub(document, 'createElement').returns(styleTag);
const headAppendChildStub = sinon.stub(document.head, 'appendChild');
const createTextNode = sinon.stub(document, 'createTextNode').returnsArg(0);
ui._appendStyleTag();
assert.calledOnce(styleTagAppendChildSpy);
assert.calledWith(styleTagAppendChildSpy, ui.styleText);
headAppendChildStub.restore();
createElementStub.restore();
createTextNode.restore();
});
});
// event bindings were called in the constructor so these just need to dispatch the event
describe('event bindings', () => {
describe('_bindHostClick', () => {
let closeCartStub;
let initStub;
let event;
beforeEach(() => {
closeCartStub = sinon.stub(ui, 'closeCart');
initStub = sinon.stub(Cart.prototype, 'init').resolves();
event = new Event('click', {bubbles: true});
});
afterEach(() => {
closeCartStub.restore();
initStub.restore();
});
it('does nothing if cart is clicked', () => {
const node = document.createElement('div');
ui.components.cart = [{node}];
ui.components.cart[0].node.dispatchEvent(event);
assert.notCalled(closeCartStub);
});
it('does nothing if cart does not exist', () => {
ui.components.cart = [];
document.dispatchEvent(event);
assert.equal(ui.components.cart.length, 0);
assert.notCalled(closeCartStub);
});
it('closes cart if it exists and a click happened outside of the cart', () => {
const node = document.createElement('div');
ui.components.cart = [{node}];
document.dispatchEvent(event);
assert.calledOnce(closeCartStub);
});
});
describe('_bindResize', () => {
it('throttles with resize and safeResize params', () => {
const throttleStub = sinon.stub(throttle, 'default');
ui._bindResize();
assert.calledWith(throttleStub, 'resize', 'safeResize');
throttleStub.restore();
});
describe('on safeResize event', () => {
let event;
beforeEach(() => {
event = new Event('safeResize');
});
it('resizes view for each collection on safeResize', () => {
const resizeSpy1 = sinon.spy();
const resizeSpy2 = sinon.spy();
ui.components.collection = [
{view: {resize: resizeSpy1}},
{view: {resize: resizeSpy2}},
];
window.dispatchEvent(event);
assert.calledOnce(resizeSpy1);
assert.calledOnce(resizeSpy2);
ui.components.collection = [];
});
it('resizes view for each productSet', () => {
const resizeSpy1 = sinon.spy();
const resizeSpy2 = sinon.spy();
const resizeSpy3 = sinon.spy();
ui.components.productSet = [
{view: {resize: resizeSpy1}},
{view: {resize: resizeSpy2}},
{view: {resize: resizeSpy3}},
];
window.dispatchEvent(event);
assert.calledOnce(resizeSpy1);
assert.calledOnce(resizeSpy2);
assert.calledOnce(resizeSpy3);
ui.components.productSet = [];
});
it('resizes view for each product', () => {
const resizeSpy1 = sinon.spy();
const resizeSpy2 = sinon.spy();
ui.components.product = [
{view: {resize: resizeSpy1}},
{view: {resize: resizeSpy2}},
];
window.dispatchEvent(event);
assert.calledOnce(resizeSpy1);
assert.calledOnce(resizeSpy2);
ui.components.product = [];
});
});
});
describe('_bindEsc', () => {
let closeModalStub;
let closeCartStub;
let event;
beforeEach(() => {
closeModalStub = sinon.stub(ui, 'closeModal');
closeCartStub = sinon.stub(ui, 'closeCart');
event = new Event('keydown', {bubbles: true});
});
afterEach(() => {
closeModalStub.restore();
closeCartStub.restore();
});
it('closes modal and cart if escape key is pressed', () => {
event.keyCode = 27; // escape key
window.dispatchEvent(event);
assert.calledOnce(closeModalStub);
assert.calledOnce(closeCartStub);
});
it('does nothing if escape key was not pressed', () => {
event.keyCode = 99999;
window.dispatchEvent(event);
assert.notCalled(closeModalStub);
assert.notCalled(closeCartStub);
});
});
describe('_bindPostMessage', () => {
let event;
let parseStub;
beforeEach(() => {
parseStub = sinon.stub(JSON, 'parse').returns({});
event = new Event('message');
event.data = 'test';
});
afterEach(() => {
parseStub.restore();
});
it('parses data from message', () => {
window.dispatchEvent(event);
// called once is not tested because the stub is on the global JSON instance rather than the class instance
assert.calledWith(parseStub, 'test');
});
});
});
});
});
});