Skip to content

Commit cc7f161

Browse files
authored
test(contributors): add responsive breakpoints test suite (JhaSourav07#2859) (JhaSourav07#3010)
* test(resume-preview): add theme contrast test suite (JhaSourav07#2875) * test(resume-preview): add accessibility compliance test suite (JhaSourav07#2876) * test(contributors): add responsive breakpoints test suite (JhaSourav07#2859) --------- Co-authored-by: Sourav Jha <25BCS12964@cuchd.in>
2 parents f4db3bd + 1ec52e0 commit cc7f161

1 file changed

Lines changed: 175 additions & 0 deletions

File tree

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
import { beforeEach, describe, expect, it, vi } from 'vitest';
2+
import { render, screen } from '@testing-library/react';
3+
import ContributorsPage from './page';
4+
import type { ReactNode, HTMLAttributes } from 'react';
5+
import '@testing-library/jest-dom';
6+
7+
vi.mock('next/image', () => ({
8+
__esModule: true,
9+
default: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (
10+
<img {...props} alt={props.alt || ''} />
11+
),
12+
}));
13+
14+
vi.mock('next/link', () => ({
15+
__esModule: true,
16+
default: ({
17+
children,
18+
href,
19+
...props
20+
}: { children: ReactNode; href: string } & HTMLAttributes<HTMLAnchorElement>) => (
21+
<a href={href} {...props}>
22+
{children}
23+
</a>
24+
),
25+
}));
26+
27+
vi.mock('gsap', () => {
28+
const tween = { kill: vi.fn() };
29+
const mockGsap = {
30+
registerPlugin: vi.fn(),
31+
to: vi.fn().mockReturnValue(tween),
32+
fromTo: vi.fn().mockReturnValue(tween),
33+
set: vi.fn(),
34+
context: vi.fn((callback: () => void) => {
35+
if (typeof callback === 'function') {
36+
callback();
37+
}
38+
return { revert: vi.fn() };
39+
}),
40+
};
41+
return { default: mockGsap, gsap: mockGsap };
42+
});
43+
44+
vi.mock('gsap/ScrollTrigger', () => ({
45+
ScrollTrigger: {
46+
getAll: vi.fn(() => []),
47+
},
48+
}));
49+
50+
vi.mock('framer-motion', () => ({
51+
motion: {
52+
div: ({ children, ...props }: HTMLAttributes<HTMLDivElement> & { children?: ReactNode }) => (
53+
<div {...props}>{children}</div>
54+
),
55+
span: ({ children, ...props }: HTMLAttributes<HTMLSpanElement> & { children?: ReactNode }) => (
56+
<span {...props}>{children}</span>
57+
),
58+
p: ({
59+
children,
60+
...props
61+
}: HTMLAttributes<HTMLParagraphElement> & { children?: ReactNode }) => (
62+
<p {...props}>{children}</p>
63+
),
64+
h1: ({ children, ...props }: HTMLAttributes<HTMLHeadingElement> & { children?: ReactNode }) => (
65+
<h1 {...props}>{children}</h1>
66+
),
67+
h2: ({ children, ...props }: HTMLAttributes<HTMLHeadingElement> & { children?: ReactNode }) => (
68+
<h2 {...props}>{children}</h2>
69+
),
70+
h3: ({ children, ...props }: HTMLAttributes<HTMLHeadingElement> & { children?: ReactNode }) => (
71+
<h3 {...props}>{children}</h3>
72+
),
73+
h4: ({ children, ...props }: HTMLAttributes<HTMLHeadingElement> & { children?: ReactNode }) => (
74+
<h4 {...props}>{children}</h4>
75+
),
76+
h5: ({ children, ...props }: HTMLAttributes<HTMLHeadingElement> & { children?: ReactNode }) => (
77+
<h5 {...props}>{children}</h5>
78+
),
79+
h6: ({ children, ...props }: HTMLAttributes<HTMLHeadingElement> & { children?: ReactNode }) => (
80+
<h6 {...props}>{children}</h6>
81+
),
82+
section: ({ children, ...props }: HTMLAttributes<HTMLElement> & { children?: ReactNode }) => (
83+
<section {...props}>{children}</section>
84+
),
85+
a: ({ children, ...props }: HTMLAttributes<HTMLAnchorElement> & { children?: ReactNode }) => (
86+
<a {...props}>{children}</a>
87+
),
88+
button: ({
89+
children,
90+
...props
91+
}: HTMLAttributes<HTMLButtonElement> & { children?: ReactNode }) => (
92+
<button {...props}>{children}</button>
93+
),
94+
img: (props: React.ImgHTMLAttributes<HTMLImageElement>) => (
95+
<img {...props} alt={props.alt || ''} />
96+
),
97+
},
98+
AnimatePresence: ({ children }: { children: ReactNode }) => <>{children}</>,
99+
useMotionValue: (initial: number) => ({ current: initial, set: vi.fn() }),
100+
useSpring: (value: { current: number }) => value,
101+
useTransform: (value: { current: number }, fn: (v: number) => number) => fn(value.current),
102+
}));
103+
104+
describe('ContributorsPage - Responsive Breakpoints', () => {
105+
beforeEach(() => {
106+
vi.restoreAllMocks();
107+
108+
global.fetch = vi.fn(() =>
109+
Promise.resolve({
110+
ok: true,
111+
json: async () => [
112+
{
113+
id: 1,
114+
login: 'developer1',
115+
avatar_url: 'https://example.com/avatar.png',
116+
contributions: 42,
117+
html_url: 'https://github.com/developer1',
118+
},
119+
],
120+
})
121+
) as unknown as typeof fetch;
122+
123+
window.HTMLElement.prototype.scrollIntoView = vi.fn();
124+
125+
if (!window.requestAnimationFrame) {
126+
window.requestAnimationFrame = (callback: FrameRequestCallback) =>
127+
setTimeout(callback, 0) as unknown as number;
128+
}
129+
});
130+
131+
it('verifies typography classes scaling across responsive viewports', async () => {
132+
const element = await ContributorsPage();
133+
render(element);
134+
135+
const mainHeader = screen.getByRole('heading', { level: 1 });
136+
expect(mainHeader).toHaveClass('text-6xl');
137+
expect(mainHeader).toHaveClass('sm:text-7xl');
138+
expect(mainHeader).toHaveClass('md:text-8xl');
139+
expect(mainHeader).toHaveClass('lg:text-[10rem]');
140+
});
141+
142+
it('verifies responsive column grids for layout containers', async () => {
143+
const element = await ContributorsPage();
144+
render(element);
145+
146+
// Stats section should be 1 column on mobile and 3 columns on medium screens
147+
const statsContainer = screen
148+
.getByText('Global Architects')
149+
.closest('.stat-item')?.parentElement;
150+
expect(statsContainer).toHaveClass('grid-cols-1');
151+
expect(statsContainer).toHaveClass('md:grid-cols-3');
152+
});
153+
154+
it('verifies flex layout wrapping rules adapt to screen size in CTA block', async () => {
155+
const element = await ContributorsPage();
156+
render(element);
157+
158+
// CTA section buttons wrap on mobile (flex-col) and align horizontally on desktop (sm:flex-row)
159+
const buttonGroup = screen.getByText('View Repository').closest('div')?.parentElement;
160+
expect(buttonGroup).toHaveClass('flex-col');
161+
expect(buttonGroup).toHaveClass('sm:flex-row');
162+
});
163+
164+
it('verifies mobile-only responsive display classes for decorative elements', async () => {
165+
const element = await ContributorsPage();
166+
render(element);
167+
168+
// Custom cursor container should be hidden on mobile (hidden) and shown on desktop (md:block)
169+
const customCursor = document.querySelector('.mix-blend-difference');
170+
if (customCursor) {
171+
expect(customCursor).toHaveClass('hidden');
172+
expect(customCursor).toHaveClass('md:block');
173+
}
174+
});
175+
});

0 commit comments

Comments
 (0)