kopia lustrzana https://github.com/cloudflare/wildebeest
Merge pull request #300 from cloudflare/account-link
Improve navigation to accounts and tootspull/294/head
commit
20be442595
|
@ -1,5 +1,5 @@
|
|||
import { createPerson, getPersonByEmail, type Person } from 'wildebeest/backend/src/activitypub/actors'
|
||||
import { replies, statuses } from 'wildebeest/frontend/src/dummyData'
|
||||
import { reblogs, replies, statuses } from 'wildebeest/frontend/src/dummyData'
|
||||
import type { Account, MastodonStatus } from 'wildebeest/frontend/src/types'
|
||||
import { Note } from 'wildebeest/backend/src/activitypub/objects/note'
|
||||
import { createReblog } from 'wildebeest/backend/src/mastodon/reblog'
|
||||
|
@ -24,8 +24,17 @@ export async function init(domain: string, db: D1Database) {
|
|||
loadedStatuses.push({ status, note })
|
||||
}
|
||||
|
||||
const { reblogger, noteToReblog } = await pickReblogDetails(loadedStatuses, domain, db)
|
||||
await createReblog(db, reblogger, noteToReblog)
|
||||
for (const reblog of reblogs) {
|
||||
const rebloggerAccount = reblog.account
|
||||
const reblogger = await getOrCreatePerson(domain, db, rebloggerAccount)
|
||||
const reblogStatus = reblog.reblog
|
||||
if (reblogStatus?.id) {
|
||||
const noteToReblog = loadedStatuses.find(({ status: { id } }) => id === reblogStatus.id)?.note
|
||||
if (noteToReblog) {
|
||||
await createReblog(db, reblogger, noteToReblog)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const reply of replies) {
|
||||
await createReply(domain, db, reply, loadedStatuses)
|
||||
|
@ -74,21 +83,3 @@ async function getOrCreatePerson(
|
|||
}
|
||||
return newPerson
|
||||
}
|
||||
|
||||
/**
|
||||
* Picks the details to use to reblog an arbitrary note/status.
|
||||
*
|
||||
* Both the note/status and the reblogger are picked arbitrarily
|
||||
* form a list of available notes/states (respectively from the first
|
||||
* and second entries).
|
||||
*/
|
||||
async function pickReblogDetails(
|
||||
loadedStatuses: { status: MastodonStatus; note: Note }[],
|
||||
domain: string,
|
||||
db: D1Database
|
||||
) {
|
||||
const rebloggerAccount = loadedStatuses[1].status.account
|
||||
const reblogger = await getOrCreatePerson(domain, db, rebloggerAccount)
|
||||
const noteToReblog = loadedStatuses[2].note
|
||||
return { reblogger, noteToReblog }
|
||||
}
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { component$, $, useStyles$ } from '@builder.io/qwik'
|
||||
import { Link, useNavigate } from '@builder.io/qwik-city'
|
||||
import { formatTimeAgo } from '~/utils/dateTime'
|
||||
import { Avatar } from '../avatar'
|
||||
import type { Account, MastodonStatus } from '~/types'
|
||||
import styles from '../../utils/innerHtmlContent.scss?inline'
|
||||
import { MediaGallery } from '../MediaGallery.tsx'
|
||||
import { useAccountUrl } from '~/utils/useAccountUrl'
|
||||
import { getDisplayNameElement } from '~/utils/getDisplayNameElement'
|
||||
import { StatusAccountCard } from '../StatusAccountCard/StatusAccountCard'
|
||||
|
||||
type Props = {
|
||||
status: MastodonStatus
|
||||
|
@ -27,28 +27,20 @@ export default component$((props: Props) => {
|
|||
return (
|
||||
<article class="p-4 border-t border-wildebeest-700 break-words sm:break-normal">
|
||||
<RebloggerLink account={reblogger}></RebloggerLink>
|
||||
<div onClick$={handleContentClick}>
|
||||
<div class="flex justify-between mb-3">
|
||||
<div class="flex">
|
||||
<Avatar primary={status.account} secondary={reblogger} />
|
||||
<div class="flex-col ml-3">
|
||||
<div>
|
||||
<Link class="no-underline" href={accountUrl}>
|
||||
{getDisplayNameElement(status.account)}
|
||||
</Link>
|
||||
</div>
|
||||
<div class="text-wildebeest-500">@{status.account.username}</div>
|
||||
</div>
|
||||
<div class="flex justify-between mb-3">
|
||||
<StatusAccountCard status={status} subText="username" secondaryAvatar={reblogger} />
|
||||
<Link class="no-underline" href={statusUrl}>
|
||||
<div class="text-wildebeest-500 flex items-baseline">
|
||||
<i style={{ height: '0.75rem', width: '0.75rem' }} class="fa fa-xs fa-globe w-3 h-3" />
|
||||
<span class="ml-2 text-sm hover:underline">{formatTimeAgo(new Date(status.created_at))}</span>
|
||||
</div>
|
||||
<Link class="no-underline" href={statusUrl}>
|
||||
<div class="text-wildebeest-500 flex items-baseline">
|
||||
<i style={{ height: '0.75rem', width: '0.75rem' }} class="fa fa-xs fa-globe w-3 h-3" />
|
||||
<span class="ml-2 text-sm hover:underline">{formatTimeAgo(new Date(status.created_at))}</span>
|
||||
</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div class="leading-relaxed inner-html-content" dangerouslySetInnerHTML={status.content} />
|
||||
</Link>
|
||||
</div>
|
||||
<div
|
||||
onClick$={handleContentClick}
|
||||
class="leading-relaxed inner-html-content cursor-pointer"
|
||||
dangerouslySetInnerHTML={status.content}
|
||||
/>
|
||||
|
||||
<MediaGallery medias={status.media_attachments} />
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
import { component$ } from '@builder.io/qwik'
|
||||
import { Link } from '@builder.io/qwik-city'
|
||||
import { type MastodonStatus } from '~/types'
|
||||
import { getDisplayNameElement } from '~/utils/getDisplayNameElement'
|
||||
import { useAccountUrl } from '~/utils/useAccountUrl'
|
||||
import { Avatar, type AvatarDetails } from '../avatar'
|
||||
|
||||
export const StatusAccountCard = component$<{
|
||||
status: MastodonStatus
|
||||
subText: 'username' | 'acct'
|
||||
secondaryAvatar?: AvatarDetails | null
|
||||
}>(({ status, subText, secondaryAvatar }) => {
|
||||
const accountUrl = useAccountUrl(status.account)
|
||||
|
||||
return (
|
||||
<Link
|
||||
href={accountUrl}
|
||||
class="inline-grid grid-cols-[repeat(2,_max-content)] grid-rows-[1fr,1fr] items-center no-underline"
|
||||
>
|
||||
<div class="row-span-2">
|
||||
<Avatar primary={status.account} secondary={secondaryAvatar ?? null} />
|
||||
</div>
|
||||
<div data-testid="account-display-name" class="ml-2 col-start-2 row-start-1">
|
||||
{getDisplayNameElement(status.account)}
|
||||
</div>
|
||||
<div class="ml-2 text-wildebeest-400 col-start-2 row-start-2">
|
||||
@{subText === 'username' ? status.account.username : status.account.acct}
|
||||
</div>
|
||||
</Link>
|
||||
)
|
||||
})
|
|
@ -1,32 +1,35 @@
|
|||
import { component$ } from '@builder.io/qwik'
|
||||
import { Link } from '@builder.io/qwik-city'
|
||||
import type { Account } from '~/types'
|
||||
import { useAccountUrl } from '~/utils/useAccountUrl'
|
||||
|
||||
type AvatarDetails = Partial<Pick<Account, 'id'>> & Pick<Account, 'display_name' | 'avatar' | 'url'>
|
||||
export type AvatarDetails = Partial<Pick<Account, 'id'>> & Pick<Account, 'display_name' | 'avatar' | 'url'>
|
||||
|
||||
type Props = {
|
||||
primary: AvatarDetails
|
||||
secondary: AvatarDetails | null
|
||||
withLinks?: boolean
|
||||
}
|
||||
|
||||
export const Avatar = component$<Props>(({ primary, secondary }) => {
|
||||
export const Avatar = component$<Props>(({ primary, secondary, withLinks }) => {
|
||||
const primaryUrl = useAccountUrl(primary)
|
||||
const secondaryUrl = useAccountUrl(secondary)
|
||||
|
||||
// eslint-disable-next-line qwik/single-jsx-root
|
||||
const primaryImg = <img class="rounded h-12 w-12" src={primary.avatar} alt={`Avatar of ${primary.display_name}`} />
|
||||
|
||||
const secondaryImg = (
|
||||
<img
|
||||
class="absolute right-0 bottom-0 rounded h-6 w-6"
|
||||
src={secondary?.avatar}
|
||||
alt={`Avatar of ${secondary?.display_name}`}
|
||||
/>
|
||||
)
|
||||
|
||||
return (
|
||||
<div class={`relative ${secondary && 'pr-2 pb-2'}`}>
|
||||
<a href={primaryUrl}>
|
||||
<img class="rounded h-12 w-12" src={primary.avatar} alt={`Avatar of ${primary.display_name}`} />
|
||||
</a>
|
||||
{secondary && (
|
||||
<a href={secondaryUrl}>
|
||||
<img
|
||||
class="absolute right-0 bottom-0 rounded h-6 w-6"
|
||||
src={secondary.avatar}
|
||||
alt={`Avatar of ${secondary.display_name}`}
|
||||
/>
|
||||
</a>
|
||||
)}
|
||||
{withLinks ? <Link href={primaryUrl}>{primaryImg}</Link> : primaryImg}
|
||||
{secondary && (withLinks ? <Link href={secondaryUrl}>{secondaryImg}</Link> : secondaryImg)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -5,8 +5,8 @@ export const george = generateDummyAccount({
|
|||
username: 'george',
|
||||
acct: 'george_george@dummy.users.wildebeest.com',
|
||||
display_name: 'George :verified: 👍',
|
||||
avatar: getAvatarUrl(805),
|
||||
avatar_static: getAvatarUrl(805),
|
||||
avatar: getAvatarUrl(837),
|
||||
avatar_static: getAvatarUrl(837),
|
||||
})
|
||||
|
||||
export const zak = generateDummyAccount({
|
||||
|
|
|
@ -5,7 +5,8 @@ export function generateDummyStatus(
|
|||
content: string,
|
||||
account: Account,
|
||||
mediaAttachments: MediaAttachment[] = [],
|
||||
inReplyTo: string | null = null
|
||||
inReplyTo: string | null = null,
|
||||
reblog: MastodonStatus | null = null
|
||||
): MastodonStatus {
|
||||
return {
|
||||
id: `${Math.random() * 9999999}`.padStart(3, '7'),
|
||||
|
@ -23,7 +24,7 @@ export function generateDummyStatus(
|
|||
favourites_count: Math.random() * 900,
|
||||
edited_at: null,
|
||||
content,
|
||||
reblog: null,
|
||||
reblog,
|
||||
application: { name: 'Wildebeest', website: null },
|
||||
account,
|
||||
media_attachments: mediaAttachments,
|
||||
|
|
|
@ -2,7 +2,7 @@ import type { MediaAttachment, MastodonStatus } from '~/types'
|
|||
import { generateDummyStatus } from './generateDummyStatus'
|
||||
import { ben, george, penny, rafael, zak } from './accounts'
|
||||
|
||||
// Raw statuses taken directly from mastodon
|
||||
// Raw statuses which follow the precise structure found mastodon does
|
||||
const mastodonRawStatuses: MastodonStatus[] = [
|
||||
generateDummyStatus(
|
||||
`
|
||||
|
@ -45,6 +45,8 @@ export const replies: MastodonStatus[] = [
|
|||
generateDummyStatus('<p> Yes you guys did it! </p>', penny, [], statuses[1].id),
|
||||
]
|
||||
|
||||
export const reblogs: MastodonStatus[] = [generateDummyStatus('', george, [], null, statuses[2])]
|
||||
|
||||
function getStandardMediaType(mediaAttachmentMastodonType: string): string {
|
||||
switch (mediaAttachmentMastodonType) {
|
||||
case 'image':
|
||||
|
|
|
@ -87,6 +87,7 @@ export default component$(() => {
|
|||
url: url.toString(),
|
||||
}}
|
||||
secondary={null}
|
||||
withLinks={true}
|
||||
/>
|
||||
</div>
|
||||
<p class="col-start-2">Signed in as:</p>
|
||||
|
|
|
@ -5,17 +5,15 @@ import { formatDateTime } from '~/utils/dateTime'
|
|||
import { formatRoundedNumber } from '~/utils/numbers'
|
||||
import * as statusAPI from 'wildebeest/functions/api/v1/statuses/[id]'
|
||||
import * as contextAPI from 'wildebeest/functions/api/v1/statuses/[id]/context'
|
||||
import { DocumentHead, Link, loader$ } from '@builder.io/qwik-city'
|
||||
import { DocumentHead, loader$ } from '@builder.io/qwik-city'
|
||||
import StickyHeader from '~/components/StickyHeader/StickyHeader'
|
||||
import { Avatar } from '~/components/avatar'
|
||||
import { MediaGallery } from '~/components/MediaGallery.tsx'
|
||||
import { getNotFoundHtml } from '~/utils/getNotFoundHtml/getNotFoundHtml'
|
||||
import { getErrorHtml } from '~/utils/getErrorHtml/getErrorHtml'
|
||||
import styles from '../../../../utils/innerHtmlContent.scss?inline'
|
||||
import { getTextContent } from 'wildebeest/backend/src/activitypub/objects'
|
||||
import { getDocumentHead } from '~/utils/getDocumentHead'
|
||||
import { useAccountUrl } from '~/utils/useAccountUrl'
|
||||
import { getDisplayNameElement } from '~/utils/getDisplayNameElement'
|
||||
import { StatusAccountCard } from '~/components/StatusAccountCard/StatusAccountCard'
|
||||
|
||||
export const statusLoader = loader$<
|
||||
{ DATABASE: D1Database },
|
||||
|
@ -57,7 +55,7 @@ export default component$(() => {
|
|||
<>
|
||||
<StickyHeader withBackButton />
|
||||
<div class="bg-wildebeest-700 p-4">
|
||||
<AccountCard status={loaderData.status} />
|
||||
<StatusAccountCard subText="acct" status={loaderData.status} />
|
||||
<div class="leading-normal inner-html-content text-lg" dangerouslySetInnerHTML={loaderData.status.content} />
|
||||
|
||||
<MediaGallery medias={loaderData.status.media_attachments} />
|
||||
|
@ -73,24 +71,6 @@ export default component$(() => {
|
|||
)
|
||||
})
|
||||
|
||||
export const AccountCard = component$<{ status: MastodonStatus }>(({ status }) => {
|
||||
const accountUrl = useAccountUrl(status.account)
|
||||
|
||||
return (
|
||||
<div class="flex">
|
||||
<Avatar primary={status.account} secondary={null} />
|
||||
<div class="flex flex-col">
|
||||
<div class="p-1">
|
||||
<Link href={accountUrl} class="no-underline">
|
||||
{getDisplayNameElement(status.account)}
|
||||
</Link>
|
||||
</div>
|
||||
<div class="p-1 text-wildebeest-400">@{status.account.acct}</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})
|
||||
|
||||
export const InfoTray = component$<{ status: MastodonStatus }>(({ status }) => {
|
||||
return (
|
||||
<div class="text-wildebeest-500 mt-4 text-sm">
|
||||
|
|
|
@ -1,41 +1,26 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
const navigationsVia = ['name link', 'avatar'] as const
|
||||
test(`Navigation via to and view of an account (with 1 post)`, async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:8788/explore')
|
||||
await page.getByRole('article').getByRole('link').filter({ hasText: 'Ben, just Ben' }).first().click()
|
||||
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('1Posts0Following0Followers')
|
||||
|
||||
navigationsVia.forEach((via) =>
|
||||
test(`Navigation via ${via} to and view of an account (with 1 post)`, async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:8788/explore')
|
||||
await page.getByRole('article').getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
|
||||
await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
|
||||
await page.waitForLoadState('networkidle')
|
||||
const linkOption =
|
||||
via === 'name link' ? { name: 'Ben, just Ben', exact: true } : { name: 'Avatar of Ben, just Ben' }
|
||||
await page.getByRole('link', linkOption).click()
|
||||
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('1Posts0Following0Followers')
|
||||
|
||||
expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(1)
|
||||
await expect(
|
||||
page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' })
|
||||
).toBeVisible()
|
||||
await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText(
|
||||
'A very simple update: all good!'
|
||||
)
|
||||
})
|
||||
)
|
||||
expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(1)
|
||||
await expect(
|
||||
page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' })
|
||||
).toBeVisible()
|
||||
await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText(
|
||||
'A very simple update: all good!'
|
||||
)
|
||||
})
|
||||
|
||||
test('Navigation to and view of an account (with 2 posts)', async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:8788/explore')
|
||||
await page
|
||||
.locator('article')
|
||||
.filter({ hasText: "I'm Rafael and I am a web designer" })
|
||||
.locator('i.fa-globe + span')
|
||||
.click()
|
||||
await page.waitForLoadState('networkidle')
|
||||
await page.getByRole('link', { name: 'Raffa123$', exact: true }).click()
|
||||
await page.getByRole('article').getByRole('link').filter({ hasText: 'Raffa123$' }).first().click()
|
||||
|
||||
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Raffa123$' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Raffa123$' })).toBeVisible()
|
||||
|
|
|
@ -40,7 +40,11 @@ test('View of custom emojis in an toots author display name', async ({ page, bro
|
|||
.locator('i.fa-globe + span')
|
||||
.click()
|
||||
|
||||
const customEmojiLocator = page.getByRole('link', { name: 'George :verified: 👍', exact: true }).getByRole('img')
|
||||
const customEmojiLocator = page
|
||||
.getByRole('link')
|
||||
.filter({ hasText: 'George' })
|
||||
.getByTestId('account-display-name')
|
||||
.getByRole('img')
|
||||
await expect(customEmojiLocator).toBeVisible()
|
||||
await expect(customEmojiLocator).toHaveAttribute(
|
||||
'src',
|
||||
|
|
|
@ -26,9 +26,7 @@ test.describe('Infinite (statuses) scrolling', () => {
|
|||
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 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?*',
|
||||
|
|
|
@ -1,13 +1,21 @@
|
|||
import { test, expect } from '@playwright/test'
|
||||
|
||||
test('Navigation to and view of an individual toot', async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:8788/explore')
|
||||
await page.locator('article').filter({ hasText: 'Ben, just Ben' }).locator('i.fa-globe + span').click()
|
||||
await expect(page.getByRole('button', { name: 'Back' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Avatar of Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Ben, just Ben', exact: true })).toBeVisible()
|
||||
await expect(page.locator('span', { hasText: 'A very simple update: all good!' })).toBeVisible()
|
||||
})
|
||||
const navigationVias = ['time link', 'toot content'] as const
|
||||
|
||||
navigationVias.forEach((via) =>
|
||||
test(`Navigation to and view of an individual toot via ${via}`, async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:8788/explore')
|
||||
if (via === 'time link') {
|
||||
await page.locator('article').filter({ hasText: 'Ben, just Ben' }).locator('i.fa-globe + span').click()
|
||||
} else {
|
||||
await page.getByText('A very simple update: all good!').click()
|
||||
}
|
||||
await expect(page.getByRole('button', { name: 'Back' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Avatar of Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.getByTestId('account-display-name').filter({ hasText: 'Ben, just Ben' })).toBeVisible()
|
||||
await expect(page.locator('span', { hasText: 'A very simple update: all good!' })).toBeVisible()
|
||||
})
|
||||
)
|
||||
|
||||
test('Navigation to and view of an individual toot with images', async ({ page }) => {
|
||||
await page.goto('http://127.0.0.1:8788/explore')
|
||||
|
@ -18,7 +26,7 @@ test('Navigation to and view of an individual toot with images', async ({ page }
|
|||
.click()
|
||||
await expect(page.getByRole('button', { name: 'Back' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Avatar of Raffa123$' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Raffa123$', exact: true })).toBeVisible()
|
||||
await expect(page.getByTestId('account-display-name').filter({ hasText: 'Raffa123$' })).toBeVisible()
|
||||
await expect(page.locator('p', { hasText: "I'm Rafael and I am a web designer!" })).toBeVisible()
|
||||
expect(await page.getByTestId('media-gallery').getByRole('img').count()).toBe(4)
|
||||
await expect(page.getByTestId('images-modal')).not.toBeVisible()
|
||||
|
@ -57,7 +65,7 @@ test("Navigation to and view of a toot's replies", async ({ page }) => {
|
|||
.click()
|
||||
|
||||
await expect(page.getByRole('link', { name: 'Avatar of Zak Smith' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Zak Smith', exact: true })).toBeVisible()
|
||||
await expect(page.getByTestId('account-display-name').filter({ hasText: 'Zak Smith' })).toBeVisible()
|
||||
await expect(page.getByText('Yes we did!')).toBeVisible()
|
||||
|
||||
await page.getByRole('button', { name: 'Back' }).click()
|
||||
|
@ -72,6 +80,6 @@ test("Navigation to and view of a toot's replies", async ({ page }) => {
|
|||
.click()
|
||||
|
||||
await expect(page.getByRole('link', { name: 'Avatar of Penny' })).toBeVisible()
|
||||
await expect(page.getByRole('link', { name: 'Penny', exact: true })).toBeVisible()
|
||||
await expect(page.getByTestId('account-display-name').filter({ hasText: 'Penny' })).toBeVisible()
|
||||
await expect(page.getByText('Yes you guys did it!')).toBeVisible()
|
||||
})
|
||||
|
|
Ładowanie…
Reference in New Issue