Files
remark42/frontend/app/components/auth/auth.spec.tsx
T

206 lines
8.4 KiB
TypeScript

import '@testing-library/jest-dom';
import { h } from 'preact';
import { fireEvent, render, waitFor } from '@testing-library/preact';
import { Provider, User } from 'common/types';
import { StaticStore } from 'common/static-store';
import Auth from './auth';
import * as utils from './auth.utils';
import * as api from './auth.api';
jest.mock('react-redux', () => ({
useDispatch: () => jest.fn(),
}));
jest.mock('hooks/useTheme', () => () => 'light');
describe('<Auth/>', () => {
let defaultProviders = StaticStore.config.auth_providers;
afterAll(() => {
StaticStore.config.auth_providers = defaultProviders;
});
// TODO: separate tests of `useDropdown` mechanics with the hook
describe('useDropdown', () => {
it('should render auth with hidden dropdown', () => {
const { container } = render(<Auth />);
expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument();
});
it('should close dropdown by click on button', () => {
const { container } = render(<Auth />);
expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument();
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument();
});
it('should close dropdown by click outside of it', () => {
const { container } = render(<Auth />);
expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument();
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
fireEvent.click(document);
expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument();
});
it('should close dropdown by message from parent', async () => {
const { container } = render(<Auth />);
expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument();
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
window.postMessage('{"clickOutside": true}', '*');
await waitFor(() => expect(container.querySelector('.auth-dropdown')).not.toBeInTheDocument());
});
});
it.each([
[[]],
[['dev']],
[['facebook', 'google']],
[['facebook', 'google', 'microsoft']],
[['facebook', 'google', 'microsoft', 'yandex']],
[['facebook', 'google', 'microsoft', 'yandex', 'twitter']],
] as [Provider[]][])('should renders with %j providers', (providers) => {
StaticStore.config.auth_providers = providers;
const { container } = render(<Auth />);
expect(container.querySelector('.auth-dropdown')).toBeNull();
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
expect(container.querySelectorAll('.oauth-button')).toHaveLength(providers.length);
expect(container.querySelector('[name="username"]')).not.toBeInTheDocument();
expect(container.querySelector('.auth-submit')).not.toBeInTheDocument();
});
it('should render email provider', () => {
StaticStore.config.auth_providers = ['email'];
const { container } = render(<Auth />);
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
expect(container.querySelector('.auth-form-title')?.innerHTML).toContain('email');
expect(container.querySelector('[name="username"]')).toBeInTheDocument();
expect(container.querySelector('[name="email"]')).toBeInTheDocument();
expect(container.querySelector('.auth-submit')).toBeInTheDocument();
});
it('should render anonymous provider', () => {
StaticStore.config.auth_providers = ['anonymous'];
const { container } = render(<Auth />);
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
expect(container.querySelector('.auth-form-title')?.innerHTML).toContain('anonymous');
expect(container.querySelector('[name="username"]')).toBeInTheDocument();
expect(container.querySelector('.auth-submit')).toBeInTheDocument();
});
it('should render tabs with two form providers', () => {
StaticStore.config.auth_providers = ['email', 'anonymous'];
const { container } = render(<Auth />);
fireEvent.click(container.querySelector('.auth-button')!);
expect(container.querySelector('.auth-dropdown')).toBeInTheDocument();
expect(container.querySelector('[for="form-provider-anonymous"]')).toBeInTheDocument();
expect(container.querySelector('[for="form-provider-email"]')).toBeInTheDocument();
expect(container.querySelector('[name="username"]')).toBeInTheDocument();
expect(container.querySelector('.auth-submit')).toBeInTheDocument();
fireEvent.click(container.querySelector('[for="form-provider-email"]')!);
expect(container.querySelector('[name="username"]')).toBeInTheDocument();
expect(container.querySelector('[name="email"]')).toBeInTheDocument();
expect(container.querySelector('.auth-submit')).toBeInTheDocument();
});
it('should send email and then verify forms', async () => {
StaticStore.config.auth_providers = ['email'];
jest.spyOn(api, 'emailSignin').mockImplementationOnce(async () => null);
jest.spyOn(api, 'verifyEmailSignin').mockImplementationOnce(async () => ({} as User));
jest.spyOn(utils, 'getTokenInvalidReason').mockImplementationOnce(() => null);
const { container } = render(<Auth />);
fireEvent.click(container.querySelector('.auth-button')!);
fireEvent.change(container.querySelector('[name="username"]')!, { target: { value: 'username' } });
fireEvent.change(container.querySelector('[name="email"]')!, {
target: { value: 'email@email.com' },
});
fireEvent.click(container.querySelector('.auth-submit')!);
expect(container.querySelector('.spinner')).toBeInTheDocument();
await waitFor(() => expect(api.emailSignin).toBeCalled());
expect(container.querySelector('.auth-back-button')).toBeInTheDocument();
expect(container.querySelector('.auth-close-button')).toBeInTheDocument();
expect(container.querySelector('[name="token"]')).toBeInTheDocument();
fireEvent.change(container.querySelector('[name="token"]')!, {
target: { value: 'token' },
});
fireEvent.click(container.querySelector('.auth-submit')!);
await waitFor(() => expect(api.verifyEmailSignin).toBeCalled());
expect(api.verifyEmailSignin).toBeCalledWith('token');
});
it('should show validation error for token', async () => {
StaticStore.config.auth_providers = ['email'];
jest.spyOn(api, 'emailSignin').mockImplementationOnce(async () => null);
const { container } = render(<Auth />);
fireEvent.click(container.querySelector('.auth-button')!);
fireEvent.change(container.querySelector('[name="username"]')!, { target: { value: 'username' } });
fireEvent.change(container.querySelector('[name="email"]')!, {
target: { value: 'email@email.com' },
});
fireEvent.click(container.querySelector('.auth-submit')!);
await waitFor(() => expect(api.emailSignin).toBeCalled());
expect(container.querySelector('.auth-back-button')).toBeInTheDocument();
expect(container.querySelector('.auth-close-button')).toBeInTheDocument();
expect(container.querySelector('[name="token"]')).toBeInTheDocument();
fireEvent.change(container.querySelector('[name="token"]')!, {
target: { value: 'token' },
});
fireEvent.click(container.querySelector('.auth-submit')!);
await waitFor(() => expect(utils.getTokenInvalidReason).toBeCalled());
expect(utils.getTokenInvalidReason).toBeCalledWith('token');
});
it('should send anonym form', async () => {
StaticStore.config.auth_providers = ['anonymous'];
jest.spyOn(api, 'anonymousSignin').mockImplementationOnce(async () => ({} as User));
const { container } = render(<Auth />);
fireEvent.click(container.querySelector('.auth-button')!);
fireEvent.change(container.querySelector('[name="username"]')!, { target: { value: 'username' } });
fireEvent.click(container.querySelector('.auth-submit')!);
expect(container.querySelector('.spinner')).toBeInTheDocument();
await waitFor(() => expect(api.anonymousSignin).toBeCalled());
});
});