Utilizziamo i cookie per migliorare la tua esperienza sul sito
CodeWorlds

Testowanie Interakcji -- Symulator Pilotażu

W prawdziwym statku kosmicznym pilot naciska przyciski, obraca pokrętła i wprowadza dane na klawiaturze. W testach React musimy symulować te same interakcje, aby upewnić się, że aplikacja reaguje poprawnie.

fireEvent -- Podstawowa symulacja

fireEvent
to narzędzie z React Testing Library do wywoływania zdarzeń DOM:

1import { render, screen, fireEvent } from '@testing-library/react';
2
3test('toggles engine status on button click', () => {
4  render(<EnginePanel />);
5
6  const toggleButton = screen.getByRole('button', { name: 'Toggle Engine' });
7  expect(screen.getByText('Engine: OFF')).toBeInTheDocument();
8
9  fireEvent.click(toggleButton);
10  expect(screen.getByText('Engine: ON')).toBeInTheDocument();
11
12  fireEvent.click(toggleButton);
13  expect(screen.getByText('Engine: OFF')).toBeInTheDocument();
14});

Zdarzenia formularzy

1test('updates pilot name input', () => {
2  render(<PilotForm />);
3
4  const nameInput = screen.getByLabelText('Pilot Name');
5  fireEvent.change(nameInput, { target: { value: 'Commander Nova' } });
6
7  expect(nameInput).toHaveValue('Commander Nova');
8});
9
10test('submits mission form', () => {
11  const mockSubmit = jest.fn();
12  render(<MissionForm onSubmit={mockSubmit} />);
13
14  fireEvent.change(screen.getByLabelText('Destination'), {
15    target: { value: 'Mars' }
16  });
17  fireEvent.click(screen.getByRole('button', { name: 'Launch' }));
18
19  expect(mockSubmit).toHaveBeenCalledWith({ destination: 'Mars' });
20});

userEvent -- Realistyczna symulacja

userEvent
to bardziej zaawansowana biblioteka, która symuluje zdarzenia tak, jak robi to prawdziwy użytkownik. Zamiast jednego zdarzenia
change
, symuluje naciśnięcia poszczególnych klawiszy:

1import userEvent from '@testing-library/user-event';
2
3test('types pilot name realistically', async () => {
4  const user = userEvent.setup();
5  render(<PilotForm />);
6
7  const nameInput = screen.getByLabelText('Pilot Name');
8  await user.type(nameInput, 'Commander Nova');
9
10  expect(nameInput).toHaveValue('Commander Nova');
11});

Kluczowe różnice: fireEvent vs userEvent

1// fireEvent -- szybki, ale mniej realistyczny
2fireEvent.change(input, { target: { value: 'text' } });
3// Wywołuje TYLKO zdarzenie change
4
5// userEvent -- wolniejszy, ale realistyczny
6await user.type(input, 'text');
7// Wywołuje focus, keyDown, keyPress, input, keyUp
8// dla KAŻDEGO znaku, plus change na końcu

Klikanie i podwójne klikanie

1test('handles click and double click', async () => {
2  const user = userEvent.setup();
3  render(<NavigationPanel />);
4
5  // Pojedyncze kliknięcie
6  await user.click(screen.getByRole('button', { name: 'Select' }));
7
8  // Podwójne kliknięcie
9  await user.dblClick(screen.getByText('Mission Details'));
10
11  // Kliknięcie prawym przyciskiem
12  await user.pointer({
13    keys: '[MouseRight]',
14    target: screen.getByText('Options')
15  });
16});

Interakcje z klawiaturą

1test('keyboard navigation in mission list', async () => {
2  const user = userEvent.setup();
3  render(<MissionList />);
4
5  // Tab do następnego elementu
6  await user.tab();
7  expect(screen.getByText('Mission Alpha')).toHaveFocus();
8
9  // Tab do kolejnego
10  await user.tab();
11  expect(screen.getByText('Mission Beta')).toHaveFocus();
12
13  // Enter aby wybrać
14  await user.keyboard('{Enter}');
15  expect(screen.getByText('Selected: Mission Beta')).toBeInTheDocument();
16});

Czyszczenie i zaznaczanie tekstu

1test('clears and replaces input value', async () => {
2  const user = userEvent.setup();
3  render(<CoordinateInput defaultValue="0,0,0" />);
4
5  const input = screen.getByRole('textbox');
6  // Zaznacz wszystko i wyczyść
7  await user.clear(input);
8  expect(input).toHaveValue('');
9
10  // Wpisz nową wartość
11  await user.type(input, '42,15,88');
12  expect(input).toHaveValue('42,15,88');
13});

Selectbox i checkbox

1test('selects planet from dropdown', async () => {
2  const user = userEvent.setup();
3  render(<PlanetSelector />);
4
5  await user.selectOptions(
6    screen.getByRole('combobox'),
7    screen.getByRole('option', { name: 'Mars' })
8  );
9
10  expect(screen.getByRole('option', { name: 'Mars' }).selected).toBe(true);
11});
12
13test('toggles autopilot checkbox', async () => {
14  const user = userEvent.setup();
15  render(<AutopilotSwitch />);
16
17  const checkbox = screen.getByRole('checkbox', { name: 'Autopilot' });
18  expect(checkbox).not.toBeChecked();
19
20  await user.click(checkbox);
21  expect(checkbox).toBeChecked();
22});

Testowanie callbacków i props

1test('calls onLaunch when all systems ready', async () => {
2  const user = userEvent.setup();
3  const handleLaunch = jest.fn();
4
5  render(<LaunchButton onLaunch={handleLaunch} systemsReady={true} />);
6
7  await user.click(screen.getByRole('button', { name: 'Launch' }));
8  expect(handleLaunch).toHaveBeenCalledTimes(1);
9});
10
11test('does not call onLaunch when systems not ready', async () => {
12  const user = userEvent.setup();
13  const handleLaunch = jest.fn();
14
15  render(<LaunchButton onLaunch={handleLaunch} systemsReady={false} />);
16
17  await user.click(screen.getByRole('button', { name: 'Launch' }));
18  expect(handleLaunch).not.toHaveBeenCalled();
19});
Vai a CodeWorlds