diff --git a/cypress/apiRequests/Attribute.js b/cypress/apiRequests/Attribute.js
index f1c180d01..b0f23be23 100644
--- a/cypress/apiRequests/Attribute.js
+++ b/cypress/apiRequests/Attribute.js
@@ -1,20 +1,20 @@
class Attribute {
createAttribute(name) {
const mutation = `mutation{
- attributeCreate(input:{
- name:"${name}"
- valueRequired:false
- type:PRODUCT_TYPE
- }){
- attribute{
- id
+ attributeCreate(input:{
+ name:"${name}"
+ valueRequired:false
+ type:PRODUCT_TYPE
+ }){
+ attribute{
+ id
+ }
+ attributeErrors{
+ field
+ message
+ }
}
- attributeErrors{
- field
- message
- }
- }
- }`;
+ }`;
return cy.sendRequestWithQuery(mutation);
}
diff --git a/cypress/apiRequests/Collections.js b/cypress/apiRequests/Collections.js
new file mode 100644
index 000000000..8a9e1aa87
--- /dev/null
+++ b/cypress/apiRequests/Collections.js
@@ -0,0 +1,37 @@
+class Collections {
+ getCollections(search) {
+ const filter = search
+ ? `, filter:{
+ search:""
+ }`
+ : "";
+ const query = `query{
+ collections(first:100 ${filter}){
+ edges{
+ node{
+ id
+ name
+ }
+ }
+ }
+ }`;
+ return cy
+ .sendRequestWithQuery(query)
+ .then(resp => resp.body.data.collections.edges);
+ }
+ deleteCollection(collectionId) {
+ const mutation = `mutation{
+ collectionDelete(id:"${collectionId}"){
+ collection{
+ id
+ }
+ collectionErrors{
+ field
+ message
+ }
+ }
+ }`;
+ return cy.sendRequestWithQuery(mutation);
+ }
+}
+export default Collections;
diff --git a/cypress/apiRequests/Product.js b/cypress/apiRequests/Product.js
index b22ecf97b..8aa6b0ce8 100644
--- a/cypress/apiRequests/Product.js
+++ b/cypress/apiRequests/Product.js
@@ -1,4 +1,7 @@
+import Utils from "./utils/Utils";
+
class Product {
+ utils = new Utils();
getFirstProducts(first, search) {
const filter = search
? `, filter:{
@@ -17,44 +20,50 @@ class Product {
}
}
}
- }
- `;
+ `;
return cy
.sendRequestWithQuery(query)
.then(resp => resp.body.data.products.edges);
}
- updateChannelInProduct(productId, channelId) {
+ updateChannelInProduct({
+ productId,
+ channelId,
+ isPublished = true,
+ isAvailableForPurchase = true,
+ visibleInListings = true
+ }) {
const mutation = `mutation{
- productChannelListingUpdate(id:"${productId}",
- input:{
- addChannels:{
- channelId:"${channelId}"
- isPublished:true
- isAvailableForPurchase:true
+ productChannelListingUpdate(id:"${productId}",
+ input:{
+ addChannels:{
+ channelId:"${channelId}"
+ isPublished:${isPublished}
+ isAvailableForPurchase:${isAvailableForPurchase}
+ visibleInListings:${visibleInListings}
+ }
+ }){
+ product{
+ id
+ name
+ }
}
- }){
- product{
- id
- name
- }
- }
- }`;
- return cy.sendRequestWithQuery(mutation);
+ }`;
+ cy.sendRequestWithQuery(mutation);
}
updateChannelPriceInVariant(variantId, channelId) {
const mutation = `mutation{
- productVariantChannelListingUpdate(id: "${variantId}", input:{
- channelId: "${channelId}"
- price: 10
- costPrice: 10
- }){
- productChannelListingErrors{
- message
- }
- }
- }`;
+ productVariantChannelListingUpdate(id: "${variantId}", input: {
+ channelId: "${channelId}"
+ price: 10
+ costPrice: 10
+ }){
+ productChannelListingErrors{
+ message
+ }
+ }
+} `;
return cy.sendRequestWithQuery(mutation);
}
createProduct(attributeId, name, productType, category) {
@@ -88,27 +97,30 @@ class Product {
price = 1,
costPrice = 1
) {
- const channelListings = channelId
- ? `channelListings:{
+ const channelListings = this.utils.getValueWithDefault(
+ channelId,
+ `channelListings:{
channelId:"${channelId}"
price:"${price}"
costPrice:"${costPrice}"
}`
- : "";
- const stocks = warehouseId
- ? `stocks:{
+ );
+
+ const stocks = this.utils.getValueWithDefault(
+ warehouseId,
+ `stocks:{
warehouse:"${warehouseId}"
quantity:${quantity}
}`
- : "";
+ );
const mutation = `mutation{
- productVariantBulkCreate(product:"${productId}", variants:{
- attributes:[]
- sku:"${sku}"
+ productVariantBulkCreate(product: "${productId}", variants: {
+ attributes: []
+ sku: "${sku}"
${channelListings}
${stocks}
- }){
+ }) {
productVariants{
id
name
@@ -124,33 +136,33 @@ class Product {
createTypeProduct(name, attributeId, slug = name) {
const mutation = `mutation{
- productTypeCreate(input:{
- name:"${name}"
+ productTypeCreate(input: {
+ name: "${name}"
slug: "${slug}"
- isShippingRequired:true
- productAttributes:"${attributeId}"
- }){
- productErrors{
- field
- message
- }
- productType{
- id
- }
- }
- }`;
+ isShippingRequired: true
+ productAttributes: "${attributeId}"
+ }){
+ productErrors{
+ field
+ message
+ }
+ productType{
+ id
+ }
+ }
+} `;
return cy.sendRequestWithQuery(mutation);
}
deleteProduct(productId) {
const mutation = `mutation{
- productDelete(id:"${productId}"){
- productErrors{
- field
- message
- }
- }
- }`;
+ productDelete(id: "${productId}"){
+ productErrors{
+ field
+ message
+ }
+ }
+} `;
return cy.sendRequestWithQuery(mutation);
}
diff --git a/cypress/apiRequests/frontShop/Collections.js b/cypress/apiRequests/frontShop/Collections.js
deleted file mode 100644
index 2ff9e4fe2..000000000
--- a/cypress/apiRequests/frontShop/Collections.js
+++ /dev/null
@@ -1,52 +0,0 @@
-class Collections {
- getCollection(collectionId, channelSlug) {
- const operationName = "Collection";
- const variables = {
- attributes: {},
- priceGte: null,
- priceLte: null,
- sortBy: null,
- channel: channelSlug,
- id: collectionId,
- pageSize: 6
- };
- const query =
- "query Collection($id: ID!, $channel: String!) {\n collection(id: $id, channel: $channel) {\n id\n slug\n name\n seoDescription\n seoTitle\n backgroundImage {\n url\n __typename\n }\n __typename\n }\n attributes(filter: {channel: $channel, inCollection: $id, filterableInStorefront: true}, first: 100) {\n edges {\n node {\n id\n name\n slug\n values {\n id\n name\n slug\n __typename\n }\n __typename\n }\n __typename\n }\n __typename\n }\n}\n";
- return cy.sendFrontShopRequest(operationName, query, variables);
- }
- getCollections(search) {
- const filter = search
- ? `, filter:{
- search:""
- }`
- : "";
- const query = `query{
- collections(first:100 ${filter}){
- edges{
- node{
- id
- name
- }
- }
- }
- }`;
- return cy
- .sendRequestWithQuery(query)
- .then(resp => resp.body.data.collections.edges);
- }
- deleteCollection(collectionId) {
- const mutation = `mutation{
- collectionDelete(id:"${collectionId}"){
- collection{
- id
- }
- collectionErrors{
- field
- message
- }
- }
- }`;
- return cy.sendRequestWithQuery(mutation);
- }
-}
-export default Collections;
diff --git a/cypress/apiRequests/storeFront/Collections.js b/cypress/apiRequests/storeFront/Collections.js
new file mode 100644
index 000000000..0b50dbf54
--- /dev/null
+++ b/cypress/apiRequests/storeFront/Collections.js
@@ -0,0 +1,21 @@
+class Collections {
+ getCollection(collectionId, channelSlug) {
+ const query = `query Collection{
+ collection(id: "${collectionId}", channel: "${channelSlug}") {
+ id
+ slug
+ name
+ products(first:100){
+ edges{
+ node{
+ id
+ name
+ }
+ }
+ }
+ }
+ }`;
+ return cy.sendFrontShopRequestWithQuery(query);
+ }
+}
+export default Collections;
diff --git a/cypress/apiRequests/storeFront/ProductDetails.js b/cypress/apiRequests/storeFront/ProductDetails.js
new file mode 100644
index 000000000..9ad18c5fc
--- /dev/null
+++ b/cypress/apiRequests/storeFront/ProductDetails.js
@@ -0,0 +1,18 @@
+class ProductDetails {
+ getProductDetails(productId, channelId) {
+ const query = `fragment BasicProductFields on Product {
+ id
+ name
+ }
+ query ProductDetails{
+ product(id: "${productId}", channel: "${channelId}") {
+ ...BasicProductFields
+ isAvailable
+ isAvailableForPurchase
+ availableForPurchase
+ }
+ }`;
+ return cy.sendFrontShopRequestWithQuery(query);
+ }
+}
+export default ProductDetails;
diff --git a/cypress/apiRequests/storeFront/Search.js b/cypress/apiRequests/storeFront/Search.js
new file mode 100644
index 000000000..107be2560
--- /dev/null
+++ b/cypress/apiRequests/storeFront/Search.js
@@ -0,0 +1,20 @@
+class Search {
+ searchInShop(searchQuery) {
+ const query = `query SearchProducts {
+ products(channel: "default-channel", filter:{
+ search: "${searchQuery}"
+ }, first:10){
+ totalCount
+ edges{
+ node{
+ id
+ name
+ }
+ }
+ }
+ }`;
+
+ return cy.sendFrontShopRequestWithQuery(query);
+ }
+}
+export default Search;
diff --git a/cypress/apiRequests/utils/Utils.js b/cypress/apiRequests/utils/Utils.js
new file mode 100644
index 000000000..cbb37b751
--- /dev/null
+++ b/cypress/apiRequests/utils/Utils.js
@@ -0,0 +1,6 @@
+class Utils {
+ getValueWithDefault(condition, value, defaultValue = "") {
+ return condition ? value : defaultValue;
+ }
+}
+export default Utils;
diff --git a/cypress/elements/catalog/products/product-selectors.js b/cypress/elements/catalog/products/product-selectors.js
index e2ef305c0..2fd93e118 100644
--- a/cypress/elements/catalog/products/product-selectors.js
+++ b/cypress/elements/catalog/products/product-selectors.js
@@ -13,9 +13,20 @@ export const PRODUCTS_SELECTORS = {
saveBtn: "[data-test='button-bar-confirm']",
confirmationMsg: "[data-test='notification-success']",
channelAvailabilityItem: "[data-test='channel-availability-item']",
+ searchProducts: "[placeholder='Search Products...']",
availableManageButton:
"[data-test-id='channels-availiability-manage-button']",
channelsAvailabilityForm:
"[data-test-id='manage-products-channels-availiability-list']",
+ channelAvailabilityColumn:
+ "[data-test='availability'][data-test-availability='true']",
+ channelAvailabilityList: "ul[role='menu']",
+ goBackButton: "[data-test-id='app-header-back-button']",
+ assignedChannels: "[data-test='channel-availability-item']",
+ publishedRadioButtons: "[name*='isPublished']",
+ availableForPurchaseRadioButtons: "[name*='isAvailableForPurchase']",
+ radioButtonsValueTrue: "[value='true']",
+ radioButtonsValueFalse: "[value='false']",
+ visibleInListingsButton: "[name*='visibleInListings']",
emptyProductRow: "[class*='Skeleton']"
};
diff --git a/cypress/integration/channels.js b/cypress/integration/channels.js
index 3176552ea..91999d5e7 100644
--- a/cypress/integration/channels.js
+++ b/cypress/integration/channels.js
@@ -44,10 +44,10 @@ describe("Channels", () => {
it("should create new channel", () => {
const randomChannel = `${channelStartsWith} ${faker.random.number()}`;
- cy.waitForGraph("Channels");
+ cy.addAliasToGraphRequest("Channels");
cy.visit(urlList.channels);
- cy.wait("Channels");
- cy.waitForGraph("Channel");
+ cy.wait("@Channels");
+ cy.addAliasToGraphRequest("Channel");
channelsSteps.createChannelByView(randomChannel, currency);
// New channel should be visible in channels list
cy.wait("@Channel")
@@ -65,7 +65,9 @@ describe("Channels", () => {
.click();
// new channel should be visible at product availability form
- cy.visit(urlList.products).waitForGraph("InitialProductFilterData");
+ cy.addAliasToGraphRequest("InitialProductFilterData");
+ cy.visit(urlList.products);
+ cy.wait("@InitialProductFilterData");
cy.get(PRODUCTS_SELECTORS.productsList)
.first()
.click()
@@ -106,15 +108,18 @@ describe("Channels", () => {
randomChannelToDelete,
currency
);
- cy.visit(urlList.channels).waitForGraph("Channels");
+ cy.addAliasToGraphRequest("Channels");
+ cy.visit(urlList.channels);
+ cy.wait("@Channels");
cy.get(CHANNELS_SELECTORS.channelName)
.contains(randomChannelToDelete)
.parentsUntil(CHANNELS_SELECTORS.channelsTable)
.find("button")
- .click()
- .get(BUTTON_SELECTORS.submit)
- .click()
- .waitForGraph("Channels");
+ .click();
+ cy.addAliasToGraphRequest("Channels");
+ cy.get(BUTTON_SELECTORS.submit).click();
+ cy.wait("@Channels");
+
cy.get(CHANNELS_SELECTORS.channelName)
.contains(randomChannelToDelete)
.should("not.exist");
diff --git a/cypress/integration/collections.js b/cypress/integration/collections.js
index 0ce8c3ec2..0e32fb2cc 100644
--- a/cypress/integration/collections.js
+++ b/cypress/integration/collections.js
@@ -8,18 +8,26 @@ import ChannelsUtils from "../utils/channelsUtils";
import CollectionsUtils from "../utils/collectionsUtils";
import ProductsUtils from "../utils/productsUtils";
import ShippingUtils from "../utils/shippingUtils";
+import StoreFrontCollectionUtils from "../utils/storeFront/collectionsUtils";
+import StoreFrontProductUtils from "../utils/storeFront/storeFrontProductUtils";
describe("Collections", () => {
const productRequest = new Product();
const channelsUtils = new ChannelsUtils();
const productsUtils = new ProductsUtils();
+ const storeFrontProductUtils = new StoreFrontProductUtils();
const collectionsUtils = new CollectionsUtils();
+ const storeFrontCollectionUtils = new StoreFrontCollectionUtils();
const shippingUtils = new ShippingUtils();
const collectionsSteps = new CollectionsSteps();
const startsWith = "Cy-";
const name = `${startsWith}${faker.random.number()}`;
+ let attribute;
+ let productType;
+ let category;
+
let defaultChannel;
before(() => {
@@ -35,19 +43,16 @@ describe("Collections", () => {
productsUtils.createTypeAttributeAndCategoryForProduct(name);
})
.then(() => {
- const attribute = productsUtils.getAttribute();
- const productType = productsUtils.getProductType();
- const category = productsUtils.getCategory();
- productsUtils.createProductInChannel(
+ attribute = productsUtils.getAttribute();
+ productType = productsUtils.getProductType();
+ category = productsUtils.getCategory();
+ productsUtils.createProductInChannel({
name,
- defaultChannel.id,
- null,
- null,
- productType.id,
- attribute.id,
- category.id,
- 1
- );
+ channelId: defaultChannel.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id
+ });
});
});
@@ -63,7 +68,7 @@ describe("Collections", () => {
.createCollection(collectionName, false, defaultChannel)
.then(collection => {
collectionsSteps.assignProductsToCollection(name);
- collectionsUtils.isCollectionVisible(
+ storeFrontCollectionUtils.isCollectionVisible(
collection.id,
defaultChannel.slug
);
@@ -79,55 +84,71 @@ describe("Collections", () => {
.createCollection(collectionName, true, defaultChannel)
.then(collection => {
collectionsSteps.assignProductsToCollection(name);
- collectionsUtils.isCollectionVisible(
+ storeFrontCollectionUtils.isCollectionVisible(
collection.id,
defaultChannel.slug
);
})
.then(isVisible => expect(isVisible).to.equal(true));
});
- xit("should not display unavailable in channel collections", () => {
- channelsUtils.createChannel(true, name, name, "PLN").then(() => {
- productRequest.updateChannelInProduct(
- productsUtils.getCreatedProduct().id,
- channelsUtils.getCreatedChannel().id
- );
+ it("should not display unavailable in channel collections", () => {
+ const collectionName = `${startsWith}${faker.random.number()}`;
+ channelsUtils
+ .createChannel({ name: collectionName })
+ .then(() => {
+ productRequest.updateChannelInProduct(
+ productsUtils.getCreatedProduct().id,
+ channelsUtils.getCreatedChannel().id
+ );
+ })
+ .then(() => {
+ cy.visit(urlList.collections);
+ collectionsSteps.createCollection(
+ collectionName,
+ true,
+ channelsUtils.getCreatedChannel()
+ );
+ })
+ .then(collection => {
+ collectionsSteps.assignProductsToCollection(name);
+ storeFrontCollectionUtils.isCollectionVisible(
+ collection.id,
+ defaultChannel.slug
+ );
+ })
+ .then(isVisible => expect(isVisible).to.equal(false));
+ });
+ it("should display products hidden in listing, only in collection", () => {
+ const randomName = `${startsWith}${faker.random.number()}`;
+ const hiddenProductUtils = new ProductsUtils();
+ hiddenProductUtils.createProductInChannel({
+ name: randomName,
+ channelId: defaultChannel.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id,
+ visibleInListings: false
});
cy.visit(urlList.collections);
collectionsSteps
- .createCollection(collectionName, true, channelsUtils.getCreatedChannel())
+ .createCollection(randomName, true, defaultChannel)
.then(collection => {
- collectionsSteps.assignProductsToCollection(name);
- collectionsUtils.isCollectionVisible(
+ collectionsSteps.assignProductsToCollection(randomName);
+ storeFrontCollectionUtils.isProductInCollectionVisible(
collection.id,
- defaultChannel.slug
- );
- })
- .then(isVisible => expect(isVisible).to.equal(true));
- });
- xit("should display products hidden in listing, only in collection", () => {
- productsUtils.createProductInChannel(
- name,
- defaultChannel.id,
- null,
- null,
- productsUtils.getProductType().id,
- productsUtils.getAttribute().id,
- productsUtils.getCategory().id,
- 1
- );
- collectionsSteps
- .createCollection(collectionName, true, defaultChannel)
- .then(collection => {
- collectionsSteps.assignProductsToCollection(name);
- collectionsUtils.isProductInCollectionVisible(
- collection.id,
- defaultChannel.slug
+ defaultChannel.slug,
+ hiddenProductUtils.getCreatedProduct().id
);
})
.then(isVisible => {
expect(isVisible).to.equal(true);
- // productsUtils.searchForProduct
+ storeFrontProductUtils.isProductVisibleInSearchResult(
+ hiddenProductUtils.getCreatedProduct().name,
+ defaultChannel.slug
+ );
+ })
+ .then(isVisible => {
+ expect(isVisible).to.equal(false);
});
});
});
diff --git a/cypress/integration/homePage.js b/cypress/integration/homePage.js
index 74e8762a1..3712afd56 100644
--- a/cypress/integration/homePage.js
+++ b/cypress/integration/homePage.js
@@ -11,7 +11,7 @@ import ProductsUtils from "../utils/productsUtils";
import ShippingUtils from "../utils/shippingUtils";
//
-describe("User authorization", () => {
+describe("Homepage analytics", () => {
const startsWith = "Cy-";
const customer = new Customer();
@@ -48,12 +48,12 @@ describe("User authorization", () => {
)
.then(resp => {
customerId = resp.body.data.customerCreate.user.id;
- shippingUtils.createShipping(
- defaultChannel.id,
- randomName,
- addresses.plAddress,
- shippingPrice
- );
+ shippingUtils.createShipping({
+ channelId: defaultChannel.id,
+ name: randomName,
+ address: addresses.plAddress,
+ price: shippingPrice
+ });
})
.then(() => {
productsUtils.createTypeAttributeAndCategoryForProduct(randomName);
@@ -63,16 +63,16 @@ describe("User authorization", () => {
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
- );
+ productsUtils.createProductInChannel({
+ name: randomName,
+ channelId: defaultChannel.id,
+ warehouseId: warehouse.id,
+ quantityInWarehouse: 20,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id,
+ price: productPrice
+ });
});
});
@@ -154,16 +154,16 @@ describe("User authorization", () => {
const attribute = productsUtils.getAttribute();
const category = productsUtils.getCategory();
- productsOutOfStockUtils.createProductInChannel(
- productOutOfStockRandomName,
- defaultChannel.id,
- warehouse.id,
- 0,
- productType.id,
- attribute.id,
- category.id,
- productPrice
- );
+ productsOutOfStockUtils.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;
diff --git a/cypress/integration/products/menageProducts/availableForPurchaseProducts.js b/cypress/integration/products/menageProducts/availableForPurchaseProducts.js
new file mode 100644
index 000000000..9c4a3c468
--- /dev/null
+++ b/cypress/integration/products/menageProducts/availableForPurchaseProducts.js
@@ -0,0 +1,115 @@
+import faker from "faker";
+
+import ProductSteps from "../../../steps/productSteps";
+import { productDetailsUrl } from "../../../url/urlList";
+import ChannelsUtils from "../../../utils/channelsUtils";
+import ProductsUtils from "../../../utils/productsUtils";
+import ShippingUtils from "../../../utils/shippingUtils";
+import StoreFrontProductUtils from "../../../utils/storeFront/storeFrontProductUtils";
+
+//
+describe("Products available in listings", () => {
+ const shippingUtils = new ShippingUtils();
+ const channelsUtils = new ChannelsUtils();
+ const productsUtils = new ProductsUtils();
+ const productSteps = new ProductSteps();
+ const frontShopProductUtils = new StoreFrontProductUtils();
+ const startsWith = "Cy-";
+ const name = `${startsWith}${faker.random.number()}`;
+ let productType;
+ let attribute;
+ let category;
+ let defaultChannel;
+ let warehouse;
+
+ before(() => {
+ cy.clearSessionData().loginUserViaRequest();
+ shippingUtils.deleteShipping(startsWith);
+ productsUtils.deleteProperProducts(startsWith);
+
+ channelsUtils
+ .getDefaultChannel()
+ .then(channel => {
+ defaultChannel = channel;
+ cy.fixture("addresses");
+ })
+ .then(addressesFixture => {
+ shippingUtils.createShipping({
+ channelId: defaultChannel.id,
+ name,
+ address: addressesFixture.plAddress
+ });
+ })
+ .then(() => {
+ warehouse = shippingUtils.getWarehouse();
+ });
+
+ productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
+ productType = productsUtils.getProductType();
+ attribute = productsUtils.getAttribute();
+ category = productsUtils.getCategory();
+ });
+ });
+
+ beforeEach(() => {
+ cy.clearSessionData().loginUserViaRequest();
+ });
+
+ it("should update product to available for purchase", () => {
+ const productName = `${startsWith}${faker.random.number()}`;
+ productsUtils
+ .createProductInChannel({
+ name: productName,
+ channelId: defaultChannel.id,
+ warehouseId: warehouse.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id,
+ isAvailableForPurchase: false
+ })
+ .then(() => {
+ const productUrl = productDetailsUrl(
+ productsUtils.getCreatedProduct().id
+ );
+ productSteps.updateProductIsAvailableForPurchase(productUrl, true);
+ })
+ .then(() => {
+ frontShopProductUtils.isProductAvailableForPurchase(
+ productsUtils.getCreatedProduct().id,
+ defaultChannel.slug,
+ productName
+ );
+ })
+ .then(isProductVisible => {
+ expect(isProductVisible).to.be.eq(true);
+ });
+ });
+ it("should update product to not available for purchase", () => {
+ const productName = `${startsWith}${faker.random.number()}`;
+ productsUtils
+ .createProductInChannel({
+ name: productName,
+ channelId: defaultChannel.id,
+ warehouseId: warehouse.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id
+ })
+ .then(() => {
+ const productUrl = productDetailsUrl(
+ productsUtils.getCreatedProduct().id
+ );
+ productSteps.updateProductIsAvailableForPurchase(productUrl, false);
+ })
+ .then(() => {
+ frontShopProductUtils.isProductAvailableForPurchase(
+ productsUtils.getCreatedProduct().id,
+ defaultChannel.slug,
+ productName
+ );
+ })
+ .then(isProductVisible => {
+ expect(isProductVisible).to.be.eq(false);
+ });
+ });
+});
diff --git a/cypress/integration/products/menageProducts/publishedProducts.js b/cypress/integration/products/menageProducts/publishedProducts.js
new file mode 100644
index 000000000..48015293f
--- /dev/null
+++ b/cypress/integration/products/menageProducts/publishedProducts.js
@@ -0,0 +1,108 @@
+import faker from "faker";
+
+import ProductSteps from "../../../steps/productSteps";
+import { productDetailsUrl } from "../../../url/urlList";
+import ChannelsUtils from "../../../utils/channelsUtils";
+import ProductsUtils from "../../../utils/productsUtils";
+import StoreFrontProductUtils from "../../../utils/storeFront/storeFrontProductUtils";
+
+//
+describe("Published products", () => {
+ const channelsUtils = new ChannelsUtils();
+ const productsUtils = new ProductsUtils();
+ const productSteps = new ProductSteps();
+ const frontShopProductUtils = new StoreFrontProductUtils();
+
+ const startsWith = "Cy-";
+ const name = `${startsWith}${faker.random.number()}`;
+ let productType;
+ let attribute;
+ let category;
+
+ before(() => {
+ cy.clearSessionData().loginUserViaRequest();
+ productsUtils.deleteProperProducts(startsWith);
+ productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
+ productType = productsUtils.getProductType();
+ attribute = productsUtils.getAttribute();
+ category = productsUtils.getCategory();
+ });
+ });
+
+ beforeEach(() => {
+ cy.clearSessionData().loginUserViaRequest();
+ });
+ it("should update product to published", () => {
+ const productName = `${startsWith}${faker.random.number()}`;
+ let defaultChannel;
+ channelsUtils
+ .getDefaultChannel()
+ .then(channel => {
+ defaultChannel = channel;
+ productsUtils.createProductInChannel({
+ name: productName,
+ channelId: defaultChannel.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id,
+ isPublished: false,
+ isAvailableForPurchase: false
+ });
+ })
+ .then(() => {
+ const product = productsUtils.getCreatedProduct();
+ const productUrl = productDetailsUrl(product.id);
+ productSteps.updateProductPublish(productUrl, true);
+ frontShopProductUtils.isProductVisible(
+ product.id,
+ defaultChannel.slug,
+ productName
+ );
+ })
+ .then(isVisible => {
+ expect(isVisible).to.be.eq(true);
+ });
+ });
+ it("should update product to not published", () => {
+ const productName = `${startsWith}${faker.random.number()}`;
+ let defaultChannel;
+ let product;
+
+ channelsUtils
+ .getDefaultChannel()
+ .then(channel => {
+ defaultChannel = channel;
+ productsUtils.createProductInChannel({
+ name: productName,
+ channelId: defaultChannel.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id
+ });
+ })
+ .then(() => {
+ product = productsUtils.getCreatedProduct();
+ const productUrl = productDetailsUrl(product.id);
+ productSteps.updateProductPublish(productUrl, false);
+ frontShopProductUtils.isProductVisible(
+ product.id,
+ defaultChannel.slug,
+ productName
+ );
+ })
+ .then(isVisible => {
+ expect(isVisible).to.be.eq(false);
+ cy.loginInShop();
+ })
+ .then(() => {
+ frontShopProductUtils.isProductVisible(
+ product.id,
+ defaultChannel.slug,
+ productName
+ );
+ })
+ .then(isVisible => {
+ expect(isVisible).to.be.eq(true);
+ });
+ });
+});
diff --git a/cypress/integration/products/menageProducts/visibleInListingsProducts.js b/cypress/integration/products/menageProducts/visibleInListingsProducts.js
new file mode 100644
index 000000000..19463c5ce
--- /dev/null
+++ b/cypress/integration/products/menageProducts/visibleInListingsProducts.js
@@ -0,0 +1,102 @@
+import faker from "faker";
+
+import ProductSteps from "../../../steps/productSteps";
+import { productDetailsUrl } from "../../../url/urlList";
+import ChannelsUtils from "../../../utils/channelsUtils";
+import ProductsUtils from "../../../utils/productsUtils";
+import StoreFrontProductUtils from "../../../utils/storeFront/storeFrontProductUtils";
+
+//
+describe("Products displayed in listings", () => {
+ const channelsUtils = new ChannelsUtils();
+ const productsUtils = new ProductsUtils();
+ const productSteps = new ProductSteps();
+ const frontShopProductUtils = new StoreFrontProductUtils();
+
+ const startsWith = "Cy-";
+ const name = `${startsWith}${faker.random.number()}`;
+ let productType;
+ let attribute;
+ let category;
+
+ before(() => {
+ cy.clearSessionData().loginUserViaRequest();
+ productsUtils.deleteProperProducts(startsWith);
+ productsUtils.createTypeAttributeAndCategoryForProduct(name).then(() => {
+ productType = productsUtils.getProductType();
+ attribute = productsUtils.getAttribute();
+ category = productsUtils.getCategory();
+ });
+ });
+
+ beforeEach(() => {
+ cy.clearSessionData().loginUserViaRequest();
+ });
+ it("should update product to visible in listings", () => {
+ const productName = `${startsWith}${faker.random.number()}`;
+ let defaultChannel;
+ channelsUtils
+ .getDefaultChannel()
+ .then(channel => {
+ defaultChannel = channel;
+ productsUtils.createProductInChannel({
+ name: productName,
+ channelId: defaultChannel.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id,
+ visibleInListings: false,
+ isAvailableForPurchase: false
+ });
+ })
+ .then(() => {
+ const product = productsUtils.getCreatedProduct();
+ const productUrl = productDetailsUrl(product.id);
+ productSteps.updateProductVisibleInListings(productUrl);
+ frontShopProductUtils.isProductVisibleInSearchResult(
+ productName,
+ defaultChannel.slug
+ );
+ })
+ .then(isProductVisible => {
+ expect(isProductVisible).to.be.eq(true);
+ });
+ });
+ it("should update product to not visible in listings", () => {
+ const productName = `${startsWith}${faker.random.number()}`;
+ let defaultChannel;
+ channelsUtils
+ .getDefaultChannel()
+ .then(channel => {
+ defaultChannel = channel;
+ productsUtils.createProductInChannel({
+ name: productName,
+ channelId: defaultChannel.id,
+ productTypeId: productType.id,
+ attributeId: attribute.id,
+ categoryId: category.id,
+ visibleInListings: true
+ });
+ })
+ .then(() => {
+ const product = productsUtils.getCreatedProduct();
+ const productUrl = productDetailsUrl(product.id);
+ productSteps.updateProductVisibleInListings(productUrl);
+ frontShopProductUtils
+ .isProductVisibleInSearchResult(productName, defaultChannel.slug)
+ .then(isProductVisible => {
+ expect(isProductVisible).to.be.eq(false);
+ });
+ cy.loginInShop();
+ })
+ .then(() => {
+ frontShopProductUtils.isProductVisibleInSearchResult(
+ productName,
+ defaultChannel.slug
+ );
+ })
+ .then(isProductVisible => {
+ expect(isProductVisible).to.be.eq(true);
+ });
+ });
+});
diff --git a/cypress/integration/products.js b/cypress/integration/products/products.js
similarity index 87%
rename from cypress/integration/products.js
rename to cypress/integration/products/products.js
index f1e8f5468..87960c269 100644
--- a/cypress/integration/products.js
+++ b/cypress/integration/products/products.js
@@ -1,7 +1,7 @@
//
-import { LEFT_MENU_SELECTORS } from "../elements/account/left-menu/left-menu-selectors";
-import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors";
-import { urlList } from "../url/urlList";
+import { LEFT_MENU_SELECTORS } from "../../elements/account/left-menu/left-menu-selectors";
+import { PRODUCTS_SELECTORS } from "../../elements/catalog/product-selectors";
+import { urlList } from "../../url/urlList";
describe("Products", () => {
beforeEach(() => {
diff --git a/cypress/steps/collectionsSteps.js b/cypress/steps/collectionsSteps.js
index 90ef78fa2..a2eb97db8 100644
--- a/cypress/steps/collectionsSteps.js
+++ b/cypress/steps/collectionsSteps.js
@@ -2,13 +2,11 @@ import { COLLECTION_SELECTORS } from "../elements/catalog/collection-selectors";
import { ASSIGN_PRODUCTS_SELECTORS } from "../elements/catalog/products/assign-products-selectors";
import { MENAGE_CHANNEL_AVAILABILITY_FORM } from "../elements/channels/menage-channel-availability-form";
import { BUTTON_SELECTORS } from "../elements/shared/button-selectors";
-import CollectionsUtils from "../utils/collectionsUtils";
class CollectionsSteps {
createCollection(collectionName, isPublished, channel) {
const publishedSelector = isPublished
? MENAGE_CHANNEL_AVAILABILITY_FORM.radioButtonsValueTrue
: MENAGE_CHANNEL_AVAILABILITY_FORM.radioButtonsValueFalse;
- const collectionsUtils = new CollectionsUtils();
cy.get(COLLECTION_SELECTORS.createCollectionButton)
.click()
@@ -28,11 +26,12 @@ class CollectionsSteps {
.get(
`${MENAGE_CHANNEL_AVAILABILITY_FORM.publishedCheckbox}${publishedSelector}`
)
- .click()
- .waitForGraph("CreateCollection")
- .get(COLLECTION_SELECTORS.saveButton)
.click();
- return collectionsUtils.waitForCreateCollectionRequest();
+ cy.addAliasToGraphRequest("CreateCollection");
+ cy.get(COLLECTION_SELECTORS.saveButton).click();
+ return cy
+ .wait("@CreateCollection")
+ .its("response.body.data.collectionCreate.collection");
}
assignProductsToCollection(productName) {
cy.get(COLLECTION_SELECTORS.addProductButton)
diff --git a/cypress/steps/homePageSteps.js b/cypress/steps/homePageSteps.js
index bd53c0972..72b9c6d96 100644
--- a/cypress/steps/homePageSteps.js
+++ b/cypress/steps/homePageSteps.js
@@ -1,12 +1,12 @@
import { HEADER_SELECTORS } from "../elements/header/header-selectors";
class HomePageSteps {
changeChannel(channelName) {
- cy.get(HEADER_SELECTORS.channelSelect)
- .click()
- .get(HEADER_SELECTORS.channelSelectList)
+ cy.get(HEADER_SELECTORS.channelSelect).click();
+ cy.addAliasToGraphRequest("Home");
+ cy.get(HEADER_SELECTORS.channelSelectList)
.contains(channelName)
- .click()
- .waitForGraph("Home");
+ .click();
+ cy.wait("@Home");
}
}
export default HomePageSteps;
diff --git a/cypress/steps/productSteps.js b/cypress/steps/productSteps.js
new file mode 100644
index 000000000..eec8c3736
--- /dev/null
+++ b/cypress/steps/productSteps.js
@@ -0,0 +1,37 @@
+import { PRODUCTS_SELECTORS } from "../elements/catalog/product-selectors";
+
+class ProductSteps {
+ valueTrue = PRODUCTS_SELECTORS.radioButtonsValueTrue;
+ valueFalse = PRODUCTS_SELECTORS.radioButtonsValueFalse;
+
+ updateProductIsAvailableForPurchase(productUrl, isAvailableForPurchase) {
+ const isAvailableForPurchaseSelector = isAvailableForPurchase
+ ? this.valueTrue
+ : this.valueFalse;
+ const availableForPurchaseSelector = `${PRODUCTS_SELECTORS.availableForPurchaseRadioButtons}${isAvailableForPurchaseSelector}`;
+ this.updateProductMenageInChannel(productUrl, availableForPurchaseSelector);
+ }
+ updateProductPublish(productUrl, isPublished) {
+ const isPublishedSelector = isPublished ? this.valueTrue : this.valueFalse;
+ const publishedSelector = `${PRODUCTS_SELECTORS.publishedRadioButtons}${isPublishedSelector}`;
+ this.updateProductMenageInChannel(productUrl, publishedSelector);
+ }
+ updateProductVisibleInListings(productUrl) {
+ this.updateProductMenageInChannel(
+ productUrl,
+ PRODUCTS_SELECTORS.visibleInListingsButton
+ );
+ }
+ updateProductMenageInChannel(productUrl, menageSelector) {
+ cy.visit(productUrl)
+ .get(PRODUCTS_SELECTORS.assignedChannels)
+ .click()
+ .get(menageSelector)
+ .click();
+ cy.addAliasToGraphRequest("ProductChannelListingUpdate");
+ cy.get(PRODUCTS_SELECTORS.saveBtn)
+ .click()
+ .wait("@ProductChannelListingUpdate");
+ }
+}
+export default ProductSteps;
diff --git a/cypress/support/index.js b/cypress/support/index.js
index 4e9a2361d..2d9dad3db 100644
--- a/cypress/support/index.js
+++ b/cypress/support/index.js
@@ -21,7 +21,7 @@ Cypress.Commands.add("clearSessionData", () => {
});
});
-Cypress.Commands.add("waitForGraph", operationName => {
+Cypress.Commands.add("addAliasToGraphRequest", operationName => {
cy.intercept("POST", urlList.apiUri, req => {
req.statusCode = 200;
const requestBody = req.body;
@@ -39,7 +39,10 @@ Cypress.Commands.add("waitForGraph", operationName => {
});
});
-Cypress.Commands.add("sendRequestWithQuery", query =>
+Cypress.Commands.add("sendFrontShopRequestWithQuery", query =>
+ cy.sendRequestWithQuery(query, "token")
+);
+Cypress.Commands.add("sendRequestWithQuery", (query, authorization = "auth") =>
cy.request({
body: {
method: "POST",
@@ -47,27 +50,9 @@ Cypress.Commands.add("sendRequestWithQuery", query =>
url: urlList.apiUri
},
headers: {
- Authorization: `JWT ${window.sessionStorage.getItem("auth")}`
+ Authorization: `JWT ${window.sessionStorage.getItem(authorization)}`
},
method: "POST",
url: urlList.apiUri
})
);
-Cypress.Commands.add(
- "sendFrontShopRequest",
- (operationName, query, variables) =>
- cy.request({
- method: "POST",
- url: urlList.apiUri,
- headers: {
- authorization: `JWT ${window.localStorage.getItem("token")}`
- },
- body: [
- {
- operationName,
- variables,
- query
- }
- ]
- })
-);
diff --git a/cypress/support/user/index.js b/cypress/support/user/index.js
index b0f7f66b0..3ba659b6d 100644
--- a/cypress/support/user/index.js
+++ b/cypress/support/user/index.js
@@ -1,5 +1,4 @@
import { LOGIN_SELECTORS } from "../../elements/account/login-selectors";
-import { urlList } from "../../url/urlList";
Cypress.Commands.add("loginUser", () =>
cy
@@ -11,40 +10,32 @@ Cypress.Commands.add("loginUser", () =>
.click()
);
-Cypress.Commands.add("loginUserViaRequest", () => {
- const logInMutationQuery = `mutation TokenAuth($email: String!, $password: String!) {
- tokenCreate(email: $email, password: $password) {
+Cypress.Commands.add("loginInShop", () => {
+ cy.loginUserViaRequest("token");
+});
+
+Cypress.Commands.add("loginUserViaRequest", (authorization = "auth") => {
+ const mutation = `mutation TokenAuth{
+ tokenCreate(email: "${Cypress.env("USER_NAME")}", password: "${Cypress.env(
+ "USER_PASSWORD"
+ )}") {
token
errors: accountErrors {
code
field
message
- __typename
}
user {
id
- __typename
}
- __typename
}
}`;
-
- return cy
- .request({
- body: {
- operationName: "TokenAuth",
- query: logInMutationQuery,
- variables: {
- email: Cypress.env("USER_NAME"),
- password: Cypress.env("USER_PASSWORD")
- }
- },
- method: "POST",
- url: urlList.apiUri
- })
- .then(resp => {
- window.sessionStorage.setItem("auth", resp.body.data.tokenCreate.token);
- });
+ return cy.sendRequestWithQuery(mutation, authorization).then(resp => {
+ window.sessionStorage.setItem(
+ authorization,
+ resp.body.data.tokenCreate.token
+ );
+ });
});
Cypress.Commands.add("loginInShop", () => {
cy.request({
diff --git a/cypress/url/urlList.js b/cypress/url/urlList.js
index dec3bea5e..995a67ccc 100644
--- a/cypress/url/urlList.js
+++ b/cypress/url/urlList.js
@@ -8,3 +8,4 @@ export const urlList = {
warehouses: "warehouses/",
collections: "collections/"
};
+export const productDetailsUrl = productId => `${urlList.products}${productId}`;
diff --git a/cypress/utils/channelsUtils.js b/cypress/utils/channelsUtils.js
index c5e9dc6d0..a67a1b404 100644
--- a/cypress/utils/channelsUtils.js
+++ b/cypress/utils/channelsUtils.js
@@ -38,7 +38,7 @@ class ChannelsUtils {
}));
});
}
- createChannel(isActive, name, slug, currencyCode) {
+ createChannel({ isActive = true, name, slug = name, currencyCode = "PLN" }) {
return this.channels
.createChannel(isActive, name, slug, currencyCode)
.then(
@@ -46,7 +46,7 @@ class ChannelsUtils {
);
}
getCreatedChannel() {
- return channel;
+ return this.createdChannel;
}
}
export default ChannelsUtils;
diff --git a/cypress/utils/collectionsUtils.js b/cypress/utils/collectionsUtils.js
index b510af4fc..bf80f36ec 100644
--- a/cypress/utils/collectionsUtils.js
+++ b/cypress/utils/collectionsUtils.js
@@ -1,21 +1,8 @@
-import Collections from "../apiRequests/frontShop/Collections";
+import Collections from "../apiRequests/Collections";
class CollectionsUtils {
collectionsRequest = new Collections();
- isCollectionVisible(collectionId, channelSlug) {
- return this.collectionsRequest
- .getCollection(collectionId, channelSlug)
- .then(resp => {
- const collection = resp.body[0].data.collection;
- return collection !== null && collection.id === collectionId;
- });
- }
- waitForCreateCollectionRequest() {
- return cy
- .wait(`@CreateCollection`)
- .its("response.body.data.collectionCreate.collection");
- }
deleteProperCollections(startsWith) {
cy.deleteProperElements(
this.collectionsRequest.deleteCollection,
diff --git a/cypress/utils/productsUtils.js b/cypress/utils/productsUtils.js
index 43fba4be3..2ac9f0ce7 100644
--- a/cypress/utils/productsUtils.js
+++ b/cypress/utils/productsUtils.js
@@ -13,19 +13,37 @@ class ProductsUtils {
attribute;
category;
- createProductInChannel(
+ createProductWithVariant(name, attributeId, productTypeId, categoryId) {
+ return this.createProduct(
+ attributeId,
+ name,
+ productTypeId,
+ categoryId
+ ).then(() => this.createVariant(this.product.id, name));
+ }
+
+ createProductInChannel({
name,
channelId,
- warehouseId,
- quantityInWarehouse,
+ warehouseId = null,
+ quantityInWarehouse = 10,
productTypeId,
attributeId,
categoryId,
- price
- ) {
+ price = 1,
+ isPublished = true,
+ isAvailableForPurchase = true,
+ visibleInListings = true
+ }) {
return this.createProduct(attributeId, name, productTypeId, categoryId)
.then(() =>
- this.productRequest.updateChannelInProduct(this.product.id, channelId)
+ this.productRequest.updateChannelInProduct({
+ productId: this.product.id,
+ channelId,
+ isPublished,
+ isAvailableForPurchase,
+ visibleInListings
+ })
)
.then(() => {
this.createVariant(
@@ -92,7 +110,9 @@ class ProductsUtils {
resp.body.data.productVariantBulkCreate.productVariants)
);
}
-
+ getCreatedProduct() {
+ return this.product;
+ }
getCreatedVariants() {
return this.variants;
}
diff --git a/cypress/utils/shippingUtils.js b/cypress/utils/shippingUtils.js
index 1fb352907..75eb7501f 100644
--- a/cypress/utils/shippingUtils.js
+++ b/cypress/utils/shippingUtils.js
@@ -8,7 +8,7 @@ class ShippingUtils {
shippingZone;
warehouse;
- createShipping(channelId, name, address, price) {
+ createShipping({ channelId, name, address, price = 1 }) {
return this.createShippingZone(name, address.country)
.then(() => this.createWarehouse(name, this.shippingZone.id, address))
.then(() => this.createShippingRate(name, this.shippingZone.id))
diff --git a/cypress/utils/storeFront/collectionsUtils.js b/cypress/utils/storeFront/collectionsUtils.js
new file mode 100644
index 000000000..3a25953c0
--- /dev/null
+++ b/cypress/utils/storeFront/collectionsUtils.js
@@ -0,0 +1,23 @@
+import Collections from "../../apiRequests/storeFront/Collections";
+
+class CollectionsUtils {
+ collectionsRequest = new Collections();
+
+ isCollectionVisible(collectionId, channelSlug) {
+ return this.collectionsRequest
+ .getCollection(collectionId, channelSlug)
+ .then(resp => {
+ const collection = resp.body.data.collection;
+ return collection !== null && collection.id === collectionId;
+ });
+ }
+ isProductInCollectionVisible(collectionId, channelSlug, productId) {
+ return this.collectionsRequest
+ .getCollection(collectionId, channelSlug)
+ .then(resp => {
+ const product = resp.body.data.collection.products.edges[0].node;
+ return product !== null && product.id === productId;
+ });
+ }
+}
+export default CollectionsUtils;
diff --git a/cypress/utils/storeFront/storeFrontProductUtils.js b/cypress/utils/storeFront/storeFrontProductUtils.js
new file mode 100644
index 000000000..676075f19
--- /dev/null
+++ b/cypress/utils/storeFront/storeFrontProductUtils.js
@@ -0,0 +1,34 @@
+import ProductDetails from "../../apiRequests/storeFront/ProductDetails";
+import Search from "../../apiRequests/storeFront/Search";
+
+class StoreFrontProductUtils {
+ isProductVisible(productId, channelSlug, name) {
+ const productDetails = new ProductDetails();
+ return productDetails
+ .getProductDetails(productId, channelSlug)
+ .then(productDetailsResp => {
+ const product = productDetailsResp.body.data.product;
+ return product !== null && product.name === name;
+ });
+ }
+ isProductAvailableForPurchase(productId, channelSlug) {
+ const productDetails = new ProductDetails();
+ return productDetails
+ .getProductDetails(productId, channelSlug)
+ .then(
+ productDetailsResp =>
+ productDetailsResp.body.data.product.isAvailableForPurchase
+ );
+ }
+ isProductVisibleInSearchResult(productName, channelSlug) {
+ const search = new Search();
+ return search
+ .searchInShop(productName, channelSlug)
+ .then(
+ resp =>
+ resp.body.data.products.totalCount !== 0 &&
+ resp.body.data.products.edges[0].node.name === productName
+ );
+ }
+}
+export default StoreFrontProductUtils;