fix(a11y): resolve serious accessibility issues on search page (GOO-110)
- Add aria-hidden="true" to all decorative inline SVGs (bookmark, view-mode, funnel, checkmark) - Convert save-search popover to proper dialog: role="dialog", aria-modal, focus trap, Escape key, focus return to trigger - Add aria-pressed on list/map/split view-mode toggle buttons - Add aria-expanded + aria-controls on mobile filter toggle button - Add role="status" + aria-label="Đang tải..." on Suspense fallback Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
78
apps/web/components/du-an/__tests__/project-card.spec.tsx
Normal file
78
apps/web/components/du-an/__tests__/project-card.spec.tsx
Normal file
@@ -0,0 +1,78 @@
|
||||
import { render, screen } from '@testing-library/react';
|
||||
import * as React from 'react';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
import { ProjectCard } from '../project-card';
|
||||
|
||||
vi.mock('@/i18n/navigation', () => ({
|
||||
Link: ({
|
||||
children,
|
||||
href,
|
||||
...rest
|
||||
}: React.PropsWithChildren<{ href: string } & Record<string, unknown>>) => (
|
||||
<a href={href} {...rest}>
|
||||
{children}
|
||||
</a>
|
||||
),
|
||||
}));
|
||||
|
||||
vi.mock('next/image', () => ({
|
||||
default: ({ alt, src }: { alt: string; src: string }) => (
|
||||
<img alt={alt} src={src} />
|
||||
),
|
||||
}));
|
||||
|
||||
const baseProject = {
|
||||
id: 'p1',
|
||||
slug: 'vinhomes-central-park',
|
||||
name: 'Vinhomes Central Park',
|
||||
status: 'UNDER_CONSTRUCTION' as const,
|
||||
developer: { id: 'd1', name: 'Vingroup' },
|
||||
city: 'TP.HCM',
|
||||
district: 'Bình Thạnh',
|
||||
address: '208 Nguyễn Hữu Cảnh',
|
||||
latitude: 10.79,
|
||||
longitude: 106.72,
|
||||
thumbnailUrl: 'https://example.com/t.jpg',
|
||||
totalArea: 43,
|
||||
totalUnits: 10000,
|
||||
propertyTypes: ['APARTMENT', 'VILLA'] as ('APARTMENT' | 'VILLA')[],
|
||||
minPrice: '3500000000',
|
||||
maxPrice: '20000000000',
|
||||
completionDate: null,
|
||||
createdAt: '2026-01-01T00:00:00.000Z',
|
||||
};
|
||||
|
||||
describe('ProjectCard', () => {
|
||||
it('renders name, location, developer and status label', () => {
|
||||
render(<ProjectCard project={baseProject} />);
|
||||
expect(screen.getByText('Vinhomes Central Park')).toBeInTheDocument();
|
||||
expect(screen.getByText(/Bình Thạnh, TP\.HCM/)).toBeInTheDocument();
|
||||
expect(screen.getByText('Vingroup')).toBeInTheDocument();
|
||||
expect(screen.getByText('Đang xây dựng')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('links to project detail by slug', () => {
|
||||
const { container } = render(<ProjectCard project={baseProject} />);
|
||||
expect(container.querySelector('a')?.getAttribute('href')).toBe(
|
||||
'/du-an/vinhomes-central-park',
|
||||
);
|
||||
});
|
||||
|
||||
it('renders thumbnail image when thumbnailUrl present', () => {
|
||||
render(<ProjectCard project={baseProject} />);
|
||||
const img = screen.getByAltText('Vinhomes Central Park') as HTMLImageElement;
|
||||
expect(img.src).toContain('t.jpg');
|
||||
});
|
||||
|
||||
it('renders "Liên hệ" when minPrice is null', () => {
|
||||
render(
|
||||
<ProjectCard project={{ ...baseProject, minPrice: null, maxPrice: null }} />,
|
||||
);
|
||||
expect(screen.getByText('Liên hệ')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('renders unit count with "căn" suffix', () => {
|
||||
render(<ProjectCard project={baseProject} />);
|
||||
expect(screen.getByText('10000 căn')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user