ElectronicBabylonianLiterature/ebl-frontend

View on GitHub
src/bibliography/ui/BibliographyEditor.test.tsx

Summary

Maintainability
B
4 hrs
Test Coverage
import React from 'react'
import { matchPath, MemoryRouter, match } from 'react-router'
import { render, Matcher, screen } from '@testing-library/react'
import { Promise } from 'bluebird'
import _ from 'lodash'
import SessionContext from 'auth/SessionContext'
import { submitForm } from 'test-support/utils'
import BibliographyEditor from './BibliographyEditor'
import BibliographyEntry, {
  template,
} from 'bibliography/domain/BibliographyEntry'
import { createMemoryHistory } from 'history'
import { bibliographyEntryFactory } from 'test-support/bibliography-fixtures'

const errorMessage = 'error'
const createWaitFor = /family name/
const resultId = 'RN1000'
let result
let bibliographyService
let session

beforeEach(async () => {
  result = bibliographyEntryFactory.build({}, { transient: { id: resultId } })
  session = {
    isAllowedToReadBibliography: _.stubTrue(),
    isAllowedToWriteBibliography: jest.fn(),
  }
  bibliographyService = {
    find: jest.fn(),
    update: jest.fn(),
    create: jest.fn(),
  }
})

describe('Editing', () => {
  beforeEach(() => {
    bibliographyService.find.mockReturnValueOnce(Promise.resolve(result))
  })

  test('Queries the entry from API', async () => {
    await renderWithRouter(true, false, resultId)

    expect(bibliographyService.find).toBeCalledWith('id')
  })

  test('Displays result on successfull query', async () => {
    const { container } = await renderWithRouter(true, false, resultId)

    expectTextContentToContainCslJson(container, result)
  })

  test('Posts on submit', async () => {
    bibliographyService.update.mockReturnValueOnce(Promise.resolve())
    const { container } = await renderWithRouter(true, false, resultId)

    await submitForm(container)

    expect(bibliographyService.update).toHaveBeenCalledWith(result)
  })

  commonTests(false, resultId)
})

describe('Creating', () => {
  test('Displays template', async () => {
    const { container } = await renderWithRouter(true, true, createWaitFor)

    expectTextContentToContainCslJson(container, template)
  })

  test('Puts on submit', async () => {
    bibliographyService.create.mockReturnValueOnce(Promise.resolve())
    const { container } = await renderWithRouter(true, true, createWaitFor)

    await submitForm(container)

    expect(bibliographyService.create).toHaveBeenCalledWith(template)
  })

  commonTests(true, createWaitFor)
})

function expectTextContentToContainCslJson(
  container: HTMLElement,
  entry: BibliographyEntry
) {
  expect(container).toHaveTextContent(
    JSON.stringify(entry.toCslData(), null, 1).replace(/\s+/g, ' ')
  )
}

function commonTests(create, waitFor): void {
  test('Displays error message failed submit', async () => {
    bibliographyService.update.mockImplementationOnce(() =>
      Promise.reject(new Error(errorMessage))
    )
    bibliographyService.create.mockImplementationOnce(() =>
      Promise.reject(new Error(errorMessage))
    )
    const { container } = await renderWithRouter(true, create, waitFor)

    await submitForm(container)

    await screen.findByText(errorMessage)
  })

  test('Cancels promise on unmount', async () => {
    const promise = new Promise(_.noop)
    jest.spyOn(promise, 'cancel')
    bibliographyService.update.mockReturnValueOnce(promise)
    bibliographyService.create.mockReturnValueOnce(promise)
    const { unmount, container } = await renderWithRouter(true, create, waitFor)
    await submitForm(container)
    unmount()
    expect(promise.isCancelled()).toBe(true)
  })

  test('Saving is disabled when not allowed to write:bibliography', async () => {
    await renderWithRouter(false, create, waitFor)
    expect(screen.getByText('Save')).toBeDisabled()
  })
}

async function renderWithRouter(
  isAllowedTo = true,
  create = false,
  waitFor: Matcher
) {
  const matchedPath = create
    ? (matchPath('/bibliography', {
        path: '/bibliography',
      }) as match)
    : (matchPath('/bibliography/id', {
        path: '/bibliography/:id',
      }) as match)
  session.isAllowedToWriteBibliography.mockReturnValue(isAllowedTo)

  const view = render(
    <MemoryRouter>
      <SessionContext.Provider value={session}>
        <BibliographyEditor
          match={matchedPath}
          bibliographyService={bibliographyService}
          create={create}
          history={createMemoryHistory()}
        />
      </SessionContext.Provider>
    </MemoryRouter>
  )
  await screen.findAllByText(waitFor)
  return view
}