UNPKG

bootstrap-vue

Version:

Quickly integrate Bootstrap 4 components with Vue.js

636 lines (535 loc) 24.4 kB
import { loadFixture, testVM, setData, nextTick, sleep } from '../../../tests/utils'; describe("table", async () => { beforeEach(loadFixture(__dirname, "table")); testVM(); it("all example tables should contain class names", async () => { const { app: { $refs, $el } } = window; expect($refs.table_basic).toHaveAllClasses(["table", "b-table", "table-striped", "table-hover"]); expect($refs.table_paginated).toHaveAllClasses([ "table", "b-table", "table-sm", "table-striped", "table-bordered", "table-hover", "table-responsive" ]); expect($refs.table_dark).toHaveAllClasses([ "table", "b-table", "table-sm", "table-bordered", "table-dark" ]); }); it("table_basic should have thead and tbody", async () => { const { app: { $refs, $el } } = window; const parts = [...$refs.table_basic.$el.children]; const thead = parts.find(el => el.tagName && el.tagName === "THEAD"); expect(thead).toBeDefined(); const tbody = parts.find(el => el.tagName && el.tagName === "TBODY"); expect(tbody).toBeDefined(); const tfoot = parts.find(el => el.tagName && el.tagName === "TFOOT"); expect(tfoot).not.toBeDefined(); }); it("table_paginated should have thead, tbody and tfoot", async () => { const { app: { $refs, $el } } = window; const parts = [...$refs.table_paginated.$el.children]; const thead = parts.find(el => el.tagName && el.tagName === "THEAD"); expect(thead).toBeDefined(); const tbody = parts.find(el => el.tagName && el.tagName === "TBODY"); expect(tbody).toBeDefined(); const tfoot = parts.find(el => el.tagName && el.tagName === "TFOOT"); expect(tfoot).toBeDefined(); }); it("table_dark should have thead and tbody", async () => { const { app: { $refs, $el } } = window; const parts = [...$refs.table_dark.$el.children]; const thead = parts.find(el => el.tagName && el.tagName === "THEAD"); expect(thead).toBeDefined(); const tbody = parts.find(el => el.tagName && el.tagName === "TBODY"); expect(tbody).toBeDefined(); const tfoot = parts.find(el => el.tagName && el.tagName === "TFOOT"); expect(tfoot).not.toBeDefined(); }); it("table_paginated thead should contain class thead-dark", async () => { const { app: { $refs, $el } } = window; const thead = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { expect(thead.classList.contains("thead-dark")).toBe(true); } }); it("table_paginated tfoot should contain class thead-light", async () => { const { app: { $refs, $el } } = window; const tfoot = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "TFOOT"); expect(tfoot).toBeDefined(); if (tfoot) { expect(tfoot.classList.contains("thead-light")).toBe(true); } }); it("all examples have correct number of columns", async () => { const { app: { $refs, $el } } = window; const tables = ["table_basic", "table_paginated", "table_dark"]; tables.forEach((table, idx) => { const vm = $refs[table]; const thead = [...vm.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { const tr = [...thead.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children.length).toBe(Object.keys(vm.fields).length); } } }); }); it("all examples should show the correct number of visible rows", async () => { const { app: { $refs, $el } } = window; const app = window.app; const tables = ["table_basic", "table_paginated", "table_dark"]; tables.forEach((table, idx) => { const vm = $refs[table]; const tbody = [...vm.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { expect(tbody.children.length).toBe(vm.perPage || app.items.length); } }); }); it("all examples have sortable & unsortable headers", async () => { const { app: { $refs, $el } } = window; const tables = ["table_basic", "table_paginated", "table_dark"]; const sortables = [true, true, false, false]; tables.forEach(table => { const vm = $refs[table]; const thead = [...vm.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { const tr = [...thead.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { const fieldKeys = Object.keys(vm.fields); const ths = [...tr.children]; expect(ths.length).toBe(fieldKeys.length); ths.forEach((th, idx) => { expect(th.classList.contains("sorting")).toBe(vm.fields[fieldKeys[idx]].sortable || false); }); } } }); }); it("table_paginated has sortable & unsortable footers", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const fieldKeys = Object.keys(vm.fields); const tfoot = [...vm.$el.children].find(el => el && el.tagName === "TFOOT"); expect(tfoot).toBeDefined(); if (tfoot) { const tr = [...tfoot.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { const ths = [...tr.children]; expect(ths.length).toBe(fieldKeys.length); ths.forEach((th, idx) => { expect(th.classList.contains("sorting")).toBe(vm.fields[fieldKeys[idx]].sortable || false); }); } } }); it('all example tables should have attribute aria-busy="false" when busy is false', async () => { const { app: { $refs, $el } } = window; const tables = ["table_basic", "table_paginated", "table_dark"]; await setData(app, "isBusy", false); await nextTick(); tables.forEach(table => { expect($refs[table].$el.getAttribute("aria-busy")).toBe("false"); }); }); it('table_paginated should have attribute aria-busy="true" when busy is true', async () => { const { app: { $refs, $el } } = window; const app = window.app; await setData(app, "isBusy", true); await nextTick(); expect($refs.table_paginated.$el.getAttribute("aria-busy")).toBe("true"); await setData(app, "isBusy", false); await nextTick(); expect($refs.table_paginated.$el.getAttribute("aria-busy")).toBe("false"); }); it("sortable columns should have ARIA labels in thead", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const ariaLabel = vm.labelSortDesc; const thead = [...vm.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { const tr = [...thead.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children[0].getAttribute("aria-label")).toBe(ariaLabel); expect(tr.children[1].getAttribute("aria-label")).toBe(ariaLabel); expect(tr.children[2].getAttribute("aria-label")).toBe(null); expect(tr.children[3].getAttribute("aria-label")).toBe(null); } } }); it("sortable columns should have ARIA labels in tfoot", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const ariaLabel = vm.labelSortDesc; const tfoot = [...vm.$el.children].find(el => el && el.tagName === "THEAD"); expect(tfoot).toBeDefined(); if (tfoot) { const tr = [...tfoot.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children[0].getAttribute("aria-label")).toBe(ariaLabel); expect(tr.children[1].getAttribute("aria-label")).toBe(ariaLabel); expect(tr.children[2].getAttribute("aria-label")).toBe(null); expect(tr.children[3].getAttribute("aria-label")).toBe(null); } } }); it('all examples should have variant "success" on 1st row', async () => { const { app: { $refs, $el } } = window; const app = window.app; const tables = ["table_basic", "table_paginated", "table_dark"]; const items = app.items.slice(); items[0]._rowVariant = "success"; await setData(app, "items", items); await nextTick(); tables.forEach((table, idx) => { const vm = $refs[table]; const tbody = [...vm.$el.children].find(el => el && el.tagName == "TBODY"); expect(tbody).toBeDefined(); if (tbody) { const tr = tbody.children[0]; const variant = vm.dark ? "bg-success" : "table-success"; expect(Boolean(tr) && Boolean(tr.classList) && tr.classList.contains(variant)).toBe(true); } }); }); it("table_basic should contain custom formatted columns", async () => { const { app: { $refs, $el } } = window; const app = window.app; const vm = $refs.table_basic; const tbody = [...vm.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { const tr = [...tbody.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children[0].textContent).toContain(vm.items[0].name.first + " " + vm.items[0].name.last); expect(tr.children[1].textContent).toContain(String(vm.items[0].age)); expect(tr.children[3].children[0].tagName).toBe("BUTTON"); } } }); it("table_paginated should contain custom formatted columns", async () => { const { app: { $refs, $el } } = window; const app = window.app; const vm = $refs.table_basic; const tbody = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { const tr = [...tbody.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children[0].textContent).toContain(vm.items[0].name.first + " " + vm.items[0].name.last); expect(tr.children[1].textContent).toContain(String(vm.items[0].age)); expect(tr.children[3].children[0].tagName).toBe("INPUT"); } } }); it("table_paginated should contain custom formatted headers", async () => { const { app: { $refs, $el } } = window; const thead = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { const tr = [...thead.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children[0].textContent).toContain("Person Full name"); expect(tr.children[1].textContent).toContain("Person age"); expect(tr.children[2].textContent).toContain("is Active"); expect(tr.children[3].textContent).toContain("Select"); } } }); it("table_paginated should contain custom formatted footers", async () => { const { app: { $refs, $el } } = window; const tfoot = [...$refs.table_paginated.$el.children].find(el => el && el.tagName === "TFOOT"); expect(tfoot).toBeDefined(); if (tfoot) { const tr = [...tfoot.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { expect(tr.children[0].textContent).toContain("Showing 5 People"); expect(tr.children[1].textContent).toContain("Person age"); expect(tr.children[2].textContent).toContain("is Active"); expect(tr.children[3].textContent).toContain("Selected: 0"); } } }); it("each data row should emit a row-clicked event when clicked", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const tbody = [...vm.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { const trs = [...tbody.children]; expect(trs.length).toBe(vm.perPage); trs.forEach((tr, idx) => { const spy = jest.fn(); vm.$on("row-clicked", spy); tr.click(); vm.$off("row-clicked", spy); expect(spy).toHaveBeenCalled(); }); } }); it("each header th should emit a head-clicked event when clicked", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const fieldKeys = Object.keys(vm.fields); const thead = [...vm.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { const tr = [...thead.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { const ths = [...tr.children]; expect(ths.length).toBe(fieldKeys.length); ths.forEach((th, idx) => { const spy = jest.fn(); vm.$on("head-clicked", spy); th.click(); vm.$off("head-clicked", spy); expect(spy).toHaveBeenCalled(); }); } } }); it("each footer th should emit a head-clicked event when clicked", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const fieldKeys = Object.keys(vm.fields); const tfoot = [...vm.$el.children].find(el => el && el.tagName === "TFOOT"); expect(tfoot).toBeDefined(); if (tfoot) { const tr = [...tfoot.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { const ths = [...tr.children]; expect(ths.length).toBe(fieldKeys.length); ths.forEach((th, idx) => { const spy = jest.fn(); vm.$on("head-clicked", spy); th.click(); vm.$off("head-clicked", spy); expect(spy).toHaveBeenCalled(); }); } } }); it("sortable header th should emit a sort-changed event with context when clicked and sort changed", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const spy = jest.fn(); const fieldKeys = Object.keys(vm.fields); vm.$on("sort-changed", spy); const thead = [...vm.$el.children].find(el => el && el.tagName === "THEAD"); expect(thead).toBeDefined(); if (thead) { const tr = [...thead.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { let sortBy = null; const ths = [...tr.children]; expect(ths.length).toBe(fieldKeys.length); ths.forEach((th, idx) => { th.click(); if (vm.fields[fieldKeys[idx]].sortable) { expect(spy).toHaveBeenCalledWith(vm.context); expect(vm.context.sortBy).toBe(fieldKeys[idx]); sortBy = vm.context.sortBy; } else { if (sortBy) { expect(spy).toHaveBeenCalledWith(vm.context); expect(vm.context.sortBy).toBe(null); sortBy = null; } else { expect(spy).not.toHaveBeenCalled(); expect(vm.context.sortBy).toBe(null); } } spy.mockClear(); }); } } }); it("sortable footer th should emit a sort-changed event with context when clicked and sort changed", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const spy = jest.fn(); const fieldKeys = Object.keys(vm.fields); vm.$on("sort-changed", spy); const tfoot = [...vm.$el.children].find(el => el && el.tagName === "TFOOT"); expect(tfoot).toBeDefined(); if (tfoot) { const tr = [...tfoot.children].find(el => el && el.tagName === "TR"); expect(tr).toBeDefined(); if (tr) { let sortBy = null; const ths = [...tr.children]; expect(ths.length).toBe(fieldKeys.length); ths.forEach((th, idx) => { th.click(); if (vm.fields[fieldKeys[idx]].sortable) { expect(spy).toHaveBeenCalledWith(vm.context); expect(vm.context.sortBy).toBe(fieldKeys[idx]); sortBy = vm.context.sortBy; } else { if (sortBy) { expect(spy).toHaveBeenCalledWith(vm.context); expect(vm.context.sortBy).toBe(null); sortBy = null; } else { expect(spy).not.toHaveBeenCalled(); expect(vm.context.sortBy).toBe(null); } } spy.mockClear(); }); } } }); it("table_paginated pagination works", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const app = window.app; const spy = jest.fn(); const tbody = [...vm.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { // We need between 11 and 14 ites for this test expect(app.items.length > 10).toBe(true); expect(app.items.length < 15).toBe(true); vm.$on("input", spy); // Page size to be less then number of items await setData(app, "currentPage", 1); await setData(app, "perPage", 10); await nextTick(); expect(vm.perPage).toBe(10); expect(vm.value.length).toBe(10); expect(tbody.children.length).toBe(10); // Goto page 2, should have length 1 await setData(app, "currentPage", 2); await nextTick(); expect(vm.value.length).toBe(app.items.length - 10); expect(tbody.children.length).toBe(app.items.length - 10); expect(spy).toHaveBeenCalled(); } }); it("table_paginated filtering works", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const app = window.app; const spy = jest.fn(); expect(vm.showEmpty).toBe(true); expect(app.items.length > 10).toBe(true); expect(app.items.length < 15).toBe(true); const tbody = [...vm.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { expect(app.items.length > 1).toBe(true); vm.$on("input", spy); // Set page size to max number of items await setData(app, "currentPage", 1); await setData(app, "perPage", 15); await nextTick(); expect(vm.value.length).toBe(app.items.length); expect(tbody.children.length).toBe(app.items.length); // Apply Fiter await setData(app, "filter", String(app.items[0].name.last)); await nextTick(); expect(vm.value.length < app.items.length).toBe(true); expect(tbody.children.length < app.items.length).toBe(true); // Empty filter alert await setData(app, "filter", "ZZZZZZZZZZZZZZZZZzzzzzzzzzzzzzzzzz........"); await nextTick(); expect(vm.value.length).toBe(0); expect(tbody.children.length).toBe(1); expect(tbody.children[0].children[0].textContent).toContain(vm.emptyFilteredText); expect(spy).toHaveBeenCalled(); } }); it("table_paginated shows empty message when no items", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_paginated; const app = window.app; const spy = jest.fn(); expect(vm.showEmpty).toBe(true); const tbody = [...vm.$el.children].find(el => el && el.tagName === "TBODY"); expect(tbody).toBeDefined(); if (tbody) { expect(app.items.length > 10).toBe(true); expect(app.items.length < 15).toBe(true); vm.$on("input", spy); // Set page size to show all items await setData(app, "currentPage", 1); await setData(app, "perPage", 15); await nextTick(); expect(vm.value.length).toBe(app.items.length); expect(tbody.children.length).toBe(app.items.length); // Set items to empty list await setData(app, "items", []); await nextTick(); expect(app.items.length).toBe(0); expect(vm.value.length).toBe(0); expect(tbody.children.length).toBe(1); expect(tbody.textContent).toContain(vm.emptyText); expect(spy).toHaveBeenCalled(); } }); it("table_provider should emit a refreshed event for providerArray", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_provider; const spy = jest.fn(); await setData(app, "providerType", "array"); await nextTick(); await sleep(100); vm.$on("refreshed", spy); vm.refresh(); await nextTick(); await sleep(100); expect(spy).toHaveBeenCalled(); // expect(vm.value.length).toBe(app.items.length) }); it("table_provider should emit a refreshed event for providerCallback", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_provider; const spy = jest.fn(); await setData(app, "providerType", "callback"); await nextTick(); await sleep(100); vm.$on("refreshed", spy); vm.refresh(); await nextTick(); await sleep(100); expect(spy).toHaveBeenCalled(); }); it("table_provider should emit a refreshed event for providerPromise", async () => { const { app: { $refs, $el } } = window; const vm = $refs.table_provider; const spy = jest.fn(); await setData(app, "providerType", "promise"); await nextTick(); await sleep(100); vm.$on("refreshed", spy); vm.refresh(); await nextTick(); await sleep(100); expect(spy).toHaveBeenCalled(); }); });