mirror of
https://gitea.toothfairyai.com/ToothFairyAI/tf_code.git
synced 2026-03-30 22:03:58 +00:00
323 lines
8.3 KiB
TypeScript
323 lines
8.3 KiB
TypeScript
import { afterEach, test, expect } from "bun:test"
|
|
import { Question } from "../../src/question"
|
|
import { Instance } from "../../src/project/instance"
|
|
import { QuestionID } from "../../src/question/schema"
|
|
import { tmpdir } from "../fixture/fixture"
|
|
import { SessionID } from "../../src/session/schema"
|
|
|
|
afterEach(async () => {
|
|
await Instance.disposeAll()
|
|
})
|
|
|
|
/** Reject all pending questions so dangling Deferred fibers don't hang the test. */
|
|
async function rejectAll() {
|
|
const pending = await Question.list()
|
|
for (const req of pending) {
|
|
await Question.reject(req.id)
|
|
}
|
|
}
|
|
|
|
test("ask - returns pending promise", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const promise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions: [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Option 1", description: "First option" },
|
|
{ label: "Option 2", description: "Second option" },
|
|
],
|
|
},
|
|
],
|
|
})
|
|
expect(promise).toBeInstanceOf(Promise)
|
|
await rejectAll()
|
|
await promise.catch(() => {})
|
|
},
|
|
})
|
|
})
|
|
|
|
test("ask - adds to pending list", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const questions = [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Option 1", description: "First option" },
|
|
{ label: "Option 2", description: "Second option" },
|
|
],
|
|
},
|
|
]
|
|
|
|
const askPromise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions,
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
expect(pending.length).toBe(1)
|
|
expect(pending[0].questions).toEqual(questions)
|
|
await rejectAll()
|
|
await askPromise.catch(() => {})
|
|
},
|
|
})
|
|
})
|
|
|
|
// reply tests
|
|
|
|
test("reply - resolves the pending ask with answers", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const questions = [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Option 1", description: "First option" },
|
|
{ label: "Option 2", description: "Second option" },
|
|
],
|
|
},
|
|
]
|
|
|
|
const askPromise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions,
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
const requestID = pending[0].id
|
|
|
|
await Question.reply({
|
|
requestID,
|
|
answers: [["Option 1"]],
|
|
})
|
|
|
|
const answers = await askPromise
|
|
expect(answers).toEqual([["Option 1"]])
|
|
},
|
|
})
|
|
})
|
|
|
|
test("reply - removes from pending list", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const askPromise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions: [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Option 1", description: "First option" },
|
|
{ label: "Option 2", description: "Second option" },
|
|
],
|
|
},
|
|
],
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
expect(pending.length).toBe(1)
|
|
|
|
await Question.reply({
|
|
requestID: pending[0].id,
|
|
answers: [["Option 1"]],
|
|
})
|
|
await askPromise
|
|
|
|
const pendingAfter = await Question.list()
|
|
expect(pendingAfter.length).toBe(0)
|
|
},
|
|
})
|
|
})
|
|
|
|
test("reply - does nothing for unknown requestID", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
await Question.reply({
|
|
requestID: QuestionID.make("que_unknown"),
|
|
answers: [["Option 1"]],
|
|
})
|
|
// Should not throw
|
|
},
|
|
})
|
|
})
|
|
|
|
// reject tests
|
|
|
|
test("reject - throws RejectedError", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const askPromise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions: [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Option 1", description: "First option" },
|
|
{ label: "Option 2", description: "Second option" },
|
|
],
|
|
},
|
|
],
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
await Question.reject(pending[0].id)
|
|
|
|
await expect(askPromise).rejects.toBeInstanceOf(Question.RejectedError)
|
|
},
|
|
})
|
|
})
|
|
|
|
test("reject - removes from pending list", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const askPromise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions: [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Option 1", description: "First option" },
|
|
{ label: "Option 2", description: "Second option" },
|
|
],
|
|
},
|
|
],
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
expect(pending.length).toBe(1)
|
|
|
|
await Question.reject(pending[0].id)
|
|
askPromise.catch(() => {}) // Ignore rejection
|
|
|
|
const pendingAfter = await Question.list()
|
|
expect(pendingAfter.length).toBe(0)
|
|
},
|
|
})
|
|
})
|
|
|
|
test("reject - does nothing for unknown requestID", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
await Question.reject(QuestionID.make("que_unknown"))
|
|
// Should not throw
|
|
},
|
|
})
|
|
})
|
|
|
|
// multiple questions tests
|
|
|
|
test("ask - handles multiple questions", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const questions = [
|
|
{
|
|
question: "What would you like to do?",
|
|
header: "Action",
|
|
options: [
|
|
{ label: "Build", description: "Build the project" },
|
|
{ label: "Test", description: "Run tests" },
|
|
],
|
|
},
|
|
{
|
|
question: "Which environment?",
|
|
header: "Env",
|
|
options: [
|
|
{ label: "Dev", description: "Development" },
|
|
{ label: "Prod", description: "Production" },
|
|
],
|
|
},
|
|
]
|
|
|
|
const askPromise = Question.ask({
|
|
sessionID: SessionID.make("ses_test"),
|
|
questions,
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
|
|
await Question.reply({
|
|
requestID: pending[0].id,
|
|
answers: [["Build"], ["Dev"]],
|
|
})
|
|
|
|
const answers = await askPromise
|
|
expect(answers).toEqual([["Build"], ["Dev"]])
|
|
},
|
|
})
|
|
})
|
|
|
|
// list tests
|
|
|
|
test("list - returns all pending requests", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const p1 = Question.ask({
|
|
sessionID: SessionID.make("ses_test1"),
|
|
questions: [
|
|
{
|
|
question: "Question 1?",
|
|
header: "Q1",
|
|
options: [{ label: "A", description: "A" }],
|
|
},
|
|
],
|
|
})
|
|
|
|
const p2 = Question.ask({
|
|
sessionID: SessionID.make("ses_test2"),
|
|
questions: [
|
|
{
|
|
question: "Question 2?",
|
|
header: "Q2",
|
|
options: [{ label: "B", description: "B" }],
|
|
},
|
|
],
|
|
})
|
|
|
|
const pending = await Question.list()
|
|
expect(pending.length).toBe(2)
|
|
await rejectAll()
|
|
p1.catch(() => {})
|
|
p2.catch(() => {})
|
|
},
|
|
})
|
|
})
|
|
|
|
test("list - returns empty when no pending", async () => {
|
|
await using tmp = await tmpdir({ git: true })
|
|
await Instance.provide({
|
|
directory: tmp.path,
|
|
fn: async () => {
|
|
const pending = await Question.list()
|
|
expect(pending.length).toBe(0)
|
|
},
|
|
})
|
|
})
|