Skip to content

Commit

Permalink
Refactor and enhance dropdown functionality and tests
Browse files Browse the repository at this point in the history
1. Dropdown Components:
   - Add  class to DropdownBase.vue.
   - Add  class to DropdownLanguage.vue.

2. Component Objects:
   - BaseComponent.ts: Import and use  utility function.
   - HeaderWebsite.ts:
     - Add locators for HAMBURGER, SIDEBAR, SELECTED_LANGUAGE, LANGUAGE_MENU, and LANGUAGE_OPTIONS.
     - Implement methods: , , , , , , .

3. Page Objects:
   - BasePage.ts:
     - Import and use  utility function.
     - Add  method.

4. Test Specifications:
   - landing-page.spec.ts:
     - Remove console log from the title test.
     - Refactor theme and language dropdown tests to enhance functionality and readability.

5. Utility Functions:
   - Create  with  function.
  • Loading branch information
github-actions[bot] committed May 23, 2024
1 parent 9f03561 commit 70964e7
Show file tree
Hide file tree
Showing 7 changed files with 116 additions and 19 deletions.
2 changes: 1 addition & 1 deletion frontend/components/dropdown/DropdownBase.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<MenuButton
@focus="expandOnFocus"
v-slot="{ open }"
class="style-btn inline-flex w-full select-none whitespace-nowrap rounded-md px-4 py-2 font-semibold"
class="selected-option style-btn inline-flex w-full select-none whitespace-nowrap rounded-md px-4 py-2 font-semibold"
:class="{
'pl-6': isSideMenu,
'style-menu-option-cta flex items-center rounded-md pl-1':
Expand Down
1 change: 1 addition & 0 deletions frontend/components/dropdown/DropdownLanguage.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
<NuxtLink
v-for="l in availableLocales"
:key="getLocaleCode(l)"
class="dropdown-language-list-items"
:to="switchLocalePath(getLocaleCode(l))"
>
<MenuItem v-slot="{ active }" class="flex">
Expand Down
5 changes: 5 additions & 0 deletions frontend/tests/component-objects/BaseComponent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Page, Locator } from "@playwright/test";
import { isMobile } from "../utils/utils";

export default abstract class BaseComponent {
protected readonly page: Page;
Expand All @@ -8,6 +9,10 @@ export default abstract class BaseComponent {
this.page = page;
}

public async isMobile(): Promise<boolean> {
return isMobile(this.page);
}

protected setLocators(locators: Record<string, string>): void {
this.locators = locators;
}
Expand Down
76 changes: 75 additions & 1 deletion frontend/tests/component-objects/HeaderWebsite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,14 @@ export default class HeaderWebsite extends BaseComponent {
ROADMAP_BUTTON: "#desktop-header #btn-roadmap",
GET_IN_TOUCH_BUTTON:
"#btn-get-in-touch-large:visible, #btn-get-in-touch-medium:visible",
HAMBURGER: "#sidebar-right-hamburger:visible",
SIDEBAR: "#drawer-navigation",
THEME_DROPDOWN: ".dropdown-theme:visible",
SELECTED_LANGUAGE: ".dropdown-language:visible .selected-option",
LANGUAGE_DROPDOWN: ".dropdown-language:visible",
LANGUAGE_MENU: ".dropdown-language:visible ul",
LANGUAGE_OPTIONS:
".dropdown-language:visible .dropdown-language-list-items",
};

constructor(page: Page) {
Expand Down Expand Up @@ -37,30 +43,98 @@ export default class HeaderWebsite extends BaseComponent {
return this.getLocator("GET_IN_TOUCH_BUTTON");
}

get hamburger(): Locator {
return this.getLocator("HAMBURGER");
}

get sidebar(): Locator {
return this.getLocator("SIDEBAR");
}

async openSidebar(): Promise<void> {
if (!(await this.sidebar.isVisible())) {
await this.hamburger.click();
}
}

async closeSidebar(): Promise<void> {
if (await this.sidebar.isVisible()) {
await this.hamburger.click();
}
}

async selectDropdownOption(
dropdown: Locator,
optionText: string
): Promise<void> {
await dropdown.click();
await this.page.locator(`text=${optionText}`).click();
}

get themeDropdown(): Locator {
return this.getLocator("THEME_DROPDOWN");
}

async openThemeDropdown(): Promise<void> {
if (await this.isMobile()) {
await this.openSidebar();
}
await this.themeDropdown.click();
}

async selectThemeOption(theme: string): Promise<void> {
await this.openThemeDropdown();
await this.selectDropdownOption(this.themeDropdown, theme);
}

get languageDropdown(): Locator {
return this.getLocator("LANGUAGE_DROPDOWN");
}

async openLanguageDropdown(): Promise<void> {
if (await this.isMobile()) {
await this.openSidebar();
}
const isDropdownOpen = await this.getLocator("LANGUAGE_MENU").isVisible();
if (!isDropdownOpen) {
await this.languageDropdown.click();
}
}

async selectLanguageOption(language: string): Promise<void> {
await this.openLanguageDropdown();
await this.selectDropdownOption(this.languageDropdown, language);
}

async getSelectedLanguage(): Promise<string> {
await this.openLanguageDropdown();
return (
await this.page
.locator(HeaderWebsite.locators.SELECTED_LANGUAGE)
.innerText()
)
.trim()
.toLowerCase();
}

async getLanguageOptions(): Promise<Locator[]> {
await this.openLanguageDropdown();
const languageOptions = await this.getLocator("LANGUAGE_OPTIONS").all();
return languageOptions;
}

async findLanguageOption(
languageOptions: Locator[],
optionText: string
): Promise<Locator | undefined> {
for (const option of languageOptions) {
const textContent = await option.innerText();
if (textContent.includes(optionText)) {
return option;
}
}
return undefined;
}

async navigateTo(link: Locator): Promise<void> {
await link.click();
}
Expand Down
8 changes: 6 additions & 2 deletions frontend/tests/page-objects/BasePage.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type { Page, Locator } from "@playwright/test";
import { isMobile } from "../utils/utils";
export default abstract class BasePage {
protected readonly pageName: string;
protected readonly pageURL: string;
Expand All @@ -25,8 +26,7 @@ export default abstract class BasePage {
}

public async isMobile(): Promise<boolean> {
const viewportSize = await this.page.viewportSize();
return viewportSize !== null && viewportSize.width < 768;
return isMobile(this.page);
}

public async waitForUrlChange(
Expand All @@ -37,6 +37,10 @@ export default abstract class BasePage {
await this.page.waitForURL(expectedUrlPattern, { timeout });
}

public async currentTheme(): Promise<string> {
return (await this.page.locator("html").getAttribute("class")) ?? "";
}

protected setLocators(locators: Record<string, string>): void {
this.locators = locators;
}
Expand Down
37 changes: 22 additions & 15 deletions frontend/tests/specs/landing-page.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import AxeBuilder from "@axe-core/playwright";
import { LandingPage, expect, test } from "../fixtures/page-fixtures";
import locales from "../../locales";

test.describe("Landing Page", () => {
// Initialize page before each test, wait for the landing splash to be visible.
Expand Down Expand Up @@ -60,24 +61,31 @@ test.describe("Landing Page", () => {

// Test that the theme dropdown is visible and functional.
test("Theme dropdown is functional", async ({ landingPage }) => {
const themeDropdown = landingPage.header.themeDropdown;
await expect(themeDropdown).toBeVisible();
await landingPage.header.selectThemeOption("Light");
expect(await landingPage.getPage.getAttribute("html", "class")).toBe(
"light"
);
await landingPage.header.selectThemeOption("Dark");
expect(await landingPage.getPage.getAttribute("html", "class")).toBe(
"dark"
);
const themes = ["light", "dark"];
for (const theme of themes) {
await landingPage.header.selectThemeOption(theme);
const currentTheme = await landingPage.currentTheme();
expect(currentTheme).toContain(theme);
}
});

// Test that the language dropdown is visible and functional.
test("Language dropdown is functional", async ({ landingPage }) => {
const languageDropdown = landingPage.header.languageDropdown;
await expect(languageDropdown).toBeVisible();
await landingPage.header.selectLanguageOption("English");
await landingPage.header.selectLanguageOption("Español");
const selectedLanguage = await landingPage.header.getSelectedLanguage();
const languageOptions = await landingPage.header.getLanguageOptions();

for (const locale of locales) {
if (locale.code === selectedLanguage) {
continue;
}
const optionText = locale.name;
const option = await landingPage.header.findLanguageOption(
languageOptions,
optionText
);
const langOptionIsVisible = await option?.isVisible();
expect(langOptionIsVisible).toBe(true);
}
});

/* *********************************************************** */
Expand Down Expand Up @@ -106,7 +114,6 @@ test.describe("Landing Page", () => {

test('title should contain "activist"', async ({ landingPage }) => {
const pageTitle = await landingPage.getPage.title();
console.log("Page Title:", pageTitle);
expect(pageTitle).toContain("activist");
});

Expand Down
6 changes: 6 additions & 0 deletions frontend/tests/utils/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import type { Page } from "@playwright/test";

export async function isMobile(page: Page): Promise<boolean> {
const viewportSize = page.viewportSize();
return viewportSize !== null && viewportSize.width < 768;
}

0 comments on commit 70964e7

Please sign in to comment.