From f1d4b11a81f734deb9d292dfcf87674970c5f632 Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Tue, 19 Jan 2021 22:17:49 +0100 Subject: [PATCH 01/24] test for elements visibility, TODO - api requests for creating order --- .../elements/dashboard/dashboard-selectors.js | 11 +++ cypress/fixtures/addresses.json | 12 +++ cypress/integration/dashboard.js | 36 +++++++++ cypress/support/customer/index.js | 37 +++++++++ cypress/support/index.js | 3 + cypress/support/shippingMethod.js | 48 +++++++++++ cypress/support/softAsserations/index.js | 81 +++++++++++++++++++ 7 files changed, 228 insertions(+) create mode 100644 cypress/elements/dashboard/dashboard-selectors.js create mode 100644 cypress/fixtures/addresses.json create mode 100644 cypress/integration/dashboard.js create mode 100644 cypress/support/customer/index.js create mode 100644 cypress/support/shippingMethod.js create mode 100644 cypress/support/softAsserations/index.js diff --git a/cypress/elements/dashboard/dashboard-selectors.js b/cypress/elements/dashboard/dashboard-selectors.js new file mode 100644 index 000000000..5c71fe47e --- /dev/null +++ b/cypress/elements/dashboard/dashboard-selectors.js @@ -0,0 +1,11 @@ +export const DASHBOARD_SELECTORS = { + sales: "div:nth-child(1) > [class*='HomeAnalyticsCard-cardContent']", + orders: "div:nth-child(2) > [class*='HomeAnalyticsCard-cardContent']", + activity: "[class*='Grid-root'] > div:nth-child(2) > [class*='MuiPaper']", + topProducts: + "[class*='Grid-root'] > div:nth-child(1) > [class*='MuiPaper']:nth-child(4)", + ordersReadyToFulfill: "[class*='HomeNotificationTable'] > tr:nth-child(1)", + paymentsWaitingForCapture: + "[class*='HomeNotificationTable'] > tr:nth-child(2)", + productsOutOfStock: "[class*='HomeNotificationTable'] > tr:nth-child(3)" +}; diff --git a/cypress/fixtures/addresses.json b/cypress/fixtures/addresses.json new file mode 100644 index 000000000..742bd227e --- /dev/null +++ b/cypress/fixtures/addresses.json @@ -0,0 +1,12 @@ +{ + "plAddress": { + "companyName": "Test3", + "streetAddress1": "Smolna", + "streetAddress2": "13/1", + "city": "Wrocław", + "postalCode": "53-346", + "country": "PL", + "countryArea": "Dolny Śląsk", + "phone": "123456787" + } +} \ No newline at end of file diff --git a/cypress/integration/dashboard.js b/cypress/integration/dashboard.js new file mode 100644 index 000000000..ad6ee2945 --- /dev/null +++ b/cypress/integration/dashboard.js @@ -0,0 +1,36 @@ +// import { DASHBOARD_SELECTORS } from "../elements/dashboard/dashboard-selectors"; + +// // +// describe("User authorization", () => { +// beforeEach(() => { +// cy.clearSessionData().loginUserViaRequest(); +// }); + +// xit("should all elements be visible on the dashboard", () => { +// cy.visit("/"); +// softAssertVisibility(DASHBOARD_SELECTORS.sales); +// softAssertVisibility(DASHBOARD_SELECTORS.orders); +// softAssertVisibility(DASHBOARD_SELECTORS.activity); +// softAssertVisibility(DASHBOARD_SELECTORS.topProducts); +// softAssertVisibility(DASHBOARD_SELECTORS.ordersReadyToFulfill); +// softAssertVisibility(DASHBOARD_SELECTORS.paymentsWaitingForCapture); +// softAssertVisibility(DASHBOARD_SELECTORS.productsOutOfStock); +// }); + +// xit("aa", () => { +// // cy.fixture('addresses').then((json) => { +// // cy.createCustomer("Test9","Test9", json.plAddress); +// // }); +// // createChannel(); +// // createRateShipping(); +// // addChannelToProduct(); +// // createOrder(); +// }); + +// function softAssertVisibility(selector){ +// const {softExpect} = chai; +// cy.get(selector).then( element => { +// softExpect(element).to.be.visible; +// }) +// } +// }); diff --git a/cypress/support/customer/index.js b/cypress/support/customer/index.js new file mode 100644 index 000000000..0a900581c --- /dev/null +++ b/cypress/support/customer/index.js @@ -0,0 +1,37 @@ +Cypress.Commands.add( + "createCustomer", + (email, name, address, isActive = false) => { + const mustation = ` + mutation{ + customerCreate(input:{ + firstName: "${name}" + lastName: "${name}" + 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}" + } + }){ + accountErrors{ + code + } + } + } + `; + } +); diff --git a/cypress/support/index.js b/cypress/support/index.js index 531b8aab9..c863c2167 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -1,4 +1,7 @@ import "./user"; +import "./softAsserations"; +import "./customer"; +import "./shippingMethod"; Cypress.Commands.add("clearSessionData", () => { // Because of known cypress bug, not all local storage data are cleared. diff --git a/cypress/support/shippingMethod.js b/cypress/support/shippingMethod.js new file mode 100644 index 000000000..84fa3cfd7 --- /dev/null +++ b/cypress/support/shippingMethod.js @@ -0,0 +1,48 @@ +Cypress.Commands.add("createShippingRate", (name, shippingZone) => { + const mutation = ` + mutation{ + CreateShippingRate(input:{ + maximumDeliveryDays: null + minimumDeliveryDays: null + name: "${name}" + shippingZone: "${shippingZone}" + type: "PRICE" + }) + } + `; +}); + +Cypress.Commands.add("createShippingZone", (name, country) => { + const mutation = ` + mutation{ + shippingZoneCreate(input:{ + name: "${name}" + countries: "${country}" + }){ + shippingZone{ + id + } + } + } + `; +}); + +Cypress.Commands.add("", (shippingRateId, channelId) => { + const mutation = ` + mutation{ + shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ + addChannels: { + channelId:"${channelId}" + } + }){ + shippingMethod{ + id + } + shippingErrors{ + code + message + } + } + } + `; +}); diff --git a/cypress/support/softAsserations/index.js b/cypress/support/softAsserations/index.js new file mode 100644 index 000000000..3405514da --- /dev/null +++ b/cypress/support/softAsserations/index.js @@ -0,0 +1,81 @@ +// 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; +// }); From f9e80901207c297dba5cce4d801114e1648569de Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Thu, 21 Jan 2021 11:05:54 +0100 Subject: [PATCH 02/24] Add mutation query --- cypress/fixtures/example.json | 5 + cypress/integration/dashboard.js | 61 ++++---- .../index.js} | 3 + cypress/support/softAsserations/index.js | 141 +++++++++--------- 4 files changed, 106 insertions(+), 104 deletions(-) create mode 100644 cypress/fixtures/example.json rename cypress/support/{shippingMethod.js => shippingMethod/index.js} (94%) diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json new file mode 100644 index 000000000..da18d9352 --- /dev/null +++ b/cypress/fixtures/example.json @@ -0,0 +1,5 @@ +{ + "name": "Using fixtures to represent data", + "email": "hello@cypress.io", + "body": "Fixtures are a great way to mock data for responses to routes" +} \ No newline at end of file diff --git a/cypress/integration/dashboard.js b/cypress/integration/dashboard.js index ad6ee2945..d4f1c0749 100644 --- a/cypress/integration/dashboard.js +++ b/cypress/integration/dashboard.js @@ -1,36 +1,33 @@ -// import { DASHBOARD_SELECTORS } from "../elements/dashboard/dashboard-selectors"; +import { DASHBOARD_SELECTORS } from "../elements/dashboard/dashboard-selectors"; -// // -// describe("User authorization", () => { -// beforeEach(() => { -// cy.clearSessionData().loginUserViaRequest(); -// }); +// +describe("User authorization", () => { + beforeEach(() => { + cy.clearSessionData().loginUserViaRequest(); + }); -// xit("should all elements be visible on the dashboard", () => { -// cy.visit("/"); -// softAssertVisibility(DASHBOARD_SELECTORS.sales); -// softAssertVisibility(DASHBOARD_SELECTORS.orders); -// softAssertVisibility(DASHBOARD_SELECTORS.activity); -// softAssertVisibility(DASHBOARD_SELECTORS.topProducts); -// softAssertVisibility(DASHBOARD_SELECTORS.ordersReadyToFulfill); -// softAssertVisibility(DASHBOARD_SELECTORS.paymentsWaitingForCapture); -// softAssertVisibility(DASHBOARD_SELECTORS.productsOutOfStock); -// }); + it("should all elements be visible on the dashboard", () => { + cy.visit("/"); + softAssertVisibility(DASHBOARD_SELECTORS.sales); + softAssertVisibility(DASHBOARD_SELECTORS.orders); + softAssertVisibility(DASHBOARD_SELECTORS.activity); + softAssertVisibility(DASHBOARD_SELECTORS.topProducts); + softAssertVisibility(DASHBOARD_SELECTORS.ordersReadyToFulfill); + softAssertVisibility(DASHBOARD_SELECTORS.paymentsWaitingForCapture); + softAssertVisibility(DASHBOARD_SELECTORS.productsOutOfStock); + }); -// xit("aa", () => { -// // cy.fixture('addresses').then((json) => { -// // cy.createCustomer("Test9","Test9", json.plAddress); -// // }); -// // createChannel(); -// // createRateShipping(); -// // addChannelToProduct(); -// // createOrder(); -// }); + xit("aa", () => { + cy.fixture("addresses").then(json => { + cy.createCustomer("Test9", "Test9", json.plAddress); + }); + createChannel(); + createRateShipping(); + addChannelToProduct(); + createOrder(); + }); -// function softAssertVisibility(selector){ -// const {softExpect} = chai; -// cy.get(selector).then( element => { -// softExpect(element).to.be.visible; -// }) -// } -// }); + function softAssertVisibility(selector) { + cy.get(selector).then(element => chai.softExpect(element).to.be.visible); + } +}); diff --git a/cypress/support/shippingMethod.js b/cypress/support/shippingMethod/index.js similarity index 94% rename from cypress/support/shippingMethod.js rename to cypress/support/shippingMethod/index.js index 84fa3cfd7..949b97651 100644 --- a/cypress/support/shippingMethod.js +++ b/cypress/support/shippingMethod/index.js @@ -10,6 +10,7 @@ Cypress.Commands.add("createShippingRate", (name, shippingZone) => { }) } `; + return mutation; }); Cypress.Commands.add("createShippingZone", (name, country) => { @@ -25,6 +26,7 @@ Cypress.Commands.add("createShippingZone", (name, country) => { } } `; + return mutation; }); Cypress.Commands.add("", (shippingRateId, channelId) => { @@ -45,4 +47,5 @@ Cypress.Commands.add("", (shippingRateId, channelId) => { } } `; + return mutation; }); diff --git a/cypress/support/softAsserations/index.js b/cypress/support/softAsserations/index.js index 3405514da..07dc3dcff 100644 --- a/cypress/support/softAsserations/index.js +++ b/cypress/support/softAsserations/index.js @@ -1,81 +1,78 @@ -// let isSoftAssertion = false; -// let errors = []; +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); -// } +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 { +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); + } +}; -// 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 `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 = ""; -// // 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; + }); -// if ( Cypress.browser.isHeaded ) { + msg = msg.replace(/^/gm, "\t"); + } -// msg = 'Failed soft assertions... check log above ↑'; -// } else { + throw new Error(msg); + } + }); +} -// _.each( errors, error => { -// msg += '\n' + error; -// }); +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); +}; -// 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; -// }); +beforeEach(() => { + errors = []; +}); +afterEach(() => { + errors = []; + isSoftAssertion = false; +}); From 95be7b5163a7cbc691a70b511fc166b5dbfb9ffa Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Wed, 27 Jan 2021 10:41:55 +0100 Subject: [PATCH 03/24] order ready to fulfill created --- cypress/api/Customer.js | 84 ++++++++++++++++++ cypress/api/Order.js | 60 +++++++++++++ cypress/api/Product.js | 55 ++++++++++++ cypress/api/ShippingMethod.js | 97 +++++++++++++++++++++ cypress/integration/dashboard.js | 111 ++++++++++++++++++++++-- cypress/support/customer/index.js | 37 -------- cypress/support/index.js | 17 +++- cypress/support/shippingMethod/index.js | 51 ----------- 8 files changed, 414 insertions(+), 98 deletions(-) create mode 100644 cypress/api/Customer.js create mode 100644 cypress/api/Order.js create mode 100644 cypress/api/Product.js create mode 100644 cypress/api/ShippingMethod.js delete mode 100644 cypress/support/customer/index.js delete mode 100644 cypress/support/shippingMethod/index.js diff --git a/cypress/api/Customer.js b/cypress/api/Customer.js new file mode 100644 index 000000000..c9beb7042 --- /dev/null +++ b/cypress/api/Customer.js @@ -0,0 +1,84 @@ +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 + } + 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/api/Order.js b/cypress/api/Order.js new file mode 100644 index 000000000..571f27fb0 --- /dev/null +++ b/cypress/api/Order.js @@ -0,0 +1,60 @@ +class Order { + markOrderAsPaid(orderId) { + const mutation = `mutation{ + orderMarkAsPaid(id:"${orderId}"){ + orderErrors{ + message + } + } + }`; + 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/api/Product.js b/cypress/api/Product.js new file mode 100644 index 000000000..bbffa4312 --- /dev/null +++ b/cypress/api/Product.js @@ -0,0 +1,55 @@ +class Product { + getFirstProducts(first) { + const query = `query{ + products(first:${first}){ + edges{ + node{ + id + name + variants{ + id + } + } + } + } + } + `; + return cy.sendRequestWithQuery(query); + } + + updateChannelInProduct(productId, channelId) { + const mutation = `mutation{ + productChannelListingUpdate(id:"${productId}", input:{ + addChannels:{ + channelId:"${channelId}" + isPublished: true + isAvailableForPurchase:true + visibleInListings:true + } + }){ + product{ + id + name + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + + updateChannelPriceInVariant(variantId, channelId) { + const mutation = `mutation{ + productVariantChannelListingUpdate(id: "${variantId}", input:{ + channelId: "${channelId}" + price: 10 + costPrice: 10 + }){ + productChannelListingErrors{ + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } +} + +export default Product; diff --git a/cypress/api/ShippingMethod.js b/cypress/api/ShippingMethod.js new file mode 100644 index 000000000..179f1b824 --- /dev/null +++ b/cypress/api/ShippingMethod.js @@ -0,0 +1,97 @@ +class ShippingMethod { + createShippingRate(name, shippingZone) { + const mutation = ` + 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 + } + } + } + `; + return cy.sendRequestWithQuery(mutation); + } + + addChannelToShippingMethod(shippingRateId, channelId) { + const mutation = ` + mutation{ + shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ + addChannels: { + channelId:"${channelId}" + price:10 + } + }){ + shippingMethod{ + id + } + shippingErrors{ + code + message + } + } + } + `; + return cy.sendRequestWithQuery(mutation); + } + + deleteShippingZones(startsWith) { + this.getShippingZones().then(resp => { + if (resp.body.data.shippingZones) { + const shippingZone = resp.body.data.shippingZones.edges; + shippingZone.forEach(element => { + if (element.node.name.includes(startsWith)) { + this.deleteShippingZone(element.node.id); + } + }); + } + }); + } + + deleteShippingZone(shippingZoneId) { + const mutation = `mutation{ + shippingZoneDelete(id:"${shippingZoneId}"){ + shippingErrors{ + message + } + } + } + `; + return cy.sendRequestWithQuery(mutation); + } + + getShippingZones() { + const query = `query{ + shippingZones(first:100){ + edges{ + node{ + name + id + } + } + } + } + `; + return cy.sendRequestWithQuery(query); + } +} +export default ShippingMethod; diff --git a/cypress/integration/dashboard.js b/cypress/integration/dashboard.js index d4f1c0749..44213df2e 100644 --- a/cypress/integration/dashboard.js +++ b/cypress/integration/dashboard.js @@ -1,12 +1,30 @@ +import faker from "faker"; + +import Customer from "../api/Customer"; +import Order from "../api/Order"; +import Product from "../api/Product"; +import ShippingMethod from "../api/ShippingMethod"; import { DASHBOARD_SELECTORS } from "../elements/dashboard/dashboard-selectors"; // describe("User authorization", () => { + const startsWith = "Cy-"; + + const customer = new Customer(); + const product = new Product(); + const order = new Order(); + const shippingMethod = new ShippingMethod(); + + before(() => { + customer.deleteCustomers(startsWith); + shippingMethod.deleteShippingZones(startsWith); + }); + beforeEach(() => { cy.clearSessionData().loginUserViaRequest(); }); - it("should all elements be visible on the dashboard", () => { + xit("should all elements be visible on the dashboard", () => { cy.visit("/"); softAssertVisibility(DASHBOARD_SELECTORS.sales); softAssertVisibility(DASHBOARD_SELECTORS.orders); @@ -17,17 +35,94 @@ describe("User authorization", () => { softAssertVisibility(DASHBOARD_SELECTORS.productsOutOfStock); }); - xit("aa", () => { - cy.fixture("addresses").then(json => { - cy.createCustomer("Test9", "Test9", json.plAddress); + it("should correct amount of orders be displayed", () => { + faker = require("faker"); + const randomName = startsWith + faker.random.number(); + const randomEmail = randomName + "@example.com"; + product.getFirstProducts(3).then(productsResp => { + const productsList = productsResp.body.data.products.edges; + productsList.forEach(productElement => { + product.updateChannelInProduct( + "Q2hhbm5lbDoxNzk=", + productElement.node.id + ); + const variants = productElement.node.variants; + variants.forEach(variant => { + product.updateChannelPriceInVariant(variant.id, "Q2hhbm5lbDoxNzk="); + }); + }); + cy.fixture("addresses").then(json => { + customer + .createCustomer(randomEmail, randomName, json.plAddress) + .as("createCustomerResponse") + .then(resp => { + const customerId = resp.body.data.customerCreate.user.id; + shippingMethod + .createShippingZone(randomName, "PL") + .then(shippingZoneResp => { + shippingMethod + .createShippingRate( + randomName, + shippingZoneResp.body.data.shippingZoneCreate.shippingZone + .id + ) + .then(rateResp => { + const shippingMethodId = + rateResp.body.data.shippingPriceCreate.shippingMethod.id; + shippingMethod + .addChannelToShippingMethod( + shippingMethodId, + "Q2hhbm5lbDoxNzk=" + ) + .then(shippingMethodResp => { + createReadyToFullfillOrder( + customerId, + shippingMethodId, + "Q2hhbm5lbDoxNzk=", + productsList + ); + }); + }); + }); + }); + }); }); - createChannel(); - createRateShipping(); - addChannelToProduct(); - createOrder(); + cy.visit("/"); + softAssertMatch(DASHBOARD_SELECTORS.orders, /^0/); + softAssertMatch(DASHBOARD_SELECTORS.ordersReadyToFulfill, /^Brak/); + softAssertMatch(DASHBOARD_SELECTORS.paymentsWaitingForCapture, /^Brak/); + softAssertMatch(DASHBOARD_SELECTORS.productsOutOfStock, /^Brak/); }); + function createReadyToFullfillOrder( + customerId, + shippingMethodId, + channelId, + productsList + ) { + order + .createDraftOrder(customerId, shippingMethodId, channelId) + .then(draftOrderResp => { + const orderId = draftOrderResp.body.data.draftOrderCreate.order.id; + productsList.forEach(productElement => { + productElement.node.variants.forEach(variantElement => { + order.addProductToOrder(orderId, variantElement.id); + }); + }); + order.markOrderAsPaid(orderId); + order.completeOrder(orderId); + }); + } + function softAssertVisibility(selector) { cy.get(selector).then(element => chai.softExpect(element).to.be.visible); } + + function softAssertMatch(selector, regexp) { + cy.get(selector) + .invoke("text") + .then(text => + chai.softExpect(assert.match(text, regexp, "regexp matches")) + ); + } }); diff --git a/cypress/support/customer/index.js b/cypress/support/customer/index.js deleted file mode 100644 index 0a900581c..000000000 --- a/cypress/support/customer/index.js +++ /dev/null @@ -1,37 +0,0 @@ -Cypress.Commands.add( - "createCustomer", - (email, name, address, isActive = false) => { - const mustation = ` - mutation{ - customerCreate(input:{ - firstName: "${name}" - lastName: "${name}" - 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}" - } - }){ - accountErrors{ - code - } - } - } - `; - } -); diff --git a/cypress/support/index.js b/cypress/support/index.js index c863c2167..3cfc0f3cf 100644 --- a/cypress/support/index.js +++ b/cypress/support/index.js @@ -1,7 +1,5 @@ import "./user"; import "./softAsserations"; -import "./customer"; -import "./shippingMethod"; Cypress.Commands.add("clearSessionData", () => { // Because of known cypress bug, not all local storage data are cleared. @@ -20,3 +18,18 @@ Cypress.Commands.add("clearSessionData", () => { } }); }); + +Cypress.Commands.add("sendRequestWithQuery", query => + cy.request({ + method: "POST", + body: { + method: "POST", + url: Cypress.env("API_URI"), + query + }, + headers: { + Authorization: `JWT ${window.sessionStorage.getItem("auth")}` + }, + url: Cypress.env("API_URI") + }) +); diff --git a/cypress/support/shippingMethod/index.js b/cypress/support/shippingMethod/index.js deleted file mode 100644 index 949b97651..000000000 --- a/cypress/support/shippingMethod/index.js +++ /dev/null @@ -1,51 +0,0 @@ -Cypress.Commands.add("createShippingRate", (name, shippingZone) => { - const mutation = ` - mutation{ - CreateShippingRate(input:{ - maximumDeliveryDays: null - minimumDeliveryDays: null - name: "${name}" - shippingZone: "${shippingZone}" - type: "PRICE" - }) - } - `; - return mutation; -}); - -Cypress.Commands.add("createShippingZone", (name, country) => { - const mutation = ` - mutation{ - shippingZoneCreate(input:{ - name: "${name}" - countries: "${country}" - }){ - shippingZone{ - id - } - } - } - `; - return mutation; -}); - -Cypress.Commands.add("", (shippingRateId, channelId) => { - const mutation = ` - mutation{ - shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ - addChannels: { - channelId:"${channelId}" - } - }){ - shippingMethod{ - id - } - shippingErrors{ - code - message - } - } - } - `; - return mutation; -}); From fe9f55ee81a5ccebee616190a3518a36eb04d5a1 Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Tue, 2 Feb 2021 12:34:10 +0100 Subject: [PATCH 04/24] created orders and products, missing data-testid --- cypress/api/Product.js | 55 ------ cypress/apiRequests/Attribute.js | 49 +++++ cypress/apiRequests/Category.js | 43 +++++ cypress/apiRequests/Channels.js | 74 ++++++++ cypress/apiRequests/Checkout.js | 70 +++++++ cypress/{api => apiRequests}/Customer.js | 1 + cypress/{api => apiRequests}/Order.js | 2 +- cypress/apiRequests/Product.js | 178 ++++++++++++++++++ .../{api => apiRequests}/ShippingMethod.js | 17 +- cypress/apiRequests/Warehouse.js | 55 ++++++ cypress/elements/header/header-selectors.js | 4 + cypress/fixtures/addresses.json | 3 +- cypress/fixtures/example.json | 5 - cypress/integration/dashboard.js | 167 ++++++++-------- cypress/utils/ordersUtils.js | 46 +++++ cypress/utils/productsUtils.js | 124 ++++++++++++ cypress/utils/shippingUtils.js | 71 +++++++ 17 files changed, 808 insertions(+), 156 deletions(-) delete mode 100644 cypress/api/Product.js create mode 100644 cypress/apiRequests/Attribute.js create mode 100644 cypress/apiRequests/Category.js create mode 100644 cypress/apiRequests/Channels.js create mode 100644 cypress/apiRequests/Checkout.js rename cypress/{api => apiRequests}/Customer.js (99%) rename cypress/{api => apiRequests}/Order.js (96%) create mode 100644 cypress/apiRequests/Product.js rename cypress/{api => apiRequests}/ShippingMethod.js (80%) create mode 100644 cypress/apiRequests/Warehouse.js create mode 100644 cypress/elements/header/header-selectors.js delete mode 100644 cypress/fixtures/example.json create mode 100644 cypress/utils/ordersUtils.js create mode 100644 cypress/utils/productsUtils.js create mode 100644 cypress/utils/shippingUtils.js diff --git a/cypress/api/Product.js b/cypress/api/Product.js deleted file mode 100644 index bbffa4312..000000000 --- a/cypress/api/Product.js +++ /dev/null @@ -1,55 +0,0 @@ -class Product { - getFirstProducts(first) { - const query = `query{ - products(first:${first}){ - edges{ - node{ - id - name - variants{ - id - } - } - } - } - } - `; - return cy.sendRequestWithQuery(query); - } - - updateChannelInProduct(productId, channelId) { - const mutation = `mutation{ - productChannelListingUpdate(id:"${productId}", input:{ - addChannels:{ - channelId:"${channelId}" - isPublished: true - isAvailableForPurchase:true - visibleInListings:true - } - }){ - product{ - id - name - } - } - }`; - return cy.sendRequestWithQuery(mutation); - } - - updateChannelPriceInVariant(variantId, channelId) { - const mutation = `mutation{ - productVariantChannelListingUpdate(id: "${variantId}", input:{ - channelId: "${channelId}" - price: 10 - costPrice: 10 - }){ - productChannelListingErrors{ - message - } - } - }`; - return cy.sendRequestWithQuery(mutation); - } -} - -export default Product; diff --git a/cypress/apiRequests/Attribute.js b/cypress/apiRequests/Attribute.js new file mode 100644 index 000000000..a7253f8b8 --- /dev/null +++ b/cypress/apiRequests/Attribute.js @@ -0,0 +1,49 @@ +class Attribute { + createAttribute(name) { + const mutation = `mutation{ + attributeCreate(input:{ + name:"${name}" + valueRequired:false + type:PRODUCT_TYPE + }){ + attribute{ + id + } + attributeErrors{ + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + + getAttributes(first, search) { + const mutation = `query{ + attributes(first:${first}, filter:{ + search:"${search}" + }){ + edges{ + node{ + id + name + } + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + + deleteAttribute(attributeId) { + const mutation = `mutation{ + attributeDelete(id:"${attributeId}"){ + attributeErrors{ + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } +} +export default Attribute; diff --git a/cypress/apiRequests/Category.js b/cypress/apiRequests/Category.js new file mode 100644 index 000000000..7ea65eb7a --- /dev/null +++ b/cypress/apiRequests/Category.js @@ -0,0 +1,43 @@ +class Category { + createCategory(name, slug = name) { + const mutation = `mutation{ + 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 + } + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + deleteCategory(categoryId) { + const mutation = `mutation{ + categoryDelete(id:"${categoryId}"){ + productErrors{ + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } +} +export default Category; diff --git a/cypress/apiRequests/Channels.js b/cypress/apiRequests/Channels.js new file mode 100644 index 000000000..9afa7cc6b --- /dev/null +++ b/cypress/apiRequests/Channels.js @@ -0,0 +1,74 @@ +class Channels { + createChannel(isActive, name, slug, currencyCode) { + const createChannelMutation = `mutation{ + channelCreate(input: { + isActive: ${isActive} + name: "${name}" + slug: "${slug}" + currencyCode: "${currencyCode}" + }){ + channel{ + id + name + slug + } + channelErrors{ + code + message + } + } + }`; + return cy.sendRequestWithQuery(createChannelMutation); + } + + deleteTestChannels(nameStartsWith) { + const getChannelsInfoQuery = `query{ + channels{ + name + id + isActive + slug + currencyCode + } + } + `; + cy.sendRequestWithQuery(getChannelsInfoQuery).then(resp => { + const channels = new Set(resp.body.data.channels); + if (channels) { + channels.forEach(element => { + if (element.name.startsWith(nameStartsWith)) { + const targetChannels = Array.from(channels).filter(function( + channel + ) { + return ( + element.currencyCode === channel.currencyCode && + element.id !== channel.id + ); + }); + if (targetChannels[0]) { + this.deleteChannel(element.id, targetChannels[0].id); + channels.delete(element); + } + } + }); + } + }); + } + + deleteChannel(channelId, targetChennelId) { + const deleteChannelMutation = `mutation{ + channelDelete(id: "${channelId}", input:{ + targetChannel: "${targetChennelId}" + }){ + channel{ + name + } + channelErrors{ + message + } + } + }`; + return cy.sendRequestWithQuery(deleteChannelMutation); + } +} +export default Channels; diff --git a/cypress/apiRequests/Checkout.js b/cypress/apiRequests/Checkout.js new file mode 100644 index 000000000..ca63560f4 --- /dev/null +++ b/cypress/apiRequests/Checkout.js @@ -0,0 +1,70 @@ +class Checkout { + createCheckout(channelSlug, email, productQuantity, variantsList) { + const lines = []; + variantsList.forEach(variant => { + lines.push(`{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); + } + compliteCheckout(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/api/Customer.js b/cypress/apiRequests/Customer.js similarity index 99% rename from cypress/api/Customer.js rename to cypress/apiRequests/Customer.js index c9beb7042..336dbf698 100644 --- a/cypress/api/Customer.js +++ b/cypress/apiRequests/Customer.js @@ -28,6 +28,7 @@ export class Customer { }){ user{ id + email } accountErrors{ code diff --git a/cypress/api/Order.js b/cypress/apiRequests/Order.js similarity index 96% rename from cypress/api/Order.js rename to cypress/apiRequests/Order.js index 571f27fb0..0005d344a 100644 --- a/cypress/api/Order.js +++ b/cypress/apiRequests/Order.js @@ -7,7 +7,7 @@ class Order { } } }`; - cy.sendRequestWithQuery(mutation); + return cy.sendRequestWithQuery(mutation); } addProductToOrder(orderId, variantId, quantity = 1) { diff --git a/cypress/apiRequests/Product.js b/cypress/apiRequests/Product.js new file mode 100644 index 000000000..b747d238f --- /dev/null +++ b/cypress/apiRequests/Product.js @@ -0,0 +1,178 @@ +class Product { + getFirstProducts(first, search) { + let filter = ""; + if (search) { + filter = `, filter:{ + search:"${search}" + }`; + } + const query = `query{ + products(first:${first}${filter}){ + edges{ + node{ + id + name + variants{ + id + } + } + } + } + } + `; + return cy.sendRequestWithQuery(query); + } + + updateChannelInProduct(productId, channelId) { + const mutation = `mutation{ + productChannelListingUpdate(id:"${productId}", + input:{ + addChannels:{ + channelId:"${channelId}" + isPublished:true + isAvailableForPurchase:true + } + }){ + product{ + id + name + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + + updateChannelPriceInVariant(variantId, channelId) { + const mutation = `mutation{ + productVariantChannelListingUpdate(id: "${variantId}", input:{ + channelId: "${channelId}" + price: 10 + costPrice: 10 + }){ + 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 + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + + createVariant( + productId, + sku, + warehouseId, + quantity, + channelId, + price = 1, + costPrice = 1 + ) { + const mutation = `mutation{ + 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 + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + + deleteProduct(productId) { + const mutation = `mutation{ + 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 + } + } + } + }`; + return cy.sendRequestWithQuery(query); + } + + deleteProductType(productTypeId) { + const mutation = `mutation{ + productTypeDelete(id:"${productTypeId}"){ + productErrors{ + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } +} + +export default Product; diff --git a/cypress/api/ShippingMethod.js b/cypress/apiRequests/ShippingMethod.js similarity index 80% rename from cypress/api/ShippingMethod.js rename to cypress/apiRequests/ShippingMethod.js index 179f1b824..93ecb8f80 100644 --- a/cypress/api/ShippingMethod.js +++ b/cypress/apiRequests/ShippingMethod.js @@ -32,13 +32,13 @@ class ShippingMethod { return cy.sendRequestWithQuery(mutation); } - addChannelToShippingMethod(shippingRateId, channelId) { + addChannelToShippingMethod(shippingRateId, channelId, price) { const mutation = ` mutation{ shippingMethodChannelListingUpdate(id:"${shippingRateId}", input:{ addChannels: { channelId:"${channelId}" - price:10 + price: ${price} } }){ shippingMethod{ @@ -54,19 +54,6 @@ class ShippingMethod { return cy.sendRequestWithQuery(mutation); } - deleteShippingZones(startsWith) { - this.getShippingZones().then(resp => { - if (resp.body.data.shippingZones) { - const shippingZone = resp.body.data.shippingZones.edges; - shippingZone.forEach(element => { - if (element.node.name.includes(startsWith)) { - this.deleteShippingZone(element.node.id); - } - }); - } - }); - } - deleteShippingZone(shippingZoneId) { const mutation = `mutation{ shippingZoneDelete(id:"${shippingZoneId}"){ diff --git a/cypress/apiRequests/Warehouse.js b/cypress/apiRequests/Warehouse.js new file mode 100644 index 000000000..478d28726 --- /dev/null +++ b/cypress/apiRequests/Warehouse.js @@ -0,0 +1,55 @@ +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 + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } + getWarehouses(first, search) { + const query = `query{ + warehouses(first:${first}, filter:{ + search:"${search}" + }){ + edges{ + node{ + id + name + } + } + } + }`; + return cy.sendRequestWithQuery(query); + } + deleteWarehouse(warehouseId) { + const mutation = `mutation{ + deleteWarehouse(id:"${warehouseId}"){ + warehouseErrors{ + field + message + } + } + }`; + return cy.sendRequestWithQuery(mutation); + } +} +export default Warehouse; diff --git a/cypress/elements/header/header-selectors.js b/cypress/elements/header/header-selectors.js new file mode 100644 index 000000000..935421c34 --- /dev/null +++ b/cypress/elements/header/header-selectors.js @@ -0,0 +1,4 @@ +export const HEADER_SELECTORS = { + channelSelect: "[data-test-id='app-channel-select']", + channelSelectList: "[class*='MuiMenu-paper']" +}; diff --git a/cypress/fixtures/addresses.json b/cypress/fixtures/addresses.json index 742bd227e..08fad0466 100644 --- a/cypress/fixtures/addresses.json +++ b/cypress/fixtures/addresses.json @@ -7,6 +7,7 @@ "postalCode": "53-346", "country": "PL", "countryArea": "Dolny Śląsk", - "phone": "123456787" + "phone": "123456787", + "currency": "PLN" } } \ No newline at end of file diff --git a/cypress/fixtures/example.json b/cypress/fixtures/example.json deleted file mode 100644 index da18d9352..000000000 --- a/cypress/fixtures/example.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "Using fixtures to represent data", - "email": "hello@cypress.io", - "body": "Fixtures are a great way to mock data for responses to routes" -} \ No newline at end of file diff --git a/cypress/integration/dashboard.js b/cypress/integration/dashboard.js index 44213df2e..4251afa72 100644 --- a/cypress/integration/dashboard.js +++ b/cypress/integration/dashboard.js @@ -1,23 +1,29 @@ import faker from "faker"; -import Customer from "../api/Customer"; -import Order from "../api/Order"; -import Product from "../api/Product"; -import ShippingMethod from "../api/ShippingMethod"; +import Channels from "../apiRequests/Channels"; +import Customer from "../apiRequests/Customer"; import { DASHBOARD_SELECTORS } from "../elements/dashboard/dashboard-selectors"; +import { HEADER_SELECTORS } from "../elements/header/header-selectors"; +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 product = new Product(); - const order = new Order(); - const shippingMethod = new ShippingMethod(); + const channels = new Channels(); + const productsUtils = new ProductsUtils(); + const shippingUtils = new ShippingUtils(); + const ordersUtils = new OrdersUtils(); before(() => { + cy.clearSessionData().loginUserViaRequest(); customer.deleteCustomers(startsWith); - shippingMethod.deleteShippingZones(startsWith); + shippingUtils.deleteShipping(startsWith); + productsUtils.deleteProducts(startsWith); + channels.deleteTestChannels(startsWith); }); beforeEach(() => { @@ -36,84 +42,87 @@ describe("User authorization", () => { }); it("should correct amount of orders be displayed", () => { - faker = require("faker"); const randomName = startsWith + faker.random.number(); const randomEmail = randomName + "@example.com"; - product.getFirstProducts(3).then(productsResp => { - const productsList = productsResp.body.data.products.edges; - productsList.forEach(productElement => { - product.updateChannelInProduct( - "Q2hhbm5lbDoxNzk=", - productElement.node.id - ); - const variants = productElement.node.variants; - variants.forEach(variant => { - product.updateChannelPriceInVariant(variant.id, "Q2hhbm5lbDoxNzk="); + const randomNameProductOutOfStock = `${startsWith}${faker.random.number()}`; + const shippingPrice = 12; + const productPrice = 22; + cy.fixture("addresses").then(json => { + channels + .createChannel(true, randomName, randomName, json.plAddress.currency) + .then(channelsResp => { + const channelId = channelsResp.body.data.channelCreate.channel.id; + const channelSlug = channelsResp.body.data.channelCreate.channel.slug; + customer + .createCustomer(randomEmail, randomName, json.plAddress) + .then(resp => { + const customerId = resp.body.data.customerCreate.user.id; + const customerEmail = resp.body.data.customerCreate.user.email; + shippingUtils + .createShipping( + channelId, + randomName, + json.plAddress, + shippingPrice + ) + .then(() => { + const shippingId = shippingUtils.getShippingMethodId(); + const warehouseId = shippingUtils.getWarehouseId(); + productsUtils + .createTypeAttributeAndCategoryForProduct(randomName) + .then(() => { + const productTypeId = productsUtils.getProductTypeId(); + const attributeId = productsUtils.getAttributeId(); + const categoryId = productsUtils.getCategoryId(); + productsUtils + .createProductInChannel( + randomName, + channelId, + warehouseId, + 10, + productTypeId, + attributeId, + categoryId, + productPrice + ) + .then(() => { + const variantsList = productsUtils.getCreatedVariants(); + ordersUtils.createReadyToFullfillOrder( + customerId, + shippingId, + channelId, + variantsList + ); + ordersUtils.createWaitingForCaptureOrder( + channelSlug, + customerEmail, + variantsList, + shippingId + ); + }); + productsUtils.createProductInChannel( + randomNameProductOutOfStock, + channelId, + warehouseId, + 0, + productTypeId, + attributeId, + categoryId, + productPrice + ); + }); + }); + }); }); - }); - cy.fixture("addresses").then(json => { - customer - .createCustomer(randomEmail, randomName, json.plAddress) - .as("createCustomerResponse") - .then(resp => { - const customerId = resp.body.data.customerCreate.user.id; - shippingMethod - .createShippingZone(randomName, "PL") - .then(shippingZoneResp => { - shippingMethod - .createShippingRate( - randomName, - shippingZoneResp.body.data.shippingZoneCreate.shippingZone - .id - ) - .then(rateResp => { - const shippingMethodId = - rateResp.body.data.shippingPriceCreate.shippingMethod.id; - shippingMethod - .addChannelToShippingMethod( - shippingMethodId, - "Q2hhbm5lbDoxNzk=" - ) - .then(shippingMethodResp => { - createReadyToFullfillOrder( - customerId, - shippingMethodId, - "Q2hhbm5lbDoxNzk=", - productsList - ); - }); - }); - }); - }); - }); }); cy.visit("/"); - softAssertMatch(DASHBOARD_SELECTORS.orders, /^0/); - softAssertMatch(DASHBOARD_SELECTORS.ordersReadyToFulfill, /^Brak/); - softAssertMatch(DASHBOARD_SELECTORS.paymentsWaitingForCapture, /^Brak/); - softAssertMatch(DASHBOARD_SELECTORS.productsOutOfStock, /^Brak/); + cy.get(HEADER_SELECTORS.channelSelect) + .click() + .get(HEADER_SELECTORS.channelSelectList) + .contains(randomName) + .click(); }); - function createReadyToFullfillOrder( - customerId, - shippingMethodId, - channelId, - productsList - ) { - order - .createDraftOrder(customerId, shippingMethodId, channelId) - .then(draftOrderResp => { - const orderId = draftOrderResp.body.data.draftOrderCreate.order.id; - productsList.forEach(productElement => { - productElement.node.variants.forEach(variantElement => { - order.addProductToOrder(orderId, variantElement.id); - }); - }); - order.markOrderAsPaid(orderId); - order.completeOrder(orderId); - }); - } - function softAssertVisibility(selector) { cy.get(selector).then(element => chai.softExpect(element).to.be.visible); } diff --git a/cypress/utils/ordersUtils.js b/cypress/utils/ordersUtils.js new file mode 100644 index 000000000..dad9ebc29 --- /dev/null +++ b/cypress/utils/ordersUtils.js @@ -0,0 +1,46 @@ +import Checkout from "../apiRequests/Checkout"; +import Order from "../apiRequests/Order"; + +class OrdersUtils { + createWaitingForCaptureOrder( + channelSlug, + email, + variantsList, + shippingMethodId + ) { + const checkout = new Checkout(); + return checkout + .createCheckout(channelSlug, email, 1, variantsList) + .then(createCheckoutResp => { + const checkoutId = + createCheckoutResp.body.data.checkoutCreate.checkout.id; + return checkout + .addShippingMethod(checkoutId, shippingMethodId) + .then(() => + checkout + .addPayment(checkoutId, "mirumee.payments.dummy", "not-charged") + .then(() => checkout.compliteCheckout(checkoutId)) + ); + }); + } + createReadyToFullfillOrder( + customerId, + shippingMethodId, + channelId, + variantsList + ) { + const order = new Order(); + return order + .createDraftOrder(customerId, shippingMethodId, channelId) + .then(draftOrderResp => { + const orderId = draftOrderResp.body.data.draftOrderCreate.order.id; + variantsList.forEach(variantElement => { + order.addProductToOrder(orderId, variantElement.id); + }); + return order + .markOrderAsPaid(orderId) + .then(() => order.completeOrder(orderId)); + }); + } +} +export default OrdersUtils; diff --git a/cypress/utils/productsUtils.js b/cypress/utils/productsUtils.js new file mode 100644 index 000000000..d02efde08 --- /dev/null +++ b/cypress/utils/productsUtils.js @@ -0,0 +1,124 @@ +import Attribute from "../apiRequests/Attribute"; +import Category from "../apiRequests/Category"; +import Product from "../apiRequests/Product"; + +class ProductsUtils { + createdVariantId; + productTypeId; + attributeId; + categoryId; + + 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); + }); + }); + } + createProductInChannel( + name, + channelId, + warehouseId, + quantityInWarehouse, + productTypeId, + attributeId, + categoryId, + price + ) { + const product = new Product(); + return product + .createProduct(attributeId, name, productTypeId, categoryId) + .then(createProductResp => { + const productId = createProductResp.body.data.productCreate.product.id; + return product.updateChannelInProduct(productId, channelId).then(() => + product + .createVariant( + productId, + name, + warehouseId, + quantityInWarehouse, + channelId, + price + ) + .then(createVariantResp => { + this.createdVariantId = + createVariantResp.body.data.productVariantBulkCreate.productVariants; + }) + ); + }); + } + + 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; + }); + }); + }); + } + + getCreatedVariants() { + return this.createdVariantId; + } + getProductTypeId() { + return this.productTypeId; + } + getAttributeId() { + return this.attributeId; + } + getCategoryId() { + return this.categoryId; + } + + deleteProducts(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); + } + }); + }); + } +} +export default productsUtils; diff --git a/cypress/utils/shippingUtils.js b/cypress/utils/shippingUtils.js new file mode 100644 index 000000000..5806ac82d --- /dev/null +++ b/cypress/utils/shippingUtils.js @@ -0,0 +1,71 @@ +import ShippingMethod from "../apiRequests/ShippingMethod"; +import Warehouse from "../apiRequests/Warehouse"; +class ShippingUtils { + shippingMethodId; + shippingZoneId; + warehouseId; + + 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 + ); + }); + }); + }); + } + + getShippingMethodId() { + return this.shippingMethodId; + } + + getShippingZoneId() { + return this.shippingZoneId; + } + + getWarehouseId() { + return this.warehouseId; + } + + 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); + } + }); + }); + } +} +export default ShippingUtils; From 27e5d912e403a981420abbb9726ad80e3fb7dbdc Mon Sep 17 00:00:00 2001 From: Karolina Rakoczy Date: Thu, 11 Feb 2021 13:20:00 +0100 Subject: [PATCH 05/24] tests for dashboard --- cypress/apiRequests/Channels.js | 4 +- cypress/apiRequests/Checkout.js | 2 +- .../elements/dashboard/dashboard-selectors.js | 17 +++--- cypress/integration/dashboard.js | 55 +++++++++++-------- cypress/support/softAsserations/index.js | 11 ++++ cypress/utils/ordersUtils.js | 4 +- cypress/utils/productsUtils.js | 2 +- src/components/AppLayout/AppChannelSelect.tsx | 1 + .../SingleSelectField/SingleSelectField.tsx | 5 +- .../HomeActivityCard/HomeActivityCard.tsx | 5 +- .../HomeAnalyticsCard/HomeAnalyticsCard.tsx | 5 +- .../HomeNotificationTable.tsx | 6 +- src/home/components/HomePage/HomePage.tsx | 8 ++- .../HomeProductListCard.tsx | 5 +- 14 files changed, 81 insertions(+), 49 deletions(-) diff --git a/cypress/apiRequests/Channels.js b/cypress/apiRequests/Channels.js index 9afa7cc6b..197a709bc 100644 --- a/cypress/apiRequests/Channels.js +++ b/cypress/apiRequests/Channels.js @@ -55,10 +55,10 @@ class Channels { }); } - deleteChannel(channelId, targetChennelId) { + deleteChannel(channelId, targetChannelId) { const deleteChannelMutation = `mutation{ channelDelete(id: "${channelId}", input:{ - targetChannel: "${targetChennelId}" + targetChannel: "${targetChannelId}" }){ channel{ name diff --git a/cypress/apiRequests/Checkout.js b/cypress/apiRequests/Checkout.js index ca63560f4..0b611f883 100644 --- a/cypress/apiRequests/Checkout.js +++ b/cypress/apiRequests/Checkout.js @@ -50,7 +50,7 @@ class Checkout { }`; return cy.sendRequestWithQuery(mutation); } - compliteCheckout(checkoutId) { + completeCheckout(checkoutId) { const mutation = `mutation{ checkoutComplete(checkoutId:"${checkoutId}"){ order{ diff --git a/cypress/elements/dashboard/dashboard-selectors.js b/cypress/elements/dashboard/dashboard-selectors.js index 5c71fe47e..ad81a2ad8 100644 --- a/cypress/elements/dashboard/dashboard-selectors.js +++ b/cypress/elements/dashboard/dashboard-selectors.js @@ -1,11 +1,10 @@ export const DASHBOARD_SELECTORS = { - sales: "div:nth-child(1) > [class*='HomeAnalyticsCard-cardContent']", - orders: "div:nth-child(2) > [class*='HomeAnalyticsCard-cardContent']", - activity: "[class*='Grid-root'] > div:nth-child(2) > [class*='MuiPaper']", - topProducts: - "[class*='Grid-root'] > div:nth-child(1) > [class*='MuiPaper']:nth-child(4)", - ordersReadyToFulfill: "[class*='HomeNotificationTable'] > tr:nth-child(1)", - paymentsWaitingForCapture: - "[class*='HomeNotificationTable'] > tr:nth-child(2)", - productsOutOfStock: "[class*='HomeNotificationTable'] > tr:nth-child(3)" + 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']", + dataAreLoading: "[class*='Skeleton-skeleton']" }; diff --git a/cypress/integration/dashboard.js b/cypress/integration/dashboard.js index 4251afa72..471634092 100644 --- a/cypress/integration/dashboard.js +++ b/cypress/integration/dashboard.js @@ -30,15 +30,15 @@ describe("User authorization", () => { cy.clearSessionData().loginUserViaRequest(); }); - xit("should all elements be visible on the dashboard", () => { - cy.visit("/"); - softAssertVisibility(DASHBOARD_SELECTORS.sales); - softAssertVisibility(DASHBOARD_SELECTORS.orders); - softAssertVisibility(DASHBOARD_SELECTORS.activity); - softAssertVisibility(DASHBOARD_SELECTORS.topProducts); - softAssertVisibility(DASHBOARD_SELECTORS.ordersReadyToFulfill); - softAssertVisibility(DASHBOARD_SELECTORS.paymentsWaitingForCapture); - softAssertVisibility(DASHBOARD_SELECTORS.productsOutOfStock); + it("should all elements be visible on the dashboard", () => { + cy.visit("/") + .softAssertVisibility(DASHBOARD_SELECTORS.sales) + .softAssertVisibility(DASHBOARD_SELECTORS.orders) + .softAssertVisibility(DASHBOARD_SELECTORS.activity) + .softAssertVisibility(DASHBOARD_SELECTORS.topProducts) + .softAssertVisibility(DASHBOARD_SELECTORS.ordersReadyToFulfill) + .softAssertVisibility(DASHBOARD_SELECTORS.paymentsWaitingForCapture) + .softAssertVisibility(DASHBOARD_SELECTORS.productsOutOfStock); }); it("should correct amount of orders be displayed", () => { @@ -47,6 +47,9 @@ describe("User authorization", () => { const randomNameProductOutOfStock = `${startsWith}${faker.random.number()}`; const shippingPrice = 12; const productPrice = 22; + let sales = productPrice * 2 + shippingPrice; + + // Create channel, customer, product - everything needed to create order cy.fixture("addresses").then(json => { channels .createChannel(true, randomName, randomName, json.plAddress.currency) @@ -87,12 +90,16 @@ describe("User authorization", () => { ) .then(() => { const variantsList = productsUtils.getCreatedVariants(); - ordersUtils.createReadyToFullfillOrder( + + // Create order ready to fulfill + ordersUtils.createReadyToFulfillOrder( customerId, shippingId, channelId, variantsList ); + + // Create order waiting for capture ordersUtils.createWaitingForCaptureOrder( channelSlug, customerEmail, @@ -100,6 +107,8 @@ describe("User authorization", () => { shippingId ); }); + + // Create product out of stock productsUtils.createProductInChannel( randomNameProductOutOfStock, channelId, @@ -120,18 +129,18 @@ describe("User authorization", () => { .click() .get(HEADER_SELECTORS.channelSelectList) .contains(randomName) - .click(); + .click() + .get(DASHBOARD_SELECTORS.dataAreLoading) + .should("not.exist"); + const regex = /^1\D+/; + sales = sales.toFixed(2).replace(".", ","); + cy.softAssertMatch(DASHBOARD_SELECTORS.ordersReadyToFulfill, regex) + .softAssertMatch(DASHBOARD_SELECTORS.paymentsWaitingForCapture, regex) + .softAssertMatch(DASHBOARD_SELECTORS.productsOutOfStock, regex) + .softAssertMatch( + DASHBOARD_SELECTORS.sales, + new RegExp(`\\D+${sales}\\D+`) + ) + .softAssertMatch(DASHBOARD_SELECTORS.orders, /\D+2\D*/); }); - - function softAssertVisibility(selector) { - cy.get(selector).then(element => chai.softExpect(element).to.be.visible); - } - - function softAssertMatch(selector, regexp) { - cy.get(selector) - .invoke("text") - .then(text => - chai.softExpect(assert.match(text, regexp, "regexp matches")) - ); - } }); diff --git a/cypress/support/softAsserations/index.js b/cypress/support/softAsserations/index.js index 07dc3dcff..559ae921f 100644 --- a/cypress/support/softAsserations/index.js +++ b/cypress/support/softAsserations/index.js @@ -76,3 +76,14 @@ 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/ordersUtils.js b/cypress/utils/ordersUtils.js index dad9ebc29..e1416cbc7 100644 --- a/cypress/utils/ordersUtils.js +++ b/cypress/utils/ordersUtils.js @@ -19,11 +19,11 @@ class OrdersUtils { .then(() => checkout .addPayment(checkoutId, "mirumee.payments.dummy", "not-charged") - .then(() => checkout.compliteCheckout(checkoutId)) + .then(() => checkout.completeCheckout(checkoutId)) ); }); } - createReadyToFullfillOrder( + createReadyToFulfillOrder( customerId, shippingMethodId, channelId, diff --git a/cypress/utils/productsUtils.js b/cypress/utils/productsUtils.js index d02efde08..af6601b19 100644 --- a/cypress/utils/productsUtils.js +++ b/cypress/utils/productsUtils.js @@ -121,4 +121,4 @@ class ProductsUtils { }); } } -export default productsUtils; +export default ProductsUtils; diff --git a/src/components/AppLayout/AppChannelSelect.tsx b/src/components/AppLayout/AppChannelSelect.tsx index c9385288a..944443585 100644 --- a/src/components/AppLayout/AppChannelSelect.tsx +++ b/src/components/AppLayout/AppChannelSelect.tsx @@ -38,6 +38,7 @@ const AppChannelSelect: React.FC = ({ return (
= props => { hint, selectProps, placeholder, - InputProps + InputProps, + testId } = props; const classes = useStyles(props); @@ -84,6 +86,7 @@ export const SingleSelectField: React.FC = props => { {label} - - - - - Changed quantity in checkout - - -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +
-
- -
+
+ +
+
+ +
+
+ +
+
+ +
+
+ +