Skip to content

Commit 36dd357

Browse files
feat: add missing a11y tests for blog post components (#1429)
1 parent 848cd43 commit 36dd357

6 files changed

Lines changed: 132 additions & 6 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// This type declaration file is required to break a circular type resolution in vue-tsc.
2+
// And is based off Package.d.vue.ts
3+
4+
import type { DefineComponent } from 'vue'
5+
6+
declare const _default: DefineComponent<{
7+
title: string
8+
authors?: { name: string; blueskyHandle?: string }[]
9+
date?: string
10+
primaryColor?: string
11+
}>
12+
13+
export default _default

app/pages/blog/index.vue

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
<script setup lang="ts">
2-
const router = useRouter()
3-
42
import type { BlogPostFrontmatter } from '#shared/schemas/blog'
53
64
const blogModules = import.meta.glob<BlogPostFrontmatter>('./*.md', { eager: true })

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,6 @@
133133
"@types/sanitize-html": "2.16.0",
134134
"@types/semver": "7.7.1",
135135
"@types/validate-npm-package-name": "4.0.2",
136-
"@valibot/to-json-schema": "^1.5.0",
137136
"@vitest/browser-playwright": "4.0.18",
138137
"@vitest/coverage-v8": "4.0.18",
139138
"@vue/test-utils": "2.4.6",

pnpm-lock.yaml

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

test/nuxt/a11y.spec.ts

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,12 @@ import {
121121
AppLogo,
122122
AboutLogoImg,
123123
AboutLogoList,
124+
AuthorAvatar,
125+
AuthorList,
126+
BlogPostListCard,
127+
BlogPostWrapper,
128+
BlueskyComment,
129+
BlueskyComments,
124130
BaseCard,
125131
BlueskyPostEmbed,
126132
BuildEnvironment,
@@ -2170,6 +2176,117 @@ describe('component accessibility audits', () => {
21702176
})
21712177
})
21722178

2179+
describe('AuthorAvatar', () => {
2180+
it('should have no accessibility violations with fallback text', async () => {
2181+
const component = await mountSuspended(AuthorAvatar, {
2182+
props: {
2183+
author: {
2184+
name: 'Daniel Roe',
2185+
blueskyHandle: 'danielroe.dev',
2186+
avatar: null,
2187+
profileUrl: 'https://bsky.app/profile/danielroe.dev',
2188+
},
2189+
},
2190+
})
2191+
const results = await runAxe(component)
2192+
expect(results.violations).toEqual([])
2193+
})
2194+
})
2195+
2196+
describe('AuthorList', () => {
2197+
it('should have no accessibility violations', async () => {
2198+
const component = await mountSuspended(AuthorList, {
2199+
props: {
2200+
authors: [
2201+
{ name: 'Daniel Roe', blueskyHandle: 'danielroe.dev' },
2202+
{ name: 'Salma Alam-Naylor' },
2203+
],
2204+
},
2205+
})
2206+
const results = await runAxe(component)
2207+
expect(results.violations).toEqual([])
2208+
})
2209+
})
2210+
2211+
describe('BlogPostWrapper', () => {
2212+
it('should have no accessibility violations', async () => {
2213+
const component = await mountSuspended(BlogPostWrapper, {
2214+
props: {
2215+
frontmatter: {
2216+
authors: [{ name: 'Daniel Roe', blueskyHandle: 'danielroe.dev' }],
2217+
title: 'Building Accessible Vue Components',
2218+
date: '2024-06-15',
2219+
description: 'A guide to building accessible components in Vue.js applications.',
2220+
path: '/blog/building-accessible-vue-components',
2221+
slug: 'building-accessible-vue-components',
2222+
},
2223+
},
2224+
slots: { default: '<p>Blog post content here.</p>' },
2225+
})
2226+
const results = await runAxe(component)
2227+
expect(results.violations).toEqual([])
2228+
})
2229+
})
2230+
2231+
describe('BlueskyComment', () => {
2232+
it('should have no accessibility violations', async () => {
2233+
const component = await mountSuspended(BlueskyComment, {
2234+
props: {
2235+
comment: {
2236+
uri: 'at://did:plc:2gkh62xvzokhlf6li4ol3b3d/app.bsky.feed.post/3mcg7k75fdc2k',
2237+
cid: 'bafyreigincphooxt7zox3blbocf6hnczzv36fkuj2zi5iuzpjgq6gk6pju',
2238+
author: {
2239+
did: 'did:plc:2gkh62xvzokhlf6li4ol3b3d',
2240+
handle: 'patak.dev',
2241+
displayName: 'patak',
2242+
avatar:
2243+
'https://cdn.bsky.app/img/avatar/plain/did:plc:2gkh62xvzokhlf6li4ol3b3d/bafkreifgzl4e5jqlakd77ajvnilsb5tufsv24h2sxfwmitkzxrh3sk6mhq@jpeg',
2244+
},
2245+
text: 'our kids will need these new stories, thanks for writing this Daniel',
2246+
createdAt: '2026-01-14T23:22:05.257Z',
2247+
likeCount: 13,
2248+
replyCount: 0,
2249+
repostCount: 0,
2250+
replies: [],
2251+
},
2252+
depth: 0,
2253+
},
2254+
})
2255+
const results = await runAxe(component)
2256+
expect(results.violations).toEqual([])
2257+
})
2258+
})
2259+
2260+
describe('BlueskyComments', () => {
2261+
it('should have no accessibility violations', async () => {
2262+
const component = await mountSuspended(BlueskyComments, {
2263+
props: {
2264+
postUri: 'at://did:plc:jbeaa5kdaladzwq3r7f5xgwe/app.bsky.feed.post/3mcg6svsgsm2k',
2265+
},
2266+
})
2267+
const results = await runAxe(component)
2268+
expect(results.violations).toEqual([])
2269+
})
2270+
})
2271+
2272+
describe('BlogPostListCard', () => {
2273+
it('should have no accessibility violations', async () => {
2274+
const component = await mountSuspended(BlogPostListCard, {
2275+
props: {
2276+
authors: [{ name: 'Daniel Roe', blueskyHandle: 'danielroe.dev' }],
2277+
title: 'Building Accessible Vue Components',
2278+
topics: ['accessibility', 'vue'],
2279+
excerpt: 'A guide to building accessible components in Vue.js applications.',
2280+
published: '2024-06-15',
2281+
path: 'building-accessible-vue-components',
2282+
index: 0,
2283+
},
2284+
})
2285+
const results = await runAxe(component)
2286+
expect(results.violations).toEqual([])
2287+
})
2288+
})
2289+
21732290
describe('PackageReplacement', () => {
21742291
it('should have no accessibility violations for native replacement', async () => {
21752292
const component = await mountSuspended(PackageReplacement, {

test/unit/a11y-component-coverage.spec.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const SKIPPED_COMPONENTS: Record<string, string> = {
2525
// OgImage components are server-side rendered images, not interactive UI
2626
'OgImage/Default.vue': 'OG Image component - server-rendered image, not interactive UI',
2727
'OgImage/Package.vue': 'OG Image component - server-rendered image, not interactive UI',
28+
'OgImage/BlogPost.vue': 'OG Image component - server-rendered image, not interactive UI',
2829

2930
// Client-only components with complex dependencies
3031
'Header/AuthModal.client.vue': 'Complex auth modal with navigation - requires full app context',

0 commit comments

Comments
 (0)