diff --git a/components/table/__tests__/__snapshots__/index.test.tsx.snap b/components/table/__tests__/__snapshots__/index.test.tsx.snap
new file mode 100644
index 0000000..a3523fc
--- /dev/null
+++ b/components/table/__tests__/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,469 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Table should be no erros when width is too large 1`] = `
+"
property
description
default
type
Content type
-
Component
DOM element to use
-
bold
Bold style
true
"
+`;
+
+exports[`Table should render children for table head 1`] = `
+"property
type
Component
bold
"
+`;
+
+exports[`Table should render correctly 1`] = `
+"property
description
default
type
Content type
-
Component
DOM element to use
-
bold
Bold style
true
"
+`;
+
+exports[`Table should set width automatically 1`] = `
+"property
description
default
type
Content type
-
Component
DOM element to use
-
bold
Bold style
true
"
+`;
+
+exports[`Table should work with other components 1`] = `
+"property
description
default
type
Content type
-
Component
DOM element to use
-
bold
Bold style
true
bold
boolean
true
"
+`;
+
+exports[`Table should work without hover effect 1`] = `
+"property
description
default
type
Content type
-
Component
DOM element to use
-
bold
Bold style
true
"
+`;
diff --git a/components/table/__tests__/index.test.tsx b/components/table/__tests__/index.test.tsx
new file mode 100644
index 0000000..26dc195
--- /dev/null
+++ b/components/table/__tests__/index.test.tsx
@@ -0,0 +1,183 @@
+import React from 'react'
+import { mount } from 'enzyme'
+import { Table, Code } from 'components'
+import { cellActions } from 'components/table/table-cell'
+import { nativeEvent, updateWrapper } from 'tests/utils'
+
+const data = [
+ { property: 'type', description: 'Content type', default: '-' },
+ { property: 'Component', description: 'DOM element to use', default: '-' },
+ { property: 'bold', description: 'Bold style', default: 'true' },
+]
+
+describe('Table', () => {
+ it('should render correctly', () => {
+ const wrapper = mount(
+
+ )
+ expect(wrapper.html()).toMatchSnapshot()
+ expect(() => wrapper.unmount()).not.toThrow()
+ })
+
+ it('should re-render when data changed', async () => {
+ const wrapper = mount(
+
+ )
+ expect(wrapper.find('tbody').find('tr').length).toBe(data.length)
+ wrapper.setProps({ data: [] })
+ await updateWrapper(wrapper, 350)
+ expect(wrapper.find('tbody').find('tr').length).toBe(0)
+
+ })
+
+ it('should set width automatically', () => {
+ window.getComputedStyle = jest.fn()
+ .mockImplementation(() => ({
+ width: '100px',
+ }))
+ const wrapper = mount(
+
+ )
+ expect(wrapper.html()).toMatchSnapshot()
+ expect(() => wrapper.unmount()).not.toThrow()
+ ;(window.getComputedStyle as jest.Mock).mockClear()
+ })
+
+ it('should be no erros when width is too large', () => {
+ window.getComputedStyle = jest.fn()
+ .mockImplementation(() => ({
+ width: '10px',
+ }))
+ const wrapper = mount(
+
+ )
+ expect(wrapper.html()).toMatchSnapshot()
+ expect(() => wrapper.unmount()).not.toThrow()
+ ;(window.getComputedStyle as jest.Mock).mockClear()
+ })
+
+ it('should work with other components', () => {
+ const dataWithNodes = [
+ ...data,
+ { property: 'bold', description: boolean, default: 'true' },
+ ]
+ const wrapper = mount(
+
+ )
+ expect(wrapper.html()).toMatchSnapshot()
+ expect(wrapper.find('code').length).not.toBe(0)
+ expect(() => wrapper.unmount()).not.toThrow()
+ })
+
+ it('should work without hover effect', () => {
+ const wrapper = mount(
+
+ )
+ expect(wrapper.html()).toMatchSnapshot()
+ expect(() => wrapper.unmount()).not.toThrow()
+ })
+
+ it('should be possible to remove the row', () => {
+ const operation = (actions: cellActions) => {
+ return actions.remove()}>Remove
+ }
+ const data = [
+ { property: 'bold', description: 'boolean', operation },
+ ]
+ const wrapper = mount(
+
+ )
+ expect(wrapper.find('tbody').find('tr').length).toBe(1)
+ wrapper.find('tbody').find('button')
+ .simulate('click')
+ expect(wrapper.find('tbody').find('tr').length).toBe(0)
+ expect(() => wrapper.unmount()).not.toThrow()
+ })
+
+ it('should render emptyText when data missing', () => {
+ const data = [
+ { property: 'bold', description: 'boolean' },
+ ]
+ const wrapper = mount(
+
+ )
+ expect(wrapper.find('tbody').text()).toContain('test-not-found')
+ })
+
+ it('should trigger events when cell clicked', () => {
+ const rowHandler = jest.fn()
+ const cellHandler = jest.fn()
+ const data = [
+ { property: 'bold', description: 'boolean' },
+ ]
+ const wrapper = mount(
+
+ )
+ wrapper.find('tbody').find('tr').find('td').at(0)
+ .simulate('click', nativeEvent)
+ expect(rowHandler).toHaveBeenCalled()
+ expect(cellHandler).toHaveBeenCalled()
+ })
+
+ it('should wraning when prop missing', () => {
+ const errorSpy = jest.spyOn(console, 'error')
+ .mockImplementation(() => {})
+ mount(
+
+ )
+ expect(errorSpy).toHaveBeenCalled()
+ errorSpy.mockRestore()
+ })
+
+ it('should render children for table head', () => {
+ const wrapper = mount(
+
+ )
+ expect(wrapper.find('thead').find('code').length)
+ .not.toBe(0)
+ expect(wrapper.html()).toMatchSnapshot()
+ })
+})
diff --git a/components/tabs/__tests__/__snapshots__/index.test.tsx.snap b/components/tabs/__tests__/__snapshots__/index.test.tsx.snap
new file mode 100644
index 0000000..e9ce16c
--- /dev/null
+++ b/components/tabs/__tests__/__snapshots__/index.test.tsx.snap
@@ -0,0 +1,72 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Tabs should render correctly 1`] = `
+""
+`;
diff --git a/components/tabs/__tests__/index.test.tsx b/components/tabs/__tests__/index.test.tsx
new file mode 100644
index 0000000..3299b83
--- /dev/null
+++ b/components/tabs/__tests__/index.test.tsx
@@ -0,0 +1,95 @@
+import React from 'react'
+import { mount } from 'enzyme'
+import { Tabs } from 'components'
+import { nativeEvent, updateWrapper } from 'tests/utils'
+
+describe('Tabs', () => {
+ it('should render correctly', () => {
+ const wrapper = mount(
+
+ 1
+ 2
+
+ )
+ expect(wrapper.html()).toMatchSnapshot()
+ expect(() => wrapper.unmount()).not.toThrow()
+ })
+
+ it('should trigger events when tab changed', () => {
+ let value = ''
+ const changeHandler = jest.fn()
+ .mockImplementation(val => value = val)
+ const wrapper = mount(
+
+ 1
+ 2
+
+ )
+
+ wrapper.find('header').find('.tab').at(1)
+ .simulate('click', nativeEvent)
+ expect(changeHandler).toHaveBeenCalled()
+ expect(value).toBe('2')
+ })
+
+ it('should ignore events when tab disabled', () => {
+ const changeHandler = jest.fn()
+ const wrapper = mount(
+
+ 1
+ 2
+
+ )
+
+ wrapper.find('header').find('.tab').at(1)
+ .simulate('click', nativeEvent)
+ expect(changeHandler).not.toHaveBeenCalled()
+ })
+
+ it('should be activate the specified tab', async () => {
+ const wrapper = mount(
+
+ test-1
+ test-2
+
+ )
+ let active = wrapper.find('header').find('.active')
+ expect(active.text()).toContain('label1')
+
+ wrapper.setProps({ value: '2' })
+ await updateWrapper(wrapper, 350)
+ active = wrapper.find('header').find('.active')
+ expect(active.text()).toContain('label2')
+ })
+
+ it('should warning when label duplicated', () => {
+ const errorSpy = jest.spyOn(console, 'error')
+ .mockImplementation(() => {})
+ mount(
+
+ test-1
+ test-2
+
+ )
+ expect(errorSpy).toHaveBeenCalled()
+ errorSpy.mockRestore()
+ })
+
+ it('should use label as key when value is missing', async () => {
+ const errorSpy = jest.spyOn(console, 'error')
+ .mockImplementation(() => {})
+ const wrapper = mount(
+
+ test-1
+ test-2
+
+ )
+ expect(errorSpy).not.toHaveBeenCalled()
+
+ wrapper.setProps({ value: 'label2' })
+ await updateWrapper(wrapper, 350)
+ const active = wrapper.find('header').find('.active')
+ expect(active.text()).toContain('label2')
+ errorSpy.mockRestore()
+ })
+})
diff --git a/components/tabs/__tests__/use-tabs.test.tsx b/components/tabs/__tests__/use-tabs.test.tsx
new file mode 100644
index 0000000..c487b06
--- /dev/null
+++ b/components/tabs/__tests__/use-tabs.test.tsx
@@ -0,0 +1,34 @@
+import React, { useEffect } from 'react'
+import { mount } from 'enzyme'
+import { Tabs, useTabs } from 'components'
+import { nativeEvent, updateWrapper } from 'tests/utils'
+
+describe('UseTabs', () => {
+ it('should follow changes with use-tabs', async () => {
+ const MockTabs: React.FC<{ value?: string }> = ({ value }) => {
+ const { setState, bindings } = useTabs('1')
+ useEffect(() => {
+ if (value) setState(value)
+ }, [value])
+ return (
+
+ 1
+ 2
+
+ )
+ }
+ const wrapper = mount( )
+ let active = wrapper.find('header').find('.active')
+ expect(active.text()).toContain('label1')
+
+ wrapper.setProps({ value: '2' })
+ await updateWrapper(wrapper, 350)
+ active = wrapper.find('header').find('.active')
+ expect(active.text()).toContain('label2')
+
+ wrapper.find('header').find('.tab').at(0)
+ .simulate('click', nativeEvent)
+ active = wrapper.find('header').find('.active')
+ expect(active.text()).toContain('label1')
+ })
+})