From aa10e08699841eb7821257c88b4b5ccaa0431471 Mon Sep 17 00:00:00 2001 From: PollySt Date: Fri, 26 Jan 2024 18:11:41 +0200 Subject: [PATCH] create tests for the collections, add new locators, data-testids, functions --- .env.local-example | 3 +- e2e/constants.ts | 1 + e2e/page-objects/collections-page.ts | 4 ++ e2e/tests/collections.spec.ts | 45 +++++++++++++++++++ e2e/tests/shopping-cart.spec.ts | 4 +- e2e/utils.ts | 9 ++++ .../NavigationTop/components/TopLinks.tsx | 4 +- 7 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 e2e/tests/collections.spec.ts create mode 100644 e2e/utils.ts diff --git a/.env.local-example b/.env.local-example index fe1ccb60..7eeca42c 100644 --- a/.env.local-example +++ b/.env.local-example @@ -23,5 +23,6 @@ PLAYWRIGHT_PRODUCT_NAME='Mesh Gym Shorts' PLAYWRIGHT_PRODUCT_NAME_OUTOFSTOCK='An Exceptional Tee for Men' PLAYWRIGHT_PRODUCT_SIZE_OUTOFSTOCK='XS' PLAYWRIGHT_PRODUCT_COLOR_OUTOFSTOCK='Gray' -PLAYWRIGHT_COLLECTION_NAME='men' +PLAYWRIGHT_COLLECTION_NAME='Men' +PLAYWRIGHT_BRAND_NAME='Nike' diff --git a/e2e/constants.ts b/e2e/constants.ts index 4600f640..12ca5da3 100644 --- a/e2e/constants.ts +++ b/e2e/constants.ts @@ -14,3 +14,4 @@ export const INVALID_PHONE_NUMBER = faker.string.numeric(5); export const VALID_PHONE_NUMBER = '+1' + faker.string.numeric(10); export const USER_NAME = 'test'; export const MESSAGE = faker.lorem.sentence(); +export const BRAND_NAME = process.env.PLAYWRIGHT_BRAND_NAME; diff --git a/e2e/page-objects/collections-page.ts b/e2e/page-objects/collections-page.ts index d15fb66e..3f564b65 100644 --- a/e2e/page-objects/collections-page.ts +++ b/e2e/page-objects/collections-page.ts @@ -9,4 +9,8 @@ export class CollectionsPage { productItems = () => this.page.getByTestId('product-item'); getProductByName = (productName: string) => this.productItems().getByText(productName); + collectionsDialog = () => this.page.getByTestId('collection-popup-dialog'); + collectionSection = () => this.page.getByTestId('collection-section'); + brandsSection = () => this.collectionSection().filter({ hasText: 'Brands' }).getByRole('list'); + getBrandByName = (brand: string) => this.brandsSection().getByText(brand, { exact: true }); } diff --git a/e2e/tests/collections.spec.ts b/e2e/tests/collections.spec.ts new file mode 100644 index 00000000..892e81a3 --- /dev/null +++ b/e2e/tests/collections.spec.ts @@ -0,0 +1,45 @@ +import { test } from '../fixtures'; +import { expect } from 'playwright/test'; +import { BRAND_NAME, COLLECTION_NAME, COLLECTIONS_ENDPOINT, HOMEPAGE_ENDPOINT } from '../constants'; +import { getCollectionEndpoint } from '../utils'; + +test.describe('Collections page', () => { + test.beforeEach('Navigate to the home page and open collection menu', async ({ page, collectionsPage }) => { + if (!COLLECTION_NAME) { + test.skip(!COLLECTION_NAME, 'PLAYWRIGHT_COLLECTION_NAME was not defined'); + return; + } + + await page.goto(HOMEPAGE_ENDPOINT); + await page.getByTestId('nav-bar').getByRole('button', { name: COLLECTION_NAME, exact: true }).click(); + await collectionsPage.collectionsDialog().waitFor(); + }); + + test('Verify user can navigate to the collection', async ({ page, collectionsPage }) => { + await collectionsPage + .collectionsDialog() + .locator('a', { hasText: `Shop all ${COLLECTION_NAME}` }) + .click(); + await page.waitForURL(getCollectionEndpoint()); + + await page.getByRole('heading', { name: COLLECTION_NAME, exact: true }).waitFor(); + await expect(collectionsPage.productItems()).not.toHaveCount(0); + }); + + test('Verify user can navigate to the collection by brand name', async ({ page, collectionsPage }) => { + if (!BRAND_NAME) { + test.skip(!BRAND_NAME, 'PLAYWRIGHT_BRAND_NAME was not defined'); + return; + } + + await collectionsPage.brandsSection().hover(); + await collectionsPage.getBrandByName(BRAND_NAME).click(); + await page.waitForURL(COLLECTIONS_ENDPOINT + BRAND_NAME.toLowerCase()); + + await page.getByRole('heading', { name: BRAND_NAME, exact: true }).waitFor(); + await expect(collectionsPage.productItems()).not.toHaveCount(0); + for (const product of await collectionsPage.productItems().all()) { + await expect(product).toContainText(BRAND_NAME, { ignoreCase: true }); + } + }); +}); diff --git a/e2e/tests/shopping-cart.spec.ts b/e2e/tests/shopping-cart.spec.ts index e11d0096..8a454e9c 100644 --- a/e2e/tests/shopping-cart.spec.ts +++ b/e2e/tests/shopping-cart.spec.ts @@ -1,13 +1,13 @@ import { test } from '../fixtures'; import { COLLECTION_NAME, - COLLECTIONS_ENDPOINT, PRODUCT_COLOR_OUTOFSTOCK, PRODUCT_NAME, PRODUCT_OUTOFSTOCK, PRODUCT_SIZE_OUTOFSTOCK } from '../constants'; import { expect } from 'playwright/test'; +import { getCollectionEndpoint } from '../utils'; test.describe('Shopping cart', () => { test.beforeEach('Navigate to the Collections page', async ({ page }) => { @@ -15,7 +15,7 @@ test.describe('Shopping cart', () => { test.skip(!COLLECTION_NAME, 'PLAYWRIGHT_COLLECTION_NAME was not defined'); return; } - await page.goto(COLLECTIONS_ENDPOINT + COLLECTION_NAME); + await page.goto(getCollectionEndpoint()); }); test('User is able to add product to cart', async ({ page, collectionsPage, shoppingCart, productPage }) => { diff --git a/e2e/utils.ts b/e2e/utils.ts new file mode 100644 index 00000000..9afae3f7 --- /dev/null +++ b/e2e/utils.ts @@ -0,0 +1,9 @@ +import { COLLECTION_NAME, COLLECTIONS_ENDPOINT } from './constants'; + +export function transformStringToSlug(string: string) { + return string.toLowerCase().replace(/\s+/g, '-'); +} + +export function getCollectionEndpoint() { + return COLLECTIONS_ENDPOINT + transformStringToSlug(`${COLLECTION_NAME}`); +} diff --git a/src/features/Navigation/NavigationTop/components/TopLinks.tsx b/src/features/Navigation/NavigationTop/components/TopLinks.tsx index fb7e73a9..4706025d 100644 --- a/src/features/Navigation/NavigationTop/components/TopLinks.tsx +++ b/src/features/Navigation/NavigationTop/components/TopLinks.tsx @@ -32,7 +32,7 @@ const SectionWithPopover = ({ section }: { section: NavigationSection }) => ( {/* Presentational element used to render the bottom shadow, if we put the shadow on the actual panel it pokes out the top, so we use this shorter element to hide the top of the shadow */}