'use strict'; const assert = require('node:assert/strict'); const path = require('node:path'); const { spawnSync } = require('node:child_process'); const test = require('node:test'); let fixture; function rendered() { if (!fixture) { const run = spawnSync(process.env.PHP_BINARY || 'php', [path.join(__dirname, 'ticket-native-render-harness.php')], { encoding: 'utf8' }); assert.equal(run.status, 0, run.stderr || run.stdout); fixture = JSON.parse(run.stdout); } return fixture; } test('list view links rows to the workspace and offers creation only as a dialog', () => { const { list, initial } = rendered(); assert.equal((list.match(/ { const { open, closed, detail_list_queries: listQueries } = rendered(); assert.equal(listQueries, 0, 'workspace must not query the list'); assert.match(open, /

[^]*Question <svg onload=alert\(1\)><\/h1>/); assert.match(open, /href="[^"]*page=jio_tickets&status=pending&s=not\+in\+list&paged=3"[^>]*>[^]*返回工单列表/); assert.match(open, /data-jio-ticket-detail="21"/); for (const action of ['reply', 'status', 'note']) assert.ok(open.includes(`data-jio-ticket-form="${action}"`)); assert.match(open, /action="https:\/\/example.test\/wp-json\/jio\/v1\/admin\/tickets\/21\/notes"/); assert.match(open, /data-jio-ticket-close-confirm/); assert.match(open, /value="closed" data-closed="1"/); assert.match(open, /
工单号<\/dt>
TK-00021<\/dd>/); assert.match(open, /data-jio-ticket-feedback/); assert.match(closed, /data-jio-ticket-detail="99"/); assert.match(closed, /jio-ticket-detail__closed/); assert.match(closed, /data-jio-ticket-form="note"/); assert.doesNotMatch(closed, /data-jio-ticket-form="(?:reply|status)"/); // 回复框是会话卡片的底部,不是独立卡片;工作区唯一的弹窗是内部备注。 const conversation = open.match(/
/)?.[0] || ''; assert.match(conversation, /jio-ticket-conversation__scroll[^]*data-jio-ticket-form="reply"/); assert.match(conversation, /data-jio-ticket-send-shortcut/); assert.match(conversation, /