Run critical tests after test env deployment (#1902)

* run critical tests after test env deployment

* add cache

* add all branches

* change workflow name

* add run on pull request for testing

* change type

* add run on deployment

* run on copleted

* test critical

* add quote

* change baseUrl

* fix base url

* fix base url

* upload reports

* run in parallel

* save build folder

* remove build from gitignore

* remove build

* update nide version

* last try with parallel

* save build

* save build

* Run critical

* change cypress API url

* run critical in parallel

* check which workflow has lower duration time

* save all reports with container in name

* add reports on failure

* remove reporters

* fix jobs

* merge

* add group name

* run critical

* Refactor critical tests (#1906)

* refactored tag added to purchaseWithProductsTypes, navigation, stocksInCheckout

* homePageAnalitics - refactor

* refactor home page

* refactor creating variants

* refactor adding product without sku to order

* add script to run critical locally

* change tests cases names

* fix names, remove comments, add script to run refactored tests

* remove workflow for parallel

* remove key
This commit is contained in:
Karolina Rakoczy 2022-03-21 16:17:37 +04:00 committed by GitHub
parent f3bca9af39
commit f85786f203
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 686 additions and 721 deletions

67
.github/workflows/critical-tests.yml vendored Normal file
View file

@ -0,0 +1,67 @@
name: RUN_CRITICAL_TESTS
# Only trigger, when the build workflow succeeded
on:
workflow_run:
workflows: [TEST-ENV-DEPLOYMENT]
types: [completed]
jobs:
cypress-run-critical:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Get API_URI
id: api_uri
# Search for API_URI in PR description and use default if not defined
env:
pull_request_body: ${{ github.event.pull_request.body }}
prefix: API_URI=
pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/?
fallback_uri: ${{ secrets.CYPRESS_API_URI }}
run: |
echo "::set-output name=custom_api_uri::$(echo $pull_request_body | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1 | { read custom_uri; if [ -z "$custom_uri" ]; then echo "$fallback_uri"; else echo "$custom_uri"; fi })"
- name: Get base_URL
id: base_URL
run: |
echo "::set-output name=base_URL::https://$(echo ${GITHUB_HEAD_REF}).dashboard.saleor.rocks"
- name: Setup Node
uses: actions/setup-node@v1
with:
node-version: 14
- name: Cache node modules
uses: actions/cache@v2
env:
cache-name: cache-node-modules
with:
path: ~/.npm
key: ${{ runner.os }}-qa-${{ env.cache-name }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-qa-${{ env.cache-name }}-
${{ runner.os }}-qa-
${{ runner.os }}-
- name: Install Dependencies
if: steps.cache-node-modules.outputs.cache-hit != 'true'
run: npm install
- name: Cypress run critical
uses: cypress-io/github-action@v2
env:
API_URI: ${{ steps.api_uri.outputs.custom_api_uri }}
APP_MOUNT_URI: ${{ secrets.APP_MOUNT_URI }}
CYPRESS_baseUrl: ${{ steps.base_URL.outputs.base_URL }}
CYPRESS_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
CYPRESS_SECOND_USER_NAME: ${{ secrets.CYPRESS_SECOND_USER_NAME }}
CYPRESS_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}
CYPRESS_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
with:
command: npm run cy:run:critical
wait-on: ${{ steps.base_URL.outputs.base_URL }}
- uses: actions/upload-artifact@v1
with:
name: cypress-videos
path: cypress/videos

View file

@ -69,45 +69,4 @@ jobs:
if: ${{ failure() }} if: ${{ failure() }}
with: with:
name: cypress-videos name: cypress-videos
path: cypress/videos path: cypress/videos
cypress-run-critical:
if: github.event.pull_request.head.repo.full_name == 'saleor/saleor-dashboard' && ((github.event.label.name != 'run e2e') || !(contains(github.event.pull_request.labels.*.name, 'run e2e')))
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v1
- name: Get API_URI
id: api_uri
# Search for CYPRESS_API_URI in PR description and use default if not defined
env:
pull_request_body: ${{ github.event.pull_request.body }}
prefix: CYPRESS_API_URI=
pattern: (http|https)://[a-zA-Z0-9.-]+/graphql/?
fallback_uri: ${{ secrets.CYPRESS_API_URI }}
run: |
echo "::set-output name=custom_api_uri::$(echo $pull_request_body | grep -Eo "$prefix$pattern" | sed s/$prefix// | head -n 1 | { read custom_uri; if [ -z "$custom_uri" ]; then echo "$fallback_uri"; else echo "$custom_uri"; fi })"
- name: Cypress run critical
if: ${{ steps.api_uri.outputs.custom_api_uri != 'https://qa.staging.saleor.cloud/graphql/' }}
uses: cypress-io/github-action@v2
env:
API_URI: ${{ steps.api_uri.outputs.custom_api_uri }}
APP_MOUNT_URI: ${{ secrets.APP_MOUNT_URI }}
CYPRESS_baseUrl: ${{ secrets.CYPRESS_BASEURL }}
CYPRESS_USER_NAME: ${{ secrets.CYPRESS_USER_NAME }}
CYPRESS_SECOND_USER_NAME: ${{ secrets.CYPRESS_SECOND_USER_NAME }}
CYPRESS_USER_PASSWORD: ${{ secrets.CYPRESS_USER_PASSWORD }}
CYPRESS_PERMISSIONS_USERS_PASSWORD: ${{ secrets.CYPRESS_PERMISSIONS_USERS_PASSWORD }}
with:
build: npm run build
start: npx local-web-server --spa index.html
wait-on: http://localhost:9000/
wait-on-timeout: 120
command: npm run cy:run:critical
- uses: actions/upload-artifact@v1
if: ${{ failure() }}
with:
name: cypress-videos
path: cypress/videos

View file

@ -6,5 +6,6 @@
"defaultCommandTimeout": 15000, "defaultCommandTimeout": 15000,
"requestTimeout": 15000, "requestTimeout": 15000,
"viewportWidth": 1400, "viewportWidth": 1400,
"viewportHeight": 660 "viewportHeight": 660,
"videos": false
} }

View file

@ -4,65 +4,81 @@ import { ONE_PERMISSION_USERS, TEST_ADMIN_USER } from "./users";
export const PERMISSIONS_OPTIONS = { export const PERMISSIONS_OPTIONS = {
all: { all: {
user: TEST_ADMIN_USER, user: TEST_ADMIN_USER,
permissions: Object.values(PERMISSIONS) permissions: Object.values(PERMISSIONS),
testCase: "TC: SALEOR_3401"
}, },
app: { app: {
user: ONE_PERMISSION_USERS.app, user: ONE_PERMISSION_USERS.app,
permissions: [PERMISSIONS.app] permissions: [PERMISSIONS.app],
testCase: "TC: SALEOR_3402"
}, },
channel: { channel: {
user: ONE_PERMISSION_USERS.channel, user: ONE_PERMISSION_USERS.channel,
permissions: [PERMISSIONS.channel] permissions: [PERMISSIONS.channel],
testCase: "TC: SALEOR_3403"
}, },
customer: { customer: {
user: ONE_PERMISSION_USERS.user, user: ONE_PERMISSION_USERS.user,
permissions: [PERMISSIONS.customer] permissions: [PERMISSIONS.customer],
testCase: "TC: SALEOR_3404"
}, },
discount: { discount: {
user: ONE_PERMISSION_USERS.discount, user: ONE_PERMISSION_USERS.discount,
permissions: [PERMISSIONS.discounts] permissions: [PERMISSIONS.discounts],
testCase: "TC: SALEOR_3405"
}, },
giftCard: { giftCard: {
user: ONE_PERMISSION_USERS.giftCard user: ONE_PERMISSION_USERS.giftCard,
testCase: "TC: SALEOR_3406"
}, },
order: { order: {
user: ONE_PERMISSION_USERS.order, user: ONE_PERMISSION_USERS.order,
permissions: [PERMISSIONS.order] permissions: [PERMISSIONS.order],
testCase: "TC: SALEOR_3407"
}, },
page: { page: {
user: ONE_PERMISSION_USERS.page, user: ONE_PERMISSION_USERS.page,
permissions: [PERMISSIONS.page] permissions: [PERMISSIONS.page],
testCase: "TC: SALEOR_3408"
}, },
plugin: { plugin: {
user: ONE_PERMISSION_USERS.plugin, user: ONE_PERMISSION_USERS.plugin,
permissions: [PERMISSIONS.plugin] permissions: [PERMISSIONS.plugin],
testCase: "TC: SALEOR_3409"
}, },
product: { product: {
user: ONE_PERMISSION_USERS.product, user: ONE_PERMISSION_USERS.product,
permissions: [PERMISSIONS.product, PERMISSIONS.warehouse] permissions: [PERMISSIONS.product, PERMISSIONS.warehouse],
testCase: "TC: SALEOR_3410"
}, },
productTypeAndAttribute: { productTypeAndAttribute: {
user: ONE_PERMISSION_USERS.productTypeAndAttribute, user: ONE_PERMISSION_USERS.productTypeAndAttribute,
permissions: [PERMISSIONS.productTypeAndAttribute] permissions: [PERMISSIONS.productTypeAndAttribute],
testCase: "TC: SALEOR_3411"
}, },
pageTypeAndAttribute: { pageTypeAndAttribute: {
user: ONE_PERMISSION_USERS.pageTypeAndAttribute, user: ONE_PERMISSION_USERS.pageTypeAndAttribute,
permissions: [PERMISSIONS.pageTypeAndAttribute] permissions: [PERMISSIONS.pageTypeAndAttribute],
testCase: "TC: SALEOR_3412"
}, },
settings: { settings: {
user: ONE_PERMISSION_USERS.settings, user: ONE_PERMISSION_USERS.settings,
permissions: [PERMISSIONS.settings] permissions: [PERMISSIONS.settings],
testCase: "TC: SALEOR_3413"
}, },
shipping: { shipping: {
user: ONE_PERMISSION_USERS.shipping, user: ONE_PERMISSION_USERS.shipping,
permissions: [PERMISSIONS.shipping] permissions: [PERMISSIONS.shipping],
testCase: "TC: SALEOR_3415"
}, },
staff: { staff: {
user: ONE_PERMISSION_USERS.staff, user: ONE_PERMISSION_USERS.staff,
permissions: [PERMISSIONS.staff] permissions: [PERMISSIONS.staff],
testCase: "TC: SALEOR_3414"
}, },
translations: { translations: {
user: ONE_PERMISSION_USERS.translations, user: ONE_PERMISSION_USERS.translations,
permissions: [PERMISSIONS.translations] permissions: [PERMISSIONS.translations],
testCase: "TC: SALEOR_3416"
} }
}; };

View file

@ -3,21 +3,13 @@
import faker from "faker"; import faker from "faker";
import { createAttribute } from "../../support/api/requests/Attribute";
import { createCategory } from "../../support/api/requests/Category";
import { import {
checkoutShippingAddressUpdate, checkoutShippingAddressUpdate,
checkoutShippingMethodUpdate,
checkoutVariantsUpdate, checkoutVariantsUpdate,
completeCheckout, completeCheckout,
createCheckout createCheckout
} from "../../support/api/requests/Checkout"; } from "../../support/api/requests/Checkout";
import { getOrder } from "../../support/api/requests/Order"; import { getOrder } from "../../support/api/requests/Order";
import {
createDigitalContent,
createTypeProduct
} from "../../support/api/requests/ProductType";
import { getDefaultChannel } from "../../support/api/utils/channelsUtils";
import { import {
addPayment, addPayment,
createAndCompleteCheckoutWithoutShipping, createAndCompleteCheckoutWithoutShipping,
@ -25,110 +17,46 @@ import {
getShippingMethodIdFromCheckout, getShippingMethodIdFromCheckout,
updateShippingInCheckout updateShippingInCheckout
} from "../../support/api/utils/ordersUtils"; } from "../../support/api/utils/ordersUtils";
import { import { createDigitalAndPhysicalProductWithNewDataAndDefaultChannel } from "../../support/api/utils/products/productsUtils";
addDigitalContentAndUpdateProductType,
createProductInChannel,
deleteProductsStartsWith
} from "../../support/api/utils/products/productsUtils";
import {
createShipping,
deleteShippingStartsWith
} from "../../support/api/utils/shippingUtils";
import filterTests from "../../support/filterTests"; import filterTests from "../../support/filterTests";
filterTests({ definedTags: ["all", "critical"] }, () => { filterTests({ definedTags: ["all", "critical", "refactored"] }, () => {
describe("Purchase products with all products types", () => { describe("As an unlogged customer I want to order physical and digital products", () => {
const startsWith = `CyPurchaseByType`; const startsWith = `CyPurchaseByType`;
const name = `${startsWith}${faker.datatype.number()}`;
const email = `${startsWith}@example.com`; const email = `${startsWith}@example.com`;
const testsMessage = "Check order status"; const testsMessage = "Check order status";
const digitalName = `${startsWith}${faker.datatype.number()}`;
const physicalName = `${startsWith}${faker.datatype.number()}`;
const { softExpect } = chai; const { softExpect } = chai;
let defaultChannel; let defaultChannel;
let address; let address;
let warehouse;
let attribute;
let category;
let shippingMethod; let shippingMethod;
let createProductData; let digitalVariants;
let physicalVariants;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
deleteProductsStartsWith(startsWith); createDigitalAndPhysicalProductWithNewDataAndDefaultChannel({
deleteShippingStartsWith(startsWith); physicalProductName: physicalName,
getDefaultChannel().then(channelResp => (defaultChannel = channelResp)); digitalProductName: digitalName
cy.fixture("addresses") }).then(resp => {
.then(addresses => { defaultChannel = resp.defaultChannel;
address = addresses.usAddress; address = resp.address;
createShipping({ shippingMethod = resp.shippingMethod;
channelId: defaultChannel.id, digitalVariants = resp.digitalVariants;
name, physicalVariants = resp.physicalVariants;
address, });
price: 10
});
})
.then(
({
warehouse: warehouseResp,
shippingMethod: shippingMethodResp
}) => {
warehouse = warehouseResp;
shippingMethod = shippingMethodResp;
}
);
createAttribute({ name })
.then(attributeResp => {
attribute = attributeResp;
createCategory({ name });
})
.then(categoryResp => {
category = categoryResp;
});
}); });
beforeEach(() => { it("should purchase digital product as unlogged customer. TC: SALEOR_0402", () => {
cy.clearSessionData().loginUserViaRequest(); createAndCompleteCheckoutWithoutShipping({
createProductData = { channelSlug: defaultChannel.slug,
channelId: defaultChannel.id, email,
warehouseId: warehouse.id, billingAddress: address,
quantityInWarehouse: 10, variantsList: digitalVariants,
attributeId: attribute.id, auth: "token"
categoryId: category.id,
price: 10
};
});
it("should purchase digital product", () => {
const digitalName = `${startsWith}${faker.datatype.number()}`;
let variants;
createTypeProduct({
name: digitalName,
attributeId: attribute.id,
shippable: false
}) })
.then(productType => {
createProductData.name = digitalName;
createProductData.productTypeId = productType.id;
createProductInChannel(createProductData);
})
.then(({ variantsList }) => {
variants = variantsList;
addDigitalContentAndUpdateProductType(
variants[0].id,
createProductData.productTypeId,
defaultChannel.id
);
})
.then(() => {
createAndCompleteCheckoutWithoutShipping({
channelSlug: defaultChannel.slug,
email,
billingAddress: address,
variantsList: variants,
auth: "token"
});
})
.then(({ order }) => { .then(({ order }) => {
getOrder(order.id); getOrder(order.id);
}) })
@ -141,27 +69,14 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
}); });
}); });
it("should purchase physical product", () => { it("should purchase physical product as unlogged customer. TC: SALEOR_0403", () => {
const physicalName = `${startsWith}${faker.datatype.number()}`; createWaitingForCaptureOrder({
createTypeProduct({ channelSlug: defaultChannel.slug,
name: physicalName, email,
attributeId: attribute.id, variantsList: physicalVariants,
shippable: true shippingMethodName: shippingMethod.name,
address
}) })
.then(productType => {
createProductData.name = physicalName;
createProductData.productTypeId = productType.id;
createProductInChannel(createProductData);
})
.then(({ variantsList }) => {
createWaitingForCaptureOrder({
channelSlug: defaultChannel.slug,
email,
variantsList,
shippingMethodName: shippingMethod.name,
address
});
})
.then(({ order }) => { .then(({ order }) => {
getOrder(order.id); getOrder(order.id);
}) })
@ -174,52 +89,22 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
}); });
}); });
it("should purchase multiple products with all product types", () => { it("should purchase multiple products with all product types as unlogged customer. TC: SALEOR_0404", () => {
const physicalName = `${startsWith}${faker.datatype.number()}`;
const digitalName = `${startsWith}${faker.datatype.number()}`;
let digitalProductVariantsList;
let checkout; let checkout;
createTypeProduct({
name: digitalName, createCheckout({
attributeId: attribute.id, channelSlug: defaultChannel.slug,
shippable: false email,
variantsList: digitalVariants,
billingAddress: address,
auth: "token"
}) })
.then(productType => {
createProductData.name = digitalName;
createProductData.productTypeId = productType.id;
createProductInChannel(createProductData);
})
.then(({ variantsList }) => {
digitalProductVariantsList = variantsList;
createDigitalContent(variantsList[0].id);
})
.then(() => {
createCheckout({
channelSlug: defaultChannel.slug,
email,
variantsList: digitalProductVariantsList,
billingAddress: address,
auth: "token"
});
})
.then(({ checkout: checkoutResp }) => { .then(({ checkout: checkoutResp }) => {
checkout = checkoutResp; checkout = checkoutResp;
addPayment(checkout.id); addPayment(checkout.id);
}) })
.then(() => { .then(() => {
createTypeProduct({ checkoutVariantsUpdate(checkout.id, physicalVariants);
name: physicalName,
attributeId: attribute.id,
shippable: true
});
})
.then(productType => {
createProductData.name = physicalName;
createProductData.productTypeId = productType.id;
createProductInChannel(createProductData);
})
.then(({ variantsList }) => {
checkoutVariantsUpdate(checkout.id, variantsList);
}) })
.then(() => { .then(() => {
const shippingMethodId = getShippingMethodIdFromCheckout( const shippingMethodId = getShippingMethodIdFromCheckout(

View file

@ -8,114 +8,70 @@ import {
createCheckout createCheckout
} from "../../support/api/requests/Checkout"; } from "../../support/api/requests/Checkout";
import { getVariants } from "../../support/api/requests/Product"; import { getVariants } from "../../support/api/requests/Product";
import { getDefaultChannel } from "../../support/api/utils/channelsUtils"; import { createWaitingForCaptureOrder } from "../../support/api/utils/ordersUtils";
import { createOrderWithNewProduct } from "../../support/api/utils/ordersUtils"; import { createNewProductWithSeveralVariants } from "../../support/api/utils/products/productsUtils";
import {
createProductInChannel,
createTypeAttributeAndCategoryForProduct,
deleteProductsStartsWith
} from "../../support/api/utils/products/productsUtils";
import {
createShipping,
deleteShippingStartsWith
} from "../../support/api/utils/shippingUtils";
import filterTests from "../../support/filterTests"; import filterTests from "../../support/filterTests";
filterTests({ definedTags: ["all", "critical"] }, () => { filterTests({ definedTags: ["all", "critical", "refactored"] }, () => {
describe("Products stocks in checkout", () => { describe("Manage products stocks in checkout", () => {
const startsWith = "CyStocksCheckout-"; const startsWith = "CyStocksCheckout-";
const name = `${startsWith}${faker.datatype.number()}`; const name = `${startsWith}${faker.datatype.number()}`;
let defaultChannel; let defaultChannel;
let address; let address;
let warehouse;
let attribute;
let category;
let productType;
let shippingMethod; let shippingMethod;
let variantsWithLowStock;
let variantsWithoutTrackInventory;
let lastVariantInStock;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
deleteProductsStartsWith(startsWith);
deleteShippingStartsWith(startsWith);
cy.fixture("addresses")
.then(addresses => {
address = addresses.usAddress;
getDefaultChannel();
})
.then(channel => {
defaultChannel = channel;
createShipping({
channelId: defaultChannel.id,
name,
address
});
})
.then(
({
warehouse: warehouseResp,
shippingMethod: shippingMethodResp
}) => {
warehouse = warehouseResp;
shippingMethod = shippingMethodResp;
createTypeAttributeAndCategoryForProduct({ name });
}
)
.then(
({
attribute: attributeResp,
category: categoryResp,
productType: productTypeResp
}) => {
attribute = attributeResp;
category = categoryResp;
productType = productTypeResp;
}
);
});
it("should create checkout with last product in stock", () => {
const productName = `${startsWith}${faker.datatype.number()}`;
createOrderWithNewProduct({ const variantsData = [
attributeId: attribute.id, {
categoryId: category.id, name: "variantsWithLowStock",
productTypeId: productType.id, trackInventory: true,
channel: defaultChannel, quantityInWarehouse: 1
name: productName, },
warehouseId: warehouse.id, {
shippingMethod, name: "variantsWithoutTrackInventory",
address trackInventory: false,
}).then(({ order }) => { quantityInWarehouse: 0
expect(order, "order should be created").to.be.ok; },
{
name: "lastVariantInStock",
trackInventory: true,
quantityInWarehouse: 1
}
];
createNewProductWithSeveralVariants(name, variantsData).then(resp => {
defaultChannel = resp.defaultChannel;
address = resp.address;
shippingMethod = resp.shippingMethod;
variantsWithLowStock = resp.createdVariants.find(
variant => variant.name === "variantsWithLowStock"
);
variantsWithoutTrackInventory = resp.createdVariants.find(
variant => variant.name === "variantsWithoutTrackInventory"
);
lastVariantInStock = resp.createdVariants.find(
variant => variant.name === "lastVariantInStock"
);
}); });
}); });
it("should not be possible to add product with quantity greater than stock", () => { it("should not be possible to add product with quantity greater than stock to checkout. TC: SALEOR_0405", () => {
const productName = `${startsWith}${faker.datatype.number()}`; createCheckout({
let variants; channelSlug: defaultChannel.slug,
address,
createProductInChannel({ billingAddress: address,
attributeId: attribute.id, email: "email@example.com",
categoryId: category.id, variantsList: [variantsWithLowStock],
productTypeId: productType.id, auth: "token"
channelId: defaultChannel.id,
name: productName,
warehouseId: warehouse.id,
quantityInWarehouse: 1
}) })
.then(({ variantsList }) => {
variants = variantsList;
createCheckout({
channelSlug: defaultChannel.slug,
address,
billingAddress: address,
email: "email@example.com",
variantsList,
auth: "token"
});
})
.then(({ checkout: checkout }) => { .then(({ checkout: checkout }) => {
addProductsToCheckout(checkout.id, variants, 2); addProductsToCheckout(checkout.id, [variantsWithLowStock], 2);
}) })
.then(({ errors }) => { .then(({ errors }) => {
expect( expect(
@ -125,46 +81,34 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
}); });
}); });
it("should buy product with no quantity if tracking is not set", () => { it("should buy product with no quantity if tracking is not set. TC: SALEOR_0406", () => {
const productName = `${startsWith}${faker.datatype.number()}`; createWaitingForCaptureOrder({
address,
createOrderWithNewProduct({ channelSlug: defaultChannel.slug,
attributeId: attribute.id, email: "example@example.com",
categoryId: category.id, shippingMethodName: shippingMethod.name,
productTypeId: productType.id, variantsList: [variantsWithoutTrackInventory]
channel: defaultChannel,
name: productName,
warehouseId: warehouse.id,
quantityInWarehouse: 0,
trackInventory: false,
shippingMethod,
address
}).then(({ order }) => { }).then(({ order }) => {
expect(order, "order should be created").to.be.ok; expect(order, "order should be created").to.be.ok;
}); });
}); });
it("should change product stock after purchase", () => { it("should create checkout with last product in stock. TC: SALEOR_0419", () => {
const productName = `${startsWith}${faker.datatype.number()}`; createWaitingForCaptureOrder({
address,
createOrderWithNewProduct({ channelSlug: defaultChannel.slug,
attributeId: attribute.id, email: "example@example.com",
categoryId: category.id, shippingMethodName: shippingMethod.name,
productTypeId: productType.id, variantsList: [lastVariantInStock]
channel: defaultChannel,
name: productName,
warehouseId: warehouse.id,
quantityInWarehouse: 10,
trackInventory: true,
shippingMethod,
address
}) })
.then(({ variantsList }) => { .then(({ order }) => {
getVariants(variantsList); expect(order, "order should be created").to.be.ok;
getVariants([lastVariantInStock]);
}) })
.then(variantsList => { .then(variantsList => {
const variant = variantsList.edges[0]; const variant = variantsList.edges[0];
expect(variant.node.stocks[0].quantityAllocated).to.eq(1); expect(variant.node.stocks[0].quantityAllocated).to.eq(1);
expect(variant.node.stocks[0].quantity).to.eq(1);
}); });
}); });
}); });

View file

@ -5,28 +5,32 @@ import faker from "faker";
import { HOMEPAGE_SELECTORS } from "../../elements/homePage/homePage-selectors"; import { HOMEPAGE_SELECTORS } from "../../elements/homePage/homePage-selectors";
import { urlList } from "../../fixtures/urlList"; import { urlList } from "../../fixtures/urlList";
import { import { createCustomer } from "../../support/api/requests/Customer";
createCustomer,
deleteCustomersStartsWith
} from "../../support/api/requests/Customer";
import { getDefaultChannel } from "../../support/api/utils/channelsUtils";
import * as homePageUtils from "../../support/api/utils/homePageUtils"; import * as homePageUtils from "../../support/api/utils/homePageUtils";
import { import {
createReadyToFulfillOrder, createReadyToFulfillOrder,
createWaitingForCaptureOrder createWaitingForCaptureOrder
} from "../../support/api/utils/ordersUtils"; } from "../../support/api/utils/ordersUtils";
import * as productsUtils from "../../support/api/utils/products/productsUtils"; import * as productsUtils from "../../support/api/utils/products/productsUtils";
import * as shippingUtils from "../../support/api/utils/shippingUtils";
import filterTests from "../../support/filterTests"; import filterTests from "../../support/filterTests";
import { changeChannel } from "../../support/pages/homePage"; import {
changeChannel,
getOrdersReadyForCaptureRegex,
getOrdersReadyToFulfillRegex,
getProductsOutOfStockRegex,
getSalesAmountRegex,
getTodaysOrdersRegex
} from "../../support/pages/homePage";
// <reference types="cypress" /> filterTests({ definedTags: ["all", "critical", "refactored"] }, () => {
describe("As an admin I want to see correct information on dashboard home page", () => {
filterTests({ definedTags: ["all", "critical"] }, () => {
describe("Homepage analytics", () => {
const startsWith = "CyHomeAnalytics"; const startsWith = "CyHomeAnalytics";
const productPrice = 22;
const shippingPrice = 12;
const randomName = startsWith + faker.datatype.number();
const randomEmail = `${startsWith}${randomName}@example.com`;
let customerId; let customer;
let defaultChannel; let defaultChannel;
let createdVariants; let createdVariants;
let productType; let productType;
@ -34,72 +38,108 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
let category; let category;
let warehouse; let warehouse;
let shippingMethod; let shippingMethod;
let addresses; let address;
let ordersReadyToFulfillRegexp;
const productPrice = 22; let ordersReadyForCaptureRegexp;
const shippingPrice = 12; let productsOutOfStockRegexp;
const randomName = startsWith + faker.datatype.number(); let salesAmountRegexp;
const randomEmail = `${startsWith}${randomName}@example.com`; let ordersRegexp;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
productsUtils.deleteProductsStartsWith(startsWith);
deleteCustomersStartsWith(startsWith);
shippingUtils.deleteShippingStartsWith(startsWith);
getDefaultChannel() productsUtils
.then(channel => { .createProductWithShipping({
defaultChannel = channel; name: randomName,
cy.fixture("addresses"); productPrice,
shippingPrice
}) })
.then(addressesFixture => (addresses = addressesFixture))
.then(() =>
createCustomer(randomEmail, randomName, addresses.plAddress)
)
.then(resp => { .then(resp => {
customerId = resp.user.id; createdVariants = resp.variantsList;
shippingUtils.createShipping({ address = resp.address;
channelId: defaultChannel.id, warehouse = resp.warehouse;
name: randomName, defaultChannel = resp.defaultChannel;
address: addresses.plAddress, shippingMethod = resp.shippingMethod;
price: shippingPrice attribute = resp.attribute;
}); category = resp.category;
productType = resp.productType;
createCustomer(randomEmail, randomName, address).then(
customerResp => (customer = customerResp)
);
homePageUtils
.getOrdersReadyToFulfill(defaultChannel.slug)
.then(ordersReadyToFulfillBefore => {
ordersReadyToFulfillRegexp = getOrdersReadyToFulfillRegex(
ordersReadyToFulfillBefore,
1
);
});
homePageUtils
.getOrdersReadyForCapture(defaultChannel.slug)
.then(ordersReadyForCaptureBefore => {
ordersReadyForCaptureRegexp = getOrdersReadyForCaptureRegex(
ordersReadyForCaptureBefore,
1
);
});
homePageUtils
.getProductsOutOfStock(defaultChannel.slug)
.then(productsOutOfStockBefore => {
productsOutOfStockRegexp = getProductsOutOfStockRegex(
productsOutOfStockBefore,
1
);
});
homePageUtils
.getSalesAmount(defaultChannel.slug)
.then(salesAmount => {
salesAmountRegexp = getSalesAmountRegex(
salesAmount,
productPrice * 2 + shippingPrice
);
});
homePageUtils
.getTodaysOrders(defaultChannel.slug)
.then(ordersBefore => {
ordersRegexp = getTodaysOrdersRegex(ordersBefore, 2);
});
}) })
.then( .then(() => {
({ createReadyToFulfillOrder({
warehouse: warehouseResp, customerId: customer.id,
shippingMethod: shippingMethodResp shippingMethodId: shippingMethod.id,
}) => { channelId: defaultChannel.id,
warehouse = warehouseResp; variantsList: createdVariants,
shippingMethod = shippingMethodResp; address
productsUtils.createTypeAttributeAndCategoryForProduct({ });
name: randomName
}); createWaitingForCaptureOrder({
} channelSlug: defaultChannel.slug,
) email: randomEmail,
.then( variantsList: createdVariants,
({ shippingMethodName: shippingMethod.name,
productType: productTypeResp, address
attribute: attributeResp, });
category: categoryResp
}) => { const productOutOfStockRandomName =
productType = productTypeResp; startsWith + faker.datatype.number();
attribute = attributeResp;
category = categoryResp; productsUtils.createProductInChannel({
productsUtils.createProductInChannel({ name: productOutOfStockRandomName,
name: randomName, channelId: defaultChannel.id,
channelId: defaultChannel.id, warehouseId: warehouse.id,
warehouseId: warehouse.id, quantityInWarehouse: 0,
quantityInWarehouse: 20, productTypeId: productType.id,
productTypeId: productType.id, attributeId: attribute.id,
attributeId: attribute.id, categoryId: category.id,
categoryId: category.id, price: productPrice
price: productPrice });
});
}
)
.then(({ variantsList: variantsResp }) => {
createdVariants = variantsResp;
}); });
}); });
@ -107,161 +147,25 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
}); });
it("should all elements be visible on the dashboard", () => { it("should display correct information on dashboard home page. SALEOR_2004", () => {
cy.visit(urlList.homePage) cy.visit(urlList.homePage);
.softAssertVisibility(HOMEPAGE_SELECTORS.sales) changeChannel(defaultChannel.name);
.softAssertVisibility(HOMEPAGE_SELECTORS.orders) cy.contains(HOMEPAGE_SELECTORS.orders, ordersRegexp).should("be.visible");
.softAssertVisibility(HOMEPAGE_SELECTORS.activity) cy.contains(
.softAssertVisibility(HOMEPAGE_SELECTORS.topProducts) HOMEPAGE_SELECTORS.ordersReadyToFulfill,
.softAssertVisibility(HOMEPAGE_SELECTORS.ordersReadyToFulfill) ordersReadyToFulfillRegexp
.softAssertVisibility(HOMEPAGE_SELECTORS.paymentsWaitingForCapture) ).should("be.visible");
.softAssertVisibility(HOMEPAGE_SELECTORS.productsOutOfStock); cy.contains(
}); HOMEPAGE_SELECTORS.ordersReadyForCapture,
ordersReadyForCaptureRegexp
it("should correct amount of ready to fullfil orders be displayed", () => { ).should("be.visible");
homePageUtils cy.contains(HOMEPAGE_SELECTORS.sales, salesAmountRegexp).should(
.getOrdersReadyToFulfill(defaultChannel.slug) "be.visible"
.as("ordersReadyToFulfill"); );
createReadyToFulfillOrder({ cy.contains(
customerId, HOMEPAGE_SELECTORS.productsOutOfStock,
shippingMethodId: shippingMethod.id, productsOutOfStockRegexp
channelId: defaultChannel.id, ).should("be.visible");
variantsList: createdVariants,
address: addresses.plAddress
});
cy.get("@ordersReadyToFulfill").then(ordersReadyToFulfillBefore => {
const allOrdersReadyToFulfill = ordersReadyToFulfillBefore + 1;
const notANumberRegex = "\\D*";
const ordersReadyToFulfillRegexp = new RegExp(
`${notANumberRegex}${allOrdersReadyToFulfill}${notANumberRegex}`
);
cy.visit(urlList.homePage);
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");
createWaitingForCaptureOrder({
channelSlug: defaultChannel.slug,
email: randomEmail,
variantsList: createdVariants,
shippingMethodName: shippingMethod.name,
address: addresses.plAddress
});
cy.get("@ordersReadyForCapture").then(ordersReadyForCaptureBefore => {
const allOrdersReadyForCapture = ordersReadyForCaptureBefore + 1;
const notANumberRegex = "\\D*";
const ordersReadyForCaptureRegexp = new RegExp(
`${notANumberRegex}${allOrdersReadyForCapture}${notANumberRegex}`
);
cy.visit(urlList.homePage);
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.datatype.number();
productsUtils.createProductInChannel({
name: productOutOfStockRandomName,
channelId: defaultChannel.id,
warehouseId: warehouse.id,
quantityInWarehouse: 0,
productTypeId: productType.id,
attributeId: attribute.id,
categoryId: category.id,
price: productPrice
});
cy.get("@productsOutOfStock").then(productsOutOfStockBefore => {
const allProductsOutOfStock = productsOutOfStockBefore + 1;
const notANumberRegex = "\\D*";
const productsOutOfStockRegexp = new RegExp(
`${notANumberRegex}${allProductsOutOfStock}${notANumberRegex}`
);
cy.visit(urlList.homePage);
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");
createReadyToFulfillOrder({
customerId,
shippingMethodId: shippingMethod.id,
channelId: defaultChannel.id,
variantsList: createdVariants,
address: addresses.plAddress
});
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 = new Intl.NumberFormat(
"en"
)
.format(totalAmountIntegerValue)
.replaceAll(",", "[,.]*");
const totalAmountWithSeparators = `${totalAmountIntegerWithThousandsSeparator}${decimalSeparator}${totalAmountDecimalValue}`;
const notANumberRegex = "\\D*";
const salesAmountRegexp = new RegExp(
`${notANumberRegex}${totalAmountWithSeparators}${notANumberRegex}`
);
cy.visit(urlList.homePage);
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");
createReadyToFulfillOrder({
customerId,
shippingMethodId: shippingMethod.id,
channelId: defaultChannel.id,
variantsList: createdVariants,
address: addresses.plAddress
});
cy.get("@todaysOrders").then(ordersBefore => {
const allOrders = ordersBefore + 1;
const notANumberRegex = "\\D*";
const ordersRegexp = new RegExp(
`${notANumberRegex}${allOrders}${notANumberRegex}`
);
cy.visit(urlList.homePage);
changeChannel(defaultChannel.name);
cy.contains(HOMEPAGE_SELECTORS.orders, ordersRegexp).should(
"be.visible"
);
});
}); });
}); });
}); });

View file

@ -5,11 +5,12 @@ import { PERMISSIONS_OPTIONS } from "../fixtures/permissionsUsers";
import filterTests from "../support/filterTests"; import filterTests from "../support/filterTests";
import * as permissionsSteps from "../support/pages/permissionsPage"; import * as permissionsSteps from "../support/pages/permissionsPage";
describe("Navigation for users with different permissions", () => { describe("As a staff user I want to navigate through shop using different permissions", () => {
Object.keys(PERMISSIONS_OPTIONS).forEach(key => { Object.keys(PERMISSIONS_OPTIONS).forEach(key => {
const tags = key === "all" ? ["critical", "all"] : ["all"]; const tags =
key === "all" ? ["critical", "all", "refactored"] : ["all", "refactored"];
filterTests({ definedTags: tags }, () => { filterTests({ definedTags: tags }, () => {
it(`should navigate as an user with ${key} permission`, () => { it(`should be able to navigate through shop as a staff member using ${key} permission. ${PERMISSIONS_OPTIONS[key].testCase}`, () => {
const permissionOption = PERMISSIONS_OPTIONS[key]; const permissionOption = PERMISSIONS_OPTIONS[key];
const permissions = permissionOption.permissions; const permissions = permissionOption.permissions;
cy.clearSessionData(); cy.clearSessionData();

View file

@ -14,7 +14,6 @@ import {
expectCorrectProductInformation, expectCorrectProductInformation,
expectCorrectProductVariantInformation expectCorrectProductVariantInformation
} from "../../support/api/utils/products/checkProductInfo"; } from "../../support/api/utils/products/checkProductInfo";
import * as productUtils from "../../support/api/utils/products/productsUtils";
import filterTests from "../../support/filterTests"; import filterTests from "../../support/filterTests";
import { metadataForms } from "../../support/pages/catalog/metadataComponent"; import { metadataForms } from "../../support/pages/catalog/metadataComponent";
import { import {
@ -25,7 +24,7 @@ import { fillUpCommonFieldsForAllProductTypes } from "../../support/pages/catalo
import { selectChannelInDetailsPages } from "../../support/pages/channelsPage"; import { selectChannelInDetailsPages } from "../../support/pages/channelsPage";
filterTests({ definedTags: ["all", "critical"] }, () => { filterTests({ definedTags: ["all", "critical"] }, () => {
describe("Create product", () => { describe("As an admin I should be able to create product", () => {
const startsWith = "CyCreateProduct-"; const startsWith = "CyCreateProduct-";
const name = `${startsWith}${faker.datatype.number()}`; const name = `${startsWith}${faker.datatype.number()}`;
const generalInfo = { const generalInfo = {
@ -53,7 +52,6 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
productUtils.deleteProductsStartsWith(startsWith);
createAttribute({ name }).then(attributeResp => { createAttribute({ name }).then(attributeResp => {
attribute = attributeResp; attribute = attributeResp;
}); });
@ -62,7 +60,7 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
}); });
it("should create product with variants", () => { it("should be able to create product with variants as an admin. SALEOR_2701", () => {
const randomName = `${startsWith}${faker.datatype.number()}`; const randomName = `${startsWith}${faker.datatype.number()}`;
seo.slug = randomName; seo.slug = randomName;
const productData = { const productData = {
@ -89,7 +87,7 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
}); });
}); });
it("should create product without variants", () => { it("should be able to create product without variants as an admin. SALEOR_2702", () => {
const prices = { sellingPrice: 6, costPrice: 3 }; const prices = { sellingPrice: 6, costPrice: 3 };
const randomName = `${startsWith}${faker.datatype.number()}`; const randomName = `${startsWith}${faker.datatype.number()}`;
seo.slug = randomName; seo.slug = randomName;

View file

@ -7,7 +7,7 @@ import { SHARED_ELEMENTS } from "../../elements/shared/sharedElements";
import { demoProductsNames } from "../../fixtures/products"; import { demoProductsNames } from "../../fixtures/products";
import { productDetailsUrl, urlList } from "../../fixtures/urlList"; import { productDetailsUrl, urlList } from "../../fixtures/urlList";
import { getFirstProducts } from "../../support/api/requests/Product"; import { getFirstProducts } from "../../support/api/requests/Product";
import { deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel } from "../../support/api/utils/products/productsUtils"; import { createNewProductWithNewDataAndDefaultChannel } from "../../support/api/utils/products/productsUtils";
import filterTests from "../../support/filterTests"; import filterTests from "../../support/filterTests";
filterTests({ definedTags: ["all"] }, () => { filterTests({ definedTags: ["all"] }, () => {
@ -71,7 +71,7 @@ filterTests({ definedTags: ["all"] }, () => {
const name = "CyImages"; const name = "CyImages";
cy.clearSessionData().loginUserViaRequest(); cy.clearSessionData().loginUserViaRequest();
deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({ name }) createNewProductWithNewDataAndDefaultChannel({ name })
.then(({ product }) => { .then(({ product }) => {
cy.visit(productDetailsUrl(product.id)) cy.visit(productDetailsUrl(product.id))
.waitForProgressBarToNotBeVisible() .waitForProgressBarToNotBeVisible()

View file

@ -10,10 +10,7 @@ import {
createProduct, createProduct,
updateChannelInProduct updateChannelInProduct
} from "../../support/api/requests/Product"; } from "../../support/api/requests/Product";
import { import { getDefaultChannel } from "../../support/api/utils/channelsUtils";
deleteChannelsStartsWith,
getDefaultChannel
} from "../../support/api/utils/channelsUtils";
import * as productUtils from "../../support/api/utils/products/productsUtils"; import * as productUtils from "../../support/api/utils/products/productsUtils";
import * as shippingUtils from "../../support/api/utils/shippingUtils"; import * as shippingUtils from "../../support/api/utils/shippingUtils";
import { getProductVariants } from "../../support/api/utils/storeFront/storeFrontProductUtils"; import { getProductVariants } from "../../support/api/utils/storeFront/storeFrontProductUtils";
@ -23,10 +20,13 @@ import {
createVariant, createVariant,
variantsShouldBeVisible variantsShouldBeVisible
} from "../../support/pages/catalog/products/VariantsPage"; } from "../../support/pages/catalog/products/VariantsPage";
import { enterHomePageChangeChannelAndReturn } from "../../support/pages/channelsPage"; import {
enterHomePageChangeChannelAndReturn,
selectChannelInHeader
} from "../../support/pages/channelsPage";
filterTests({ definedTags: ["all", "critical"] }, () => { filterTests({ definedTags: ["all", "critical", "refactored"] }, () => {
describe("Creating variants", () => { describe("As an admin I should be able to create variant", () => {
const startsWith = "CyCreateVariants-"; const startsWith = "CyCreateVariants-";
const attributeValues = ["value1", "value2"]; const attributeValues = ["value1", "value2"];
@ -38,43 +38,22 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
let newChannel; let newChannel;
before(() => { before(() => {
cy.clearSessionData().loginUserViaRequest();
shippingUtils.deleteShippingStartsWith(startsWith);
productUtils.deleteProductsStartsWith(startsWith);
deleteChannelsStartsWith(startsWith);
const name = `${startsWith}${faker.datatype.number()}`; const name = `${startsWith}${faker.datatype.number()}`;
getDefaultChannel()
.then(channel => { cy.clearSessionData().loginUserViaRequest();
defaultChannel = channel;
cy.fixture("addresses"); productUtils
}) .createShippingProductTypeAttributeAndCategory(name, attributeValues)
.then(fixtureAddresses => .then(resp => {
shippingUtils.createShipping({ attribute = resp.attribute;
channelId: defaultChannel.id, productType = resp.productType;
name, category = resp.category;
address: fixtureAddresses.plAddress defaultChannel = resp.defaultChannel;
}) warehouse = resp.warehouse;
)
.then(({ warehouse: warehouseResp }) => {
warehouse = warehouseResp;
createChannel({ isActive: true, name, currencyCode: "USD" }); createChannel({ isActive: true, name, currencyCode: "USD" });
}) })
.then(resp => (newChannel = resp)); .then(resp => (newChannel = resp));
productUtils
.createTypeAttributeAndCategoryForProduct({ name, attributeValues })
.then(
({
attribute: attributeResp,
productType: productTypeResp,
category: categoryResp
}) => {
attribute = attributeResp;
productType = productTypeResp;
category = categoryResp;
}
);
}); });
beforeEach(() => { beforeEach(() => {
@ -84,7 +63,7 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
); );
}); });
it("should create variant visible on frontend", () => { it("should be able to create variant visible for the customers in all channels. TC: SALEOR_2901", () => {
const name = `${startsWith}${faker.datatype.number()}`; const name = `${startsWith}${faker.datatype.number()}`;
const price = 10; const price = 10;
let createdProduct; let createdProduct;
@ -101,6 +80,10 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
productId: createdProduct.id, productId: createdProduct.id,
channelId: defaultChannel.id channelId: defaultChannel.id
}); });
updateChannelInProduct({
productId: createdProduct.id,
channelId: newChannel.id
});
cy.visit(`${urlList.products}${createdProduct.id}`); cy.visit(`${urlList.products}${createdProduct.id}`);
createFirstVariant({ createFirstVariant({
sku: name, sku: name,
@ -111,13 +94,25 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
variantsShouldBeVisible({ name, price }); variantsShouldBeVisible({ name, price });
getProductVariants(createdProduct.id, defaultChannel.slug); getProductVariants(createdProduct.id, defaultChannel.slug);
}) })
.then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", price);
selectChannelInHeader(newChannel.name);
variantsShouldBeVisible({ name, price });
getProductVariants(createdProduct.id, defaultChannel.slug);
})
.then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", price);
getProductVariants(createdProduct.id, newChannel.slug);
})
.then(([variant]) => { .then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]); expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", price); expect(variant).to.have.property("price", price);
}); });
}); });
it("should create several variants", () => { it("should be able to create several variants visible for the customers. TC: SALEOR_2902", () => {
const name = `${startsWith}${faker.datatype.number()}`; const name = `${startsWith}${faker.datatype.number()}`;
const secondVariantSku = `${startsWith}${faker.datatype.number()}`; const secondVariantSku = `${startsWith}${faker.datatype.number()}`;
const variants = [{ price: 7 }, { name: attributeValues[1], price: 16 }]; const variants = [{ price: 7 }, { name: attributeValues[1], price: 16 }];
@ -157,52 +152,5 @@ filterTests({ definedTags: ["all", "critical"] }, () => {
expect(secondVariant).to.have.property("price", variants[1].price); expect(secondVariant).to.have.property("price", variants[1].price);
}); });
}); });
it("should create variant for many channels", () => {
const name = `${startsWith}${faker.datatype.number()}`;
const variantsPrice = 10;
let createdProduct;
createProduct({
attributeId: attribute.id,
name,
productTypeId: productType.id,
categoryId: category.id
})
.then(productResp => {
createdProduct = productResp;
updateChannelInProduct({
productId: createdProduct.id,
channelId: defaultChannel.id
});
})
.then(() => {
updateChannelInProduct({
productId: createdProduct.id,
channelId: newChannel.id
});
})
.then(() => {
cy.visit(`${urlList.products}${createdProduct.id}`);
createFirstVariant({
sku: name,
price: variantsPrice,
attribute: attributeValues[0]
});
enterHomePageChangeChannelAndReturn(defaultChannel.name);
variantsShouldBeVisible({ name, price: variantsPrice });
enterHomePageChangeChannelAndReturn(newChannel.name);
variantsShouldBeVisible({ name, price: variantsPrice });
getProductVariants(createdProduct.id, defaultChannel.slug);
})
.then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", variantsPrice);
getProductVariants(createdProduct.id, newChannel.slug);
})
.then(([variant]) => {
expect(variant).to.have.property("name", attributeValues[0]);
expect(variant).to.have.property("price", variantsPrice);
});
});
}); });
}); });

View file

@ -1,30 +1,18 @@
/// <reference types="cypress"/> /// <reference types="cypress"/>
/// <reference types="../../../support"/> /// <reference types="../../../support"/>
import { import faker from "faker";
createCustomer,
deleteCustomersStartsWith import { createCustomer } from "../../../support/api/requests/Customer";
} from "../../../support/api/requests/Customer";
import { createReadyToFulfillOrder } from "../../../support/api/utils/ordersUtils"; import { createReadyToFulfillOrder } from "../../../support/api/utils/ordersUtils";
import { import { createProductWithShipping } from "../../../support/api/utils/products/productsUtils";
createProductWithShipping,
deleteProductsStartsWith
} from "../../../support/api/utils/products/productsUtils";
import { deleteShippingStartsWith } from "../../../support/api/utils/shippingUtils";
import filterTests from "../../../support/filterTests"; import filterTests from "../../../support/filterTests";
filterTests({ definedTags: ["all", "critical"] }, () => { filterTests({ definedTags: ["all", "critical", "refactored"] }, () => {
const name = "ProductsWithoutSkuInOrder"; const name = `ProductsWithoutSkuInOrder${faker.datatype.number()}`;
describe("Add productWithout SKU to order", () => { describe("As an admin I should be able to create order with variant without SKU", () => {
before(() => { it("should create order with variant product without sku. SALEOR_2801", () => {
cy.clearSessionData().loginUserViaRequest();
deleteProductsStartsWith(name);
deleteShippingStartsWith(name);
deleteCustomersStartsWith(name);
});
it("should create order with variant product without sku", () => {
let variants; let variants;
let channel; let channel;
let shippingMethodId; let shippingMethodId;

View file

@ -22,7 +22,7 @@ const graphql = require("graphql-request");
module.exports = async (on, config) => { module.exports = async (on, config) => {
// make env variables visible for cypress // make env variables visible for cypress
require("cypress-mochawesome-reporter/plugin")(on); // require("cypress-mochawesome-reporter/plugin")(on); - uncomment to run reports
config.env.API_URI = process.env.API_URI; config.env.API_URI = process.env.API_URI;
config.env.APP_MOUNT_URI = process.env.APP_MOUNT_URI; config.env.APP_MOUNT_URI = process.env.APP_MOUNT_URI;
config.env.mailHogUrl = process.env.CYPRESS_MAILHOG; config.env.mailHogUrl = process.env.CYPRESS_MAILHOG;

View file

@ -148,7 +148,7 @@ export function createVariant({
productId, productId,
sku, sku,
warehouseId, warehouseId,
quantityInWarehouse, quantityInWarehouse = 1,
channelId, channelId,
attributeId, attributeId,
price = 1, price = 1,

View file

@ -12,9 +12,11 @@ import {
setProductTypeAsDigital setProductTypeAsDigital
} from "../../requests/ProductType"; } from "../../requests/ProductType";
import { deleteAttributesStartsWith } from "../attributes/attributeUtils"; import { deleteAttributesStartsWith } from "../attributes/attributeUtils";
import { deleteCollectionsStartsWith } from "../catalog/collectionsUtils";
import { getDefaultChannel } from "../channelsUtils"; import { getDefaultChannel } from "../channelsUtils";
import { createShipping, deleteShippingStartsWith } from "../shippingUtils"; import {
createShipping,
createShippingWithDefaultChannelAndAddress
} from "../shippingUtils";
export function createProductInChannel({ export function createProductInChannel({
name, name,
@ -116,7 +118,7 @@ export function deleteProductsStartsWith(startsWith) {
); );
} }
export function deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({ export function createNewProductWithNewDataAndDefaultChannel({
name, name,
description = name, description = name,
warehouseId, warehouseId,
@ -128,9 +130,9 @@ export function deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({
let defaultChannel; let defaultChannel;
let collection; let collection;
let attribute; let attribute;
let category;
let productType;
deleteProductsStartsWith(name);
deleteCollectionsStartsWith(name);
return getDefaultChannel() return getDefaultChannel()
.then(channel => { .then(channel => {
defaultChannel = channel; defaultChannel = channel;
@ -140,23 +142,37 @@ export function deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({
collection = collectionResp; collection = collectionResp;
createTypeAttributeAndCategoryForProduct({ name, attributeValues }); createTypeAttributeAndCategoryForProduct({ name, attributeValues });
}) })
.then(({ attribute: attributeResp, category, productType }) => { .then(
attribute = attributeResp; ({
createProductInChannel({ attribute: attributeResp,
attributeId: attribute.id, category: categoryResp,
categoryId: category.id, productType: productTypeResp
productTypeId: productType.id, }) => {
channelId: defaultChannel.id, attribute = attributeResp;
name, category = categoryResp;
collectionId: collection.id, productType = productTypeResp;
description, createProductInChannel({
warehouseId, attributeId: attribute.id,
price: productPrice, categoryId: category.id,
preorder, productTypeId: productType.id,
sku channelId: defaultChannel.id,
}); name,
}) collectionId: collection.id,
.then(({ product, variantsList }) => ({ product, variantsList })); description,
warehouseId,
price: productPrice,
preorder,
sku
});
}
)
.then(({ product, variantsList }) => ({
product,
variantsList,
attribute,
category,
productType
}));
} }
export function createProductWithShipping({ export function createProductWithShipping({
@ -173,7 +189,6 @@ export function createProductWithShipping({
let defaultChannel; let defaultChannel;
let shippingZone; let shippingZone;
deleteShippingStartsWith(name);
return cy return cy
.fixture("addresses") .fixture("addresses")
.then(addresses => { .then(addresses => {
@ -198,7 +213,7 @@ export function createProductWithShipping({
warehouse = warehouseResp; warehouse = warehouseResp;
shippingMethod = shippingMethodResp; shippingMethod = shippingMethodResp;
shippingZone = shippingZoneResp; shippingZone = shippingZoneResp;
deleteProductsAndCreateNewOneWithNewDataAndDefaultChannel({ createNewProductWithNewDataAndDefaultChannel({
name, name,
warehouseId: warehouse.id, warehouseId: warehouse.id,
productPrice, productPrice,
@ -208,14 +223,17 @@ export function createProductWithShipping({
}); });
} }
) )
.then(({ variantsList, product }) => ({ .then(({ variantsList, product, attribute, category, productType }) => ({
variantsList, variantsList,
product, product,
warehouse, warehouse,
shippingZone, shippingZone,
defaultChannel, defaultChannel,
shippingMethod, shippingMethod,
address address,
attribute,
category,
productType
})); }));
} }
@ -264,3 +282,166 @@ export function addDigitalContentAndUpdateProductType(
setProductTypeAsDigital(productTypeId); setProductTypeAsDigital(productTypeId);
productRequest.updateVariantPrice({ variantId, channelId, price }); productRequest.updateVariantPrice({ variantId, channelId, price });
} }
export function createDigitalAndPhysicalProductWithNewDataAndDefaultChannel({
physicalProductName,
digitalProductName
}) {
let physicalVariants;
let digitalVariants;
let warehouse;
let attribute;
let shippingMethod;
let defaultChannel;
let address;
let category;
let digitalProductType;
return createProductWithShipping({
name: physicalProductName,
attributeValues: ["physical"]
})
.then(resp => {
physicalVariants = resp.variantsList;
warehouse = resp.warehouse;
shippingMethod = resp.shippingMethod;
attribute = resp.attribute;
defaultChannel = resp.defaultChannel;
address = resp.address;
category = resp.category;
createTypeProduct({
name: digitalProductName,
shippable: false,
attributeId: attribute.id
});
})
.then(productType => {
digitalProductType = productType;
createProductInChannel({
attributeId: attribute.id,
productTypeId: productType.id,
categoryId: category.id,
channelId: defaultChannel.id,
name: digitalProductName,
warehouseId: warehouse.id
});
})
.then(({ variantsList }) => {
digitalVariants = variantsList;
addDigitalContentAndUpdateProductType(
digitalVariants[0].id,
digitalProductType.id,
defaultChannel.id
);
})
.then(() => ({
digitalVariants,
physicalVariants,
shippingMethod,
defaultChannel,
address
}));
}
export function createNewProductWithSeveralVariants(name, variantsData) {
let address;
let defaultChannel;
let warehouse;
let shippingMethod;
const createdVariants = [];
let attribute;
let productType;
let category;
return cy
.fixture("addresses")
.then(addresses => {
address = addresses.usAddress;
getDefaultChannel();
})
.then(channel => {
defaultChannel = channel;
createShipping({
channelId: defaultChannel.id,
name,
address
});
})
.then(
({ warehouse: warehouseResp, shippingMethod: shippingMethodResp }) => {
warehouse = warehouseResp;
shippingMethod = shippingMethodResp;
const attributeValues = [];
variantsData.forEach(variant => {
attributeValues.push(variant.name);
});
createTypeAttributeAndCategoryForProduct({
name,
attributeValues
});
}
)
.then(
({
attribute: attributeResp,
category: categoryResp,
productType: productTypeResp
}) => {
attribute = attributeResp;
category = categoryResp;
productType = productTypeResp;
createProductInChannelWithoutVariants({
attributeId: attribute.id,
categoryId: category.id,
productTypeId: productType.id,
channelId: defaultChannel.id,
name
});
}
)
.then(product => {
variantsData.forEach(variant => {
productRequest
.createVariant({
productId: product.id,
attributeId: attribute.id,
channelId: defaultChannel.id,
attributeName: variant.name,
trackInventory: variant.trackInventory,
warehouseId: warehouse.id,
quantityInWarehouse: variant.quantityInWarehouse
})
.then(variants => {
createdVariants.push(variants[0]);
});
});
})
.then(() => ({ createdVariants, address, shippingMethod, defaultChannel }));
}
export function createShippingProductTypeAttributeAndCategory(
name,
attributeValues
) {
let warehouse;
let defaultChannel;
return createShippingWithDefaultChannelAndAddress(name)
.then(({ warehouse: warehouseResp, defaultChannel: channel }) => {
warehouse = warehouseResp;
defaultChannel = channel;
createTypeAttributeAndCategoryForProduct({ name, attributeValues });
})
.then(({ attribute, productType, category }) => ({
attribute,
productType,
category,
warehouse,
defaultChannel
}));
}

View file

@ -1,5 +1,6 @@
import * as shippingMethodRequest from "../requests/ShippingMethod"; import * as shippingMethodRequest from "../requests/ShippingMethod";
import * as warehouseRequest from "../requests/Warehouse"; import * as warehouseRequest from "../requests/Warehouse";
import { getDefaultChannel } from "./channelsUtils";
export function createShipping({ export function createShipping({
channelId, channelId,
@ -40,6 +41,30 @@ export function createShipping({
}) })
.then(() => ({ shippingMethod, shippingZone, warehouse })); .then(() => ({ shippingMethod, shippingZone, warehouse }));
} }
export function createShippingWithDefaultChannelAndAddress(name) {
let defaultChannel;
return getDefaultChannel()
.then(channel => {
defaultChannel = channel;
cy.fixture("addresses");
})
.then(fixtureAddresses =>
createShipping({
channelId: defaultChannel.id,
name,
address: fixtureAddresses.plAddress
})
)
.then(({ shippingMethod, shippingZone, warehouse }) => ({
shippingMethod,
shippingZone,
warehouse,
defaultChannel
}));
}
export function createShippingRate({ name, shippingZoneId }) { export function createShippingRate({ name, shippingZoneId }) {
return shippingMethodRequest return shippingMethodRequest
.createShippingRate({ name, shippingZone: shippingZoneId }) .createShippingRate({ name, shippingZone: shippingZoneId })

View file

@ -21,20 +21,8 @@ commandTimings();
import { urlList } from "../fixtures/urlList"; import { urlList } from "../fixtures/urlList";
Cypress.Commands.add("clearSessionData", () => { Cypress.Commands.add("clearSessionData", () => {
// Because of known cypress bug, not all local storage data are cleared.
// Here is workaround to ensure tests have no side effects.
// Suggested usage:
// beforeEach(() => {
// cy.clearSessionData();
// });
cy.clearCookies(); cy.clearCookies();
cy.clearLocalStorage(); cy.clearLocalStorage();
cy.visit(urlList.homePage, {
onBeforeLoad: win => {
win.sessionStorage.clear();
}
});
}); });
Cypress.Commands.add("addAliasToGraphRequest", operationName => { Cypress.Commands.add("addAliasToGraphRequest", operationName => {

View file

@ -18,3 +18,61 @@ export function expectWelcomeMessageIncludes(name) {
expect(text, `welcome message should contains ${name}`).to.contains(name); expect(text, `welcome message should contains ${name}`).to.contains(name);
}); });
} }
export function getOrdersReadyToFulfillRegex(
ordersReadyToFulfillBefore,
quantityOfNewOrders
) {
const allOrdersReadyToFulfill =
ordersReadyToFulfillBefore + quantityOfNewOrders;
const notANumberRegex = "\\D*";
return new RegExp(
`${notANumberRegex}${allOrdersReadyToFulfill}${notANumberRegex}`
);
}
export function getOrdersReadyForCaptureRegex(
ordersReadyForCaptureBefore,
quantityOfNewOrders
) {
const allOrdersReadyForCapture =
ordersReadyForCaptureBefore + quantityOfNewOrders;
const notANumberRegex = "\\D*";
return new RegExp(
`${notANumberRegex}${allOrdersReadyForCapture}${notANumberRegex}`
);
}
export function getProductsOutOfStockRegex(
productsOutOfStockBefore,
quantityOfNewProducts
) {
const allProductsOutOfStock =
productsOutOfStockBefore + quantityOfNewProducts;
const notANumberRegex = "\\D*";
return new RegExp(
`${notANumberRegex}${allProductsOutOfStock}${notANumberRegex}`
);
}
export function getSalesAmountRegex(salesAmountBefore, addedAmount) {
const totalAmount = salesAmountBefore + addedAmount;
const totalAmountString = totalAmount.toFixed(2);
const totalAmountIntegerValue = totalAmountString.split(".")[0];
const totalAmountDecimalValue = totalAmountString.split(".")[1];
const decimalSeparator = "[,.]";
const totalAmountIntegerWithThousandsSeparator = new Intl.NumberFormat("en")
.format(totalAmountIntegerValue)
.replaceAll(",", "[,.]*");
const totalAmountWithSeparators = `${totalAmountIntegerWithThousandsSeparator}${decimalSeparator}${totalAmountDecimalValue}`;
const notANumberRegex = "\\D*";
return new RegExp(
`${notANumberRegex}${totalAmountWithSeparators}${notANumberRegex}`
);
}
export function getTodaysOrdersRegex(ordersBefore, quantityOfNewOrders) {
const allOrders = ordersBefore + quantityOfNewOrders;
const notANumberRegex = "\\D*";
return new RegExp(`${notANumberRegex}${allOrders}${notANumberRegex}`);
}

View file

@ -272,7 +272,9 @@
"cy:run:dashboard": "cypress run --record --key 1fe833f5-fca4-4454-ac55-943815b91c6c", "cy:run:dashboard": "cypress run --record --key 1fe833f5-fca4-4454-ac55-943815b91c6c",
"cy:run:record": "npm run cy:run -- --record", "cy:run:record": "npm run cy:run -- --record",
"cy:open": "cypress open", "cy:open": "cypress open",
"cy:run:critical": "cypress run --env tags=critical --spec 'cypress/integration/navigation.js','cypress/integration/products/*.js','cypress/integration/checkout/*.js' --record --key 1fe833f5-fca4-4454-ac55-943815b91c6c", "cy:run:critical:locally": "cypress run --env tags=critical --spec 'cypress/integration/navigation.js','cypress/integration/products/createProduct.js', 'cypress/integration/products/productsVariants.js','cypress/integration/checkout/purchaseWithProductTypes.js','cypress/integration/checkout/stocksInCheckout.js' --reporter cypress-mochawesome-reporter --reporter-options reportDir='cypress/reports',overwrite=true,charts=true",
"cy:run:refactored:locally": "cypress run --env tags=refactored --spec 'cypress/integration/navigation.js','cypress/integration/products/createProduct.js', 'cypress/integration/products/productsVariants.js','cypress/integration/checkout/purchaseWithProductTypes.js','cypress/integration/checkout/stocksInCheckout.js' --reporter cypress-mochawesome-reporter --reporter-options reportDir='cypress/reports',overwrite=true,charts=true",
"cy:run:critical": "cypress run --env tags=critical --spec 'cypress/integration/navigation.js','cypress/integration/products/*.js','cypress/integration/checkout/*.js'",
"cy:run:allEnv": "cypress run --env tags=all --record --key 1fe833f5-fca4-4454-ac55-943815b91c6c", "cy:run:allEnv": "cypress run --env tags=all --record --key 1fe833f5-fca4-4454-ac55-943815b91c6c",
"test:e2e:run": "start-server-and-test start http://localhost:9000 cy:run", "test:e2e:run": "start-server-and-test start http://localhost:9000 cy:run",
"test:e2e:run:record": "start-server-and-test start http://localhost:9000 cy:run:record", "test:e2e:run:record": "start-server-and-test start http://localhost:9000 cy:run:record",