import { describe, expect, it } from 'vitest';
|
|
import {
|
AUDIT_BIZ_SIGN_HEADER,
|
AUDIT_DISPLAY_FIELDS_HEADER,
|
buildAuditDisplayFields,
|
buildGlobalAuditRequestHeaders,
|
createAuditRequestOnlineUtils,
|
createSignedAuditRequestOnlineUtils,
|
registerPendingAuditDisplayFields,
|
} from './auditDisplay';
|
|
describe('buildAuditDisplayFields', () => {
|
it('collects enabled fields in form order through layout containers', () => {
|
const fields = [
|
{ __vModel__: 'code', __config__: { biz_log_enabled: true, jnpfKey: 'input' } },
|
{
|
__config__: {
|
jnpfKey: 'row',
|
children: [
|
{ __vModel__: 'disabled', __config__: { biz_log_enabled: false, jnpfKey: 'input' } },
|
{ __vModel__: 'status', __config__: { biz_log_enabled: true, jnpfKey: 'select' }, options: [{ label: '已批准', value: 1 }] },
|
],
|
},
|
},
|
];
|
|
expect(buildAuditDisplayFields(fields, { code: 'LIMS-001', disabled: 'x', status: 1 })).toEqual([
|
{ field: 'code', displayValue: 'LIMS-001' },
|
{ field: 'status', displayValue: '已批准' },
|
]);
|
});
|
|
it('uses the selected reference row instead of its stored id', () => {
|
const fields = [
|
{
|
__vModel__: 'product_id',
|
__config__: { biz_log_enabled: true, jnpfKey: 'popupSelect' },
|
relationField: 'product_name',
|
},
|
];
|
|
expect(buildAuditDisplayFields(fields, { product_id: '101' }, { product_id: { option: { product_name: '阿莫西林胶囊' }, value: '101' } })).toEqual([
|
{ field: 'product_id', displayValue: '阿莫西林胶囊' },
|
]);
|
});
|
|
it('does not reuse a stale selected label after a script changes the stored value', () => {
|
const fields = [
|
{
|
__vModel__: 'product_id',
|
__config__: { biz_log_enabled: true, jnpfKey: 'popupSelect' },
|
relationField: 'product_name',
|
},
|
];
|
|
expect(buildAuditDisplayFields(fields, { product_id: '102' }, { product_id: { option: { product_name: '旧产品' }, value: '101' } })).toEqual([]);
|
});
|
|
it('does not send unresolved reference ids or signature fields', () => {
|
const fields = [
|
{ __vModel__: 'user_id', __config__: { biz_log_enabled: true, jnpfKey: 'userSelect' } },
|
{ __vModel__: 'biz_sign', __config__: { biz_log_enabled: true, jnpfKey: 'signature' } },
|
];
|
|
expect(buildAuditDisplayFields(fields, { user_id: '1001', biz_sign: 'secret' })).toEqual([]);
|
});
|
|
it('keeps child-table values out of the main record title payload', () => {
|
const fields = [
|
{
|
__vModel__: 'items',
|
__config__: {
|
biz_log_enabled: false,
|
jnpfKey: 'table',
|
children: [{ __vModel__: 'name', __config__: { biz_log_enabled: true, isSubTable: true, jnpfKey: 'input' } }],
|
},
|
},
|
];
|
|
expect(buildAuditDisplayFields(fields, { items: [{ name: '子项' }] })).toEqual([]);
|
});
|
});
|
|
describe('createAuditRequestOnlineUtils', () => {
|
it('injects the latest display fields into same-origin LIMS write requests', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(base, () => [{ field: 'product', displayValue: '阿莫西林胶囊' }]);
|
|
await scoped.request('/api/lims/sample/receive', 'post', { id: '1' }, { Existing: 'yes' });
|
|
expect(calls).toHaveLength(1);
|
expect(calls[0][3].Existing).toBe('yes');
|
const decoded = new TextDecoder().decode(Uint8Array.from(atob(calls[0][3][AUDIT_DISPLAY_FIELDS_HEADER]), (char) => char.codePointAt(0)!));
|
expect(JSON.parse(decoded)).toEqual([{ field: 'product', displayValue: '阿莫西林胶囊' }]);
|
});
|
|
it('injects the current biz_sign used by the custom request', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(
|
base,
|
() => [],
|
() => '839875756384423365',
|
);
|
|
await scoped.request('/api/lims/sample/receive', 'post', { id: '1' });
|
|
expect(calls[0][3][AUDIT_BIZ_SIGN_HEADER]).toBe('839875756384423365');
|
});
|
|
it('falls back to biz_sign in the custom request payload', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(base, () => []);
|
|
await scoped.request('/api/lims/sample/receive', 'post', { biz_sign: '839875756384423365' });
|
|
expect(calls[0][3][AUDIT_BIZ_SIGN_HEADER]).toBe('839875756384423365');
|
});
|
|
it('reuses one 32-character UUID for multiple unsigned requests in the same custom event', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(base, () => []);
|
|
await scoped.request('/api/lims/sample/receive', 'post', { id: '1' });
|
await scoped.request('/api/extend/lims/biz/sample/confirm', 'put', { id: '1' });
|
|
const first = calls[0][3][AUDIT_BIZ_SIGN_HEADER];
|
expect(first).toMatch(/^[0-9a-f]{32}$/);
|
expect(calls[1][3][AUDIT_BIZ_SIGN_HEADER]).toBe(first);
|
});
|
|
it('prefers an explicit correlation header and reuses it for later requests in the event', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(base, () => []);
|
|
await scoped.request('/api/lims/sample/receive', 'post', { id: '1' }, { 'x-audit-biz-sign': 'explicit-sign' });
|
await scoped.request('/api/lims/sample/confirm', 'post', { id: '1' });
|
|
expect(calls[0][3][AUDIT_BIZ_SIGN_HEADER]).toBe('explicit-sign');
|
expect(calls[1][3][AUDIT_BIZ_SIGN_HEADER]).toBe('explicit-sign');
|
});
|
|
it('does not add the unsigned-event UUID to signature verification requests', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(base, () => []);
|
|
await scoped.request('/api/lims/sign/verify', 'post', { password: 'secret' });
|
await scoped.request('/api/lims/sign/init-all', 'post', {});
|
|
expect(calls[0][3]).toEqual({});
|
expect(calls[1][3]).toEqual({});
|
});
|
|
it.each([
|
['/api/lims/sample/1', 'get'],
|
['/api/system/User', 'post'],
|
['https://external.example/api/lims/sample', 'post'],
|
])('does not inject into %s %s', async (url, method) => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createAuditRequestOnlineUtils(base, () => [{ field: 'code', displayValue: 'LIMS-001' }]);
|
|
await scoped.request(url, method, {}, { Existing: 'yes' });
|
|
expect(calls[0][3]).toEqual({ Existing: 'yes' });
|
});
|
});
|
|
describe('createSignedAuditRequestOnlineUtils', () => {
|
it('injects biz_sign into same-origin data interface write requests', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createSignedAuditRequestOnlineUtils(base, () => '839875756384423365');
|
|
await scoped.request('/api/system/DataInterface/847040671909949317/Actions/Preview', 'post', { tenantId: '' });
|
|
expect(calls[0][3][AUDIT_BIZ_SIGN_HEADER]).toBe('839875756384423365');
|
});
|
|
it('does not expose biz_sign to external requests', async () => {
|
const calls: any[] = [];
|
const base = {
|
request: (...args: any[]) => {
|
calls.push(args);
|
return Promise.resolve();
|
},
|
};
|
const scoped = createSignedAuditRequestOnlineUtils(base, () => '839875756384423365');
|
|
await scoped.request('https://example.com/api/update', 'post', {});
|
|
expect(calls[0][3]).toEqual({});
|
});
|
});
|
|
describe('buildGlobalAuditRequestHeaders', () => {
|
it('adds pending modal fields and biz sign to the outer onlineUtils request', () => {
|
registerPendingAuditDisplayFields([{ field: 'product', displayValue: '阿莫西林胶囊' }]);
|
|
const headers = buildGlobalAuditRequestHeaders('/api/extend/lims/biz/jiance-task/assign', 'post', {
|
biz_sign: '839875756384423365',
|
data: [{ id: '1' }],
|
});
|
|
expect(headers[AUDIT_BIZ_SIGN_HEADER]).toBe('839875756384423365');
|
const decoded = new TextDecoder().decode(Uint8Array.from(atob(headers[AUDIT_DISPLAY_FIELDS_HEADER]), (char) => char.codePointAt(0)!));
|
expect(JSON.parse(decoded)).toEqual([{ field: 'product', displayValue: '阿莫西林胶囊' }]);
|
});
|
|
it('does not consume pending modal fields on the signature verification request', () => {
|
registerPendingAuditDisplayFields([{ field: 'code', displayValue: 'TASK-001' }]);
|
expect(buildGlobalAuditRequestHeaders('/api/lims/sign/verify', 'post', { password: 'secret' })).toEqual({});
|
|
const headers = buildGlobalAuditRequestHeaders('/api/lims/task/assign', 'post', { biz_sign: 'sign-1' });
|
expect(headers[AUDIT_BIZ_SIGN_HEADER]).toBe('sign-1');
|
expect(headers[AUDIT_DISPLAY_FIELDS_HEADER]).toBeTruthy();
|
});
|
|
it('reuses the pending modal event UUID for multiple unsigned requests', () => {
|
registerPendingAuditDisplayFields([]);
|
|
const first = buildGlobalAuditRequestHeaders('/api/lims/task/prepare', 'post', { id: '1' });
|
const second = buildGlobalAuditRequestHeaders('/api/extend/lims/biz/task/submit', 'post', { id: '1' });
|
|
expect(first[AUDIT_BIZ_SIGN_HEADER]).toMatch(/^[0-9a-f]{32}$/);
|
expect(second[AUDIT_BIZ_SIGN_HEADER]).toBe(first[AUDIT_BIZ_SIGN_HEADER]);
|
});
|
|
it('keeps a real biz_sign for later unsigned requests in the pending modal event', () => {
|
registerPendingAuditDisplayFields([]);
|
|
const signed = buildGlobalAuditRequestHeaders('/api/lims/task/prepare', 'post', { biz_sign: 'real-sign' });
|
const later = buildGlobalAuditRequestHeaders('/api/lims/task/submit', 'post', { id: '1' });
|
|
expect(signed[AUDIT_BIZ_SIGN_HEADER]).toBe('real-sign');
|
expect(later[AUDIT_BIZ_SIGN_HEADER]).toBe('real-sign');
|
});
|
});
|