tests for sales (#1494)

* tests for sales

* fix create sale with assigned products tests and add test for deleting voucher

* remove unused imports

* Update cypress/support/api/utils/discounts/salesUtils.js

Co-authored-by: Dominik Żegleń <flesz3@o2.pl>

* fix async, remove unused imports

Co-authored-by: Dominik Żegleń <flesz3@o2.pl>
This commit is contained in:
Karolina Rakoczy 2021-10-28 16:43:26 +02:00 committed by GitHub
parent d618b8e775
commit b0369bf5ca
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 679 additions and 10 deletions

View file

@ -11,5 +11,6 @@ export const BUTTON_SELECTORS = {
expandIcon: '[data-test-id="expand-icon"]',
nextPaginationButton: '[data-test="button-pagination-next"]',
deleteIcon: '[data-test-id="deleteIcon"]',
showMoreButton: '[data-test-id="showMoreButton"]'
showMoreButton: '[data-test-id="showMoreButton"]',
button: "button"
};

View file

@ -72,5 +72,9 @@ export const productTypeDetailsUrl = productTypeId =>
export const giftCardDetailsUrl = giftCardId =>
`${urlList.giftCards}${giftCardId}`;
export const saleDetailsUrl = saleId => `${urlList.sales}${saleId}`;
export const voucherDetailsUrl = voucherId => `${urlList.vouchers}${voucherId}`;
export const stripeConfirmationUrl = id =>
`https://api.stripe.com/v1/payment_intents/${id}/confirm`;

View file

@ -0,0 +1,202 @@
/// <reference types="cypress"/>
/// <reference types="../../../support"/>
import faker from "faker";
import { urlList } from "../../../fixtures/urlList";
import { createChannel } from "../../../support/api/requests/Channels";
import { updateChannelInProduct } from "../../../support/api/requests/Product";
import * as channelsUtils from "../../../support/api/utils/channelsUtils";
import { deleteSalesStartsWith } from "../../../support/api/utils/discounts/salesUtils";
import * as productsUtils from "../../../support/api/utils/products/productsUtils";
import {
createShipping,
deleteShippingStartsWith
} from "../../../support/api/utils/shippingUtils";
import { getProductPrice } from "../../../support/api/utils/storeFront/storeFrontProductUtils";
import filterTests from "../../../support/filterTests";
import {
assignProducts,
createSale,
discountOptions
} from "../../../support/pages/discounts/salesPage";
filterTests({ definedTags: ["all"] }, () => {
describe("Create sale with assigned products", () => {
const startsWith = "CyCreateSaleProd-";
let productType;
let attribute;
let category;
let defaultChannel;
let warehouse;
before(() => {
cy.clearSessionData().loginUserViaRequest();
channelsUtils.deleteChannelsStartsWith(startsWith);
deleteSalesStartsWith(startsWith);
productsUtils.deleteProductsStartsWith(startsWith);
deleteShippingStartsWith(startsWith);
const name = `${startsWith}${faker.datatype.number()}`;
productsUtils
.createTypeAttributeAndCategoryForProduct({ name })
.then(
({
productType: productTypeResp,
attribute: attributeResp,
category: categoryResp
}) => {
productType = productTypeResp;
attribute = attributeResp;
category = categoryResp;
channelsUtils.getDefaultChannel();
}
)
.then(channel => {
defaultChannel = channel;
cy.fixture("addresses");
})
.then(addresses => {
createShipping({
channelId: defaultChannel.id,
name,
address: addresses.plAddress,
price: 100
});
})
.then(({ warehouse: warehouseResp }) => {
warehouse = warehouseResp;
});
});
beforeEach(() => {
cy.clearSessionData().loginUserViaRequest();
});
it("should create percentage discount", () => {
const saleName = `${startsWith}${faker.datatype.number()}`;
const discountValue = 50;
const productPrice = 100;
productsUtils
.createProductInChannel({
name: saleName,
channelId: defaultChannel.id,
warehouseId: warehouse.id,
productTypeId: productType.id,
attributeId: attribute.id,
categoryId: category.id,
price: productPrice
})
.then(({ product: productResp }) => {
/* Uncomment after fixing SALEOR-3367 bug
cy.clearSessionData()
.loginUserViaRequest("auth", ONE_PERMISSION_USERS.discount)
*/
cy.visit(urlList.sales);
cy.softExpectSkeletonIsVisible();
const product = productResp;
createSale({
saleName,
channelName: defaultChannel.name,
discountValue,
discountOption: discountOptions.PERCENTAGE
});
assignProducts(product.name);
getProductPrice(product.id, defaultChannel.slug);
})
.then(price => {
const expectedPrice = (productPrice * discountValue) / 100;
expect(expectedPrice).to.be.eq(price);
});
});
it("should create fixed price discount", () => {
const saleName = `${startsWith}${faker.datatype.number()}`;
const discountValue = 50;
const productPrice = 100;
productsUtils
.createProductInChannel({
name: saleName,
channelId: defaultChannel.id,
warehouseId: warehouse.id,
productTypeId: productType.id,
attributeId: attribute.id,
categoryId: category.id,
price: productPrice
})
.then(({ product: productResp }) => {
/* Uncomment after fixing SALEOR-3367 bug
cy.clearSessionData()
.loginUserViaRequest("auth", ONE_PERMISSION_USERS.discount)
*/
cy.visit(urlList.sales);
cy.softExpectSkeletonIsVisible();
const product = productResp;
createSale({
saleName,
channelName: defaultChannel.name,
discountValue,
discountOption: discountOptions.FIXED
});
assignProducts(product.name);
getProductPrice(product.id, defaultChannel.slug);
})
.then(price => {
const expectedPrice = productPrice - discountValue;
expect(expectedPrice).to.be.eq(price);
});
});
it("should not displayed discount not assign to channel", () => {
const saleName = `${startsWith}${faker.datatype.number()}`;
let channel;
let product;
const discountValue = 50;
const productPrice = 100;
createChannel({ name: saleName }).then(
channelResp => (channel = channelResp)
);
productsUtils
.createProductInChannel({
name: saleName,
channelId: defaultChannel.id,
warehouseId: warehouse.id,
productTypeId: productType.id,
attributeId: attribute.id,
categoryId: category.id,
price: productPrice
})
.then(({ product: productResp }) => {
product = productResp;
updateChannelInProduct({
productId: product.id,
channelId: channel.id
});
})
.then(() => {
/* Uncomment after fixing SALEOR-3367 bug
cy.clearSessionData()
.loginUserViaRequest("auth", ONE_PERMISSION_USERS.discount)
*/
cy.visit(urlList.sales);
cy.softExpectSkeletonIsVisible();
createSale({
saleName,
channelName: channel.name,
discountValue
});
assignProducts(product.name);
getProductPrice(product.id, defaultChannel.slug);
})
.then(price => expect(price).to.equal(productPrice));
});
});
});

View file

@ -0,0 +1,221 @@
/// <reference types="cypress"/>
/// <reference types="../../../support"/>
import faker from "faker";
import { SALES_SELECTORS } from "../../../elements/discounts/sales";
import { BUTTON_SELECTORS } from "../../../elements/shared/button-selectors";
import { SHARED_ELEMENTS } from "../../../elements/shared/sharedElements";
import { saleDetailsUrl } from "../../../fixtures/urlList";
import { createCheckout } from "../../../support/api/requests/Checkout";
import { updateSale } from "../../../support/api/requests/Discounts/Sales";
import {
createVariant,
getVariant
} from "../../../support/api/requests/Product";
import { getDefaultChannel } from "../../../support/api/utils/channelsUtils";
import {
createSaleInChannel,
createSaleInChannelWithProduct,
deleteSalesStartsWith
} from "../../../support/api/utils/discounts/salesUtils";
import {
createProductInChannel,
createTypeAttributeAndCategoryForProduct,
deleteProductsStartsWith
} from "../../../support/api/utils/products/productsUtils";
import {
createShipping,
deleteShippingStartsWith
} from "../../../support/api/utils/shippingUtils";
import filterTests from "../../../support/filterTests";
filterTests({ definedTags: ["all"] }, () => {
describe("Create sale with assigned products", () => {
const startsWith = "CySales";
const saleValue = 10;
let channel;
let sale;
let warehouse;
let address;
let productData;
before(() => {
cy.clearSessionData().loginUserViaRequest();
deleteProductsStartsWith(startsWith);
deleteShippingStartsWith(startsWith);
deleteSalesStartsWith(startsWith);
getDefaultChannel()
.then(defaultChannel => {
channel = defaultChannel;
createSaleInChannel({
name: startsWith,
type: "FIXED",
value: saleValue,
channelId: channel.id
});
})
.then(saleResp => (sale = saleResp));
cy.fixture("addresses")
.then(addresses => {
address = addresses.usAddress;
createShipping({
channelId: channel.id,
address,
name: startsWith
});
})
.then(({ warehouse: warehouseResp }) => {
warehouse = warehouseResp;
});
createTypeAttributeAndCategoryForProduct({
name: startsWith,
attributeValues: ["value1", "value2"]
}).then(({ attribute, category, productType }) => {
productData = {
attributeId: attribute.id,
categoryId: category.id,
productTypeId: productType.id,
channelId: channel.id,
warehouseId: warehouse.id,
price: 30
};
});
});
beforeEach(() => {
cy.clearSessionData().loginUserViaRequest();
});
it("should discount only variants added to sale", () => {
const productName = `${startsWith}${faker.datatype.number()}`;
const name = `${startsWith}${faker.datatype.number()}`;
let variantNotOnSale;
let variantOnSale;
productData.name = productName;
createProductInChannel(productData)
.then(({ product, variantsList }) => {
variantNotOnSale = variantsList;
productData.name = name;
productData.sku = name;
productData.productId = product.id;
productData.quantityInWarehouse = 10;
productData.attributeValues = ["value2"];
createVariant(productData);
})
.then(variantsList => {
variantOnSale = variantsList;
updateSale({ saleId: sale.id, variants: variantOnSale });
})
.then(() => {
createCheckout({
channelSlug: channel.slug,
email: "example@example.com",
address,
variantsList: variantOnSale.concat(variantNotOnSale)
});
})
.then(({ checkout }) => {
const variantRespNotOnSale = checkout.lines.find(
element => element.variant.id === variantNotOnSale[0].id
).variant;
const variantRespOnSale = checkout.lines.find(
element => element.variant.id === variantOnSale[0].id
).variant;
expect(variantRespNotOnSale.pricing.onSale).to.be.false;
expect(variantRespOnSale.pricing.onSale).to.be.true;
expect(variantRespNotOnSale.pricing.price.gross.amount).to.eq(
productData.price
);
expect(variantRespOnSale.pricing.price.gross.amount).to.eq(
productData.price - saleValue
);
});
});
it("should delete sale", () => {
const name = `${startsWith}${faker.datatype.number()}`;
let variants;
let saleToDelete;
productData.name = name;
createProductInChannel(productData)
.then(({ variantsList }) => {
variants = variantsList;
createSaleInChannelWithProduct({
name,
type: "FIXED",
value: saleValue,
channelId: channel.id,
variants
});
})
.then(saleResp => {
saleToDelete = saleResp;
getVariant(variants[0].id, channel.slug);
})
.then(variantResp => {
expect(variantResp.pricing.onSale).to.be.true;
expect(variantResp.pricing.price.gross.amount).to.eq(
productData.price - saleValue
);
cy.visit(saleDetailsUrl(saleToDelete.id))
.addAliasToGraphRequest("SaleDelete")
.get(BUTTON_SELECTORS.deleteButton)
.click()
.get(BUTTON_SELECTORS.submit)
.click()
.wait("@SaleDelete");
getVariant(variants[0].id, channel.slug);
})
.then(variantResp => {
expect(variantResp.pricing.onSale).to.be.false;
expect(variantResp.pricing.price.gross.amount).to.eq(
productData.price
);
});
});
it("should remove variant from sale", () => {
const name = `${startsWith}${faker.datatype.number()}`;
let product;
let variants;
productData.name = name;
createProductInChannel(productData)
.then(({ variantsList, product: productResp }) => {
product = productResp;
variants = variantsList;
updateSale({
saleId: sale.id,
variants
});
})
.then(() => {
getVariant(variants[0].id, channel.slug);
})
.then(variantResp => {
expect(variantResp.pricing.onSale).to.be.true;
expect(variantResp.pricing.price.gross.amount).to.eq(
productData.price - saleValue
);
cy.visit(saleDetailsUrl(sale.id))
.get(SALES_SELECTORS.variantsTab)
.click()
.addAliasToGraphRequest("SaleCataloguesRemove");
cy.contains(SHARED_ELEMENTS.tableRow, product.name)
.find(BUTTON_SELECTORS.button)
.click()
.wait("@SaleCataloguesRemove");
getVariant(variants[0].id, channel.slug);
})
.then(variantResp => {
expect(variantResp.pricing.onSale).to.be.false;
expect(variantResp.pricing.price.gross.amount).to.eq(
productData.price
);
});
});
});
});

View file

@ -3,11 +3,15 @@
import faker from "faker";
import { urlList } from "../../fixtures/urlList";
import { BUTTON_SELECTORS } from "../../elements/shared/button-selectors";
import { urlList, voucherDetailsUrl } from "../../fixtures/urlList";
import { ONE_PERMISSION_USERS } from "../../fixtures/users";
import { createChannel } from "../../support/api/requests/Channels";
import * as channelsUtils from "../../support/api/utils/channelsUtils";
import { deleteVouchersStartsWith } from "../../support/api/utils/discounts/vouchersUtils";
import {
createVoucherInChannel,
deleteVouchersStartsWith
} from "../../support/api/utils/discounts/vouchersUtils";
import { createCheckoutWithVoucher } from "../../support/api/utils/ordersUtils";
import * as productsUtils from "../../support/api/utils/products/productsUtils";
import {
@ -33,6 +37,7 @@ filterTests({ definedTags: ["all"] }, () => {
let category;
let shippingMethod;
let variants;
let product;
let address;
before(() => {
@ -86,7 +91,8 @@ filterTests({ definedTags: ["all"] }, () => {
});
}
)
.then(({ variantsList: variantsResp }) => {
.then(({ variantsList: variantsResp, product: productResp }) => {
product = productResp;
variants = variantsResp;
createChannel({ name });
})
@ -151,6 +157,39 @@ filterTests({ definedTags: ["all"] }, () => {
);
});
it("should delete voucher", () => {
const name = `${startsWith}${faker.datatype.number()}`;
const voucherValue = 50;
let voucher;
cy.clearSessionData().loginUserViaRequest();
createVoucherInChannel({
name,
productId: product.id,
channelId: defaultChannel.id,
value: voucherValue
})
.then(voucherResp => {
voucher = voucherResp;
expect(voucher.id).to.be.ok;
})
.then(resp => {
cy.visit(voucherDetailsUrl(voucher.id))
.addAliasToGraphRequest("VoucherDelete")
.get(BUTTON_SELECTORS.deleteButton)
.click()
.get(BUTTON_SELECTORS.submit)
.click()
.wait("@VoucherDelete");
createCheckoutForCreatedVoucher(voucher.code);
})
.then(({ addPromoCodeResp }) => {
const errorField = addPromoCodeResp.checkoutErrors[0].field;
expect(errorField).to.be.eq("promoCode");
});
});
function createCheckoutForCreatedVoucher(voucherCode) {
return createCheckoutWithVoucher({
channelSlug: defaultChannel.slug,

View file

@ -48,9 +48,23 @@ export function createCheckout({
checkout{
token
id
token
availableShippingMethods{
name
}
lines{
variant{
id
pricing{
onSale
price{
gross{
amount
}
}
}
}
}
${availableCollectionPointsLines}
}
}

View file

@ -1,4 +1,8 @@
import { getValueWithDefault } from "../utils/Utils";
import {
getValuesInArray,
getValueWithDefault,
getVariantsIdsLines
} from "../utils/Utils";
export function getSales(first, searchQuery) {
const filter = getValueWithDefault(
@ -33,3 +37,64 @@ export function deleteSale(saleId) {
}`;
return cy.sendRequestWithQuery(mutation);
}
export function createSale({ name, type, value, products, variants }) {
const productsLine = getValueWithDefault(products, `products: ${products}`);
const variantsLine = getValueWithDefault(variants, `variants: ${variants}`);
const mutation = `mutation{
saleCreate(input:{
name: "${name}"
type: ${type}
value: ${value}
${productsLine}
${variantsLine}
}){
sale{
id
name
}
}
}`;
return cy.sendRequestWithQuery(mutation).its("body.data.saleCreate.sale");
}
export function updateSale({ saleId, variants, productId }) {
const productsLine = getValueWithDefault(
productId,
`products: [${productId}]`
);
const variantsLines = getValueWithDefault(
variants,
getValuesInArray(getVariantsIdsLines(variants)),
"[]"
);
const mutation = `mutation{
saleUpdate(id:"${saleId}" input:{
${productsLine}
variants: ${variantsLines}
}){
errors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
export function addChannelToSale(saleId, channelId, discountValue) {
const mutation = `mutation{
saleChannelListingUpdate(id:"${saleId}" input:{
addChannels: [{
channelId: "${channelId}"
discountValue: "${discountValue}"
}]
}){
errors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}

View file

@ -15,6 +15,7 @@ export function getVouchers(first, startsWith) {
.sendRequestWithQuery(query)
.then(resp => resp.body.data.vouchers.edges);
}
export function deleteVouchers(voucherId) {
const mutation = `mutation deleteVouchers{
voucherDelete(id:"${voucherId}"){
@ -26,3 +27,40 @@ export function deleteVouchers(voucherId) {
}`;
return cy.sendRequestWithQuery(mutation);
}
export function createVoucher({ name, productId, code = name }) {
const mutation = `mutation{
voucherCreate(input:{
name:"${name}",
code:"${code}"
products:["${productId}"]
}){
voucher{
id
code
}
errors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation).its("body.data.voucherCreate");
}
export function addChannelToVoucher(voucherId, channelId, value) {
const mutation = `mutation{
voucherChannelListingUpdate(id:"${voucherId}" input:{
addChannels:{
channelId:"${channelId}"
discountValue:"${value}"
}
}){
errors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}

View file

@ -1,5 +1,9 @@
import { stringify } from "../.././formatData/formatJson";
import { getValueWithDefault, getVariantsListIds } from "./utils/Utils";
import {
getValuesInArray,
getValueWithDefault,
getVariantsListIds
} from "./utils/Utils";
export function getFirstProducts(first, search) {
const filter = search
@ -148,7 +152,8 @@ export function createVariant({
price = 1,
costPrice = 1,
trackInventory = true,
weight = 1
weight = 1,
attributeValues = ["value"]
}) {
const channelListings = getValueWithDefault(
channelId,
@ -171,7 +176,7 @@ export function createVariant({
productVariantBulkCreate(product: "${productId}", variants: {
attributes: [{
id:"${attributeId}"
values: ["value"]
values: ${getValuesInArray(attributeValues)}
}]
weight: ${weight}
sku: "${sku}"

View file

@ -27,6 +27,10 @@ export function getVariantsLines(variantsList, quantity) {
);
}
export function getVariantsIdsLines(variantsList) {
return variantsList.map(variant => `${variant.id}`);
}
export function getVariantsListIds(variantsList) {
return variantsList.map(variant => `"${variant.id}"`).join();
}
@ -35,3 +39,6 @@ export const getPaymentDataLine = paymentData =>
paymentData
? `, paymentData:"{\\"riskData\\":{\\"clientData\\":\\"${paymentData.clientData}\\"}, \\"paymentMethod\\":{\\"type\\":\\"scheme\\", \\"encryptedCardNumber\\":\\"${paymentData.encryptedCardNumber}\\", \\"encryptedExpiryMonth\\":\\"${paymentData.encryptedExpiryMonth}\\", \\"encryptedExpiryYear\\":\\"${paymentData.encryptedExpiryYear}\\", \\"encryptedSecurityCode\\":\\"${paymentData.encryptedSecurityCode}\\", \\"brand\\":\\"${paymentData.brand}\\"}}"`
: "";
export const getValuesInArray = array =>
getValueWithDefault(array.length === 1, `["${array}"]`, `${array}`);

View file

@ -1,5 +1,57 @@
import { deleteSale, getSales } from "../../requests/Discounts/Sales";
import {
addChannelToSale,
createSale,
deleteSale,
getSales,
updateSale
} from "../../requests/Discounts/Sales";
export function deleteSalesStartsWith(startsWith) {
cy.deleteElementsStartsWith(deleteSale, getSales, startsWith);
}
export function createSaleInChannel({
name,
type,
value,
channelId,
discountValue = value
}) {
let sale;
return createSale({
name,
type,
value
})
.then(saleResp => {
sale = saleResp;
addChannelToSale(sale.id, channelId, discountValue);
})
.then(() => sale);
}
export function createSaleInChannelWithProduct({
name,
type,
value,
channelId,
variants,
productId
}) {
let sale;
return createSaleInChannel({
name,
type,
value,
channelId
})
.then(saleResp => {
sale = saleResp;
updateSale({
saleId: sale.id,
variants,
productId
});
})
.then(() => sale);
}

View file

@ -1,5 +1,26 @@
import { deleteVouchers, getVouchers } from "../../requests/Discounts/Vouchers";
import {
addChannelToVoucher,
createVoucher,
deleteVouchers,
getVouchers
} from "../../requests/Discounts/Vouchers";
export function deleteVouchersStartsWith(startsWith) {
cy.deleteElementsStartsWith(deleteVouchers, getVouchers, startsWith, "code");
}
export function createVoucherInChannel({
name,
productId,
channelId,
value,
code = name
}) {
let voucher;
return createVoucher({ name, productId, code })
.then(({ voucher: voucherResp }) => {
voucher = voucherResp;
addChannelToVoucher(voucher.id, channelId, value);
})
.then(() => voucher);
}