import {
  testContext,
  testHook,
  testRenderProp,
} from '../../__tests__/helpers/state'
import {
  useVisibility,
  useVisibilityContext,
  Visibility,
  VisibilityProvider,
} from '../Visibility'

const validateAPI = (api) => {
  expect(api.isVisible).toEqual(false)
  expect(api.show).toBeInstanceOf(Function)
  expect(api.hide).toBeInstanceOf(Function)
  expect(api.toggle).toBeInstanceOf(Function)
}

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

const configTest = {
  test: 'config',
  config: {
    initialIsVisible: true,
  },
  callback: ({ isVisible }) => {
    expect(isVisible).toEqual(true)
  },
}

describe('Visibility', () => {
  testHook(useVisibility, [
    apiTest,
    configTest,
    {
      test: 'mutations',
      config: {},
      mutations: [
        ['show', null, ['isVisible', 'toBe', true]],
        ['hide', null, ['isVisible', 'toBe', false]],
        ['toggle', null, ['isVisible', 'toBe', true]],
        ['toggle', null, ['isVisible', 'toBe', false]],
      ],
    },
  ])

  testRenderProp(Visibility, 'visibility', [apiTest, configTest])

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

        expect(context.isVisible).toBe(false)
        context.show()
        context.hide()
        context.toggle()
        expect(spy).toBeCalledTimes(3)
        expect(spy).toHaveBeenNthCalledWith(
          1,
          'Could not call `show`, please wrap your component in a `<VisibilityProvider>`'
        )
        expect(spy).toHaveBeenNthCalledWith(
          2,
          'Could not call `hide`, please wrap your component in a `<VisibilityProvider>`'
        )
        expect(spy).toHaveBeenNthCalledWith(
          3,
          'Could not call `toggle`, please wrap your component in a `<VisibilityProvider>`'
        )

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