ElectronicBabylonianLiterature/ebl-frontend

View on GitHub
src/common/List.test.tsx

Summary

Maintainability
A
0 mins
Test Coverage
import React from 'react'
import _ from 'lodash'
import { FormControl } from 'react-bootstrap'
import List from './List'
import { render, screen } from '@testing-library/react'
import { whenClicked, whenChangedByValue } from 'test-support/utils'

const label = 'List'
const id = 'list'
const noun = 'text'
const items = ['text1', 'text2', 'text3']
let defaultValue
let onChange

beforeEach(() => {
  onChange = jest.fn()
})

describe('Default is not a function', () => {
  beforeEach(async () => {
    defaultValue = ''
    renderList()
  })

  it('New entry has the default value', async () => {
    await whenClicked(screen, `Add ${noun}`)
      .expect(onChange)
      .toHaveBeenCalledWith([...items, defaultValue])
  })

  commonTests()
})

describe('Default is a function', () => {
  beforeEach(async () => {
    defaultValue = () => ''
    renderList()
  })

  it('New entry has the default value', async () => {
    await whenClicked(screen, `Add ${noun}`)
      .expect(onChange)
      .toHaveBeenCalledWith([...items, defaultValue()])
  })

  commonTests()
})

function commonTests() {
  it('Displays the label', () => {
    expect(screen.getByText(label)).toBeVisible()
  })

  describe.each(items)('Item %#', (item) => {
    const index = items.indexOf(item)

    it(`Displays the item`, () => {
      expect(screen.getByDisplayValue(item)).toBeVisible()
    })

    it(`Removes the item when Delete is clicked`, async () => {
      await whenClicked(screen, `Delete ${noun}`, index)
        .expect(onChange)
        .toHaveBeenCalledWith(
          _.reject(items, (value, itemIndex) => itemIndex === index)
        )
    })

    it(`Calls onChange with updated value on item change`, () => {
      whenChangedByValue(screen, item, 'new')
        .expect(onChange)
        .toHaveBeenCalledWith((updatedItem) =>
          items.map((item, itemIndex) =>
            itemIndex === index ? updatedItem : item
          )
        )
    })
  })
}

function renderList() {
  function TestFormControl({
    onChange,
    value,
  }: {
    onChange: (value: string) => void
    value: string
  }): JSX.Element {
    return (
      <FormControl
        type="text"
        value={value}
        onChange={(event) => onChange(event.target.value)}
      />
    )
  }
  render(
    <List
      id={id}
      value={items}
      onChange={onChange}
      label={label}
      noun={noun}
      defaultValue={defaultValue}
    >
      {(value, onChange) => (
        <TestFormControl value={value} onChange={onChange} />
      )}
    </List>
  )
}