diff --git a/components/ui/__tests__/tabs.spec.js b/components/ui/__tests__/tabs.spec.js
new file mode 100644
index 000000000..d954988df
--- /dev/null
+++ b/components/ui/__tests__/tabs.spec.js
@@ -0,0 +1,68 @@
+import tabs from "../tabs"
+import tab from "../tab"
+
+import { mount } from "@vue/test-utils"
+
+const factory = () =>
+ mount(tabs, {
+ slots: {
+ default: [
+ `tab1
`,
+ `tab1
`,
+ `tab1
`,
+ ],
+ },
+ stubs: {
+ tab,
+ },
+ })
+
+describe("tabs", () => {
+ test("mounts properly", async () => {
+ const wrapper = factory()
+
+ await wrapper.vm.$nextTick()
+
+ expect(wrapper).toBeTruthy()
+ })
+
+ test("tab labels shown", async () => {
+ const wrapper = factory()
+
+ await wrapper.vm.$nextTick()
+
+ const labels = wrapper.findAll("li a span").wrappers.map((w) => w.text())
+ expect(labels).toEqual(["tab 1", "tab 2", "tab 3"])
+ })
+
+ test("tab icons are shown", async () => {
+ const wrapper = factory()
+
+ await wrapper.vm.$nextTick()
+
+ const labels = wrapper.findAll("li a i").wrappers.map((w) => w.text())
+ expect(labels).toEqual(["testicon1", "testicon2", "testicon3"])
+ })
+
+ test("clicking on tab labels switches the selected page", async () => {
+ const wrapper = factory()
+
+ await wrapper.vm.$nextTick()
+ wrapper.vm.selectTab({ id: "tab2" })
+ await wrapper.vm.$nextTick()
+
+ expect(wrapper.vm.$data.tabs[1].$data.isActive).toEqual(true)
+ })
+
+ test("switched tab page is rendered and the other page is not rendered", async () => {
+ const wrapper = factory()
+
+ await wrapper.vm.$nextTick()
+ wrapper.vm.selectTab({ id: "tab2" })
+ await wrapper.vm.$nextTick()
+
+ expect(wrapper.vm.$data.tabs[0].$data.isActive).toEqual(false)
+ expect(wrapper.vm.$data.tabs[1].$data.isActive).toEqual(true)
+ expect(wrapper.vm.$data.tabs[2].$data.isActive).toEqual(false)
+ })
+})