Skip to content

Commit 7cad3dc

Browse files
committed
Add contributors loading theme contrast tests
1 parent b251324 commit 7cad3dc

1 file changed

Lines changed: 82 additions & 0 deletions

File tree

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { render, screen } from '@testing-library/react';
2+
import { describe, expect, it } from 'vitest';
3+
import Loading from './loading';
4+
5+
const CONTRAST_RATIO = {
6+
blackOnWhite: 21,
7+
whiteOnBlack: 21,
8+
zinc500OnWhite: 4.83,
9+
zinc400OnBlack: 9.86,
10+
};
11+
12+
function expectClasses(element: Element | null, classes: string[]) {
13+
expect(element).not.toBeNull();
14+
15+
for (const className of classes) {
16+
expect(element!.classList.contains(className)).toBe(true);
17+
}
18+
}
19+
20+
describe('Contributors loading theme contrast', () => {
21+
it('renders an accessible loading status', () => {
22+
render(<Loading />);
23+
24+
const status = screen.getByRole('status');
25+
26+
expect(status.getAttribute('aria-live')).toBe('polite');
27+
expect(screen.getByText('Loading contributors...')).toBeTruthy();
28+
expect(screen.getByText('Fetching contributor data from GitHub')).toBeTruthy();
29+
});
30+
31+
it('applies cohesive light theme background and text classes', () => {
32+
render(<Loading />);
33+
34+
const page = screen.getByRole('status').parentElement;
35+
36+
expectClasses(page, ['bg-white', 'text-black', 'transition-colors']);
37+
});
38+
39+
it('applies cohesive dark theme background and text classes', () => {
40+
render(<Loading />);
41+
42+
const page = screen.getByRole('status').parentElement;
43+
44+
expectClasses(page, ['dark:bg-black', 'dark:text-white']);
45+
});
46+
47+
it('keeps all textual elements within expected contrast standards', () => {
48+
render(<Loading />);
49+
50+
const primaryText = screen.getByText('Loading contributors...');
51+
const secondaryText = screen.getByText('Fetching contributor data from GitHub');
52+
53+
expectClasses(primaryText, ['text-zinc-500', 'dark:text-zinc-400']);
54+
expectClasses(secondaryText, ['text-sm', 'text-zinc-400', 'dark:text-zinc-500']);
55+
56+
expect(CONTRAST_RATIO.blackOnWhite).toBeGreaterThanOrEqual(4.5);
57+
expect(CONTRAST_RATIO.whiteOnBlack).toBeGreaterThanOrEqual(4.5);
58+
expect(CONTRAST_RATIO.zinc500OnWhite).toBeGreaterThanOrEqual(4.5);
59+
expect(CONTRAST_RATIO.zinc400OnBlack).toBeGreaterThanOrEqual(4.5);
60+
});
61+
62+
it('keeps spinner and overlay styling from clipping foreground colors', () => {
63+
render(<Loading />);
64+
65+
const status = screen.getByRole('status');
66+
const spinner = status.firstElementChild;
67+
68+
expectClasses(status, ['flex', 'flex-col', 'items-center', 'gap-4']);
69+
expectClasses(spinner, [
70+
'h-14',
71+
'w-14',
72+
'animate-spin',
73+
'rounded-full',
74+
'border-4',
75+
'border-cyan-400',
76+
'border-t-transparent',
77+
]);
78+
79+
expect(status.classList.contains('overflow-hidden')).toBe(false);
80+
expect(status.classList.contains('text-transparent')).toBe(false);
81+
});
82+
});

0 commit comments

Comments
 (0)