merge with products

This commit is contained in:
Karolina Rakoczy 2021-02-24 20:35:37 +01:00
commit 83bf59889e
23 changed files with 489 additions and 534 deletions

View file

@ -1,4 +1,7 @@
import Utils from "./utils/Utils";
class Product { class Product {
utils = new Utils();
getFirstProducts(first, search) { getFirstProducts(first, search) {
const filter = search const filter = search
? `, filter:{ ? `, filter:{
@ -23,13 +26,13 @@ class Product {
.then(resp => resp.body.data.products.edges); .then(resp => resp.body.data.products.edges);
} }
updateChannelInProduct( updateChannelInProduct({
productId, productId,
channelId, channelId,
isPublished = true, isPublished = true,
isAvailableForPurchase = true, isAvailableForPurchase = true,
visibleInListings = true visibleInListings = true
) { }) {
const mutation = `mutation{ const mutation = `mutation{
productChannelListingUpdate(id:"${productId}", productChannelListingUpdate(id:"${productId}",
input:{ input:{
@ -94,19 +97,22 @@ class Product {
price = 1, price = 1,
costPrice = 1 costPrice = 1
) { ) {
const channelListings = channelId const channelListings = this.utils.getValueWithDefault(
? `channelListings:{ channelId,
`channelListings:{
channelId:"${channelId}" channelId:"${channelId}"
price:"${price}" price:"${price}"
costPrice:"${costPrice}" costPrice:"${costPrice}"
}` }`
: ""; );
const stocks = warehouseId
? `stocks:{ const stocks = this.utils.getValueWithDefault(
warehouseId,
`stocks:{
warehouse:"${warehouseId}" warehouse:"${warehouseId}"
quantity:${quantity} quantity:${quantity}
}` }`
: ""; );
const mutation = `mutation{ const mutation = `mutation{
productVariantBulkCreate(product: "${productId}", variants: { productVariantBulkCreate(product: "${productId}", variants: {

View file

@ -1,32 +0,0 @@
class ProductDetails {
getProductDetails(productId, channelId) {
return cy.request({
method: "POST",
url: Cypress.env("API_URI"),
headers: {
authorization: `JWT ${window.localStorage.getItem("token")}`
},
body: [
{
operationName: "ProductDetails",
variables: {
channel: channelId,
id: productId
},
query:
"fragment BasicProductFields on Product {\n id\n name\n thumbnail {\n url\n alt\n __typename\n }\n thumbnail2x: thumbnail(size: 510) {\n url\n __typename\n }\n __typename\n}\n\nfragment SelectedAttributeFields on SelectedAttribute {\n attribute {\n id\n name\n __typename\n }\n values {\n id\n name\n __typename\n }\n __typename\n}\n\nfragment Price on TaxedMoney {\n gross {\n amount\n currency\n __typename\n }\n net {\n amount\n currency\n __typename\n }\n __typename\n}\n\nfragment ProductVariantFields on ProductVariant {\n id\n sku\n name\n quantityAvailable(countryCode: $countryCode)\n images {\n id\n url\n alt\n __typename\n }\n pricing {\n onSale\n priceUndiscounted {\n ...Price\n __typename\n }\n price {\n ...Price\n __typename\n }\n __typename\n }\n attributes(variantSelection: VARIANT_SELECTION) {\n attribute {\n id\n name\n slug\n __typename\n }\n values {\n id\n name\n value: name\n __typename\n }\n __typename\n }\n __typename\n}\n\nfragment ProductPricingField on Product {\n pricing {\n onSale\n priceRangeUndiscounted {\n start {\n ...Price\n __typename\n }\n stop {\n ...Price\n __typename\n }\n __typename\n }\n priceRange {\n start {\n ...Price\n __typename\n }\n stop {\n ...Price\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n}\n\nquery ProductDetails($id: ID!, $channel: String, $countryCode: CountryCode) {\n product(id: $id, channel: $channel) {\n ...BasicProductFields\n ...ProductPricingField\n description\n category {\n id\n name\n products(first: 3, channel: $channel) {\n edges {\n node {\n ...BasicProductFields\n ...ProductPricingField\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n images {\n id\n alt\n url\n __typename\n }\n attributes {\n ...SelectedAttributeFields\n __typename\n }\n variants {\n ...ProductVariantFields\n __typename\n }\n seoDescription\n seoTitle\n isAvailable\n isAvailableForPurchase\n availableForPurchase\n __typename\n }\n}\n"
}
]
});
}
isAvailableForPurchaseFromResp(resp) {
return resp.body[0].data.product.isAvailableForPurchase;
}
isProductExist(resp, name) {
return (
resp.body[0].data.product !== null &&
resp.body[0].data.product.name === name
);
}
}
export default ProductDetails;

View file

@ -1,34 +0,0 @@
class Search {
searchInShop(searchQuery) {
return cy.request({
method: "POST",
url: Cypress.env("API_URI"),
headers: {
authorization: `JWT ${window.localStorage.getItem("token")}`
},
body: [
{
operationName: "SearchProducts",
variables: {
attributes: {},
channel: "default-channel",
pageSize: 6,
priceGte: null,
priceLte: null,
query: searchQuery,
sortBy: null
},
query:
"fragment Price on TaxedMoney {\n gross {\n amount\n currency\n __typename\n }\n net {\n amount\n currency\n __typename\n }\n __typename\n}\n\nfragment ProductPricingField on Product {\n pricing {\n onSale\n priceRangeUndiscounted {\n start {\n ...Price\n __typename\n }\n stop {\n ...Price\n __typename\n }\n __typename\n }\n priceRange {\n start {\n ...Price\n __typename\n }\n stop {\n ...Price\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n}\n\nquery SearchProducts($query: String!, $channel: String!, $attributes: [AttributeInput], $pageSize: Int, $sortBy: ProductOrder, $after: String) {\n products(channel: $channel, filter: {search: $query, attributes: $attributes}, first: $pageSize, sortBy: $sortBy, after: $after) {\n totalCount\n edges {\n node {\n ...ProductPricingField\n id\n name\n thumbnail {\n url\n alt\n __typename\n }\n thumbnail2x: thumbnail(size: 510) {\n url\n __typename\n }\n category {\n id\n name\n __typename\n }\n __typename\n }\n __typename\n }\n pageInfo {\n endCursor\n hasNextPage\n __typename\n }\n __typename\n }\n attributes(filter: {filterableInStorefront: true}, first: 100) {\n edges {\n node {\n id\n name\n slug\n values {\n id\n name\n slug\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n"
}
]
});
}
isProductExist(resp, name) {
return (
resp.body[0].data.products.totalCount !== 0 &&
resp.body[0].data.products.edges[0].node.name === name
);
}
}
export default Search;

View file

@ -0,0 +1,18 @@
class ProductDetails {
getProductDetails(productId, channelId) {
const query = `fragment BasicProductFields on Product {
id
name
}
query ProductDetails{
product(id: "${productId}", channel: "${channelId}") {
...BasicProductFields
isAvailable
isAvailableForPurchase
availableForPurchase
}
}`;
return cy.sendFrontShopRequestWithQuery(query);
}
}
export default ProductDetails;

View file

@ -0,0 +1,20 @@
class Search {
searchInShop(searchQuery) {
const query = `query SearchProducts {
products(channel: "default-channel", filter:{
search: "${searchQuery}"
}, first:10){
totalCount
edges{
node{
id
name
}
}
}
}`;
return cy.sendFrontShopRequestWithQuery(query);
}
}
export default Search;

View file

@ -0,0 +1,6 @@
class Utils {
getValueWithDefault(condition, value, defaultValue = "") {
return condition ? value : defaultValue;
}
}
export default Utils;

View file

@ -44,10 +44,13 @@ describe("Channels", () => {
it("should create new channel", () => { it("should create new channel", () => {
const randomChannel = `${channelStartsWith} ${faker.random.number()}`; const randomChannel = `${channelStartsWith} ${faker.random.number()}`;
cy.visit(urlList.channels).waitForGraph("Channels"); cy.addAliasToGraphRequest("Channels");
cy.visit(urlList.channels);
cy.wait("@Channels");
cy.addAliasToGraphRequest("Channel");
channelsSteps.createChannelByView(randomChannel, currency); channelsSteps.createChannelByView(randomChannel, currency);
// New channel should be visible in channels list // New channel should be visible in channels list
cy.waitForGraph("Channel") cy.wait("@Channel")
.get(ADD_CHANNEL_FORM_SELECTORS.backToChannelsList) .get(ADD_CHANNEL_FORM_SELECTORS.backToChannelsList)
.click() .click()
.get(CHANNELS_SELECTORS.channelsTable) .get(CHANNELS_SELECTORS.channelsTable)
@ -62,7 +65,9 @@ describe("Channels", () => {
.click(); .click();
// new channel should be visible at product availability form // new channel should be visible at product availability form
cy.visit(urlList.products).waitForGraph("InitialProductFilterData"); cy.addAliasToGraphRequest("InitialProductFilterData");
cy.visit(urlList.products);
cy.wait("@InitialProductFilterData");
cy.get(PRODUCTS_SELECTORS.productsList) cy.get(PRODUCTS_SELECTORS.productsList)
.first() .first()
.click() .click()
@ -103,15 +108,18 @@ describe("Channels", () => {
randomChannelToDelete, randomChannelToDelete,
currency currency
); );
cy.visit(urlList.channels).waitForGraph("Channels"); cy.addAliasToGraphRequest("Channels");
cy.visit(urlList.channels);
cy.wait("@Channels");
cy.get(CHANNELS_SELECTORS.channelName) cy.get(CHANNELS_SELECTORS.channelName)
.contains(randomChannelToDelete) .contains(randomChannelToDelete)
.parentsUntil(CHANNELS_SELECTORS.channelsTable) .parentsUntil(CHANNELS_SELECTORS.channelsTable)
.find("button") .find("button")
.click() .click();
.get(BUTTON_SELECTORS.submit) cy.addAliasToGraphRequest("Channels");
.click() cy.get(BUTTON_SELECTORS.submit).click();
.waitForGraph("Channels"); cy.wait("@Channels");
cy.get(CHANNELS_SELECTORS.channelName) cy.get(CHANNELS_SELECTORS.channelName)
.contains(randomChannelToDelete) .contains(randomChannelToDelete)
.should("not.exist"); .should("not.exist");

View file

@ -48,12 +48,12 @@ describe("Homepage analytics", () => {
) )
.then(resp => { .then(resp => {
customerId = resp.body.data.customerCreate.user.id; customerId = resp.body.data.customerCreate.user.id;
shippingUtils.createShipping( shippingUtils.createShipping({
defaultChannel.id, channelId: defaultChannel.id,
randomName, name: randomName,
addresses.plAddress, address: addresses.plAddress,
shippingPrice price: shippingPrice
); });
}) })
.then(() => { .then(() => {
productsUtils.createTypeAttributeAndCategoryForProduct(randomName); productsUtils.createTypeAttributeAndCategoryForProduct(randomName);
@ -63,16 +63,16 @@ describe("Homepage analytics", () => {
const productType = productsUtils.getProductType(); const productType = productsUtils.getProductType();
const attribute = productsUtils.getAttribute(); const attribute = productsUtils.getAttribute();
const category = productsUtils.getCategory(); const category = productsUtils.getCategory();
productsUtils.createProductInChannel( productsUtils.createProductInChannel({
randomName, name: randomName,
defaultChannel.id, channelId: defaultChannel.id,
warehouse.id, warehouseId: warehouse.id,
20, quantityInWarehouse: 20,
productType.id, productTypeId: productType.id,
attribute.id, attributeId: attribute.id,
category.id, categoryId: category.id,
productPrice price: productPrice
); });
}); });
}); });
@ -154,16 +154,16 @@ describe("Homepage analytics", () => {
const attribute = productsUtils.getAttribute(); const attribute = productsUtils.getAttribute();
const category = productsUtils.getCategory(); const category = productsUtils.getCategory();
productsOutOfStockUtils.createProductInChannel( productsOutOfStockUtils.createProductInChannel({
productOutOfStockRandomName, name: productOutOfStockRandomName,
defaultChannel.id, channelId: defaultChannel.id,
warehouse.id, warehouseId: warehouse.id,
0, quantityInWarehouse: 0,
productType.id, productTypeId: productType.id,
attribute.id, attributeId: attribute.id,
category.id, categoryId: category.id,
productPrice price: productPrice
); });
cy.get("@productsOutOfStock").then(productsOutOfStockBefore => { cy.get("@productsOutOfStock").then(productsOutOfStockBefore => {
const allProductsOutOfStock = productsOutOfStockBefore + 1; const allProductsOutOfStock = productsOutOfStockBefore + 1;

View file

@ -1,11 +1,11 @@
import faker from "faker"; import faker from "faker";
import ProductSteps from "../../steps/productSteps"; import ProductSteps from "../../../steps/productSteps";
import { urlList } from "../../url/urlList"; import { productDetailsUrl } from "../../../url/urlList";
import ChannelsUtils from "../../utils/channelsUtils"; import ChannelsUtils from "../../../utils/channelsUtils";
import FrontShopProductUtils from "../../utils/frontShop/frontShopProductUtils"; import ProductsUtils from "../../../utils/productsUtils";
import ProductsUtils from "../../utils/productsUtils"; import ShippingUtils from "../../../utils/shippingUtils";
import ShippingUtils from "../../utils/shippingUtils"; import StoreFrontProductUtils from "../../../utils/storeFront/storeFrontProductUtils";
// <reference types="cypress" /> // <reference types="cypress" />
describe("Products available in listings", () => { describe("Products available in listings", () => {
@ -13,7 +13,7 @@ describe("Products available in listings", () => {
const channelsUtils = new ChannelsUtils(); const channelsUtils = new ChannelsUtils();
const productsUtils = new ProductsUtils(); const productsUtils = new ProductsUtils();
const productSteps = new ProductSteps(); const productSteps = new ProductSteps();
const frontShopProductUtils = new FrontShopProductUtils(); const frontShopProductUtils = new StoreFrontProductUtils();
const startsWith = "Cy-"; const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`; const name = `${startsWith}${faker.random.number()}`;
let productType; let productType;
@ -34,12 +34,11 @@ describe("Products available in listings", () => {
cy.fixture("addresses"); cy.fixture("addresses");
}) })
.then(addressesFixture => { .then(addressesFixture => {
shippingUtils.createShipping( shippingUtils.createShipping({
defaultChannel, channelId: defaultChannel.id,
name, name,
addressesFixture.plAddress, address: addressesFixture.plAddress
10 });
);
}) })
.then(() => { .then(() => {
warehouse = shippingUtils.getWarehouse(); warehouse = shippingUtils.getWarehouse();
@ -59,23 +58,19 @@ describe("Products available in listings", () => {
it("should update product to available for purchase", () => { it("should update product to available for purchase", () => {
const productName = `${startsWith}${faker.random.number()}`; const productName = `${startsWith}${faker.random.number()}`;
productsUtils productsUtils
.createProductInChannel( .createProductInChannel({
productName, name: productName,
defaultChannel.id, channelId: defaultChannel.id,
warehouse.id, warehouseId: warehouse.id,
10, productTypeId: productType.id,
productType.id, attributeId: attribute.id,
attribute.id, categoryId: category.id,
category.id, isAvailableForPurchase: false
1, })
true,
false,
true
)
.then(() => { .then(() => {
const productUrl = `${urlList.products}${ const productUrl = productDetailsUrl(
productsUtils.getCreatedProduct().id productsUtils.getCreatedProduct().id
}`; );
productSteps.updateProductIsAvailableForPurchase(productUrl, true); productSteps.updateProductIsAvailableForPurchase(productUrl, true);
}) })
.then(() => { .then(() => {
@ -92,33 +87,29 @@ describe("Products available in listings", () => {
it("should update product to not available for purchase", () => { it("should update product to not available for purchase", () => {
const productName = `${startsWith}${faker.random.number()}`; const productName = `${startsWith}${faker.random.number()}`;
productsUtils productsUtils
.createProductInChannel( .createProductInChannel({
productName, name: productName,
defaultChannel.id, channelId: defaultChannel.id,
warehouse.id, warehouseId: warehouse.id,
10, productTypeId: productType.id,
productType.id, attributeId: attribute.id,
attribute.id, categoryId: category.id
category.id, })
1,
true,
true,
true
)
.then(() => { .then(() => {
const productUrl = `${urlList.products}${ const productUrl = productDetailsUrl(
productsUtils.getCreatedProduct().id productsUtils.getCreatedProduct().id
}`; );
productSteps.updateProductIsAvailableForPurchase(productUrl, false); productSteps.updateProductIsAvailableForPurchase(productUrl, false);
frontShopProductUtils })
.isProductAvailableForPurchase( .then(() => {
frontShopProductUtils.isProductAvailableForPurchase(
productsUtils.getCreatedProduct().id, productsUtils.getCreatedProduct().id,
defaultChannel.slug, defaultChannel.slug,
productName productName
) );
})
.then(isProductVisible => { .then(isProductVisible => {
expect(isProductVisible).to.be.eq(false); expect(isProductVisible).to.be.eq(false);
}); });
}); });
});
}); });

View file

@ -1,17 +1,17 @@
import faker from "faker"; import faker from "faker";
import ProductSteps from "../../steps/productSteps"; import ProductSteps from "../../../steps/productSteps";
import { urlList } from "../../url/urlList"; import { productDetailsUrl } from "../../../url/urlList";
import ChannelsUtils from "../../utils/channelsUtils"; import ChannelsUtils from "../../../utils/channelsUtils";
import FrontShopProductUtils from "../../utils/frontShop/frontShopProductUtils"; import ProductsUtils from "../../../utils/productsUtils";
import ProductsUtils from "../../utils/productsUtils"; import StoreFrontProductUtils from "../../../utils/storeFront/storeFrontProductUtils";
// <reference types="cypress" /> // <reference types="cypress" />
describe("Published products", () => { describe("Published products", () => {
const channelsUtils = new ChannelsUtils(); const channelsUtils = new ChannelsUtils();
const productsUtils = new ProductsUtils(); const productsUtils = new ProductsUtils();
const productSteps = new ProductSteps(); const productSteps = new ProductSteps();
const frontShopProductUtils = new FrontShopProductUtils(); const frontShopProductUtils = new StoreFrontProductUtils();
const startsWith = "Cy-"; const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`; const name = `${startsWith}${faker.random.number()}`;
@ -39,23 +39,19 @@ describe("Published products", () => {
.getDefaultChannel() .getDefaultChannel()
.then(channel => { .then(channel => {
defaultChannel = channel; defaultChannel = channel;
productsUtils.createProductInChannel( productsUtils.createProductInChannel({
productName, name: productName,
defaultChannel.id, channelId: defaultChannel.id,
null, productTypeId: productType.id,
null, attributeId: attribute.id,
productType.id, categoryId: category.id,
attribute.id, isPublished: false,
category.id, isAvailableForPurchase: false
1, });
false,
false,
true
);
}) })
.then(() => { .then(() => {
const product = productsUtils.getCreatedProduct(); const product = productsUtils.getCreatedProduct();
const productUrl = `${urlList.products}${product.id}`; const productUrl = productDetailsUrl(product.id);
productSteps.updateProductPublish(productUrl, true); productSteps.updateProductPublish(productUrl, true);
frontShopProductUtils.isProductVisible( frontShopProductUtils.isProductVisible(
product.id, product.id,
@ -76,19 +72,17 @@ describe("Published products", () => {
.getDefaultChannel() .getDefaultChannel()
.then(channel => { .then(channel => {
defaultChannel = channel; defaultChannel = channel;
productsUtils.createProductInChannel( productsUtils.createProductInChannel({
productName, name: productName,
defaultChannel.id, channelId: defaultChannel.id,
null, productTypeId: productType.id,
null, attributeId: attribute.id,
productType.id, categoryId: category.id
attribute.id, });
category.id
);
}) })
.then(() => { .then(() => {
product = productsUtils.getCreatedProduct(); product = productsUtils.getCreatedProduct();
const productUrl = `${urlList.products}${product.id}`; const productUrl = productDetailsUrl(product.id);
productSteps.updateProductPublish(productUrl, false); productSteps.updateProductPublish(productUrl, false);
frontShopProductUtils.isProductVisible( frontShopProductUtils.isProductVisible(
product.id, product.id,

View file

@ -1,17 +1,17 @@
import faker from "faker"; import faker from "faker";
import ProductSteps from "../../steps/productSteps"; import ProductSteps from "../../../steps/productSteps";
import { urlList } from "../../url/urlList"; import { productDetailsUrl } from "../../../url/urlList";
import ChannelsUtils from "../../utils/channelsUtils"; import ChannelsUtils from "../../../utils/channelsUtils";
import FrontShopProductUtils from "../../utils/frontShop/frontShopProductUtils"; import ProductsUtils from "../../../utils/productsUtils";
import ProductsUtils from "../../utils/productsUtils"; import StoreFrontProductUtils from "../../../utils/storeFront/storeFrontProductUtils";
// <reference types="cypress" /> // <reference types="cypress" />
describe("Products displayed in listings", () => { describe("Products displayed in listings", () => {
const channelsUtils = new ChannelsUtils(); const channelsUtils = new ChannelsUtils();
const productsUtils = new ProductsUtils(); const productsUtils = new ProductsUtils();
const productSteps = new ProductSteps(); const productSteps = new ProductSteps();
const frontShopProductUtils = new FrontShopProductUtils(); const frontShopProductUtils = new StoreFrontProductUtils();
const startsWith = "Cy-"; const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`; const name = `${startsWith}${faker.random.number()}`;
@ -39,23 +39,19 @@ describe("Products displayed in listings", () => {
.getDefaultChannel() .getDefaultChannel()
.then(channel => { .then(channel => {
defaultChannel = channel; defaultChannel = channel;
productsUtils.createProductInChannel( productsUtils.createProductInChannel({
productName, name: productName,
defaultChannel.id, channelId: defaultChannel.id,
null, productTypeId: productType.id,
null, attributeId: attribute.id,
productType.id, categoryId: category.id,
attribute.id, visibleInListings: false,
category.id, isAvailableForPurchase: false
1, });
true,
false,
false
);
}) })
.then(() => { .then(() => {
const product = productsUtils.getCreatedProduct(); const product = productsUtils.getCreatedProduct();
const productUrl = `${urlList.products}${product.id}`; const productUrl = productDetailsUrl(product.id);
productSteps.updateProductVisibleInListings(productUrl); productSteps.updateProductVisibleInListings(productUrl);
frontShopProductUtils.isProductVisibleInSearchResult( frontShopProductUtils.isProductVisibleInSearchResult(
productName, productName,
@ -73,23 +69,18 @@ describe("Products displayed in listings", () => {
.getDefaultChannel() .getDefaultChannel()
.then(channel => { .then(channel => {
defaultChannel = channel; defaultChannel = channel;
productsUtils.createProductInChannel( productsUtils.createProductInChannel({
productName, name: productName,
defaultChannel.id, channelId: defaultChannel.id,
null, productTypeId: productType.id,
null, attributeId: attribute.id,
productType.id, categoryId: category.id,
attribute.id, visibleInListings: true
category.id, });
1,
true,
false,
true
);
}) })
.then(() => { .then(() => {
const product = productsUtils.getCreatedProduct(); const product = productsUtils.getCreatedProduct();
const productUrl = `${urlList.products}${product.id}`; const productUrl = productDetailsUrl(product.id);
productSteps.updateProductVisibleInListings(productUrl); productSteps.updateProductVisibleInListings(productUrl);
frontShopProductUtils frontShopProductUtils
.isProductVisibleInSearchResult(productName, defaultChannel.slug) .isProductVisibleInSearchResult(productName, defaultChannel.slug)

View file

@ -0,0 +1,200 @@
import faker from "faker";
import { visit } from "graphql";
import Channels from "../../apiRequests/Channels";
import Product from "../../apiRequests/Product";
import ProductDetails from "../../apiRequests/storeFront/ProductDetails";
import VariantsSteps from "../../steps/products/VariantsSteps";
import { urlList } from "../../url/urlList";
import ChannelsUtils from "../../utils/channelsUtils";
import ProductsUtils from "../../utils/productsUtils";
import ShippingUtils from "../../utils/shippingUtils";
import StoreFrontProductUtils from "../../utils/storeFront/storeFrontProductUtils";
// <reference types="cypress" />
describe("creating variants", () => {
const startsWith = "Cy-";
const productUtils = new ProductsUtils();
const channelsUtils = new ChannelsUtils();
const shippingUtils = new ShippingUtils();
const storeFrontProductUtils = new StoreFrontProductUtils();
const product = new Product();
const channels = new Channels();
const productDetails = new ProductDetails();
const variantsSteps = new VariantsSteps();
let defaultChannel;
let warehouse;
let attribute;
let productType;
let category;
before(() => {
cy.clearSessionData().loginUserViaRequest();
shippingUtils.deleteShipping(startsWith);
productUtils.deleteProperProducts(startsWith);
const name = `${startsWith}${faker.random.number()}`;
channelsUtils
.getDefaultChannel()
.then(channel => {
defaultChannel = channel;
cy.fixture("addresses");
})
.then(fixtureAddresses =>
shippingUtils.createShipping({
channelId: defaultChannel.id,
name,
address: fixtureAddresses.plAddress
})
)
.then(() => (warehouse = shippingUtils.getWarehouse()));
productUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
attribute = productUtils.getAttribute();
productType = productUtils.getProductType();
category = productUtils.getCategory();
});
});
beforeEach(() => {
cy.clearSessionData().loginUserViaRequest();
});
it("should create variant visible on frontend", () => {
const name = `${startsWith}${faker.random.number()}`;
const price = 10;
let createdProduct;
product
.createProduct(attribute.id, name, productType.id, category.id)
.then(resp => {
createdProduct = resp.body.data.productCreate.product;
product.updateChannelInProduct({
productId: createdProduct.id,
channelId: defaultChannel.id
});
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createFirstVariant(name, warehouse.id, price);
storeFrontProductUtils.getProductVariants(
createdProduct.id,
defaultChannel.slug
);
// productDetails
// .getProductDetails(createdProduct.id, defaultChannel.slug)
})
.then(variants => {
// expect(productDetailsResp.body[0].data.product.name).to.equal(name);
expect(variants[0].name).to.equal(name);
expect(variants[0].pricing.price.gross.amount).to.equal(price);
// expect(
// productDetailsResp.body[0].data.product.variants[0].pricing.price
// .gross.amount
// ).to.equal(price);
});
});
it("should create several variants", () => {
const name = `${startsWith}${faker.random.number()}`;
const secondVariantSku = `${startsWith}${faker.random.number()}`;
const variantsPrice = 5;
let createdProduct;
productUtils
.createProductInChannel({
name,
channelId: defaultChannel.id,
warehouseId: warehouse.id,
productTypeId: productType.id,
categoryId: category.id,
price: variantsPrice
})
.then(() => {
createdProduct = productUtils.getCreatedProduct();
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createVariant(
secondVariantSku,
warehouse.name,
variantsPrice
);
})
.then(
() =>
storeFrontProductUtils.getProductVariants(
createdProduct.id,
defaultChannel.slug
)
// productDetails.getProductDetails(createdProduct.id, defaultChannel.slug)
)
.then(variants => {
expect(variants).to.have.length(2);
expect(variants[0].pricing.price.gross.amount).to.equal(variantsPrice);
expect(variants[1].pricing.price.gross.amount).to.equal(variantsPrice);
// expect(productDetailsResp.body[0].data.product.name).to.equal(name);
// expect(productDetailsResp.body[0].data.product.variants).to.have.length(
// 2
// );
// expect(
// productDetailsResp.body[0].data.product.variants[0].pricing.price
// .gross.amount
// ).to.equal(variantsPrice);
// expect(
// productDetailsResp.body[0].data.product.variants[1].pricing.price
// .gross.amount
// ).to.equal(variantsPrice);
});
});
it("should create variant for many channels", () => {
const name = `${startsWith}${faker.random.number()}`;
const variantsPrice = 10;
let newChannel;
let createdProduct;
channels
.createChannel(true, name, name, "PLN")
.then(resp => {
newChannel = resp.body.data.channelCreate.channel;
productUtils.createProduct(
attribute.id,
name,
productType.id,
category.id
);
})
.then(() => {
createdProduct = productUtils.getCreatedProduct();
product.updateChannelInProduct({
productId: createdProduct.id,
channelId: defaultChannel.id
});
})
.then(() => {
product.updateChannelInProduct({
productId: createdProduct.id,
channelId: newChannel.id
});
})
.then(() => {
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createFirstVariant(name, warehouse.id, variantsPrice);
// productDetails.getProductDetails(product.id, defaultChannel.slug);
storeFrontProductUtils.getProductVariants(
product.id,
defaultChannel.slug
);
})
.then(variants => {
expect(variants[0].pricing.price.gross.amount).to.equal(variantsPrice);
})
.then(() => {
storeFrontProductUtils.getProductVariants(
product.id,
defaultChannel.slug
);
// productDetails.getProductDetails(product.id, newChannel.slug);
})
.then(variants => {
expect(variants[0].pricing.price.gross.amount).to.equal(variantsPrice);
});
});
});

View file

@ -1,194 +0,0 @@
import faker from "faker";
import { visit } from "graphql";
import Channels from "../apiRequests/Channels";
import ProductDetails from "../apiRequests/frontShop/ProductDetails";
import Product from "../apiRequests/Product";
import VariantsSteps from "../steps/products/VariantsSteps";
import { urlList } from "../url/urlList";
import ChannelsUtils from "../utils/channelsUtils";
import ProductsUtils from "../utils/productsUtils";
import ShippingUtils from "../utils/shippingUtils";
// <reference types="cypress" />
describe("creating variants", () => {
const startsWith = "Cy-";
const productUtils = new ProductsUtils();
const channelsUtils = new ChannelsUtils();
const shippingUtils = new ShippingUtils();
const product = new Product();
const channels = new Channels();
const productDetails = new ProductDetails();
const variantsSteps = new VariantsSteps();
let defaultChannel;
let warehouse;
let attribute;
let productType;
let category;
before(() => {
cy.clearSessionData().loginUserViaRequest();
shippingUtils.deleteShipping(startsWith);
productUtils.deleteProperProducts(startsWith);
const name = `${startsWith}${faker.random.number()}`;
channelsUtils
.getDefaultChannel()
.then(channel => {
defaultChannel = channel;
cy.fixture("addresses");
})
.then(fixtureAddresses =>
shippingUtils.createShipping(
defaultChannel.id,
name,
fixtureAddresses.plAddress,
10
)
)
.then(() => (warehouse = shippingUtils.getWarehouse()));
productUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
attribute = productUtils.getAttribute();
productType = productUtils.getProductType();
category = productUtils.getCategory();
});
});
beforeEach(() => {
cy.clearSessionData().loginUserViaRequest();
});
it("should create variant visible on frontend", () => {
const name = `${startsWith}${faker.random.number()}`;
const price = 10;
let createdProduct;
product
.createProduct(attribute.id, name, productType.id, category.id)
.then(resp => {
createdProduct = resp.body.data.productCreate.product;
product.updateChannelInProduct(
createdProduct.id,
defaultChannel.id,
true,
true,
true
);
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createFirstVariant(name, warehouse.id, price);
productDetails
.getProductDetails(createdProduct.id, defaultChannel.slug)
.then(productDetailsResp => {
expect(productDetailsResp.body[0].data.product.name).to.equal(name);
expect(
productDetailsResp.body[0].data.product.variants[0].pricing.price
.gross.amount
).to.equal(price);
});
});
});
it("should create several variants", () => {
const name = `${startsWith}${faker.random.number()}`;
const secondVariantSku = `${startsWith}${faker.random.number()}`;
const variantsPrice = 5;
let createdProduct;
productUtils
.createProductInChannel(
name,
defaultChannel.id,
warehouse.id,
1,
productType.id,
attribute.id,
category.id,
variantsPrice
)
.then(() => {
createdProduct = productUtils.getCreatedProduct();
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createVariant(
secondVariantSku,
warehouse.name,
variantsPrice
);
})
.then(() =>
productDetails.getProductDetails(createdProduct.id, defaultChannel.slug)
)
.then(productDetailsResp => {
expect(productDetailsResp.body[0].data.product.name).to.equal(name);
expect(productDetailsResp.body[0].data.product.variants).to.have.length(
2
);
expect(
productDetailsResp.body[0].data.product.variants[0].pricing.price
.gross.amount
).to.equal(variantsPrice);
expect(
productDetailsResp.body[0].data.product.variants[1].pricing.price
.gross.amount
).to.equal(variantsPrice);
});
});
it("should create variant for many channels", () => {
const name = `${startsWith}${faker.random.number()}`;
let newChannel;
let createdProduct;
channels
.createChannel(true, name, name, "PLN")
.then(resp => {
newChannel = resp.body.data.channelCreate.channel;
productUtils.createProduct(
attribute.id,
name,
productType.id,
category.id
);
})
.then(() => {
createdProduct = productUtils.getCreatedProduct();
product.updateChannelInProduct(
createdProduct.id,
defaultChannel.id,
true,
true,
true
);
})
.then(() => {
product.updateChannelInProduct(
createdProduct.id,
newChannel.id,
true,
true,
true
);
})
.then(() => {
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createFirstVariant(warehouse.id);
productDetails.getProductDetails(product.id, defaultChannel.slug);
})
.then(productDetailsResp => {
expect(productDetailsResp.body[0].data.product.name).to.equal(name);
expect(
productDetailsResp.body[0].data.product.variants[0].pricing.price
.gross.amount
).to.equal(10);
})
.then(() => {
productDetails.getProductDetails(product.id, newChannel.slug);
})
.then(productDetailsResp => {
expect(productDetailsResp.body[0].data.product.name).to.equal(name);
expect(
productDetailsResp.body[0].data.product.variants[0].pricing.price
.gross.amount
).to.equal(10);
});
});
});

View file

@ -1,12 +1,12 @@
import { HEADER_SELECTORS } from "../elements/header/header-selectors"; import { HEADER_SELECTORS } from "../elements/header/header-selectors";
class HomePageSteps { class HomePageSteps {
changeChannel(channelName) { changeChannel(channelName) {
cy.get(HEADER_SELECTORS.channelSelect) cy.get(HEADER_SELECTORS.channelSelect).click();
.click() cy.addAliasToGraphRequest("Home");
.get(HEADER_SELECTORS.channelSelectList) cy.get(HEADER_SELECTORS.channelSelectList)
.contains(channelName) .contains(channelName)
.click() .click();
.waitForGraph("Home"); cy.wait("@Home");
} }
} }
export default HomePageSteps; export default HomePageSteps;

View file

@ -1,30 +1,20 @@
import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors"; import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors";
class ProductSteps { class ProductSteps {
valueTrue = PRODUCTS_SELECTORS.radioButtonsValueTrue;
valueFalse = PRODUCTS_SELECTORS.radioButtonsValueFalse;
updateProductIsAvailableForPurchase(productUrl, isAvailableForPurchase) { updateProductIsAvailableForPurchase(productUrl, isAvailableForPurchase) {
let isAvailableForPurchaseSelector; const isAvailableForPurchaseSelector = isAvailableForPurchase
if (isAvailableForPurchase) { ? this.valueTrue
isAvailableForPurchaseSelector = PRODUCTS_SELECTORS.radioButtonsValueTrue; : this.valueFalse;
} else { const availableForPurchaseSelector = `${PRODUCTS_SELECTORS.availableForPurchaseRadioButtons}${isAvailableForPurchaseSelector}`;
isAvailableForPurchaseSelector = this.updateProductMenageInChannel(productUrl, availableForPurchaseSelector);
PRODUCTS_SELECTORS.radioButtonsValueFalse;
}
this.updateProductMenageInChannel(
productUrl,
`${PRODUCTS_SELECTORS.availableForPurchaseRadioButtons}${isAvailableForPurchaseSelector}`
);
} }
updateProductPublish(productUrl, isPublished) { updateProductPublish(productUrl, isPublished) {
let isPublishedSelector; const isPublishedSelector = isPublished ? this.valueTrue : this.valueFalse;
if (isPublished) { const publishedSelector = `${PRODUCTS_SELECTORS.publishedRadioButtons}${isPublishedSelector}`;
isPublishedSelector = PRODUCTS_SELECTORS.radioButtonsValueTrue; this.updateProductMenageInChannel(productUrl, publishedSelector);
} else {
isPublishedSelector = PRODUCTS_SELECTORS.radioButtonsValueFalse;
}
this.updateProductMenageInChannel(
productUrl,
`${PRODUCTS_SELECTORS.publishedRadioButtons}${isPublishedSelector}`
);
} }
updateProductVisibleInListings(productUrl) { updateProductVisibleInListings(productUrl) {
this.updateProductMenageInChannel( this.updateProductMenageInChannel(
@ -37,10 +27,11 @@ class ProductSteps {
.get(PRODUCTS_SELECTORS.assignedChannels) .get(PRODUCTS_SELECTORS.assignedChannels)
.click() .click()
.get(menageSelector) .get(menageSelector)
.click();
cy.addAliasToGraphRequest("ProductChannelListingUpdate");
cy.get(PRODUCTS_SELECTORS.saveBtn)
.click() .click()
.get(PRODUCTS_SELECTORS.saveBtn) .wait("@ProductChannelListingUpdate");
.click()
.waitForGraph("ProductChannelListingUpdate");
} }
} }
export default ProductSteps; export default ProductSteps;

View file

@ -8,16 +8,20 @@ class VariantsSteps {
.first() .first()
.click() .click()
.get(VARIANTS_SELECTORS.nextButton) .get(VARIANTS_SELECTORS.nextButton)
.click() .click();
.get(VARIANTS_SELECTORS.priceInput) const priceInput = cy.get(VARIANTS_SELECTORS.priceInput);
.forEach(priceInput => cy.priceInput.type(price)); if (Array.isArray(priceInput)) {
priceInput.forEach(input => input.type(price));
} else {
priceInput.type(price);
}
cy.get(`[name*='${warehouseId}']`) cy.get(`[name*='${warehouseId}']`)
.click() .click()
.get(VARIANTS_SELECTORS.nextButton) .get(VARIANTS_SELECTORS.nextButton)
.click() .click()
.get(VARIANTS_SELECTORS.skuInput) .get(VARIANTS_SELECTORS.skuInput)
.type(sku); .type(sku);
cy.waitForGraph("ProductVariantBulkCreate"); cy.addAliasToGraphRequest("ProductVariantBulkCreate");
cy.get(VARIANTS_SELECTORS.nextButton).click(); cy.get(VARIANTS_SELECTORS.nextButton).click();
cy.wait("@ProductVariantBulkCreate"); cy.wait("@ProductVariantBulkCreate");
} }
@ -38,7 +42,7 @@ class VariantsSteps {
.get(VARIANTS_SELECTORS.addWarehouseButton) .get(VARIANTS_SELECTORS.addWarehouseButton)
.click(); .click();
cy.contains(VARIANTS_SELECTORS.warehouseOption, warehouseName).click(); cy.contains(VARIANTS_SELECTORS.warehouseOption, warehouseName).click();
cy.waitForGraph("VariantCreate"); cy.addAliasToGraphRequest("VariantCreate");
cy.get(VARIANTS_SELECTORS.saveButton).click(); cy.get(VARIANTS_SELECTORS.saveButton).click();
cy.wait("@VariantCreate"); cy.wait("@VariantCreate");
} }

View file

@ -21,7 +21,7 @@ Cypress.Commands.add("clearSessionData", () => {
}); });
}); });
Cypress.Commands.add("waitForGraph", operationName => { Cypress.Commands.add("addAliasToGraphRequest", operationName => {
cy.intercept("POST", urlList.apiUri, req => { cy.intercept("POST", urlList.apiUri, req => {
req.statusCode = 200; req.statusCode = 200;
const requestBody = req.body; const requestBody = req.body;
@ -39,7 +39,10 @@ Cypress.Commands.add("waitForGraph", operationName => {
}); });
}); });
Cypress.Commands.add("sendRequestWithQuery", query => Cypress.Commands.add("sendFrontShopRequestWithQuery", query =>
cy.sendRequestWithQuery(query, "token")
);
Cypress.Commands.add("sendRequestWithQuery", (query, authorization = "auth") =>
cy.request({ cy.request({
body: { body: {
method: "POST", method: "POST",
@ -47,7 +50,7 @@ Cypress.Commands.add("sendRequestWithQuery", query =>
url: urlList.apiUri url: urlList.apiUri
}, },
headers: { headers: {
Authorization: `JWT ${window.sessionStorage.getItem("auth")}` Authorization: `JWT ${window.sessionStorage.getItem(authorization)}`
}, },
method: "POST", method: "POST",
url: urlList.apiUri url: urlList.apiUri

View file

@ -1,5 +1,4 @@
import { LOGIN_SELECTORS } from "../../elements/account/login-selectors"; import { LOGIN_SELECTORS } from "../../elements/account/login-selectors";
import { urlList } from "../../url/urlList";
Cypress.Commands.add("loginUser", () => Cypress.Commands.add("loginUser", () =>
cy cy
@ -11,58 +10,30 @@ Cypress.Commands.add("loginUser", () =>
.click() .click()
); );
Cypress.Commands.add("loginUserViaRequest", () => { Cypress.Commands.add("loginInShop", () => {
const logInMutationQuery = `mutation TokenAuth($email: String!, $password: String!) { cy.loginUserViaRequest("token");
tokenCreate(email: $email, password: $password) { });
Cypress.Commands.add("loginUserViaRequest", (authorization = "auth") => {
const mutation = `mutation TokenAuth{
tokenCreate(email: "${Cypress.env("USER_NAME")}", password: "${Cypress.env(
"USER_PASSWORD"
)}") {
token token
errors: accountErrors { errors: accountErrors {
code code
field field
message message
__typename
} }
user { user {
id id
__typename
} }
__typename
} }
}`; }`;
return cy.sendRequestWithQuery(mutation, authorization).then(resp => {
return cy window.sessionStorage.setItem(
.request({ authorization,
body: { resp.body.data.tokenCreate.token
operationName: "TokenAuth", );
query: logInMutationQuery,
variables: {
email: Cypress.env("USER_NAME"),
password: Cypress.env("USER_PASSWORD")
}
},
method: "POST",
url: urlList.apiUri
})
.then(resp => {
window.sessionStorage.setItem("auth", resp.body.data.tokenCreate.token);
});
});
Cypress.Commands.add("loginInShop", () => {
cy.request({
method: "POST",
url: Cypress.env("API_URI"),
body: [
{
operationName: "TokenAuth",
variables: {
email: Cypress.env("USER_NAME"),
password: Cypress.env("USER_PASSWORD")
},
query:
"mutation TokenAuth($email: String!, $password: String!) {\n tokenCreate(email: $email, password: $password) {\n token\n errors: accountErrors {\n code\n field\n message\n __typename\n }\n user {\n id\n __typename\n }\n __typename\n }\n}\n"
}
]
}).then(resp => {
window.localStorage.setItem("token", resp.body[0].data.tokenCreate.token);
}); });
}); });

View file

@ -7,3 +7,4 @@ export const urlList = {
products: "products/", products: "products/",
warehouses: "warehouses/" warehouses: "warehouses/"
}; };
export const productDetailsUrl = productId => `${urlList.products}${productId}`;

View file

@ -1,28 +0,0 @@
import ProductDetails from "../../apiRequests/frontShop/ProductDetails";
import Search from "../../apiRequests/frontShop/Search";
class FrontShopProductUtils {
isProductVisible(productId, channelSlug, name) {
const productDetails = new ProductDetails();
return productDetails
.getProductDetails(productId, channelSlug)
.then(productDetailsResp =>
productDetails.isProductExist(productDetailsResp, name)
);
}
isProductAvailableForPurchase(productId, channelSlug) {
const productDetails = new ProductDetails();
return productDetails
.getProductDetails(productId, channelSlug)
.then(productDetailsResp =>
productDetails.isAvailableForPurchaseFromResp(productDetailsResp)
);
}
isProductVisibleInSearchResult(productName, channelSlug) {
const search = new Search();
return search
.searchInShop(productName, channelSlug)
.then(resp => search.isProductExist(resp, productName));
}
}
export default FrontShopProductUtils;

View file

@ -22,28 +22,28 @@ class ProductsUtils {
).then(() => this.createVariant(this.product.id, name, attributeId)); ).then(() => this.createVariant(this.product.id, name, attributeId));
} }
createProductInChannel( createProductInChannel({
name, name,
channelId, channelId,
warehouseId, warehouseId = null,
quantityInWarehouse, quantityInWarehouse = 10,
productTypeId, productTypeId,
attributeId, attributeId,
categoryId, categoryId,
price, price = 1,
isPublished = true, isPublished = true,
isAvailableForPurchase = true, isAvailableForPurchase = true,
visibleInListings = true visibleInListings = true
) { }) {
return this.createProduct(attributeId, name, productTypeId, categoryId) return this.createProduct(attributeId, name, productTypeId, categoryId)
.then(() => .then(() =>
this.productRequest.updateChannelInProduct( this.productRequest.updateChannelInProduct({
this.product.id, productId: this.product.id,
channelId, channelId,
isPublished, isPublished,
isAvailableForPurchase, isAvailableForPurchase,
visibleInListings visibleInListings
) })
) )
.then(() => { .then(() => {
this.createVariant( this.createVariant(

View file

@ -8,7 +8,7 @@ class ShippingUtils {
shippingZone; shippingZone;
warehouse; warehouse;
createShipping(channelId, name, address, price) { createShipping({ channelId, name, address, price = 1 }) {
return this.createShippingZone(name, address.country) return this.createShippingZone(name, address.country)
.then(() => this.createWarehouse(name, this.shippingZone.id, address)) .then(() => this.createWarehouse(name, this.shippingZone.id, address))
.then(() => this.createShippingRate(name, this.shippingZone.id)) .then(() => this.createShippingRate(name, this.shippingZone.id))

View file

@ -0,0 +1,39 @@
import ProductDetails from "../../apiRequests/storeFront/ProductDetails";
import Search from "../../apiRequests/storeFront/Search";
class StoreFrontProductUtils {
productDetails = new ProductDetails();
isProductVisible(productId, channelSlug, name) {
return this.productDetails
.getProductDetails(productId, channelSlug)
.then(productDetailsResp => {
const product = productDetailsResp.body.data.product;
return product !== null && product.name === name;
});
}
isProductAvailableForPurchase(productId, channelSlug) {
return this.productDetails
.getProductDetails(productId, channelSlug)
.then(
productDetailsResp =>
productDetailsResp.body.data.product.isAvailableForPurchase
);
}
isProductVisibleInSearchResult(productName, channelSlug) {
const search = new Search();
return search
.searchInShop(productName, channelSlug)
.then(
resp =>
resp.body.data.products.totalCount !== 0 &&
resp.body.data.products.edges[0].node.name === productName
);
}
getProductVariants(productId, channelSlug) {
return this.productDetails
.getProductDetails(productId, channelSlug)
.then(resp => resp.body.data.product.variants.edges);
}
}
export default StoreFrontProductUtils;