wildebeest/ui-e2e-tests/infinite-scrolling.spec.ts

92 wiersze
3.5 KiB
TypeScript

import { test, expect, Page, Request } from '@playwright/test'
import type { Account, MastodonStatus } from 'wildebeest/frontend/src/types'
test.describe('Infinite (statuses) scrolling', () => {
const tests = [
{
description: 'in explore page',
goToPageFn: async (page: Page) => await page.goto('http://127.0.0.1:8788/explore'),
fetchUrl: 'http://127.0.0.1:8788/api/v1/timelines/public?*',
},
{
description: 'in local page',
goToPageFn: async (page: Page) => await page.goto('http://127.0.0.1:8788/public/local'),
fetchUrl: 'http://127.0.0.1:8788/api/v1/timelines/public?*',
isRequestValid: (request: Request) => {
const searchParams = new URL(request.url()).searchParams
return searchParams.get('local') === 'true'
},
},
{
description: 'in federated page',
goToPageFn: async (page: Page) => await page.goto('http://127.0.0.1:8788/public'),
fetchUrl: 'http://127.0.0.1:8788/api/v1/timelines/public?*',
},
{
description: 'in account page',
goToPageFn: async (page: Page) => {
await page.goto('http://127.0.0.1:8788/explore')
await page.getByRole('article').getByRole('link').filter({ hasText: 'Raffa123$' }).first().click()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Raffa123$' })).toBeVisible()
},
fetchUrl: 'http://127.0.0.1:8788/api/v1/accounts/Rafael/statuses?*',
},
]
tests.forEach(({ description, fetchUrl, goToPageFn, isRequestValid }) =>
test(description, async ({ page, browserName }) => {
test.skip(browserName !== 'chromium', 'Only chromium tests infinite scrolling well')
await goToPageFn(page)
await page.waitForLoadState('networkidle')
const generateFakeStatus = getMockStatusFn()
await page.route(fetchUrl, async (route, request) => {
let newStatuses: MastodonStatus[] = []
if (!isRequestValid || isRequestValid(request)) {
newStatuses = new Array(5).fill(null).map(generateFakeStatus)
}
await route.fulfill({ body: JSON.stringify(newStatuses) })
})
for (let i = 0; i < 3; i++) {
await page.keyboard.down('End')
for (let j = 0; j < 5; j++) {
const paddedJ = `${i * 5 + j}`.padStart(3, '0')
// check that the new toots have been loaded
await expect(page.locator('article').filter({ hasText: `Mock Fetched Status #${paddedJ}` })).toBeVisible()
}
const paddedExtra = `${i * 5 + 6}`.padStart(3, '0')
// check that a 6th toot hasn't been loaded (since the mock endpoint returns 5 toots)
await expect(
page.locator('article').filter({ hasText: `Mock Fetched Status #${paddedExtra}` })
).not.toBeVisible()
}
const numOfMockFetchedToots = await page.locator('article').filter({ hasText: `Mock Fetched Status` }).count()
// check that all 15 toots have been loaded
expect(numOfMockFetchedToots).toBe(15)
})
)
})
/**
* generates a function that creates mock statuses when called,
* it uses a closure to keep track of the number of generated
* statuses to that they are consistently enumerated
* ('Mock Fetched Status #000', 'Mock Fetched Status #001', ...)
*/
export function getMockStatusFn(): () => MastodonStatus {
let numOfGeneratedMockStatuses = 0
return () => {
const paddedNum = `${numOfGeneratedMockStatuses}`.padStart(3, '0')
const status = {
content: `Mock Fetched Status #${paddedNum}`,
account: { display_name: 'test', emojis: [] } as unknown as Account,
media_attachments: [],
} as unknown as MastodonStatus
numOfGeneratedMockStatuses++
return status
}
}