79 lines
3.2 KiB
JavaScript
79 lines
3.2 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import { readFileSync } from 'node:fs'
|
|
import test from 'node:test'
|
|
import { parse, compileScript } from 'vue/compiler-sfc'
|
|
import ts from 'typescript'
|
|
import * as vue from 'vue'
|
|
|
|
const source = readFileSync(new URL('./DataTable.vue', import.meta.url), 'utf8')
|
|
|
|
function paginationHarness(t) {
|
|
const descriptor = parse(source).descriptor
|
|
const compiled = compileScript(descriptor, { id: 'data-table-pagination-test' })
|
|
const code = ts.transpileModule(compiled.content, { compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2022 } }).outputText
|
|
const exports = {}
|
|
const deps = { vue, '@lucide/vue': { ChevronLeft: {}, ChevronRight: {} }, './tableActions': {} }
|
|
new Function('require', 'exports', code)(id => { assert.ok(id in deps, id); return deps[id] }, exports)
|
|
const component = exports.default
|
|
component.render = () => null
|
|
const state = vue.reactive({ page: 5, total: 5542, loading: false, error: false })
|
|
const emitted = []
|
|
const renderer = vue.createRenderer({
|
|
createElement: tag => ({ tag }), createText: text => ({ text }), createComment: text => ({ text }),
|
|
insert() {}, remove() {}, setElementText() {}, setText() {}, patchProp() {},
|
|
parentNode: () => null, nextSibling: () => null,
|
|
})
|
|
const app = renderer.createApp({ render: () => vue.h(component, {
|
|
data: [], columns: [], page: state.page, pageSize: 50, total: state.total, loading: state.loading,
|
|
'onUpdate:page': value => { emitted.push(value); state.page = value },
|
|
}, state.error ? { error: () => vue.h('div', 'Request failed') } : {}) })
|
|
app.mount({})
|
|
t.after(() => app.unmount())
|
|
return { state, emitted }
|
|
}
|
|
|
|
test('server-page loading must not reset the requested page when total temporarily clears', async t => {
|
|
const { state, emitted } = paginationHarness(t)
|
|
state.loading = true; state.total = 0
|
|
await vue.nextTick()
|
|
assert.equal(state.page, 5)
|
|
assert.deepEqual(emitted, [])
|
|
state.total = 5542; state.loading = false
|
|
await vue.nextTick()
|
|
assert.equal(state.page, 5)
|
|
assert.deepEqual(emitted, [])
|
|
})
|
|
|
|
test('failed server page retains its page for explicit retry and emits no automatic fallback request', async t => {
|
|
const { state, emitted } = paginationHarness(t)
|
|
state.loading = true; state.total = 0
|
|
await vue.nextTick()
|
|
state.error = true; state.loading = false
|
|
await vue.nextTick()
|
|
assert.equal(state.page, 5)
|
|
assert.deepEqual(emitted, [])
|
|
state.error = false; state.loading = true
|
|
await vue.nextTick()
|
|
state.total = 5542; state.loading = false
|
|
await vue.nextTick()
|
|
assert.equal(state.page, 5)
|
|
assert.deepEqual(emitted, [])
|
|
})
|
|
|
|
test('settled successful totals still clamp out-of-range and empty pages', async t => {
|
|
const { state, emitted } = paginationHarness(t)
|
|
state.total = 120
|
|
await vue.nextTick()
|
|
assert.equal(state.page, 3)
|
|
state.total = 0
|
|
await vue.nextTick()
|
|
assert.equal(state.page, 1)
|
|
assert.deepEqual(emitted, [3, 1])
|
|
})
|
|
|
|
test('keeps action-only table toolbars on the left', () => {
|
|
assert.match(source, /'data-table__toolbar--actions-only': !\$slots\.toolbar/)
|
|
assert.match(source, /v-if="\$slots\.toolbar" class="data-table__toolbar-heading"/)
|
|
assert.match(source, /\.data-table__toolbar--actions-only \{ justify-content: flex-start; \}/)
|
|
})
|