-
-
Notifications
You must be signed in to change notification settings - Fork 658
Added End-to-End test cases for All pages #978
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
Changes from 6 commits
bfa9bac
ac07533
b058707
4ad389d
3d0951c
b0c77c0
f9aa4cb
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,51 @@ | ||
| import { test, expect } from '@playwright/test' | ||
| import { mockChapterDetailsData } from '@unit/data/mockChapterDetailsData' | ||
|
|
||
| test.describe('Chapter Details Page', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await page.route('**/graphql/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| json: { data: { chapter: mockChapterDetailsData } }, | ||
| }) | ||
| }) | ||
| await page.goto('/chapters/test-chapter') | ||
| }) | ||
|
|
||
| test('should have a heading and summary', async ({ page }) => { | ||
| await expect(page.getByRole('heading', { name: 'OWASP Test Chapter' })).toBeVisible() | ||
| await expect(page.getByText('This is a test chapter summary.')).toBeVisible() | ||
| }) | ||
|
|
||
| test('should have chapter details block', async ({ page }) => { | ||
| await expect(page.getByText('Location: Test City, Test')).toBeVisible() | ||
| await expect(page.getByText('Region: Test Region')).toBeVisible() | ||
| await expect(page.getByRole('link', { name: 'https://owasp.org/test-chapter' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('should have map with geolocation', async ({ page }) => { | ||
| await expect(page.locator('#chapter-map')).toBeVisible() | ||
| await expect(page.locator('#chapter-map').locator('img').nth(1)).toBeVisible() | ||
| await expect(page.getByRole('button', { name: 'Zoom in' })).toBeVisible() | ||
| await expect(page.getByRole('button', { name: 'Zoom out' })).toBeVisible() | ||
| await expect(page.getByRole('button', { name: 'Marker' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('should have top contributors', async ({ page }) => { | ||
| await expect(page.getByRole('heading', { name: 'Top Contributors' })).toBeVisible() | ||
| await expect(page.getByRole('img', { name: 'Contributor 1' })).toBeVisible() | ||
| await expect(page.getByText('Contributor 1')).toBeVisible() | ||
| await expect(page.getByText('10 Contributions')).toBeVisible() | ||
| await expect(page.getByRole('img', { name: 'Contributor 2' })).toBeVisible() | ||
| await expect(page.getByText('Contributor 2')).toBeVisible() | ||
| await expect(page.getByText('8 Contributions')).toBeVisible() | ||
| }) | ||
|
|
||
| test('toggle top contributors', async ({ page }) => { | ||
| await expect(page.getByRole('button', { name: 'Show more' })).toBeVisible() | ||
| await page.getByRole('button', { name: 'Show more' }).click() | ||
| await expect(page.getByRole('button', { name: 'Show less' })).toBeVisible() | ||
| await page.getByRole('button', { name: 'Show less' }).click() | ||
| await expect(page.getByRole('button', { name: 'Show more' })).toBeVisible() | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import { test, expect } from '@playwright/test' | ||
| import { mockChapterData } from '@unit/data/mockChapterData' | ||
|
|
||
| test.describe('Chapters Page', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await page.route('**/idx/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: JSON.stringify({ | ||
| hits: mockChapterData.chapters, | ||
| nbPages: 2, | ||
| }), | ||
| }) | ||
| }) | ||
| await page.goto('/chapters') | ||
| }) | ||
|
|
||
| test('renders chapter data correctly', async ({ page }) => { | ||
| await expect(page.getByRole('link', { name: 'Chapter 1' })).toBeVisible() | ||
| await expect(page.getByText('This is a summary of Chapter')).toBeVisible() | ||
| await expect(page.getByRole('link', { name: "Isanori Sakanashi's avatar" })).toBeVisible() | ||
| await expect(page.getByRole('button', { name: 'View Details' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('displays "No chapters found" when there are no chapters', async ({ page }) => { | ||
| await page.route('**/idx/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: JSON.stringify({ hits: [], nbPages: 0 }), | ||
| }) | ||
| }) | ||
| await page.goto('/chapters') | ||
| await expect(page.getByText('No chapters found')).toBeVisible() | ||
| }) | ||
|
|
||
| test('handles page change correctly', async ({ page }) => { | ||
| const nextPageButton = await page.getByRole('button', { name: '2' }) | ||
| await nextPageButton.click() | ||
| expect(await page.url()).toContain('page=2') | ||
| }) | ||
|
|
||
| test('opens window on View Details button click', async ({ page }) => { | ||
| const contributeButton = await page.getByRole('button', { name: 'View Details' }) | ||
| await contributeButton.click() | ||
| expect(await page.url()).toContain('chapters/chapter_1') | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,36 @@ | ||
| import { test, expect } from '@playwright/test' | ||
| import { mockCommitteeDetailsData } from '@unit/data/mockCommitteeDetailsData' | ||
|
|
||
| test.describe('Committee Details Page', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await page.route('**/graphql/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| json: { data: mockCommitteeDetailsData }, | ||
| }) | ||
| }) | ||
| await page.goto('/committees/test-committee') | ||
| }) | ||
|
|
||
| test('should have a heading and summary', async ({ page }) => { | ||
| await expect(page.getByRole('heading', { name: 'Test Committee' })).toBeVisible() | ||
| await expect(page.getByText('This is a test committee')).toBeVisible() | ||
| }) | ||
|
|
||
| test('should have committee details block', async ({ page }) => { | ||
| await expect(page.getByRole('heading', { name: 'Committee Details' })).toBeVisible() | ||
| await expect(page.getByText('Last Updated: Dec 13, 2024')).toBeVisible() | ||
| await expect(page.getByText('Leaders: Leader 1, Leader 2')).toBeVisible() | ||
| await expect(page.getByRole('link', { name: 'https://owasp.org/test-committee' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('should have top contributors', async ({ page }) => { | ||
| await expect(page.getByRole('heading', { name: 'Top Contributors' })).toBeVisible() | ||
| await expect(page.getByRole('img', { name: 'Contributor 1' })).toBeVisible() | ||
| await expect(page.getByText('Contributor 1')).toBeVisible() | ||
| await expect(page.getByText('2157 Contributions')).toBeVisible() | ||
| await expect(page.getByRole('img', { name: 'Contributor 2' })).toBeVisible() | ||
| await expect(page.getByText('Contributor 2')).toBeVisible() | ||
| await expect(page.getByText('309 Contributions')).toBeVisible() | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,47 @@ | ||
| import { test, expect } from '@playwright/test' | ||
| import { mockCommitteeData } from '@unit/data/mockCommitteeData' | ||
|
|
||
| test.describe('Committees Page', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await page.route('**/idx/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: JSON.stringify({ | ||
| hits: mockCommitteeData.committees, | ||
| nbPages: 2, | ||
| }), | ||
| }) | ||
| }) | ||
| await page.goto('/committees') | ||
| }) | ||
|
|
||
| test('renders committee data correctly', async ({ page }) => { | ||
| await expect(page.getByRole('link', { name: 'Committee 1' })).toBeVisible() | ||
| await expect(page.getByText('This is a summary of Committee 1')).toBeVisible() | ||
| await expect(page.getByRole('link', { name: "Sam Stepanyan's avatar" })).toBeVisible() | ||
| await expect(page.getByRole('button', { name: 'Learn more about Committee' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('displays "No committees found" when there are no committees', async ({ page }) => { | ||
| await page.route('**/idx/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: JSON.stringify({ hits: [], nbPages: 0 }), | ||
| }) | ||
| }) | ||
| await page.goto('/committees') | ||
|
Comment on lines
+25
to
+32
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix response field inconsistency in empty state test. The mock response uses body: JSON.stringify({ hits: [], totalPages: 0 }),
+ body: JSON.stringify({ hits: [], nbPages: 0 }),
|
||
| await expect(page.getByText('No committees found')).toBeVisible() | ||
| }) | ||
|
|
||
| test('handles page change correctly', async ({ page }) => { | ||
| const nextPageButton = await page.getByRole('button', { name: '2' }) | ||
| await nextPageButton.click() | ||
| expect(await page.url()).toContain('page=2') | ||
| }) | ||
|
|
||
| test('opens window on View Details button click', async ({ page }) => { | ||
| const contributeButton = await page.getByRole('button', { name: 'Learn more about Committee' }) | ||
| await contributeButton.click() | ||
| expect(await page.url()).toContain('committees/committee_1') | ||
| }) | ||
| }) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| import { test, expect } from '@playwright/test' | ||
| import { mockContributeData } from '@unit/data/mockContributeData' | ||
|
|
||
| test.describe('Contribute Page', () => { | ||
| test.beforeEach(async ({ page }) => { | ||
| await page.route('**/idx/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: JSON.stringify({ | ||
| hits: mockContributeData.issues, | ||
| nbPages: 2, | ||
| }), | ||
| }) | ||
| }) | ||
| await page.goto('/projects/contribute') | ||
| }) | ||
|
|
||
| test('renders issue data correctly', async ({ page }) => { | ||
| await expect(page.getByRole('link', { name: 'Contribution 1' })).toBeVisible() | ||
| await expect(page.getByText('2 months ago')).toBeVisible() | ||
| await expect(page.getByRole('link', { name: 'Owasp Nest' })).toBeVisible() | ||
| await expect(page.getByText('This is a summary of Contribution 1')).toBeVisible() | ||
| await expect(page.getByRole('button', { name: 'Read More' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('displays "No Issues found" when there are no issues', async ({ page }) => { | ||
| await page.route('**/idx/', async (route) => { | ||
| await route.fulfill({ | ||
| status: 200, | ||
| body: JSON.stringify({ hits: [], totalPages: 0 }), | ||
| }) | ||
| }) | ||
| await page.goto('/projects/contribute') | ||
| await expect(page.getByText('No issues found')).toBeVisible() | ||
| }) | ||
|
|
||
| test('handles page change correctly', async ({ page }) => { | ||
| const nextPageButton = await page.getByRole('button', { name: '2' }) | ||
| await nextPageButton.click() | ||
| expect(await page.url()).toContain('page=2') | ||
| }) | ||
|
|
||
| test('opens dialog on View Details button click', async ({ page }) => { | ||
| const contributeButton = await page.getByRole('button', { name: 'Read More' }) | ||
| await expect(contributeButton).toBeVisible() | ||
| await contributeButton.click() | ||
| await expect( | ||
| page | ||
| .locator('[id="dialog\\:\\:r3\\:\\:positioner"]') | ||
| .getByText('Contribution 1', { exact: true }) | ||
| ).toBeVisible() | ||
| await expect( | ||
| page.getByText( | ||
| 'The issue summary and the recommended steps to address it have been generated by AI' | ||
| ) | ||
| ).toBeVisible() | ||
| await expect(page.getByRole('link', { name: 'View Issue' })).toBeVisible() | ||
| }) | ||
|
|
||
| test('closes dialog on close button click', async ({ page }) => { | ||
| const contributeButton = await page.getByRole('button', { name: 'Read More' }) | ||
| await expect(contributeButton).toBeVisible() | ||
| await contributeButton.click() | ||
| const CloseButton = await page.getByRole('button', { name: 'close-modal' }) | ||
| await expect(CloseButton).toBeVisible() | ||
| await CloseButton.click() | ||
| await expect(contributeButton).toBeVisible() | ||
| }) | ||
| }) |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,103 @@ | ||||||||||||||||||||||||||||||
| import { test, expect } from '@playwright/test' | ||||||||||||||||||||||||||||||
| import { mockProjectDetailsData } from '@unit/data/mockProjectDetailsData' | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test.describe('Project Details Page', () => { | ||||||||||||||||||||||||||||||
| test.beforeEach(async ({ page }) => { | ||||||||||||||||||||||||||||||
| await page.route('**/graphql/', async (route) => { | ||||||||||||||||||||||||||||||
| await route.fulfill({ | ||||||||||||||||||||||||||||||
| status: 200, | ||||||||||||||||||||||||||||||
| json: { data: mockProjectDetailsData }, | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
| await page.goto('/projects/test-project') | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have a heading and summary', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Test Project' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect( | ||||||||||||||||||||||||||||||
| page.getByText('An example project showcasing GraphQL and Django integration.') | ||||||||||||||||||||||||||||||
| ).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project details block', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Project Details' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Last Updated: Feb 7, 2025')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Level: Lab')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Project Leaders: alice, bob')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('URL: https://github.com/')).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project statics block', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByText('2.2K Stars')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('10 Forks')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('1.2K Contributors')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('10 Issues')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('3 Repositories')).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project topics', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Topics' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('graphql', { exact: true })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('django', { exact: true })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('backend')).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project languages', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Languages' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Python', { exact: true })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('GraphQL', { exact: true })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('JavaScript', { exact: true })).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have top contributors', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Top Contributors' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('img', { name: 'Contributor 1' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Contributor 1')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('30 Contributions')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('img', { name: 'Contributor 2' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Contributor 2')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('29 Contributions')).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('toggle top contributors', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('button', { name: 'Show more' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await page.getByRole('button', { name: 'Show more' }).click() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('button', { name: 'Show less' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await page.getByRole('button', { name: 'Show less' }).click() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('button', { name: 'Show more' })).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project recent issues', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Recent Issues' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Fix authentication bug' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('img', { name: 'Dave Debugger' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Dave Debugger')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Feb 5, 2025')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('5 comments')).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project recent releases', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Recent Releases' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'V1.2.0' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('img', { name: 'Charlie Dev' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Charlie Dev')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Jan 20, 2025')).toBeVisible() | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
Comment on lines
+76
to
+85
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix incorrect heading assertion in recent releases test. The test is checking for "Recent Issues" heading when it should be checking for "Recent Releases" since this test is for recent releases functionality. - await expect(page.getByRole('heading', { name: 'Recent Issues' })).toBeVisible()
+ await expect(page.getByRole('heading', { name: 'Recent Releases' })).toBeVisible()📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| test('should have project repositories', async ({ page }) => { | ||||||||||||||||||||||||||||||
| await expect(page.getByRole('heading', { name: 'Repositories' })).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Repo One')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Stars95')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Forks12')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Contributors40')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Issues6')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Repo Two')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Stars60')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Forks8')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Contributors30')).toBeVisible() | ||||||||||||||||||||||||||||||
| await expect(page.getByText('Issues3', { exact: true })).toBeVisible() | ||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||
| await page.getByText('Repo One').click() | ||||||||||||||||||||||||||||||
| expect(page.url()).toContain('repositories/repo-1') | ||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
|
Comment on lines
+97
to
+102
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fix doubled expect statement in URL verification. The statement has nested expects which is unnecessary and potentially confusing. - expect(expect(page.url()).toContain('repositories/repo-1'))
+ expect(page.url()).toContain('repositories/repo-1')📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||
| }) | ||||||||||||||||||||||||||||||
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.
🛠️ Refactor suggestion
Fix variable naming for clarity.
The variable name doesn't match its purpose. It's named
contributeButtonbut it references the "View Details" button.test('opens window on View Details button click', async ({ page }) => { - const contributeButton = await page.getByRole('button', { name: 'View Details' }) - await contributeButton.click() + const viewDetailsButton = await page.getByRole('button', { name: 'View Details' }) + await viewDetailsButton.click() expect(await page.url()).toContain('chapters/chapter_1') })📝 Committable suggestion