Files
novalon-website/config/test/jest.setup.js
T
张翔 10404dbb36 chore: sync marketing pages, CMS extensions, tests and project docs
同步工作区剩余变更,主要包括:
- 营销页面组件与布局持续优化(about/news/services/solutions/team 等)
- 详情页四层叙事组件、布局组件、UI 组件调整
- CMS 数据模型、API 路由、权限、工作流、站内通知、媒体管理扩展
- 新增/补充单元测试与 E2E 测试(cms-workflow.spec.ts 等)
- ESLint 9 迁移、jest/tsconfig 配置更新、依赖调整
- 新增 ADR、CMS 评估文档、Release Review / Acceptance 报告
- 移除水墨装饰组件与大体积未使用字体文件
2026-07-25 08:04:01 +08:00

204 lines
5.3 KiB
JavaScript

require('@testing-library/jest-dom');
const { TextEncoder, TextDecoder } = require('util');
global.TextEncoder = TextEncoder;
global.TextDecoder = TextDecoder;
jest.mock('nanoid', () => ({
nanoid: jest.fn(() => 'test-id-123'),
}));
jest.mock('@/generated/prisma/client', () => ({
PrismaClient: jest.fn().mockImplementation(() => ({
contentItem: {
findMany: jest.fn().mockResolvedValue([]),
findFirst: jest.fn().mockResolvedValue(null),
findUnique: jest.fn().mockResolvedValue(null),
},
contentModel: {
findMany: jest.fn().mockResolvedValue([]),
},
contentZone: {
findMany: jest.fn().mockResolvedValue([]),
findUnique: jest.fn().mockResolvedValue(null),
},
})),
}));
jest.mock('@/lib/cms/data-server', () => ({
getPublishedItems: jest.fn().mockResolvedValue([]),
getPublishedItemBySlug: jest.fn().mockResolvedValue(null),
getItemById: jest.fn().mockResolvedValue(null),
getPageZones: jest.fn().mockResolvedValue([]),
getZone: jest.fn().mockResolvedValue(null),
getContentModels: jest.fn().mockResolvedValue([]),
getCases: jest.fn().mockResolvedValue([]),
getNews: jest.fn().mockResolvedValue([]),
getServices: jest.fn().mockResolvedValue([]),
getProducts: jest.fn().mockResolvedValue([]),
getSolutions: jest.fn().mockResolvedValue([]),
getStats: jest.fn().mockResolvedValue([]),
getHeroBanners: jest.fn().mockResolvedValue([]),
getCaseBySlug: jest.fn().mockResolvedValue(null),
getNewsBySlug: jest.fn().mockResolvedValue(null),
getServiceBySlug: jest.fn().mockResolvedValue(null),
getProductBySlug: jest.fn().mockResolvedValue(null),
getSolutionBySlug: jest.fn().mockResolvedValue(null),
getHomePageZones: jest.fn().mockResolvedValue([]),
getAllPublishedSlugs: jest.fn().mockResolvedValue([]),
}));
jest.mock('next/dynamic', () => ({
__esModule: true,
default: (_importFn, _options) => {
const MockComponent = (_props) => null;
MockComponent.displayName = 'DynamicComponent';
MockComponent.preload = () => Promise.resolve();
return MockComponent;
},
}));
jest.mock('next/server', () => ({
NextRequest: class MockNextRequest {
constructor(input, init = {}) {
this.url = typeof input === 'string' ? input : input.url;
this.method = init.method || 'GET';
this.headers = new Headers(init.headers);
this.body = init.body;
}
async json() {
return typeof this.body === 'string' ? JSON.parse(this.body) : this.body;
}
},
NextResponse: {
json: (body, init = {}) => ({
status: init.status || 200,
json: async () => body,
}),
},
}));
global.console = {
...console,
error: jest.fn(),
warn: jest.fn(),
log: jest.fn(),
};
class MockIntersectionObserver {
constructor(callback, options = {}) {
this.callback = callback;
this.options = options;
this.elements = new Set();
this.observationEntries = [];
}
observe(element) {
this.elements.add(element);
const entry = {
isIntersecting: true,
target: element,
boundingClientRect: element.getBoundingClientRect ? element.getBoundingClientRect() : {},
intersectionRatio: 1,
intersectionRect: {},
rootBounds: {},
time: Date.now(),
};
this.observationEntries.push(entry);
this.callback(this.observationEntries, this);
}
unobserve(element) {
this.elements.delete(element);
this.observationEntries = this.observationEntries.filter(
entry => entry.target !== element
);
}
disconnect() {
this.elements.clear();
this.observationEntries = [];
}
takeRecords() {
return this.observationEntries;
}
}
global.IntersectionObserver = MockIntersectionObserver;
global.IntersectionObserverEntry = class IntersectionObserverEntry {
constructor() {
this.isIntersecting = true;
this.target = {};
this.boundingClientRect = {};
this.intersectionRatio = 1;
this.intersectionRect = {};
this.rootBounds = {};
this.time = Date.now();
}
};
Object.defineProperty(window, 'matchMedia', {
writable: true,
value: jest.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn(),
addEventListener: jest.fn(),
removeEventListener: jest.fn(),
dispatchEvent: jest.fn(),
})),
});
global.Request = class Request {
constructor(input, init = {}) {
this.url = typeof input === 'string' ? input : input.url;
this.method = init.method || 'GET';
this.headers = new Headers(init.headers);
this.body = init.body;
}
async json() {
return typeof this.body === 'string' ? JSON.parse(this.body) : this.body;
}
};
global.Headers = class Headers {
constructor(init = {}) {
this.headers = {};
if (init) {
Object.entries(init).forEach(([key, value]) => {
this.headers[key.toLowerCase()] = value;
});
}
}
get(name) {
return this.headers[name.toLowerCase()];
}
set(name, value) {
this.headers[name.toLowerCase()] = value;
}
};
global.Response = class Response {
constructor(body, init = {}) {
this.body = body;
this.status = init.status || 200;
this.statusText = init.statusText || 'OK';
this.headers = new Headers(init.headers);
}
async json() {
return typeof this.body === 'string' ? JSON.parse(this.body) : this.body;
}
async text() {
return String(this.body);
}
};