forked from hangshuo652/aurak
1224a74e63
- Grader: separate followup hint from scoring feedback - Interviewer: use followup hint directly without prefix/suffix - Restored standard and choice question presentation paths
104 lines
4.0 KiB
TypeScript
104 lines
4.0 KiB
TypeScript
import { interviewerNode } from './interviewer.node';
|
|
import { AIMessage } from '@langchain/core/messages';
|
|
|
|
function baseState(overrides: any = {}) {
|
|
return {
|
|
questions: [{ id: 'q1', questionText: 'What is JS?', keyPoints: ['point1'], dimension: 'llm' }],
|
|
currentQuestionIndex: 0,
|
|
shouldFollowUp: false,
|
|
language: 'en',
|
|
...overrides,
|
|
} as any;
|
|
}
|
|
|
|
describe('interviewerNode', () => {
|
|
describe('empty questions handling', () => {
|
|
it('should return apology message when questions array is empty', async () => {
|
|
const state = baseState({ questions: [] });
|
|
const result = await interviewerNode(state);
|
|
expect(result.messages).toBeDefined();
|
|
expect((result.messages as any)[0].content).toContain("sorry");
|
|
});
|
|
|
|
it('should return apology message when questions is undefined', async () => {
|
|
const state = baseState({ questions: undefined });
|
|
const result = await interviewerNode(state);
|
|
expect(result.messages).toBeDefined();
|
|
expect((result.messages as any)[0].content).toContain("sorry");
|
|
});
|
|
|
|
it('should return Chinese apology when language is zh', async () => {
|
|
const state = baseState({ questions: [], language: 'zh' });
|
|
const result = await interviewerNode(state);
|
|
expect((result.messages as any)[0].content).toContain('抱歉');
|
|
});
|
|
|
|
it('should return Japanese apology when language is ja', async () => {
|
|
const state = baseState({ questions: [], language: 'ja' });
|
|
const result = await interviewerNode(state);
|
|
expect((result.messages as any)[0].content).toContain('申し訳');
|
|
});
|
|
});
|
|
|
|
describe('question index range checks', () => {
|
|
it('should return shouldFollowUp: false when currentQuestionIndex >= questions.length', async () => {
|
|
const state = baseState({ currentQuestionIndex: 5, questions: [{ id: 'q1', questionText: 'Q', keyPoints: ['k'], dimension: 'llm' }] });
|
|
const result = await interviewerNode(state);
|
|
expect(result.shouldFollowUp).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('standard question presentation', () => {
|
|
it('should present the current question', async () => {
|
|
const result = await interviewerNode(baseState());
|
|
expect(result.messages).toBeDefined();
|
|
const msg = (result.messages as any)[0].content as string;
|
|
expect(msg).toContain('Question 1');
|
|
expect(msg).toContain('What is JS?');
|
|
});
|
|
|
|
it('should include answer instruction', async () => {
|
|
const result = await interviewerNode(baseState());
|
|
const msg = (result.messages as any)[0].content as string;
|
|
expect(msg).toContain('answer');
|
|
});
|
|
|
|
it('should use Chinese labels when language is zh', async () => {
|
|
const state = baseState({ language: 'zh' });
|
|
const result = await interviewerNode(state);
|
|
const msg = (result.messages as any)[0].content as string;
|
|
expect(msg).toContain('问题');
|
|
expect(msg).toContain('回答');
|
|
});
|
|
|
|
it('should use Japanese labels when language is ja', async () => {
|
|
const state = baseState({ language: 'ja' });
|
|
const result = await interviewerNode(state);
|
|
const msg = (result.messages as any)[0].content as string;
|
|
expect(msg).toContain('質問');
|
|
expect(msg).toContain('回答');
|
|
});
|
|
});
|
|
|
|
describe('follow-up mode', () => {
|
|
it('should use last feedbackHistory message content as follow-up prompt', async () => {
|
|
const state = baseState({
|
|
shouldFollowUp: true,
|
|
feedbackHistory: [new AIMessage('You need more details')],
|
|
});
|
|
const result = await interviewerNode(state);
|
|
const msg = (result.messages as any)[0].content as string;
|
|
expect(msg).toContain('You need more details');
|
|
});
|
|
|
|
it('should reset shouldFollowUp to false after processing', async () => {
|
|
const state = baseState({
|
|
shouldFollowUp: true,
|
|
feedbackHistory: [new AIMessage('Feedback: More info needed')],
|
|
});
|
|
const result = await interviewerNode(state);
|
|
expect(result.shouldFollowUp).toBe(false);
|
|
});
|
|
});
|
|
});
|