修复采购审核竞态并整理管理页面展示
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
import { nextTick } from 'vue'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { printLoadingList } from './printLoadingList'
|
||||
|
||||
afterEach(() => { vi.restoreAllMocks(); document.body.replaceChildren() })
|
||||
|
||||
function manifest() {
|
||||
document.body.innerHTML = `<aside>平台导航</aside><nav>后台页签</nav><section id="manifest" aria-label="装柜清单 · LIST-TEST">
|
||||
<header><button>返回货柜概览</button><button>打印装柜清单</button></header>
|
||||
<section class="detail-summary" data-loading-list-print-summary><div><span>柜次号</span><strong>CB-TEST</strong></div><div><span>集装箱号</span><strong>CONTAINER-TEST</strong></div></section>
|
||||
<div data-loading-list-print-items><button>字段设置</button><div style="width:3000px;overflow:hidden"><table>
|
||||
<thead><tr><th>入仓码</th><th>SKU</th><th>备注</th></tr></thead>
|
||||
<tbody><tr><td style="width:200px;white-space:nowrap">IN-FIRST</td><td>SKU & <盒></td><td>第一行备注</td></tr>
|
||||
<tr><td>IN-LAST</td><td>SKU-LAST</td><td>最后一列完整备注</td></tr></tbody>
|
||||
</table></div></div><section>操作历史:创建计划、调整货物</section></section>`
|
||||
return document.getElementById('manifest')!
|
||||
}
|
||||
|
||||
function interceptPrint(onPrint: (frame: HTMLIFrameElement) => void) {
|
||||
let frame: HTMLIFrameElement | undefined
|
||||
const append = document.body.append.bind(document.body)
|
||||
vi.spyOn(document.body, 'append').mockImplementation((...nodes) => {
|
||||
append(...nodes)
|
||||
for (const node of nodes) {
|
||||
if (!(node instanceof HTMLIFrameElement)) continue
|
||||
frame = node
|
||||
vi.spyOn(node.contentWindow!, 'focus').mockImplementation(() => {})
|
||||
vi.spyOn(node.contentWindow!, 'print').mockImplementation(() => onPrint(node))
|
||||
}
|
||||
})
|
||||
return async () => {
|
||||
await nextTick()
|
||||
if (!frame) throw new Error('Print frame was not created')
|
||||
frame.dispatchEvent(new Event('load'))
|
||||
return frame
|
||||
}
|
||||
}
|
||||
|
||||
describe('loading list printing', () => {
|
||||
it('prints the manifest summary and every cargo row and column in an isolated document', async () => {
|
||||
const root = manifest(), original = root.outerHTML
|
||||
const hostPrint = vi.spyOn(window, 'print').mockImplementation(() => {})
|
||||
let snapshot: Document | undefined
|
||||
const load = interceptPrint(frame => {
|
||||
snapshot = frame.contentDocument!
|
||||
expect(snapshot.title).toBe('装柜清单 · LIST-TEST')
|
||||
expect(snapshot.querySelector('h1')?.textContent).toBe('装柜清单 · LIST-TEST')
|
||||
expect(snapshot.body.textContent).toContain('CB-TEST')
|
||||
expect(snapshot.body.textContent).toContain('CONTAINER-TEST')
|
||||
expect(snapshot.querySelectorAll('tbody tr')).toHaveLength(2)
|
||||
expect(snapshot.querySelectorAll('thead th')).toHaveLength(3)
|
||||
expect(snapshot.body.textContent).toContain('最后一列完整备注')
|
||||
expect(snapshot.body.textContent).toContain('SKU & <盒>')
|
||||
expect(snapshot.querySelector('td')?.getAttribute('style')).toBeNull()
|
||||
expect(snapshot.body.textContent).not.toMatch(/平台导航|后台页签|返回货柜概览|字段设置|操作历史/)
|
||||
expect(snapshot.querySelectorAll('button')).toHaveLength(0)
|
||||
frame.contentWindow!.dispatchEvent(new Event('afterprint'))
|
||||
})
|
||||
const pending = printLoadingList(root)
|
||||
const frame = await load()
|
||||
await expect(pending).resolves.toBe(true)
|
||||
expect(snapshot).toBeDefined()
|
||||
expect(hostPrint).not.toHaveBeenCalled()
|
||||
expect(frame.isConnected).toBe(false)
|
||||
expect(root.outerHTML).toBe(original)
|
||||
})
|
||||
|
||||
it('keeps the print document until the dialog closes and prevents duplicate print jobs', async () => {
|
||||
const root = manifest(), print = vi.fn()
|
||||
const load = interceptPrint(print)
|
||||
const pending = printLoadingList(root)
|
||||
const frame = await load()
|
||||
expect(frame.isConnected).toBe(true)
|
||||
expect(print).toHaveBeenCalledOnce()
|
||||
await expect(printLoadingList(root)).resolves.toBe(false)
|
||||
expect(document.querySelectorAll('iframe')).toHaveLength(1)
|
||||
frame.contentWindow!.dispatchEvent(new Event('afterprint'))
|
||||
await expect(pending).resolves.toBe(true)
|
||||
expect(frame.isConnected).toBe(false)
|
||||
expect(document.querySelector('aside')?.textContent).toBe('平台导航')
|
||||
})
|
||||
|
||||
it('never falls back to printing the entire page when the manifest is missing or incomplete', async () => {
|
||||
const hostPrint = vi.spyOn(window, 'print').mockImplementation(() => {})
|
||||
await expect(printLoadingList(null)).rejects.toThrow('清单尚未加载完成')
|
||||
await expect(printLoadingList(document.createElement('section'))).rejects.toThrow('清单尚未加载完成')
|
||||
expect(hostPrint).not.toHaveBeenCalled()
|
||||
expect(document.querySelector('iframe')).toBeNull()
|
||||
})
|
||||
|
||||
it('removes the isolated document after a print failure', async () => {
|
||||
const root = manifest(), original = root.outerHTML
|
||||
const load = interceptPrint(() => { throw new Error('printer unavailable') })
|
||||
const pending = printLoadingList(root)
|
||||
const rejected = expect(pending).rejects.toThrow('printer unavailable')
|
||||
const frame = await load()
|
||||
await rejected
|
||||
expect(frame.isConnected).toBe(false)
|
||||
expect(root.outerHTML).toBe(original)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user