Files
prop-ai-hr/mobile-uni/tests/candidate-view.test.mjs
T

150 lines
6.0 KiB
JavaScript

import assert from 'node:assert/strict';
import { readFile } from 'node:fs/promises';
import test, { after } from 'node:test';
import { fileURLToPath } from 'node:url';
import { createServer } from 'vite';
const vite = await createServer({
root: fileURLToPath(new URL('..', import.meta.url)),
configFile: false,
optimizeDeps: { noDiscovery: true },
server: { middlewareMode: true, hmr: false },
appType: 'custom'
});
after(async () => {
await vite.close();
});
const candidateView = await vite.ssrLoadModule('/src/services/candidate-view.ts');
const { buildCandidateFlow, candidateRoutes, formatCandidateFileSize, materialStatusTone } = candidateView;
const record = (overrides = {}) => ({
time: '2026-07-10 10:00:00',
candidate: '候选人0001',
position: '生活顾问',
score: 86,
result: '建议进入下一轮',
summary: '沟通完整',
...overrides
});
const material = (overrides = {}) => ({
id: 1,
ossId: 2,
fileName: '简历.pdf',
materialType: '补充资料',
fileSize: 2048,
status: '待审核',
time: '2026-07-10 10:30:00',
...overrides
});
const pageSource = async (path) => readFile(new URL(path, import.meta.url), 'utf8');
test('候选流程从面试、补资料、审核到完成只依赖真实记录', () => {
assert.deepEqual(buildCandidateFlow([], []), {
stage: 'interview',
badge: '待面试',
title: '完成结构化面试',
desc: '按岗位题目完成回答,提交后生成正式面试记录。',
progress: 0,
progressText: '0/2',
notice: '待完成结构化面试',
cta: '开始面试',
route: candidateRoutes.interview
});
assert.equal(buildCandidateFlow([record()], []).stage, 'materials');
assert.equal(buildCandidateFlow([record()], []).route, candidateRoutes.materials);
assert.equal(buildCandidateFlow([record()], [material({ status: '已驳回' })]).badge, '资料被驳回');
assert.equal(buildCandidateFlow([record()], [material()]).stage, 'review');
assert.equal(buildCandidateFlow([record()], [material()]).route, candidateRoutes.progress);
assert.equal(buildCandidateFlow([record()], [material({ status: '已通过' })]).stage, 'complete');
assert.equal(buildCandidateFlow([record()], [material({ status: '已通过' })]).progress, 100);
});
test('资料展示格式保持三态且文件大小可读', () => {
assert.equal(materialStatusTone('已通过'), 'passed');
assert.equal(materialStatusTone('已驳回'), 'rejected');
assert.equal(materialStatusTone('待审核'), 'pending');
assert.equal(formatCandidateFileSize(0), '0KB');
assert.equal(formatCandidateFileSize(2048), '2KB');
assert.equal(formatCandidateFileSize(1572864), '1.5MB');
});
test('候选首页只做状态总览和独立页面分流', async () => {
const source = await pageSource('../src/pages/candidate/index/index.vue');
assert.match(source, /getCandidateInterviewRecords/);
assert.match(source, /getCandidateMaterials/);
Object.values(candidateRoutes).forEach((route) => assert.match(source, new RegExp(route.replaceAll('/', '\\/'))));
assert.doesNotMatch(source, /startCandidateInterview/);
assert.doesNotMatch(source, /uploadCandidateMaterial/);
assert.doesNotMatch(source, /searchKnowledge/);
assert.doesNotMatch(source, /interviewQuestions/);
});
test('候选端刷新失败不保留上一轮真实记录', async () => {
const [home, materials, progress] = await Promise.all([
pageSource('../src/pages/candidate/index/index.vue'),
pageSource('../src/pages/candidate/materials/index.vue'),
pageSource('../src/pages/candidate/progress/index.vue')
]);
assert.match(home, /catch \(error\) \{\n\s*clearData\(\);/);
assert.match(materials, /catch \(error\) \{\n\s*clearData\(\);/);
assert.match(progress, /catch \(error\) \{\n\s*clearData\(\);/);
});
test('面试、资料、进度和预习页各自只承载一类真实任务', async () => {
const [interview, materials, progress, study] = await Promise.all([
pageSource('../src/pages/candidate/interview/index.vue'),
pageSource('../src/pages/candidate/materials/index.vue'),
pageSource('../src/pages/candidate/progress/index.vue'),
pageSource('../src/pages/candidate/study/index.vue')
]);
assert.match(interview, /startCandidateInterview/);
assert.match(interview, /saveInterviewAnswer/);
assert.match(interview, /finishCandidateInterview/);
assert.doesNotMatch(interview, /uploadCandidateMaterial|searchKnowledge/);
assert.match(materials, /chooseCandidateFile/);
assert.match(materials, /uploadCandidateMaterial/);
assert.doesNotMatch(materials, /startCandidateInterview|searchKnowledge/);
assert.match(progress, /getCandidateInterviewRecords/);
assert.match(progress, /getCandidateMaterials/);
assert.doesNotMatch(progress, /startCandidateInterview|uploadCandidateMaterial|searchKnowledge/);
assert.match(study, /searchKnowledge/);
assert.doesNotMatch(study, /startCandidateInterview|uploadCandidateMaterial/);
});
test('五个候选页面登录都使用 redirectTo 并保留当前任务页', async () => {
const sources = await Promise.all([
pageSource('../src/pages/candidate/index/index.vue'),
pageSource('../src/pages/candidate/interview/index.vue'),
pageSource('../src/pages/candidate/materials/index.vue'),
pageSource('../src/pages/candidate/progress/index.vue'),
pageSource('../src/pages/candidate/study/index.vue')
]);
sources.forEach((source) => {
const goLogin = source.match(/const goLogin = \(\) => \{\n[\s\S]*?\n\};/)?.[0] || '';
assert.match(goLogin, /rememberLoginRedirect\(currentPath\)/);
assert.match(goLogin, /uni\.redirectTo\(\{ url: '\/pages\/auth\/login\/index' \}\)/);
assert.doesNotMatch(goLogin, /uni\.navigateTo\(/);
});
});
test('候选子路由已注册为真实页面', async () => {
const pages = await pageSource('../src/pages.json');
assert.match(pages, /pages\/candidate\/interview\/index/);
assert.match(pages, /pages\/candidate\/materials\/index/);
assert.match(pages, /pages\/candidate\/progress\/index/);
assert.match(pages, /pages\/candidate\/study\/index/);
});