1const myComponent = () => (
2 <div>Hello World!</div>
3)
4
5function lessonTitle(title) {
6 return document.createElement('span').setAttribute('text', title)
7}
8
9const fib = (n) => {
10 if (n === 0 || n === 1) {
11 return n
12 }
13 return fib(n-1) + fib(n-2)
14}
1const fib = (n) => {
2 if (n === 0 || n === 1) {
3 return n
4 }
5 return fib(n-1) + fib(n-2)
6}
7export default { fib }
8
9test('should calculate fibonacci numbers', () => {
10 expect(fib(5)).toBe(8)
11})
1const fibR = (n, memo) => {
2 if (memo[n]) {
3 return memo[n]
4 }
5 memo[n] = fib(n-1, memo) + fib(n-2, memo)
6 return memo[n]
7}
8
9const fib = (n) => {
10 return fibR(n, [0,1])
11}
12export default { fib }
13
14test('should calculate fibonacci numbers', () => {
15 expect(fib(5)).toBe(8)
16})
17
18test('should test with mocks', () => {
19 const fibRSpy = jest.spyOn(fibR)
20 fib(5)
21
22 expect(fibRSpy).toHaveBeenCalled()
23})
1import { makeAdder, makeSubtracter } from './func-utils'
2
3// const makeAdder = (x) => (n) => n + x
4// const makeSubtracter = (x) => (n) => n - x
5
6const fib = (n) => {
7 if (n === 0 || n === 1) {
8 return n
9 }
10 return makeAdder(fib(makeSubtracter(1)(n)))(fib(makeSubtracter(2)(n)))
11}
12export default { fib }
13
14test('should calculate fibonacci numbers', () => {
15 expect(fib(5)).toBe(8)
16})
17
18test('should calculate fibonacci numbers', () => {
19 const mockAdder = jest.spyOn(makeAdder)
20 const mockSubtracter = jest.spyOn(makeSubtracter)
21
22 fib(5)
23
24 expect(mockAdder).toBeCalledWith(3)
25})
1import {render, screen} from '@testing-library/react'
2import userEvent from '@testing-library/user-event'
3import Greeter from './greeter'
4
5it('displays a greeting', async () => {
6 // Arrange
7 const name = "World"
8 render(<Greeter name={name} />)
9
10 // Act
11 await screen.findByRole('heading')
12
13 // Assert
14 expect(screen.getByRole('heading')).toHaveTextContent(`Hello ${name}`)
15})
1// Queries Accessible to Everyone
2screen.getByRole('button', { hidden: true })
3screen.getByLabelText('Username')
4screen.getByPlaceholderText('Username')
5screen.getByText(/about/i)
6screen.getByDisplayValue('Alaska')
7
8// Semantic Queries
9screen.getByAltText(/incredibles.*? poster/i)
10screen.getByTitle('Delete')
11
12// Test IDs
13screen.getByTestId('custom-element')
1screen.getByRole('spinbutton', {value: {now: 5}})
2// <button>Volume</button>
3
4screen.getAllByRole('spinbutton', {value: {min: 0}})
5// [
6// <button>Volume</button>,
7// <button>Pitch</button>
8// ]
9
10screen.queryByRole('spinbutton', {value: {now: 5}})
11// null
1test('type into an input field', async () => {
2 const user = userEvent.setup()
3
4 render(<input defaultValue="Hello," />)
5 const input = screen.getByRole('textbox')
6
7 await user.type(input, ' World!')
8
9 expect(input).toHaveValue('Hello, World!')
10})
1pointer(input: PointerActionInput | Array<PointerActionInput>): Promise<void>
2pointer([
3 // touch the screen at element1
4 {keys: '[TouchA>]', target: element1},
5 // move the touch pointer to element2
6 {pointerName: 'TouchA', target: element2},
7 // release the touch pointer at the last position (element2)
8 {keys: '[/TouchA]'},
9])
10
11keyboard(input: KeyboardInput): Promise<void>
12keyboard('{Shift>}A{/Shift}')
13
14clear(element: Element): Promise<void>
15clear(screen.queryByRole('spinbutton'))
16
17selectOptions(
18 element: Element,
19 values: HTMLElement | HTMLElement[] | string[] | string,
20): Promise<void>
21deselectOptions(
22 element: Element,
23 values: HTMLElement | HTMLElement[] | string[] | string,
24): Promise<void>
25selectOptions(screen.getByRole('listbox'), ['1', 'C'])
26
27upload(
28 element: HTMLElement,
29 fileOrFiles: File | File[],
30): Promise<void>
31upload(screen.getByLabelText(/upload file/i), new File())
32
33hover(element: Element): Promise<void>
34hover(screen.getByRole('button'))
35
36unhover(element: Element): Promise<void>
37unhover(screen.getByRole('button'))
1import {render, screen} from '@testing-library/react'
2import userEvent from '@testing-library/user-event'
3import Greeter from './greeter'
4
5jest.mock('react-i18next', () => ({
6 useTranslation: () => ({ t: (str: string) => 'Привіт' })
7}))
8
9test('displays a greeting', async () => {
10 // Arrange
11 const name = "Світ"
12 render(<Greeter language="ukr" name={name} />)
13
14 // Act
15 await screen.findByRole('heading')
16
17 // Assert
18 expect(screen.getByRole('heading')).toHaveTextContent(`Привіт ${name}`)
19})
1import {render, screen} from '@testing-library/react'
2import userEvent from '@testing-library/user-event'
3import Button from './button'
4
5test('calls the onClick handler', async () => {
6 // Arrange
7 const handleClick = jest.fn();
8 render(<Button onClick={handleClick} />)
9
10 // Act
11 await userEvent.click(await screen.findByRole('button'))
12
13 // Assert
14 expect(handleClick).toHaveBeenCalled()
15})
setTimeout
, setInterval
, clearTimeout
, clearInterval
), use fake timers1describe('my fake timers', () => {
2 beforeEach(() => {
3 jest.useFakeTimers()
4 })
5
6 it('runs setTimeout', ...)
7
8 afterEach(() => {
9 jest.runOnlyPendingTimers()
10 jest.useRealTimers()
11 })
12})
1yarn test --coverage
1import type { Meta, StoryObj } from '@storybook/react';
2import { Button } from './Button';
3
4const meta: Meta<typeof Button> = {
5 component: Button,
6};
7
8export default meta;
9
10type Story = StoryObj<typeof Button>;
11
12export const Primary: Story = {
13 render: () => <Button variant="primary" label="Button" />,
14};
15
16export const Secondary: Story = {
17 render: () => <Button variant="secondary" label="Other Button" />,
18}
1import type { Meta } from '@storybook/react';
2
3import { Button } from './Button';
4
5const meta: Meta<typeof Button> = {
6 component: Button,
7 argTypes: {
8 variant: { control: 'select', options: ['primary', 'secondary', 'tertiary'] },
9 label: { control: 'text' }
10 },
11};
12
13export default meta;
14type Story = StoryObj<typeof Button>;
15
16export const Default: Story = {
17 render({ label, variant }) {
18 return <Button label={label} variant={variant} />
19 }
20}
1import type { Meta, StoryObj } from '@storybook/react'
2
3import { DurationInput as DurationInputComponent } from './common/forms/DurationInput'
4
5const meta: Meta<typeof DurationInputComponent> = {
6 title: 'common/forms/DurationInput',
7 component: DurationInputComponent,
8}
9
10export default meta
11type Story = StoryObj<typeof DurationInputComponent>
12
13export const DurationInput: Story = {}
1yarn storybook