resolve conflicts

This commit is contained in:
Karolina Rakoczy 2021-03-04 13:58:01 +01:00
commit b6093e3fc5
22 changed files with 348 additions and 37 deletions

View file

@ -1,13 +1,17 @@
class Attribute {
createAttribute(name) {
createAttribute(name, attributeValues = ["value"]) {
attributeValues = attributeValues.map(element => `{name:"${element}"}`);
const mutation = `mutation{
attributeCreate(input:{
name:"${name}"
valueRequired:false
type:PRODUCT_TYPE
values: [${attributeValues}]
}){
attribute{
id
name
values{name}
}
attributeErrors{
field

View file

@ -1,7 +1,6 @@
import Utils from "./utils/Utils";
import { getValueWithDefault } from "./utils/Utils";
class Product {
utils = new Utils();
getFirstProducts(first, search) {
const filter = search
? `, filter:{
@ -49,7 +48,7 @@ class Product {
}
}
}`;
cy.sendRequestWithQuery(mutation);
return cy.sendRequestWithQuery(mutation);
}
updateChannelPriceInVariant(variantId, channelId) {
@ -88,7 +87,7 @@ class Product {
return cy.sendRequestWithQuery(mutation);
}
createVariant(
createVariant({
productId,
sku,
warehouseId,
@ -96,8 +95,8 @@ class Product {
channelId,
price = 1,
costPrice = 1
) {
const channelListings = this.utils.getValueWithDefault(
}) {
const channelListings = getValueWithDefault(
channelId,
`channelListings:{
channelId:"${channelId}"
@ -106,7 +105,7 @@ class Product {
}`
);
const stocks = this.utils.getValueWithDefault(
const stocks = getValueWithDefault(
warehouseId,
`stocks:{
warehouse:"${warehouseId}"
@ -141,6 +140,7 @@ class Product {
slug: "${slug}"
isShippingRequired: true
productAttributes: "${attributeId}"
variantAttributes: "${attributeId}"
}){
productErrors{
field

View file

@ -20,6 +20,7 @@ class Warehouse {
}
warehouse{
id
name
}
}
}`;

View file

@ -4,9 +4,31 @@ class ProductDetails {
id
name
}
fragment Price on TaxedMoney {
gross {
amount
currency
}
}
fragment ProductVariantFields on ProductVariant {
id
sku
name
pricing {
price {
...Price
}
}
}
query ProductDetails{
product(id: "${productId}", channel: "${channelId}") {
...BasicProductFields
variants {
...ProductVariantFields
}
isAvailable
isAvailableForPurchase
availableForPurchase

View file

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

View file

@ -22,6 +22,8 @@ export const PRODUCTS_SELECTORS = {
channelAvailabilityList: "ul[role='menu']",
goBackButton: "[data-test-id='app-header-back-button']",
assignedChannels: "[data-test='channel-availability-item']",
publishedRadioButton: "[role=radiogroup]",
addVariantsButton: "[data-test*='button-add-variant']",
publishedRadioButtons: "[name*='isPublished']",
availableForPurchaseRadioButtons: "[name*='isAvailableForPurchase']",
radioButtonsValueTrue: "[value='true']",

View file

@ -0,0 +1,15 @@
export const VARIANTS_SELECTORS = {
attributeCheckbox: "[name*='value:']",
valueContainer: "[data-test-id='value-container']",
nextButton: "[class*='MuiButton-containedPrimary']",
priceInput: "[name*='channel-price']",
costPriceInput: "[name*='channel-costPrice']",
warehouseCheckboxes: "[name*='warehouse:']",
skuInput: "input[class*='MuiInputBase'][type='text']",
attributeSelector: "[data-test='attribute-value']",
attributeOption: "[data-test-type='option']",
addWarehouseButton: "button[class*='MuiIconButton-colorPrimary']",
warehouseOption: "[role='menuitem']",
saveButton: "[data-test='button-bar-confirm']",
skuInputInAddVariant: "[name='sku']"
};

View file

@ -1,6 +1,6 @@
import faker from "faker";
import ProductSteps from "../../../steps/productSteps";
import ProductSteps from "../../../steps/products/productSteps";
import { productDetailsUrl } from "../../../url/urlList";
import ChannelsUtils from "../../../utils/channelsUtils";
import ProductsUtils from "../../../utils/productsUtils";

View file

@ -1,6 +1,6 @@
import faker from "faker";
import ProductSteps from "../../../steps/productSteps";
import ProductSteps from "../../../steps/products/productSteps";
import { productDetailsUrl } from "../../../url/urlList";
import ChannelsUtils from "../../../utils/channelsUtils";
import ProductsUtils from "../../../utils/productsUtils";

View file

@ -1,6 +1,6 @@
import faker from "faker";
import ProductSteps from "../../../steps/productSteps";
import ProductSteps from "../../../steps/products/productSteps";
import { productDetailsUrl } from "../../../url/urlList";
import ChannelsUtils from "../../../utils/channelsUtils";
import ProductsUtils from "../../../utils/productsUtils";

View file

@ -0,0 +1,175 @@
import faker from "faker";
import Channels from "../../apiRequests/Channels";
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";
import { getProductVariants } from "../../utils/storeFront/storeFrontProductUtils";
// <reference types="cypress" />
describe("creating variants", () => {
const startsWith = "Cy-";
const attributeValues = ["value1", "value2"];
const productUtils = new ProductsUtils();
const channelsUtils = new ChannelsUtils();
const shippingUtils = new ShippingUtils();
const product = new Product();
const channels = new Channels();
const variantsSteps = new VariantsSteps();
let defaultChannel;
let warehouse;
let attribute;
let productType;
let category;
before(() => {
cy.clearSessionData().loginUserViaRequest();
shippingUtils.deleteShipping(startsWith);
productUtils.deleteProperProducts(startsWith);
channelsUtils.deleteChannels(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, attributeValues)
.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({
sku: name,
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);
});
});
it("should create several variants", () => {
const name = `${startsWith}${faker.random.number()}`;
const secondVariantSku = `${startsWith}${faker.random.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(() => {
createdProduct = productUtils.getCreatedProduct();
cy.visit(`${urlList.products}${createdProduct.id}`);
variantsSteps.createVariant({
sku: secondVariantSku,
warehouseName: warehouse.name,
attributeName: variants[1].name,
price: variants[1].price
});
})
.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);
});
});
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({
sku: name,
warehouseId: warehouse.id,
price: variantsPrice,
attribute: attributeValues[0]
});
getProductVariants(createdProduct.id, defaultChannel.slug);
})
.then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", variantsPrice);
getProductVariants(createdProduct.id, newChannel.slug);
})
.then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", variantsPrice);
});
});
});

View file

@ -0,0 +1,55 @@
import { PRODUCTS_SELECTORS } from "../../elements/catalog/products/product-selectors";
import { VARIANTS_SELECTORS } from "../../elements/catalog/variants-selectors";
class VariantsSteps {
createFirstVariant({ sku, warehouseId, price, attribute }) {
cy.get(PRODUCTS_SELECTORS.addVariantsButton).click();
cy.get(VARIANTS_SELECTORS.valueContainer)
.contains(attribute)
.find(VARIANTS_SELECTORS.attributeCheckbox)
.click()
.get(VARIANTS_SELECTORS.nextButton)
.click()
.get(VARIANTS_SELECTORS.priceInput)
.each($priceInput => {
cy.wrap($priceInput).type(price);
});
cy.get(`[name*='${warehouseId}']`)
.click()
.get(VARIANTS_SELECTORS.nextButton)
.click()
.get(VARIANTS_SELECTORS.skuInput)
.type(sku);
cy.addAliasToGraphRequest("ProductVariantBulkCreate");
cy.get(VARIANTS_SELECTORS.nextButton).click();
cy.wait("@ProductVariantBulkCreate");
}
createVariant({
sku,
warehouseName,
attributeName,
price,
costPrice = price
}) {
cy.get(PRODUCTS_SELECTORS.addVariantsButton)
.click()
.get(VARIANTS_SELECTORS.attributeSelector)
.click()
.get(VARIANTS_SELECTORS.attributeOption)
.contains(attributeName)
.click()
.get(VARIANTS_SELECTORS.priceInput)
.type(price)
.get(VARIANTS_SELECTORS.costPriceInput)
.type(costPrice)
.get(VARIANTS_SELECTORS.skuInputInAddVariant)
.type(sku)
.get(VARIANTS_SELECTORS.addWarehouseButton)
.click();
cy.contains(VARIANTS_SELECTORS.warehouseOption, warehouseName).click();
cy.addAliasToGraphRequest("ProductVariantDetails");
cy.get(VARIANTS_SELECTORS.saveButton).click();
cy.wait("@ProductVariantDetails");
}
}
export default VariantsSteps;

View file

@ -1,4 +1,4 @@
import { PRODUCTS_SELECTORS } from "../elements/catalog/products/product-selectors";
import { PRODUCTS_SELECTORS } from "../../elements/catalog/products/product-selectors";
class ProductSteps {
valueTrue = PRODUCTS_SELECTORS.radioButtonsValueTrue;

View file

@ -19,7 +19,7 @@ class ProductsUtils {
name,
productTypeId,
categoryId
).then(() => this.createVariant(this.product.id, name));
).then(() => this.createVariant(this.product.id, name, attributeId));
}
createProductInChannel({
@ -46,25 +46,25 @@ class ProductsUtils {
})
)
.then(() => {
this.createVariant(
this.product.id,
name,
this.createVariant({
productId: this.product.id,
sku: name,
warehouseId,
quantityInWarehouse,
channelId,
price
);
});
});
}
createTypeAttributeAndCategoryForProduct(name) {
return this.createAttribute(name)
createTypeAttributeAndCategoryForProduct(name, attributeValues) {
return this.createAttribute(name, attributeValues)
.then(() => this.createTypeProduct(name, this.attribute.id))
.then(() => this.createCategory(name));
}
createAttribute(name) {
createAttribute(name, attributeValues) {
return this.attributeRequest
.createAttribute(name)
.createAttribute(name, attributeValues)
.then(
resp => (this.attribute = resp.body.data.attributeCreate.attribute)
);
@ -87,23 +87,23 @@ class ProductsUtils {
.createProduct(attributeId, name, productTypeId, categoryId)
.then(resp => (this.product = resp.body.data.productCreate.product));
}
createVariant(
createVariant({
productId,
name,
sku,
warehouseId,
quantityInWarehouse,
channelId,
price
) {
}) {
return this.productRequest
.createVariant(
.createVariant({
productId,
name,
sku,
warehouseId,
quantityInWarehouse,
quantity: quantityInWarehouse,
channelId,
price
)
})
.then(
resp =>
(this.variants =

View file

@ -26,3 +26,12 @@ export const isProductVisibleInSearchResult = (productName, channelSlug) =>
responseValueKey: ["edges", 0, "node", "name"],
value: productName
});
export const getProductVariants = (productId, channelSlug) =>
productDetails.getProductDetails(productId, channelSlug).then(resp => {
const variantsList = resp.body.data.product.variants;
return variantsList.map(element => ({
name: element.name,
price: element.pricing.price.gross.amount
}));
});

2
package-lock.json generated
View file

@ -52734,4 +52734,4 @@
}
}
}
}
}

View file

@ -122,7 +122,7 @@ function usePageForm(
title: page?.title || ""
});
const [content, changeContent] = useRichText({
initial: page?.content,
initial: pageExists ? page?.content : null,
triggerChange
});

View file

@ -310,6 +310,7 @@ const ProductStocks: React.FC<ProductStocksProps> = ({
>
<div ref={anchor}>
<IconButton
data-test-id="add-warehouse"
color="primary"
onClick={() => setExpansionState(!isExpanded)}
>

View file

@ -200,6 +200,7 @@ const ProductVariantCreatePage: React.FC<ProductVariantCreatePageProps> = props
)}
{step !== ProductVariantCreatorStep.summary ? (
<Button
data-test-id="next-step"
className={classes.button}
color="primary"
disabled={!canHitNext(step, wizardData)}

View file

@ -307,6 +307,7 @@ const ProductVariantCreatorSummary: React.FC<ProductVariantCreatorSummaryProps>
))}
<div className={classNames(classes.col, classes.colSku)}>
<TextField
name="sku"
className={classes.input}
error={!!variantFormErrors.sku}
helperText={getBulkProductErrorMessage(

View file

@ -39,7 +39,10 @@ const ProductVariantCreatorValues: React.FC<ProductVariantCreatorValuesProps> =
<React.Fragment key={attribute.id}>
<Card>
<CardTitle title={attribute?.name || <Skeleton />} />
<CardContent className={classes.valueContainer}>
<CardContent
className={classes.valueContainer}
data-test-id="value-container"
>
{attribute.values.map(value => (
<Debounce
debounceFn={() => onValueClick(attribute.id, value.slug)}

View file

@ -160652,6 +160652,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary defaul
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -160959,6 +160960,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary defaul
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -161266,6 +161268,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary defaul
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -161573,6 +161576,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary defaul
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -161960,6 +161964,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary errors
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -162267,6 +162272,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary errors
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -162574,6 +162580,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary errors
<input
aria-invalid="false"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -162881,6 +162888,7 @@ exports[`Storyshots Views / Products / Create multiple variants / summary errors
<input
aria-invalid="true"
class="MuiInputBase-input-id MuiOutlinedInput-input-id"
name="sku"
type="text"
value=""
/>
@ -162967,6 +162975,7 @@ exports[`Storyshots Views / Products / Create multiple variants choose values 1`
/>
<div
class="MuiCardContent-root-id ProductVariantCreatorValues-valueContainer-id"
data-test-id="value-container"
>
<label
class="MuiFormControlLabel-root-id"
@ -163168,6 +163177,7 @@ exports[`Storyshots Views / Products / Create multiple variants choose values 1`
/>
<div
class="MuiCardContent-root-id ProductVariantCreatorValues-valueContainer-id"
data-test-id="value-container"
>
<label
class="MuiFormControlLabel-root-id"
@ -163323,6 +163333,7 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
>
<button
class="MuiButtonBase-root-id MuiButton-root-id MuiButton-contained-id ProductVariantCreatePage-button-id MuiButton-containedPrimary-id MuiButton-disabled-id MuiButtonBase-disabled-id"
data-test-id="next-step"
disabled=""
tabindex="-1"
type="button"
@ -163362,6 +163373,7 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
/>
<div
class="MuiCardContent-root-id ProductVariantCreatorValues-valueContainer-id"
data-test-id="value-container"
>
<label
class="MuiFormControlLabel-root-id"
@ -163471,6 +163483,7 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
/>
<div
class="MuiCardContent-root-id ProductVariantCreatorValues-valueContainer-id"
data-test-id="value-container"
>
<label
class="MuiFormControlLabel-root-id"
@ -163660,6 +163673,7 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
/>
<div
class="MuiCardContent-root-id ProductVariantCreatorValues-valueContainer-id"
data-test-id="value-container"
>
<label
class="MuiFormControlLabel-root-id"
@ -163769,6 +163783,7 @@ exports[`Storyshots Views / Products / Create multiple variants interactive 1`]
/>
<div
class="MuiCardContent-root-id ProductVariantCreatorValues-valueContainer-id"
data-test-id="value-container"
>
<label
class="MuiFormControlLabel-root-id"
@ -168018,6 +168033,7 @@ exports[`Storyshots Views / Products / Create product variant add first variant
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -169256,6 +169272,7 @@ exports[`Storyshots Views / Products / Create product variant default 1`] = `
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -171480,6 +171497,7 @@ exports[`Storyshots Views / Products / Create product variant when loading data
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -172728,6 +172746,7 @@ exports[`Storyshots Views / Products / Create product variant with errors 1`] =
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -177094,6 +177113,7 @@ exports[`Storyshots Views / Products / Product edit no stock and no variants 1`]
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -180652,6 +180672,7 @@ exports[`Storyshots Views / Products / Product edit no variants 1`] = `
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -183734,6 +183755,7 @@ exports[`Storyshots Views / Products / Product edit when loading data 1`] = `
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -187025,6 +187047,7 @@ exports[`Storyshots Views / Products / Product edit when product has no variants
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -200084,6 +200107,7 @@ exports[`Storyshots Views / Products / Product variant details attribute errors
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -203496,6 +203520,7 @@ exports[`Storyshots Views / Products / Product variant details when loaded data
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>
@ -204738,6 +204763,7 @@ exports[`Storyshots Views / Products / Product variant details when loading data
<div>
<button
class="MuiButtonBase-root-id MuiIconButton-root-id MuiIconButton-colorPrimary-id"
data-test-id="add-warehouse"
tabindex="0"
type="button"
>