-
-
Notifications
You must be signed in to change notification settings - Fork 128
test: add E2E tests for untested pages #1530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
d17642e
523777a
84cfd25
3e33f39
5d99e46
344d1ad
baafb46
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| import { expect, setupTest, test } from './utils' | ||
|
|
||
| test.describe('Data Research Page Tests', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await setupTest(page) | ||
| }) | ||
|
|
||
| test('accessing /data-research directly works', async ({ page }) => { | ||
| await page.goto('/data-research') | ||
| await page.locator('.preloader').waitFor({ state: 'hidden' }) | ||
| await page.waitForLoadState('networkidle') | ||
| await expect(page).toHaveURL(/data-research/) | ||
| }) | ||
|
|
||
| test('page displays research section heading', async ({ page }) => { | ||
| await page.goto('/data-research') | ||
| await page.locator('.preloader').waitFor({ state: 'hidden' }) | ||
| await page.waitForLoadState('networkidle') | ||
| const title = page.locator('h2', { hasText: 'מחקרים' }) | ||
| await expect(title).toBeVisible() | ||
| }) | ||
|
|
||
| test('page displays research description text', async ({ page }) => { | ||
| await page.goto('/data-research') | ||
| await page.locator('.preloader').waitFor({ state: 'hidden' }) | ||
| await page.waitForLoadState('networkidle') | ||
| await expect( | ||
| page.getByText('אם יש לכם רעיון מעניין למה קורים פה דברים, דברו איתנו בסלאק!'), | ||
| ).toBeVisible() | ||
| }) | ||
|
|
||
| test('stacked research section with charts is rendered', async ({ page }) => { | ||
| await page.goto('/data-research') | ||
| await page.locator('.preloader').waitFor({ state: 'hidden' }) | ||
| await page.waitForLoadState('networkidle') | ||
| const etlWidget = page.locator('h2', { hasText: 'בעיות etl/gps/משהו גלובאלי אחר' }) | ||
| await expect(etlWidget).toBeVisible() | ||
| }) | ||
|
|
||
| test('research page has date selectors and operator selector', async ({ page }) => { | ||
| await page.goto('/data-research') | ||
| await page.locator('.preloader').waitFor({ state: 'hidden' }) | ||
| await page.waitForLoadState('networkidle') | ||
| const startDateGroup = page.getByRole('group', { name: 'התחלה' }).first() | ||
| const endDateGroup = page.getByRole('group', { name: 'סיום' }).first() | ||
| await expect(startDateGroup).toBeVisible() | ||
| await expect(endDateGroup).toBeVisible() | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||||||
| import i18next from 'i18next' | ||||||||||
| import { expect, setupTest, test } from './utils' | ||||||||||
|
|
||||||||||
| test.describe('Donate Modal Tests', () => { | ||||||||||
| test.beforeEach(async ({ page }) => { | ||||||||||
| await setupTest(page) | ||||||||||
| }) | ||||||||||
|
|
||||||||||
| test('clicking donate menu item opens the modal', async ({ page }) => { | ||||||||||
| const donateLink = page.locator('li a', { hasText: i18next.t('donate_title') }) | ||||||||||
| await donateLink.click() | ||||||||||
| const modal = page.getByRole('dialog') | ||||||||||
| await expect(modal).toBeVisible() | ||||||||||
| await expect( | ||||||||||
| page.getByRole('heading', { name: i18next.t('how_to_donate_title') }), | ||||||||||
| ).toBeVisible() | ||||||||||
| }) | ||||||||||
|
|
||||||||||
| test('modal contains donation link to jgive.com', async ({ page }) => { | ||||||||||
| const donateLink = page.locator('li a', { hasText: i18next.t('donate_title') }) | ||||||||||
| await donateLink.click() | ||||||||||
| const modal = page.getByRole('dialog') | ||||||||||
| await expect(modal).toBeVisible() | ||||||||||
| const jgiveLink = modal.locator('a[href*="jgive.com"]').first() | ||||||||||
| await expect(jgiveLink).toBeVisible() | ||||||||||
| await expect(jgiveLink).toHaveAttribute('href', /jgive\.com/) | ||||||||||
| }) | ||||||||||
|
|
||||||||||
| test('modal contains bank transfer details', async ({ page }) => { | ||||||||||
| const donateLink = page.locator('li a', { hasText: i18next.t('donate_title') }) | ||||||||||
| await donateLink.click() | ||||||||||
| const modal = page.getByRole('dialog') | ||||||||||
| await expect(modal).toBeVisible() | ||||||||||
| await expect(modal.getByText(i18next.t('donation_through_bank_title'))).toBeVisible() | ||||||||||
| await expect(modal.getByText(i18next.t('donation_through_bank_details_account'))).toBeVisible() | ||||||||||
| }) | ||||||||||
|
|
||||||||||
| test('modal can be closed', async ({ page }) => { | ||||||||||
| const donateLink = page.locator('li a', { hasText: i18next.t('donate_title') }) | ||||||||||
| await donateLink.click() | ||||||||||
| const modal = page.getByRole('dialog') | ||||||||||
| await expect(modal).toBeVisible() | ||||||||||
| // Close button is the X button inside the modal | ||||||||||
| const closeButton = modal.locator('button').first() | ||||||||||
|
Comment on lines
+43
to
+44
|
||||||||||
| // Close button is the X button inside the modal | |
| const closeButton = modal.locator('button').first() | |
| // Target the modal's close control by semantics instead of button order | |
| const closeButton = modal.getByRole('button', { name: /close/i }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import i18next from 'i18next' | ||
| import { expect, harOptions, setupTest, test, visitPage } from './utils' | ||
|
|
||
| test.describe('Gaps Page Tests', () => { | ||
| test.beforeEach(async ({ page, advancedRouteFromHAR }) => { | ||
| await setupTest(page) | ||
| await advancedRouteFromHAR('tests/HAR/missing.har', harOptions) | ||
| await visitPage(page, 'gaps_page_title') | ||
| }) | ||
|
|
||
| test('page title is visible', async ({ page }) => { | ||
| await expect(page.locator('h4')).toHaveText(i18next.t('gaps_page_title')) | ||
| }) | ||
|
|
||
| test('page description alert is visible', async ({ page }) => { | ||
| await expect(page.getByText(i18next.t('gaps_page_description'))).toBeVisible() | ||
| }) | ||
|
|
||
| test('date selector is present', async ({ page }) => { | ||
| const dateInput = page.locator('input[type="text"]').first() | ||
| await expect(dateInput).toBeVisible() | ||
| }) | ||
|
|
||
| test('operator selector is present', async ({ page }) => { | ||
| await expect(page.getByLabel(i18next.t('choose_operator'))).toBeVisible() | ||
| }) | ||
|
|
||
| test('line number selector is present', async ({ page }) => { | ||
| await expect(page.getByLabel(i18next.t('choose_line'))).toBeVisible() | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,33 @@ | ||
| import i18next from 'i18next' | ||
| import { expect, fillDateField, harOptions, setupTest, test, visitPage } from './utils' | ||
|
|
||
| test.describe('Gaps Patterns Page Tests', () => { | ||
| test.beforeEach(async ({ page, advancedRouteFromHAR }) => { | ||
| await setupTest(page) | ||
| await advancedRouteFromHAR('tests/HAR/patterns.har', harOptions) | ||
| await visitPage(page, 'gaps_patterns_page_title') | ||
| }) | ||
|
|
||
| test('page heading is displayed', async ({ page }) => { | ||
| await expect(page.locator('h4')).toContainText(i18next.t('gaps_patterns_page_title')) | ||
| }) | ||
|
|
||
| test('page description is visible', async ({ page }) => { | ||
| await expect(page.getByText(i18next.t('gaps_patterns_page_description'))).toBeVisible() | ||
| }) | ||
|
|
||
| test('start and end date selectors are present', async ({ page }) => { | ||
| const dateInputs = page.locator('input[type="text"]') | ||
| const count = await dateInputs.count() | ||
| expect(count).toBeGreaterThanOrEqual(2) | ||
| }) | ||
|
|
||
| test('date selectors accept input', async ({ page }) => { | ||
| await fillDateField(page, 'התחלה', '01/02/2024') | ||
| await fillDateField(page, 'סיום', '08/02/2024') | ||
| }) | ||
|
|
||
| test('operator selector is present', async ({ page }) => { | ||
| await expect(page.getByLabel(i18next.t('choose_operator'))).toBeVisible() | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,44 @@ | ||||||||||||||||||||||||
| import i18next from 'i18next' | ||||||||||||||||||||||||
| import { expect, setupTest, test } from './utils' | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| test.describe('Homepage Tests', () => { | ||||||||||||||||||||||||
| test.beforeEach(async ({ page }) => { | ||||||||||||||||||||||||
| await setupTest(page) | ||||||||||||||||||||||||
| await page.waitForLoadState('networkidle') | ||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| test('homepage displays welcome heading', async ({ page }) => { | ||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: i18next.t('homepage.welcome') })).toBeVisible() | ||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| test('homepage displays definition', async ({ page }) => { | ||||||||||||||||||||||||
| await expect(page.locator('h2').last()).toContainText(i18next.t('homepage.databus_definition')) | ||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||
|
|
||||||||||||||||||||||||
| test('homepage displays bus illustration', async ({ page }) => { | ||||||||||||||||||||||||
| const img = page.locator('img[alt="Public Transportaion Bus Illustration"]') | ||||||||||||||||||||||||
|
||||||||||||||||||||||||
| const img = page.locator('img[alt="Public Transportaion Bus Illustration"]') | |
| const img = page.getByAltText(/Public Transporta(?:tion|ion) Bus Illustration/) |
Copilot
AI
Apr 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Asserting an exact link count is brittle and will fail on legitimate UI changes (adding/removing a link, A/B tests, responsive variants). A more stable approach is to assert the presence of specific expected links (by role/name) or to check a minimum count if the exact number isn’t a strict product requirement.
| const links = page.locator('section.links .page-link') | |
| const count = await links.count() | |
| expect(count).toBe(6) | |
| const linksSection = page.locator('section.links') | |
| await expect(linksSection.getByRole('link', { name: i18next.t('nav.home') })).toBeVisible() | |
| await expect(linksSection.getByRole('link', { name: i18next.t('nav.routes') })).toBeVisible() | |
| await expect(linksSection.getByRole('link', { name: i18next.t('nav.stops') })).toBeVisible() | |
| await expect(linksSection.getByRole('link', { name: i18next.t('nav.map') })).toBeVisible() | |
| await expect(linksSection.getByRole('link', { name: i18next.t('nav.about') })).toBeVisible() | |
| await expect(linksSection.getByRole('link', { name: i18next.t('nav.contact') })).toBeVisible() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| import { expect, setupTest, test } from './utils' | ||
|
|
||
| test.describe('Line Profile Page Tests', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await setupTest(page) | ||
| }) | ||
|
|
||
| test('navigating to a profile route loads without error', async ({ page }) => { | ||
| await page.goto('/profile/1') | ||
| await page.locator('.preloader').waitFor({ state: 'hidden' }) | ||
| await expect(page).toHaveURL(/\/profile\/1/) | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { expect, setupTest, test, visitPage } from './utils' | ||
|
|
||
| test.describe('Public Appeal Page Tests', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await setupTest(page) | ||
| await visitPage(page, 'public_appeal_title') | ||
| }) | ||
|
|
||
| test('page renders without error', async ({ page }) => { | ||
| await expect(page).toHaveURL(/\/public-appeal/) | ||
| }) | ||
|
|
||
| test('page has proper RTL layout', async ({ page }) => { | ||
| const dir = await page.locator('html').getAttribute('dir') | ||
| expect(dir).toBe('rtl') | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,69 @@ | ||||||||||||||||||||||||||
| import i18next from 'i18next' | ||||||||||||||||||||||||||
| import { expect, setupTest, test, visitPage } from './utils' | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| test.describe('Velocity Heatmap Page Tests', () => { | ||||||||||||||||||||||||||
| test.beforeEach(async ({ page }) => { | ||||||||||||||||||||||||||
| await setupTest(page) | ||||||||||||||||||||||||||
| await visitPage(page, 'velocity_heatmap_page_title') | ||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| test('page displays heading and date controls', async ({ page }) => { | ||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Velocity Aggregation Heatmap' })).toBeVisible() | ||||||||||||||||||||||||||
|
||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Velocity Aggregation Heatmap' })).toBeVisible() | |
| await expect( | |
| page.getByRole('heading', { name: i18next.t('velocity_heatmap_page_title') }), | |
| ).toBeVisible() |
Copilot
AI
Apr 24, 2026
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
page.waitForTimeout(300) makes this test timing-dependent and flaky under slow CI. Prefer waiting on an explicit condition (e.g., await expect(dateInput).not.toHaveValue(initialValue) after prev-day click, and then await expect(dateInput).toHaveValue(initialValue) after next-day click), or use expect.poll on inputValue() so Playwright waits until the UI updates.
| await page.waitForTimeout(300) | |
| const afterPrevDay = await dateInput.inputValue() | |
| expect(afterPrevDay).not.toEqual(initialValue) | |
| await page.getByRole('button', { name: i18next.t('date_navigator_next_day') }).click() | |
| await page.waitForTimeout(300) | |
| const afterNextDay = await dateInput.inputValue() | |
| expect(afterNextDay).toEqual(initialValue) | |
| await expect(dateInput).not.toHaveValue(initialValue) | |
| await page.getByRole('button', { name: i18next.t('date_navigator_next_day') }).click() | |
| await expect(dateInput).toHaveValue(initialValue) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This file repeats the same navigation + waiting sequence in multiple tests, which will significantly slow the suite and increases surface area for flakes. Since these tests all target the same route, consider moving the
goto('/data-research')+ wait logic intobeforeEach(or a shared helper likevisitPage) and keep tests focused on assertions.