kopia lustrzana https://github.com/cloudflare/wildebeest
refactor infinite scrolling e2e tests
create a new infinite scrolling e2e test so to keep the testing code DRYpull/283/head
rodzic
351b179b08
commit
d2a5ff122a
|
@ -1,67 +0,0 @@
|
||||||
import type { MastodonStatus } from 'wildebeest/frontend/src/types'
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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: MastodonStatus = {
|
|
||||||
id: `mock-fetch-status-${paddedNum}`,
|
|
||||||
created_at: new Date().toISOString(),
|
|
||||||
in_reply_to_id: null,
|
|
||||||
in_reply_to_account_id: null,
|
|
||||||
sensitive: false,
|
|
||||||
spoiler_text: '',
|
|
||||||
visibility: 'public',
|
|
||||||
language: 'en',
|
|
||||||
uri: '',
|
|
||||||
url: '',
|
|
||||||
replies_count: 0,
|
|
||||||
reblogs_count: 0,
|
|
||||||
favourites_count: 0,
|
|
||||||
edited_at: null,
|
|
||||||
content: `Mock Fetched Status #${paddedNum}`,
|
|
||||||
reblog: null,
|
|
||||||
account: {
|
|
||||||
id: '109355700962815786',
|
|
||||||
username: 'georgetakei',
|
|
||||||
acct: 'georgetakei@universeodon.com',
|
|
||||||
display_name: 'George Takei 🏳️🌈🖖🏽',
|
|
||||||
locked: false,
|
|
||||||
bot: false,
|
|
||||||
discoverable: true,
|
|
||||||
group: false,
|
|
||||||
created_at: '2022-11-15T00:00:00.000Z',
|
|
||||||
note: '\u003cp\u003eI boldly went to this new site. Follow for more recipes and tips.\u003c/p\u003e',
|
|
||||||
url: 'https://universeodon.com/@georgetakei',
|
|
||||||
avatar:
|
|
||||||
'https://files.mastodon.social/cache/accounts/avatars/109/355/700/962/815/786/original/7d278db7224de27d.jpg',
|
|
||||||
avatar_static:
|
|
||||||
'https://files.mastodon.social/cache/accounts/avatars/109/355/700/962/815/786/original/7d278db7224de27d.jpg',
|
|
||||||
header:
|
|
||||||
'https://files.mastodon.social/cache/accounts/headers/109/355/700/962/815/786/original/01c05d0b46e15480.jpg',
|
|
||||||
header_static:
|
|
||||||
'https://files.mastodon.social/cache/accounts/headers/109/355/700/962/815/786/original/01c05d0b46e15480.jpg',
|
|
||||||
followers_count: 331437,
|
|
||||||
following_count: 37,
|
|
||||||
statuses_count: 187,
|
|
||||||
last_status_at: '2023-01-04',
|
|
||||||
emojis: [],
|
|
||||||
fields: [],
|
|
||||||
},
|
|
||||||
media_attachments: [],
|
|
||||||
mentions: [],
|
|
||||||
tags: [],
|
|
||||||
emojis: [],
|
|
||||||
card: null,
|
|
||||||
poll: null,
|
|
||||||
}
|
|
||||||
numOfGeneratedMockStatuses++
|
|
||||||
return status
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { getMockStatusFn } from 'wildebeest/ui-e2e-tests-utils/getMockStatusFn'
|
|
||||||
|
|
||||||
test('Navigation to and view of an account (with 1 post)', async ({ page }) => {
|
test('Navigation to and view of an account (with 1 post)', async ({ page }) => {
|
||||||
await page.goto('http://127.0.0.1:8788/explore')
|
await page.goto('http://127.0.0.1:8788/explore')
|
||||||
|
@ -46,35 +45,3 @@ test('Navigation to and view of an account (with 2 posts)', async ({ page }) =>
|
||||||
await expect(post2Locator.getByRole('img', { name: 'Avatar of Raffa123$' })).toBeVisible()
|
await expect(post2Locator.getByRole('img', { name: 'Avatar of Raffa123$' })).toBeVisible()
|
||||||
await expect(post2Locator).toContainText('Hi! My name is Rafael!')
|
await expect(post2Locator).toContainText('Hi! My name is Rafael!')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Fetching of new account toots on scroll (infinite scrolling)', async ({ page, browserName }) => {
|
|
||||||
test.skip(browserName !== 'chromium', 'Only chromium tests this well')
|
|
||||||
|
|
||||||
const generateFakeStatus = getMockStatusFn()
|
|
||||||
await page.route('http://127.0.0.1:8788/api/v1/accounts/rafa/statuses?*', async (route) => {
|
|
||||||
const newStatuses = new Array(5).fill(null).map(generateFakeStatus)
|
|
||||||
await route.fulfill({ body: JSON.stringify(newStatuses) })
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.goto('http://127.0.0.1:8788/explore')
|
|
||||||
await page.locator('article').filter({ hasText: "I'm Rafa, a designer and app" }).locator('i.fa-globe + span').click()
|
|
||||||
await page.waitForLoadState('networkidle')
|
|
||||||
await page.getByRole('link', { name: 'Rafa', exact: true }).click()
|
|
||||||
await page.waitForLoadState('networkidle')
|
|
||||||
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { test, expect } from '@playwright/test'
|
import { test, expect } from '@playwright/test'
|
||||||
import { getMockStatusFn } from 'wildebeest/ui-e2e-tests-utils/getMockStatusFn'
|
|
||||||
|
|
||||||
test('Display the list of toots in the explore page', async ({ page }) => {
|
test('Display the list of toots in the explore page', async ({ page }) => {
|
||||||
await page.goto('http://127.0.0.1:8788/explore')
|
await page.goto('http://127.0.0.1:8788/explore')
|
||||||
|
@ -15,32 +14,3 @@ test('Display the list of toots in the explore page', async ({ page }) => {
|
||||||
await expect(page.locator('article').filter({ hasText: tootText })).toBeVisible()
|
await expect(page.locator('article').filter({ hasText: tootText })).toBeVisible()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
test('Fetching of new toots on scroll (infinite scrolling)', async ({ page, browserName }) => {
|
|
||||||
test.skip(browserName !== 'chromium', 'Only chromium tests this well')
|
|
||||||
|
|
||||||
const generateFakeStatus = getMockStatusFn()
|
|
||||||
await page.route('http://127.0.0.1:8788/api/v1/timelines/public?*', async (route) => {
|
|
||||||
const newStatuses = new Array(5).fill(null).map(generateFakeStatus)
|
|
||||||
await route.fulfill({ body: JSON.stringify(newStatuses) })
|
|
||||||
})
|
|
||||||
|
|
||||||
await page.goto('http://127.0.0.1:8788/explore')
|
|
||||||
await page.waitForLoadState('networkidle')
|
|
||||||
|
|
||||||
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)
|
|
||||||
})
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
import { test, expect, Page } 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 account page',
|
||||||
|
goToPageFn: async (page: Page) => {
|
||||||
|
await page.goto('http://127.0.0.1:8788/explore')
|
||||||
|
await page.locator('article').filter({ hasText: "I'm Rafael" }).locator('i.fa-globe + span').click()
|
||||||
|
await page.waitForLoadState('networkidle')
|
||||||
|
await page.getByRole('link', { name: 'Raffa123$', exact: true }).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 }) =>
|
||||||
|
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) => {
|
||||||
|
const 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: {} as Account,
|
||||||
|
media_attachments: [],
|
||||||
|
} as unknown as MastodonStatus
|
||||||
|
numOfGeneratedMockStatuses++
|
||||||
|
return status
|
||||||
|
}
|
||||||
|
}
|
Ładowanie…
Reference in New Issue