import {
  testContext,
  testHook,
  testRenderProp,
} from '../../__tests__/helpers/state'
import { Buffer, BufferProvider, useBuffer, useBufferContext } from '../Buffer'

const validateAPI = (api) => {
  expect(api.value).toEqual('')
  expect(api.clear).toBeInstanceOf(Function)
  expect(api.reset).toBeInstanceOf(Function)
  expect(api.update).toBeInstanceOf(Function)
}

const apiTest = {
  test: 'api',
  config: {},
  callback: validateAPI,
}

const configTest = {
  test: 'config',
  config: { initialValue: 'foo' },
  callback: ({ value }) => expect(value).toEqual('foo'),
}

describe('Buffer', () => {
  testHook(useBuffer, [
    apiTest,
    configTest,
    {
      test: 'mutations',
      config: { initialValue: 'foo' },
      mutations: [
        ['update', 'bar', ['value', 'toBe', 'bar']],
        ['clear', null, ['value', 'toBe', '']],
        ['reset', null, ['value', 'toBe', 'foo']],
      ],
    },
  ])

  testRenderProp(Buffer, 'buffer', [apiTest, configTest])

  testContext(BufferProvider, useBufferContext, [
    apiTest,
    configTest,
    {
      test: 'missing provider',
      config: {},
      injectProvider: false,
      callback: (context, { spy }) => {
        spy.mockImplementation(() => {})

        context.update()
        context.clear()
        context.reset()
        expect(context.value).toBe('')
        expect(spy).toBeCalledTimes(3)
        expect(spy).toHaveBeenNthCalledWith(
          1,
          'Could not call `update`, please wrap your component in a `<BufferProvider>`'
        )
        expect(spy).toHaveBeenNthCalledWith(
          2,
          'Could not call `clear`, please wrap your component in a `<BufferProvider>`'
        )
        expect(spy).toHaveBeenNthCalledWith(
          3,
          'Could not call `reset`, please wrap your component in a `<BufferProvider>`'
        )

        spy.mockRestore()
      },
    },
  ])
})
