import assert from 'node:assert/strict' import { readFileSync } from 'node:fs' import test from 'node:test' import { parse } from '@vue/compiler-sfc' import ts from 'typescript' const source = parse( readFileSync(new URL('../src/views/m/crm/product/categories.vue', import.meta.url), 'utf8') ).descriptor.scriptSetup!.content const ast = ts.createSourceFile('category.ts', source, ts.ScriptTarget.Latest, true) function harness(fetchCategoryTree: (...args: any[]) => Promise) { const names = ['loadTree', 'getCategoryTreeSelect', 'openAdd', 'resetForm'] const code = ast.statements .filter((n) => ts.isFunctionDeclaration(n) && names.includes(n.name!.text)) .map((n) => n.getText(ast)) .join('\n') const state: Record = { fetchCategoryTree, keyword: { value: ' 酸 ' }, loading: { value: false }, loadError: { value: '' }, tree: { value: [] }, expandedIds: { value: {} }, collectExpandIds: () => ({}), categoryTreeOptions: { value: [] }, actionOpen: { value: false }, formOpen: { value: false }, formTitle: { value: '' }, formData: {}, nameError: { value: '' }, showFailToast: (message: string) => state.toasts.push(message), toasts: [] } const handlers = new Function( ...Object.keys(state), 'let loadSeq = 0;\n' + ts.transpile(code) + ';return {loadTree,openAdd}' )(...Object.values(state)) return { ...state, ...handlers } } test('category search trims query, reports errors, and retries successfully', async () => { let fail = true const calls: any[] = [] const h = harness(async (params) => { calls.push(params) if (fail) throw new Error('网络中断') return { data: [{ id: 'a', categoryName: '酸' }] } }) await h.loadTree() assert.equal(h.loadError.value, '网络中断') assert.equal(h.loading.value, false) fail = false await h.loadTree() assert.deepEqual(calls, [{ categoryName: '酸' }, { categoryName: '酸' }]) assert.equal(h.loadError.value, '') assert.equal(h.tree.value[0].id, 'a') }) test('an earlier category response cannot replace the latest search', async () => { const resolve: ((value: any) => void)[] = [] const h = harness(() => new Promise((r) => resolve.push(r))) const first = h.loadTree() h.keyword.value = '碱' const second = h.loadTree() resolve[1]({ data: [{ id: 'new' }] }) await second resolve[0]({ data: [{ id: 'old' }] }) await first assert.equal(h.tree.value[0].id, 'new') }) test('failed parent-option loading keeps the category form closed and explains retry', async () => { const h = harness(async () => { throw new Error('分类加载失败') }) await h.openAdd() assert.equal(h.formOpen.value, false) assert.deepEqual(h.toasts, ['分类加载失败']) })