diff --git a/cypress/apiRequests/Attribute.js b/cypress/apiRequests/Attribute.js index f1c180d01..b0f23be23 100644 --- a/cypress/apiRequests/Attribute.js +++ b/cypress/apiRequests/Attribute.js @@ -1,20 +1,20 @@ class Attribute { createAttribute(name) { const mutation = `mutation{ - attributeCreate(input:{ - name:"${name}" - valueRequired:false - type:PRODUCT_TYPE - }){ - attribute{ - id + attributeCreate(input:{ + name:"${name}" + valueRequired:false + type:PRODUCT_TYPE + }){ + attribute{ + id + } + attributeErrors{ + field + message + } } - attributeErrors{ - field - message - } - } - }`; + }`; return cy.sendRequestWithQuery(mutation); } diff --git a/cypress/apiRequests/Product.js b/cypress/apiRequests/Product.js index 09dca8bf6..8aa6b0ce8 100644 --- a/cypress/apiRequests/Product.js +++ b/cypress/apiRequests/Product.js @@ -1,4 +1,7 @@ +import Utils from "./utils/Utils"; + class Product { + utils = new Utils(); getFirstProducts(first, search) { const filter = search ? `, filter:{ @@ -17,44 +20,50 @@ class Product { } } } - } - `; + `; return cy .sendRequestWithQuery(query) .then(resp => resp.body.data.products.edges); } - updateChannelInProduct(productId, channelId) { + updateChannelInProduct({ + productId, + channelId, + isPublished = true, + isAvailableForPurchase = true, + visibleInListings = true + }) { const mutation = `mutation{ - productChannelListingUpdate(id:"${productId}", - input:{ - addChannels:{ - channelId:"${channelId}" - isPublished:true - isAvailableForPurchase:true + productChannelListingUpdate(id:"${productId}", + input:{ + addChannels:{ + channelId:"${channelId}" + isPublished:${isPublished} + isAvailableForPurchase:${isAvailableForPurchase} + visibleInListings:${visibleInListings} + } + }){ + product{ + id + name + } } - }){ - product{ - id - name - } - } - }`; - return cy.sendRequestWithQuery(mutation); + }`; + cy.sendRequestWithQuery(mutation); } updateChannelPriceInVariant(variantId, channelId) { const mutation = `mutation{ - productVariantChannelListingUpdate(id: "${variantId}", input:{ - channelId: "${channelId}" - price: 10 - costPrice: 10 - }){ - productChannelListingErrors{ - message - } - } - }`; + productVariantChannelListingUpdate(id: "${variantId}", input: { + channelId: "${channelId}" + price: 10 + costPrice: 10 + }){ + productChannelListingErrors{ + message + } + } +} `; return cy.sendRequestWithQuery(mutation); } createProduct(attributeId, name, productType, category) { @@ -88,20 +97,30 @@ class Product { price = 1, costPrice = 1 ) { + const channelListings = this.utils.getValueWithDefault( + channelId, + `channelListings:{ + channelId:"${channelId}" + price:"${price}" + costPrice:"${costPrice}" + }` + ); + + const stocks = this.utils.getValueWithDefault( + warehouseId, + `stocks:{ + warehouse:"${warehouseId}" + quantity:${quantity} + }` + ); + const mutation = `mutation{ - productVariantBulkCreate(product:"${productId}", variants:{ - attributes:[] - sku:"${sku}" - channelListings:{ - channelId:"${channelId}" - price:"${price}" - costPrice:"${costPrice}" - } - stocks:{ - warehouse:"${warehouseId}" - quantity:${quantity} - } - }){ + productVariantBulkCreate(product: "${productId}", variants: { + attributes: [] + sku: "${sku}" + ${channelListings} + ${stocks} + }) { productVariants{ id name @@ -117,33 +136,33 @@ class Product { createTypeProduct(name, attributeId, slug = name) { const mutation = `mutation{ - productTypeCreate(input:{ - name:"${name}" + productTypeCreate(input: { + name: "${name}" slug: "${slug}" - isShippingRequired:true - productAttributes:"${attributeId}" - }){ - productErrors{ - field - message - } - productType{ - id - } - } - }`; + isShippingRequired: true + productAttributes: "${attributeId}" + }){ + productErrors{ + field + message + } + productType{ + id + } + } +} `; return cy.sendRequestWithQuery(mutation); } deleteProduct(productId) { const mutation = `mutation{ - productDelete(id:"${productId}"){ - productErrors{ - field - message - } - } - }`; + productDelete(id: "${productId}"){ + productErrors{ + field + message + } + } +} `; return cy.sendRequestWithQuery(mutation); } diff --git a/cypress/apiRequests/storeFront/ProductDetails.js b/cypress/apiRequests/storeFront/ProductDetails.js new file mode 100644 index 000000000..e3bb9d7a1 --- /dev/null +++ b/cypress/apiRequests/storeFront/ProductDetails.js @@ -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.sendRequestWithQuery(query, "token"); + } +} +export default ProductDetails; diff --git a/cypress/apiRequests/storeFront/Search.js b/cypress/apiRequests/storeFront/Search.js new file mode 100644 index 000000000..776ba2860 --- /dev/null +++ b/cypress/apiRequests/storeFront/Search.js @@ -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.sendRequestWithQuery(query, "token"); + } +} +export default Search; diff --git a/cypress/apiRequests/utils/Utils.js b/cypress/apiRequests/utils/Utils.js new file mode 100644 index 000000000..cbb37b751 --- /dev/null +++ b/cypress/apiRequests/utils/Utils.js @@ -0,0 +1,6 @@ +class Utils { + getValueWithDefault(condition, value, defaultValue = "") { + return condition ? value : defaultValue; + } +} +export default Utils; diff --git a/cypress/elements/catalog/product-selectors.js b/cypress/elements/catalog/product-selectors.js index e2ef305c0..2fd93e118 100644 --- a/cypress/elements/catalog/product-selectors.js +++ b/cypress/elements/catalog/product-selectors.js @@ -13,9 +13,20 @@ export const PRODUCTS_SELECTORS = { saveBtn: "[data-test='button-bar-confirm']", confirmationMsg: "[data-test='notification-success']", channelAvailabilityItem: "[data-test='channel-availability-item']", + searchProducts: "[placeholder='Search Products...']", availableManageButton: "[data-test-id='channels-availiability-manage-button']", channelsAvailabilityForm: "[data-test-id='manage-products-channels-availiability-list']", + channelAvailabilityColumn: + "[data-test='availability'][data-test-availability='true']", + channelAvailabilityList: "ul[role='menu']", + goBackButton: "[data-test-id='app-header-back-button']", + assignedChannels: "[data-test='channel-availability-item']", + publishedRadioButtons: "[name*='isPublished']", + availableForPurchaseRadioButtons: "[name*='isAvailableForPurchase']", + radioButtonsValueTrue: "[value='true']", + radioButtonsValueFalse: "[value='false']", + visibleInListingsButton: "[name*='visibleInListings']", emptyProductRow: "[class*='Skeleton']" }; diff --git a/cypress/integration/channels.js b/cypress/integration/channels.js index bfee7abae..0f64da273 100644 --- a/cypress/integration/channels.js +++ b/cypress/integration/channels.js @@ -44,10 +44,13 @@ describe("Channels", () => { it("should create new channel", () => { 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); // New channel should be visible in channels list - cy.waitForGraph("Channel") + cy.wait("@Channel") .get(ADD_CHANNEL_FORM_SELECTORS.backToChannelsList) .click() .get(CHANNELS_SELECTORS.channelsTable) @@ -62,7 +65,9 @@ describe("Channels", () => { .click(); // 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) .first() .click() @@ -103,15 +108,18 @@ describe("Channels", () => { randomChannelToDelete, currency ); - cy.visit(urlList.channels).waitForGraph("Channels"); + cy.addAliasToGraphRequest("Channels"); + cy.visit(urlList.channels); + cy.wait("@Channels"); cy.get(CHANNELS_SELECTORS.channelName) .contains(randomChannelToDelete) .parentsUntil(CHANNELS_SELECTORS.channelsTable) .find("button") - .click() - .get(BUTTON_SELECTORS.submit) - .click() - .waitForGraph("Channels"); + .click(); + cy.addAliasToGraphRequest("Channels"); + cy.get(BUTTON_SELECTORS.submit).click(); + cy.wait("@Channels"); + cy.get(CHANNELS_SELECTORS.channelName) .contains(randomChannelToDelete) .should("not.exist"); diff --git a/cypress/integration/homePage.js b/cypress/integration/homePage.js index 74e8762a1..3712afd56 100644 --- a/cypress/integration/homePage.js +++ b/cypress/integration/homePage.js @@ -11,7 +11,7 @@ import ProductsUtils from "../utils/productsUtils"; import ShippingUtils from "../utils/shippingUtils"; // -describe("User authorization", () => { +describe("Homepage analytics", () => { const startsWith = "Cy-"; const customer = new Customer(); @@ -48,12 +48,12 @@ describe("User authorization", () => { ) .then(resp => { customerId = resp.body.data.customerCreate.user.id; - shippingUtils.createShipping( - defaultChannel.id, - randomName, - addresses.plAddress, - shippingPrice - ); + shippingUtils.createShipping({ + channelId: defaultChannel.id, + name: randomName, + address: addresses.plAddress, + price: shippingPrice + }); }) .then(() => { productsUtils.createTypeAttributeAndCategoryForProduct(randomName); @@ -63,16 +63,16 @@ describe("User authorization", () => { const productType = productsUtils.getProductType(); const attribute = productsUtils.getAttribute(); const category = productsUtils.getCategory(); - productsUtils.createProductInChannel( - randomName, - defaultChannel.id, - warehouse.id, - 20, - productType.id, - attribute.id, - category.id, - productPrice - ); + productsUtils.createProductInChannel({ + name: randomName, + channelId: defaultChannel.id, + warehouseId: warehouse.id, + quantityInWarehouse: 20, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id, + price: productPrice + }); }); }); @@ -154,16 +154,16 @@ describe("User authorization", () => { const attribute = productsUtils.getAttribute(); const category = productsUtils.getCategory(); - productsOutOfStockUtils.createProductInChannel( - productOutOfStockRandomName, - defaultChannel.id, - warehouse.id, - 0, - productType.id, - attribute.id, - category.id, - productPrice - ); + productsOutOfStockUtils.createProductInChannel({ + name: productOutOfStockRandomName, + channelId: defaultChannel.id, + warehouseId: warehouse.id, + quantityInWarehouse: 0, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id, + price: productPrice + }); cy.get("@productsOutOfStock").then(productsOutOfStockBefore => { const allProductsOutOfStock = productsOutOfStockBefore + 1; diff --git a/cypress/integration/products/menageProducts/availableForPurchaseProducts.js b/cypress/integration/products/menageProducts/availableForPurchaseProducts.js new file mode 100644 index 000000000..39413c295 --- /dev/null +++ b/cypress/integration/products/menageProducts/availableForPurchaseProducts.js @@ -0,0 +1,114 @@ +import faker from "faker"; + +import ProductSteps from "../../../steps/productSteps"; +import { productDetailsUrl } from "../../../url/urlList"; +import ChannelsUtils from "../../../utils/channelsUtils"; +import ProductsUtils from "../../../utils/productsUtils"; +import ShippingUtils from "../../../utils/shippingUtils"; +import { isProductAvailableForPurchase } from "../../../utils/storeFront/storeFrontProductUtils"; + +// +describe("Products available in listings", () => { + const shippingUtils = new ShippingUtils(); + const channelsUtils = new ChannelsUtils(); + const productsUtils = new ProductsUtils(); + const productSteps = new ProductSteps(); + const startsWith = "Cy-"; + const name = `${startsWith}${faker.random.number()}`; + let productType; + let attribute; + let category; + let defaultChannel; + let warehouse; + + before(() => { + cy.clearSessionData().loginUserViaRequest(); + shippingUtils.deleteShipping(startsWith); + productsUtils.deleteProperProducts(startsWith); + + channelsUtils + .getDefaultChannel() + .then(channel => { + defaultChannel = channel; + cy.fixture("addresses"); + }) + .then(addressesFixture => { + shippingUtils.createShipping({ + channelId: defaultChannel.id, + name, + address: addressesFixture.plAddress + }); + }) + .then(() => { + warehouse = shippingUtils.getWarehouse(); + }); + + productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { + productType = productsUtils.getProductType(); + attribute = productsUtils.getAttribute(); + category = productsUtils.getCategory(); + }); + }); + + beforeEach(() => { + cy.clearSessionData().loginUserViaRequest(); + }); + + it("should update product to available for purchase", () => { + const productName = `${startsWith}${faker.random.number()}`; + productsUtils + .createProductInChannel({ + name: productName, + channelId: defaultChannel.id, + warehouseId: warehouse.id, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id, + isAvailableForPurchase: false + }) + .then(() => { + const productUrl = productDetailsUrl( + productsUtils.getCreatedProduct().id + ); + productSteps.updateProductIsAvailableForPurchase(productUrl, true); + }) + .then(() => { + isProductAvailableForPurchase( + productsUtils.getCreatedProduct().id, + defaultChannel.slug, + productName + ); + }) + .then(isVisibleResp => { + expect(isVisibleResp).to.be.eq(true); + }); + }); + it("should update product to not available for purchase", () => { + const productName = `${startsWith}${faker.random.number()}`; + productsUtils + .createProductInChannel({ + name: productName, + channelId: defaultChannel.id, + warehouseId: warehouse.id, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id + }) + .then(() => { + const productUrl = productDetailsUrl( + productsUtils.getCreatedProduct().id + ); + productSteps.updateProductIsAvailableForPurchase(productUrl, false); + }) + .then(() => { + isProductAvailableForPurchase( + productsUtils.getCreatedProduct().id, + defaultChannel.slug, + productName + ); + }) + .then(isProductVisible => { + expect(isProductVisible).to.be.eq(false); + }); + }); +}); diff --git a/cypress/integration/products/menageProducts/publishedProducts.js b/cypress/integration/products/menageProducts/publishedProducts.js new file mode 100644 index 000000000..974f5756d --- /dev/null +++ b/cypress/integration/products/menageProducts/publishedProducts.js @@ -0,0 +1,95 @@ +import faker from "faker"; + +import ProductSteps from "../../../steps/productSteps"; +import { productDetailsUrl } from "../../../url/urlList"; +import ChannelsUtils from "../../../utils/channelsUtils"; +import ProductsUtils from "../../../utils/productsUtils"; +import { isProductVisible } from "../../../utils/storeFront/storeFrontProductUtils"; + +// +describe("Published products", () => { + const channelsUtils = new ChannelsUtils(); + const productsUtils = new ProductsUtils(); + const productSteps = new ProductSteps(); + + const startsWith = "Cy-"; + const name = `${startsWith}${faker.random.number()}`; + let productType; + let attribute; + let category; + + before(() => { + cy.clearSessionData().loginUserViaRequest(); + productsUtils.deleteProperProducts(startsWith); + productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { + productType = productsUtils.getProductType(); + attribute = productsUtils.getAttribute(); + category = productsUtils.getCategory(); + }); + }); + + beforeEach(() => { + cy.clearSessionData().loginUserViaRequest(); + }); + it("should update product to published", () => { + const productName = `${startsWith}${faker.random.number()}`; + let defaultChannel; + channelsUtils + .getDefaultChannel() + .then(channel => { + defaultChannel = channel; + productsUtils.createProductInChannel({ + name: productName, + channelId: defaultChannel.id, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id, + isPublished: false, + isAvailableForPurchase: false + }); + }) + .then(() => { + const product = productsUtils.getCreatedProduct(); + const productUrl = productDetailsUrl(product.id); + productSteps.updateProductPublish(productUrl, true); + isProductVisible(product.id, defaultChannel.slug, productName); + }) + .then(isVisible => { + expect(isVisible).to.be.eq(true); + }); + }); + it("should update product to not published", () => { + const productName = `${startsWith}${faker.random.number()}`; + let defaultChannel; + let product; + + channelsUtils + .getDefaultChannel() + .then(channel => { + defaultChannel = channel; + productsUtils.createProductInChannel({ + name: productName, + channelId: defaultChannel.id, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id + }); + }) + .then(() => { + product = productsUtils.getCreatedProduct(); + const productUrl = productDetailsUrl(product.id); + productSteps.updateProductPublish(productUrl, false); + isProductVisible(product.id, defaultChannel.slug, productName); + }) + .then(isVisible => { + expect(isVisible).to.be.eq(false); + cy.loginInShop(); + }) + .then(() => { + isProductVisible(product.id, defaultChannel.slug, productName); + }) + .then(isVisible => { + expect(isVisible).to.be.eq(true); + }); + }); +}); diff --git a/cypress/integration/products/menageProducts/visibleInListingsProducts.js b/cypress/integration/products/menageProducts/visibleInListingsProducts.js new file mode 100644 index 000000000..b41dc2df9 --- /dev/null +++ b/cypress/integration/products/menageProducts/visibleInListingsProducts.js @@ -0,0 +1,95 @@ +import faker from "faker"; + +import ProductSteps from "../../../steps/productSteps"; +import { productDetailsUrl } from "../../../url/urlList"; +import ChannelsUtils from "../../../utils/channelsUtils"; +import ProductsUtils from "../../../utils/productsUtils"; +import { isProductVisibleInSearchResult } from "../../../utils/storeFront/storeFrontProductUtils"; + +// +describe("Products displayed in listings", () => { + const channelsUtils = new ChannelsUtils(); + const productsUtils = new ProductsUtils(); + const productSteps = new ProductSteps(); + + const startsWith = "Cy-"; + const name = `${startsWith}${faker.random.number()}`; + let productType; + let attribute; + let category; + + before(() => { + cy.clearSessionData().loginUserViaRequest(); + productsUtils.deleteProperProducts(startsWith); + productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { + productType = productsUtils.getProductType(); + attribute = productsUtils.getAttribute(); + category = productsUtils.getCategory(); + }); + }); + + beforeEach(() => { + cy.clearSessionData().loginUserViaRequest(); + }); + it("should update product to visible in listings", () => { + const productName = `${startsWith}${faker.random.number()}`; + let defaultChannel; + channelsUtils + .getDefaultChannel() + .then(channel => { + defaultChannel = channel; + productsUtils.createProductInChannel({ + name: productName, + channelId: defaultChannel.id, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id, + visibleInListings: false, + isAvailableForPurchase: false + }); + }) + .then(() => { + const product = productsUtils.getCreatedProduct(); + const productUrl = productDetailsUrl(product.id); + productSteps.updateProductVisibleInListings(productUrl); + isProductVisibleInSearchResult(productName, defaultChannel.slug); + }) + .then(isProductVisible => { + expect(isProductVisible).to.be.eq(true); + }); + }); + it("should update product to not visible in listings", () => { + const productName = `${startsWith}${faker.random.number()}`; + let defaultChannel; + channelsUtils + .getDefaultChannel() + .then(channel => { + defaultChannel = channel; + productsUtils.createProductInChannel({ + name: productName, + channelId: defaultChannel.id, + productTypeId: productType.id, + attributeId: attribute.id, + categoryId: category.id, + visibleInListings: true + }); + }) + .then(() => { + const product = productsUtils.getCreatedProduct(); + const productUrl = productDetailsUrl(product.id); + productSteps.updateProductVisibleInListings(productUrl); + isProductVisibleInSearchResult(productName, defaultChannel.slug).then( + isProductVisible => { + expect(isProductVisible).to.be.eq(false); + } + ); + cy.loginInShop(); + }) + .then(() => { + isProductVisibleInSearchResult(productName, defaultChannel.slug); + }) + .then(isProductVisible => { + expect(isProductVisible).to.be.eq(true); + }); + }); +}); diff --git a/cypress/integration/products.js b/cypress/integration/products/products.js similarity index 87% rename from cypress/integration/products.js rename to cypress/integration/products/products.js index f1e8f5468..87960c269 100644 --- a/cypress/integration/products.js +++ b/cypress/integration/products/products.js @@ -1,7 +1,7 @@ // -import { LEFT_MENU_SELECTORS } from "../elements/account/left-menu/left-menu-selectors"; -import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors"; -import { urlList } from "../url/urlList"; +import { LEFT_MENU_SELECTORS } from "../../elements/account/left-menu/left-menu-selectors"; +import { PRODUCTS_SELECTORS } from "../../elements/catalog/product-selectors"; +import { urlList } from "../../url/urlList"; describe("Products", () => { beforeEach(() => { diff --git a/cypress/steps/homePageSteps.js b/cypress/steps/homePageSteps.js index bd53c0972..72b9c6d96 100644 --- a/cypress/steps/homePageSteps.js +++ b/cypress/steps/homePageSteps.js @@ -1,12 +1,12 @@ import { HEADER_SELECTORS } from "../elements/header/header-selectors"; class HomePageSteps { changeChannel(channelName) { - cy.get(HEADER_SELECTORS.channelSelect) - .click() - .get(HEADER_SELECTORS.channelSelectList) + cy.get(HEADER_SELECTORS.channelSelect).click(); + cy.addAliasToGraphRequest("Home"); + cy.get(HEADER_SELECTORS.channelSelectList) .contains(channelName) - .click() - .waitForGraph("Home"); + .click(); + cy.wait("@Home"); } } export default HomePageSteps; diff --git a/cypress/steps/productSteps.js b/cypress/steps/productSteps.js new file mode 100644 index 000000000..eec8c3736 --- /dev/null +++ b/cypress/steps/productSteps.js @@ -0,0 +1,37 @@ +import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors"; + +class ProductSteps { + valueTrue = PRODUCTS_SELECTORS.radioButtonsValueTrue; + valueFalse = PRODUCTS_SELECTORS.radioButtonsValueFalse; + + updateProductIsAvailableForPurchase(productUrl, isAvailableForPurchase) { + const isAvailableForPurchaseSelector = isAvailableForPurchase + ? this.valueTrue + : this.valueFalse; + const availableForPurchaseSelector = `${PRODUCTS_SELECTORS.availableForPurchaseRadioButtons}${isAvailableForPurchaseSelector}`; + this.updateProductMenageInChannel(productUrl, availableForPurchaseSelector); + } + updateProductPublish(productUrl, isPublished) { + const isPublishedSelector = isPublished ? this.valueTrue : this.valueFalse; + const publishedSelector = `${PRODUCTS_SELECTORS.publishedRadioButtons}${isPublishedSelector}`; + this.updateProductMenageInChannel(productUrl, publishedSelector); + } + updateProductVisibleInListings(productUrl) { + this.updateProductMenageInChannel( + productUrl, + PRODUCTS_SELECTORS.visibleInListingsButton + ); + } + updateProductMenageInChannel(productUrl, menageSelector) { + cy.visit(productUrl) + .get(PRODUCTS_SELECTORS.assignedChannels) + .click() + .get(menageSelector) + .click(); + cy.addAliasToGraphRequest("ProductChannelListingUpdate"); + cy.get(PRODUCTS_SELECTORS.saveBtn) + .click() + .wait("@ProductChannelListingUpdate"); + } +} +export default ProductSteps; diff --git a/cypress/support/index.js b/cypress/support/index.js index f6115623a..fbeac6e3a 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -21,7 +21,7 @@ Cypress.Commands.add("clearSessionData", () => { }); }); -Cypress.Commands.add("waitForGraph", operationName => { +Cypress.Commands.add("addAliasToGraphRequest", operationName => { cy.intercept("POST", urlList.apiUri, req => { req.statusCode = 200; const requestBody = req.body; @@ -37,10 +37,9 @@ Cypress.Commands.add("waitForGraph", operationName => { } } }); - cy.wait(`@${operationName}`); }); -Cypress.Commands.add("sendRequestWithQuery", query => +Cypress.Commands.add("sendRequestWithQuery", (query, authorization = "auth") => cy.request({ body: { method: "POST", @@ -48,7 +47,7 @@ Cypress.Commands.add("sendRequestWithQuery", query => url: urlList.apiUri }, headers: { - Authorization: `JWT ${window.sessionStorage.getItem("auth")}` + Authorization: `JWT ${window.sessionStorage.getItem(authorization)}` }, method: "POST", url: urlList.apiUri diff --git a/cypress/support/user/index.js b/cypress/support/user/index.js index 3b43e3dfe..33fcc4adc 100644 --- a/cypress/support/user/index.js +++ b/cypress/support/user/index.js @@ -1,5 +1,4 @@ import { LOGIN_SELECTORS } from "../../elements/account/login-selectors"; -import { urlList } from "../../url/urlList"; Cypress.Commands.add("loginUser", () => cy @@ -11,38 +10,30 @@ Cypress.Commands.add("loginUser", () => .click() ); -Cypress.Commands.add("loginUserViaRequest", () => { - const logInMutationQuery = `mutation TokenAuth($email: String!, $password: String!) { - tokenCreate(email: $email, password: $password) { +Cypress.Commands.add("loginInShop", () => { + cy.loginUserViaRequest("token"); +}); + +Cypress.Commands.add("loginUserViaRequest", (authorization = "auth") => { + const mutation = `mutation TokenAuth{ + tokenCreate(email: "${Cypress.env("USER_NAME")}", password: "${Cypress.env( + "USER_PASSWORD" + )}") { token errors: accountErrors { code field message - __typename } user { id - __typename } - __typename } }`; - - return cy - .request({ - body: { - 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); - }); + return cy.sendRequestWithQuery(mutation, authorization).then(resp => { + window.sessionStorage.setItem( + authorization, + resp.body.data.tokenCreate.token + ); + }); }); diff --git a/cypress/url/urlList.js b/cypress/url/urlList.js index 2ceb592c5..c469ba6e6 100644 --- a/cypress/url/urlList.js +++ b/cypress/url/urlList.js @@ -7,3 +7,4 @@ export const urlList = { products: "products/", warehouses: "warehouses/" }; +export const productDetailsUrl = productId => `${urlList.products}${productId}`; diff --git a/cypress/utils/productsUtils.js b/cypress/utils/productsUtils.js index 43fba4be3..2ac9f0ce7 100644 --- a/cypress/utils/productsUtils.js +++ b/cypress/utils/productsUtils.js @@ -13,19 +13,37 @@ class ProductsUtils { attribute; category; - createProductInChannel( + createProductWithVariant(name, attributeId, productTypeId, categoryId) { + return this.createProduct( + attributeId, + name, + productTypeId, + categoryId + ).then(() => this.createVariant(this.product.id, name)); + } + + createProductInChannel({ name, channelId, - warehouseId, - quantityInWarehouse, + warehouseId = null, + quantityInWarehouse = 10, productTypeId, attributeId, categoryId, - price - ) { + price = 1, + isPublished = true, + isAvailableForPurchase = true, + visibleInListings = true + }) { return this.createProduct(attributeId, name, productTypeId, categoryId) .then(() => - this.productRequest.updateChannelInProduct(this.product.id, channelId) + this.productRequest.updateChannelInProduct({ + productId: this.product.id, + channelId, + isPublished, + isAvailableForPurchase, + visibleInListings + }) ) .then(() => { this.createVariant( @@ -92,7 +110,9 @@ class ProductsUtils { resp.body.data.productVariantBulkCreate.productVariants) ); } - + getCreatedProduct() { + return this.product; + } getCreatedVariants() { return this.variants; } diff --git a/cypress/utils/shippingUtils.js b/cypress/utils/shippingUtils.js index 1fb352907..75eb7501f 100644 --- a/cypress/utils/shippingUtils.js +++ b/cypress/utils/shippingUtils.js @@ -8,7 +8,7 @@ class ShippingUtils { shippingZone; warehouse; - createShipping(channelId, name, address, price) { + createShipping({ channelId, name, address, price = 1 }) { return this.createShippingZone(name, address.country) .then(() => this.createWarehouse(name, this.shippingZone.id, address)) .then(() => this.createShippingRate(name, this.shippingZone.id)) diff --git a/cypress/utils/storeFront/storeFrontProductUtils.js b/cypress/utils/storeFront/storeFrontProductUtils.js new file mode 100644 index 000000000..854c3f79a --- /dev/null +++ b/cypress/utils/storeFront/storeFrontProductUtils.js @@ -0,0 +1,32 @@ +import ProductDetails from "../../apiRequests/storeFront/ProductDetails"; +import Search from "../../apiRequests/storeFront/Search"; + +export const isProductVisible = (productId, channelSlug, name) => { + const productDetails = new ProductDetails(); + return productDetails + .getProductDetails(productId, channelSlug) + .then(productDetailsResp => { + const product = productDetailsResp.body.data.product; + return product !== null && product.name === name; + }); +}; + +export const isProductAvailableForPurchase = (productId, channelSlug) => { + const productDetails = new ProductDetails(); + return productDetails + .getProductDetails(productId, channelSlug) + .then( + productDetailsResp => + productDetailsResp.body.data.product.isAvailableForPurchase + ); +}; +export const 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 + ); +};