@nguyenmv2/buy-button
Version:
BuyButton.js allows merchants to build Shopify interfaces into any website
451 lines (399 loc) • 13.8 kB
JavaScript
import ProductSet from '../../src/components/product-set';
import Component from '../../src/component';
import Updater from '../../src/updater';
import Product from '../../src/components/product';
import testProduct from '../fixtures/product-fixture';
import ShopifyBuy from '../../src/buybutton';
const config = {
storefrontId: 'Z2lkOi8vc2hvcGlmeS9Db2xsZWN0aW9uLzEyMzQ1',
options: {
product: {
templates: {
button: '<button id="button" class="button">Fake button</button>'
}
}
},
};
const fakeProduct = testProduct;
describe('ProductSet class', () => {
let client;
let set;
beforeEach(() => {
client = ShopifyBuy.buildClient({
domain: 'test.myshopify.com',
storefrontAccessToken: 123
});
config.node = document.createElement('div');
config.node.setAttribute('id', 'fixture');
document.body.appendChild(config.node);
set = new ProductSet(config, {
client,
createCart: () => Promise.resolve(),
destroyComponent: () => Promise.resolve()
});
sinon.stub(set.props.client.collection, 'fetchWithProducts').returns(Promise.resolve({
products: [
{title: 'vapehat'},
{title: 'vapeshoe'}
]
}));
});
afterEach(() => {
set = null;
document.body.removeChild(config.node);
config.node = null;
});
it('converts database collection id to storefrontId', () => {
const id = 12345
const collection = new ProductSet({id}, {});
assert.equal(collection.storefrontId, btoa(`gid://shopify/Collection/${id}`))
}),
it('converts a list of database product ids to storefrontId', () => {
const id = [12345, 34567];
const collection = new ProductSet({id}, {});
assert.deepEqual(collection.storefrontId, [
btoa(`gid://shopify/Product/${id[0]}`),
btoa(`gid://shopify/Product/${id[1]}`),
]);
}),
describe('fetchData', () => {
it('returns product data', () => {
return set.fetchData().then((data) => {
assert.deepEqual(data, {
products: [{title: 'vapehat'}, {title: 'vapeshoe'}]
});
});
});
});
describe('sdkFetch', () => {
describe('when passed a collection ID', () => {
let collection;
let fetchWithProductsStub;
const id = 12345;
const storefrontId = btoa(`gid://shopify/Collection/${id}`);
let productSetOpts;
beforeEach(() => {
client = ShopifyBuy.buildClient({
domain: 'test.myshopify.com',
storefrontAccessToken: 123
});
productSetOpts = {
client,
createCart: () => Promise.resolve()
};
});
it('calls collection.fetchWithProducts with collection storefrontId when passed a storefrontId', () => {
collection = new ProductSet({
storefrontId,
options: config.options,
}, productSetOpts);
fetchWithProductsStub = sinon.stub(
collection.props.client.collection,
'fetchWithProducts'
).returns(Promise.resolve([]));
const result = collection.sdkFetch();
assert.ok(result.then);
assert.calledWith(fetchWithProductsStub, storefrontId);
});
it('calls collection.fetchWithProducts with collection storefrontId when passed a database id', () => {
collection = new ProductSet({
id,
options: config.options,
}, productSetOpts);
fetchWithProductsStub = sinon.stub(
collection.props.client.collection,
'fetchWithProducts'
).returns(Promise.resolve({}));
const result = collection.sdkFetch();
assert.ok(result.then);
assert.calledWith(fetchWithProductsStub, storefrontId);
});
});
describe('when passed a collection handle', () => {
let collection;
let fetchWithProductsStub;
let fetchByHandleStub;
beforeEach(() => {
client = ShopifyBuy.buildClient({
domain: 'test.myshopify.com',
storefrontAccessToken: 123
});
collection = new ProductSet({
handle: 'hats',
options: config.options,
}, {
client,
createCart: () => Promise.resolve()
});
fetchWithProductsStub = sinon.stub(collection.props.client.collection, 'fetchWithProducts').returns(Promise.resolve({}));
fetchByHandleStub = sinon.stub(collection.props.client.collection, 'fetchByHandle').returns(Promise.resolve({id: 'an-id'}));
});
it('calls fetchByHandle and fetchWithProducts with collection id', () => {
return collection.sdkFetch().then(() => {
assert.calledWith(fetchByHandleStub, 'hats');
assert.calledWith(fetchWithProductsStub, 'an-id');
});
});
});
describe('when passed an array of database product IDs', () => {
let collection;
let fetchMultipleStub;
let productSetOpts;
const id = [1234, 2345];
const storefrontId = [
btoa(`gid://shopify/Product/${id[0]}`),
btoa(`gid://shopify/Product/${id[1]}`),
];
beforeEach(() => {
client = ShopifyBuy.buildClient({
domain: 'test.myshopify.com',
storefrontAccessToken: 123
});
productSetOpts = {
client,
createCart: () => Promise.resolve()
};
fetchMultipleStub = sinon.stub(client.product, 'fetchMultiple').returns(Promise.resolve({}));
});
it('calls fetchMultiple with an array of storefront ids when passed database ids', () => {
collection = new ProductSet({
id,
options: config.options,
}, productSetOpts);
const result = collection.sdkFetch();
assert.ok(result.then);
assert.calledWith(fetchMultipleStub, storefrontId);
});
it('calls fetchMultiple with an array of storefront ids when passed storefront ids', () => {
collection = new ProductSet({
storefrontId,
options: config.options,
}, productSetOpts);
const result = collection.sdkFetch();
assert.ok(result.then);
assert.calledWith(fetchMultipleStub, storefrontId);
});
});
});
describe('renderProducts', () => {
let initSpy;
let showPaginationStub;
beforeEach(() => {
initSpy = sinon.spy(Product.prototype, 'init');
showPaginationStub = sinon.stub(set, 'showPagination').returns(Promise.resolve());
set.model.products = [fakeProduct];
set.view.render();
});
afterEach(() => {
initSpy.restore();
showPaginationStub.restore();
});
it('initializes an array of products', () => {
return set.renderProducts().then(() => {
assert.calledWith(initSpy, fakeProduct);
});
});
it('calls showPagination if pagination is set to true in contents and products have connections', () => {
set.config.productSet.contents.pagination = true;
const updatedFakeProduct = Object.assign({}, fakeProduct);
updatedFakeProduct.hasNextPage = true;
set.model.products = [updatedFakeProduct];
return set.renderProducts().then(() => {
assert.calledOnce(showPaginationStub);
});
});
it('does not call showPagination if pagination is set to true in contents and products do not have connections', () => {
set.config.productSet.contents.pagination = true;
return set.renderProducts().then(() => {
assert.notCalled(showPaginationStub);
});
});
it('does not call showPagination if pagination is set to false in contents and products have connections', () => {
set.config.productSet.contents.pagination = false;
const updatedFakeProduct = Object.assign({}, fakeProduct);
updatedFakeProduct.hasNextPage = true;
set.model.products = [updatedFakeProduct];
return set.renderProducts().then(() => {
assert.notCalled(showPaginationStub);
});
});
it('does not call showPagination if pagination is set to false in contents and products do not have connections', () => {
set.config.productSet.contents.pagination = false;
return set.renderProducts().then(() => {
assert.notCalled(showPaginationStub);
});
});
});
describe('updateConfig', () => {
const newConfig = {
options: {
styles: {
button: {
'color': 'red',
},
},
},
}
let superSpy;
let renderProductsSpy;
beforeEach(() => {
superSpy = sinon.stub(Updater.prototype, 'updateConfig');
renderProductsSpy = sinon.stub(set, 'renderProducts');
set.products = [{
updateConfig: sinon.spy()
}];
set.cart = {
updateConfig: sinon.spy()
}
});
afterEach(() => {
superSpy.restore();
});
it('calls updateConfig on super, cart and first product', () => {
set.updateConfig(newConfig);
assert.calledWith(set.cart.updateConfig, newConfig);
assert.calledWith(set.products[0].updateConfig, {options: newConfig.options});
assert.calledWith(superSpy, newConfig);
});
});
describe('showPagination', () => {
let sdkFetchSpy;
let renderChildStub;
let resizeSpy;
let fetchNextPageSpy;
const nextPageData = {
model: [
{title: 'vapebelt'},
{title: 'vapeglasses'},
],
};
beforeEach(() => {
set.id = 1234;
set.model.products = [{title: 'product1'}, {title: 'product2'}];
renderChildStub = sinon.stub(set.view, 'renderChild');
resizeSpy = sinon.stub(set.view, 'resize');
fetchNextPageSpy = sinon.stub(set.props.client, 'fetchNextPage').returns(Promise.resolve(nextPageData));
});
it('sets nextModel and rerenders pagination button', () => {
return set.showPagination().then(() => {
assert.deepEqual(set.nextModel, {products: nextPageData.model});
assert.calledWith(renderChildStub, set.classes.productSet.paginationButton, set.paginationTemplate);
});
});
});
describe('trackingInfo', () => {
let expectedContentString;
beforeEach(() => {
expectedContentString = Object.keys(set.config.product.contents).filter((key) => set.config.product.contents[key]).toString();
});
it('returns an object with the collection id and button destination when an the product set id is not an array', () => {
const info = set.trackingInfo;
assert.deepEqual(info, {
id: config.storefrontId,
destination: set.config.product.buttonDestination,
layout: set.config.product.layout,
contents: expectedContentString,
checkoutPopup: set.config.cart.popup,
});
});
it('returns an array of product info objects when the product set id is an array of ids', () => {
const fakeProduct2 = {
title: 'test2',
id: 4567,
storefrontId: 'GTYlkOi8vc2hvcGlmeS9Qcm9kdWN0LzEyMw==',
images: [
{
id: '1',
src: 'https://cdn.shopify.com/s/files/1/0014/8583/2214/products/image-one.jpg',
},
{
id: '2',
src: 'https://cdn.shopify.com/s/files/1/0014/8583/2214/products/image-two.jpeg',
},
{
id: '3',
src: 'https://cdn.shopify.com/s/files/1/0014/8583/2214/products/image-three.jpg',
},
{
id: '4',
src: 'https://cdn.shopify.com/s/files/1/0014/8583/2214/products/image-four.jpeg',
},
],
options: [
{
name: 'Print',
values: [
{value: 'sloth'},
{value: 'shark'},
{value: 'cat'},
],
},
{
name: 'Size',
selected: 'small',
values: [
{value: 'small'},
{value: 'large'},
],
},
],
variants: [
{
id: 'GTYOi8vc2hvcGlmeS9Qcm9kdWN0VmFyaWFudC8xMjM0NQ==',
productId: 1245,
price: '20.00',
priceV2: {
amount: '20.00',
currencyCode: 'CAD',
},
title: 'sloth / small',
available: true,
image: {
id: 100,
src: 'https://cdn.shopify.com/s/files/1/0014/8583/2214/products/image-one.jpg',
},
selectedOptions: [
{
name: 'Print',
value: 'sloth',
},
{
name: 'Size',
value: 'small',
},
],
},
],
};
set.id = [1234, 4567];
set.model.products = [fakeProduct, fakeProduct2];
const info = set.trackingInfo;
assert.deepEqual(info, [{
id: fakeProduct.id,
name: fakeProduct.title,
variantId: fakeProduct.variants[0].id,
variantName: fakeProduct.variants[0].title,
price: fakeProduct.variants[0].priceV2.amount,
destination: set.config.product.buttonDestination,
layout: set.config.product.layout,
contents: expectedContentString,
checkoutPopup: set.config.cart.popup,
sku: null,
isProductSet: true,
},
{
id: fakeProduct2.id,
name: fakeProduct2.title,
variantId: fakeProduct2.variants[0].id,
variantName: fakeProduct2.variants[0].title,
price: fakeProduct2.variants[0].priceV2.amount,
destination: set.config.product.buttonDestination,
layout: set.config.product.layout,
contents: expectedContentString,
checkoutPopup: set.config.cart.popup,
sku: null,
isProductSet: true,
}]);
});
});
});