merge with master

This commit is contained in:
Karolina Rakoczy 2021-02-18 16:28:29 +01:00
commit 5fa5eda4a7
34 changed files with 1251 additions and 510 deletions

View file

@ -8,7 +8,7 @@ jobs:
build: build:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
env: env:
API_URI: https://master.staging.saleor.cloud/graphql/ API_URI: /graphql/
APP_MOUNT_URI: /dashboard/ APP_MOUNT_URI: /dashboard/
STATIC_URL: /dashboard/static/ STATIC_URL: /dashboard/static/
SENTRY_ORG: saleor SENTRY_ORG: saleor

View file

@ -20,29 +20,31 @@ class Attribute {
getAttributes(first, search) { getAttributes(first, search) {
const mutation = `query{ const mutation = `query{
attributes(first:${first}, filter:{ attributes(first:${first}, filter:{
search:"${search}" search:"${search}"
}){ }){
edges{ edges{
node{ node{
id id
name name
}
} }
} }
}`; }
return cy.sendRequestWithQuery(mutation); }`;
return cy
.sendRequestWithQuery(mutation)
.then(resp => resp.body.data.attributes.edges);
} }
deleteAttribute(attributeId) { deleteAttribute(attributeId) {
const mutation = `mutation{ const mutation = `mutation{
attributeDelete(id:"${attributeId}"){ attributeDelete(id:"${attributeId}"){
attributeErrors{ attributeErrors{
field field
message message
}
} }
}`; }
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
} }

View file

@ -1,42 +1,44 @@
class Category { class Category {
createCategory(name, slug = name) { createCategory(name, slug = name) {
const mutation = `mutation{ const mutation = `mutation{
categoryCreate(input:{name:"${name}", slug: "${slug}"}){ categoryCreate(input:{name:"${name}", slug: "${slug}"}){
productErrors{ productErrors{
field field
message message
} }
category{ category{
id id
} }
} }
}`; }`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
getCategories(first, search) { getCategories(first, search) {
const mutation = `query{ const mutation = `query{
categories(first:${first}, filter:{ categories(first:${first}, filter:{
search:"${search}" search:"${search}"
}){ }){
edges{ edges{
node{ node{
id id
name name
}
} }
} }
}`; }
return cy.sendRequestWithQuery(mutation); }`;
return cy
.sendRequestWithQuery(mutation)
.then(resp => resp.body.data.categories.edges);
} }
deleteCategory(categoryId) { deleteCategory(categoryId) {
const mutation = `mutation{ const mutation = `mutation{
categoryDelete(id:"${categoryId}"){ categoryDelete(id:"${categoryId}"){
productErrors{ productErrors{
field field
message message
}
} }
}`; }
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
} }

View file

@ -8,6 +8,7 @@ class Channels {
currencyCode: "${currencyCode}" currencyCode: "${currencyCode}"
}){ }){
channel{ channel{
id
name name
slug slug
} }
@ -19,32 +20,30 @@ class Channels {
}`; }`;
return cy.sendRequestWithQuery(createChannelMutation); return cy.sendRequestWithQuery(createChannelMutation);
} }
getChannels() { getChannels() {
const getChannelsInfoQuery = `query{ const getChannelsInfoQuery = `query{
channels{ channels{
name name
id id
isActive isActive
slug slug
currencyCode currencyCode
}
} }
`; }
`;
return cy.sendRequestWithQuery(getChannelsInfoQuery); return cy.sendRequestWithQuery(getChannelsInfoQuery);
} }
deleteChannel(channelId, targetChennelId) { deleteChannel(channelId, targetChannelId) {
const deleteChannelMutation = `mutation{ const deleteChannelMutation = `mutation{
channelDelete(id: "${channelId}", input:{ channelDelete(id: "${channelId}", input:{
targetChannel: "${targetChennelId}" targetChannel: "${targetChannelId}"
}){ }){
channel{ channel{
name name
} }
channelErrors{ channelErrors{
message message
}
} }
}`; }`;
return cy.sendRequestWithQuery(deleteChannelMutation); return cy.sendRequestWithQuery(deleteChannelMutation);

View file

@ -0,0 +1,69 @@
class Checkout {
createCheckout(channelSlug, email, productQuantity, variantsList) {
const lines = variantsList.map(
variant => `{quantity:${productQuantity}
variantId:"${variant.id}"}`
);
const mutation = `mutation{
checkoutCreate(input:{
channel:"${channelSlug}"
email:"${email}"
lines: [${lines.join()}]
}){
checkoutErrors{
field
message
}
created
checkout{
id
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
addShippingMethod(checkoutId, shippingMethodId) {
const mutation = `mutation{
checkoutShippingMethodUpdate(checkoutId:"${checkoutId}",
shippingMethodId:"${shippingMethodId}"){
checkoutErrors{
message
field
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
addPayment(checkoutId, gateway, token) {
const mutation = `mutation{
checkoutPaymentCreate(checkoutId:"${checkoutId}",
input:{
gateway: "${gateway}"
token:"${token}"
}){
paymentErrors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
completeCheckout(checkoutId) {
const mutation = `mutation{
checkoutComplete(checkoutId:"${checkoutId}"){
order{
id
}
confirmationNeeded
confirmationData
checkoutErrors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
}
export default Checkout;

View file

@ -0,0 +1,85 @@
export class Customer {
createCustomer(email, customerName, address, isActive = false) {
const mutation = `
mutation{
customerCreate(input:{
firstName: "${customerName}"
lastName: "${customerName}"
email: "${email}"
isActive: ${isActive}
defaultBillingAddress: {
companyName: "${address.companyName}"
streetAddress1: "${address.streetAddress1}"
streetAddress2: "${address.streetAddress2}"
city: "${address.city}"
postalCode: "${address.postalCode}"
country: ${address.country}
phone: "${address.phone}"
}
defaultShippingAddress: {
companyName: "${address.companyName}"
streetAddress1: "${address.streetAddress1}"
streetAddress2: "${address.streetAddress2}"
city: "${address.city}"
postalCode: "${address.postalCode}"
country: ${address.country}
phone: "${address.phone}"
}
}){
user{
id
email
}
accountErrors{
code
message
}
}
}
`;
return cy.sendRequestWithQuery(mutation);
}
deleteCustomers(startsWith) {
this.getCustomers(startsWith).then(resp => {
if (resp.body.data.customers) {
const customers = resp.body.data.customers.edges;
customers.forEach(element => {
if (element.node.email.includes(startsWith)) {
this.deleteCustomer(element.node.id);
}
});
}
});
}
deleteCustomer(customerId) {
const mutation = `mutation{
customerDelete(id:"${customerId}"){
accountErrors{
code
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
getCustomers(startsWith) {
const query = `query{
customers(first:100, filter: {
search: "${startsWith}"
}){
edges{
node{
id
email
}
}
}
}
`;
return cy.sendRequestWithQuery(query);
}
}
export default Customer;

View file

@ -0,0 +1,37 @@
class HomePage {
getSalesForChannel(channelSlug, period) {
const query = `query{
ordersTotal(period: ${period}, channel:"${channelSlug}"){
gross{
amount
}
}
}`;
return cy.sendRequestWithQuery(query);
}
getOrdersForChannel(channelSlug, created) {
const query = `query{
orders(created: ${created}, channel:"${channelSlug}"){
totalCount
}
}`;
return cy.sendRequestWithQuery(query);
}
getOrdersWithStatus(status, channelSlug) {
const query = `query{
orders(status: ${status}, channel:"${channelSlug}"){
totalCount
}
}`;
return cy.sendRequestWithQuery(query);
}
getProductsOutOfStock(channelSlug) {
const query = `query{
products(stockAvailability: OUT_OF_STOCK, channel:"${channelSlug}"){
totalCount
}
}`;
return cy.sendRequestWithQuery(query);
}
}
export default HomePage;

View file

@ -0,0 +1,60 @@
class Order {
markOrderAsPaid(orderId) {
const mutation = `mutation{
orderMarkAsPaid(id:"${orderId}"){
orderErrors{
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
addProductToOrder(orderId, variantId, quantity = 1) {
const mutation = `mutation{
draftOrderLinesCreate(id:"${orderId}", input:{
quantity:${quantity}
variantId: "${variantId}"
}){
orderErrors{
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
createDraftOrder(customerId, shippingMethodId, channelId) {
const mutation = `
mutation{
draftOrderCreate(input:{
user:"${customerId}"
shippingMethod:"${shippingMethodId}"
channel: "${channelId}"
}){
orderErrors{
message
}
order{
id
}
}
}
`;
return cy.sendRequestWithQuery(mutation);
}
completeOrder(orderId) {
const mutation = `mutation{
draftOrderComplete(id:"${orderId}"){
order{
id
}
orderErrors{
message
}
}
}`;
return cy.sendRequestWithQuery(mutation);
}
}
export default Order;

View file

@ -1,34 +1,34 @@
class Product { class Product {
getFirstProducts(first, search) { getFirstProducts(first, search) {
let filter = ""; const filter = search
if (search) { ? `, filter:{
filter = `, filter:{ search:"${search}"
search:"${search}" }`
}`; : "";
}
const query = `query{ const query = `query{
products(first:${first}${filter}){ products(first:${first}${filter}){
edges{ edges{
node{ node{
id
name
variants{
id id
name
variants{
id
}
} }
} }
} }
} }
`; `;
return cy.sendRequestWithQuery(query); return cy
.sendRequestWithQuery(query)
.then(resp => resp.body.data.products.edges);
} }
updateChannelInProduct( updateChannelInProduct(
productId, productId,
channelId, channelId,
isPublished, isPublished = true,
isAvailableForPurchase, isAvailableForPurchase = true,
visibleInListings visibleInListings = true
) { ) {
const mutation = `mutation{ const mutation = `mutation{
productChannelListingUpdate(id:"${productId}", productChannelListingUpdate(id:"${productId}",
@ -46,42 +46,41 @@ class Product {
} }
} }
}`; }`;
return cy.sendRequestWithQuery(mutation);
} }
updateChannelPriceInVariant(variantId, channelId) { updateChannelPriceInVariant(variantId, channelId) {
const mutation = `mutation{ const mutation = `mutation{
productVariantChannelListingUpdate(id: "${variantId}", input:{ productVariantChannelListingUpdate(id: "${variantId}", input: {
channelId: "${channelId}" channelId: "${channelId}"
price: 10 price: 10
costPrice: 10 costPrice: 10
}){ }){
productChannelListingErrors{ productChannelListingErrors{
message message
} }
} }
}`; } `;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
createProduct(attributeId, name, productType, category) { createProduct(attributeId, name, productType, category) {
const mutation = `mutation{ const mutation = `mutation{
productCreate(input:{ productCreate(input:{
attributes:[{ attributes:[{
id:"${attributeId}" id:"${attributeId}"
}] }]
name:"${name}" name:"${name}"
productType:"${productType}" productType:"${productType}"
category:"${category}" category:"${category}"
}){ }){
product{ product{
id id
}
productErrors{
field
message
}
} }
}`; productErrors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
@ -94,98 +93,92 @@ class Product {
price = 1, price = 1,
costPrice = 1 costPrice = 1
) { ) {
let channelListings = "";
let stocks = "";
if (channelId) {
channelListings = `channelListings:{
channelId:"${channelId}"
price:"${price}"
costPrice:"${costPrice}"
}`;
}
if (warehouseId) {
stocks = `stocks:{
warehouse:"${warehouseId}"
quantity:${quantity}
}`;
}
const mutation = `mutation{ const mutation = `mutation{
productVariantBulkCreate(product:"${productId}", variants:{ productVariantBulkCreate(product: "${productId}", variants: {
attributes:[] attributes: []
sku:"${sku}" sku: "${sku}"
${channelListings} channelListings: {
${stocks} channelId: "${channelId}"
}){ price: "${price}"
productVariants{ costPrice: "${costPrice}"
id
name
}
bulkProductErrors{
field
message
}
} }
}`; stocks: {
warehouse: "${warehouseId}"
quantity: ${quantity}
}
}) {
productVariants{
id
name
}
bulkProductErrors{
field
message
}
}
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
createTypeProduct(name, attributeId, slug = name) { createTypeProduct(name, attributeId, slug = name) {
const mutation = `mutation{ const mutation = `mutation{
productTypeCreate(input:{ productTypeCreate(input: {
name:"${name}" name: "${name}"
slug: "${slug}" slug: "${slug}"
isShippingRequired:true isShippingRequired: true
productAttributes:"${attributeId}" productAttributes: "${attributeId}"
}){ }){
productErrors{ productErrors{
field field
message message
} }
productType{ productType{
id id
} }
} }
}`; } `;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
deleteProduct(productId) { deleteProduct(productId) {
const mutation = `mutation{ const mutation = `mutation{
productDelete(id:"${productId}"){ productDelete(id: "${productId}"){
productErrors{ productErrors{
field field
message message
} }
} }
}`; } `;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
getProductTypes(first, search) { getProductTypes(first, search) {
const query = `query{ const query = `query{
productTypes(first:${first}, filter:{ productTypes(first:${first}, filter:{
search:"${search}" search:"${search}"
}){ }){
edges{ edges{
node{ node{
id id
name name
}
} }
} }
}`; }
return cy.sendRequestWithQuery(query); }`;
return cy
.sendRequestWithQuery(query)
.then(resp => resp.body.data.productTypes.edges);
} }
deleteProductType(productTypeId) { deleteProductType(productTypeId) {
const mutation = `mutation{ const mutation = `mutation{
productTypeDelete(id:"${productTypeId}"){ productTypeDelete(id:"${productTypeId}"){
productErrors{ productErrors{
field field
message message
}
} }
}`; }
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
} }

View file

@ -1,84 +1,86 @@
class ShippingMethod { class ShippingMethod {
createShippingRate(name, shippingZone) { createShippingRate(name, shippingZone) {
const mutation = ` const mutation = `
mutation{ mutation{
shippingPriceCreate(input:{ shippingPriceCreate(input:{
name: "${name}" name: "${name}"
shippingZone: "${shippingZone}" shippingZone: "${shippingZone}"
type: PRICE type: PRICE
}){ }){
shippingMethod{ shippingMethod{
id id
}
} }
} }
`; }
`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
createShippingZone(name, country) { createShippingZone(name, country) {
const mutation = ` const mutation = `
mutation{ mutation{
shippingZoneCreate(input:{ shippingZoneCreate(input:{
name: "${name}" name: "${name}"
countries: "${country}" countries: "${country}"
}){ }){
shippingZone{ shippingZone{
id id
}
} }
} }
`; }
`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
addChannelToShippingMethod(shippingRateId, channelId, price) { addChannelToShippingMethod(shippingRateId, channelId, price) {
const mutation = ` const mutation = `
mutation{ mutation{
shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{
addChannels: { addChannels: {
channelId:"${channelId}" channelId:"${channelId}"
price: ${price} price: ${price}
} }
}){ }){
shippingMethod{ shippingMethod{
id id
} }
shippingErrors{ shippingErrors{
code code
message message
}
} }
} }
`; }
`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
deleteShippingZone(shippingZoneId) { deleteShippingZone(shippingZoneId) {
const mutation = `mutation{ const mutation = `mutation{
shippingZoneDelete(id:"${shippingZoneId}"){ shippingZoneDelete(id:"${shippingZoneId}"){
shippingErrors{ shippingErrors{
message message
}
} }
} }
`; }
`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
getShippingZones() { getShippingZones() {
const query = `query{ const query = `query{
shippingZones(first:100){ shippingZones(first:100){
edges{ edges{
node{ node{
name name
id id
}
} }
} }
} }
`; }
return cy.sendRequestWithQuery(query); `;
return cy
.sendRequestWithQuery(query)
.then(resp => resp.body.data.shippingZones.edges);
} }
} }
export default ShippingMethod; export default ShippingMethod;

View file

@ -1,54 +1,56 @@
class Warehouse { class Warehouse {
createWarehouse(name, shippingZone, address, slug = name) { createWarehouse(name, shippingZone, address, slug = name) {
const mutation = `mutation{ const mutation = `mutation{
createWarehouse(input:{ createWarehouse(input:{
name:"${name}" name:"${name}"
slug:"${slug}" slug:"${slug}"
shippingZones:"${shippingZone}" shippingZones:"${shippingZone}"
address:{ address:{
streetAddress1: "${address.streetAddress1}" streetAddress1: "${address.streetAddress1}"
streetAddress2: "${address.streetAddress2}" streetAddress2: "${address.streetAddress2}"
city: "${address.city}" city: "${address.city}"
postalCode: "${address.postalCode}" postalCode: "${address.postalCode}"
country: ${address.country} country: ${address.country}
phone: "${address.phone}" phone: "${address.phone}"
}
}){
warehouseErrors{
field
message
}
warehouse{
id
}
} }
}`; }){
warehouseErrors{
field
message
}
warehouse{
id
}
}
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
getWarehouses(first, search) { getWarehouses(first, search) {
const query = `query{ const query = `query{
warehouses(first:${first}, filter:{ warehouses(first:${first}, filter:{
search:"${search}" search:"${search}"
}){ }){
edges{ edges{
node{ node{
id id
name name
}
} }
} }
}`; }
return cy.sendRequestWithQuery(query); }`;
return cy
.sendRequestWithQuery(query)
.then(resp => resp.body.data.warehouses.edges);
} }
deleteWarehouse(warehouseId) { deleteWarehouse(warehouseId) {
const mutation = `mutation{ const mutation = `mutation{
deleteWarehouse(id:"${warehouseId}"){ deleteWarehouse(id:"${warehouseId}"){
warehouseErrors{ warehouseErrors{
field field
message message
}
} }
}`; }
}`;
return cy.sendRequestWithQuery(mutation); return cy.sendRequestWithQuery(mutation);
} }
} }

View file

@ -0,0 +1,9 @@
export const HOMEPAGE_SELECTORS = {
sales: "[data-test-id='sales-analytics']",
orders: "[data-test-id='orders-analytics']",
activity: "[data-test-id='activity-card']",
topProducts: "[data-test-id='top-products']",
ordersReadyToFulfill: "[data-test-id='orders-to-fulfill']",
paymentsWaitingForCapture: "[data-test-id='orders-to-capture']",
productsOutOfStock: "[data-test-id='products-out-of-stock']"
};

View file

@ -20,8 +20,8 @@ describe("Channels", () => {
const channelStartsWith = "Cypress:"; const channelStartsWith = "Cypress:";
const currency = "PLN"; const currency = "PLN";
const channels = new Channels(); const channels = new Channels();
const channelsSteps = new ChannelsSteps();
const channelsUtils = new ChannelsUtils(); const channelsUtils = new ChannelsUtils();
const channelsSteps = new ChannelsSteps();
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();

View file

@ -0,0 +1,235 @@
import faker from "faker";
import Customer from "../apiRequests/Customer";
import { HOMEPAGE_SELECTORS } from "../elements/homePage/homePage-selectors";
import HomePageSteps from "../steps/homePageSteps";
import { urlList } from "../url/urlList";
import ChannelsUtils from "../utils/channelsUtils";
import HomePageUtils from "../utils/homePageUtils";
import OrdersUtils from "../utils/ordersUtils";
import ProductsUtils from "../utils/productsUtils";
import ShippingUtils from "../utils/shippingUtils";
// <reference types="cypress" />
describe("User authorization", () => {
const startsWith = "Cy-";
const customer = new Customer();
const productsUtils = new ProductsUtils();
const shippingUtils = new ShippingUtils();
const ordersUtils = new OrdersUtils();
const channelsUtils = new ChannelsUtils();
const homePageUtils = new HomePageUtils();
const homePageSteps = new HomePageSteps();
let customerId;
let defaultChannel;
const productPrice = 22;
const shippingPrice = 12;
const randomName = startsWith + faker.random.number();
const randomEmail = randomName + "@example.com";
before(() => {
cy.clearSessionData().loginUserViaRequest();
productsUtils.deleteProperProducts(startsWith);
customer.deleteCustomers(startsWith);
shippingUtils.deleteShipping(startsWith);
let addresses;
channelsUtils
.getDefaultChannel()
.then(channel => {
defaultChannel = channel;
cy.fixture("addresses");
})
.then(addressesFixture => (addresses = addressesFixture))
.then(() =>
customer.createCustomer(randomEmail, randomName, addresses.plAddress)
)
.then(resp => {
customerId = resp.body.data.customerCreate.user.id;
shippingUtils.createShipping(
defaultChannel.id,
randomName,
addresses.plAddress,
shippingPrice
);
})
.then(() => {
productsUtils.createTypeAttributeAndCategoryForProduct(randomName);
})
.then(() => {
const warehouse = shippingUtils.getWarehouse();
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
);
});
});
beforeEach(() => {
cy.clearSessionData().loginUserViaRequest();
});
it("should all elements be visible on the dashboard", () => {
cy.visit(urlList.homePage)
.softAssertVisibility(HOMEPAGE_SELECTORS.sales)
.softAssertVisibility(HOMEPAGE_SELECTORS.orders)
.softAssertVisibility(HOMEPAGE_SELECTORS.activity)
.softAssertVisibility(HOMEPAGE_SELECTORS.topProducts)
.softAssertVisibility(HOMEPAGE_SELECTORS.ordersReadyToFulfill)
.softAssertVisibility(HOMEPAGE_SELECTORS.paymentsWaitingForCapture)
.softAssertVisibility(HOMEPAGE_SELECTORS.productsOutOfStock);
});
it("should correct amount of ready to fullfil orders be displayed", () => {
homePageUtils
.getOrdersReadyToFulfill(defaultChannel.slug)
.as("ordersReadyToFulfill");
ordersUtils.createReadyToFulfillOrder(
customerId,
shippingUtils.getShippingMethod().id,
defaultChannel.id,
productsUtils.getCreatedVariants()
);
cy.get("@ordersReadyToFulfill").then(ordersReadyToFulfillBefore => {
const allOrdersReadyToFulfill = ordersReadyToFulfillBefore + 1;
const notANumberRegex = "\\D*";
const ordersReadyToFulfillRegexp = new RegExp(
`${notANumberRegex}${allOrdersReadyToFulfill}${notANumberRegex}`
);
cy.visit(urlList.homePage);
homePageSteps.changeChannel(defaultChannel.name);
cy.contains(
HOMEPAGE_SELECTORS.ordersReadyToFulfill,
ordersReadyToFulfillRegexp
).should("be.visible");
});
});
it("should correct amount of payments waiting for capture be displayed", () => {
homePageUtils
.getOrdersReadyForCapture(defaultChannel.slug)
.as("ordersReadyForCapture");
const variantsList = productsUtils.getCreatedVariants();
ordersUtils.createWaitingForCaptureOrder(
defaultChannel.slug,
randomEmail,
variantsList,
shippingUtils.getShippingMethod().id
);
cy.get("@ordersReadyForCapture").then(ordersReadyForCaptureBefore => {
const allOrdersReadyForCapture = ordersReadyForCaptureBefore + 1;
const notANumberRegex = "\\D*";
const ordersReadyForCaptureRegexp = new RegExp(
`${notANumberRegex}${allOrdersReadyForCapture}${notANumberRegex}`
);
cy.visit(urlList.homePage);
homePageSteps.changeChannel(defaultChannel.name);
cy.contains(
HOMEPAGE_SELECTORS.ordersReadyForCapture,
ordersReadyForCaptureRegexp
).should("be.visible");
});
});
it("should correct amount of products out of stock be displayed", () => {
homePageUtils
.getProductsOutOfStock(defaultChannel.slug)
.as("productsOutOfStock");
const productOutOfStockRandomName = startsWith + faker.random.number();
const productsOutOfStockUtils = new ProductsUtils();
const warehouse = shippingUtils.getWarehouse();
const productType = productsUtils.getProductType();
const attribute = productsUtils.getAttribute();
const category = productsUtils.getCategory();
productsOutOfStockUtils.createProductInChannel(
productOutOfStockRandomName,
defaultChannel.id,
warehouse.id,
0,
productType.id,
attribute.id,
category.id,
productPrice
);
cy.get("@productsOutOfStock").then(productsOutOfStockBefore => {
const allProductsOutOfStock = productsOutOfStockBefore + 1;
const notANumberRegex = "\\D*";
const productsOutOfStockRegexp = new RegExp(
`${notANumberRegex}${allProductsOutOfStock}${notANumberRegex}`
);
cy.visit(urlList.homePage);
homePageSteps.changeChannel(defaultChannel.name);
cy.contains(
HOMEPAGE_SELECTORS.productsOutOfStock,
productsOutOfStockRegexp
).should("be.visible");
});
});
it("should correct amount of sales be displayed", () => {
homePageUtils.getSalesAmount(defaultChannel.slug).as("salesAmount");
ordersUtils.createReadyToFulfillOrder(
customerId,
shippingUtils.getShippingMethod().id,
defaultChannel.id,
productsUtils.getCreatedVariants()
);
cy.get("@salesAmount").then(salesAmount => {
const totalAmount = salesAmount + productPrice;
const totalAmountString = totalAmount.toFixed(2);
const totalAmountIntegerValue = totalAmountString.split(".")[0];
const totalAmountDecimalValue = totalAmountString.split(".")[1];
const decimalSeparator = "[,.]";
const totalAmountIntegerWithThousandsSeparator = totalAmountIntegerValue.replace(
/(\d)(?=(\d{3})+(?!\d))/g,
"1[,.]*"
);
const totalAmountWithSeparators = `${totalAmountIntegerWithThousandsSeparator}${decimalSeparator}${totalAmountDecimalValue}`;
const notANumberRegex = "\\D*";
const salesAmountRegexp = new RegExp(
`${notANumberRegex}${totalAmountWithSeparators}${notANumberRegex}`
);
cy.visit(urlList.homePage);
homePageSteps.changeChannel(defaultChannel.name);
cy.contains(HOMEPAGE_SELECTORS.sales, salesAmountRegexp).should(
"be.visible"
);
});
});
it("should correct amount of orders be displayed", () => {
homePageUtils.getTodaysOrders(defaultChannel.slug).as("todaysOrders");
ordersUtils.createReadyToFulfillOrder(
customerId,
shippingUtils.getShippingMethod().id,
defaultChannel.id,
productsUtils.getCreatedVariants()
);
cy.get("@todaysOrders").then(ordersBefore => {
const allOrders = ordersBefore + 1;
const notANumberRegex = "\\D*";
const ordersRegexp = new RegExp(
`${notANumberRegex}${allOrders}${notANumberRegex}`
);
cy.visit(urlList.homePage);
homePageSteps.changeChannel(defaultChannel.name);
cy.contains(HOMEPAGE_SELECTORS.orders, ordersRegexp).should("be.visible");
});
});
});

View file

@ -16,16 +16,16 @@ describe("Products available in listings", () => {
const frontShopProductUtils = new FrontShopProductUtils(); const frontShopProductUtils = new FrontShopProductUtils();
const startsWith = "Cy-"; const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`; const name = `${startsWith}${faker.random.number()}`;
let productTypeId; let productType;
let attributeId; let attribute;
let categoryId; let category;
let defaultChannel; let defaultChannel;
let warehouseId; let warehouse;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
shippingUtils.deleteShipping(startsWith); shippingUtils.deleteShipping(startsWith);
productsUtils.deleteProducts(startsWith); productsUtils.deleteProperProducts(startsWith);
channelsUtils.getDefaultChannel().then(channel => { channelsUtils.getDefaultChannel().then(channel => {
defaultChannel = channel; defaultChannel = channel;
@ -33,14 +33,14 @@ describe("Products available in listings", () => {
shippingUtils shippingUtils
.createShipping(defaultChannel, name, json.plAddress, 10) .createShipping(defaultChannel, name, json.plAddress, 10)
.then(() => { .then(() => {
warehouseId = shippingUtils.getWarehouseId(); warehouse = shippingUtils.getWarehouse();
}); });
}); });
}); });
productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
productTypeId = productsUtils.getProductTypeId(); productType = productsUtils.getProductType();
attributeId = productsUtils.getAttributeId(); attribute = productsUtils.getAttribute();
categoryId = productsUtils.getCategoryId(); category = productsUtils.getCategory();
}); });
}); });
@ -50,19 +50,20 @@ 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.createProductInChannel(productName);
productsUtils productsUtils
.createProductInChannel( .createProductInChannel(
productName, productName,
productTypeId,
attributeId,
categoryId,
defaultChannel.id, defaultChannel.id,
warehouse.id,
10,
productType.id,
attribute.id,
category,
true, true,
false, false,
true, true,
warehouseId, 1
10,
10
) )
.then(() => { .then(() => {
const productUrl = `${ const productUrl = `${
@ -85,16 +86,16 @@ describe("Products available in listings", () => {
productsUtils productsUtils
.createProductInChannel( .createProductInChannel(
productName, productName,
productTypeId,
attributeId,
categoryId,
defaultChannel.id, defaultChannel.id,
true, warehouse.id,
true,
true,
warehouseId,
10, 10,
10 productType.id,
attribute.id,
category,
true,
true,
true,
1
) )
.then(() => { .then(() => {
const productUrl = `${ const productUrl = `${

View file

@ -15,17 +15,17 @@ describe("Publish products", () => {
const startsWith = "Cy-"; const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`; const name = `${startsWith}${faker.random.number()}`;
let productTypeId; let productType;
let attributeId; let attribute;
let categoryId; let category;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
productsUtils.deleteProducts(startsWith); productsUtils.deleteProperProducts(startsWith);
productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
productTypeId = productsUtils.getProductTypeId(); productType = productsUtils.getProductType();
attributeId = productsUtils.getAttributeId(); attribute = productsUtils.getAttribute();
categoryId = productsUtils.getCategoryId(); category = productsUtils.getCategory();
}); });
}); });
@ -38,9 +38,9 @@ describe("Publish products", () => {
productsUtils productsUtils
.createProductInChannel( .createProductInChannel(
productName, productName,
productTypeId, productType.id,
attributeId, attribute.id,
categoryId, category.id,
defaultChannel.id, defaultChannel.id,
false, false,
false, false,
@ -64,9 +64,9 @@ describe("Publish products", () => {
productsUtils productsUtils
.createProductInChannel( .createProductInChannel(
productName, productName,
productTypeId, productType.id,
attributeId, attribute.id,
categoryId, category.id,
defaultChannel.id, defaultChannel.id,
true, true,
false, false,

View file

@ -15,17 +15,17 @@ describe("Products displayed in listings", () => {
const startsWith = "Cy-"; const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`; const name = `${startsWith}${faker.random.number()}`;
let productTypeId; let productType;
let attributeId; let attribute;
let categoryId; let category;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
productsUtils.deleteProducts(startsWith); productsUtils.deleteProperProducts(startsWith);
productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
productTypeId = productsUtils.getProductTypeId(); productType = productsUtils.getProductType();
attributeId = productsUtils.getAttributeId(); attribute = productsUtils.getAttribute();
categoryId = productsUtils.getCategoryId(); category = productsUtils.getCategory();
}); });
}); });
@ -38,9 +38,9 @@ describe("Products displayed in listings", () => {
productsUtils productsUtils
.createProductInChannel( .createProductInChannel(
productName, productName,
productTypeId, productType.id,
attributeId, attribute.id,
categoryId, category.id,
defaultChannel.id, defaultChannel.id,
true, true,
false, false,
@ -64,9 +64,9 @@ describe("Products displayed in listings", () => {
productsUtils productsUtils
.createProductInChannel( .createProductInChannel(
productName, productName,
productTypeId, productType.id,
attributeId, attribute.id,
categoryId, category.id,
defaultChannel.id, defaultChannel.id,
true, true,
false, false,

View file

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

View file

@ -0,0 +1,18 @@
Cypress.Commands.add(
"handleDeleteElement",
(element, deleteFunction, startsWith) => {
if (element.node.name.includes(startsWith)) {
deleteFunction(element.node.id);
}
}
);
Cypress.Commands.add(
"deleteProperElements",
(deleteFunction, getFunction, startsWith, name) => {
getFunction(100, startsWith).then(elements => {
elements.forEach(element => {
cy.handleDeleteElement(element, deleteFunction, startsWith);
});
});
}
);

View file

@ -1,4 +1,6 @@
import "./user"; import "./user";
import "./softAssertions";
import "./deleteElement/index.js";
import { urlList } from "../url/urlList"; import { urlList } from "../url/urlList";
@ -20,7 +22,7 @@ Cypress.Commands.add("clearSessionData", () => {
}); });
Cypress.Commands.add("waitForGraph", operationName => { Cypress.Commands.add("waitForGraph", operationName => {
cy.intercept("POST", Cypress.env("API_URI"), req => { cy.intercept("POST", urlList.apiUri, req => {
req.statusCode = 200; req.statusCode = 200;
const requestBody = req.body; const requestBody = req.body;
if (Array.isArray(requestBody)) { if (Array.isArray(requestBody)) {

View file

@ -0,0 +1,89 @@
let isSoftAssertion = false;
let errors = [];
chai.softExpect = function(...args) {
isSoftAssertion = true;
return chai.expect(...args);
};
chai.softAssert = function(...args) {
isSoftAssertion = true;
return chai.assert(...args);
};
const origAssert = chai.Assertion.prototype.assert;
chai.Assertion.prototype.assert = function(...args) {
if (isSoftAssertion) {
try {
origAssert.call(this, ...args);
} catch (error) {
errors.push(error);
}
isSoftAssertion = false;
} else {
origAssert.call(this, ...args);
}
};
// monkey-patch `Cypress.log` so that the last `cy.then()` isn't logged to command log
const origLog = Cypress.log;
Cypress.log = function(data) {
if (data && data.error && /soft assertions/i.test(data.error.message)) {
data.error.message = "\n\n\t" + data.error.message + "\n\n";
throw data.error;
}
return origLog.call(Cypress, ...arguments);
};
// monkey-patch `it` callback so we insert `cy.then()` as a last command
// to each test case where we'll assert if there are any soft assertion errors
function itCallback(func) {
func();
cy.then(() => {
if (errors.length) {
const _ = Cypress._;
let msg = "";
if (Cypress.browser.isHeaded) {
msg = "Failed soft assertions... check log above ↑";
} else {
_.each(errors, error => {
msg += "\n" + error;
});
msg = msg.replace(/^/gm, "\t");
}
throw new Error(msg);
}
});
}
const origIt = window.it;
window.it = (title, func) => {
origIt(title, func && (() => itCallback(func)));
};
window.it.only = (title, func) => {
origIt.only(title, func && (() => itCallback(func)));
};
window.it.skip = (title, func) => {
origIt.skip(title, func);
};
beforeEach(() => {
errors = [];
});
afterEach(() => {
errors = [];
isSoftAssertion = false;
});
Cypress.Commands.add("softAssertMatch", (selector, regexp) => {
cy.get(selector)
.invoke("text")
.then(text =>
chai.softExpect(assert.match(text, regexp, "regexp matches"))
);
});
Cypress.Commands.add("softAssertVisibility", selector => {
cy.get(selector).then(element => chai.softExpect(element).to.be.visible);
});

View file

@ -6,24 +6,25 @@ class ChannelsUtils {
deleteChannels(nameStartsWith) { deleteChannels(nameStartsWith) {
this.channels.getChannels().then(resp => { this.channels.getChannels().then(resp => {
const channelsArray = new Set(resp.body.data.channels); const channelsArray = new Set(resp.body.data.channels);
if (channelsArray) { if (!channelsArray) {
channelsArray.forEach(element => { return;
if (element.name.startsWith(nameStartsWith)) {
const targetChannels = Array.from(channelsArray).filter(function(
channelElement
) {
return (
element.currencyCode === channelElement.currencyCode &&
element.id !== channelElement.id
);
});
if (targetChannels[0]) {
this.channels.deleteChannel(element.id, targetChannels[0].id);
channelsArray.delete(element);
}
}
});
} }
channelsArray.forEach(element => {
if (element.name.startsWith(nameStartsWith)) {
const targetChannels = Array.from(channelsArray).filter(function(
channelElement
) {
return (
element.currencyCode === channelElement.currencyCode &&
element.id !== channelElement.id
);
});
if (targetChannels[0]) {
this.channels.deleteChannel(element.id, targetChannels[0].id);
channelsArray.delete(element);
}
}
});
}); });
} }
getDefaultChannel() { getDefaultChannel() {

View file

@ -0,0 +1,30 @@
import HomePage from "../apiRequests/HomePage";
class HomePageUtils {
homePage = new HomePage();
getOrdersReadyToFulfill(channelSlug) {
return this.homePage
.getOrdersWithStatus("READY_TO_FULFILL", channelSlug)
.then(resp => resp.body.data.orders.totalCount);
}
getOrdersReadyForCapture(channelSlug) {
return this.homePage
.getOrdersWithStatus("READY_TO_CAPTURE", channelSlug)
.then(resp => resp.body.data.orders.totalCount);
}
getProductsOutOfStock(channelSlug) {
return this.homePage
.getProductsOutOfStock(channelSlug)
.then(resp => resp.body.data.products.totalCount);
}
getSalesAmount(channelSlug) {
return this.homePage
.getSalesForChannel(channelSlug, "TODAY")
.then(resp => resp.body.data.ordersTotal.gross.amount);
}
getTodaysOrders(channelSlug) {
return this.homePage
.getOrdersForChannel(channelSlug, "TODAY")
.then(resp => resp.body.data.orders.totalCount);
}
}
export default HomePageUtils;

View file

@ -0,0 +1,60 @@
import Checkout from "../apiRequests/Checkout";
import Order from "../apiRequests/Order";
class OrdersUtils {
checkoutRequest = new Checkout();
orderRequest = new Order();
checkout;
order;
createWaitingForCaptureOrder(
channelSlug,
email,
variantsList,
shippingMethodId
) {
return this.createCheckout(channelSlug, email, variantsList)
.then(() =>
this.checkoutRequest.addShippingMethod(
this.checkout.id,
shippingMethodId
)
)
.then(() => this.addPayment(this.checkout.id))
.then(() => this.checkoutRequest.completeCheckout(this.checkout.id));
}
createReadyToFulfillOrder(
customerId,
shippingMethodId,
channelId,
variantsList
) {
return this.createDraftOrder(customerId, shippingMethodId, channelId)
.then(() => {
variantsList.forEach(variantElement => {
this.orderRequest.addProductToOrder(this.order.id, variantElement.id);
});
})
.then(() => this.orderRequest.markOrderAsPaid(this.order.id))
.then(() => this.orderRequest.completeOrder(this.order.id));
}
createDraftOrder(customerId, shippingMethodId, channelId) {
return this.orderRequest
.createDraftOrder(customerId, shippingMethodId, channelId)
.then(resp => (this.order = resp.body.data.draftOrderCreate.order));
}
createCheckout(channelSlug, email, variantsList) {
return this.checkoutRequest
.createCheckout(channelSlug, email, 1, variantsList)
.then(resp => (this.checkout = resp.body.data.checkoutCreate.checkout));
}
addPayment(checkoutId) {
return this.checkoutRequest.addPayment(
checkoutId,
"mirumee.payments.dummy",
"not-charged"
);
}
}
export default OrdersUtils;

View file

@ -3,153 +3,139 @@ import Category from "../apiRequests/Category";
import Product from "../apiRequests/Product"; import Product from "../apiRequests/Product";
class ProductsUtils { class ProductsUtils {
createdVariantId; productRequest = new Product();
createdProductId; attributeRequest = new Attribute();
productTypeId; categoryRequest = new Category();
attributeId;
categoryId;
updateChannelInProduct(productsList, channelId) { product;
const product = new Product(); variants;
productsList.forEach(productElement => { productType;
product.updateChannelInProduct(productElement.node.id, channelId); attribute;
const variants = productElement.node.variants; category;
variants.forEach(variant => {
product.updateChannelPriceInVariant(variant.id, channelId); createProductWithVariant(name, attributeId, productTypeId, categoryId) {
}); return this.createProduct(
}); attributeId,
} name,
createProduct(name, attributeId, productTypeId, categoryId) { productTypeId,
const product = new Product(); categoryId
return product ).then(() => this.createVariant(this.product.id, name));
.createProduct(attributeId, name, productTypeId, categoryId)
.then(createProductResp => {
this.createdProductId =
createProductResp.body.data.productCreate.product.id;
return product
.createVariant(this.createdProductId, name)
.then(createVariantResp => {
this.createdVariantId =
createVariantResp.body.data.productVariantBulkCreate.productVariants;
});
});
} }
createProductInChannel( createProductInChannel(
name, name,
channelId,
warehouseId,
quantityInWarehouse,
productTypeId, productTypeId,
attributeId, attributeId,
categoryId, categoryId,
channelId,
isPublished,
isAvailableForPurchase,
visibleInListings,
warehouseId,
quantityInWarehouse,
price price
) { ) {
const product = new Product(); return this.createProduct(attributeId, name, productTypeId, categoryId)
return product .then(() =>
.createProduct(attributeId, name, productTypeId, categoryId) this.productRequest.updateChannelInProduct(this.product.id, channelId)
.then(createProductResp => { )
this.createdProductId = .then(() => {
createProductResp.body.data.productCreate.product.id; this.createVariant(
return product this.product.id,
.updateChannelInProduct( name,
this.createdProductId, warehouseId,
channelId, quantityInWarehouse,
isPublished, channelId,
isAvailableForPurchase, price
visibleInListings );
)
.then(() =>
product
.createVariant(
this.createdProductId,
name,
warehouseId,
quantityInWarehouse,
channelId,
price
)
.then(createVariantResp => {
this.createdVariantId =
createVariantResp.body.data.productVariantBulkCreate.productVariants;
})
);
}); });
} }
createTypeAttributeAndCategoryForProduct(name) { createTypeAttributeAndCategoryForProduct(name) {
const attribute = new Attribute(); return this.createAttribute(name)
const category = new Category(); .then(() => this.createTypeProduct(name, this.attribute.id))
const product = new Product(); .then(() => this.createCategory(name));
return attribute.createAttribute(name).then(createAttributeResp => { }
this.attributeId = createAttribute(name) {
createAttributeResp.body.data.attributeCreate.attribute.id; return this.attributeRequest
return product .createAttribute(name)
.createTypeProduct(name, this.attributeId) .then(
.then(createTypeProductResp => { resp => (this.attribute = resp.body.data.attributeCreate.attribute)
this.productTypeId = );
createTypeProductResp.body.data.productTypeCreate.productType.id; }
return category.createCategory(name).then(categoryResp => { createTypeProduct(name, attributeId) {
this.categoryId = categoryResp.body.data.categoryCreate.category.id; return this.productRequest
}); .createTypeProduct(name, attributeId)
}); .then(
}); resp =>
(this.productType = resp.body.data.productTypeCreate.productType)
);
}
createCategory(name) {
return this.categoryRequest
.createCategory(name)
.then(resp => (this.category = resp.body.data.categoryCreate.category));
}
createProduct(attributeId, name, productTypeId, categoryId) {
return this.productRequest
.createProduct(attributeId, name, productTypeId, categoryId)
.then(resp => (this.product = resp.body.data.productCreate.product));
}
createVariant(
productId,
name,
warehouseId,
quantityInWarehouse,
channelId,
price
) {
return this.productRequest
.createVariant(
productId,
name,
warehouseId,
quantityInWarehouse,
channelId,
price
)
.then(
resp =>
(this.variants =
resp.body.data.productVariantBulkCreate.productVariants)
);
} }
getCreatedVariants() { getCreatedVariants() {
return this.createdVariantId; return this.variants;
} }
getProductTypeId() { getProductType() {
return this.productTypeId; return this.productType;
} }
getAttributeId() { getAttribute() {
return this.attributeId; return this.attribute;
} }
getCategoryId() { getCategory() {
return this.categoryId; return this.category;
} }
getCreatedProductId() { deleteProperProducts(startsWith) {
return this.createdProductId;
}
deleteProducts(startsWith) {
const product = new Product(); const product = new Product();
const attribute = new Attribute(); const attribute = new Attribute();
const category = new Category(); const category = new Category();
product.getProductTypes(100, startsWith).then(resp => { cy.deleteProperElements(
const productTypes = resp.body.data.productTypes.edges; product.deleteProductType,
productTypes.forEach(productType => { product.getProductTypes,
if (productType.node.name.includes(startsWith)) { startsWith,
product.deleteProductType(productType.node.id); "productType"
} );
}); cy.deleteProperElements(
}); attribute.deleteAttribute,
attribute.getAttributes(100, startsWith).then(resp => { attribute.getAttributes,
const attributes = resp.body.data.attributes.edges; startsWith,
attributes.forEach(attributeElement => { "attributes"
if (attributeElement.node.name.includes(startsWith)) { );
attribute.deleteAttribute(attributeElement.node.id); cy.deleteProperElements(
} category.deleteCategory,
}); category.getCategories,
}); startsWith,
category.getCategories(100, startsWith).then(resp => { "categories"
const categories = resp.body.data.categories.edges; );
categories.forEach(categoryElement => {
if (categoryElement.node.name.includes(startsWith)) {
category.deleteCategory(categoryElement.node.id);
}
});
});
product.getFirstProducts(100, startsWith).then(getProductResp => {
const products = getProductResp.body.data.products.edges;
products.forEach(productElement => {
if (productElement.node.name.includes(startsWith)) {
product.deleteProducts(productElement.node.id);
}
});
});
} }
} }
export default ProductsUtils; export default ProductsUtils;

View file

@ -1,71 +1,77 @@
import ShippingMethod from "../apiRequests/ShippingMethod"; import ShippingMethod from "../apiRequests/ShippingMethod";
import Warehouse from "../apiRequests/Warehouse"; import Warehouse from "../apiRequests/Warehouse";
class ShippingUtils { class ShippingUtils {
shippingMethodId; shippingMethodRequest = new ShippingMethod();
shippingZoneId; warehouseRequest = new Warehouse();
warehouseId;
shippingMethod;
shippingZone;
warehouse;
createShipping(channelId, name, address, price) { createShipping(channelId, name, address, price) {
const shippingMethod = new ShippingMethod(); return this.createShippingZone(name, address.country)
const warehouse = new Warehouse(); .then(() => this.createWarehouse(name, this.shippingZone.id, address))
return shippingMethod .then(() => this.createShippingRate(name, this.shippingZone.id))
.createShippingZone(name, address.country) .then(() =>
.then(shippingZoneResp => { this.shippingMethodRequest.addChannelToShippingMethod(
this.shippingZoneId = this.shippingMethod.id,
shippingZoneResp.body.data.shippingZoneCreate.shippingZone.id; channelId,
return warehouse price
.createWarehouse(name, this.shippingZoneId, address) )
.then(createWarehouseResp => { );
this.warehouseId = }
createWarehouseResp.body.data.createWarehouse.warehouse.id;
return shippingMethod createShippingZone(name, country) {
.createShippingRate(name, this.shippingZoneId) return this.shippingMethodRequest
.then(rateResp => { .createShippingZone(name, country)
this.shippingMethodId = .then(resp => {
rateResp.body.data.shippingPriceCreate.shippingMethod.id; this.shippingZone = resp.body.data.shippingZoneCreate.shippingZone;
return shippingMethod.addChannelToShippingMethod(
this.shippingMethodId,
channelId,
price
);
});
});
}); });
} }
createWarehouse(name, shippingZoneId, address) {
getShippingMethodId() { return this.warehouseRequest
return this.shippingMethodId; .createWarehouse(name, shippingZoneId, address)
.then(resp => {
this.warehouse = resp.body.data.createWarehouse.warehouse;
});
}
createShippingRate(name, shippingZoneId) {
return this.shippingMethodRequest
.createShippingRate(name, shippingZoneId)
.then(
resp =>
(this.shippingMethod =
resp.body.data.shippingPriceCreate.shippingMethod)
);
} }
getShippingZoneId() { getShippingMethod() {
return this.shippingZoneId; return this.shippingMethod;
} }
getWarehouseId() { getShippingZone() {
return this.warehouseId; return this.shippingZone;
}
getWarehouse() {
return this.warehouse;
} }
deleteShipping(startsWith) { deleteShipping(startsWith) {
const shippingMethod = new ShippingMethod(); const shippingMethod = new ShippingMethod();
const warehouse = new Warehouse(); const warehouse = new Warehouse();
shippingMethod.getShippingZones().then(resp => { cy.deleteProperElements(
if (resp.body.data.shippingZones) { shippingMethod.deleteShippingZone,
const shippingZone = resp.body.data.shippingZones.edges; shippingMethod.getShippingZones,
shippingZone.forEach(element => { startsWith,
if (element.node.name.includes(startsWith)) { "shippingZONE"
shippingMethod.deleteShippingZone(element.node.id); );
} cy.deleteProperElements(
}); warehouse.deleteWarehouse,
} warehouse.getWarehouses,
}); startsWith,
warehouse.getWarehouses(100, startsWith).then(resp => { "Warehouse"
const warehouses = resp.body.data.warehouses.edges; );
warehouses.forEach(warehouseElement => {
if (warehouseElement.node.name.includes(startsWith)) {
warehouse.deleteWarehouse(warehouseElement.node.id);
}
});
});
} }
} }
export default ShippingUtils; export default ShippingUtils;

6
package-lock.json generated
View file

@ -17,6 +17,7 @@
"@material-ui/icons": "^4.5.1", "@material-ui/icons": "^4.5.1",
"@material-ui/styles": "^4.5.2", "@material-ui/styles": "^4.5.2",
"@saleor/macaw-ui": "^0.1.1-9", "@saleor/macaw-ui": "^0.1.1-9",
"@types/faker": "^5.1.6",
"@sentry/react": "^6.0.0", "@sentry/react": "^6.0.0",
"apollo": "^2.21.2", "apollo": "^2.21.2",
"apollo-cache-inmemory": "^1.6.5", "apollo-cache-inmemory": "^1.6.5",
@ -32475,6 +32476,11 @@
"integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==",
"dev": true "dev": true
}, },
"@types/faker": {
"version": "5.1.6",
"resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.1.6.tgz",
"integrity": "sha512-D+gfFWR/YCvlrYL8lgNZO1jKgIUW+cfhxsgMOqUMYwCI+tl0htD7vCCXp/oJsIxJpxuI7zqmo3gpVQBkFCM4iA=="
},
"@types/fuzzaldrin": { "@types/fuzzaldrin": {
"version": "2.1.2", "version": "2.1.2",
"resolved": "https://registry.npmjs.org/@types/fuzzaldrin/-/fuzzaldrin-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@types/fuzzaldrin/-/fuzzaldrin-2.1.2.tgz",

View file

@ -26,6 +26,7 @@
"@material-ui/icons": "^4.5.1", "@material-ui/icons": "^4.5.1",
"@material-ui/styles": "^4.5.2", "@material-ui/styles": "^4.5.2",
"@saleor/macaw-ui": "^0.1.1-9", "@saleor/macaw-ui": "^0.1.1-9",
"@types/faker": "^5.1.6",
"@sentry/react": "^6.0.0", "@sentry/react": "^6.0.0",
"apollo": "^2.21.2", "apollo": "^2.21.2",
"apollo-cache-inmemory": "^1.6.5", "apollo-cache-inmemory": "^1.6.5",

View file

@ -30,16 +30,17 @@ const useStyles = makeStyles(
interface HomeActivityCardProps { interface HomeActivityCardProps {
activities: Home_activities_edges_node[]; activities: Home_activities_edges_node[];
testId?: string;
} }
const HomeActivityCard: React.FC<HomeActivityCardProps> = props => { const HomeActivityCard: React.FC<HomeActivityCardProps> = props => {
const { activities } = props; const { activities, testId } = props;
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
return ( return (
<Card> <Card data-test-id={testId}>
<CardTitle <CardTitle
title={intl.formatMessage({ title={intl.formatMessage({
defaultMessage: "Activity", defaultMessage: "Activity",

View file

@ -53,19 +53,20 @@ const useStyles = makeStyles(
); );
interface HomeAnalyticsCardProps { interface HomeAnalyticsCardProps {
testId?: string;
icon: React.ReactElement<IconProps>; icon: React.ReactElement<IconProps>;
title: string; title: string;
children?: React.ReactNode; children?: React.ReactNode;
} }
const HomeAnalyticsCard: React.FC<HomeAnalyticsCardProps> = props => { const HomeAnalyticsCard: React.FC<HomeAnalyticsCardProps> = props => {
const { children, title, icon } = props; const { children, title, icon, testId } = props;
const classes = useStyles(props); const classes = useStyles(props);
return ( return (
<Card className={classes.cardSpacing}> <Card className={classes.cardSpacing}>
<CardContent className={classes.cardContent}> <CardContent className={classes.cardContent} data-test-id={testId}>
<div> <div>
<Typography className={classes.cardTitle} variant="subtitle1"> <Typography className={classes.cardTitle} variant="subtitle1">
{title} {title}

View file

@ -116,7 +116,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
requiredPermissions={[PermissionEnum.MANAGE_ORDERS]} requiredPermissions={[PermissionEnum.MANAGE_ORDERS]}
> >
<TableRow hover={true} onClick={onOrdersToFulfillClick}> <TableRow hover={true} onClick={onOrdersToFulfillClick}>
<TableCell> <TableCell data-test-id="orders-to-fulfill">
{ordersToFulfill === undefined ? ( {ordersToFulfill === undefined ? (
<Skeleton /> <Skeleton />
) : ordersToFulfill === 0 ? ( ) : ordersToFulfill === 0 ? (
@ -136,7 +136,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
</TableCell> </TableCell>
</TableRow> </TableRow>
<TableRow hover={true} onClick={onOrdersToCaptureClick}> <TableRow hover={true} onClick={onOrdersToCaptureClick}>
<TableCell> <TableCell data-test-id="orders-to-capture">
{ordersToCapture === undefined ? ( {ordersToCapture === undefined ? (
<Skeleton /> <Skeleton />
) : ordersToCapture === 0 ? ( ) : ordersToCapture === 0 ? (
@ -161,7 +161,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
requiredPermissions={[PermissionEnum.MANAGE_PRODUCTS]} requiredPermissions={[PermissionEnum.MANAGE_PRODUCTS]}
> >
<TableRow hover={true} onClick={onProductsOutOfStockClick}> <TableRow hover={true} onClick={onProductsOutOfStockClick}>
<TableCell> <TableCell data-test-id="products-out-of-stock">
{productsOutOfStock === undefined ? ( {productsOutOfStock === undefined ? (
<Skeleton /> <Skeleton />
) : productsOutOfStock === 0 ? ( ) : productsOutOfStock === 0 ? (

View file

@ -95,6 +95,7 @@ const HomePage: React.FC<HomePageProps> = props => {
<div className={classes.cardContainer}> <div className={classes.cardContainer}>
<HomeAnalyticsCard <HomeAnalyticsCard
title={"Sales"} title={"Sales"}
testId="sales-analytics"
icon={ icon={
<Sales <Sales
className={classes.icon} className={classes.icon}
@ -113,6 +114,7 @@ const HomePage: React.FC<HomePageProps> = props => {
</HomeAnalyticsCard> </HomeAnalyticsCard>
<HomeAnalyticsCard <HomeAnalyticsCard
title={"Orders"} title={"Orders"}
testId="orders-analytics"
icon={ icon={
<Orders <Orders
className={classes.icon} className={classes.icon}
@ -152,6 +154,7 @@ const HomePage: React.FC<HomePageProps> = props => {
]} ]}
> >
<HomeProductListCard <HomeProductListCard
testId="top-products"
onRowClick={onProductClick} onRowClick={onProductClick}
topProducts={topProducts} topProducts={topProducts}
/> />
@ -165,7 +168,10 @@ const HomePage: React.FC<HomePageProps> = props => {
userPermissions={userPermissions} userPermissions={userPermissions}
requiredPermissions={[PermissionEnum.MANAGE_ORDERS]} requiredPermissions={[PermissionEnum.MANAGE_ORDERS]}
> >
<HomeActivityCard activities={activities} /> <HomeActivityCard
activities={activities}
testId="activity-card"
/>
</RequirePermissions> </RequirePermissions>
</div> </div>
)} )}

View file

@ -46,18 +46,19 @@ const useStyles = makeStyles(
); );
interface HomeProductListProps { interface HomeProductListProps {
testId?: string;
topProducts: Home_productTopToday_edges_node[]; topProducts: Home_productTopToday_edges_node[];
onRowClick: (productId: string, variantId: string) => void; onRowClick: (productId: string, variantId: string) => void;
} }
export const HomeProductList: React.FC<HomeProductListProps> = props => { export const HomeProductList: React.FC<HomeProductListProps> = props => {
const { topProducts, onRowClick } = props; const { topProducts, onRowClick, testId } = props;
const classes = useStyles(props); const classes = useStyles(props);
const intl = useIntl(); const intl = useIntl();
return ( return (
<Card> <Card data-test-id={testId}>
<CardTitle <CardTitle
title={intl.formatMessage({ title={intl.formatMessage({
defaultMessage: "Top Products", defaultMessage: "Top Products",

View file

@ -92177,6 +92177,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="sales-analytics"
> >
<div> <div>
<div <div
@ -92220,6 +92221,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="orders-analytics"
> >
<div> <div>
<div <div
@ -92276,6 +92278,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-fulfill"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -92307,6 +92310,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-capture"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -92335,6 +92339,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="products-out-of-stock"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -92367,6 +92372,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
/> />
<div <div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id" class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
data-test-id="top-products"
> >
<div <div
class="CardTitle-root-id" class="CardTitle-root-id"
@ -92466,6 +92472,7 @@ exports[`Storyshots Views / HomePage default 1`] = `
<div> <div>
<div <div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id" class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
data-test-id="activity-card"
> >
<div <div
class="CardTitle-root-id" class="CardTitle-root-id"
@ -92882,6 +92889,7 @@ exports[`Storyshots Views / HomePage loading 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="sales-analytics"
> >
<div> <div>
<div <div
@ -92930,6 +92938,7 @@ exports[`Storyshots Views / HomePage loading 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="orders-analytics"
> >
<div> <div>
<div <div
@ -92991,6 +93000,7 @@ exports[`Storyshots Views / HomePage loading 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-fulfill"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93019,6 +93029,7 @@ exports[`Storyshots Views / HomePage loading 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-capture"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93047,6 +93058,7 @@ exports[`Storyshots Views / HomePage loading 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="products-out-of-stock"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93123,6 +93135,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="sales-analytics"
> >
<div> <div>
<div <div
@ -93166,6 +93179,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="orders-analytics"
> >
<div> <div>
<div <div
@ -93222,6 +93236,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-fulfill"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93253,6 +93268,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-capture"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93281,6 +93297,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="products-out-of-stock"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93313,6 +93330,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
/> />
<div <div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id" class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
data-test-id="top-products"
> >
<div <div
class="CardTitle-root-id" class="CardTitle-root-id"
@ -93375,6 +93393,7 @@ exports[`Storyshots Views / HomePage no data 1`] = `
<div> <div>
<div <div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id" class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
data-test-id="activity-card"
> >
<div <div
class="CardTitle-root-id" class="CardTitle-root-id"
@ -93515,6 +93534,7 @@ exports[`Storyshots Views / HomePage order permissions 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="sales-analytics"
> >
<div> <div>
<div <div
@ -93558,6 +93578,7 @@ exports[`Storyshots Views / HomePage order permissions 1`] = `
> >
<div <div
class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id" class="MuiCardContent-root-id HomeAnalyticsCard-cardContent-id"
data-test-id="orders-analytics"
> >
<div> <div>
<div <div
@ -93614,6 +93635,7 @@ exports[`Storyshots Views / HomePage order permissions 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-fulfill"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93645,6 +93667,7 @@ exports[`Storyshots Views / HomePage order permissions 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="orders-to-capture"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"
@ -93679,6 +93702,7 @@ exports[`Storyshots Views / HomePage order permissions 1`] = `
<div> <div>
<div <div
class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id" class="MuiPaper-root-id MuiPaper-elevation0-id MuiCard-root-id MuiPaper-rounded-id"
data-test-id="activity-card"
> >
<div <div
class="CardTitle-root-id" class="CardTitle-root-id"
@ -94094,6 +94118,7 @@ exports[`Storyshots Views / HomePage product permissions 1`] = `
> >
<td <td
class="MuiTableCell-root-id MuiTableCell-body-id" class="MuiTableCell-root-id MuiTableCell-body-id"
data-test-id="products-out-of-stock"
> >
<div <div
class="MuiTypography-root-id MuiTypography-body1-id" class="MuiTypography-root-id MuiTypography-body1-id"