Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
174 changes: 90 additions & 84 deletions field-logic/src/lib/engine.test.ts
Original file line number Diff line number Diff line change
@@ -1,98 +1,104 @@
import { describe, it, expect, beforeEach } from 'vitest';
import { SurveyEngine } from './SurveyEngine';
import type { SurveyDefinition } from '../types/schema';
import { describe, it, expect, beforeEach } from "vitest";
import { SurveyEngine } from "./SurveyEngine";
import type { SurveyDefinition } from "../types/schema";

const mockSurvey: SurveyDefinition = {
meta: {
survey_id: "test_v1",
title: "Test Survey",
version: "1.0",
created_at: "2023-01-01"
meta: {
survey_id: "test_v1",
title: "Test Survey",
version: "1.0",
created_at: "2023-01-01",
},
config: {
allow_back_navigation: true,
save_progress_automatically: false,
},
nodes: [
{
id: "start",
type: "info",
content: { text: "Welcome" },
routing: { default: "q1" },
},
config: {
allow_back_navigation: true,
save_progress_automatically: false
{
id: "q1",
type: "boolean",
content: { question: "Yes or No?" },
routing: {
rules: [
{ operator: "equals", value: true, target: "q2_yes" },
{ operator: "equals", value: false, target: "q2_no" },
],
default: "end",
},
},
nodes: [
{
id: "start",
type: "info",
content: { text: "Welcome" },
routing: { default: "q1" }
},
{
id: "q1",
type: "boolean",
content: { question: "Yes or No?" },
routing: {
rules: [
{ operator: "equals", value: true, target: "q2_yes" },
{ operator: "equals", value: false, target: "q2_no" }
],
default: "end"
}
},
{
id: "q2_yes",
type: "text",
content: { question: "Why yes?" },
routing: { default: "end" }
},
{
id: "q2_no",
type: "text",
content: { question: "Why no?" },
routing: { default: "end" }
},
{
id: "end",
type: "summary",
content: { text: "Done" },
routing: { default: null }
}
]
{
id: "q2_yes",
type: "text",
content: { question: "Why yes?" },
routing: { default: "end" },
},
{
id: "q2_no",
type: "text",
content: { question: "Why no?" },
routing: { default: "end" },
},
{
id: "end",
type: "summary",
content: { text: "Done" },
routing: { default: null },
},
],
};

describe('SurveyEngine', () => {
let engine: SurveyEngine;
describe("SurveyEngine", () => {
let engine: SurveyEngine;

beforeEach(() => {
engine = new SurveyEngine(mockSurvey, "test_session");
});

beforeEach(() => {
engine = new SurveyEngine(mockSurvey, 'test_session');
});
it("should start at the first node", () => {
const node = engine.start();
expect(node.id).toBe("start");
});

it('should start at the first node', () => {
const node = engine.start();
expect(node.id).toBe('start');
});
it("should navigate to next node via default route", () => {
engine.start();
const node = engine.submitAnswer(null); // 'info' type has no answer
expect(node?.id).toBe("q1");
});

it('should navigate to next node via default route', () => {
engine.start();
const node = engine.submitAnswer(null); // 'info' type has no answer
expect(node?.id).toBe('q1');
});
it("should handle boolean branching (true)", () => {
engine.start();
engine.submitAnswer(null); // move to q1
const node = engine.submitAnswer(true); // Answer true to q1
expect(node?.id).toBe("q2_yes");
});

it('should handle boolean branching (true)', () => {
engine.start();
engine.submitAnswer(null); // move to q1
const node = engine.submitAnswer(true); // Answer true to q1
expect(node?.id).toBe('q2_yes');
});
it("should handle boolean branching (false)", () => {
engine.start();
engine.submitAnswer(null); // move to q1
const node = engine.submitAnswer(false); // Answer false to q1
expect(node?.id).toBe("q2_no");
});

it('should handle boolean branching (false)', () => {
engine.start();
engine.submitAnswer(null); // move to q1
const node = engine.submitAnswer(false); // Answer false to q1
expect(node?.id).toBe('q2_no');
});
it("should record answers in session", () => {
engine.start();
engine.submitAnswer(null); // q1
engine.submitAnswer(true); // q2_yes
const session = engine.getSession();

it('should record answers in session', () => {
engine.start();
engine.submitAnswer(null); // q1
engine.submitAnswer(true); // q2_yes
const session = engine.getSession();
expect(session.responses["q1"]).toBe(true);
expect(session.visitedNodes).toContain("q1");
expect(session.visitedNodes).toContain("q2_yes");
});

expect(session.responses['q1']).toBe(true);
expect(session.visitedNodes).toContain('q1');
expect(session.visitedNodes).toContain('q2_yes');
});
it("should throw error if submitAnswer called before start", () => {
expect(() => engine.submitAnswer("some answer")).toThrow(
"Survey not active",
);
});
});