Skip to content
Draft
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
165 changes: 165 additions & 0 deletions tests/Header.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/**
* Test suite for Header component
* Comprehensive coverage for simple navigation component
*/

import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import { Header } from '../frontend/components/Header';

describe('Header Component', () => {
describe('Rendering', () => {
it('renders the header element with correct className', () => {
const { container } = render(<Header />);
const header = container.querySelector('header');

expect(header).toBeInTheDocument();
expect(header).toHaveClass('site-header');
});

it('renders the main heading with correct text', () => {
render(<Header />);

const heading = screen.getByRole('heading', { level: 1 });
expect(heading).toBeInTheDocument();
expect(heading).toHaveTextContent('Corporate Website');
});

it('renders navigation element', () => {
const { container } = render(<Header />);
const nav = container.querySelector('nav');

expect(nav).toBeInTheDocument();
});
});

describe('Navigation Links', () => {
it('renders all three navigation links', () => {
render(<Header />);

const links = screen.getAllByRole('link');
expect(links).toHaveLength(3);
});

it('renders Home link with correct href', () => {
render(<Header />);

const homeLink = screen.getByRole('link', { name: /home/i });
expect(homeLink).toBeInTheDocument();
expect(homeLink).toHaveAttribute('href', '/');
});

it('renders About link with correct href', () => {
render(<Header />);

const aboutLink = screen.getByRole('link', { name: /about/i });
expect(aboutLink).toBeInTheDocument();
expect(aboutLink).toHaveAttribute('href', '/about');
});

it('renders Contact link with correct href', () => {
render(<Header />);

const contactLink = screen.getByRole('link', { name: /contact/i });
expect(contactLink).toBeInTheDocument();
expect(contactLink).toHaveAttribute('href', '/contact');
});
});

describe('Accessibility', () => {
it('has proper semantic structure with header and nav elements', () => {
const { container } = render(<Header />);

const header = container.querySelector('header');
const nav = container.querySelector('nav');

expect(header).toBeInTheDocument();
expect(nav).toBeInTheDocument();
expect(header).toContainElement(nav);
});

it('all navigation links are accessible', () => {
render(<Header />);

const links = screen.getAllByRole('link');

links.forEach(link => {
expect(link).toBeVisible();
expect(link).toHaveAccessibleName();
});
});

it('has a single h1 heading for document structure', () => {
render(<Header />);

const headings = screen.getAllByRole('heading', { level: 1 });
expect(headings).toHaveLength(1);
});
});

describe('Component Structure', () => {
it('renders as a functional component', () => {
const component = <Header />;
expect(component).toBeDefined();
expect(component.type).toBe(Header);
});

it('contains heading inside header element', () => {
const { container } = render(<Header />);

const header = container.querySelector('header');
const heading = screen.getByRole('heading', { level: 1 });

expect(header).toContainElement(heading);
});

it('contains navigation inside header element', () => {
const { container } = render(<Header />);

const header = container.querySelector('header');
const nav = container.querySelector('nav');

expect(header).toContainElement(nav);
});
});

describe('Content Verification', () => {
it('renders correct text content for all elements', () => {
const { container } = render(<Header />);

expect(screen.getByText('Corporate Website')).toBeInTheDocument();
expect(screen.getByText('Home')).toBeInTheDocument();
expect(screen.getByText('About')).toBeInTheDocument();
expect(screen.getByText('Contact')).toBeInTheDocument();
});

it('navigation links appear in correct order', () => {
render(<Header />);

const links = screen.getAllByRole('link');
expect(links[0]).toHaveTextContent('Home');
expect(links[1]).toHaveTextContent('About');
expect(links[2]).toHaveTextContent('Contact');
});
});

describe('Edge Cases', () => {
it('renders without props', () => {
expect(() => render(<Header />)).not.toThrow();
});

it('renders consistently on multiple renders', () => {
const { container: container1 } = render(<Header />);
const { container: container2 } = render(<Header />);

expect(container1.innerHTML).toBe(container2.innerHTML);
});

it('is a pure component with no side effects', () => {
const renderCount1 = render(<Header />);
const renderCount2 = render(<Header />);

expect(renderCount1.container.innerHTML).toBe(renderCount2.container.innerHTML);
});
});
});
1 change: 1 addition & 0 deletions tests/setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-dom';
16 changes: 16 additions & 0 deletions vitest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { defineConfig } from 'vitest/config'

export default defineConfig({
test: {
environment: 'jsdom',
globals: true,
setupFiles: ['./tests/setup.ts'],
coverage: {
provider: 'v8',
reporter: ['text', 'json', 'html', 'json-summary'],
reportsDirectory: './coverage/js',
include: ['src/**/*.{ts,tsx,js,jsx}', 'frontend/**/*.{ts,tsx,js,jsx}', 'main.js'],
exclude: ['node_modules/', 'tests/', 'dist/', 'coverage/']
}
}
})