Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions tests/partials/ArticleItemSkeletonPartial.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import ArticleItemSkeletonPartial from '@partials/ArticleItemSkeletonPartial.vue';

describe('ArticleItemSkeletonPartial', () => {
it('is animated by default', () => {
const wrapper = mount(ArticleItemSkeletonPartial);

expect(wrapper.attributes('class')).toContain('animate-pulse');

Check failure on line 9 in tests/partials/ArticleItemSkeletonPartial.test.ts

View workflow job for this annotation

GitHub Actions / vitest

tests/partials/ArticleItemSkeletonPartial.test.ts > ArticleItemSkeletonPartial > is animated by default

AssertionError: expected 'py-5 border-b border-slate-100 dark:b…' to contain 'animate-pulse' Expected: "animate-pulse" Received: "py-5 border-b border-slate-100 dark:border-slate-800" ❯ tests/partials/ArticleItemSkeletonPartial.test.ts:9:39
});

it('can disable the animation', () => {
const wrapper = mount(ArticleItemSkeletonPartial, {
props: { isAnimated: false },
});

expect(wrapper.attributes('class')).not.toContain('animate-pulse');
});
});
4 changes: 2 additions & 2 deletions tests/partials/ArticlesListPartial.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -191,16 +191,16 @@
// Coalesced or duplicated triggers are OK; we only require that a refresh was scheduled.
expect(getPosts.mock.calls.length).toBeGreaterThan(initialGetPostsCalls);

let skeletons = wrapper.findAllComponents(ArticleItemSkeletonPartial);
let skeletons = wrapper.findAll('[aria-busy="true"] article[aria-hidden="true"]');
let attempts = 0;

while (skeletons.length !== posts.length && attempts < 10) {
await nextTick();
skeletons = wrapper.findAllComponents(ArticleItemSkeletonPartial);
skeletons = wrapper.findAll('[aria-busy="true"] article[aria-hidden="true"]');
attempts += 1;
}

expect(skeletons).toHaveLength(posts.length);

Check failure on line 203 in tests/partials/ArticlesListPartial.test.ts

View workflow job for this annotation

GitHub Actions / vitest

tests/partials/ArticlesListPartial.test.ts > ArticlesListPartial > uses the previous result count while refreshing the list

AssertionError: expected [] to have a length of 3 but got +0 - Expected + Received - 3 + 0 ❯ tests/partials/ArticlesListPartial.test.ts:203:21

resolveRefreshPosts?.(postsCollection);
await flushPromises();
Expand Down
19 changes: 19 additions & 0 deletions tests/partials/PostPageSkeletonPartial.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import PostPageSkeletonPartial from '@partials/PostPageSkeletonPartial.vue';

describe('PostPageSkeletonPartial', () => {
it('exposes a stable test id', () => {
const wrapper = mount(PostPageSkeletonPartial);

const root = wrapper.get('[data-testid="post-page-skeleton"]');
expect(root.exists()).toBe(true);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The wrapper.get() method throws an error if the element is not found, making this expect assertion redundant. The test's purpose is fulfilled by get() succeeding. You can remove this line for a more concise test.

});

it('is identified as non-interactive placeholder', () => {
const wrapper = mount(PostPageSkeletonPartial);

expect(wrapper.attributes('aria-hidden')).toBe('true');
expect(wrapper.attributes('class')).toContain('animate-pulse');
});
});
27 changes: 27 additions & 0 deletions tests/partials/ProjectCardSkeletonPartial.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import ProjectCardSkeletonPartial from '@partials/ProjectCardSkeletonPartial.vue';

describe('ProjectCardSkeletonPartial', () => {
it('renders animated wrapper by default', () => {
const wrapper = mount(ProjectCardSkeletonPartial);

expect(wrapper.attributes('class')).toContain('animate-pulse');

Check failure on line 9 in tests/partials/ProjectCardSkeletonPartial.test.ts

View workflow job for this annotation

GitHub Actions / vitest

tests/partials/ProjectCardSkeletonPartial.test.ts > ProjectCardSkeletonPartial > renders animated wrapper by default

AssertionError: expected 'rounded-lg border border-slate-200 da…' to contain 'animate-pulse' Expected: "animate-pulse" Received: "rounded-lg border border-slate-200 dark:border-slate-800 dark:bg-gradient-to-t dark:from-slate-800 dark:to-slate-800/30 p-5" ❯ tests/partials/ProjectCardSkeletonPartial.test.ts:9:39
});

it('merges custom wrapper classes', () => {
const wrapper = mount(ProjectCardSkeletonPartial, {
props: { wrapperClass: 'custom-class' },
});

expect(wrapper.classes()).toContain('custom-class');
});

it('disables animation when requested', () => {
const wrapper = mount(ProjectCardSkeletonPartial, {
props: { isAnimated: false },
});

expect(wrapper.attributes('class')).not.toContain('animate-pulse');
});
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This test suite is missing a check for accessibility. Skeleton loaders are purely decorative and should be hidden from assistive technologies using aria-hidden="true". Please add a test case to ensure this attribute is present. Note that this will require updating the ProjectCardSkeletonPartial.vue component to include aria-hidden="true" on its root element to make the test pass.

Suggested change
});
});
it('is hidden from assistive technology', () => {
const wrapper = mount(ProjectCardSkeletonPartial);
expect(wrapper.attributes('aria-hidden')).toBe('true');
});

20 changes: 20 additions & 0 deletions tests/partials/TalkCardSkeletonPartial.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import TalkCardSkeletonPartial from '@partials/TalkCardSkeletonPartial.vue';

describe('TalkCardSkeletonPartial', () => {
it('applies animation by default', () => {
const wrapper = mount(TalkCardSkeletonPartial);

expect(wrapper.attributes('class')).toContain('animate-pulse');

Check failure on line 9 in tests/partials/TalkCardSkeletonPartial.test.ts

View workflow job for this annotation

GitHub Actions / vitest

tests/partials/TalkCardSkeletonPartial.test.ts > TalkCardSkeletonPartial > applies animation by default

AssertionError: expected 'relative aspect-video rounded-lg over…' to contain 'animate-pulse' Expected: "animate-pulse" Received: "relative aspect-video rounded-lg overflow-hidden bg-linear-to-tr from-slate-800 to-slate-700 odd:rotate-1 even:-rotate-1 hover:rotate-0 transition-transform duration-700 hover:duration-100 ease-in-out shadow-xl" ❯ tests/partials/TalkCardSkeletonPartial.test.ts:9:39
expect(wrapper.attributes('aria-hidden')).toBe('true');
});

it('respects disabled animation flag', () => {
const wrapper = mount(TalkCardSkeletonPartial, {
props: { isAnimated: false },
});

expect(wrapper.attributes('class')).not.toContain('animate-pulse');
});
});
22 changes: 22 additions & 0 deletions tests/partials/WidgetSkillsSkeletonPartial.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { mount } from '@vue/test-utils';
import { describe, it, expect } from 'vitest';
import WidgetSkillsSkeletonPartial from '@partials/WidgetSkillsSkeletonPartial.vue';

describe('WidgetSkillsSkeletonPartial', () => {
it('renders six placeholder skill rows', () => {
const wrapper = mount(WidgetSkillsSkeletonPartial);
const items = wrapper.findAll('li');

expect(items).toHaveLength(6);
items.forEach((item) => {
expect(item.classes()).toContain('flex');
});
});

it('is marked as purely decorative', () => {
const wrapper = mount(WidgetSkillsSkeletonPartial);

expect(wrapper.attributes('aria-hidden')).toBeUndefined();
expect(wrapper.attributes('class')).toContain('animate-pulse');
});
});
Loading