ifmeorg/ifme

View on GitHub
client/app/components/Input/__tests__/InputTextareaTemplate.spec.jsx

Summary

Maintainability
A
0 mins
Test Coverage
// @flow
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import * as pell from 'pell';
import { InputMocks } from 'mocks/InputMocks';

describe('InputTextareaTemplate', () => {
  beforeAll(() => {
    // mocks obsolete method used internally in Pell
    document.queryCommandState = jest.fn();
    jest.spyOn(pell, 'init');
  });

  it('renders correctly', () => {
    const component = InputMocks.createInput(
      InputMocks.inputTextareaTemplateProps,
    );
    const { container } = render(component);

    const textarea = screen.getByRole('textbox');
    expect(textarea).toBeInTheDocument();

    // Since '@testing-library/react' does not get hidden inputs,
    // it can be queried directly from the container for this test.
    const hiddenInput = container.querySelector('input[type="hidden"]');
    expect(hiddenInput).toBeInTheDocument();

    const editor = container.querySelector('.editor');
    expect(editor).toBeInTheDocument();
  });

  describe('editor', () => {
    it('initializes on mount', () => {
      const component = InputMocks.createInput(
        InputMocks.inputTextareaTemplateProps,
      );
      const { container } = render(component);
      const editor = container.querySelector('.editor');
      expect(pell.init).toHaveBeenCalledWith(
        expect.objectContaining({ element: editor }),
      );
    });

    it('has a tab index and focuses', async () => {
      const component = InputMocks.createInput(
        InputMocks.inputTextareaTemplateProps,
      );
      render(component);
      // first tab should focus the editor textarea
      const textarea = screen.getByRole('textbox');
      await userEvent.tab();
      await userEvent.tab();
      expect(textarea).toHaveFocus();
    });

    describe('if required', () => {
      const { id } = InputMocks.inputTextareaTemplateProps;
      const onError = jest.fn();

      afterEach(() => {
        onError.mockClear();
      });

      describe('on blurring', () => {
        afterEach(() => {
          onError.mockClear();
        });

        it('handles error when empty', async () => {
          const component = InputMocks.createInput(
            InputMocks.inputTextareaTemplateProps,
            { required: true, onError },
          );
          render(component);
          const textarea = screen.getByRole('textbox');
          await userEvent.click(textarea);
          await userEvent.tab();

          expect(onError).toHaveBeenCalledWith(id, true);
        });

        it('does not handle error when a value exists', async () => {
          const component = InputMocks.createInput(
            InputMocks.inputTextareaTemplateProps,
            { required: true, onError, value: 'Some value' },
          );
          render(component);
          const textarea = screen.getByRole('textbox');
          await userEvent.click(textarea);
          await userEvent.tab();

          expect(onError).toHaveBeenCalledWith(id, false);
        });
      });

      it('on focusing resets error', async () => {
        const component = InputMocks.createInput(
          InputMocks.inputTextareaTemplateProps,
          { required: true, onError },
        );
        render(component);
        // triggers focus
        const textarea = screen.getByRole('textbox');
        await userEvent.click(textarea);
        expect(onError).toHaveBeenCalledWith(id, false);
      });
    });

    describe('if not required', () => {
      const onError = jest.fn();

      afterEach(() => {
        onError.mockClear();
      });

      describe('on blurring', () => {
        afterEach(() => {
          onError.mockClear();
        });

        it('does not handle error', async () => {
          const component = InputMocks.createInput(
            InputMocks.inputTextareaTemplateProps,
            { required: false, onError },
          );
          render(component);
          // triggers focus, then blur
          const textarea = screen.getByRole('textbox');
          await userEvent.click(textarea);
          await userEvent.tab();
          expect(onError).not.toHaveBeenCalled();
        });
      });

      it('on focusing does not reset error', async () => {
        const component = InputMocks.createInput(
          InputMocks.inputTextareaTemplateProps,
          { required: false, onError },
        );
        render(component);
        // triggers focus
        const textarea = screen.getByRole('textbox');
        await userEvent.click(textarea);
        expect(onError).not.toHaveBeenCalled();
      });
    });

    it('handles formatting actions', async () => {
      const sampleUrl = 'sample-url';
      jest.spyOn(pell, 'exec');
      // mocks prompting the user for link url
      jest.spyOn(window, 'prompt').mockImplementationOnce(() => sampleUrl);
      render(InputMocks.createInput(InputMocks.inputTextareaTemplateProps));

      const buttons = [
        // default actions
        { title: 'Bold', expectedArgs: ['bold'] },
        // overridden actions
        { title: 'Link', expectedArgs: ['createLink', sampleUrl] },
        { title: 'Ordered List', expectedArgs: ['insertOrderedList'] },
        { title: 'Unordered List', expectedArgs: ['insertUnorderedList'] },
      ];

      buttons.forEach(async ({ title, expectedArgs }) => {
        const button = screen.getByTitle(title);
        userEvent.click(button);
        await waitFor(() => expect(pell.exec).toHaveBeenCalledWith(...expectedArgs));
      });
    });
  });
});