Skip to content

Commit b085c92

Browse files
authored
Merge pull request #41 from nesrineabdmouleh/enableModalFO
Enable Quick view and Block Cart modals
2 parents f506458 + b8a8ff9 commit b085c92

File tree

12 files changed

+715
-22
lines changed

12 files changed

+715
-22
lines changed

src/data/types/product.ts

+19-4
Original file line numberDiff line numberDiff line change
@@ -136,17 +136,31 @@ type ProductCustomizations = {
136136
};
137137

138138
type ProductDetailsBasic = {
139-
image: string
139+
image?: string
140140
name: string
141141
price: number
142-
quantity: number
142+
quantity?: number
143143
};
144144

145145
type ProductDetails = ProductDetailsBasic & {
146-
summary: string
147-
description: string
146+
summary?: string
147+
description?: string
148148
shipping?: string
149149
subtotal?: number
150+
coverImage?:string,
151+
thumbImage?:string,
152+
taxShippingDeliveryLabel?: string,
153+
shortDescription?: string,
154+
};
155+
156+
type ProductDetailsWithDiscount = ProductDetailsBasic & {
157+
discountPercentage: string,
158+
regularPrice: number,
159+
subtotal?: number,
160+
taxShippingDeliveryLabel?: string,
161+
coverImage?:string,
162+
thumbImage?:string,
163+
shortDescription?: string,
150164
};
151165

152166
type ProductDiscount = {
@@ -242,6 +256,7 @@ export type {
242256
ProductCustomization,
243257
ProductDetails,
244258
ProductDetailsBasic,
259+
ProductDetailsWithDiscount,
245260
ProductDiscount,
246261
ProductFilterMinMax,
247262
ProductHeaderSummary,

src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ export {default as foClassicCheckoutPage} from '@pages/FO/classic/checkout';
9494
export {default as foClassicCheckoutOrderConfirmationPage} from '@pages/FO/classic/checkout/orderConfirmation';
9595
export {default as foClassicHomePage} from '@pages/FO/classic/home';
9696
export {default as foClassicLoginPage} from '@pages/FO/classic/login';
97+
export {default as foClassicModalBlockCartPage} from '@pages/FO/classic/modal/blockCart';
98+
export {default as foClassicModalQuickViewPage} from '@pages/FO/classic/modal/quickView';
9799
export {default as foClassicProductPage} from '@pages/FO/classic/product';
98100

99101
// Export Modules

src/interfaces/FO/cart/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import {FOBasePagePageInterface} from '@interfaces/FO';
2-
import type {ProductAttribute} from '@data/types/product';
2+
import type {ProductAttribute, ProductDetailsWithDiscount} from '@data/types/product';
33
import type {Page} from '@playwright/test';
44

55
export interface FoCartPageInterface extends FOBasePagePageInterface {
@@ -28,7 +28,7 @@ export interface FoCartPageInterface extends FOBasePagePageInterface {
2828
getNoItemsInYourCartMessage(page: Page): Promise<string>;
2929
getNotificationMessage(page: Page): Promise<string>;
3030
getProductAttributes(page: Page, row: number): Promise<ProductAttribute[]>;
31-
getProductDetail(page: Page, row: number): Promise<object>;
31+
getProductDetail(page: Page, row: number): Promise<ProductDetailsWithDiscount>;
3232
getProductsNumber(page: Page): Promise<number>;
3333
getSubtotalDiscountValue(page: Page): Promise<number>;
3434
isAlertWarningForMinimumPurchaseVisible(page: Page): Promise<boolean>;

src/interfaces/FO/checkout/orderConfirmation.ts

+5
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,12 @@ import type {Page} from '@playwright/test';
33

44
export interface FoCheckoutOrderConfirmationPageInterface extends FOBasePagePageInterface {
55
readonly orderConfirmationCardTitle: string;
6+
readonly pageTitle: string;
67

8+
getGiftWrappingValue(page: Page): Promise<number>;
79
getOrderConfirmationCardTitle(page: Page): Promise<string>;
810
getOrderReferenceValue(page: Page): Promise<string>;
11+
getPaymentMethod(page: Page): Promise<string>;
12+
goToContactUsPage(page: Page): Promise<void>;
13+
isFinalSummaryVisible(page: Page): Promise<boolean>;
914
}

src/interfaces/FO/modal/blockCart.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import {FOBasePagePageInterface} from '@interfaces/FO';
2+
3+
// Import data
4+
import type {ProductAttribute} from '@data/types/product';
5+
import type {CartProductDetails} from '@data/types/cart';
6+
7+
import type {Page} from '@playwright/test';
8+
9+
export interface FoModalBlockCartPageInterface extends FOBasePagePageInterface {
10+
getBlockCartModalTitle(page: Page): Promise<string>;
11+
isBlockCartModalVisible(page: Page): Promise<boolean>;
12+
getProductDetailsFromBlockCartModal(page: Page): Promise<CartProductDetails>;
13+
getProductAttributesFromBlockCartModal(page: Page): Promise<ProductAttribute[]>;
14+
proceedToCheckout(page: Page): Promise<void>;
15+
continueShopping(page: Page): Promise<boolean>;
16+
closeBlockCartModal(page: Page, clickOutside?: boolean): Promise<boolean>;
17+
}

src/interfaces/FO/modal/quickView.ts

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
import {FOBasePagePageInterface} from '@interfaces/FO';
2+
3+
// Import data
4+
import type {ProductAttribute, ProductDetails, ProductDetailsWithDiscount} from '@data/types/product';
5+
6+
import type {Page} from '@playwright/test';
7+
8+
export interface FoModalQuickViewPageInterface extends FOBasePagePageInterface {
9+
quickViewModalDiv: string;
10+
11+
addToCartByQuickView(page: Page): Promise<void>;
12+
closeQuickViewModal(page: Page, clickOutside?: boolean): Promise<boolean>;
13+
getProductAttributesFromQuickViewModal(page: Page): Promise<ProductAttribute[]>;
14+
getProductAvailabilityText(page: Page): Promise<string>;
15+
getProductDetailsFromQuickViewModal(page: Page): Promise<ProductDetails>;
16+
getProductQuantityFromQuickViewModal(page: Page): Promise<number>;
17+
getProductWithDiscountDetailsFromQuickViewModal(page: Page): Promise<ProductDetailsWithDiscount>;
18+
getQuickViewCoverImage(page: Page): Promise<string | null>;
19+
getQuickViewImageMain(page: Page): Promise<string | null>;
20+
getSelectedAttributes(page: Page): Promise<ProductAttribute[]>;
21+
getSelectedAttributesFromQuickViewModal(page: Page, attribute: ProductAttribute): Promise<ProductAttribute[]>;
22+
getSocialSharingLink(page: Page, socialSharing: string): Promise<string>;
23+
isAddToCartButtonDisabled(page: Page): Promise<boolean>;
24+
isAddToCartButtonEnabled(page: Page): Promise<boolean>;
25+
isQuickViewProductModalVisible(page: Page): Promise<boolean>;
26+
selectThumbImage(page: Page, position: number): Promise<string>;
27+
setAttribute(page: Page, attributes: ProductAttribute): Promise<void>;
28+
setAttributes(page: Page, attributes: ProductAttribute[]): Promise<void>;
29+
setAttributesAndAddToCart(page: Page, attributes: ProductAttribute[], quantity: number): Promise<void>;
30+
setQuantity(page: Page, quantity: number | string): Promise<void>;
31+
setQuantityAndAddToCart(page: Page, quantityWanted?: number | string): Promise<void>;
32+
setQuantityByArrowUpDown(page: Page, quantityWanted: number, direction: string): Promise<void>;
33+
34+
}

src/pages/BO/catalog/products/index.ts

+4-5
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ import testContext from '@utils/test';
44

55
const psVersion = testContext.getPSVersion();
66

7-
/* eslint-disable global-require */
7+
/* eslint-disable global-require, @typescript-eslint/no-var-requires */
88
function requirePage(): BOProductsPageInterface {
99
if (semver.gte(psVersion, '0.0.0')) {
10-
return require('@versions/develop/pages/BO/catalog/products');
10+
return require('@versions/develop/pages/BO/catalog/products').productsPage;
1111
}
12-
return require('@versions/develop/pages/BO/catalog/products');
12+
return require('@versions/develop/pages/BO/catalog/products').productsPage;
1313
}
14-
15-
/* eslint-enable global-require */
14+
/* eslint-disable global-require, @typescript-eslint/no-var-requires */
1615

1716
export default requirePage();
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type {FoModalBlockCartPageInterface} from '@interfaces/FO/modal/blockCart';
2+
import testContext from '@utils/test';
3+
import semver from 'semver';
4+
5+
const psVersion = testContext.getPSVersion();
6+
7+
/* eslint-disable global-require, @typescript-eslint/no-var-requires */
8+
function requirePage(): FoModalBlockCartPageInterface {
9+
if (semver.gte(psVersion, '0.0.0')) {
10+
return require('@versions/develop/pages/FO/classic/modal/blockCart').blockCartModal;
11+
}
12+
return require('@versions/develop/pages/FO/classic/modal/blockCart').blockCartModal;
13+
}
14+
/* eslint-enable global-require, @typescript-eslint/no-var-requires */
15+
16+
export default requirePage();
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import type {FoModalQuickViewPageInterface} from '@interfaces/FO/modal/quickView';
2+
import testContext from '@utils/test';
3+
import semver from 'semver';
4+
5+
const psVersion = testContext.getPSVersion();
6+
7+
/* eslint-disable global-require, @typescript-eslint/no-var-requires */
8+
function requirePage(): FoModalQuickViewPageInterface {
9+
if (semver.gte(psVersion, '0.0.0')) {
10+
return require('@versions/develop/pages/FO/classic/modal/quickView').quickViewModal;
11+
}
12+
return require('@versions/develop/pages/FO/classic/modal/quickView').quickViewModal;
13+
}
14+
/* eslint-enable global-require, @typescript-eslint/no-var-requires */
15+
16+
export default requirePage();

src/versions/develop/pages/FO/classic/cart/index.ts

+3-11
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {FoCartPageInterface} from '@interfaces/FO/cart';
33
import FOBasePage from '@pages/FO/FOBasePage';
44

55
// Import data
6-
import type {ProductAttribute} from '@data/types/product';
6+
import type {ProductAttribute, ProductDetailsWithDiscount} from '@data/types/product';
77

88
import type {Page} from 'playwright';
99

@@ -216,23 +216,15 @@ class CartPage extends FOBasePage implements FoCartPageInterface {
216216
* @returns {Promise<{discountPercentage: string, image: string|null, quantity: number, totalPrice: number,
217217
* price: number, regularPrice: number, name: string}>}
218218
*/
219-
async getProductDetail(page: Page, row: number): Promise<{
220-
discountPercentage: string,
221-
image: string | null,
222-
quantity: number,
223-
totalPrice: number,
224-
price: number,
225-
regularPrice: number,
226-
name: string,
227-
}> {
219+
async getProductDetail(page: Page, row: number): Promise<ProductDetailsWithDiscount> {
228220
return {
229221
name: await this.getTextContent(page, this.productName(row)),
230222
regularPrice: await this.getPriceFromText(page, this.productRegularPrice(row)),
231223
price: await this.getPriceFromText(page, this.productPrice(row)),
232224
discountPercentage: await this.getTextContent(page, this.productDiscountPercentage(row)),
233225
image: await this.getAttributeContent(page, this.productImage(row), 'src'),
234226
quantity: parseFloat(await this.getAttributeContent(page, this.productQuantity(row), 'value') ?? ''),
235-
totalPrice: await this.getPriceFromText(page, this.productTotalPrice(row)),
227+
subtotal: await this.getPriceFromText(page, this.productTotalPrice(row)),
236228
};
237229
}
238230

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
// Import pages
2+
import type {FoModalBlockCartPageInterface} from '@interfaces/FO/modal/blockCart';
3+
import FOBasePage from '@pages/FO/FOBasePage';
4+
5+
// Import data
6+
import type {ProductAttribute} from '@data/types/product';
7+
import type {CartProductDetails} from '@data/types/cart';
8+
9+
import type {Page} from 'playwright';
10+
11+
/**
12+
* Block cart modal, contains functions that can be used on the modal
13+
* @class
14+
* @extends FOBasePage
15+
*/
16+
class BlockCartModal extends FOBasePage implements FoModalBlockCartPageInterface {
17+
private readonly blockCartLabel: string;
18+
19+
protected readonly blockCartModalDiv: string;
20+
21+
protected blockCartModalCloseButton: string;
22+
23+
private readonly cartModalProductNameBlock: string;
24+
25+
private readonly cartModalProductPriceBlock: string;
26+
27+
private readonly cartModalProductSizeBlock: string;
28+
29+
private readonly cartModalProductColorBlock: string;
30+
31+
private readonly cartModalProductQuantityBlock: string;
32+
33+
private readonly cartContentBlock: string;
34+
35+
protected cartModalProductsCountBlock: string;
36+
37+
protected cartModalShippingBlock: string;
38+
39+
protected cartModalSubtotalBlock: string;
40+
41+
protected cartModalProductTaxInclBlock: string;
42+
43+
protected cartModalCheckoutLink: string;
44+
45+
protected continueShoppingButton: string;
46+
47+
/**
48+
* @constructs
49+
* Setting up texts and selectors to use on home page
50+
*/
51+
constructor(theme: string = 'classic') {
52+
super(theme);
53+
54+
this.blockCartModalDiv = '#blockcart-modal';
55+
this.blockCartLabel = '#myModalLabel';
56+
this.blockCartModalCloseButton = `${this.blockCartModalDiv} button.close`;
57+
this.cartModalProductNameBlock = `${this.blockCartModalDiv} .product-name`;
58+
this.cartModalProductPriceBlock = `${this.blockCartModalDiv} .product-price`;
59+
this.cartModalProductSizeBlock = `${this.blockCartModalDiv} .size strong`;
60+
this.cartModalProductColorBlock = `${this.blockCartModalDiv} .color strong`;
61+
this.cartModalProductQuantityBlock = `${this.blockCartModalDiv} .product-quantity`;
62+
this.cartContentBlock = `${this.blockCartModalDiv} .cart-content`;
63+
this.cartModalProductsCountBlock = `${this.cartContentBlock} .cart-products-count`;
64+
this.cartModalShippingBlock = `${this.cartContentBlock} .shipping.value`;
65+
this.cartModalSubtotalBlock = `${this.cartContentBlock} .subtotal.value`;
66+
this.cartModalProductTaxInclBlock = `${this.cartContentBlock} .product-total .value`;
67+
this.cartModalCheckoutLink = `${this.blockCartModalDiv} div.cart-content-btn a`;
68+
this.continueShoppingButton = `${this.blockCartModalDiv} div.cart-content-btn button.btn-secondary`;
69+
}
70+
71+
/**
72+
* Get block cart modal title
73+
* @param page {Page} Browser tab
74+
* @returns {Promise<string>}
75+
*/
76+
async getBlockCartModalTitle(page: Page): Promise<string> {
77+
return this.getTextContent(page, this.blockCartLabel);
78+
}
79+
80+
/**
81+
* Is block cart modal visible
82+
* @param page {Page} Browser tab
83+
* @returns {Promise<boolean>}
84+
*/
85+
async isBlockCartModalVisible(page: Page): Promise<boolean> {
86+
return this.elementVisible(page, this.blockCartModalDiv, 2000);
87+
}
88+
89+
/**
90+
* Get product details from blockCart modal
91+
* @param page {Page} Browser tab
92+
* @returns {Promise<CartProductDetails>}
93+
*/
94+
async getProductDetailsFromBlockCartModal(page: Page): Promise<CartProductDetails> {
95+
return {
96+
name: await this.getTextContent(page, this.cartModalProductNameBlock),
97+
price: parseFloat((await this.getTextContent(page, this.cartModalProductPriceBlock)).replace('€', '')),
98+
quantity: await this.getNumberFromText(page, this.cartModalProductQuantityBlock),
99+
cartProductsCount: await this.getNumberFromText(page, this.cartModalProductsCountBlock),
100+
cartSubtotal: parseFloat((await this.getTextContent(page, this.cartModalSubtotalBlock)).replace('€', '')),
101+
cartShipping: await this.getTextContent(page, this.cartModalShippingBlock),
102+
totalTaxIncl: parseFloat((await this.getTextContent(page, this.cartModalProductTaxInclBlock)).replace('€', '')),
103+
};
104+
}
105+
106+
/**
107+
* Get product attributes from block cart modal
108+
* @param page {Page} Browser tab
109+
* @returns {Promise<ProductAttribute[]>}
110+
*/
111+
async getProductAttributesFromBlockCartModal(page: Page): Promise<ProductAttribute[]> {
112+
return [
113+
{
114+
name: 'size',
115+
value: await this.getTextContent(page, this.cartModalProductSizeBlock),
116+
},
117+
{
118+
name: 'color',
119+
value: await this.getTextContent(page, this.cartModalProductColorBlock),
120+
},
121+
];
122+
}
123+
124+
/**
125+
* Click on proceed to checkout after adding product to cart (in modal homePage)
126+
* @param page {Page} Browser tab
127+
* @return {Promise<void>}
128+
*/
129+
async proceedToCheckout(page: Page): Promise<void> {
130+
await this.clickAndWaitForURL(page, this.cartModalCheckoutLink);
131+
await page.waitForLoadState('domcontentloaded');
132+
}
133+
134+
/**
135+
* Click on continue shopping
136+
* @param page {Page} Browser tab
137+
* @returns {Promise<boolean>}
138+
*/
139+
async continueShopping(page: Page): Promise<boolean> {
140+
await this.waitForSelectorAndClick(page, this.continueShoppingButton);
141+
142+
return this.elementNotVisible(page, this.blockCartModalDiv, 2000);
143+
}
144+
145+
/**
146+
* Close block cart modal
147+
* @param page {Page} Browser tab
148+
* @param clickOutside {boolean} True if we need to click outside to close the modal
149+
* @returns {Promise<boolean>}
150+
*/
151+
async closeBlockCartModal(page: Page, clickOutside: boolean = false): Promise<boolean> {
152+
if (clickOutside) {
153+
await page.waitForTimeout(1000);
154+
await page.mouse.click(5, 5);
155+
} else {
156+
await this.waitForSelectorAndClick(page, this.blockCartModalCloseButton);
157+
}
158+
return this.elementNotVisible(page, this.blockCartModalDiv, 1000);
159+
}
160+
}
161+
162+
const blockCartModal = new BlockCartModal();
163+
export {blockCartModal, BlockCartModal};

0 commit comments

Comments
 (0)