From a3115836471bd8d054d044d9f0e2f67a27173940 Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Mon, 22 Nov 2021 15:57:20 +0400 Subject: [PATCH] Add tests for creating products without sku (#1550) * create products without sku * update stories * update stories --- .../catalog/products/product-details.js | 7 +- .../catalog/products/variants-selectors.js | 3 +- .../createProductWithoutSku.js | 243 ++++++++++++++++++ cypress/support/api/requests/ProductType.js | 17 ++ .../storeFront/storeFrontProductUtils.js | 1 + .../pages/catalog/products/VariantsPage.js | 45 ++-- .../ProductStocks/ProductStocks.tsx | 1 + .../ProductVariantCreatorStock.tsx | 1 + .../__snapshots__/Stories.test.ts.snap | 4 + 9 files changed, 304 insertions(+), 18 deletions(-) create mode 100644 cypress/integration/products/produkctsWithoutSku/createProductWithoutSku.js diff --git a/cypress/elements/catalog/products/product-details.js b/cypress/elements/catalog/products/product-details.js index bc234f018..254e7972b 100644 --- a/cypress/elements/catalog/products/product-details.js +++ b/cypress/elements/catalog/products/product-details.js @@ -23,5 +23,10 @@ export const PRODUCT_DETAILS = { uploadImageButton: '[data-test="button-upload-image"]', uploadSavedImagesButton: '[data-test="uploadImages"]', uploadMediaUrlButton: '[data-test="uploadMediaUrl"]', - saveUploadUrlButton: '[data-test-id="upload-url-button"]' + saveUploadUrlButton: '[data-test-id="upload-url-button"]', + addWarehouseButton: '[data-test-id="add-warehouse"]', + warehouseOption: "[role='menuitem']", + stockInput: '[data-test-id="stock-input"]', + costPriceInput: '[name*="costPrice"]', + sellingPriceInput: '[name*="channel-price"]' }; diff --git a/cypress/elements/catalog/products/variants-selectors.js b/cypress/elements/catalog/products/variants-selectors.js index ba21c4434..744127469 100644 --- a/cypress/elements/catalog/products/variants-selectors.js +++ b/cypress/elements/catalog/products/variants-selectors.js @@ -9,5 +9,6 @@ export const VARIANTS_SELECTORS = { addWarehouseButton: "button[class*='MuiIconButton-colorPrimary']", warehouseOption: "[role='menuitem']", saveButton: "[data-test='button-bar-confirm']", - skuInputInAddVariant: "[name='sku']" + skuInputInAddVariant: "[name='sku']", + stockInput: "[data-test-id='stock-input']" }; diff --git a/cypress/integration/products/produkctsWithoutSku/createProductWithoutSku.js b/cypress/integration/products/produkctsWithoutSku/createProductWithoutSku.js new file mode 100644 index 000000000..3ce148aa8 --- /dev/null +++ b/cypress/integration/products/produkctsWithoutSku/createProductWithoutSku.js @@ -0,0 +1,243 @@ +/// +/// + +import faker from "faker"; + +import { PRODUCT_DETAILS } from "../../../elements/catalog/products/product-details"; +import { PRODUCTS_LIST } from "../../../elements/catalog/products/products-list"; +import { AVAILABLE_CHANNELS_FORM } from "../../../elements/channels/available-channels-form"; +import { BUTTON_SELECTORS } from "../../../elements/shared/button-selectors"; +import { urlList } from "../../../fixtures/urlList"; +import { ONE_PERMISSION_USERS } from "../../../fixtures/users"; +import { + createProduct, + updateChannelInProduct +} from "../../../support/api/requests/Product"; +import { createTypeProduct } from "../../../support/api/requests/ProductType"; +import { + deleteChannelsStartsWith, + getDefaultChannel +} from "../../../support/api/utils/channelsUtils"; +import { createWaitingForCaptureOrder } from "../../../support/api/utils/ordersUtils"; +import * as productUtils from "../../../support/api/utils/products/productsUtils"; +import * as shippingUtils from "../../../support/api/utils/shippingUtils"; +import { getProductVariants } from "../../../support/api/utils/storeFront/storeFrontProductUtils"; +import filterTests from "../../../support/filterTests"; +import { + createFirstVariant, + createVariant +} from "../../../support/pages/catalog/products/VariantsPage"; +import { selectChannelInDetailsPages } from "../../../support/pages/channelsPage"; + +filterTests({ definedTags: ["all", "critical"], version: "3.1.0" }, () => { + describe("Creating variants", () => { + const startsWith = "CyCreateVariants-"; + const attributeValues = ["value1", "value2"]; + + let defaultChannel; + let warehouse; + let attribute; + let productType; + let simpleProductType; + let category; + let shippingMethod; + let address; + + before(() => { + cy.clearSessionData().loginUserViaRequest(); + shippingUtils.deleteShippingStartsWith(startsWith); + productUtils.deleteProductsStartsWith(startsWith); + deleteChannelsStartsWith(startsWith); + + const name = `${startsWith}${faker.datatype.number()}`; + const simpleProductTypeName = `${startsWith}${faker.datatype.number()}`; + getDefaultChannel() + .then(channel => { + defaultChannel = channel; + cy.fixture("addresses"); + }) + .then(fixtureAddresses => { + address = fixtureAddresses.plAddress; + shippingUtils.createShipping({ + channelId: defaultChannel.id, + name, + address + }); + }) + .then( + ({ + warehouse: warehouseResp, + shippingMethod: shippingMethodResp + }) => { + warehouse = warehouseResp; + shippingMethod = shippingMethodResp; + } + ); + productUtils + .createTypeAttributeAndCategoryForProduct({ name, attributeValues }) + .then( + ({ + attribute: attributeResp, + productType: productTypeResp, + category: categoryResp + }) => { + attribute = attributeResp; + productType = productTypeResp; + category = categoryResp; + createTypeProduct({ + name: simpleProductTypeName, + attributeId: attribute.id, + hasVariants: false + }); + } + ) + .then(type => { + simpleProductType = type; + }); + }); + + beforeEach(() => { + cy.clearSessionData().loginUserViaRequest( + "auth", + ONE_PERMISSION_USERS.product + ); + }); + + it("should create variant without sku by variant creator", () => { + const name = `${startsWith}${faker.datatype.number()}`; + const price = 10; + let createdProduct; + + createProduct({ + attributeId: attribute.id, + name, + productTypeId: productType.id, + categoryId: category.id + }) + .then(resp => { + createdProduct = resp; + updateChannelInProduct({ + productId: createdProduct.id, + channelId: defaultChannel.id + }); + cy.visit(`${urlList.products}${createdProduct.id}`); + createFirstVariant({ + warehouseId: warehouse.id, + price, + attribute: attributeValues[0] + }); + getProductVariants(createdProduct.id, defaultChannel.slug); + }) + .then(([variant]) => { + expect(variant).to.have.property("name", attributeValues[0]); + expect(variant).to.have.property("price", price); + createWaitingForCaptureOrder({ + channelSlug: defaultChannel.slug, + email: "example@example.com", + variantsList: [variant], + shippingMethodId: shippingMethod.id, + address + }); + }) + .then(({ order }) => { + expect(order.id).to.be.ok; + }); + }); + + it("should create variant without sku", () => { + const name = `${startsWith}${faker.datatype.number()}`; + const variants = [{ price: 7 }, { name: attributeValues[1], price: 16 }]; + let createdProduct; + + productUtils + .createProductInChannel({ + name, + attributeId: attribute.id, + channelId: defaultChannel.id, + warehouseId: warehouse.id, + productTypeId: productType.id, + categoryId: category.id, + price: variants[0].price + }) + .then(({ product: productResp }) => { + createdProduct = productResp; + cy.visit(`${urlList.products}${createdProduct.id}`); + createVariant({ + warehouseName: warehouse.name, + attributeName: variants[1].name, + price: variants[1].price, + channelName: defaultChannel.name + }); + }) + .then(() => { + getProductVariants(createdProduct.id, defaultChannel.slug); + }) + .then(([firstVariant, secondVariant]) => { + expect(firstVariant).to.have.property("price", variants[0].price); + expect(secondVariant).to.have.property("name", variants[1].name); + expect(secondVariant).to.have.property("price", variants[1].price); + createWaitingForCaptureOrder({ + channelSlug: defaultChannel.slug, + email: "example@example.com", + variantsList: [secondVariant], + shippingMethodId: shippingMethod.id, + address + }); + }) + .then(({ order }) => { + expect(order.id).to.be.ok; + }); + }); + + it("should create simple product without sku", () => { + const name = `${startsWith}${faker.datatype.number()}`; + cy.visit(urlList.products) + .get(PRODUCTS_LIST.createProductBtn) + .click() + .get(PRODUCT_DETAILS.productNameInput) + .type(name) + .fillAutocompleteSelect( + PRODUCT_DETAILS.productTypeInput, + simpleProductType.name + ) + .fillAutocompleteSelect(PRODUCT_DETAILS.categoryInput); + selectChannelInDetailsPages(defaultChannel.name); + cy.get(PRODUCT_DETAILS.addWarehouseButton).click(); + cy.contains(PRODUCT_DETAILS.warehouseOption, warehouse.name) + .click() + .get(PRODUCT_DETAILS.stockInput) + .clearAndType(10) + .get(PRODUCT_DETAILS.costPriceInput) + .type(10) + .get(PRODUCT_DETAILS.sellingPriceInput) + .type(10) + .get(AVAILABLE_CHANNELS_FORM.assignedChannels) + .click() + .get( + `${AVAILABLE_CHANNELS_FORM.availableForPurchaseRadioButtons}${AVAILABLE_CHANNELS_FORM.radioButtonsValueTrue}` + ) + .click() + .get( + `${AVAILABLE_CHANNELS_FORM.publishedRadioButtons}${AVAILABLE_CHANNELS_FORM.radioButtonsValueTrue}` + ) + .click() + .addAliasToGraphRequest("VariantCreate") + .get(BUTTON_SELECTORS.confirm) + .click() + .confirmationMessageShouldDisappear() + .wait("@VariantCreate") + .then(({ response }) => { + const variants = [ + response.body.data.productVariantCreate.productVariant + ]; + createWaitingForCaptureOrder({ + channelSlug: defaultChannel.slug, + email: "example@example.com", + variantsList: variants, + shippingMethodId: shippingMethod.id, + address + }); + }); + }); + }); +}); diff --git a/cypress/support/api/requests/ProductType.js b/cypress/support/api/requests/ProductType.js index 5432a0139..6aa56216c 100644 --- a/cypress/support/api/requests/ProductType.js +++ b/cypress/support/api/requests/ProductType.js @@ -90,6 +90,23 @@ export function deleteProductType(productTypeId) { return cy.sendRequestWithQuery(mutation); } +export function productAttributeAssignmentUpdate({ + productTypeId, + attributeId, + variantSelection = true +}) { + const mutation = `mutation { + productAttributeAssignmentUpdate( + operations: {id: "${attributeId}", variantSelection: ${variantSelection}} productTypeId:"${productTypeId}") { + errors { + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); +} + export function getProductType(productTypeId) { const query = `query{ productType(id:"${productTypeId}"){ diff --git a/cypress/support/api/utils/storeFront/storeFrontProductUtils.js b/cypress/support/api/utils/storeFront/storeFrontProductUtils.js index 10581f92d..8d0213631 100644 --- a/cypress/support/api/utils/storeFront/storeFrontProductUtils.js +++ b/cypress/support/api/utils/storeFront/storeFrontProductUtils.js @@ -22,6 +22,7 @@ export const getProductVariants = (productId, channelSlug) => { getProductDetails(productId, channelSlug).then(resp => { const variantsList = resp.body.data.product.variants; return variantsList.map(element => ({ + id: element.id, name: element.name, price: element.pricing.price.gross.amount })); diff --git a/cypress/support/pages/catalog/products/VariantsPage.js b/cypress/support/pages/catalog/products/VariantsPage.js index 4363f956e..ae4077e47 100644 --- a/cypress/support/pages/catalog/products/VariantsPage.js +++ b/cypress/support/pages/catalog/products/VariantsPage.js @@ -6,12 +6,18 @@ import { BUTTON_SELECTORS } from "../../../../elements/shared/button-selectors"; import { selectChannelVariantInDetailsPage } from "../../channelsPage"; import { fillUpPriceList } from "./priceListComponent"; -export function variantsShouldBeVisible({ name, price }) { - cy.contains(PRODUCT_DETAILS.variantRow, name).should("be.visible"); +export function variantsShouldBeVisible({ price }) { + cy.get(PRODUCT_DETAILS.variantRow).should("be.visible"); cy.contains(PRODUCT_DETAILS.variantPrice, price); } -export function createFirstVariant({ sku, warehouseId, price, attribute }) { +export function createFirstVariant({ + sku, + warehouseId, + price, + attribute, + quantity = 1 +}) { cy.get(PRODUCT_DETAILS.addVariantsButton).click(); cy.get(PRODUCT_DETAILS.addVariantsOptionDialog.optionMultiple).click(); cy.get(BUTTON_SELECTORS.submit).click(); @@ -24,11 +30,14 @@ export function createFirstVariant({ sku, warehouseId, price, attribute }) { fillUpPriceList(price); cy.get(`[name*='${warehouseId}']`) .click() + .get(VARIANTS_SELECTORS.stockInput) + .type(quantity) .get(VARIANTS_SELECTORS.nextButton) - .click() - .get(VARIANTS_SELECTORS.skuInput) - .type(sku) - .addAliasToGraphRequest("ProductVariantBulkCreate") + .click(); + if (sku) { + cy.get(VARIANTS_SELECTORS.skuInput).type(sku); + } + cy.addAliasToGraphRequest("ProductVariantBulkCreate") .get(VARIANTS_SELECTORS.nextButton) .click() .waitForRequestAndCheckIfNoErrors("@ProductVariantBulkCreate") @@ -43,7 +52,8 @@ export function createVariant({ attributeName, price, costPrice = price, - channelName + channelName, + quantity = 10 }) { cy.get(PRODUCT_DETAILS.addVariantsButton) .click() @@ -51,15 +61,18 @@ export function createVariant({ .click() .get(VARIANTS_SELECTORS.attributeOption) .contains(attributeName) - .click() - .get(VARIANTS_SELECTORS.skuInputInAddVariant) - .type(sku) - .get(VARIANTS_SELECTORS.addWarehouseButton) .click(); - cy.contains(VARIANTS_SELECTORS.warehouseOption, warehouseName).click({ - force: true - }); - cy.get(VARIANTS_SELECTORS.saveButton) + if (sku) { + cy.get(VARIANTS_SELECTORS.skuInputInAddVariant).type(sku); + } + cy.get(VARIANTS_SELECTORS.addWarehouseButton).click(); + cy.contains(VARIANTS_SELECTORS.warehouseOption, warehouseName) + .click({ + force: true + }) + .get(VARIANTS_SELECTORS.stockInput) + .type(quantity) + .get(VARIANTS_SELECTORS.saveButton) .click() .get(BUTTON_SELECTORS.back) .click() diff --git a/src/products/components/ProductStocks/ProductStocks.tsx b/src/products/components/ProductStocks/ProductStocks.tsx index 2b2f1b035..92669916e 100644 --- a/src/products/components/ProductStocks/ProductStocks.tsx +++ b/src/products/components/ProductStocks/ProductStocks.tsx @@ -375,6 +375,7 @@ const ProductStocks: React.FC = ({ = pr }