mirror of
https://github.com/soconnor0919/hristudio.git
synced 2026-03-24 03:37:51 -04:00
feat: enhance experiment designer action definitions, refactor trial analysis UI, and update video playback controls
This commit is contained in:
@@ -61,15 +61,15 @@ describe("Control Flow Persistence", () => {
|
||||
// console.log("DB Rows Conditions:", JSON.stringify(dbRows[0].conditions, null, 2));
|
||||
// END DEBUG
|
||||
|
||||
expect(dbRows[0].type).toBe("conditional");
|
||||
expect((dbRows[0].conditions as any).options).toHaveLength(2);
|
||||
expect(dbRows[0]!.type).toBe("conditional");
|
||||
expect((dbRows[0]!.conditions as any).options).toHaveLength(2);
|
||||
|
||||
// Simulate Load
|
||||
const hydratedSteps = convertDatabaseToSteps(dbRows);
|
||||
|
||||
expect(hydratedSteps[0].type).toBe("conditional");
|
||||
expect((hydratedSteps[0].trigger.conditions as any).options).toHaveLength(2);
|
||||
expect((hydratedSteps[0].trigger.conditions as any).options[0].label).toBe("Yes");
|
||||
expect(hydratedSteps[0]!.type).toBe("conditional");
|
||||
expect((hydratedSteps[0]!.trigger.conditions as any).options).toHaveLength(2);
|
||||
expect((hydratedSteps[0]!.trigger.conditions as any).options[0].label).toBe("Yes");
|
||||
});
|
||||
|
||||
it("should persist loop configuration", () => {
|
||||
@@ -97,14 +97,14 @@ describe("Control Flow Persistence", () => {
|
||||
const dbRows = convertStepsToDatabase(originalSteps);
|
||||
|
||||
// Note: 'loop' type is mapped to 'conditional' in DB, but detailed conditions should survive
|
||||
expect(dbRows[0].type).toBe("conditional");
|
||||
expect((dbRows[0].conditions as any).loop.iterations).toBe(5);
|
||||
expect(dbRows[0]!.type).toBe("conditional");
|
||||
expect((dbRows[0]!.conditions as any).loop.iterations).toBe(5);
|
||||
|
||||
// Simulate Load
|
||||
const hydratedSteps = convertDatabaseToSteps(dbRows);
|
||||
|
||||
// Checking data integrity
|
||||
expect((hydratedSteps[0].trigger.conditions as any).loop).toBeDefined();
|
||||
expect((hydratedSteps[0].trigger.conditions as any).loop.iterations).toBe(5);
|
||||
expect((hydratedSteps[0]!.trigger.conditions as any).loop).toBeDefined();
|
||||
expect((hydratedSteps[0]!.trigger.conditions as any).loop.iterations).toBe(5);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,6 +66,7 @@ describe("Hashing Utilities", () => {
|
||||
id: "act-1",
|
||||
type: "log",
|
||||
name: "Log",
|
||||
category: "observation",
|
||||
parameters: { message: "A" },
|
||||
source: { kind: "core", baseActionId: "log" },
|
||||
execution: { transport: "internal" }
|
||||
@@ -87,6 +88,7 @@ describe("Hashing Utilities", () => {
|
||||
id: "act-1",
|
||||
type: "log",
|
||||
name: "Log",
|
||||
category: "observation",
|
||||
parameters: { message: "A" },
|
||||
source: { kind: "core", baseActionId: "log" },
|
||||
execution: { transport: "internal" }
|
||||
|
||||
@@ -36,7 +36,7 @@ describe("Designer Store Integration", () => {
|
||||
|
||||
store.getState().upsertStep(step);
|
||||
expect(store.getState().steps).toHaveLength(1);
|
||||
expect(store.getState().steps[0].id).toBe("step-1");
|
||||
expect(store.getState().steps[0]!.id).toBe("step-1");
|
||||
});
|
||||
|
||||
it("should update an existing step", () => {
|
||||
@@ -55,7 +55,7 @@ describe("Designer Store Integration", () => {
|
||||
store.getState().upsertStep(updatedStep);
|
||||
|
||||
expect(store.getState().steps).toHaveLength(1);
|
||||
expect(store.getState().steps[0].name).toBe("Updated Step");
|
||||
expect(store.getState().steps[0]!.name).toBe("Updated Step");
|
||||
});
|
||||
|
||||
it("should remove a step", () => {
|
||||
@@ -100,12 +100,12 @@ describe("Designer Store Integration", () => {
|
||||
store.getState().reorderStep(0, 1);
|
||||
|
||||
const steps = store.getState().steps;
|
||||
expect(steps[0].id).toBe("step-2");
|
||||
expect(steps[1].id).toBe("step-1");
|
||||
expect(steps[0]!.id).toBe("step-2");
|
||||
expect(steps[1]!.id).toBe("step-1");
|
||||
|
||||
// Orders should be updated
|
||||
expect(steps[0].order).toBe(0);
|
||||
expect(steps[1].order).toBe(1);
|
||||
expect(steps[0]!.order).toBe(0);
|
||||
expect(steps[1]!.order).toBe(1);
|
||||
});
|
||||
|
||||
it("should upsert an action into a step", () => {
|
||||
@@ -124,6 +124,7 @@ describe("Designer Store Integration", () => {
|
||||
id: "act-1",
|
||||
type: "log",
|
||||
name: "Log",
|
||||
category: "observation",
|
||||
parameters: {},
|
||||
source: { kind: "core", baseActionId: "log" },
|
||||
execution: { transport: "internal" }
|
||||
@@ -132,7 +133,7 @@ describe("Designer Store Integration", () => {
|
||||
store.getState().upsertAction("step-1", action);
|
||||
|
||||
const storedStep = store.getState().steps[0];
|
||||
expect(storedStep.actions).toHaveLength(1);
|
||||
expect(storedStep.actions[0].id).toBe("act-1");
|
||||
expect(storedStep!.actions).toHaveLength(1);
|
||||
expect(storedStep!.actions[0]!.id).toBe("act-1");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,10 +8,13 @@ const mockActionDef: ActionDefinition = {
|
||||
id: "core.log",
|
||||
name: "Log Info",
|
||||
type: "log",
|
||||
category: "utility",
|
||||
description: "Logs information",
|
||||
category: "observation",
|
||||
icon: "lucide-info",
|
||||
color: "blue",
|
||||
parameters: [
|
||||
{ id: "message", name: "Message", type: "text", required: true },
|
||||
{ id: "level", name: "Level", type: "select", options: ["info", "warn", "error"], default: "info" }
|
||||
{ id: "level", name: "Level", type: "select", options: ["info", "warn", "error"], value: "info" }
|
||||
],
|
||||
source: { kind: "core", baseActionId: "log" }
|
||||
};
|
||||
@@ -33,7 +36,7 @@ describe("Experiment Validators", () => {
|
||||
it("should fail if experiment has no steps", () => {
|
||||
const result = validateExperimentDesign([], { steps: [], actionDefinitions: [] });
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.issues[0].message).toContain("at least one step");
|
||||
expect(result.issues[0]!.message).toContain("at least one step");
|
||||
});
|
||||
|
||||
it("should fail if step name is empty", () => {
|
||||
@@ -55,7 +58,7 @@ describe("Experiment Validators", () => {
|
||||
id: "act-1",
|
||||
type: "log",
|
||||
name: "Log",
|
||||
order: 0,
|
||||
category: "observation",
|
||||
parameters: {}, // Missing 'message'
|
||||
source: { kind: "core", baseActionId: "log" },
|
||||
execution: { transport: "internal" }
|
||||
@@ -75,7 +78,7 @@ describe("Experiment Validators", () => {
|
||||
id: "act-1",
|
||||
type: "log",
|
||||
name: "Log",
|
||||
order: 0,
|
||||
category: "observation",
|
||||
parameters: { message: "Hello" },
|
||||
source: { kind: "core", baseActionId: "log" },
|
||||
execution: { transport: "internal" }
|
||||
@@ -104,7 +107,7 @@ describe("Experiment Validators", () => {
|
||||
id: "act-1",
|
||||
type: "math",
|
||||
name: "Math",
|
||||
order: 0,
|
||||
category: "observation",
|
||||
parameters: { val: 15 }, // Too high
|
||||
source: { kind: "core", baseActionId: "math" },
|
||||
execution: { transport: "internal" }
|
||||
@@ -116,7 +119,7 @@ describe("Experiment Validators", () => {
|
||||
actionDefinitions: [rangeActionDef]
|
||||
});
|
||||
|
||||
expect(issues[0].message).toContain("must be at most 10");
|
||||
expect(issues[0]!.message).toContain("must be at most 10");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user