Merge with master, resolve conflicts
This commit is contained in:
commit
bf5e775cbf
41 changed files with 2631 additions and 146 deletions
1
.github/workflows/test.yml
vendored
1
.github/workflows/test.yml
vendored
|
@ -70,6 +70,7 @@ jobs:
|
|||
npm run test
|
||||
|
||||
cypress-run:
|
||||
if: github.event.pull_request.head.repo.full_name == 'mirumee/saleor-dashboard'
|
||||
runs-on: ubuntu-16.04
|
||||
steps:
|
||||
- name: Checkout
|
||||
|
|
|
@ -19,6 +19,8 @@ All notable, unreleased changes to this project will be documented in this file.
|
|||
- Drop descriptionJson and contentJson fields - #950 by @jwm0
|
||||
- Add error tracking with Sentry adapter - #956 by @jwm0
|
||||
- Add OAuth2 login with OpenID support - #963 by @orzechdev
|
||||
- Fix no channels crash - #984 by @dominik-zeglen
|
||||
- Update webhooks - #982 by @piotrgrundas
|
||||
|
||||
# 2.11.1
|
||||
|
||||
|
|
51
cypress/apiRequests/Attribute.js
Normal file
51
cypress/apiRequests/Attribute.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
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)
|
||||
.then(resp => resp.body.data.attributes.edges);
|
||||
}
|
||||
|
||||
deleteAttribute(attributeId) {
|
||||
const mutation = `mutation{
|
||||
attributeDelete(id:"${attributeId}"){
|
||||
attributeErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
}
|
||||
export default Attribute;
|
45
cypress/apiRequests/Category.js
Normal file
45
cypress/apiRequests/Category.js
Normal file
|
@ -0,0 +1,45 @@
|
|||
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)
|
||||
.then(resp => resp.body.data.categories.edges);
|
||||
}
|
||||
deleteCategory(categoryId) {
|
||||
const mutation = `mutation{
|
||||
categoryDelete(id:"${categoryId}"){
|
||||
productErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
}
|
||||
export default Category;
|
|
@ -1,59 +1,43 @@
|
|||
class Channels {
|
||||
createChannel(isActive, name, slug, currencyCode) {
|
||||
const createChannelMutation = `mutation{
|
||||
channelCreate(input: {
|
||||
isActive: ${isActive}
|
||||
name: "${name}"
|
||||
slug: "${slug}"
|
||||
currencyCode: "${currencyCode}"
|
||||
}){
|
||||
channel{
|
||||
name
|
||||
slug
|
||||
channelCreate(input: {
|
||||
isActive: ${isActive}
|
||||
name: "${name}"
|
||||
slug: "${slug}"
|
||||
currencyCode: "${currencyCode}"
|
||||
}){
|
||||
channel{
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
channelErrors{
|
||||
code
|
||||
message
|
||||
}
|
||||
}
|
||||
channelErrors{
|
||||
code
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
cy.sendRequestWithQuery(createChannelMutation);
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(createChannelMutation);
|
||||
}
|
||||
|
||||
deleteTestChannels(nameStartsWith) {
|
||||
getChannels() {
|
||||
const getChannelsInfoQuery = `query{
|
||||
channels{
|
||||
name
|
||||
id
|
||||
isActive
|
||||
slug
|
||||
currencyCode
|
||||
}
|
||||
}
|
||||
`;
|
||||
cy.sendRequestWithQuery(getChannelsInfoQuery).then(resp => {
|
||||
const channels = new Set(resp.body.data.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);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
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}"
|
||||
targetChannel: "${targetChannelId}"
|
||||
}){
|
||||
channel{
|
||||
name
|
||||
|
|
69
cypress/apiRequests/Checkout.js
Normal file
69
cypress/apiRequests/Checkout.js
Normal file
|
@ -0,0 +1,69 @@
|
|||
class Checkout {
|
||||
createCheckout(channelSlug, email, productQuantity, variantsList) {
|
||||
const lines = variantsList.map(
|
||||
variant => `{quantity:${productQuantity}
|
||||
variantId:"${variant.id}"}`
|
||||
);
|
||||
const mutation = `mutation{
|
||||
checkoutCreate(input:{
|
||||
channel:"${channelSlug}"
|
||||
email:"${email}"
|
||||
lines: [${lines.join()}]
|
||||
}){
|
||||
checkoutErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
created
|
||||
checkout{
|
||||
id
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
addShippingMethod(checkoutId, shippingMethodId) {
|
||||
const mutation = `mutation{
|
||||
checkoutShippingMethodUpdate(checkoutId:"${checkoutId}",
|
||||
shippingMethodId:"${shippingMethodId}"){
|
||||
checkoutErrors{
|
||||
message
|
||||
field
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
addPayment(checkoutId, gateway, token) {
|
||||
const mutation = `mutation{
|
||||
checkoutPaymentCreate(checkoutId:"${checkoutId}",
|
||||
input:{
|
||||
gateway: "${gateway}"
|
||||
token:"${token}"
|
||||
}){
|
||||
paymentErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
completeCheckout(checkoutId) {
|
||||
const mutation = `mutation{
|
||||
checkoutComplete(checkoutId:"${checkoutId}"){
|
||||
order{
|
||||
id
|
||||
}
|
||||
confirmationNeeded
|
||||
confirmationData
|
||||
checkoutErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
}
|
||||
export default Checkout;
|
85
cypress/apiRequests/Customer.js
Normal file
85
cypress/apiRequests/Customer.js
Normal file
|
@ -0,0 +1,85 @@
|
|||
export class Customer {
|
||||
createCustomer(email, customerName, address, isActive = false) {
|
||||
const mutation = `
|
||||
mutation{
|
||||
customerCreate(input:{
|
||||
firstName: "${customerName}"
|
||||
lastName: "${customerName}"
|
||||
email: "${email}"
|
||||
isActive: ${isActive}
|
||||
defaultBillingAddress: {
|
||||
companyName: "${address.companyName}"
|
||||
streetAddress1: "${address.streetAddress1}"
|
||||
streetAddress2: "${address.streetAddress2}"
|
||||
city: "${address.city}"
|
||||
postalCode: "${address.postalCode}"
|
||||
country: ${address.country}
|
||||
phone: "${address.phone}"
|
||||
}
|
||||
defaultShippingAddress: {
|
||||
companyName: "${address.companyName}"
|
||||
streetAddress1: "${address.streetAddress1}"
|
||||
streetAddress2: "${address.streetAddress2}"
|
||||
city: "${address.city}"
|
||||
postalCode: "${address.postalCode}"
|
||||
country: ${address.country}
|
||||
phone: "${address.phone}"
|
||||
}
|
||||
}){
|
||||
user{
|
||||
id
|
||||
email
|
||||
}
|
||||
accountErrors{
|
||||
code
|
||||
message
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
|
||||
deleteCustomers(startsWith) {
|
||||
this.getCustomers(startsWith).then(resp => {
|
||||
if (resp.body.data.customers) {
|
||||
const customers = resp.body.data.customers.edges;
|
||||
customers.forEach(element => {
|
||||
if (element.node.email.includes(startsWith)) {
|
||||
this.deleteCustomer(element.node.id);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
deleteCustomer(customerId) {
|
||||
const mutation = `mutation{
|
||||
customerDelete(id:"${customerId}"){
|
||||
accountErrors{
|
||||
code
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
|
||||
getCustomers(startsWith) {
|
||||
const query = `query{
|
||||
customers(first:100, filter: {
|
||||
search: "${startsWith}"
|
||||
}){
|
||||
edges{
|
||||
node{
|
||||
id
|
||||
email
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return cy.sendRequestWithQuery(query);
|
||||
}
|
||||
}
|
||||
export default Customer;
|
37
cypress/apiRequests/HomePage.js
Normal file
37
cypress/apiRequests/HomePage.js
Normal file
|
@ -0,0 +1,37 @@
|
|||
class HomePage {
|
||||
getSalesForChannel(channelSlug, period) {
|
||||
const query = `query{
|
||||
ordersTotal(period: ${period}, channel:"${channelSlug}"){
|
||||
gross{
|
||||
amount
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(query);
|
||||
}
|
||||
getOrdersForChannel(channelSlug, created) {
|
||||
const query = `query{
|
||||
orders(created: ${created}, channel:"${channelSlug}"){
|
||||
totalCount
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(query);
|
||||
}
|
||||
getOrdersWithStatus(status, channelSlug) {
|
||||
const query = `query{
|
||||
orders(status: ${status}, channel:"${channelSlug}"){
|
||||
totalCount
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(query);
|
||||
}
|
||||
getProductsOutOfStock(channelSlug) {
|
||||
const query = `query{
|
||||
products(stockAvailability: OUT_OF_STOCK, channel:"${channelSlug}"){
|
||||
totalCount
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(query);
|
||||
}
|
||||
}
|
||||
export default HomePage;
|
60
cypress/apiRequests/Order.js
Normal file
60
cypress/apiRequests/Order.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
class Order {
|
||||
markOrderAsPaid(orderId) {
|
||||
const mutation = `mutation{
|
||||
orderMarkAsPaid(id:"${orderId}"){
|
||||
orderErrors{
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
|
||||
addProductToOrder(orderId, variantId, quantity = 1) {
|
||||
const mutation = `mutation{
|
||||
draftOrderLinesCreate(id:"${orderId}", input:{
|
||||
quantity:${quantity}
|
||||
variantId: "${variantId}"
|
||||
}){
|
||||
orderErrors{
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
|
||||
createDraftOrder(customerId, shippingMethodId, channelId) {
|
||||
const mutation = `
|
||||
mutation{
|
||||
draftOrderCreate(input:{
|
||||
user:"${customerId}"
|
||||
shippingMethod:"${shippingMethodId}"
|
||||
channel: "${channelId}"
|
||||
}){
|
||||
orderErrors{
|
||||
message
|
||||
}
|
||||
order{
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
completeOrder(orderId) {
|
||||
const mutation = `mutation{
|
||||
draftOrderComplete(id:"${orderId}"){
|
||||
order{
|
||||
id
|
||||
}
|
||||
orderErrors{
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
}
|
||||
export default Order;
|
181
cypress/apiRequests/Product.js
Normal file
181
cypress/apiRequests/Product.js
Normal file
|
@ -0,0 +1,181 @@
|
|||
class Product {
|
||||
getFirstProducts(first, search) {
|
||||
const filter = search
|
||||
? `, filter:{
|
||||
search:"${search}"
|
||||
}`
|
||||
: "";
|
||||
const query = `query{
|
||||
products(first:${first}${filter}){
|
||||
edges{
|
||||
node{
|
||||
id
|
||||
name
|
||||
variants{
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return cy
|
||||
.sendRequestWithQuery(query)
|
||||
.then(resp => resp.body.data.products.edges);
|
||||
}
|
||||
|
||||
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)
|
||||
.then(resp => resp.body.data.productTypes.edges);
|
||||
}
|
||||
|
||||
deleteProductType(productTypeId) {
|
||||
const mutation = `mutation{
|
||||
productTypeDelete(id:"${productTypeId}"){
|
||||
productErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
}
|
||||
|
||||
export default Product;
|
86
cypress/apiRequests/ShippingMethod.js
Normal file
86
cypress/apiRequests/ShippingMethod.js
Normal file
|
@ -0,0 +1,86 @@
|
|||
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, price) {
|
||||
const mutation = `
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
|
||||
getShippingZones() {
|
||||
const query = `query{
|
||||
shippingZones(first:100){
|
||||
edges{
|
||||
node{
|
||||
name
|
||||
id
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
return cy
|
||||
.sendRequestWithQuery(query)
|
||||
.then(resp => resp.body.data.shippingZones.edges);
|
||||
}
|
||||
}
|
||||
export default ShippingMethod;
|
57
cypress/apiRequests/Warehouse.js
Normal file
57
cypress/apiRequests/Warehouse.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
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)
|
||||
.then(resp => resp.body.data.warehouses.edges);
|
||||
}
|
||||
deleteWarehouse(warehouseId) {
|
||||
const mutation = `mutation{
|
||||
deleteWarehouse(id:"${warehouseId}"){
|
||||
warehouseErrors{
|
||||
field
|
||||
message
|
||||
}
|
||||
}
|
||||
}`;
|
||||
return cy.sendRequestWithQuery(mutation);
|
||||
}
|
||||
}
|
||||
export default Warehouse;
|
9
cypress/elements/homePage/homePage-selectors.js
Normal file
9
cypress/elements/homePage/homePage-selectors.js
Normal file
|
@ -0,0 +1,9 @@
|
|||
export const HOMEPAGE_SELECTORS = {
|
||||
sales: "[data-test-id='sales-analytics']",
|
||||
orders: "[data-test-id='orders-analytics']",
|
||||
activity: "[data-test-id='activity-card']",
|
||||
topProducts: "[data-test-id='top-products']",
|
||||
ordersReadyToFulfill: "[data-test-id='orders-to-fulfill']",
|
||||
paymentsWaitingForCapture: "[data-test-id='orders-to-capture']",
|
||||
productsOutOfStock: "[data-test-id='products-out-of-stock']"
|
||||
};
|
13
cypress/fixtures/addresses.json
Normal file
13
cypress/fixtures/addresses.json
Normal file
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"plAddress": {
|
||||
"companyName": "Test3",
|
||||
"streetAddress1": "Smolna",
|
||||
"streetAddress2": "13/1",
|
||||
"city": "Wrocław",
|
||||
"postalCode": "53-346",
|
||||
"country": "PL",
|
||||
"countryArea": "Dolny Śląsk",
|
||||
"phone": "123456787",
|
||||
"currency": "PLN"
|
||||
}
|
||||
}
|
|
@ -14,16 +14,18 @@ import { ORDERS_SELECTORS } from "../elements/orders/orders-selectors";
|
|||
import { BUTTON_SELECTORS } from "../elements/shared/button-selectors";
|
||||
import ChannelsSteps from "../steps/channelsSteps";
|
||||
import { urlList } from "../url/urlList";
|
||||
import ChannelsUtils from "../utils/channelsUtils";
|
||||
|
||||
describe("Channels", () => {
|
||||
const channelStartsWith = "Cypress:";
|
||||
const currency = "PLN";
|
||||
const channels = new Channels();
|
||||
const channelsUtils = new ChannelsUtils();
|
||||
const channelsSteps = new ChannelsSteps();
|
||||
|
||||
before(() => {
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
channels.deleteTestChannels(channelStartsWith);
|
||||
channelsUtils.deleteChannels(channelStartsWith);
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -49,19 +51,18 @@ describe("Channels", () => {
|
|||
.get(ADD_CHANNEL_FORM_SELECTORS.backToChannelsList)
|
||||
.click()
|
||||
.get(CHANNELS_SELECTORS.channelsTable)
|
||||
.contains(randomChannel)
|
||||
|
||||
.contains(randomChannel);
|
||||
|
||||
// new channel should be visible in channel selector
|
||||
cy.visit(urlList.homePage)
|
||||
.get(HEADER_SELECTORS.channelSelect)
|
||||
.click()
|
||||
.get(HEADER_SELECTORS.channelSelectList)
|
||||
.contains(randomChannel)
|
||||
.click()
|
||||
|
||||
.click();
|
||||
|
||||
// new channel should be visible at product availability form
|
||||
cy.visit(urlList.products)
|
||||
.waitForGraph("InitialProductFilterData");
|
||||
cy.visit(urlList.products).waitForGraph("InitialProductFilterData");
|
||||
cy.get(PRODUCTS_SELECTORS.productsList)
|
||||
.first()
|
||||
.click()
|
||||
|
|
235
cypress/integration/homePage.js
Normal file
235
cypress/integration/homePage.js
Normal file
|
@ -0,0 +1,235 @@
|
|||
import faker from "faker";
|
||||
|
||||
import Customer from "../apiRequests/Customer";
|
||||
import { HOMEPAGE_SELECTORS } from "../elements/homePage/homePage-selectors";
|
||||
import HomePageSteps from "../steps/homePageSteps";
|
||||
import { urlList } from "../url/urlList";
|
||||
import ChannelsUtils from "../utils/channelsUtils";
|
||||
import HomePageUtils from "../utils/homePageUtils";
|
||||
import OrdersUtils from "../utils/ordersUtils";
|
||||
import ProductsUtils from "../utils/productsUtils";
|
||||
import ShippingUtils from "../utils/shippingUtils";
|
||||
|
||||
// <reference types="cypress" />
|
||||
describe("User authorization", () => {
|
||||
const startsWith = "Cy-";
|
||||
|
||||
const customer = new Customer();
|
||||
const productsUtils = new ProductsUtils();
|
||||
const shippingUtils = new ShippingUtils();
|
||||
const ordersUtils = new OrdersUtils();
|
||||
const channelsUtils = new ChannelsUtils();
|
||||
const homePageUtils = new HomePageUtils();
|
||||
const homePageSteps = new HomePageSteps();
|
||||
|
||||
let customerId;
|
||||
let defaultChannel;
|
||||
const productPrice = 22;
|
||||
const shippingPrice = 12;
|
||||
const randomName = startsWith + faker.random.number();
|
||||
const randomEmail = randomName + "@example.com";
|
||||
|
||||
before(() => {
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
productsUtils.deleteProperProducts(startsWith);
|
||||
customer.deleteCustomers(startsWith);
|
||||
shippingUtils.deleteShipping(startsWith);
|
||||
let addresses;
|
||||
|
||||
channelsUtils
|
||||
.getDefaultChannel()
|
||||
.then(channel => {
|
||||
defaultChannel = channel;
|
||||
cy.fixture("addresses");
|
||||
})
|
||||
.then(addressesFixture => (addresses = addressesFixture))
|
||||
.then(() =>
|
||||
customer.createCustomer(randomEmail, randomName, addresses.plAddress)
|
||||
)
|
||||
.then(resp => {
|
||||
customerId = resp.body.data.customerCreate.user.id;
|
||||
shippingUtils.createShipping(
|
||||
defaultChannel.id,
|
||||
randomName,
|
||||
addresses.plAddress,
|
||||
shippingPrice
|
||||
);
|
||||
})
|
||||
.then(() => {
|
||||
productsUtils.createTypeAttributeAndCategoryForProduct(randomName);
|
||||
})
|
||||
.then(() => {
|
||||
const warehouse = shippingUtils.getWarehouse();
|
||||
const productType = productsUtils.getProductType();
|
||||
const attribute = productsUtils.getAttribute();
|
||||
const category = productsUtils.getCategory();
|
||||
productsUtils.createProductInChannel(
|
||||
randomName,
|
||||
defaultChannel.id,
|
||||
warehouse.id,
|
||||
20,
|
||||
productType.id,
|
||||
attribute.id,
|
||||
category.id,
|
||||
productPrice
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
cy.clearSessionData().loginUserViaRequest();
|
||||
});
|
||||
|
||||
it("should all elements be visible on the dashboard", () => {
|
||||
cy.visit(urlList.homePage)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.sales)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.orders)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.activity)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.topProducts)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.ordersReadyToFulfill)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.paymentsWaitingForCapture)
|
||||
.softAssertVisibility(HOMEPAGE_SELECTORS.productsOutOfStock);
|
||||
});
|
||||
|
||||
it("should correct amount of ready to fullfil orders be displayed", () => {
|
||||
homePageUtils
|
||||
.getOrdersReadyToFulfill(defaultChannel.slug)
|
||||
.as("ordersReadyToFulfill");
|
||||
|
||||
ordersUtils.createReadyToFulfillOrder(
|
||||
customerId,
|
||||
shippingUtils.getShippingMethod().id,
|
||||
defaultChannel.id,
|
||||
productsUtils.getCreatedVariants()
|
||||
);
|
||||
cy.get("@ordersReadyToFulfill").then(ordersReadyToFulfillBefore => {
|
||||
const allOrdersReadyToFulfill = ordersReadyToFulfillBefore + 1;
|
||||
const notANumberRegex = "\\D*";
|
||||
const ordersReadyToFulfillRegexp = new RegExp(
|
||||
`${notANumberRegex}${allOrdersReadyToFulfill}${notANumberRegex}`
|
||||
);
|
||||
cy.visit(urlList.homePage);
|
||||
homePageSteps.changeChannel(defaultChannel.name);
|
||||
cy.contains(
|
||||
HOMEPAGE_SELECTORS.ordersReadyToFulfill,
|
||||
ordersReadyToFulfillRegexp
|
||||
).should("be.visible");
|
||||
});
|
||||
});
|
||||
it("should correct amount of payments waiting for capture be displayed", () => {
|
||||
homePageUtils
|
||||
.getOrdersReadyForCapture(defaultChannel.slug)
|
||||
.as("ordersReadyForCapture");
|
||||
const variantsList = productsUtils.getCreatedVariants();
|
||||
|
||||
ordersUtils.createWaitingForCaptureOrder(
|
||||
defaultChannel.slug,
|
||||
randomEmail,
|
||||
variantsList,
|
||||
shippingUtils.getShippingMethod().id
|
||||
);
|
||||
|
||||
cy.get("@ordersReadyForCapture").then(ordersReadyForCaptureBefore => {
|
||||
const allOrdersReadyForCapture = ordersReadyForCaptureBefore + 1;
|
||||
const notANumberRegex = "\\D*";
|
||||
const ordersReadyForCaptureRegexp = new RegExp(
|
||||
`${notANumberRegex}${allOrdersReadyForCapture}${notANumberRegex}`
|
||||
);
|
||||
cy.visit(urlList.homePage);
|
||||
homePageSteps.changeChannel(defaultChannel.name);
|
||||
cy.contains(
|
||||
HOMEPAGE_SELECTORS.ordersReadyForCapture,
|
||||
ordersReadyForCaptureRegexp
|
||||
).should("be.visible");
|
||||
});
|
||||
});
|
||||
it("should correct amount of products out of stock be displayed", () => {
|
||||
homePageUtils
|
||||
.getProductsOutOfStock(defaultChannel.slug)
|
||||
.as("productsOutOfStock");
|
||||
const productOutOfStockRandomName = startsWith + faker.random.number();
|
||||
const productsOutOfStockUtils = new ProductsUtils();
|
||||
const warehouse = shippingUtils.getWarehouse();
|
||||
const productType = productsUtils.getProductType();
|
||||
const attribute = productsUtils.getAttribute();
|
||||
const category = productsUtils.getCategory();
|
||||
|
||||
productsOutOfStockUtils.createProductInChannel(
|
||||
productOutOfStockRandomName,
|
||||
defaultChannel.id,
|
||||
warehouse.id,
|
||||
0,
|
||||
productType.id,
|
||||
attribute.id,
|
||||
category.id,
|
||||
productPrice
|
||||
);
|
||||
|
||||
cy.get("@productsOutOfStock").then(productsOutOfStockBefore => {
|
||||
const allProductsOutOfStock = productsOutOfStockBefore + 1;
|
||||
const notANumberRegex = "\\D*";
|
||||
const productsOutOfStockRegexp = new RegExp(
|
||||
`${notANumberRegex}${allProductsOutOfStock}${notANumberRegex}`
|
||||
);
|
||||
cy.visit(urlList.homePage);
|
||||
homePageSteps.changeChannel(defaultChannel.name);
|
||||
cy.contains(
|
||||
HOMEPAGE_SELECTORS.productsOutOfStock,
|
||||
productsOutOfStockRegexp
|
||||
).should("be.visible");
|
||||
});
|
||||
});
|
||||
it("should correct amount of sales be displayed", () => {
|
||||
homePageUtils.getSalesAmount(defaultChannel.slug).as("salesAmount");
|
||||
|
||||
ordersUtils.createReadyToFulfillOrder(
|
||||
customerId,
|
||||
shippingUtils.getShippingMethod().id,
|
||||
defaultChannel.id,
|
||||
productsUtils.getCreatedVariants()
|
||||
);
|
||||
|
||||
cy.get("@salesAmount").then(salesAmount => {
|
||||
const totalAmount = salesAmount + productPrice;
|
||||
const totalAmountString = totalAmount.toFixed(2);
|
||||
const totalAmountIntegerValue = totalAmountString.split(".")[0];
|
||||
const totalAmountDecimalValue = totalAmountString.split(".")[1];
|
||||
const decimalSeparator = "[,.]";
|
||||
const totalAmountIntegerWithThousandsSeparator = totalAmountIntegerValue.replace(
|
||||
/(\d)(?=(\d{3})+(?!\d))/g,
|
||||
"1[,.]*"
|
||||
);
|
||||
const totalAmountWithSeparators = `${totalAmountIntegerWithThousandsSeparator}${decimalSeparator}${totalAmountDecimalValue}`;
|
||||
const notANumberRegex = "\\D*";
|
||||
const salesAmountRegexp = new RegExp(
|
||||
`${notANumberRegex}${totalAmountWithSeparators}${notANumberRegex}`
|
||||
);
|
||||
cy.visit(urlList.homePage);
|
||||
homePageSteps.changeChannel(defaultChannel.name);
|
||||
cy.contains(HOMEPAGE_SELECTORS.sales, salesAmountRegexp).should(
|
||||
"be.visible"
|
||||
);
|
||||
});
|
||||
});
|
||||
it("should correct amount of orders be displayed", () => {
|
||||
homePageUtils.getTodaysOrders(defaultChannel.slug).as("todaysOrders");
|
||||
|
||||
ordersUtils.createReadyToFulfillOrder(
|
||||
customerId,
|
||||
shippingUtils.getShippingMethod().id,
|
||||
defaultChannel.id,
|
||||
productsUtils.getCreatedVariants()
|
||||
);
|
||||
|
||||
cy.get("@todaysOrders").then(ordersBefore => {
|
||||
const allOrders = ordersBefore + 1;
|
||||
const notANumberRegex = "\\D*";
|
||||
const ordersRegexp = new RegExp(
|
||||
`${notANumberRegex}${allOrders}${notANumberRegex}`
|
||||
);
|
||||
cy.visit(urlList.homePage);
|
||||
homePageSteps.changeChannel(defaultChannel.name);
|
||||
cy.contains(HOMEPAGE_SELECTORS.orders, ordersRegexp).should("be.visible");
|
||||
});
|
||||
});
|
||||
});
|
12
cypress/steps/homePageSteps.js
Normal file
12
cypress/steps/homePageSteps.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
import { HEADER_SELECTORS } from "../elements/header/header-selectors";
|
||||
class HomePageSteps {
|
||||
changeChannel(channelName) {
|
||||
cy.get(HEADER_SELECTORS.channelSelect)
|
||||
.click()
|
||||
.get(HEADER_SELECTORS.channelSelectList)
|
||||
.contains(channelName)
|
||||
.click()
|
||||
.waitForGraph("Home");
|
||||
}
|
||||
}
|
||||
export default HomePageSteps;
|
18
cypress/support/deleteElement/index.js
Normal file
18
cypress/support/deleteElement/index.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
Cypress.Commands.add(
|
||||
"handleDeleteElement",
|
||||
(element, deleteFunction, startsWith) => {
|
||||
if (element.node.name.includes(startsWith)) {
|
||||
deleteFunction(element.node.id);
|
||||
}
|
||||
}
|
||||
);
|
||||
Cypress.Commands.add(
|
||||
"deleteProperElements",
|
||||
(deleteFunction, getFunction, startsWith, name) => {
|
||||
getFunction(100, startsWith).then(elements => {
|
||||
elements.forEach(element => {
|
||||
cy.handleDeleteElement(element, deleteFunction, startsWith);
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
|
@ -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)) {
|
||||
|
@ -43,7 +45,7 @@ Cypress.Commands.add("sendRequestWithQuery", query =>
|
|||
body: {
|
||||
method: "POST",
|
||||
query,
|
||||
url: urlList.apiUri,
|
||||
url: urlList.apiUri
|
||||
},
|
||||
headers: {
|
||||
Authorization: `JWT ${window.sessionStorage.getItem("auth")}`
|
||||
|
|
89
cypress/support/softAssertions/index.js
Normal file
89
cypress/support/softAssertions/index.js
Normal file
|
@ -0,0 +1,89 @@
|
|||
let isSoftAssertion = false;
|
||||
let errors = [];
|
||||
|
||||
chai.softExpect = function(...args) {
|
||||
isSoftAssertion = true;
|
||||
return chai.expect(...args);
|
||||
};
|
||||
chai.softAssert = function(...args) {
|
||||
isSoftAssertion = true;
|
||||
return chai.assert(...args);
|
||||
};
|
||||
|
||||
const origAssert = chai.Assertion.prototype.assert;
|
||||
chai.Assertion.prototype.assert = function(...args) {
|
||||
if (isSoftAssertion) {
|
||||
try {
|
||||
origAssert.call(this, ...args);
|
||||
} catch (error) {
|
||||
errors.push(error);
|
||||
}
|
||||
isSoftAssertion = false;
|
||||
} else {
|
||||
origAssert.call(this, ...args);
|
||||
}
|
||||
};
|
||||
|
||||
// monkey-patch `Cypress.log` so that the last `cy.then()` isn't logged to command log
|
||||
const origLog = Cypress.log;
|
||||
Cypress.log = function(data) {
|
||||
if (data && data.error && /soft assertions/i.test(data.error.message)) {
|
||||
data.error.message = "\n\n\t" + data.error.message + "\n\n";
|
||||
throw data.error;
|
||||
}
|
||||
return origLog.call(Cypress, ...arguments);
|
||||
};
|
||||
|
||||
// monkey-patch `it` callback so we insert `cy.then()` as a last command
|
||||
// to each test case where we'll assert if there are any soft assertion errors
|
||||
function itCallback(func) {
|
||||
func();
|
||||
cy.then(() => {
|
||||
if (errors.length) {
|
||||
const _ = Cypress._;
|
||||
let msg = "";
|
||||
|
||||
if (Cypress.browser.isHeaded) {
|
||||
msg = "Failed soft assertions... check log above ↑";
|
||||
} else {
|
||||
_.each(errors, error => {
|
||||
msg += "\n" + error;
|
||||
});
|
||||
|
||||
msg = msg.replace(/^/gm, "\t");
|
||||
}
|
||||
|
||||
throw new Error(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const origIt = window.it;
|
||||
window.it = (title, func) => {
|
||||
origIt(title, func && (() => itCallback(func)));
|
||||
};
|
||||
window.it.only = (title, func) => {
|
||||
origIt.only(title, func && (() => itCallback(func)));
|
||||
};
|
||||
window.it.skip = (title, func) => {
|
||||
origIt.skip(title, func);
|
||||
};
|
||||
|
||||
beforeEach(() => {
|
||||
errors = [];
|
||||
});
|
||||
afterEach(() => {
|
||||
errors = [];
|
||||
isSoftAssertion = false;
|
||||
});
|
||||
|
||||
Cypress.Commands.add("softAssertMatch", (selector, regexp) => {
|
||||
cy.get(selector)
|
||||
.invoke("text")
|
||||
.then(text =>
|
||||
chai.softExpect(assert.match(text, regexp, "regexp matches"))
|
||||
);
|
||||
});
|
||||
Cypress.Commands.add("softAssertVisibility", selector => {
|
||||
cy.get(selector).then(element => chai.softExpect(element).to.be.visible);
|
||||
});
|
|
@ -37,10 +37,10 @@ Cypress.Commands.add("loginUserViaRequest", () => {
|
|||
variables: {
|
||||
email: Cypress.env("USER_NAME"),
|
||||
password: Cypress.env("USER_PASSWORD")
|
||||
},
|
||||
}
|
||||
},
|
||||
method: "POST",
|
||||
url: urlList.apiUri,
|
||||
url: urlList.apiUri
|
||||
})
|
||||
.then(resp => {
|
||||
window.sessionStorage.setItem("auth", resp.body.data.tokenCreate.token);
|
||||
|
|
41
cypress/utils/channelsUtils.js
Normal file
41
cypress/utils/channelsUtils.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
import Channels from "../apiRequests/Channels";
|
||||
|
||||
class ChannelsUtils {
|
||||
channels = new Channels();
|
||||
|
||||
deleteChannels(nameStartsWith) {
|
||||
this.channels.getChannels().then(resp => {
|
||||
const channelsArray = new Set(resp.body.data.channels);
|
||||
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() {
|
||||
return this.channels.getChannels().then(resp => {
|
||||
const channelsArray = resp.body.data.channels;
|
||||
return (this.defaultChannel = channelsArray.find(function(
|
||||
channelElement
|
||||
) {
|
||||
return channelElement.slug === "default-channel";
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
export default ChannelsUtils;
|
30
cypress/utils/homePageUtils.js
Normal file
30
cypress/utils/homePageUtils.js
Normal file
|
@ -0,0 +1,30 @@
|
|||
import HomePage from "../apiRequests/HomePage";
|
||||
class HomePageUtils {
|
||||
homePage = new HomePage();
|
||||
getOrdersReadyToFulfill(channelSlug) {
|
||||
return this.homePage
|
||||
.getOrdersWithStatus("READY_TO_FULFILL", channelSlug)
|
||||
.then(resp => resp.body.data.orders.totalCount);
|
||||
}
|
||||
getOrdersReadyForCapture(channelSlug) {
|
||||
return this.homePage
|
||||
.getOrdersWithStatus("READY_TO_CAPTURE", channelSlug)
|
||||
.then(resp => resp.body.data.orders.totalCount);
|
||||
}
|
||||
getProductsOutOfStock(channelSlug) {
|
||||
return this.homePage
|
||||
.getProductsOutOfStock(channelSlug)
|
||||
.then(resp => resp.body.data.products.totalCount);
|
||||
}
|
||||
getSalesAmount(channelSlug) {
|
||||
return this.homePage
|
||||
.getSalesForChannel(channelSlug, "TODAY")
|
||||
.then(resp => resp.body.data.ordersTotal.gross.amount);
|
||||
}
|
||||
getTodaysOrders(channelSlug) {
|
||||
return this.homePage
|
||||
.getOrdersForChannel(channelSlug, "TODAY")
|
||||
.then(resp => resp.body.data.orders.totalCount);
|
||||
}
|
||||
}
|
||||
export default HomePageUtils;
|
60
cypress/utils/ordersUtils.js
Normal file
60
cypress/utils/ordersUtils.js
Normal file
|
@ -0,0 +1,60 @@
|
|||
import Checkout from "../apiRequests/Checkout";
|
||||
import Order from "../apiRequests/Order";
|
||||
|
||||
class OrdersUtils {
|
||||
checkoutRequest = new Checkout();
|
||||
orderRequest = new Order();
|
||||
|
||||
checkout;
|
||||
order;
|
||||
|
||||
createWaitingForCaptureOrder(
|
||||
channelSlug,
|
||||
email,
|
||||
variantsList,
|
||||
shippingMethodId
|
||||
) {
|
||||
return this.createCheckout(channelSlug, email, variantsList)
|
||||
.then(() =>
|
||||
this.checkoutRequest.addShippingMethod(
|
||||
this.checkout.id,
|
||||
shippingMethodId
|
||||
)
|
||||
)
|
||||
.then(() => this.addPayment(this.checkout.id))
|
||||
.then(() => this.checkoutRequest.completeCheckout(this.checkout.id));
|
||||
}
|
||||
createReadyToFulfillOrder(
|
||||
customerId,
|
||||
shippingMethodId,
|
||||
channelId,
|
||||
variantsList
|
||||
) {
|
||||
return this.createDraftOrder(customerId, shippingMethodId, channelId)
|
||||
.then(() => {
|
||||
variantsList.forEach(variantElement => {
|
||||
this.orderRequest.addProductToOrder(this.order.id, variantElement.id);
|
||||
});
|
||||
})
|
||||
.then(() => this.orderRequest.markOrderAsPaid(this.order.id))
|
||||
.then(() => this.orderRequest.completeOrder(this.order.id));
|
||||
}
|
||||
createDraftOrder(customerId, shippingMethodId, channelId) {
|
||||
return this.orderRequest
|
||||
.createDraftOrder(customerId, shippingMethodId, channelId)
|
||||
.then(resp => (this.order = resp.body.data.draftOrderCreate.order));
|
||||
}
|
||||
createCheckout(channelSlug, email, variantsList) {
|
||||
return this.checkoutRequest
|
||||
.createCheckout(channelSlug, email, 1, variantsList)
|
||||
.then(resp => (this.checkout = resp.body.data.checkoutCreate.checkout));
|
||||
}
|
||||
addPayment(checkoutId) {
|
||||
return this.checkoutRequest.addPayment(
|
||||
checkoutId,
|
||||
"mirumee.payments.dummy",
|
||||
"not-charged"
|
||||
);
|
||||
}
|
||||
}
|
||||
export default OrdersUtils;
|
132
cypress/utils/productsUtils.js
Normal file
132
cypress/utils/productsUtils.js
Normal file
|
@ -0,0 +1,132 @@
|
|||
import Attribute from "../apiRequests/Attribute";
|
||||
import Category from "../apiRequests/Category";
|
||||
import Product from "../apiRequests/Product";
|
||||
|
||||
class ProductsUtils {
|
||||
productRequest = new Product();
|
||||
attributeRequest = new Attribute();
|
||||
categoryRequest = new Category();
|
||||
|
||||
product;
|
||||
variants;
|
||||
productType;
|
||||
attribute;
|
||||
category;
|
||||
|
||||
createProductInChannel(
|
||||
name,
|
||||
channelId,
|
||||
warehouseId,
|
||||
quantityInWarehouse,
|
||||
productTypeId,
|
||||
attributeId,
|
||||
categoryId,
|
||||
price
|
||||
) {
|
||||
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) {
|
||||
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.variants;
|
||||
}
|
||||
getProductType() {
|
||||
return this.productType;
|
||||
}
|
||||
getAttribute() {
|
||||
return this.attribute;
|
||||
}
|
||||
getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
deleteProperProducts(startsWith) {
|
||||
const product = new Product();
|
||||
const attribute = new Attribute();
|
||||
const category = new Category();
|
||||
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;
|
77
cypress/utils/shippingUtils.js
Normal file
77
cypress/utils/shippingUtils.js
Normal file
|
@ -0,0 +1,77 @@
|
|||
import ShippingMethod from "../apiRequests/ShippingMethod";
|
||||
import Warehouse from "../apiRequests/Warehouse";
|
||||
class ShippingUtils {
|
||||
shippingMethodRequest = new ShippingMethod();
|
||||
warehouseRequest = new Warehouse();
|
||||
|
||||
shippingMethod;
|
||||
shippingZone;
|
||||
warehouse;
|
||||
|
||||
createShipping(channelId, name, address, 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;
|
||||
});
|
||||
}
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
getShippingMethod() {
|
||||
return this.shippingMethod;
|
||||
}
|
||||
|
||||
getShippingZone() {
|
||||
return this.shippingZone;
|
||||
}
|
||||
|
||||
getWarehouse() {
|
||||
return this.warehouse;
|
||||
}
|
||||
|
||||
deleteShipping(startsWith) {
|
||||
const shippingMethod = new ShippingMethod();
|
||||
const warehouse = new Warehouse();
|
||||
cy.deleteProperElements(
|
||||
shippingMethod.deleteShippingZone,
|
||||
shippingMethod.getShippingZones,
|
||||
startsWith,
|
||||
"shippingZONE"
|
||||
);
|
||||
cy.deleteProperElements(
|
||||
warehouse.deleteWarehouse,
|
||||
warehouse.getWarehouses,
|
||||
startsWith,
|
||||
"Warehouse"
|
||||
);
|
||||
}
|
||||
}
|
||||
export default ShippingUtils;
|
|
@ -6767,6 +6767,10 @@
|
|||
"context": "event",
|
||||
"string": "All events"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_2745028894": {
|
||||
"context": "event",
|
||||
"string": "Page deleted"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_2862596150": {
|
||||
"context": "event",
|
||||
"string": "Invoice sent"
|
||||
|
@ -6795,6 +6799,14 @@
|
|||
"context": "event",
|
||||
"string": "Order cancelled"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_3618648517": {
|
||||
"context": "event",
|
||||
"string": "Page updated"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_3671033983": {
|
||||
"context": "event",
|
||||
"string": "Product deleted"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_3907151399": {
|
||||
"context": "event",
|
||||
"string": "Order fulfilled"
|
||||
|
@ -6803,10 +6815,6 @@
|
|||
"context": "event",
|
||||
"string": "Customer created"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_40035964": {
|
||||
"context": "event",
|
||||
"string": "Changed quantity in checkout"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_4186057882": {
|
||||
"context": "event",
|
||||
"string": "Invoice requested"
|
||||
|
@ -6815,6 +6823,14 @@
|
|||
"context": "event",
|
||||
"string": "Fulfillment created"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_679080833": {
|
||||
"context": "event",
|
||||
"string": "Page created"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookEvents_dot_787792649": {
|
||||
"context": "event",
|
||||
"string": "Customer updated"
|
||||
},
|
||||
"src_dot_webhooks_dot_components_dot_WebhookInfo_dot_1690209105": {
|
||||
"context": "webhook",
|
||||
"string": "Target URL"
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
module.exports = {
|
||||
directory: 'build/dashboard/',
|
||||
port: 9000,
|
||||
}
|
||||
directory: "build/dashboard/",
|
||||
port: 9000
|
||||
};
|
||||
|
|
6
package-lock.json
generated
6
package-lock.json
generated
|
@ -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",
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -5827,6 +5827,7 @@ enum WebhookEventTypeEnum {
|
|||
INVOICE_DELETED
|
||||
INVOICE_SENT
|
||||
CUSTOMER_CREATED
|
||||
CUSTOMER_UPDATED
|
||||
PRODUCT_CREATED
|
||||
PRODUCT_UPDATED
|
||||
PRODUCT_DELETED
|
||||
|
@ -5849,6 +5850,7 @@ enum WebhookSampleEventTypeEnum {
|
|||
INVOICE_DELETED
|
||||
INVOICE_SENT
|
||||
CUSTOMER_CREATED
|
||||
CUSTOMER_UPDATED
|
||||
PRODUCT_CREATED
|
||||
PRODUCT_UPDATED
|
||||
PRODUCT_DELETED
|
||||
|
@ -5895,4 +5897,4 @@ union _Entity = Address | User | Group | App | ProductVariant | Product | Produc
|
|||
|
||||
type _Service {
|
||||
sdl: String
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ export const AppChannelProvider: React.FC = ({ children }) => {
|
|||
|
||||
const [isPickerActive, setPickerActive] = React.useState(false);
|
||||
React.useEffect(() => {
|
||||
if (!selectedChannel && channelData?.channels) {
|
||||
if (!selectedChannel && channelData?.channels?.length > 0) {
|
||||
setSelectedChannel(channelData.channels[0].id);
|
||||
}
|
||||
}, [channelData]);
|
||||
|
|
|
@ -30,16 +30,17 @@ const useStyles = makeStyles(
|
|||
|
||||
interface HomeActivityCardProps {
|
||||
activities: Home_activities_edges_node[];
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
const HomeActivityCard: React.FC<HomeActivityCardProps> = props => {
|
||||
const { activities } = props;
|
||||
const { activities, testId } = props;
|
||||
const classes = useStyles(props);
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card data-test-id={testId}>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Activity",
|
||||
|
|
|
@ -53,19 +53,20 @@ const useStyles = makeStyles(
|
|||
);
|
||||
|
||||
interface HomeAnalyticsCardProps {
|
||||
testId?: string;
|
||||
icon: React.ReactElement<IconProps>;
|
||||
title: string;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
const HomeAnalyticsCard: React.FC<HomeAnalyticsCardProps> = props => {
|
||||
const { children, title, icon } = props;
|
||||
const { children, title, icon, testId } = props;
|
||||
|
||||
const classes = useStyles(props);
|
||||
|
||||
return (
|
||||
<Card className={classes.cardSpacing}>
|
||||
<CardContent className={classes.cardContent}>
|
||||
<CardContent className={classes.cardContent} data-test-id={testId}>
|
||||
<div>
|
||||
<Typography className={classes.cardTitle} variant="subtitle1">
|
||||
{title}
|
||||
|
|
|
@ -116,7 +116,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
|
|||
requiredPermissions={[PermissionEnum.MANAGE_ORDERS]}
|
||||
>
|
||||
<TableRow hover={true} onClick={onOrdersToFulfillClick}>
|
||||
<TableCell>
|
||||
<TableCell data-test-id="orders-to-fulfill">
|
||||
{ordersToFulfill === undefined ? (
|
||||
<Skeleton />
|
||||
) : ordersToFulfill === 0 ? (
|
||||
|
@ -136,7 +136,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
|
|||
</TableCell>
|
||||
</TableRow>
|
||||
<TableRow hover={true} onClick={onOrdersToCaptureClick}>
|
||||
<TableCell>
|
||||
<TableCell data-test-id="orders-to-capture">
|
||||
{ordersToCapture === undefined ? (
|
||||
<Skeleton />
|
||||
) : ordersToCapture === 0 ? (
|
||||
|
@ -161,7 +161,7 @@ const HomeNotificationTable: React.FC<HomeNotificationTableProps> = props => {
|
|||
requiredPermissions={[PermissionEnum.MANAGE_PRODUCTS]}
|
||||
>
|
||||
<TableRow hover={true} onClick={onProductsOutOfStockClick}>
|
||||
<TableCell>
|
||||
<TableCell data-test-id="products-out-of-stock">
|
||||
{productsOutOfStock === undefined ? (
|
||||
<Skeleton />
|
||||
) : productsOutOfStock === 0 ? (
|
||||
|
|
|
@ -95,6 +95,7 @@ const HomePage: React.FC<HomePageProps> = props => {
|
|||
<div className={classes.cardContainer}>
|
||||
<HomeAnalyticsCard
|
||||
title={"Sales"}
|
||||
testId="sales-analytics"
|
||||
icon={
|
||||
<Sales
|
||||
className={classes.icon}
|
||||
|
@ -113,6 +114,7 @@ const HomePage: React.FC<HomePageProps> = props => {
|
|||
</HomeAnalyticsCard>
|
||||
<HomeAnalyticsCard
|
||||
title={"Orders"}
|
||||
testId="orders-analytics"
|
||||
icon={
|
||||
<Orders
|
||||
className={classes.icon}
|
||||
|
@ -152,6 +154,7 @@ const HomePage: React.FC<HomePageProps> = props => {
|
|||
]}
|
||||
>
|
||||
<HomeProductListCard
|
||||
testId="top-products"
|
||||
onRowClick={onProductClick}
|
||||
topProducts={topProducts}
|
||||
/>
|
||||
|
@ -165,7 +168,10 @@ const HomePage: React.FC<HomePageProps> = props => {
|
|||
userPermissions={userPermissions}
|
||||
requiredPermissions={[PermissionEnum.MANAGE_ORDERS]}
|
||||
>
|
||||
<HomeActivityCard activities={activities} />
|
||||
<HomeActivityCard
|
||||
activities={activities}
|
||||
testId="activity-card"
|
||||
/>
|
||||
</RequirePermissions>
|
||||
</div>
|
||||
)}
|
||||
|
|
|
@ -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<HomeProductListProps> = props => {
|
||||
const { topProducts, onRowClick } = props;
|
||||
const { topProducts, onRowClick, testId } = props;
|
||||
const classes = useStyles(props);
|
||||
|
||||
const intl = useIntl();
|
||||
|
||||
return (
|
||||
<Card>
|
||||
<Card data-test-id={testId}>
|
||||
<CardTitle
|
||||
title={intl.formatMessage({
|
||||
defaultMessage: "Top Products",
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -970,6 +970,7 @@ export enum WebhookEventTypeEnum {
|
|||
CHECKOUT_CREATED = "CHECKOUT_CREATED",
|
||||
CHECKOUT_UPDATED = "CHECKOUT_UPDATED",
|
||||
CUSTOMER_CREATED = "CUSTOMER_CREATED",
|
||||
CUSTOMER_UPDATED = "CUSTOMER_UPDATED",
|
||||
FULFILLMENT_CREATED = "FULFILLMENT_CREATED",
|
||||
INVOICE_DELETED = "INVOICE_DELETED",
|
||||
INVOICE_REQUESTED = "INVOICE_REQUESTED",
|
||||
|
|
|
@ -44,6 +44,10 @@ const WebhookEvents: React.FC<WebhookEventsProps> = ({
|
|||
defaultMessage: "Customer created",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.CUSTOMER_UPDATED]: intl.formatMessage({
|
||||
defaultMessage: "Customer updated",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.CHECKOUT_CREATED]: intl.formatMessage({
|
||||
defaultMessage: "Checkout created",
|
||||
description: "event"
|
||||
|
@ -84,8 +88,8 @@ const WebhookEvents: React.FC<WebhookEventsProps> = ({
|
|||
defaultMessage: "Product updated",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.CHECKOUT_QUANTITY_CHANGED]: intl.formatMessage({
|
||||
defaultMessage: "Changed quantity in checkout",
|
||||
[WebhookEventTypeEnum.PRODUCT_DELETED]: intl.formatMessage({
|
||||
defaultMessage: "Product deleted",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.FULFILLMENT_CREATED]: intl.formatMessage({
|
||||
|
@ -103,6 +107,18 @@ const WebhookEvents: React.FC<WebhookEventsProps> = ({
|
|||
[WebhookEventTypeEnum.INVOICE_DELETED]: intl.formatMessage({
|
||||
defaultMessage: "Invoice deleted",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.PAGE_CREATED]: intl.formatMessage({
|
||||
defaultMessage: "Page created",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.PAGE_UPDATED]: intl.formatMessage({
|
||||
defaultMessage: "Page updated",
|
||||
description: "event"
|
||||
}),
|
||||
[WebhookEventTypeEnum.PAGE_DELETED]: intl.formatMessage({
|
||||
defaultMessage: "Page deleted",
|
||||
description: "event"
|
||||
})
|
||||
};
|
||||
|
||||
|
|
|
@ -44,8 +44,8 @@ module.exports = (env, argv) => {
|
|||
throw new Error("Environment variable API_URI not set");
|
||||
}
|
||||
|
||||
const publicPath = process.env.STATIC_URL || "/";
|
||||
if (!devMode) {
|
||||
const publicPath = process.env.STATIC_URL || "/";
|
||||
output = {
|
||||
chunkFilename: "[name].[chunkhash].js",
|
||||
filename: "[name].[chunkhash].js",
|
||||
|
@ -58,7 +58,7 @@ module.exports = (env, argv) => {
|
|||
chunkFilename: "[name].js",
|
||||
filename: "[name].js",
|
||||
path: resolve(dashboardBuildPath),
|
||||
publicPath: "/"
|
||||
publicPath
|
||||
};
|
||||
fileLoaderPath = "file-loader?name=[name].[ext]";
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue