ec-nest/src/catalog/catalog.service.spec.ts
liuyun 945fe5daa3 feat(c0): catalog 目录模块(属地加载 + 机构项目库)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-10-14 13:08:47 +08:00

113 lines
4.6 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { describe, expect, it, vi } from 'vitest';
import { CatalogService } from './catalog.service.js';
import type { PrismaService } from '../prisma/prisma.service.js';
import { ErrorCodes } from '../common/error-codes.js';
import { runWithRequestContext } from '../common/context/request-context.js';
import type { RequestContext } from '../common/context/request-context.js';
import type { ConfigSvcOrgDto } from './dto.js';
const ctx: RequestContext = {
tenantCode: 'T001',
userId: 'u1',
username: 'admin',
super: false,
dataScope: 'self',
orgCode: null,
orgCodes: [],
};
function makeService(overrides: {
svcLocalFindMany?: ReturnType<typeof vi.fn>;
svcNationalFindMany?: ReturnType<typeof vi.fn>;
svcOrgFindMany?: ReturnType<typeof vi.fn>;
svcOrgFindFirst?: ReturnType<typeof vi.fn>;
svcOrgUpdate?: ReturnType<typeof vi.fn>;
} = {}) {
const svcLocalFindMany = overrides.svcLocalFindMany ?? vi.fn().mockResolvedValue([{ id: 'l1', locCode: '530100', localItemName: '头面清洁' }]);
const svcNationalFindMany = overrides.svcNationalFindMany ?? vi.fn().mockResolvedValue([{ id: 'n1', natName: '擦浴' }]);
const svcOrgFindMany = overrides.svcOrgFindMany ?? vi.fn().mockResolvedValue([{ id: 'o1', tenantCode: 'T001', isEnabled: true }]);
const svcOrgFindFirst = overrides.svcOrgFindFirst ?? vi.fn().mockResolvedValue({ id: 'o1', tenantCode: 'T001' });
const svcOrgUpdate = overrides.svcOrgUpdate ?? vi.fn().mockResolvedValue({ id: 'o1', isEnabled: false });
const prisma = {
client: {
svcLocal: { findMany: svcLocalFindMany },
svcNational: { findMany: svcNationalFindMany },
svcOrg: { findMany: svcOrgFindMany, findFirst: svcOrgFindFirst, update: svcOrgUpdate },
},
};
return {
service: new CatalogService(prisma as unknown as PrismaService),
svcLocalFindMany,
svcNationalFindMany,
svcOrgFindMany,
svcOrgFindFirst,
svcOrgUpdate,
};
}
describe('CatalogService', () => {
it('listLocal 按 locCode 读全局 SvcLocal(不注入 tenantCode)', async () => {
const { service, svcLocalFindMany, svcNationalFindMany } = makeService();
const result = await service.listLocal('530100');
expect(svcLocalFindMany).toHaveBeenCalledWith({ where: { locCode: '530100' } });
expect(svcNationalFindMany).not.toHaveBeenCalled();
expect(result).toEqual([{ id: 'l1', locCode: '530100', localItemName: '头面清洁' }]);
});
it('listLocal 无本地目录时回退 SvcNational', async () => {
const svcLocalFindMany = vi.fn().mockResolvedValue([]);
const svcNationalFindMany = vi.fn().mockResolvedValue([{ id: 'n1', natName: '擦浴' }]);
const { service } = makeService({ svcLocalFindMany, svcNationalFindMany });
const result = await service.listLocal('530200');
expect(svcNationalFindMany).toHaveBeenCalled();
expect(result).toEqual([{ id: 'n1', natName: '擦浴' }]);
});
it('listOrg 读当前租户 SvcOrg', async () => {
const { service, svcOrgFindMany } = makeService();
const result = await runWithRequestContext(ctx, () => service.listOrg());
expect(svcOrgFindMany).toHaveBeenCalledWith({ where: { tenantCode: 'T001' } });
expect(result).toEqual([{ id: 'o1', tenantCode: 'T001', isEnabled: true }]);
});
it('config 只允许改 isEnabled/price,写操作按当前租户定位', async () => {
const { service, svcOrgFindFirst, svcOrgUpdate } = makeService();
await runWithRequestContext(ctx, () =>
service.config({ id: 'o1', isEnabled: false, price: '50' } as ConfigSvcOrgDto),
);
expect(svcOrgFindFirst).toHaveBeenCalledWith({ where: { id: 'o1', tenantCode: 'T001' } });
expect(svcOrgUpdate).toHaveBeenCalledWith({ where: { id: 'o1' }, data: { isEnabled: false, price: '50' } });
});
it.each([
['srcId', 'n1'],
['srcType', 'national'],
])('config 夹带 %s 抛 SVC_LOC_IMMUTABLE', async (key, value) => {
const { service, svcOrgFindFirst, svcOrgUpdate } = makeService();
await expect(
runWithRequestContext(ctx, () => service.config({ id: 'o1', [key]: value } as ConfigSvcOrgDto)),
).rejects.toMatchObject({ response: { code: ErrorCodes.SVC_LOC_IMMUTABLE } });
expect(svcOrgFindFirst).not.toHaveBeenCalled();
expect(svcOrgUpdate).not.toHaveBeenCalled();
});
it('config 目标不存在抛 SVC_ORG_NOT_FOUND', async () => {
const svcOrgFindFirst = vi.fn().mockResolvedValue(null);
const { service } = makeService({ svcOrgFindFirst });
await expect(
runWithRequestContext(ctx, () => service.config({ id: 'missing', isEnabled: true } as ConfigSvcOrgDto)),
).rejects.toMatchObject({ response: { code: ErrorCodes.SVC_ORG_NOT_FOUND } });
});
});