import React, { createRef } from 'react';
import { act, render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import AsyncButton from './index';
jest.useFakeTimers();
const pendingConfig = {
children: 'Loading…',
};
const successConfig = {
children: 'Success!',
};
const errorConfig = {
children: 'Try again',
};
describe(' component', () => {
const defaultProps = {
children: 'Click me',
pendingConfig,
successConfig,
errorConfig,
};
let user: ReturnType;
beforeEach(() => {
user = userEvent.setup({
advanceTimers: jest.advanceTimersByTime,
});
});
it('renders button properly', () => {
render();
expect(screen.queryByRole('button')).toBeInTheDocument();
});
it('passes ref correctly', () => {
const ref = createRef();
render();
const button = screen.getByRole('button');
expect(ref.current).toBe(button);
});
it('calls onClick properly', async () => {
const onClick = jest.fn();
render();
const button = screen.getByRole('button');
await user.click(button);
expect(onClick).toHaveBeenCalledTimes(1);
expect(onClick).toHaveBeenCalledWith(expect.any(Object));
});
it('changes button state to success on click if onClick is synchronous', async () => {
const onClick = () => {
// Intentionally empty
};
render();
const button = screen.getByRole('button');
await user.click(button);
const button2 = screen.getByRole('button');
expect(button2).toHaveTextContent('Success!');
});
it('changes button state to default after refresh timeout has passed', async () => {
const onClick = () => {
// Intentionally empty
};
render();
const button = screen.getByRole('button');
await user.click(button);
const button2 = screen.getByRole('button');
expect(button2).toHaveTextContent('Success!');
act(() => {
jest.advanceTimersByTime(1000);
});
const button3 = screen.getByRole('button');
expect(button3).toHaveTextContent('Success!');
act(() => {
jest.advanceTimersByTime(1000);
});
const button4 = screen.getByRole('button');
expect(button4).toHaveTextContent('Click me');
});
it('changes button state to pending on click if onClick is asynchronous', async () => {
let resolve: () => void;
const onClick = () =>
new Promise((res) => {
resolve = res;
});
render();
const button = screen.getByRole('button');
await user.click(button);
const button2 = screen.getByRole('button');
expect(button2).toHaveTextContent('Loading…');
await act(async () => {
resolve();
});
});
it('changes button state to success after asynchronous onClick is resolved', async () => {
let resolve: () => void;
const onClick = () =>
new Promise((res) => {
resolve = res;
});
render();
const button = screen.getByRole('button');
await user.click(button);
const button2 = screen.getByRole('button');
expect(button2).toHaveTextContent('Loading…');
await act(async () => {
resolve();
});
const button3 = screen.getByRole('button');
expect(button3).toHaveTextContent('Success!');
});
it('changes button state to default after refresh timeout has passed', async () => {
let resolve: () => void;
const onClick = () =>
new Promise((res) => {
resolve = res;
});
render();
const button = screen.getByRole('button');
await user.click(button);
const button2 = screen.getByRole('button');
expect(button2).toHaveTextContent('Loading…');
await act(async () => {
resolve();
});
const button3 = screen.getByRole('button');
expect(button3).toHaveTextContent('Success!');
act(() => {
jest.advanceTimersByTime(1000);
});
const button4 = screen.getByRole('button');
expect(button4).toHaveTextContent('Success!');
act(() => {
jest.advanceTimersByTime(1000);
});
const button5 = screen.getByRole('button');
expect(button5).toHaveTextContent('Click me');
});
it('should allow button props to be passed by default', () => {
// @ts-expect-no-error
;
});
it('should allow button props to be passed given as="button"', () => {
// @ts-expect-no-error
;
});
it('should not allow link props to be passed given as="button"', () => {
// @ts-expect-error-next-line
;
// Sanity check
// @ts-expect-error-next-line
;
});
it('should allow link props to be passed given as="a"', () => {
// @ts-expect-no-error
;
});
it('should not allow button props to be passed given as="a"', () => {
// @ts-expect-error-next-line
;
// Sanity check
// @ts-expect-error-next-line
Click me
;
});
it('should not allow button props to be passed given as={MyButton}', () => {
function MyButton() {
return ;
}
// @ts-expect-error-next-line
;
// Sanity check
function MyCustomComponent({ as, ...otherProps }: { as: React.ElementType }) {
const Component = as || 'div';
return ;
}
// @ts-expect-error-next-line
;
});
it('should not allow invalid values for as', () => {
// @ts-expect-error-next-line
;
// Sanity check
function MyCustomComponent({ as }: { as: React.ElementType }) {
const Component = as || 'div';
return ;
}
// @ts-expect-error-next-line
;
});
});