improve dummy data and tests

- improve the dummy data to be generated when building the mock db
- restructure dummy data folder structure
- remove all real data from the dummy data
- update the tests to use the new dummay data, and also
  - fix the incorrect 404 test
  - add a test for viewing images
pull/285/head
Dario Piotrowicz 2023-02-14 21:16:51 +00:00
rodzic 5c2e0d0282
commit 7700f40041
16 zmienionych plików z 729 dodań i 1832 usunięć

Wyświetl plik

@ -11,10 +11,14 @@ export const ImagesModal = component$<Props>(({ images, idxOfCurrentImage: initi
const idxOfCurrentImage = useSignal(initialIdx)
return (
<div class="pointer-events-auto cursor-default z-50 fixed inset-0 isolate flex items-center justify-between backdrop-blur-sm">
<div
data-testid="images-modal"
class="pointer-events-auto cursor-default z-50 fixed inset-0 isolate flex items-center justify-between backdrop-blur-sm"
>
<div class="inset-0 absolute z-[-1] bg-wildebeest-900 opacity-70" onClick$={() => onCloseImagesModal$()}></div>
{images.length > 1 && (
<button
data-testid="left-btn"
class="cursor-pointer text-4xl opacity-60 hover:opacity-90 focus-visible:opacity-90"
onClick$={() => {
const idx = idxOfCurrentImage.value - 1
@ -27,6 +31,7 @@ export const ImagesModal = component$<Props>(({ images, idxOfCurrentImage: initi
<img class="ma max-w-[80vw] max-h-[90vh] m-auto" src={images[idxOfCurrentImage.value].url} />
{images.length > 1 && (
<button
data-testid="right-btn"
class="cursor-pointer text-4xl opacity-60 hover:opacity-90 focus-visible:opacity-90"
onClick$={() => {
idxOfCurrentImage.value = (idxOfCurrentImage.value + 1) % images.length
@ -36,6 +41,7 @@ export const ImagesModal = component$<Props>(({ images, idxOfCurrentImage: initi
</button>
)}
<button
data-testid="close-btn"
class="cursor-pointer absolute top-7 right-7 text-4xl opacity-60 hover:opacity-90 focus-visible:opacity-90"
onClick$={() => onCloseImagesModal$()}
>

Wyświetl plik

@ -34,7 +34,10 @@ export const MediaGallery = component$<Props>(({ medias }) => {
return (
<>
{!!medias.length && (
<div class={`media-gallery overflow-hidden grid gap-1 h-52 md:h-60 lg:h-72 xl:h-80`}>
<div
data-testid="media-gallery"
class={`media-gallery overflow-hidden grid gap-1 h-52 md:h-60 lg:h-72 xl:h-80`}
>
{medias.map((media) => (
<div class="w-full flex items-center justify-center overflow-hidden bg-black">
{media.type === 'image' && <Image mediaAttachment={media} onOpenImagesModal$={onOpenImagesModal} />}

Plik diff jest za duży Load Diff

Wyświetl plik

@ -0,0 +1,106 @@
import { type Account } from '~/types'
import { getRandomDateInThePastYear } from './getRandomDateInThePastYear'
export const george = generateDummyAccount({
username: 'george',
acct: 'george_george@dummy.users.wildebeest.com',
display_name: 'George :verified: 👍',
avatar: getAvatarUrl(805),
avatar_static: getAvatarUrl(805),
})
export const zak = generateDummyAccount({
username: 'ZakSmith',
acct: 'ZakSmith',
display_name: 'Zak Smith',
avatar: getAvatarUrl(75),
avatar_static: getAvatarUrl(75),
})
export const penny = generateDummyAccount({
username: 'Penny',
acct: 'Penny',
display_name: 'Penny',
avatar: getAvatarUrl(140),
avatar_static: getAvatarUrl(140),
})
export const ben = generateDummyAccount({
username: 'Ben',
acct: 'ben',
display_name: 'Ben, just Ben',
avatar: getAvatarUrl(1148),
avatar_static: getAvatarUrl(1148),
})
export const rafael = generateDummyAccount({
username: 'Rafael',
acct: 'raffa',
display_name: 'Raffa123$',
avatar: getAvatarUrl(157),
avatar_static: getAvatarUrl(309),
})
function generateDummyAccount(
details: Pick<Account, 'username' | 'acct' | 'display_name' | 'avatar' | 'avatar_static'>
): Account {
return {
...details,
id: `${Math.round(Math.random() * 9999999)}`.padStart(7, '0'),
locked: false,
bot: false,
discoverable: true,
group: false,
created_at: getRandomDateInThePastYear().toISOString(),
note: '<p>A simple note!</p>',
url: `https://dummay.users.wildebeest.com/@${details.username}`,
header: getRandomHeaderUrl(),
header_static: getRandomHeaderUrl(),
followers_count: Math.round(Math.random() * 100),
following_count: Math.round(Math.random() * 100),
statuses_count: Math.round(Math.random() * 100),
last_status_at: getLastStatusAt(),
emojis: [
{
shortcode: 'verified',
url: 'https://files.mastodon.social/cache/custom_emojis/images/000/452/462/original/947cae7ac4dfdfa0.png',
static_url: 'https://files.mastodon.social/cache/custom_emojis/images/000/452/462/static/947cae7ac4dfdfa0.png',
visible_in_picker: true,
},
],
fields: [
{
name: 'Instagram',
value:
'<a href="https://www.instagram.com/" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://www.</span><span class="">instagram.com</span><span class="invisible"></span></a>',
verified_at: null,
},
{
name: 'Twitter',
value:
'<a href="https://twitter.com/" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://</span><span class="">twitter.com</span><span class="invisible"></span></a>',
verified_at: null,
},
{
name: 'Facebook',
value:
'<a href="https://www.facebook.com/" rel="nofollow noopener noreferrer" target="_blank"><span class="invisible">https://www.</span><span class="">facebook.com</span><span class="invisible"></span></a>',
verified_at: null,
},
],
}
}
// the number should be between 0 and 1249
function getAvatarUrl(number: number) {
return `https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/${number}.jpg`
}
function getRandomHeaderUrl() {
return `https:/loremflickr.com/640/480/wildebeest?lock=${Math.round(Math.random() * 999999)}`
}
function getLastStatusAt() {
const date = getRandomDateInThePastYear()
return `${date.getFullYear()}-${date.getMonth() + 1}-${date.getDate()}`
}

Wyświetl plik

@ -0,0 +1,36 @@
import { Account, MastodonStatus, MediaAttachment } from '~/types'
import { getRandomDateInThePastYear } from './getRandomDateInThePastYear'
export function generateDummyStatus(
content: string,
account: Account,
mediaAttachments: MediaAttachment[] = [],
inReplyTo: string | null = null
): MastodonStatus {
return {
id: `${Math.random() * 9999999}`.padStart(3, '7'),
created_at: getRandomDateInThePastYear().toISOString(),
in_reply_to_id: inReplyTo,
in_reply_to_account_id: null,
sensitive: false,
spoiler_text: '',
visibility: 'public',
language: 'en',
uri: '',
url: '',
replies_count: 0,
reblogs_count: 0,
favourites_count: Math.random() * 900,
edited_at: null,
content,
reblog: null,
application: { name: 'Wildebeest', website: null },
account,
media_attachments: mediaAttachments,
mentions: [],
tags: [],
emojis: [],
card: null,
poll: null,
}
}

Wyświetl plik

@ -0,0 +1,11 @@
export function getRandomDateInThePastYear(): Date {
const nowDate = new Date()
const pastDate = new Date(nowDate.getFullYear() - 1, nowDate.getMonth(), nowDate.getDate())
const pastDateInMillis = pastDate.getTime()
const nowDateInMillis = nowDate.getTime()
const random = Math.random()
const randomDateInMillis = pastDateInMillis + random * (nowDateInMillis - pastDateInMillis)
return new Date(randomDateInMillis)
}

Wyświetl plik

@ -0,0 +1,3 @@
export * from './statuses'
export * from './tags'
export * from './links'

Wyświetl plik

@ -0,0 +1,259 @@
import { MastodonLink } from '../types'
export const links: Array<MastodonLink> = [
{
url: 'https://www.forbes.com/sites/emilybaker-white/2022/12/22/tiktok-tracks-forbes-journalists-bytedance/',
title: 'EXCLUSIVE: TikTok Spied On Forbes Journalists',
description:
'ByteDance confirmed it used TikTok to monitor journalists physical location using their IP addresses, as first reported by Forbes in October.',
type: 'link',
author_name: 'Emily Baker-White',
author_url: 'https://www.forbes.com/sites/emilybaker-white/',
provider_name: 'Forbes',
provider_url: '',
html: '',
width: 400,
height: 161,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/524/205/original/471cd0adc1ee6409.jpg',
embed_url: '',
blurhash: 'UICsHx$*0Ko}w{RPnix]E1NZ-;s:gNkWRjM{',
history: [
{ day: '1671753600', accounts: '1503', uses: '1657' },
{ day: '1671667200', accounts: '1537', uses: '1727' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.theverge.com/2022/12/22/23523322/lastpass-data-breach-cloud-encrypted-password-vault-hackers',
title: 'Hackers stole encrypted LastPass password vaults, and were just now hearing about it',
description:
'LastPass has announced that during a November data breach of its cloud storage, hackers copied a backup of customer vault data that includes encrypted usernames and passwords.',
type: 'link',
author_name: 'Mitchell Clark',
author_url: '',
provider_name: 'The Verge',
provider_url: '',
html: '',
width: 400,
height: 209,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/539/308/original/64c8d7b28cfaad2f.jpg',
embed_url: '',
blurhash: 'UfF;eEs,FRSiD^ajbXWXtvbb#hslECWVs%oL',
history: [
{ day: '1671753600', accounts: '282', uses: '291' },
{ day: '1671667200', accounts: '0', uses: '0' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://arstechnica.com/tech-policy/2022/12/facial-recognition-flags-girl-scout-mom-as-security-risk-at-rockettes-show/',
title: 'MSG defends using facial recognition to kick lawyer out of Rockettes show',
description: 'MSG Entertainment began using facial recognition at venues in 2018.',
type: 'link',
author_name: '',
author_url: '',
provider_name: 'Ars Technica',
provider_url: '',
html: '',
width: 400,
height: 267,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/356/463/original/3d7c9f4eb7630b3a.jpg',
embed_url: '',
blurhash: 'ULBV@rQ+R%krPWR4n$o#1JV@oJof#RofbHWB',
history: [
{ day: '1671753600', accounts: '704', uses: '705' },
{ day: '1671667200', accounts: '3191', uses: '3228' },
{ day: '1671580800', accounts: '48', uses: '51' },
{ day: '1671494400', accounts: '17', uses: '17' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.theatlantic.com/ideas/archive/2022/12/zelensky-congress-speech-us-ukraine-support/672547/',
title: 'The Brutal Alternate World in Which the U.S. Abandoned Ukraine',
description: 'Ukrainian resistance and American support prevented a wide range of horrors.',
type: 'link',
author_name: 'Anne Applebaum',
author_url: '',
provider_name: 'The Atlantic',
provider_url: '',
html: '',
width: 400,
height: 208,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/495/789/original/a464705b4eba4614.jpg',
embed_url: '',
blurhash: 'U14B:,4oW9M_Roavt8ax4nxt%NRjRhohayax',
history: [
{ day: '1671753600', accounts: '113', uses: '117' },
{ day: '1671667200', accounts: '441', uses: '452' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.washingtonpost.com/national-security/2022/12/22/jan-6-committee-trump-should-never-hold-office-again/',
title: 'Jan. 6 committee: Trump should never hold office again',
description:
'The committees recommendation came as part of an 800-plus page report that marks the culmination of its 18-month investigation',
type: 'link',
author_name: 'Amy Gardner',
author_url: 'https://www.washingtonpost.com/people/amy-gardner/',
provider_name: 'The Washington Post',
provider_url: '',
html: '',
width: 400,
height: 267,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/548/842/original/5a159d17dc4b084a.jpeg',
embed_url: '',
blurhash: 'UKE.kHxaI9RO~TofMwn#SiWXNHWBIAWVtSoz',
history: [
{ day: '1671753600', accounts: '116', uses: '119' },
{ day: '1671667200', accounts: '0', uses: '0' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.washingtonpost.com/media/2022/12/23/musk-twitter-journalists-suspended-elonjet/',
title: 'Journalists who wont delete Musk tweets remain locked out of Twitter',
description:
'Musk suspended reporters from Twitter and later reinstated them, with a catch: They must delete tweets related to the account @ElonJet, which has tracked Musks plane using public data.',
type: 'link',
author_name: 'Paul Farhi',
author_url: 'https://www.washingtonpost.com/people/paul-farhi/',
provider_name: 'The Washington Post',
provider_url: '',
html: '',
width: 400,
height: 267,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/596/043/original/699238391e3433a5.jpeg',
embed_url: '',
blurhash: 'UA8gjY9DEMJDxUjdInNeIoNG-p$y9tt7xaxZ',
history: [
{ day: '1671753600', accounts: '119', uses: '120' },
{ day: '1671667200', accounts: '0', uses: '0' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.reuters.com/legal/facebook-parent-meta-pay-725-mln-settle-lawsuit-relating-cambridge-analytica-2022-12-23/',
title: 'Facebook parent Meta to settle Cambridge Analytica scandal case for $725 mln',
description:
'Facebook owner Meta Platforms Inc \u003ca href="https://www.reuters.com/companies/META.O" target="_blank"\u003e(META.O)\u003c/a\u003e has agreed to pay $725 million to resolve a class-action lawsuit accusing the social media giant of allowing third parties, including Cambridge Analytica, to access users\' personal information.',
type: 'link',
author_name: '',
author_url: '',
provider_name: 'Reuters',
provider_url: '',
html: '',
width: 400,
height: 209,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/566/114/original/1d0630d4cf841790.jpg',
embed_url: '',
blurhash: 'UPNKbeMwMH?GWBWAog.8McofR*%NNHIUof-;',
history: [
{ day: '1671753600', accounts: '92', uses: '97' },
{ day: '1671667200', accounts: '0', uses: '0' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.bloomberg.com/news/articles/2022-12-22/musk-s-frequent-twitter-polls-are-at-risk-of-bot-manipulation',
title: 'Musks Frequent Twitter Polls Are at Risk of Bot Manipulation',
description: 'New research shows votes can be easily purchased during Twitter polls',
type: 'link',
author_name: 'Davey Alba',
author_url: '',
provider_name: 'Bloomberg',
provider_url: '',
html: '',
width: 400,
height: 267,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/514/000/original/1bf993cf6612abd8.jpg',
embed_url: '',
blurhash: 'UHAfCIofo~o#ysWYeRWCDibHWAj?t8j@o}of',
history: [
{ day: '1671753600', accounts: '23', uses: '24' },
{ day: '1671667200', accounts: '170', uses: '196' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.wsj.com/articles/u-s-life-expectancy-fell-to-lowest-level-since-1996-11671667059',
title: 'U.S. Life Expectancy Fell to Lowest Level Since 1996',
description: 'Covid-19 and opioid overdoses contributed to a 5% rise in death rate last year',
type: 'link',
author_name: 'Julie Wernau',
author_url: '',
provider_name: 'The Wall Street Journal',
provider_url: '',
html: '',
width: 400,
height: 200,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/485/157/original/3668ba0bbaf09ebc.jpeg',
embed_url: '',
blurhash: 'UkMDZ69^v$}qrYkCo|M}OYw^I:OXRjj[t7jF',
history: [
{ day: '1671753600', accounts: '31', uses: '31' },
{ day: '1671667200', accounts: '165', uses: '168' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
{
url: 'https://www.wired.com/story/email-scam-dicks-sporting-goods-yeti-cooler/',
title: 'No, You Havent Won a Yeti Cooler From Dicks Sporting Goods',
description: 'The future of email spam utilizes a coding trick that evades the most sophisticated detection tools.',
type: 'link',
author_name: 'Lauren Goode',
author_url: '',
provider_name: 'WIRED',
provider_url: '',
html: '',
width: 400,
height: 209,
image: 'https://files.mastodon.social/cache/preview_cards/images/050/574/335/original/e10dbfa75b92a64a.jpg',
embed_url: '',
blurhash: 'UMBVv7#GI_OTV$-Lx9V|5eSw$dxDtJEoJEX7',
history: [
{ day: '1671753600', accounts: '70', uses: '72' },
{ day: '1671667200', accounts: '0', uses: '0' },
{ day: '1671580800', accounts: '0', uses: '0' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
],
},
]

Wyświetl plik

@ -0,0 +1,75 @@
import type { MediaAttachment, MastodonStatus } from '~/types'
import { generateDummyStatus } from './generateDummyStatus'
import { ben, george, penny, rafael, zak } from './accounts'
// Raw statuses taken directly from mastodon
const mastodonRawStatuses: MastodonStatus[] = [
generateDummyStatus("<p>Fine. I'll use Wildebeest!</p>", george),
generateDummyStatus('We did it!', george, [
generateDummyMediaImage(`https:/loremflickr.com/640/480/victory?lock=${Math.round(Math.random() * 999999)}`),
]),
generateDummyStatus('<span>A very simple update: all good!</span>', ben),
generateDummyStatus('<p>Hi! My name is Rafael! 👋</p>', rafael),
generateDummyStatus(
"<div><p>I'm Rafael and I am a web designer!</p><p>💪💪</p></div>",
rafael,
new Array(4)
.fill(null)
.map((_, idx) => generateDummyMediaImage(`https:/loremflickr.com/640/480/abstract?lock=${100 + idx}`))
),
]
export const statuses: MastodonStatus[] = mastodonRawStatuses.map((rawStatus) => ({
...rawStatus,
media_attachments: rawStatus.media_attachments.map((mediaAttachment) => ({
...mediaAttachment,
type: getStandardMediaType(mediaAttachment.type),
})),
}))
export const replies: MastodonStatus[] = [
generateDummyStatus('<p>Yes we did! 🎉</p>', zak, [], statuses[1].id),
generateDummyStatus('<p> Yes you guys did it! </p>', penny, [], statuses[1].id),
]
function getStandardMediaType(mediaAttachmentMastodonType: string): string {
switch (mediaAttachmentMastodonType) {
case 'image':
return 'Image'
case 'video':
return 'Video'
}
return mediaAttachmentMastodonType
}
function generateDummyMediaImage(imageUrl: string): MediaAttachment {
return {
id: `${Math.random() * 9999999}`.padStart(3, '7'),
type: 'image',
url: imageUrl,
preview_url: imageUrl,
remote_url: null,
preview_remote_url: null,
text_url: null,
meta: {
original: {
width: 1821,
height: 1138,
size: '1821x1138',
aspect: 1.6001757469244289,
},
small: {
width: 606,
height: 379,
size: '606x379',
aspect: 1.5989445910290236,
},
focus: {
x: 0.0,
y: 0.0,
},
},
description: 'A dummy image',
blurhash: '',
}
}

Wyświetl plik

@ -0,0 +1,134 @@
import { type TagDetails } from '../types'
export const tags: TagDetails[] = [
{
name: 'wintersolstice',
url: 'https://mastodon.social/tags/wintersolstice',
history: [
{ day: '1671580800', accounts: '951', uses: '1113' },
{ day: '1671494400', accounts: '59', uses: '75' },
{ day: '1671408000', accounts: '24', uses: '25' },
{ day: '1671321600', accounts: '19', uses: '21' },
{ day: '1671235200', accounts: '13', uses: '16' },
{ day: '1671148800', accounts: '13', uses: '13' },
{ day: '1671062400', accounts: '8', uses: '8' },
],
},
{
name: 'solstice',
url: 'https://mastodon.social/tags/solstice',
history: [
{ day: '1671580800', accounts: '954', uses: '1114' },
{ day: '1671494400', accounts: '80', uses: '118' },
{ day: '1671408000', accounts: '19', uses: '22' },
{ day: '1671321600', accounts: '24', uses: '28' },
{ day: '1671235200', accounts: '14', uses: '14' },
{ day: '1671148800', accounts: '9', uses: '9' },
{ day: '1671062400', accounts: '11', uses: '11' },
],
},
{
name: 'transitiontuesday',
url: 'https://mastodon.social/tags/transitiontuesday',
history: [
{ day: '1671580800', accounts: '92', uses: '103' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
{ day: '1671148800', accounts: '0', uses: '0' },
{ day: '1671062400', accounts: '0', uses: '0' },
],
},
{
name: 'mustardmovies',
url: 'https://mastodon.social/tags/mustardmovies',
history: [
{ day: '1671580800', accounts: '88', uses: '437' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
{ day: '1671148800', accounts: '0', uses: '0' },
{ day: '1671062400', accounts: '0', uses: '0' },
],
},
{
name: 'oddesttrumptaxdeductions',
url: 'https://mastodon.social/tags/oddesttrumptaxdeductions',
history: [
{ day: '1671580800', accounts: '73', uses: '113' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
{ day: '1671148800', accounts: '0', uses: '0' },
{ day: '1671062400', accounts: '0', uses: '0' },
],
},
{
name: 'wintersonnenwende',
url: 'https://mastodon.social/tags/wintersonnenwende',
history: [
{ day: '1671580800', accounts: '162', uses: '176' },
{ day: '1671494400', accounts: '8', uses: '8' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '1', uses: '1' },
{ day: '1671235200', accounts: '2', uses: '2' },
{ day: '1671148800', accounts: '0', uses: '0' },
{ day: '1671062400', accounts: '1', uses: '1' },
],
},
{
name: 'solsticehedgehog',
url: 'https://mastodon.social/tags/solsticehedgehog',
history: [
{ day: '1671580800', accounts: '54', uses: '61' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '0', uses: '0' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
{ day: '1671148800', accounts: '0', uses: '0' },
{ day: '1671062400', accounts: '0', uses: '0' },
],
},
{
name: 'waterfallwednesday',
url: 'https://mastodon.social/tags/waterfallwednesday',
history: [
{ day: '1671580800', accounts: '109', uses: '116' },
{ day: '1671494400', accounts: '4', uses: '4' },
{ day: '1671408000', accounts: '3', uses: '3' },
{ day: '1671321600', accounts: '1', uses: '1' },
{ day: '1671235200', accounts: '2', uses: '2' },
{ day: '1671148800', accounts: '5', uses: '6' },
{ day: '1671062400', accounts: '77', uses: '82' },
],
},
{
name: 'bautzen',
url: 'https://mastodon.social/tags/bautzen',
history: [
{ day: '1671580800', accounts: '50', uses: '62' },
{ day: '1671494400', accounts: '1', uses: '2' },
{ day: '1671408000', accounts: '5', uses: '11' },
{ day: '1671321600', accounts: '1', uses: '1' },
{ day: '1671235200', accounts: '2', uses: '2' },
{ day: '1671148800', accounts: '7', uses: '8' },
{ day: '1671062400', accounts: '9', uses: '13' },
],
},
{
name: 'googlefonts',
url: 'https://mastodon.social/tags/googlefonts',
history: [
{ day: '1671580800', accounts: '47', uses: '47' },
{ day: '1671494400', accounts: '0', uses: '0' },
{ day: '1671408000', accounts: '1', uses: '1' },
{ day: '1671321600', accounts: '0', uses: '0' },
{ day: '1671235200', accounts: '0', uses: '0' },
{ day: '1671148800', accounts: '0', uses: '0' },
{ day: '1671062400', accounts: '1', uses: '1' },
],
},
]

Wyświetl plik

@ -7,6 +7,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Wildebeest Error Page">
<title>Wildebeest Error</title>
<meta name="og:title" content="Wildebeest Error">
<meta name="og:description" content="Wildebeest Error Page">
<meta name="og:type" content="website">
<style>
body {
margin: 0;

Wyświetl plik

@ -7,6 +7,9 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="Wildebeest Page Not Found">
<title>Wildebeest Not Found</title>
<meta name="og:title" content="Wildebeest Not Found">
<meta name="og:description" content="Wildebeest Page Not Found">
<meta name="og:type" content="website">
<style>
body {
margin: 0;

Wyświetl plik

@ -2,40 +2,46 @@ import { test, expect } from '@playwright/test'
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.getByRole('article').getByRole('link', { name: 'Ben Rosengart', exact: true }).click()
await page.getByRole('link', { name: 'Ben Rosengart', exact: true }).click()
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')
await page.getByRole('link', { name: 'Ben Rosengart', exact: true }).click()
await page.getByRole('link', { name: 'Ben, just Ben', exact: true }).click()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Ben Rosengart' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Ben Rosengart' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Ben Rosengart' })).toBeVisible()
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 Rosengart' })
page.getByTestId('account-statuses').getByRole('article').getByRole('img', { name: 'Avatar of Ben, just Ben' })
).toBeVisible()
await expect(page.getByTestId('account-statuses').getByRole('article')).toContainText('What fresh hell is this?')
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 Rafa, a designer and app" }).locator('i.fa-globe + span').click()
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: 'Rafa', exact: true }).click()
await page.getByRole('link', { name: 'Raffa123$', exact: true }).click()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Header of Rafa' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('img', { name: 'Avatar of Rafa' })).toBeVisible()
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Rafa' })).toBeVisible()
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()
await expect(page.getByTestId('account-info').getByRole('heading', { name: 'Raffa123$' })).toBeVisible()
await expect(page.getByTestId('account-info').getByText('Joined')).toBeVisible()
await expect(page.getByTestId('account-info').getByTestId('stats')).toHaveText('2Posts0Following0Followers')
expect(await page.getByTestId('account-statuses').getByRole('article').count()).toBe(2)
const [post1Locator, post2Locator] = await page.getByTestId('account-statuses').getByRole('article').all()
await expect(post1Locator.getByRole('img', { name: 'Avatar of Rafa' })).toBeVisible()
await expect(post1Locator).toContainText("I'm Rafa, a designer and app developer currently living in Amsterdam")
await expect(post2Locator.getByRole('img', { name: 'Avatar of Rafa' })).toBeVisible()
await expect(post2Locator).toContainText('Hi, meet HiDock!')
await expect(post1Locator.getByRole('img', { name: 'Avatar of Raffa123$' })).toBeVisible()
await expect(post1Locator).toContainText("I'm Rafael and I am a web designer")
await expect(post2Locator.getByRole('img', { name: 'Avatar of Raffa123$' })).toBeVisible()
await expect(post2Locator).toContainText('Hi! My name is Rafael!')
})

Wyświetl plik

@ -4,10 +4,10 @@ test('Display the list of toots in the explore page', async ({ page }) => {
await page.goto('http://127.0.0.1:8788/explore')
const tootsTextsToCheck = [
'Hi, meet HiDock',
'George Santos is in serious trouble.',
'The real message of Jurassic Park is that you get the Unix and IT support you pay for.',
'BREAKING: Black smoke coming from Capitol chimney.',
'Hi! My name is Rafael!',
'We did it!',
"Fine. I'll use Wildebeest",
'A very simple update: all good!',
]
for (const tootText of tootsTextsToCheck) {

Wyświetl plik

@ -2,21 +2,37 @@ 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: 'Ken White' }).locator('i.fa-globe + span').click()
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 backButtonLocator = page.getByRole('button', { name: 'Back' })
await expect(backButtonLocator).toBeVisible()
const avatarLocator = page.locator('img[alt="Avatar of Ken White"]')
await expect(avatarLocator).toBeVisible()
const userLinkLocator = page.locator('a[href="/@Popehat"]', { hasText: 'Ken White' })
await expect(userLinkLocator).toBeVisible()
const tootContentLocator = page.locator('p', {
hasText: 'Just recorded the first Serious Trouble episode of the new year, out tomorrow.',
})
await expect(tootContentLocator).toBeVisible()
test('Navigation to and view of an individual toot with images', 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 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.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()
await page.getByTestId('media-gallery').getByRole('img').nth(2).click()
await expect(page.getByTestId('images-modal')).toBeVisible()
for (const n of [2, 1, 0, 3, 2, 1, 0, 3]) {
await expect(page.getByTestId('images-modal').getByRole('img')).toHaveAttribute(
'src',
`https://loremflickr.com/640/480/abstract?lock=${100 + n}`
)
await page.getByTestId('left-btn').click()
}
await page.getByTestId('close-btn').click()
await expect(page.getByTestId('images-modal')).not.toBeVisible()
})
test("Navigation to and view of a toot's replies", async ({ page }) => {
@ -24,38 +40,38 @@ test("Navigation to and view of a toot's replies", async ({ page }) => {
await page
.locator('article')
.filter({ hasText: 'Bethany Black' })
.filter({ hasText: 'George' })
.filter({
hasText: 'We did it! *wipes tear from eye*',
hasText: 'We did it!',
})
.locator('i.fa-globe + span')
.click()
await page
.locator('article')
.filter({ hasText: 'Zach Weinersmith' })
.filter({ hasText: 'Zak Smith' })
.filter({
hasText: 'Yes we did!',
})
.locator('i.fa-globe + span')
.click()
await expect(page.getByRole('link', { name: 'Avatar of Zach Weinersmith' })).toBeVisible()
await expect(page.getByRole('link', { name: 'Zach Weinersmith', exact: true })).toBeVisible()
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.getByText('Yes we did!')).toBeVisible()
await page.getByRole('button', { name: 'Back' }).click()
await page
.locator('article')
.filter({ hasText: 'nixCraft' })
.filter({ hasText: 'Penny' })
.filter({
hasText: 'Yes you guys did it!',
})
.locator('i.fa-globe + span')
.click()
await expect(page.getByRole('link', { name: 'Avatar of nixCraft' })).toBeVisible()
await expect(page.getByRole('link', { name: 'nixCraft 🐧', exact: true })).toBeVisible()
await expect(page.getByRole('link', { name: 'Avatar of Penny' })).toBeVisible()
await expect(page.getByRole('link', { name: 'Penny', exact: true })).toBeVisible()
await expect(page.getByText('Yes you guys did it!')).toBeVisible()
})

Wyświetl plik

@ -29,43 +29,43 @@ test('Presence of appropriate SEO metadata across the application', async ({ pag
})
await page.goto('http://127.0.0.1:8788/explore')
await page.locator('article').filter({ hasText: 'Hi, meet HiDock' }).locator('i.fa-globe + span').click()
await page
.locator('article')
.filter({ hasText: "I'm Rafael and I am a web designer!" })
.locator('i.fa-globe + span')
.click()
await checkPageSeoData(page, {
title: "Rafa: Hi, meet HiDock! It's a free M… - Wildebeest",
description:
"Hi, meet HiDock! It's a free Mac app that lets you set different Dock settings for different display configurations https://hidock.app →",
title: "Raffa123$: I'm Rafael and I am a web desi… - Wildebeest",
description: "I'm Rafael and I am a web designer! 💪💪",
ogType: 'article',
ogUrl: /https:\/\/127.0.0.1\/statuses\/[\w-]*\/?/,
ogImage: 'https://cdn.masto.host/mastodondesign/accounts/avatars/000/011/932/original/8f601be03c98b2e8.png',
ogImage: 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/157.jpg',
})
await page.goto('http://127.0.0.1:8788/@rafa')
await page.goto('http://127.0.0.1:8788/@Ben')
await checkPageSeoData(page, {
title: 'Rafa (@rafa@0.0.0.0) - Wildebeest',
description: 'Rafa account page - Wildebeest',
title: 'Ben, just Ben (@Ben@0.0.0.0) - Wildebeest',
description: 'Ben, just Ben account page - Wildebeest',
ogType: 'article',
ogUrl: 'https://0.0.0.0/@rafa',
ogImage: 'https://cdn.masto.host/mastodondesign/accounts/avatars/000/011/932/original/8f601be03c98b2e8.png',
ogUrl: 'https://0.0.0.0/@Ben',
ogImage: 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1148.jpg',
})
await page.goto('http://127.0.0.1:8788/explore')
await page.locator('article').filter({ hasText: 'Ken White' }).locator('i.fa-globe + span').click()
await page.locator('article').filter({ hasText: 'Ben, just Ben' }).locator('i.fa-globe + span').click()
await checkPageSeoData(page, {
title: 'Ken White: Just recorded the first Seriou… - Wildebeest',
description:
'Just recorded the first Serious Trouble episode of the new year, out tomorrow. This week: George Santos is in serious trouble. Sam Bankman-Fried is in REALLY serious trouble. And Scott Adams is still making dumb defamation threats.',
title: 'Ben, just Ben: A very simple update: all good… - Wildebeest',
description: 'A very simple update: all good!',
ogType: 'article',
ogUrl: /https:\/\/127.0.0.1\/statuses\/[\w-]*\/?/,
ogImage: 'https://files.mastodon.social/accounts/avatars/109/502/260/753/916/593/original/f721da0f38083abf.jpg',
ogImage: 'https://cloudflare-ipfs.com/ipfs/Qmd3W5DuhgHirLHGVixi6V76LhCkZUz6pnFt5AJBiyvHye/avatar/1148.jpg',
})
await page.goto('http://127.0.0.1:8788/@Popehat')
await page.goto('http://127.0.0.1:8788/@NonExistent')
await checkPageSeoData(page, {
title: 'Ken White (@Popehat@0.0.0.0) - Wildebeest',
description: 'Ken White account page - Wildebeest',
ogType: 'article',
ogUrl: 'https://0.0.0.0/@Popehat',
ogImage: 'https://files.mastodon.social/accounts/avatars/109/502/260/753/916/593/original/f721da0f38083abf.jpg',
title: 'Wildebeest Not Found',
description: 'Wildebeest Page Not Found',
ogType: 'website',
})
})
@ -73,8 +73,8 @@ type ExpectedSeoValues = {
title: string | RegExp
description: string | RegExp
ogType: 'website' | 'article'
ogUrl: string | RegExp
ogImage: string | RegExp
ogUrl?: string | RegExp
ogImage?: string | RegExp
}
async function checkPageSeoData(page: Page, expected: Partial<ExpectedSeoValues>) {