diff --git a/src/e2e/CareLeavers.E2ETests/playwright-ci.config.ts b/src/e2e/CareLeavers.E2ETests/playwright-ci.config.ts index 6ac0b16..8ed2e8c 100644 --- a/src/e2e/CareLeavers.E2ETests/playwright-ci.config.ts +++ b/src/e2e/CareLeavers.E2ETests/playwright-ci.config.ts @@ -39,6 +39,9 @@ export default defineConfig({ use: { browserName: 'chromium', ...devices['Pixel 8'], + isMobile: true, + viewport: { width: 412, height: 914 }, + userAgent: devices['Pixel 8']?.userAgent ?? devices['Pixel 7']?.userAgent, }, }, { diff --git a/src/e2e/CareLeavers.E2ETests/playwright.config.ts b/src/e2e/CareLeavers.E2ETests/playwright.config.ts index c1ec246..a1a3c37 100644 --- a/src/e2e/CareLeavers.E2ETests/playwright.config.ts +++ b/src/e2e/CareLeavers.E2ETests/playwright.config.ts @@ -39,6 +39,9 @@ export default defineConfig({ use: { browserName: 'chromium', ...devices['Pixel 8'], + isMobile: true, + viewport: { width: 412, height: 914 }, + userAgent: devices['Pixel 8']?.userAgent ?? devices['Pixel 7']?.userAgent, }, }, { diff --git a/src/e2e/CareLeavers.E2ETests/src/helpers/urls-to-check.ts b/src/e2e/CareLeavers.E2ETests/src/helpers/urls-to-check.ts index 8c7d6a2..5fdbd7c 100644 --- a/src/e2e/CareLeavers.E2ETests/src/helpers/urls-to-check.ts +++ b/src/e2e/CareLeavers.E2ETests/src/helpers/urls-to-check.ts @@ -1,4 +1,12 @@ -export const pagesToTest = [ - '/home', // Home page - '/all-support', // About page -]; \ No newline at end of file +// List of pages that will have common functionality across the site +// such as WebsiteName Link, Navigation Bar, Cookies, and Footers +export const commonPagesToTest = [ + '/home', + '/all-support', +]; + +// List of helpline-related links to test-Only certain pages will have this link +export const helplineLinksToTest = [ + '/home', + '/all-support', +]; diff --git a/src/e2e/CareLeavers.E2ETests/src/pages/BasePage.ts b/src/e2e/CareLeavers.E2ETests/src/pages/BasePage.ts index 278bf2f..0a715aa 100644 --- a/src/e2e/CareLeavers.E2ETests/src/pages/BasePage.ts +++ b/src/e2e/CareLeavers.E2ETests/src/pages/BasePage.ts @@ -3,19 +3,74 @@ import { Page,Locator, expect, BrowserContext, Cookie } from '@playwright/test'; export class BasePage { protected readonly page: Page; + //Locator for the Website Title navigation Link + public readonly WebsiteNameLink: Locator; + // Locators for cookie banner and buttons public readonly cookieBanner: Locator; public readonly acceptButton: Locator; public readonly rejectButton: Locator; + //Locators for Navigation Bar + public readonly navLinkHome: Locator; + public readonly navLinkAllSupport: Locator; + public readonly navLinkYourRights: Locator; + public readonly navLinkLeavingCareGuides: Locator; + public readonly navLinkHelplines: Locator; + + //Locators for Navigation Bar-Mobile Menu + public readonly hamburgerMenuIcon: Locator; + public readonly mobileMenuLinks: Locator; + public readonly mobileMenuContainer: Locator; + public readonly closeMenuButton: Locator; + + //Locators for helplines-If you need Help at the bottom of the page + public readonly helplineLink: Locator; + public readonly ifYouNeedHelpSection: Locator; + + //Locators for web page Footers + public readonly footer: Locator; + public readonly footerLinks: Locator; + public readonly cookiePolicyLinkInFooter: Locator; + public readonly licenceLogo: Locator; + constructor(page: Page) { this.page = page; + //Locator for the Website Title navigation Link + this.WebsiteNameLink = page.locator('a.dfe-header__link--service').nth(1); + + // Locators for cookie banner and buttons this.cookieBanner = page.locator('.govuk-cookie-banner'); this.acceptButton = page.locator('#accept-cookie'); - this.rejectButton = page.locator('#reject-cookie'); + this.rejectButton = page.locator('#reject-cookie'); + + //Locators for Navigation Bar + this.navLinkHome = page.locator('a.dfe-header__navigation-link', { hasText: "Home" }); + this.navLinkAllSupport = page.locator('a.dfe-header__navigation-link', { hasText: "All support" }); + //update locators + this.navLinkYourRights = page.locator('[role="link"][aria-label="Your rights"]'); + this.navLinkLeavingCareGuides = page.locator('[role="link"][aria-label="Leaving care guides"]'); + this.navLinkHelplines = page.locator('[role="link"][aria-label="Helplines"]'); + + //Locators for Navigation Bar-Mobile Menu + this.hamburgerMenuIcon = page.locator('#menu-toggle'); + this.mobileMenuContainer = page.locator('#header-navigation'); + this.mobileMenuLinks = page.locator('.dfe-header__navigation-list a'); + this.closeMenuButton = page.locator('#close-menu'); + + //Locators for helplines-If you need Help at the bottom of the page + this.helplineLink = page.locator('p.govuk-body a.govuk-hyperlink'); + this.ifYouNeedHelpSection = page.locator('#If-you-need-help-now'); + + //Locators for web page Footers + this.footer = page.locator('footer'); + this.footerLinks = page.locator('footer a'); + this.cookiePolicyLinkInFooter = page.locator('a.govuk-footer__link[href="/pages/cookie-policy"]'); + this.licenceLogo = page.locator('svg.govuk-footer__licence-logo'); + } - // Navigation method + // Navigates to the specified URL and waits for the page to load. async navigateTo(url: string) { await this.page.goto(url, { waitUntil: 'networkidle' }); } @@ -36,7 +91,7 @@ export class BasePage { await expect(this.cookieBanner).not.toBeVisible(); } async rejectCookies() { - await expect(this.rejectButton).toBeVisible({ timeout: 10000 }); + await expect(this.rejectButton).toBeVisible(); await this.rejectButton.click(); // Ensure the banner disappears await expect(this.cookieBanner).not.toBeVisible(); @@ -71,11 +126,102 @@ export class BasePage { value: 'expired', domain: new URL(baseURL).hostname, // Extract domain from BASE_URL path: '/', - expires: Date.now() / 1000 - 10, // Set to past time to expire + expires: Date.now() / 1000 - 10, // Set to Past time to expire secure: true, httpOnly: true, sameSite: 'Strict' } ]); } + + // Navigation Bar functionality + // Helper method to ensure the menu is visible and reopens it if needed + async ensureMenuIsVisible() { + // Check if the menu is visible, if not, click the hamburger menu to open it + const isMenuVisible = await this.mobileMenuContainer.isVisible(); + if (!isMenuVisible) { + await this.hamburgerMenuIcon.click(); + await expect(this.mobileMenuContainer).toBeVisible(); // Ensure it becomes visible + } + } + + //Verify Navigation Bar functionality + async verifyNavigation(isDesktop: boolean) { + if (isDesktop) { + // Verify desktop navigation is visible + await expect(this.page.locator('#header-navigation')).toBeVisible(); + + const navLinks = [this.navLinkHome, this.navLinkAllSupport /* add other nav links here */]; + for (const link of navLinks) { + const href = await link.getAttribute('href'); + if (!href) throw new Error('Link does not have an href attribute'); + + await link.click(); + await this.page.waitForURL(new RegExp(href)); + } + } + else { + // Click on the hamburger menu to open the mobile menu + await expect(this.hamburgerMenuIcon).toBeVisible(); + await this.hamburgerMenuIcon.click(); + + // Wait and verify that the mobile menu is visible + await expect(this.mobileMenuContainer).toBeVisible(); + + // Verify the mobile menu links + const mobileLinksCount = await this.mobileMenuLinks.count(); + expect(mobileLinksCount).toBeGreaterThan(0); + + // Close the mobile menu + await expect(this.closeMenuButton).toBeVisible(); + await this.closeMenuButton.click(); + + // Ensure the menu is closed + await expect(this.mobileMenuContainer).not.toBeVisible(); + + // click each link and ensure the menu is visible each time + const links = [ + { index: 0, href: '/home' }, + { index: 1, href: '/all-support' }, + /*{ index: 2, href: '/status' }, + { index: 3, href: '/guides-advice' }, + { index: 4, href: '/helplines' },*/ + ]; + + for (const link of links) { + await this.ensureMenuIsVisible(); // Ensure the menu is visible before clicking + await expect(this.mobileMenuLinks.nth(link.index)).toHaveAttribute('href', link.href); + await this.mobileMenuLinks.nth(link.index).click(); + await this.page.waitForURL(new RegExp(link.href)); + } + } + } + + async verifyFooterLinks() { + //Ensure the footer is visible + await expect(this.footer).toBeVisible(); + + // Verify the "Cookie Policy" link(in Footer) + const cookiePolicyLink = this.footer.locator('a.govuk-footer__link[href="/pages/cookie-policy"]'); + await expect(this.cookiePolicyLinkInFooter).toBeVisible(); + await expect(this.cookiePolicyLinkInFooter).toContainText('Cookie Policy'); + await expect(this.cookiePolicyLinkInFooter).toHaveAttribute('href', '/pages/cookie-policy'); + + // Verify the footer logo and licence description + await expect(this.licenceLogo).toBeVisible(); + const licenceDescription = this.footer.locator('.govuk-footer__licence-description'); + await expect(licenceDescription).toBeVisible(); + await expect(licenceDescription).toContainText(/All content is available under the/); + + // Verify the Footer links-Crown copyright link and Open Government Licence link + const footerLinksCount = await this.footerLinks.count(); + expect(footerLinksCount).toBeGreaterThan(0); + + for (let i = 0; i < footerLinksCount; i++) { + const link = this.footerLinks.nth(i); + await expect(link).toBeVisible(); + const href = await link.getAttribute('href'); + expect(href).not.toBeNull(); + } + } } diff --git a/src/e2e/CareLeavers.E2ETests/src/pages/HomePage.ts b/src/e2e/CareLeavers.E2ETests/src/pages/HomePage.ts index b166617..29b7549 100644 --- a/src/e2e/CareLeavers.E2ETests/src/pages/HomePage.ts +++ b/src/e2e/CareLeavers.E2ETests/src/pages/HomePage.ts @@ -1,56 +1,39 @@ import { Page, Locator, expect } from '@playwright/test'; import { BasePage } from './BasePage'; -import exp from "node:constants"; export class HomePage extends BasePage { - private supportForCareLeaversLink: Locator; + // Main Header Sections Locators private mainHeading: Locator; private firstHeaderParagraph: Locator; - private footer: Locator; - private supportHeading: Locator; + + //Sections Locators private whoIsThisForSection: Locator; private findSupportSection: Locator; - private helpfulGuidesSection: Locator; - private ifYouNeedHelpSection: Locator; - private helplineLink: Locator; - private footerLinks: Locator; - private homeNavLink: Locator; - private supportForCareLeaversNav: Locator; - private yourRightsNav: Locator; - private leavingCareGuidesNav: Locator; - private helplinesNav: Locator; + private knowWhatSupportSection: Locator; + private GuidesSection: Locator; + + //Support cards Sections private supportCards: Locator; constructor(page: Page) { super(page); - //Website title - this.supportForCareLeaversLink = page.locator('a.dfe-header__link--service').nth(1); - - let headerSection = page.locator('div#main-header-container') - let contentSection = page.locator('div#main-content-container') - + // Main Header section this.mainHeading = page.locator('h1'); - this.firstHeaderParagraph = headerSection.locator('p.govuk-body').first(); - this.footer = page.locator('footer'); this.supportHeading = page.locator('h1.govuk-heading-xl'); + let headerSection = page.locator('div#main-header-container') + this.firstHeaderParagraph = headerSection.locator('p.govuk-body').first(); + + // Main Content Sections this.whoIsThisForSection = page.locator('#Who-is-this-support-for-'); this.findSupportSection = page.locator('#Find-the-right-support'); - this.ifYouNeedHelpSection = page.locator('#If-you-need-help-now'); - this.helplinesNav = page.locator('[role="link"][aria-label="Helplines"]'); - this.helplineLink = page.locator('p.govuk-body a.govuk-hyperlink'); - //update locators - this.helpfulGuidesSection = page.locator('#helpful-guides'); - this.footerLinks = page.locator('footer a'); - this.homeNavLink = page.locator('a.dfe-header__navigation-link', { hasText: "Home" }); - this.supportForCareLeaversNav = page.locator('a.dfe-header__navigation-link', { hasText: "All support" }); - //update locators - this.yourRightsNav = page.locator('[role="link"][aria-label="Your rights"]'); - this.leavingCareGuidesNav = page.locator('[role="link"][aria-label="Leaving care guides"]'); + this.knowWhatSupportSection = page.locator('#know-what-support');//update locators + this.GuidesSection = page.locator('#helpful-guides');//update locators + // Generic locator for all cards on the home page this.supportCards = page.locator('.hf-card-container'); - + } async openHomePage() { @@ -60,66 +43,27 @@ export class HomePage extends BasePage { async assertPageElements() { await this.validateURLContains('/home'); - - await expect(this.supportForCareLeaversLink).toHaveText(/Support for/i); + // Check if the main heading is visible await expect(this.mainHeading).toHaveText("Get support if you've been in care"); + + // Validate first paragraph await expect(this.firstHeaderParagraph).toContainText("Starting life as an adult can be challenging"); + + // Check if the "who is this for" section is visible await expect(this.whoIsThisForSection).toContainText('support for'); - // Check if the element has a specific class await expect(this.page.locator('#Who-is-this-support-for-')).toHaveClass(/govuk-heading-l/); - - await expect(this.footer).toContainText("Open Government Licence v3.0"); - //to add back when the helpine link is added to mock - // await expect(this.helplineLink).toHaveAttribute('href', 'helplines'); - } async verifySectionsVisibility() { - await expect(this.supportForCareLeaversLink).toBeVisible(); await expect(this.supportHeading).toBeVisible(); + await expect(this.firstHeaderParagraph).toBeVisible(); await expect(this.whoIsThisForSection).toBeVisible(); await expect(this.findSupportSection).toBeVisible(); - await expect(this.ifYouNeedHelpSection).toBeVisible(); - //to add back when the helpine link is added to mock - //await expect(this.helplineLink).toBeVisible(); - /* await expect(this.whatSupportCanYouGetSection).toBeVisible(); await expect(this.helpfulGuidesSection).toBeVisible(); */ } - - async verifyFooterLinks() { - const footerLinksCount = await this.footerLinks.count(); - expect(footerLinksCount).toBeGreaterThan(0); - - for (let i = 0; i < footerLinksCount; i++) { - const link = this.footerLinks.nth(i); - await expect(link).toBeVisible(); - const href = await link.getAttribute('href'); - expect(href).not.toBeNull(); - } - } - - async verifyNavigation() { - - await this.homeNavLink.click(); - await this.page.waitForURL(/\/home/); - - await this.supportForCareLeaversNav.click(); - await this.page.waitForURL(/\/all-support/); - - /* update locators - await this.yourRightsNav.click(); - await this.page.waitForURL(/\/your-rights/); - - await this.leavingCareGuidesNav.click(); - await this.page.waitForURL(/\/leaving-care/); - - await this.helplinesNav.click(); - await this.page.waitForURL(/\/helplines/); - */ - } async clickSupportCard(cardTitle: string, expectedUrl: string) { // Find the card with the matching title and Click diff --git a/src/e2e/CareLeavers.E2ETests/src/tests/cookies.spec.ts b/src/e2e/CareLeavers.E2ETests/src/tests/Cookies.spec.ts similarity index 93% rename from src/e2e/CareLeavers.E2ETests/src/tests/cookies.spec.ts rename to src/e2e/CareLeavers.E2ETests/src/tests/Cookies.spec.ts index 6050d51..b6a3f95 100644 --- a/src/e2e/CareLeavers.E2ETests/src/tests/cookies.spec.ts +++ b/src/e2e/CareLeavers.E2ETests/src/tests/Cookies.spec.ts @@ -1,10 +1,10 @@ import { test, expect } from '@playwright/test'; import { BasePage } from '../pages/BasePage'; -import { pagesToTest } from '../helpers/urls-to-check'; +import { commonPagesToTest } from '../helpers/urls-to-check'; // Main test to validate cookie banner test.describe('Cookie Banner Functionality', () => { - pagesToTest.forEach((path) => { + commonPagesToTest.forEach((path) => { test(`Validate cookie banner on ${path}`, async ({ page, context }) => { const basePage = new BasePage(page); @@ -31,7 +31,7 @@ test.describe('Cookie Banner Functionality', () => { // Test to reject cookies test.describe('Reject Cookie Functionality', () => { - pagesToTest.forEach((path) => { + commonPagesToTest.forEach((path) => { test(`Reject cookie banner on ${path}`, async ({ page, context }) => { const basePage = new BasePage(page); diff --git a/src/e2e/CareLeavers.E2ETests/src/tests/HomePage.spec.ts b/src/e2e/CareLeavers.E2ETests/src/tests/HomePage.spec.ts index a1c854d..7890a01 100644 --- a/src/e2e/CareLeavers.E2ETests/src/tests/HomePage.spec.ts +++ b/src/e2e/CareLeavers.E2ETests/src/tests/HomePage.spec.ts @@ -12,15 +12,7 @@ test.describe('Home Page Tests', () => { test('should verify all main sections are present', async () => { await homePage.verifySectionsVisibility(); }); - - /*test('should verify navigation works for each link', async () => { - await homePage.verifyNavigation(); - });*/ - - test('should validate footer links', async () => { - await homePage.verifyFooterLinks(); - }); - + test('should assert page elements are correct', async () => { await homePage.assertPageElements(); }); diff --git a/src/e2e/CareLeavers.E2ETests/src/tests/SharedLinks.spec.ts b/src/e2e/CareLeavers.E2ETests/src/tests/SharedLinks.spec.ts new file mode 100644 index 0000000..c512196 --- /dev/null +++ b/src/e2e/CareLeavers.E2ETests/src/tests/SharedLinks.spec.ts @@ -0,0 +1,65 @@ +import { test, expect } from '@playwright/test'; +import { BasePage } from '../pages/BasePage'; +import { commonPagesToTest, helplineLinksToTest } from '../helpers/urls-to-check'; + +// Defining a hook that runs before each test to create the basePage +test.describe('Shared Website Functionalities', () => { + let basePage: BasePage; + + test.beforeEach(async ({ page }) => { + // Instantiate BasePage for each test + basePage = new BasePage(page); + }); + + // Test to validate WebsiteNameLink + test.describe('Navigation Links Functionality', () => { + commonPagesToTest.forEach((path) => { + test(`Validate navigation links on ${path}`, async () => { + // Navigate to page & check that WebsiteNameLink is visible + await basePage.navigateTo(path); + await expect(basePage.WebsiteNameLink).toHaveText(/Support for/i); + await expect(basePage.WebsiteNameLink).toBeVisible(); + }); + }); + }); + + // Test to validate navigation bar links including Menu button on Mobile Devices + test.describe('Navigation Bar Functionality', () => { + commonPagesToTest.forEach((path) => { + test(`Validate Navigation Bar works for each link on ${path}`, async ({ page }) => { + + // Check if the device is desktop or mobile + const isDesktop = page.viewportSize()?.width ? page.viewportSize()!.width > 600 : false; + await basePage.navigateTo(path); + await basePage.verifyNavigation(isDesktop); + }); + }); + }); + + // Test to validate footer links + test.describe('Footer Links Functionality', () => { + commonPagesToTest.forEach((path) => { + test(`Validate footer links on ${path}`, async () => { + // Navigate to page & check that footer links are visible + await basePage.navigateTo(path); + await expect(basePage.footer).toContainText("Open Government Licence v3.0"); + await basePage.verifyFooterLinks(); + }); + }); + }); + + /*commented for now until the mocks are updated to include this + // Test to validate helpline links + test.describe('Helpline Links Functionality', () => { + helplineLinksToTest.forEach((path) => { + test(`Validate helpline links on ${path}`, async () => { + // Navigate to page & check that helpline links are visible + await basePage.navigateTo(path); + await expect(basePage.ifYouNeedHelpSection).toBeVisible(); + await expect(basePage.helplineLink).toHaveAttribute('href', 'helplines'); + await expect(basePage.helplineLink).toBeVisible(); + }); + }); + }); + */ +});