From 9b44bc37f7b66bc153688bab547f3b68ea0e369a Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 14:59:44 +0200 Subject: [PATCH 01/12] implement infra --- .gitignore | 2 + ui/package-lock.json | 62 +++++++++++++++++++++++ ui/package.json | 2 + ui/playwright.config.ts | 47 +++++++++++++++++ ui/tests/infra/ui/basePage.ts | 22 ++++++++ ui/tests/infra/ui/browserWrapper.ts | 78 +++++++++++++++++++++++++++++ 6 files changed, 213 insertions(+) create mode 100644 ui/playwright.config.ts create mode 100644 ui/tests/infra/ui/basePage.ts create mode 100644 ui/tests/infra/ui/browserWrapper.ts diff --git a/.gitignore b/.gitignore index 0138b47..f9b2f24 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,5 @@ falkor-metrics*.json neo4j-metrics*.json html .DS_Store +/ui/playwright-report +/ui/test-results diff --git a/ui/package-lock.json b/ui/package-lock.json index 4d063fe..71993c2 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -25,6 +25,7 @@ "clsx": "^2.1.1", "lucide-react": "^0.469.0", "next": "15.1.3", + "playwright": "^1.49.1", "react": "^19.0.0", "react-chartjs-2": "^5.3.0", "react-dom": "^19.0.0", @@ -35,6 +36,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", + "@playwright/test": "^1.49.1", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", @@ -929,6 +931,22 @@ "node": ">=14" } }, + "node_modules/@playwright/test": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.49.1.tgz", + "integrity": "sha512-Ky+BVzPz8pL6PQxHqNRW1k3mIyv933LML7HktS8uik0bUXNCdPhoS/kLihiO1tMf/egaJb4IutXd7UywvXEW+g==", + "devOptional": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.49.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/@radix-ui/primitive": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.1.tgz", @@ -5717,6 +5735,50 @@ "node": ">= 6" } }, + "node_modules/playwright": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.49.1.tgz", + "integrity": "sha512-VYL8zLoNTBxVOrJBbDuRgDWa3i+mfQgDTrL8Ah9QXZ7ax4Dsj0MSq5bYgytRnDVVe+njoKnfsYkH3HzqVj5UZA==", + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.49.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.49.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.49.1.tgz", + "integrity": "sha512-BzmpVcs4kE2CH15rWfzpjzVGhWERJfmnXmniSyKeRZUs9Ws65m+RGIi7mjJK/euCegfn3i7jvqWeWyHe9y3Vgg==", + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/playwright/node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", diff --git a/ui/package.json b/ui/package.json index afe8de2..e6a980e 100644 --- a/ui/package.json +++ b/ui/package.json @@ -26,6 +26,7 @@ "clsx": "^2.1.1", "lucide-react": "^0.469.0", "next": "15.1.3", + "playwright": "^1.49.1", "react": "^19.0.0", "react-chartjs-2": "^5.3.0", "react-dom": "^19.0.0", @@ -36,6 +37,7 @@ }, "devDependencies": { "@eslint/eslintrc": "^3", + "@playwright/test": "^1.49.1", "@types/node": "^20", "@types/react": "^19", "@types/react-dom": "^19", diff --git a/ui/playwright.config.ts b/ui/playwright.config.ts new file mode 100644 index 0000000..5e4f6ae --- /dev/null +++ b/ui/playwright.config.ts @@ -0,0 +1,47 @@ +import { defineConfig, devices } from '@playwright/test'; + +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +// import dotenv from 'dotenv'; +// import path from 'path'; +// dotenv.config({ path: path.resolve(__dirname, '.env') }); + +/** + * See https://playwright.dev/docs/test-configuration. + */ +export default defineConfig({ + testDir: './tests/tests', + /* Run tests in files in parallel */ + fullyParallel: true, + /* Fail the build on CI if you accidentally left test.only in the source code. */ + forbidOnly: !!process.env.CI, + /* Retry on CI only */ + retries: process.env.CI ? 2 : 0, + /* Opt out of parallel tests on CI. */ + workers: process.env.CI ? 2 : undefined, + /* Reporter to use. See https://playwright.dev/docs/test-reporters */ + reporter: 'html', + /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ + use: { + /* Base URL to use in actions like `await page.goto('/')`. */ + // baseURL: 'http://127.0.0.1:3000', + + /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ + trace: 'on-first-retry', + }, + + /* Configure projects for major browsers */ + projects: [ + { + name: 'chromium', + use: { ...devices['Desktop Chrome'] }, + }, + + { + name: 'firefox', + use: { ...devices['Desktop Firefox'] }, + }, + ], +}); \ No newline at end of file diff --git a/ui/tests/infra/ui/basePage.ts b/ui/tests/infra/ui/basePage.ts new file mode 100644 index 0000000..69baf60 --- /dev/null +++ b/ui/tests/infra/ui/basePage.ts @@ -0,0 +1,22 @@ +import { Page } from 'playwright'; + +export default class BasePage { + protected page: Page; + + constructor(page: Page) { + this.page = page; + } + + async initPage(){ + await this.page.waitForLoadState() + } + + getCurrentURL() : string { + return this.page.url(); + } + + async refreshPage(){ + await this.page.reload({ waitUntil: 'networkidle' }); + } + +} \ No newline at end of file diff --git a/ui/tests/infra/ui/browserWrapper.ts b/ui/tests/infra/ui/browserWrapper.ts new file mode 100644 index 0000000..0d8c5f6 --- /dev/null +++ b/ui/tests/infra/ui/browserWrapper.ts @@ -0,0 +1,78 @@ +import { chromium, firefox, Browser, BrowserContext, Page } from 'playwright'; +import BasePage from './basePage'; +import { test } from '@playwright/test'; + +export default class BrowserWrapper { + + private browser: Browser | null = null; + + private context: BrowserContext | null = null; + + private page: Page | null = null; + + async createNewPage(PageClass: new (page: Page) => T, url?: string) { + if (!this.browser) { + const projectName = test.info().project.name; + this.browser = await this.launchBrowser(projectName); + } + if (!this.context) { + this.context = await this.browser.newContext(); + } + if (!this.page) { + this.page = await this.context.newPage(); + } + if (url) { + await this.navigateTo(url) + } + + const pageInstance = new PageClass(this.page); + return pageInstance; + } + + private async launchBrowser(projectName: string): Promise { + switch (projectName) { + case 'firefox': + return await firefox.launch(); + case 'chromium': + default: + return await chromium.launch(); + } + } + + async getPage() { + if (!this.page) { + throw new Error('Browser is not launched yet!'); + } + return this.page; + } + + async setPageToFullScreen() { + if (!this.page) { + throw new Error('Browser is not launched yet!'); + } + await this.page.setViewportSize({ width: 1920, height: 1080 }); + } + + async navigateTo(url: string) { + if (!this.page) { + throw new Error('Browser is not launched yet!'); + } + await this.page.goto(url); + await this.page.waitForLoadState('networkidle'); + } + + async closePage() { + if (this.page) { + await this.page.close(); + } else { + this.page = null; + } + } + + async closeBrowser() { + if (this.browser) { + await this.browser.close(); + } + } + +} From 1bbbbf98611992b2725bf5b55293cdc5bef5eb15 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:23:34 +0200 Subject: [PATCH 02/12] implementing pom and header spec --- ui/tests/config/urls.json | 12 ++++++++++++ ui/tests/logic/POM/mainPage.ts | 23 +++++++++++++++++++++++ ui/tests/tests/header.spec.ts | 22 ++++++++++++++++++++++ 3 files changed, 57 insertions(+) create mode 100644 ui/tests/config/urls.json create mode 100644 ui/tests/logic/POM/mainPage.ts create mode 100644 ui/tests/tests/header.spec.ts diff --git a/ui/tests/config/urls.json b/ui/tests/config/urls.json new file mode 100644 index 0000000..65ded7f --- /dev/null +++ b/ui/tests/config/urls.json @@ -0,0 +1,12 @@ +{ + "baseUrl": "http://localhost:3000/", + "falkorDBUrl": "https://www.falkordb.com/", + "benchmarkGithubUrl": "https://github.com/FalkorDB/benchmark", + "falkordbDiscordUrl": "https://discord.com/invite/99y2Ubh6tg", + "signUpUrl": "https://app.falkordb.cloud/signup", + "startFreeUrl": "https://www.falkordb.com/try-free/", + "DatasetUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md#data", + "ReadmeUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md", + "FAQUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md", + "runBenchmarkWithYourDataUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md#installation-steps" +} \ No newline at end of file diff --git a/ui/tests/logic/POM/mainPage.ts b/ui/tests/logic/POM/mainPage.ts new file mode 100644 index 0000000..6cb571b --- /dev/null +++ b/ui/tests/logic/POM/mainPage.ts @@ -0,0 +1,23 @@ + +import { Locator, Page } from "playwright"; +import BasePage from "../../infra/ui/basePage"; + +export default class NavBarComponent extends BasePage { + + private get falkorDBLogo(): Locator { + return this.page.locator("//header//img[@alt='FalkorDB']") + } + + async clickOnFalkorLogo(): Promise { + await this.falkorDBLogo.click(); + } + + async clickOnFalkor(): Promise { + await this.page.waitForLoadState('networkidle'); + const [newPage] = await Promise.all([ + this.page.waitForEvent('popup'), + this.clickOnFalkorLogo(), + ]); + return newPage + } +} \ No newline at end of file diff --git a/ui/tests/tests/header.spec.ts b/ui/tests/tests/header.spec.ts new file mode 100644 index 0000000..f94b731 --- /dev/null +++ b/ui/tests/tests/header.spec.ts @@ -0,0 +1,22 @@ +import { test, expect } from '@playwright/test'; +import BrowserWrapper from '../infra/ui/browserWrapper'; +import MainPage from '../logic/POM/mainPage'; +import urls from '../config/urls.json'; + +test.describe(' Navbar tests', () => { + let browser: BrowserWrapper; + + test.beforeAll(async () => { + browser = new BrowserWrapper(); + }); + + test.afterAll(async () => { + await browser.closeBrowser(); + }); + + test("Verify clicking on falkordb logo redirects to specified URL", async () => { + const header = await browser.createNewPage(MainPage, urls.baseUrl) + const page = await header.clickOnFalkor(); + expect(page.url()).toBe(urls.falkorDBUrl) + }) +}); \ No newline at end of file From 8b11ae9bd8d1541dadc5353d47e5b3c0dbae9321 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:31:17 +0200 Subject: [PATCH 03/12] add playwright ci --- .github/workflows/playwright.yml | 41 ++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/playwright.yml diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000..c065ec6 --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,41 @@ +name: Playwright Tests + +on: + push: + branches: [main, staging] + pull_request: + branches: [main, staging] + +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: lts/* + + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Set up environment and run tests + run: | + npm install + npm run build + npm start & + npx playwright test --reporter=dot,list + + # Step 6: Upload Playwright report + - name: Upload Playwright report + uses: actions/upload-artifact@v4 + if: ${{ always() }} + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 From 8ea0ef84b81ec09efd3370dcf47838b12bae5db6 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:40:03 +0200 Subject: [PATCH 04/12] fix CI workflow --- .github/workflows/playwright.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index c065ec6..9dc95a7 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -2,9 +2,9 @@ name: Playwright Tests on: push: - branches: [main, staging] + branches: master pull_request: - branches: [main, staging] + branches: master jobs: test: From b5ee828c67819fbc72a55c29d9eb3c49a8ff0a87 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:57:57 +0200 Subject: [PATCH 05/12] fix ci --- .github/workflows/playwright.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index 9dc95a7..b6674d6 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -10,6 +10,10 @@ jobs: test: timeout-minutes: 60 runs-on: ubuntu-latest + + defaults: + run: + working-directory: ./ui steps: - name: Checkout repository @@ -37,5 +41,5 @@ jobs: if: ${{ always() }} with: name: playwright-report - path: playwright-report/ + path: ui/playwright-report/ retention-days: 30 From 58f13d67a8d0fe5e39a750beffb2d36468385f23 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:56:24 +0200 Subject: [PATCH 06/12] adding tests (#12, #13, #14, #15, #16, #17) --- ui/app/components/footer.tsx | 3 +++ ui/app/components/header.tsx | 2 ++ ui/tests/config/testData.ts | 9 +++++++++ ui/tests/logic/POM/mainPage.ts | 30 ++++++++++++++++++++++++++++++ ui/tests/tests/header.spec.ts | 17 +++++++++++++++++ 5 files changed, 61 insertions(+) create mode 100644 ui/tests/config/testData.ts diff --git a/ui/app/components/footer.tsx b/ui/app/components/footer.tsx index e773472..0800eaf 100644 --- a/ui/app/components/footer.tsx +++ b/ui/app/components/footer.tsx @@ -7,6 +7,7 @@ const FooterComponent = () => { DATASET USED @@ -23,6 +24,7 @@ const FooterComponent = () => { README @@ -31,6 +33,7 @@ const FooterComponent = () => { FAQ diff --git a/ui/app/components/header.tsx b/ui/app/components/header.tsx index 677ae67..ab648d1 100644 --- a/ui/app/components/header.tsx +++ b/ui/app/components/header.tsx @@ -47,12 +47,14 @@ export function Header() { Sign up Start Free diff --git a/ui/tests/config/testData.ts b/ui/tests/config/testData.ts new file mode 100644 index 0000000..41febe4 --- /dev/null +++ b/ui/tests/config/testData.ts @@ -0,0 +1,9 @@ +import urls from '../config/urls.json'; + +export const navitems: { navItem: string; expectedRes: string }[] = [ + { navItem: "Home", expectedRes: urls.falkorDBUrl }, + { navItem: "Github", expectedRes: urls.benchmarkGithubUrl }, + { navItem: "Discord", expectedRes: urls.falkordbDiscordUrl }, + { navItem: "Sign up", expectedRes: urls.signUpUrl }, + { navItem: "Start Free", expectedRes: urls.startFreeUrl }, + ]; \ No newline at end of file diff --git a/ui/tests/logic/POM/mainPage.ts b/ui/tests/logic/POM/mainPage.ts index 6cb571b..9660f8a 100644 --- a/ui/tests/logic/POM/mainPage.ts +++ b/ui/tests/logic/POM/mainPage.ts @@ -4,14 +4,26 @@ import BasePage from "../../infra/ui/basePage"; export default class NavBarComponent extends BasePage { + /* Header Locators */ + private get falkorDBLogo(): Locator { return this.page.locator("//header//img[@alt='FalkorDB']") } + private get navBarSocialLink(): (navItem: string) => Locator { + return (navItem: string) => this.page.locator(`//a[@title="${navItem}"]`); + } + + private get navBarLink(): (navItem: string) => Locator { + return (navItem: string) => this.page.locator(`//a[contains(text(), '${navItem}')]`); + } + async clickOnFalkorLogo(): Promise { await this.falkorDBLogo.click(); } + /* Header Functionality */ + async clickOnFalkor(): Promise { await this.page.waitForLoadState('networkidle'); const [newPage] = await Promise.all([ @@ -20,4 +32,22 @@ export default class NavBarComponent extends BasePage { ]); return newPage } + + async getNavBarSocialLink(navItem : string): Promise { + await this.page.waitForLoadState('networkidle'); + const [newPage] = await Promise.all([ + this.page.waitForEvent('popup'), + this.navBarSocialLink(navItem).click(), + ]); + return newPage + } + + async getNavBarLink(navItem : string): Promise { + await this.page.waitForLoadState('networkidle'); + const [newPage] = await Promise.all([ + this.page.waitForEvent('popup'), + this.navBarLink(navItem).click(), + ]); + return newPage + } } \ No newline at end of file diff --git a/ui/tests/tests/header.spec.ts b/ui/tests/tests/header.spec.ts index f94b731..eab773a 100644 --- a/ui/tests/tests/header.spec.ts +++ b/ui/tests/tests/header.spec.ts @@ -2,6 +2,7 @@ import { test, expect } from '@playwright/test'; import BrowserWrapper from '../infra/ui/browserWrapper'; import MainPage from '../logic/POM/mainPage'; import urls from '../config/urls.json'; +import { navitems } from '../config/testData'; test.describe(' Navbar tests', () => { let browser: BrowserWrapper; @@ -19,4 +20,20 @@ test.describe(' Navbar tests', () => { const page = await header.clickOnFalkor(); expect(page.url()).toBe(urls.falkorDBUrl) }) + + navitems.slice(0,3).forEach(({navItem, expectedRes}) => { + test(`Verify clicking on ${navItem} redirects to specified ${navItem}`, async () => { + const header = await browser.createNewPage(MainPage, urls.baseUrl) + const page = await header.getNavBarSocialLink(navItem); + expect(page.url()).toBe(expectedRes) + }) + }) + + navitems.slice(3,5).forEach(({navItem, expectedRes}) => { + test(`Verify clicking on ${navItem} redirects to specified ${navItem}`, async () => { + const header = await browser.createNewPage(MainPage, urls.baseUrl) + const page = await header.getNavBarLink(navItem); + expect(page.url()).toBe(expectedRes) + }) + }) }); \ No newline at end of file From 534d47bba52e0cecc0de336c853a73babbabd00c Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:21:05 +0200 Subject: [PATCH 07/12] adding footer tests (#24, #25, #26, #27) --- .github/workflows/playwright.yml | 1 - ui/tests/config/testData.ts | 10 +++++- ui/tests/config/urls.json | 2 +- ui/tests/logic/POM/mainPage.ts | 33 ++++++++++++----- ui/tests/tests/footer.spec.ts | 35 ++++++++++++++++++ ui/tests/tests/header.spec.ts | 62 ++++++++++++++++++-------------- 6 files changed, 106 insertions(+), 37 deletions(-) create mode 100644 ui/tests/tests/footer.spec.ts diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml index b6674d6..27863e1 100644 --- a/.github/workflows/playwright.yml +++ b/.github/workflows/playwright.yml @@ -30,7 +30,6 @@ jobs: run: npx playwright install --with-deps - name: Set up environment and run tests run: | - npm install npm run build npm start & npx playwright test --reporter=dot,list diff --git a/ui/tests/config/testData.ts b/ui/tests/config/testData.ts index 41febe4..b64d704 100644 --- a/ui/tests/config/testData.ts +++ b/ui/tests/config/testData.ts @@ -1,9 +1,17 @@ import urls from '../config/urls.json'; -export const navitems: { navItem: string; expectedRes: string }[] = [ +export const headerItems: { navItem: string; expectedRes: string }[] = [ { navItem: "Home", expectedRes: urls.falkorDBUrl }, { navItem: "Github", expectedRes: urls.benchmarkGithubUrl }, { navItem: "Discord", expectedRes: urls.falkordbDiscordUrl }, { navItem: "Sign up", expectedRes: urls.signUpUrl }, { navItem: "Start Free", expectedRes: urls.startFreeUrl }, + ]; + + + export const footerItems: { item: string; expectedRes: string }[] = [ + { item: "DATASET USED", expectedRes: urls.DatasetUrl }, + { item: "README", expectedRes: urls.ReadmeUrl }, + { item: "FAQ", expectedRes: urls.FAQUrl }, + { item: "RUN THE BENCHMARK", expectedRes: urls.runBenchmarkWithYourDataUrl }, ]; \ No newline at end of file diff --git a/ui/tests/config/urls.json b/ui/tests/config/urls.json index 65ded7f..c5e6b72 100644 --- a/ui/tests/config/urls.json +++ b/ui/tests/config/urls.json @@ -7,6 +7,6 @@ "startFreeUrl": "https://www.falkordb.com/try-free/", "DatasetUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md#data", "ReadmeUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md", - "FAQUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md", + "FAQUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md#faq", "runBenchmarkWithYourDataUrl": "https://github.com/FalkorDB/benchmark/blob/master/readme.md#installation-steps" } \ No newline at end of file diff --git a/ui/tests/logic/POM/mainPage.ts b/ui/tests/logic/POM/mainPage.ts index 9660f8a..6115060 100644 --- a/ui/tests/logic/POM/mainPage.ts +++ b/ui/tests/logic/POM/mainPage.ts @@ -10,20 +10,26 @@ export default class NavBarComponent extends BasePage { return this.page.locator("//header//img[@alt='FalkorDB']") } - private get navBarSocialLink(): (navItem: string) => Locator { + private get headerSocialLink(): (navItem: string) => Locator { return (navItem: string) => this.page.locator(`//a[@title="${navItem}"]`); } - private get navBarLink(): (navItem: string) => Locator { + private get headerLink(): (navItem: string) => Locator { return (navItem: string) => this.page.locator(`//a[contains(text(), '${navItem}')]`); } - async clickOnFalkorLogo(): Promise { - await this.falkorDBLogo.click(); + /* Footer Locators */ + + private get footerLink(): (item: string) => Locator { + return (item: string) => this.page.locator(`//a[contains(text(), '${item}')]`); } /* Header Functionality */ + async clickOnFalkorLogo(): Promise { + await this.falkorDBLogo.click(); + } + async clickOnFalkor(): Promise { await this.page.waitForLoadState('networkidle'); const [newPage] = await Promise.all([ @@ -33,20 +39,31 @@ export default class NavBarComponent extends BasePage { return newPage } - async getNavBarSocialLink(navItem : string): Promise { + async getHeaderSocialLink(navItem : string): Promise { await this.page.waitForLoadState('networkidle'); const [newPage] = await Promise.all([ this.page.waitForEvent('popup'), - this.navBarSocialLink(navItem).click(), + this.headerSocialLink(navItem).click(), ]); return newPage } - async getNavBarLink(navItem : string): Promise { + async getHeaderLink(navItem : string): Promise { + await this.page.waitForLoadState('networkidle'); + const [newPage] = await Promise.all([ + this.page.waitForEvent('popup'), + this.headerLink(navItem).click(), + ]); + return newPage + } + + /* Footer Functionality */ + + async getFooterLink(item : string): Promise { await this.page.waitForLoadState('networkidle'); const [newPage] = await Promise.all([ this.page.waitForEvent('popup'), - this.navBarLink(navItem).click(), + this.footerLink(item).click(), ]); return newPage } diff --git a/ui/tests/tests/footer.spec.ts b/ui/tests/tests/footer.spec.ts new file mode 100644 index 0000000..cbb58bd --- /dev/null +++ b/ui/tests/tests/footer.spec.ts @@ -0,0 +1,35 @@ +import { test, expect } from "@playwright/test"; +import BrowserWrapper from "../infra/ui/browserWrapper"; +import MainPage from "../logic/POM/mainPage"; +import urls from "../config/urls.json"; +import { footerItems } from "../config/testData"; + +test.describe("Footer tests", () => { + let browser: BrowserWrapper; + + test.beforeAll(async () => { + try { + browser = new BrowserWrapper(); + } catch (error) { + console.error("Failed to initialize browser:", error); + throw error; + } + }); + + test.afterAll(async () => { + try { + await browser.closeBrowser(); + } catch (error) { + console.error("Failed to close browser:", error); + throw error; + } + }); + + footerItems.forEach(({ item, expectedRes }) => { + test(`Verify clicking on ${item} redirects to specified ${item}`, async () => { + const header = await browser.createNewPage(MainPage, urls.baseUrl); + const page = await header.getFooterLink(item); + expect(page.url()).toBe(expectedRes); + }); + }); +}); diff --git a/ui/tests/tests/header.spec.ts b/ui/tests/tests/header.spec.ts index eab773a..cec633d 100644 --- a/ui/tests/tests/header.spec.ts +++ b/ui/tests/tests/header.spec.ts @@ -1,39 +1,49 @@ -import { test, expect } from '@playwright/test'; -import BrowserWrapper from '../infra/ui/browserWrapper'; -import MainPage from '../logic/POM/mainPage'; -import urls from '../config/urls.json'; -import { navitems } from '../config/testData'; +import { test, expect } from "@playwright/test"; +import BrowserWrapper from "../infra/ui/browserWrapper"; +import MainPage from "../logic/POM/mainPage"; +import urls from "../config/urls.json"; +import { headerItems } from "../config/testData"; -test.describe(' Navbar tests', () => { +test.describe("Header tests", () => { let browser: BrowserWrapper; test.beforeAll(async () => { - browser = new BrowserWrapper(); + try { + browser = new BrowserWrapper(); + } catch (error) { + console.error("Failed to initialize browser:", error); + throw error; + } }); test.afterAll(async () => { - await browser.closeBrowser(); + try { + await browser.closeBrowser(); + } catch (error) { + console.error("Failed to close browser:", error); + throw error; + } }); - test("Verify clicking on falkordb logo redirects to specified URL", async () => { - const header = await browser.createNewPage(MainPage, urls.baseUrl) - const page = await header.clickOnFalkor(); - expect(page.url()).toBe(urls.falkorDBUrl) - }) + test("Verify clicking on falkordb logo redirects to specified URL", async () => { + const header = await browser.createNewPage(MainPage, urls.baseUrl); + const page = await header.clickOnFalkordb(); + expect(page.url()).toBe(urls.falkorDBUrl); + }); - navitems.slice(0,3).forEach(({navItem, expectedRes}) => { + headerItems.slice(0, 3).forEach(({ navItem, expectedRes }) => { test(`Verify clicking on ${navItem} redirects to specified ${navItem}`, async () => { - const header = await browser.createNewPage(MainPage, urls.baseUrl) - const page = await header.getNavBarSocialLink(navItem); - expect(page.url()).toBe(expectedRes) - }) - }) + const header = await browser.createNewPage(MainPage, urls.baseUrl); + const page = await header.getHeaderSocialLink(navItem); + expect(page.url()).toBe(expectedRes); + }); + }); - navitems.slice(3,5).forEach(({navItem, expectedRes}) => { + headerItems.slice(3, 5).forEach(({ navItem, expectedRes }) => { test(`Verify clicking on ${navItem} redirects to specified ${navItem}`, async () => { - const header = await browser.createNewPage(MainPage, urls.baseUrl) - const page = await header.getNavBarLink(navItem); - expect(page.url()).toBe(expectedRes) - }) - }) -}); \ No newline at end of file + const header = await browser.createNewPage(MainPage, urls.baseUrl); + const page = await header.getHeaderLink(navItem); + expect(page.url()).toBe(expectedRes); + }); + }); +}); From cf433ae5f99b36740df1a32502c221a9f13c7e26 Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Mon, 20 Jan 2025 17:23:35 +0200 Subject: [PATCH 08/12] Update mainPage.ts --- ui/tests/logic/POM/mainPage.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/tests/logic/POM/mainPage.ts b/ui/tests/logic/POM/mainPage.ts index 6115060..59a8486 100644 --- a/ui/tests/logic/POM/mainPage.ts +++ b/ui/tests/logic/POM/mainPage.ts @@ -30,7 +30,7 @@ export default class NavBarComponent extends BasePage { await this.falkorDBLogo.click(); } - async clickOnFalkor(): Promise { + async clickOnFalkordb(): Promise { await this.page.waitForLoadState('networkidle'); const [newPage] = await Promise.all([ this.page.waitForEvent('popup'), From f2916401a269578cb4157274960ee358c2de11ab Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:00:39 +0200 Subject: [PATCH 09/12] adding tests (#18, #19, #20, #21, #22) --- ui/app/components/dashboard.tsx | 22 +++++ ui/components/ui/sidebar.tsx | 1 + ui/tests/config/testData.ts | 8 +- ui/tests/logic/POM/mainPage.ts | 153 +++++++++++++++++++++----------- ui/tests/tests/header.spec.ts | 2 +- ui/tests/tests/sideBar.spec.ts | 72 +++++++++++++++ 6 files changed, 204 insertions(+), 54 deletions(-) create mode 100644 ui/tests/tests/sideBar.spec.ts diff --git a/ui/app/components/dashboard.tsx b/ui/app/components/dashboard.tsx index 2b2d6cb..17e1422 100644 --- a/ui/app/components/dashboard.tsx +++ b/ui/app/components/dashboard.tsx @@ -180,6 +180,28 @@ export default function DashBoard() { : "0.00", })); + + //saving data to window.allChartData + /* eslint-disable */ + if (typeof window !== "undefined") { + (window as any).allChartData = (window as any).allChartData || []; + const addOrReplaceChartData = (key: string, value: any) => { + const chartDataArray = (window as any).allChartData; + const existingIndex = chartDataArray.findIndex((entry: any) => entry.key === key); + if (existingIndex !== -1) { + chartDataArray.splice(existingIndex, 1); + } + chartDataArray.push({ key, value }); + }; + + addOrReplaceChartData("throughputData", throughputData); + addOrReplaceChartData("deadlineData", deadlineData); + addOrReplaceChartData("memoryData", memoryData); + addOrReplaceChartData("cpuData", cpuData); + addOrReplaceChartData("latencyData", latencyData); + } + + return (
diff --git a/ui/components/ui/sidebar.tsx b/ui/components/ui/sidebar.tsx index 936c0dc..cd9024a 100644 --- a/ui/components/ui/sidebar.tsx +++ b/ui/components/ui/sidebar.tsx @@ -220,6 +220,7 @@ const Sidebar = React.forwardRef< data-collapsible={state === "collapsed" ? collapsible : ""} data-variant={variant} data-side={side} + id="sidebar-container" > {/* This is what handles the sidebar gap on desktop */}
Promise + ): Promise { + try { + await this.page.waitForLoadState("networkidle", { timeout: 5000 }); + const popupPromise = this.page.waitForEvent("popup", { timeout: 5000 }); + await clickAction(); + const newPage = await popupPromise; + await newPage.waitForLoadState("load"); + return newPage; + } catch (error) { + throw new Error(`Navigation failed`); + } + } - /* Header Locators */ + /* Header Locators */ - private get falkorDBLogo(): Locator { - return this.page.locator("//header//img[@alt='FalkorDB']") - } + private get falkorDBLogo(): Locator { + return this.page.locator("//header//img[@alt='FalkorDB']"); + } - private get headerSocialLink(): (navItem: string) => Locator { - return (navItem: string) => this.page.locator(`//a[@title="${navItem}"]`); - } + private get headerSocialLink(): (navItem: string) => Locator { + return (navItem: string) => this.page.locator(`//a[@title="${navItem}"]`); + } - private get headerLink(): (navItem: string) => Locator { - return (navItem: string) => this.page.locator(`//a[contains(text(), '${navItem}')]`); - } + private get headerLink(): (navItem: string) => Locator { + return (navItem: string) => + this.page.locator(`//a[contains(text(), '${navItem}')]`); + } - /* Footer Locators */ + /* Footer Locators */ - private get footerLink(): (item: string) => Locator { - return (item: string) => this.page.locator(`//a[contains(text(), '${item}')]`); - } + private get footerLink(): (item: string) => Locator { + return (item: string) => + this.page.locator(`//a[contains(text(), '${item}')]`); + } - /* Header Functionality */ + /* SideBar Locators */ - async clickOnFalkorLogo(): Promise { - await this.falkorDBLogo.click(); - } + private get sideBarToggle(): Locator { + return this.page.locator("//button[@data-sidebar='trigger']"); + } - async clickOnFalkordb(): Promise { - await this.page.waitForLoadState('networkidle'); - const [newPage] = await Promise.all([ - this.page.waitForEvent('popup'), - this.clickOnFalkorLogo(), - ]); - return newPage - } + private get sideBarSelection(): (item: string) => Locator { + return (item: string) => this.page.locator(`//button[text()='${item}']`); + } - async getHeaderSocialLink(navItem : string): Promise { - await this.page.waitForLoadState('networkidle'); - const [newPage] = await Promise.all([ - this.page.waitForEvent('popup'), - this.headerSocialLink(navItem).click(), - ]); - return newPage - } + private get sideBarContainer(): Locator { + return this.page.locator("//div[@id='sidebar-container']"); + } - async getHeaderLink(navItem : string): Promise { - await this.page.waitForLoadState('networkidle'); - const [newPage] = await Promise.all([ - this.page.waitForEvent('popup'), - this.headerLink(navItem).click(), - ]); - return newPage - } + private get sideBarMenu(): Locator { + return this.page.locator("(//ul[@data-sidebar='menu'])[2]"); + } + + /* Header Functionality */ - /* Footer Functionality */ + async clickOnFalkorLogo(): Promise { + return this.navigateAndWaitForPopup(() => this.falkorDBLogo.click()); + } - async getFooterLink(item : string): Promise { - await this.page.waitForLoadState('networkidle'); - const [newPage] = await Promise.all([ - this.page.waitForEvent('popup'), - this.footerLink(item).click(), - ]); - return newPage + async getHeaderSocialLink(navItem: string): Promise { + return this.navigateAndWaitForPopup(() => + this.headerSocialLink(navItem).click() + ); + } + + async getHeaderLink(navItem: string): Promise { + return this.navigateAndWaitForPopup(() => this.headerLink(navItem).click()); + } + + /* Footer Functionality */ + + async getFooterLink(item: string): Promise { + return this.navigateAndWaitForPopup(() => this.footerLink(item).click()); + } + + /* SideBar Functionality */ + + async clickOnSideBarToggle(): Promise { + await this.sideBarToggle.click(); + } + + async clickOnSidebarSelection(item: string): Promise { + await this.sideBarSelection(item).click(); + } + + async getSideBarState(): Promise { + return await this.sideBarContainer.getAttribute("data-state"); + } + + async getGraphDetails(): Promise { + try { + await this.page.waitForFunction( + () => + typeof (window as any).allChartData !== "undefined" && + (window as any).allChartData !== null, + { timeout: 5000 } + ); + const graphData = await this.page.evaluate(() => { + return (window as any).allChartData; + }); + + if (!graphData) { + throw new Error("Graph data is not available in window.allChartData."); + } + + return graphData; + } catch (error) { + console.error("Error fetching graph details:", error); + throw error; } -} \ No newline at end of file + } + +} diff --git a/ui/tests/tests/header.spec.ts b/ui/tests/tests/header.spec.ts index cec633d..b25c771 100644 --- a/ui/tests/tests/header.spec.ts +++ b/ui/tests/tests/header.spec.ts @@ -27,7 +27,7 @@ test.describe("Header tests", () => { test("Verify clicking on falkordb logo redirects to specified URL", async () => { const header = await browser.createNewPage(MainPage, urls.baseUrl); - const page = await header.clickOnFalkordb(); + const page = await header.clickOnFalkorLogo(); expect(page.url()).toBe(urls.falkorDBUrl); }); diff --git a/ui/tests/tests/sideBar.spec.ts b/ui/tests/tests/sideBar.spec.ts new file mode 100644 index 0000000..07343eb --- /dev/null +++ b/ui/tests/tests/sideBar.spec.ts @@ -0,0 +1,72 @@ +import { test, expect } from "@playwright/test"; +import BrowserWrapper from "../infra/ui/browserWrapper"; +import MainPage from "../logic/POM/mainPage"; +import urls from "../config/urls.json"; +import { sideBarItems } from "../config/testData"; + +function extractSecondValues( + graphDetails: { key: any; value: any[] }[], + updatedGraphDetails: { key: any; value: any[] }[], + index: number +): { originalValue: any; updatedValue: any } { + const matchedUpdatedData = updatedGraphDetails.find( + (data: { key: any }) => data.key === graphDetails[index].key + ); + const matchedOriginalData = graphDetails.find( + (data: { key: any }) => data.key === updatedGraphDetails[index].key + ); + + if (!matchedUpdatedData || !matchedOriginalData) { + throw new Error(`Matching data not found for index ${index}`); + } + + const originalSecondValue = matchedOriginalData.value[1]; + const updatedSecondValue = matchedUpdatedData.value[1]; + + return { + originalValue: Object.values(originalSecondValue)[1], + updatedValue: Object.values(updatedSecondValue)[1], + }; +} + +test.describe("SideBar tests", () => { + let browser: BrowserWrapper; + + test.beforeAll(async () => { + try { + browser = new BrowserWrapper(); + } catch (error) { + console.error("Failed to initialize browser:", error); + throw error; + } + }); + + test.afterAll(async () => { + try { + await browser.closeBrowser(); + } catch (error) { + console.error("Failed to close browser:", error); + throw error; + } + }); + + sideBarItems.forEach(({ item, expectedRes}) => { + test(`verify selecting different hardware changes the charts ${item}`, async () => { + const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); + const graphDetails = await sidebar.getGraphDetails(); + await sidebar.clickOnSidebarSelection(item); + const updatedGraphDetails = await sidebar.getGraphDetails(); + + for (let i = 0; i < graphDetails.length; i++) { + const { originalValue, updatedValue } = extractSecondValues( + graphDetails, + updatedGraphDetails, + i + ); + const areValuesDifferent = originalValue !== updatedValue; + expect(areValuesDifferent).toBe(expectedRes); + } + }); + }); + +}); From 3933c4a82689aa863d61dd08d4ff19af92f547ba Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Tue, 21 Jan 2025 17:06:39 +0200 Subject: [PATCH 10/12] Update sideBar.spec.ts --- ui/tests/tests/sideBar.spec.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ui/tests/tests/sideBar.spec.ts b/ui/tests/tests/sideBar.spec.ts index 07343eb..c236634 100644 --- a/ui/tests/tests/sideBar.spec.ts +++ b/ui/tests/tests/sideBar.spec.ts @@ -51,7 +51,7 @@ test.describe("SideBar tests", () => { }); sideBarItems.forEach(({ item, expectedRes}) => { - test(`verify selecting different hardware changes the charts ${item}`, async () => { + test(`Verify ${item} selection updates the chart results`, async () => { const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); const graphDetails = await sidebar.getGraphDetails(); await sidebar.clickOnSidebarSelection(item); @@ -68,5 +68,13 @@ test.describe("SideBar tests", () => { } }); }); + + test("Verify Sidebar trigger button toggles the sidebar open and closed", async () => { + const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); + await sidebar.clickOnSideBarToggle(); + expect(await sidebar.getSideBarState()).toBe("collapsed"); + await sidebar.clickOnSideBarToggle(); + expect(await sidebar.getSideBarState()).toBe("expanded"); + }); }); From 7e3b7427dbf831aec566f438f419d92f5430b64d Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Wed, 22 Jan 2025 14:48:57 +0200 Subject: [PATCH 11/12] add sidebar test (#23) --- ui/tests/logic/POM/mainPage.ts | 14 +++++++++-- ui/tests/tests/sideBar.spec.ts | 46 +++++++++++++++++++++++----------- 2 files changed, 44 insertions(+), 16 deletions(-) diff --git a/ui/tests/logic/POM/mainPage.ts b/ui/tests/logic/POM/mainPage.ts index d1d50d8..1f6fbe5 100644 --- a/ui/tests/logic/POM/mainPage.ts +++ b/ui/tests/logic/POM/mainPage.ts @@ -53,8 +53,8 @@ export default class NavBarComponent extends BasePage { return this.page.locator("//div[@id='sidebar-container']"); } - private get sideBarMenu(): Locator { - return this.page.locator("(//ul[@data-sidebar='menu'])[2]"); + private get sideBarContent(): Locator { + return this.page.locator("div[data-sidebar='content']"); } /* Header Functionality */ @@ -93,6 +93,16 @@ export default class NavBarComponent extends BasePage { return await this.sideBarContainer.getAttribute("data-state"); } + async scrollToBottomInSidebar(): Promise { + await this.sideBarContent.evaluate((el) => el.scrollTo(0, el.scrollHeight)); + } + + async isScrolledToBottomInSidebar(): Promise { + return await this.sideBarContent.evaluate((el) => { + return el.scrollTop + el.clientHeight >= el.scrollHeight; + }); + } + async getGraphDetails(): Promise { try { await this.page.waitForFunction( diff --git a/ui/tests/tests/sideBar.spec.ts b/ui/tests/tests/sideBar.spec.ts index c236634..676d068 100644 --- a/ui/tests/tests/sideBar.spec.ts +++ b/ui/tests/tests/sideBar.spec.ts @@ -5,10 +5,19 @@ import urls from "../config/urls.json"; import { sideBarItems } from "../config/testData"; function extractSecondValues( - graphDetails: { key: any; value: any[] }[], - updatedGraphDetails: { key: any; value: any[] }[], + graphDetails: { key: string; value: Array> }[], + updatedGraphDetails: { key: string; value: Array> }[], index: number -): { originalValue: any; updatedValue: any } { +): { originalValue: number; updatedValue: number } { + if ( + index < 0 || + index >= graphDetails.length || + index >= updatedGraphDetails.length + ) { + throw new Error( + `Invalid index ${index}. Index must be within array bounds.` + ); + } const matchedUpdatedData = updatedGraphDetails.find( (data: { key: any }) => data.key === graphDetails[index].key ); @@ -17,7 +26,9 @@ function extractSecondValues( ); if (!matchedUpdatedData || !matchedOriginalData) { - throw new Error(`Matching data not found for index ${index}`); + throw new Error( + `No matching data found for key "${graphDetails[index].key}" at index ${index}` + ); } const originalSecondValue = matchedOriginalData.value[1]; @@ -50,21 +61,23 @@ test.describe("SideBar tests", () => { } }); - sideBarItems.forEach(({ item, expectedRes}) => { + sideBarItems.forEach(({ item, expectedRes }) => { test(`Verify ${item} selection updates the chart results`, async () => { const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); const graphDetails = await sidebar.getGraphDetails(); await sidebar.clickOnSidebarSelection(item); const updatedGraphDetails = await sidebar.getGraphDetails(); - + for (let i = 0; i < graphDetails.length; i++) { - const { originalValue, updatedValue } = extractSecondValues( - graphDetails, - updatedGraphDetails, - i - ); - const areValuesDifferent = originalValue !== updatedValue; - expect(areValuesDifferent).toBe(expectedRes); + await expect(async () => { + const { originalValue, updatedValue } = extractSecondValues( + graphDetails, + updatedGraphDetails, + i + ); + const areValuesDifferent = originalValue !== updatedValue; + expect(areValuesDifferent).toBe(expectedRes); + }).toPass({ timeout: 5000 }); } }); }); @@ -76,5 +89,10 @@ test.describe("SideBar tests", () => { await sidebar.clickOnSideBarToggle(); expect(await sidebar.getSideBarState()).toBe("expanded"); }); - + + test(`Verify manual scroll functionality`, async () => { + const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); + await sidebar.scrollToBottomInSidebar(); + expect(await sidebar.isScrolledToBottomInSidebar()).toBe(true); + }); }); From fe7537ea77383b14a3334b18fdb79ceac241606d Mon Sep 17 00:00:00 2001 From: Naseem Ali <34807727+Naseem77@users.noreply.github.com> Date: Wed, 22 Jan 2025 16:19:55 +0200 Subject: [PATCH 12/12] add sidebar tests (#39, #40) --- ui/app/components/dashboard.tsx | 10 +++++----- ui/tests/config/testData.ts | 5 +++++ ui/tests/logic/POM/mainPage.ts | 35 ++++++++++++++++++++++++++++++++- ui/tests/tests/sideBar.spec.ts | 20 ++++++++++++++++++- 4 files changed, 63 insertions(+), 7 deletions(-) diff --git a/ui/app/components/dashboard.tsx b/ui/app/components/dashboard.tsx index 17e1422..35180da 100644 --- a/ui/app/components/dashboard.tsx +++ b/ui/app/components/dashboard.tsx @@ -212,7 +212,7 @@ export default function DashBoard() { />
-
+
-
+
-
+
-
+
-
+
Locator { + return (item: string) => + this.page.locator(`//button[text()="${item}"]/following-sibling::a/span`); + } + + private get deadlineInfoLink(): Locator { + return this.page.locator("//div[@id='deadline-chart']/a/span"); + } + /* Header Locators */ private get falkorDBLogo(): Locator { @@ -57,6 +72,25 @@ export default class NavBarComponent extends BasePage { return this.page.locator("div[data-sidebar='content']"); } + /* General Functionality */ + + async hoverOnSideBarHardware(item: string): Promise { + await this.hoverElement(item).hover(); + } + + async isHoverElementVisible(): Promise { + await this.page.waitForTimeout(2000); + return this.hoverElementPopUp.isVisible(); + } + + async hoverOnDeadlineInfoLink(): Promise { + await this.deadlineInfoLink.hover(); + } + + async getDeadlineInfoLinkText(): Promise { + return await this.hoverElementPopUp.innerText(); + } + /* Header Functionality */ async clickOnFalkorLogo(): Promise { @@ -125,5 +159,4 @@ export default class NavBarComponent extends BasePage { throw error; } } - } diff --git a/ui/tests/tests/sideBar.spec.ts b/ui/tests/tests/sideBar.spec.ts index 676d068..9abaecd 100644 --- a/ui/tests/tests/sideBar.spec.ts +++ b/ui/tests/tests/sideBar.spec.ts @@ -2,7 +2,7 @@ import { test, expect } from "@playwright/test"; import BrowserWrapper from "../infra/ui/browserWrapper"; import MainPage from "../logic/POM/mainPage"; import urls from "../config/urls.json"; -import { sideBarItems } from "../config/testData"; +import { hoverItems, sideBarItems } from "../config/testData"; function extractSecondValues( graphDetails: { key: string; value: Array> }[], @@ -95,4 +95,22 @@ test.describe("SideBar tests", () => { await sidebar.scrollToBottomInSidebar(); expect(await sidebar.isScrolledToBottomInSidebar()).toBe(true); }); + + hoverItems.forEach(({ item, expectedRes }) => { + test(`Verify hover behavior for hardware item: ${item}`, async () => { + const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); + await sidebar.hoverOnSideBarHardware(item); + expect(await sidebar.isHoverElementVisible()).toBe(expectedRes); + }); + }); + + test(`Hover over 'Deadline Offset Analysis' link and validate its content`, async () => { + const sidebar = await browser.createNewPage(MainPage, urls.baseUrl); + await sidebar.hoverOnDeadlineInfoLink(); + expect(await sidebar.isHoverElementVisible()).toBe(true); + const expectedText = + "Deadline Offset Analysis Comparison of the time delays (deadlines) between different vendors to evaluate their performance and responsiveness."; + const actualText = await sidebar.getDeadlineInfoLinkText(); + expect(actualText).toBe(expectedText); + }); });