diff --git a/.github/workflows/deploy-staging.yaml b/.github/workflows/deploy-staging.yaml index f098f9a69..7efc99b97 100644 --- a/.github/workflows/deploy-staging.yaml +++ b/.github/workflows/deploy-staging.yaml @@ -8,7 +8,7 @@ jobs: build: runs-on: ubuntu-20.04 env: - API_URI: https://master.staging.saleor.cloud/graphql/ + API_URI: /graphql/ APP_MOUNT_URI: /dashboard/ STATIC_URL: /dashboard/static/ SENTRY_ORG: saleor diff --git a/cypress/apiRequests/Attribute.js b/cypress/apiRequests/Attribute.js index 4ba3467f2..b0f23be23 100644 --- a/cypress/apiRequests/Attribute.js +++ b/cypress/apiRequests/Attribute.js @@ -20,29 +20,31 @@ class Attribute { getAttributes(first, search) { const mutation = `query{ - attributes(first:${first}, filter:{ - search:"${search}" - }){ - edges{ - node{ - id - name - } + attributes(first:${first}, filter:{ + search:"${search}" + }){ + edges{ + node{ + id + name } } - }`; - return cy.sendRequestWithQuery(mutation); + } + }`; + return cy + .sendRequestWithQuery(mutation) + .then(resp => resp.body.data.attributes.edges); } deleteAttribute(attributeId) { const mutation = `mutation{ - attributeDelete(id:"${attributeId}"){ - attributeErrors{ - field - message - } + attributeDelete(id:"${attributeId}"){ + attributeErrors{ + field + message } - }`; + } + }`; return cy.sendRequestWithQuery(mutation); } } diff --git a/cypress/apiRequests/Category.js b/cypress/apiRequests/Category.js index 0d76c7b3b..ad5d4f0dd 100644 --- a/cypress/apiRequests/Category.js +++ b/cypress/apiRequests/Category.js @@ -1,42 +1,44 @@ class Category { createCategory(name, slug = name) { const mutation = `mutation{ - categoryCreate(input:{name:"${name}", slug: "${slug}"}){ - productErrors{ - field - message - } - category{ - id - } - } - }`; + categoryCreate(input:{name:"${name}", slug: "${slug}"}){ + productErrors{ + field + message + } + category{ + id + } + } + }`; return cy.sendRequestWithQuery(mutation); } getCategories(first, search) { const mutation = `query{ - categories(first:${first}, filter:{ - search:"${search}" - }){ - edges{ - node{ - id - name - } + categories(first:${first}, filter:{ + search:"${search}" + }){ + edges{ + node{ + id + name } } - }`; - return cy.sendRequestWithQuery(mutation); + } + }`; + return cy + .sendRequestWithQuery(mutation) + .then(resp => resp.body.data.categories.edges); } deleteCategory(categoryId) { const mutation = `mutation{ - categoryDelete(id:"${categoryId}"){ - productErrors{ - field - message - } + categoryDelete(id:"${categoryId}"){ + productErrors{ + field + message } - }`; + } + }`; return cy.sendRequestWithQuery(mutation); } } diff --git a/cypress/apiRequests/Channels.js b/cypress/apiRequests/Channels.js index 2daa39a9e..39e8f8162 100644 --- a/cypress/apiRequests/Channels.js +++ b/cypress/apiRequests/Channels.js @@ -8,6 +8,7 @@ class Channels { currencyCode: "${currencyCode}" }){ channel{ + id name slug } @@ -19,32 +20,30 @@ class Channels { }`; return cy.sendRequestWithQuery(createChannelMutation); } - getChannels() { const getChannelsInfoQuery = `query{ - channels{ - name - id - isActive - slug - currencyCode - } + channels{ + name + id + isActive + slug + currencyCode } - `; + } + `; return cy.sendRequestWithQuery(getChannelsInfoQuery); } - deleteChannel(channelId, targetChennelId) { + deleteChannel(channelId, targetChannelId) { const deleteChannelMutation = `mutation{ - channelDelete(id: "${channelId}", input:{ - targetChannel: "${targetChennelId}" - }){ - channel{ - name - } - channelErrors{ - message - } + channelDelete(id: "${channelId}", input:{ + targetChannel: "${targetChannelId}" + }){ + channel{ + name + } + channelErrors{ + message } }`; return cy.sendRequestWithQuery(deleteChannelMutation); diff --git a/cypress/apiRequests/Checkout.js b/cypress/apiRequests/Checkout.js new file mode 100644 index 000000000..28f9fbf69 --- /dev/null +++ b/cypress/apiRequests/Checkout.js @@ -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; diff --git a/cypress/apiRequests/Customer.js b/cypress/apiRequests/Customer.js new file mode 100644 index 000000000..336dbf698 --- /dev/null +++ b/cypress/apiRequests/Customer.js @@ -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; diff --git a/cypress/apiRequests/HomePage.js b/cypress/apiRequests/HomePage.js new file mode 100644 index 000000000..09026cc03 --- /dev/null +++ b/cypress/apiRequests/HomePage.js @@ -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; diff --git a/cypress/apiRequests/Order.js b/cypress/apiRequests/Order.js new file mode 100644 index 000000000..0005d344a --- /dev/null +++ b/cypress/apiRequests/Order.js @@ -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; diff --git a/cypress/apiRequests/Product.js b/cypress/apiRequests/Product.js index 035c6f083..e0b41cdb3 100644 --- a/cypress/apiRequests/Product.js +++ b/cypress/apiRequests/Product.js @@ -1,34 +1,34 @@ class Product { getFirstProducts(first, search) { - let filter = ""; - if (search) { - filter = `, filter:{ - search:"${search}" - }`; - } + const filter = search + ? `, filter:{ + search:"${search}" + }` + : ""; const query = `query{ - products(first:${first}${filter}){ - edges{ - node{ + products(first:${first}${filter}){ + edges{ + node{ + id + name + variants{ id - name - variants{ - id - } } } } } `; - return cy.sendRequestWithQuery(query); + return cy + .sendRequestWithQuery(query) + .then(resp => resp.body.data.products.edges); } updateChannelInProduct( productId, channelId, - isPublished, - isAvailableForPurchase, - visibleInListings + isPublished = true, + isAvailableForPurchase = true, + visibleInListings = true ) { const mutation = `mutation{ productChannelListingUpdate(id:"${productId}", @@ -46,42 +46,41 @@ class Product { } } }`; - return cy.sendRequestWithQuery(mutation); } updateChannelPriceInVariant(variantId, channelId) { const mutation = `mutation{ - productVariantChannelListingUpdate(id: "${variantId}", input:{ - channelId: "${channelId}" + productVariantChannelListingUpdate(id: "${variantId}", input: { + channelId: "${channelId}" price: 10 costPrice: 10 - }){ - productChannelListingErrors{ - message - } - } - }`; + }){ + productChannelListingErrors{ + message + } + } +} `; return cy.sendRequestWithQuery(mutation); } createProduct(attributeId, name, productType, category) { const mutation = `mutation{ - productCreate(input:{ - attributes:[{ - id:"${attributeId}" - }] - name:"${name}" - productType:"${productType}" - category:"${category}" - }){ - product{ - id - } - productErrors{ - field - message - } + productCreate(input:{ + attributes:[{ + id:"${attributeId}" + }] + name:"${name}" + productType:"${productType}" + category:"${category}" + }){ + product{ + id } - }`; + productErrors{ + field + message + } + } + }`; return cy.sendRequestWithQuery(mutation); } @@ -94,98 +93,92 @@ class Product { price = 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{ - productVariantBulkCreate(product:"${productId}", variants:{ - attributes:[] - sku:"${sku}" - ${channelListings} - ${stocks} - }){ - productVariants{ - id - name - } - bulkProductErrors{ - field - message - } + productVariantBulkCreate(product: "${productId}", variants: { + attributes: [] + sku: "${sku}" + channelListings: { + channelId: "${channelId}" + price: "${price}" + costPrice: "${costPrice}" } - }`; + stocks: { + warehouse: "${warehouseId}" + quantity: ${quantity} + } +}) { + productVariants{ + id + name + } + bulkProductErrors{ + field + message + } +} + }`; return cy.sendRequestWithQuery(mutation); } createTypeProduct(name, attributeId, slug = name) { const mutation = `mutation{ - productTypeCreate(input:{ - name:"${name}" - slug: "${slug}" - isShippingRequired:true - productAttributes:"${attributeId}" - }){ - productErrors{ - field - message - } - productType{ - id - } - } - }`; + productTypeCreate(input: { + name: "${name}" + slug: "${slug}" + isShippingRequired: true + productAttributes: "${attributeId}" + }){ + productErrors{ + field + message + } + productType{ + id + } + } +} `; return cy.sendRequestWithQuery(mutation); } deleteProduct(productId) { const mutation = `mutation{ - productDelete(id:"${productId}"){ - productErrors{ - field - message - } - } - }`; + productDelete(id: "${productId}"){ + productErrors{ + field + message + } + } +} `; return cy.sendRequestWithQuery(mutation); } getProductTypes(first, search) { const query = `query{ - productTypes(first:${first}, filter:{ - search:"${search}" - }){ - edges{ - node{ - id - name - } + productTypes(first:${first}, filter:{ + search:"${search}" + }){ + edges{ + node{ + id + name } } - }`; - return cy.sendRequestWithQuery(query); + } + }`; + return cy + .sendRequestWithQuery(query) + .then(resp => resp.body.data.productTypes.edges); } deleteProductType(productTypeId) { const mutation = `mutation{ - productTypeDelete(id:"${productTypeId}"){ - productErrors{ - field - message - } + productTypeDelete(id:"${productTypeId}"){ + productErrors{ + field + message } - }`; + } + }`; return cy.sendRequestWithQuery(mutation); } } diff --git a/cypress/apiRequests/ShippingMethod.js b/cypress/apiRequests/ShippingMethod.js index 25c067a43..6c9deb3de 100644 --- a/cypress/apiRequests/ShippingMethod.js +++ b/cypress/apiRequests/ShippingMethod.js @@ -1,84 +1,86 @@ class ShippingMethod { createShippingRate(name, shippingZone) { const mutation = ` - mutation{ - shippingPriceCreate(input:{ - name: "${name}" - shippingZone: "${shippingZone}" - type: PRICE - }){ - shippingMethod{ - id - } + mutation{ + shippingPriceCreate(input:{ + name: "${name}" + shippingZone: "${shippingZone}" + type: PRICE + }){ + shippingMethod{ + id } } - `; + } + `; return cy.sendRequestWithQuery(mutation); } createShippingZone(name, country) { const mutation = ` - mutation{ - shippingZoneCreate(input:{ - name: "${name}" - countries: "${country}" - }){ - shippingZone{ - id - } + mutation{ + shippingZoneCreate(input:{ + name: "${name}" + countries: "${country}" + }){ + shippingZone{ + id } } - `; + } + `; return cy.sendRequestWithQuery(mutation); } addChannelToShippingMethod(shippingRateId, channelId, price) { const mutation = ` - mutation{ - shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ - addChannels: { - channelId:"${channelId}" - price: ${price} - } - }){ - shippingMethod{ - id - } - shippingErrors{ - code - message - } + mutation{ + shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ + addChannels: { + channelId:"${channelId}" + price: ${price} + } + }){ + shippingMethod{ + id + } + shippingErrors{ + code + message } } - `; + } + `; return cy.sendRequestWithQuery(mutation); } deleteShippingZone(shippingZoneId) { const mutation = `mutation{ - shippingZoneDelete(id:"${shippingZoneId}"){ - shippingErrors{ - message - } + shippingZoneDelete(id:"${shippingZoneId}"){ + shippingErrors{ + message } } - `; + } + `; return cy.sendRequestWithQuery(mutation); } getShippingZones() { const query = `query{ - shippingZones(first:100){ - edges{ - node{ - name - id - } + shippingZones(first:100){ + edges{ + node{ + name + id } } } - `; - return cy.sendRequestWithQuery(query); + } + `; + return cy + .sendRequestWithQuery(query) + .then(resp => resp.body.data.shippingZones.edges); } } export default ShippingMethod; diff --git a/cypress/apiRequests/Warehouse.js b/cypress/apiRequests/Warehouse.js index 80df7f6f6..8237a9333 100644 --- a/cypress/apiRequests/Warehouse.js +++ b/cypress/apiRequests/Warehouse.js @@ -1,54 +1,56 @@ class Warehouse { createWarehouse(name, shippingZone, address, slug = name) { const mutation = `mutation{ - createWarehouse(input:{ - name:"${name}" - slug:"${slug}" - shippingZones:"${shippingZone}" - address:{ - streetAddress1: "${address.streetAddress1}" - streetAddress2: "${address.streetAddress2}" - city: "${address.city}" - postalCode: "${address.postalCode}" - country: ${address.country} - phone: "${address.phone}" - } - }){ - warehouseErrors{ - field - message - } - warehouse{ - id - } + createWarehouse(input:{ + name:"${name}" + slug:"${slug}" + shippingZones:"${shippingZone}" + address:{ + streetAddress1: "${address.streetAddress1}" + streetAddress2: "${address.streetAddress2}" + city: "${address.city}" + postalCode: "${address.postalCode}" + country: ${address.country} + phone: "${address.phone}" } - }`; + }){ + warehouseErrors{ + field + message + } + warehouse{ + id + } + } + }`; return cy.sendRequestWithQuery(mutation); } getWarehouses(first, search) { const query = `query{ - warehouses(first:${first}, filter:{ - search:"${search}" - }){ - edges{ - node{ - id - name - } + warehouses(first:${first}, filter:{ + search:"${search}" + }){ + edges{ + node{ + id + name } } - }`; - return cy.sendRequestWithQuery(query); + } + }`; + return cy + .sendRequestWithQuery(query) + .then(resp => resp.body.data.warehouses.edges); } deleteWarehouse(warehouseId) { const mutation = `mutation{ - deleteWarehouse(id:"${warehouseId}"){ - warehouseErrors{ - field - message - } + deleteWarehouse(id:"${warehouseId}"){ + warehouseErrors{ + field + message } - }`; + } + }`; return cy.sendRequestWithQuery(mutation); } } diff --git a/cypress/elements/homePage/homePage-selectors.js b/cypress/elements/homePage/homePage-selectors.js new file mode 100644 index 000000000..221cb68e8 --- /dev/null +++ b/cypress/elements/homePage/homePage-selectors.js @@ -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']" +}; diff --git a/cypress/integration/channels.js b/cypress/integration/channels.js index e9c61f7c9..bfee7abae 100644 --- a/cypress/integration/channels.js +++ b/cypress/integration/channels.js @@ -20,8 +20,8 @@ describe("Channels", () => { const channelStartsWith = "Cypress:"; const currency = "PLN"; const channels = new Channels(); - const channelsSteps = new ChannelsSteps(); const channelsUtils = new ChannelsUtils(); + const channelsSteps = new ChannelsSteps(); before(() => { cy.clearSessionData().loginUserViaRequest(); diff --git a/cypress/integration/homePage.js b/cypress/integration/homePage.js new file mode 100644 index 000000000..74e8762a1 --- /dev/null +++ b/cypress/integration/homePage.js @@ -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"; + +// +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"); + }); + }); +}); diff --git a/cypress/integration/products/availableForPurchaseProducts.js b/cypress/integration/products/availableForPurchaseProducts.js index 198f6a8ef..44d34d70f 100644 --- a/cypress/integration/products/availableForPurchaseProducts.js +++ b/cypress/integration/products/availableForPurchaseProducts.js @@ -16,16 +16,16 @@ describe("Products available in listings", () => { const frontShopProductUtils = new FrontShopProductUtils(); const startsWith = "Cy-"; const name = `${startsWith}${faker.random.number()}`; - let productTypeId; - let attributeId; - let categoryId; + let productType; + let attribute; + let category; let defaultChannel; - let warehouseId; + let warehouse; before(() => { cy.clearSessionData().loginUserViaRequest(); shippingUtils.deleteShipping(startsWith); - productsUtils.deleteProducts(startsWith); + productsUtils.deleteProperProducts(startsWith); channelsUtils.getDefaultChannel().then(channel => { defaultChannel = channel; @@ -33,14 +33,14 @@ describe("Products available in listings", () => { shippingUtils .createShipping(defaultChannel, name, json.plAddress, 10) .then(() => { - warehouseId = shippingUtils.getWarehouseId(); + warehouse = shippingUtils.getWarehouse(); }); }); }); productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { - productTypeId = productsUtils.getProductTypeId(); - attributeId = productsUtils.getAttributeId(); - categoryId = productsUtils.getCategoryId(); + productType = productsUtils.getProductType(); + attribute = productsUtils.getAttribute(); + category = productsUtils.getCategory(); }); }); @@ -50,19 +50,20 @@ describe("Products available in listings", () => { it("should update product to available for purchase", () => { const productName = `${startsWith}${faker.random.number()}`; + productsUtils.createProductInChannel(productName); productsUtils .createProductInChannel( productName, - productTypeId, - attributeId, - categoryId, defaultChannel.id, + warehouse.id, + 10, + productType.id, + attribute.id, + category, true, false, true, - warehouseId, - 10, - 10 + 1 ) .then(() => { const productUrl = `${ @@ -85,16 +86,16 @@ describe("Products available in listings", () => { productsUtils .createProductInChannel( productName, - productTypeId, - attributeId, - categoryId, defaultChannel.id, - true, - true, - true, - warehouseId, + warehouse.id, 10, - 10 + productType.id, + attribute.id, + category, + true, + true, + true, + 1 ) .then(() => { const productUrl = `${ diff --git a/cypress/integration/products/publishedProducts.js b/cypress/integration/products/publishedProducts.js index 5d6a46378..031437342 100644 --- a/cypress/integration/products/publishedProducts.js +++ b/cypress/integration/products/publishedProducts.js @@ -15,17 +15,17 @@ describe("Publish products", () => { const startsWith = "Cy-"; const name = `${startsWith}${faker.random.number()}`; - let productTypeId; - let attributeId; - let categoryId; + let productType; + let attribute; + let category; before(() => { cy.clearSessionData().loginUserViaRequest(); - productsUtils.deleteProducts(startsWith); + productsUtils.deleteProperProducts(startsWith); productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { - productTypeId = productsUtils.getProductTypeId(); - attributeId = productsUtils.getAttributeId(); - categoryId = productsUtils.getCategoryId(); + productType = productsUtils.getProductType(); + attribute = productsUtils.getAttribute(); + category = productsUtils.getCategory(); }); }); @@ -38,9 +38,9 @@ describe("Publish products", () => { productsUtils .createProductInChannel( productName, - productTypeId, - attributeId, - categoryId, + productType.id, + attribute.id, + category.id, defaultChannel.id, false, false, @@ -64,9 +64,9 @@ describe("Publish products", () => { productsUtils .createProductInChannel( productName, - productTypeId, - attributeId, - categoryId, + productType.id, + attribute.id, + category.id, defaultChannel.id, true, false, diff --git a/cypress/integration/products/visibleInListingsProducts.js b/cypress/integration/products/visibleInListingsProducts.js index 2d6ff8614..321bc1969 100644 --- a/cypress/integration/products/visibleInListingsProducts.js +++ b/cypress/integration/products/visibleInListingsProducts.js @@ -15,17 +15,17 @@ describe("Products displayed in listings", () => { const startsWith = "Cy-"; const name = `${startsWith}${faker.random.number()}`; - let productTypeId; - let attributeId; - let categoryId; + let productType; + let attribute; + let category; before(() => { cy.clearSessionData().loginUserViaRequest(); - productsUtils.deleteProducts(startsWith); + productsUtils.deleteProperProducts(startsWith); productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => { - productTypeId = productsUtils.getProductTypeId(); - attributeId = productsUtils.getAttributeId(); - categoryId = productsUtils.getCategoryId(); + productType = productsUtils.getProductType(); + attribute = productsUtils.getAttribute(); + category = productsUtils.getCategory(); }); }); @@ -38,9 +38,9 @@ describe("Products displayed in listings", () => { productsUtils .createProductInChannel( productName, - productTypeId, - attributeId, - categoryId, + productType.id, + attribute.id, + category.id, defaultChannel.id, true, false, @@ -64,9 +64,9 @@ describe("Products displayed in listings", () => { productsUtils .createProductInChannel( productName, - productTypeId, - attributeId, - categoryId, + productType.id, + attribute.id, + category.id, defaultChannel.id, true, false, diff --git a/cypress/steps/homePageSteps.js b/cypress/steps/homePageSteps.js new file mode 100644 index 000000000..bd53c0972 --- /dev/null +++ b/cypress/steps/homePageSteps.js @@ -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; diff --git a/cypress/support/deleteElement/index.js b/cypress/support/deleteElement/index.js new file mode 100644 index 000000000..ff15bd8b3 --- /dev/null +++ b/cypress/support/deleteElement/index.js @@ -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); + }); + }); + } +); diff --git a/cypress/support/index.js b/cypress/support/index.js index 03851e2ca..f6115623a 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -1,4 +1,6 @@ import "./user"; +import "./softAssertions"; +import "./deleteElement/index.js"; import { urlList } from "../url/urlList"; @@ -20,7 +22,7 @@ Cypress.Commands.add("clearSessionData", () => { }); Cypress.Commands.add("waitForGraph", operationName => { - cy.intercept("POST", Cypress.env("API_URI"), req => { + cy.intercept("POST", urlList.apiUri, req => { req.statusCode = 200; const requestBody = req.body; if (Array.isArray(requestBody)) { diff --git a/cypress/support/softAssertions/index.js b/cypress/support/softAssertions/index.js new file mode 100644 index 000000000..559ae921f --- /dev/null +++ b/cypress/support/softAssertions/index.js @@ -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); +}); diff --git a/cypress/utils/channelsUtils.js b/cypress/utils/channelsUtils.js index dbb053c6e..81af09c5d 100644 --- a/cypress/utils/channelsUtils.js +++ b/cypress/utils/channelsUtils.js @@ -6,24 +6,25 @@ class ChannelsUtils { deleteChannels(nameStartsWith) { this.channels.getChannels().then(resp => { const channelsArray = new Set(resp.body.data.channels); - if (channelsArray) { - 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); - } - } - }); + if (!channelsArray) { + return; } + 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() { diff --git a/cypress/utils/homePageUtils.js b/cypress/utils/homePageUtils.js new file mode 100644 index 000000000..27d298105 --- /dev/null +++ b/cypress/utils/homePageUtils.js @@ -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; diff --git a/cypress/utils/ordersUtils.js b/cypress/utils/ordersUtils.js new file mode 100644 index 000000000..e535624d9 --- /dev/null +++ b/cypress/utils/ordersUtils.js @@ -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; diff --git a/cypress/utils/productsUtils.js b/cypress/utils/productsUtils.js index 914e51aaa..a134e7c53 100644 --- a/cypress/utils/productsUtils.js +++ b/cypress/utils/productsUtils.js @@ -3,153 +3,139 @@ import Category from "../apiRequests/Category"; import Product from "../apiRequests/Product"; class ProductsUtils { - createdVariantId; - createdProductId; - productTypeId; - attributeId; - categoryId; + productRequest = new Product(); + attributeRequest = new Attribute(); + categoryRequest = new Category(); - updateChannelInProduct(productsList, channelId) { - const product = new Product(); - productsList.forEach(productElement => { - product.updateChannelInProduct(productElement.node.id, channelId); - const variants = productElement.node.variants; - variants.forEach(variant => { - product.updateChannelPriceInVariant(variant.id, channelId); - }); - }); - } - createProduct(name, attributeId, productTypeId, categoryId) { - const product = new Product(); - return product - .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; - }); - }); + product; + variants; + productType; + attribute; + category; + + createProductWithVariant(name, attributeId, productTypeId, categoryId) { + return this.createProduct( + attributeId, + name, + productTypeId, + categoryId + ).then(() => this.createVariant(this.product.id, name)); } + createProductInChannel( name, + channelId, + warehouseId, + quantityInWarehouse, productTypeId, attributeId, categoryId, - channelId, - isPublished, - isAvailableForPurchase, - visibleInListings, - warehouseId, - quantityInWarehouse, price ) { - const product = new Product(); - return product - .createProduct(attributeId, name, productTypeId, categoryId) - .then(createProductResp => { - this.createdProductId = - createProductResp.body.data.productCreate.product.id; - return product - .updateChannelInProduct( - this.createdProductId, - channelId, - isPublished, - isAvailableForPurchase, - visibleInListings - ) - .then(() => - product - .createVariant( - this.createdProductId, - name, - warehouseId, - quantityInWarehouse, - channelId, - price - ) - .then(createVariantResp => { - this.createdVariantId = - createVariantResp.body.data.productVariantBulkCreate.productVariants; - }) - ); + return this.createProduct(attributeId, name, productTypeId, categoryId) + .then(() => + this.productRequest.updateChannelInProduct(this.product.id, channelId) + ) + .then(() => { + this.createVariant( + this.product.id, + name, + warehouseId, + quantityInWarehouse, + channelId, + price + ); }); } createTypeAttributeAndCategoryForProduct(name) { - const attribute = new Attribute(); - const category = new Category(); - const product = new Product(); - return attribute.createAttribute(name).then(createAttributeResp => { - this.attributeId = - createAttributeResp.body.data.attributeCreate.attribute.id; - return product - .createTypeProduct(name, this.attributeId) - .then(createTypeProductResp => { - this.productTypeId = - createTypeProductResp.body.data.productTypeCreate.productType.id; - return category.createCategory(name).then(categoryResp => { - this.categoryId = categoryResp.body.data.categoryCreate.category.id; - }); - }); - }); + return this.createAttribute(name) + .then(() => this.createTypeProduct(name, this.attribute.id)) + .then(() => this.createCategory(name)); + } + createAttribute(name) { + return this.attributeRequest + .createAttribute(name) + .then( + resp => (this.attribute = resp.body.data.attributeCreate.attribute) + ); + } + createTypeProduct(name, attributeId) { + 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() { - return this.createdVariantId; + return this.variants; } - getProductTypeId() { - return this.productTypeId; + getProductType() { + return this.productType; } - getAttributeId() { - return this.attributeId; + getAttribute() { + return this.attribute; } - getCategoryId() { - return this.categoryId; + getCategory() { + return this.category; } - getCreatedProductId() { - return this.createdProductId; - } - - deleteProducts(startsWith) { + deleteProperProducts(startsWith) { const product = new Product(); const attribute = new Attribute(); const category = new Category(); - product.getProductTypes(100, startsWith).then(resp => { - const productTypes = resp.body.data.productTypes.edges; - productTypes.forEach(productType => { - if (productType.node.name.includes(startsWith)) { - product.deleteProductType(productType.node.id); - } - }); - }); - attribute.getAttributes(100, startsWith).then(resp => { - const attributes = resp.body.data.attributes.edges; - attributes.forEach(attributeElement => { - if (attributeElement.node.name.includes(startsWith)) { - attribute.deleteAttribute(attributeElement.node.id); - } - }); - }); - category.getCategories(100, startsWith).then(resp => { - 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); - } - }); - }); + cy.deleteProperElements( + product.deleteProductType, + product.getProductTypes, + startsWith, + "productType" + ); + cy.deleteProperElements( + attribute.deleteAttribute, + attribute.getAttributes, + startsWith, + "attributes" + ); + cy.deleteProperElements( + category.deleteCategory, + category.getCategories, + startsWith, + "categories" + ); } } export default ProductsUtils; diff --git a/cypress/utils/shippingUtils.js b/cypress/utils/shippingUtils.js index 5806ac82d..1fb352907 100644 --- a/cypress/utils/shippingUtils.js +++ b/cypress/utils/shippingUtils.js @@ -1,71 +1,77 @@ import ShippingMethod from "../apiRequests/ShippingMethod"; import Warehouse from "../apiRequests/Warehouse"; class ShippingUtils { - shippingMethodId; - shippingZoneId; - warehouseId; + shippingMethodRequest = new ShippingMethod(); + warehouseRequest = new Warehouse(); + + shippingMethod; + shippingZone; + warehouse; createShipping(channelId, name, address, price) { - const shippingMethod = new ShippingMethod(); - const warehouse = new Warehouse(); - return shippingMethod - .createShippingZone(name, address.country) - .then(shippingZoneResp => { - this.shippingZoneId = - shippingZoneResp.body.data.shippingZoneCreate.shippingZone.id; - return warehouse - .createWarehouse(name, this.shippingZoneId, address) - .then(createWarehouseResp => { - this.warehouseId = - createWarehouseResp.body.data.createWarehouse.warehouse.id; - return shippingMethod - .createShippingRate(name, this.shippingZoneId) - .then(rateResp => { - this.shippingMethodId = - rateResp.body.data.shippingPriceCreate.shippingMethod.id; - return shippingMethod.addChannelToShippingMethod( - this.shippingMethodId, - channelId, - price - ); - }); - }); + return this.createShippingZone(name, address.country) + .then(() => this.createWarehouse(name, this.shippingZone.id, address)) + .then(() => this.createShippingRate(name, this.shippingZone.id)) + .then(() => + this.shippingMethodRequest.addChannelToShippingMethod( + this.shippingMethod.id, + channelId, + price + ) + ); + } + + createShippingZone(name, country) { + return this.shippingMethodRequest + .createShippingZone(name, country) + .then(resp => { + this.shippingZone = resp.body.data.shippingZoneCreate.shippingZone; }); } - - getShippingMethodId() { - return this.shippingMethodId; + createWarehouse(name, shippingZoneId, address) { + return this.warehouseRequest + .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() { - return this.shippingZoneId; + getShippingMethod() { + return this.shippingMethod; } - getWarehouseId() { - return this.warehouseId; + getShippingZone() { + return this.shippingZone; + } + + getWarehouse() { + return this.warehouse; } deleteShipping(startsWith) { const shippingMethod = new ShippingMethod(); const warehouse = new Warehouse(); - shippingMethod.getShippingZones().then(resp => { - if (resp.body.data.shippingZones) { - const shippingZone = resp.body.data.shippingZones.edges; - shippingZone.forEach(element => { - if (element.node.name.includes(startsWith)) { - shippingMethod.deleteShippingZone(element.node.id); - } - }); - } - }); - warehouse.getWarehouses(100, startsWith).then(resp => { - const warehouses = resp.body.data.warehouses.edges; - warehouses.forEach(warehouseElement => { - if (warehouseElement.node.name.includes(startsWith)) { - warehouse.deleteWarehouse(warehouseElement.node.id); - } - }); - }); + cy.deleteProperElements( + shippingMethod.deleteShippingZone, + shippingMethod.getShippingZones, + startsWith, + "shippingZONE" + ); + cy.deleteProperElements( + warehouse.deleteWarehouse, + warehouse.getWarehouses, + startsWith, + "Warehouse" + ); } } export default ShippingUtils; diff --git a/package-lock.json b/package-lock.json index fd6915086..32b6981df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,6 +17,7 @@ "@material-ui/icons": "^4.5.1", "@material-ui/styles": "^4.5.2", "@saleor/macaw-ui": "^0.1.1-9", + "@types/faker": "^5.1.6", "@sentry/react": "^6.0.0", "apollo": "^2.21.2", "apollo-cache-inmemory": "^1.6.5", @@ -32475,6 +32476,11 @@ "integrity": "sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==", "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": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/@types/fuzzaldrin/-/fuzzaldrin-2.1.2.tgz", diff --git a/package.json b/package.json index 9eccdfa2f..bd58a5648 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ "@material-ui/icons": "^4.5.1", "@material-ui/styles": "^4.5.2", "@saleor/macaw-ui": "^0.1.1-9", + "@types/faker": "^5.1.6", "@sentry/react": "^6.0.0", "apollo": "^2.21.2", "apollo-cache-inmemory": "^1.6.5", diff --git a/src/home/components/HomeActivityCard/HomeActivityCard.tsx b/src/home/components/HomeActivityCard/HomeActivityCard.tsx index 4094a8f35..d8dc07803 100644 --- a/src/home/components/HomeActivityCard/HomeActivityCard.tsx +++ b/src/home/components/HomeActivityCard/HomeActivityCard.tsx @@ -30,16 +30,17 @@ const useStyles = makeStyles( interface HomeActivityCardProps { activities: Home_activities_edges_node[]; + testId?: string; } const HomeActivityCard: React.FC = props => { - const { activities } = props; + const { activities, testId } = props; const classes = useStyles(props); const intl = useIntl(); return ( - + ; title: string; children?: React.ReactNode; } const HomeAnalyticsCard: React.FC = props => { - const { children, title, icon } = props; + const { children, title, icon, testId } = props; const classes = useStyles(props); return ( - +
{title} diff --git a/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx b/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx index 918fd4646..47456b8aa 100644 --- a/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx +++ b/src/home/components/HomeNotificationTable/HomeNotificationTable.tsx @@ -116,7 +116,7 @@ const HomeNotificationTable: React.FC = props => { requiredPermissions={[PermissionEnum.MANAGE_ORDERS]} > - + {ordersToFulfill === undefined ? ( ) : ordersToFulfill === 0 ? ( @@ -136,7 +136,7 @@ const HomeNotificationTable: React.FC = props => { - + {ordersToCapture === undefined ? ( ) : ordersToCapture === 0 ? ( @@ -161,7 +161,7 @@ const HomeNotificationTable: React.FC = props => { requiredPermissions={[PermissionEnum.MANAGE_PRODUCTS]} > - + {productsOutOfStock === undefined ? ( ) : productsOutOfStock === 0 ? ( diff --git a/src/home/components/HomePage/HomePage.tsx b/src/home/components/HomePage/HomePage.tsx index dbae63670..da8d36498 100644 --- a/src/home/components/HomePage/HomePage.tsx +++ b/src/home/components/HomePage/HomePage.tsx @@ -95,6 +95,7 @@ const HomePage: React.FC = props => {
= props => { = props => { ]} > @@ -165,7 +168,10 @@ const HomePage: React.FC = props => { userPermissions={userPermissions} requiredPermissions={[PermissionEnum.MANAGE_ORDERS]} > - +
)} diff --git a/src/home/components/HomeProductListCard/HomeProductListCard.tsx b/src/home/components/HomeProductListCard/HomeProductListCard.tsx index d68cfbe64..13b0c1d6b 100644 --- a/src/home/components/HomeProductListCard/HomeProductListCard.tsx +++ b/src/home/components/HomeProductListCard/HomeProductListCard.tsx @@ -46,18 +46,19 @@ const useStyles = makeStyles( ); interface HomeProductListProps { + testId?: string; topProducts: Home_productTopToday_edges_node[]; onRowClick: (productId: string, variantId: string) => void; } export const HomeProductList: React.FC = props => { - const { topProducts, onRowClick } = props; + const { topProducts, onRowClick, testId } = props; const classes = useStyles(props); const intl = useIntl(); return ( - +