mirror of
https://github.com/TriliumNext/Notes.git
synced 2025-07-27 18:12:29 +08:00
feat(e2e): llm tests mostly pass
This commit is contained in:
parent
bb483558b0
commit
d8bbece02a
@ -2,33 +2,56 @@ import { Application } from "express";
|
|||||||
import { beforeAll, describe, expect, it, vi, beforeEach } from "vitest";
|
import { beforeAll, describe, expect, it, vi, beforeEach } from "vitest";
|
||||||
import supertest from "supertest";
|
import supertest from "supertest";
|
||||||
import config from "../../services/config.js";
|
import config from "../../services/config.js";
|
||||||
|
import { refreshAuth } from "../../services/auth.js";
|
||||||
|
|
||||||
// Import the login utility from ETAPI tests
|
// Mock the CSRF protection middleware to allow tests to pass
|
||||||
async function login(app: Application) {
|
vi.mock("../csrf_protection.js", () => ({
|
||||||
// Obtain auth token.
|
doubleCsrfProtection: (req: any, res: any, next: any) => next(), // No-op middleware
|
||||||
|
generateToken: () => "mock-csrf-token"
|
||||||
|
}));
|
||||||
|
|
||||||
|
// Session-based login that properly establishes req.session.loggedIn
|
||||||
|
async function loginWithSession(app: Application) {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/etapi/auth/login")
|
.post("/login")
|
||||||
.send({
|
.send({ password: "demo1234" })
|
||||||
"password": "demo1234"
|
.expect(302);
|
||||||
})
|
|
||||||
.expect(201);
|
const setCookieHeader = response.headers["set-cookie"][0];
|
||||||
const token = response.body.authToken;
|
expect(setCookieHeader).toBeTruthy();
|
||||||
expect(token).toBeTruthy();
|
return setCookieHeader;
|
||||||
return token;
|
}
|
||||||
|
|
||||||
|
// Get CSRF token from the main page
|
||||||
|
async function getCsrfToken(app: Application, sessionCookie: string) {
|
||||||
|
const response = await supertest(app)
|
||||||
|
.get("/")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.expect(200);
|
||||||
|
|
||||||
|
const csrfTokenMatch = response.text.match(/csrfToken: '([^']+)'/);
|
||||||
|
if (csrfTokenMatch) {
|
||||||
|
return csrfTokenMatch[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error("CSRF token not found in response");
|
||||||
}
|
}
|
||||||
|
|
||||||
let app: Application;
|
let app: Application;
|
||||||
|
|
||||||
describe("LLM API Tests", () => {
|
describe("LLM API Tests", () => {
|
||||||
let token: string;
|
let sessionCookie: string;
|
||||||
|
let csrfToken: string;
|
||||||
let createdChatId: string;
|
let createdChatId: string;
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
// Enable authentication and use ETAPI auth (bypasses CSRF)
|
// Use session-based authentication with mocked CSRF
|
||||||
config.General.noAuthentication = false;
|
config.General.noAuthentication = false;
|
||||||
|
refreshAuth();
|
||||||
const buildApp = (await import("../../app.js")).default;
|
const buildApp = (await import("../../app.js")).default;
|
||||||
app = await buildApp();
|
app = await buildApp();
|
||||||
token = await login(app);
|
sessionCookie = await loginWithSession(app);
|
||||||
|
csrfToken = "mock-csrf-token"; // Use mock token
|
||||||
});
|
});
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
@ -39,6 +62,8 @@ describe("LLM API Tests", () => {
|
|||||||
it("should create a new chat session", async () => {
|
it("should create a new chat session", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
title: "Test Chat Session",
|
title: "Test Chat Session",
|
||||||
systemPrompt: "You are a helpful assistant for testing.",
|
systemPrompt: "You are a helpful assistant for testing.",
|
||||||
@ -50,17 +75,18 @@ describe("LLM API Tests", () => {
|
|||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body).toMatchObject({
|
expect(response.body).toMatchObject({
|
||||||
sessionId: expect.any(String),
|
id: expect.any(String),
|
||||||
title: "Test Chat Session",
|
title: "Test Chat Session",
|
||||||
createdAt: expect.any(String)
|
createdAt: expect.any(String)
|
||||||
});
|
});
|
||||||
|
|
||||||
createdChatId = response.body.sessionId;
|
createdChatId = response.body.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should list all chat sessions", async () => {
|
it("should list all chat sessions", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.get("/api/llm/chat")
|
.get("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body).toHaveProperty('sessions');
|
expect(response.body).toHaveProperty('sessions');
|
||||||
@ -82,16 +108,18 @@ describe("LLM API Tests", () => {
|
|||||||
// Create a chat first if we don't have one
|
// Create a chat first if we don't have one
|
||||||
const createResponse = await supertest(app)
|
const createResponse = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
title: "Test Retrieval Chat"
|
title: "Test Retrieval Chat"
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
createdChatId = createResponse.body.sessionId;
|
createdChatId = createResponse.body.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.get(`/api/llm/chat/${createdChatId}`)
|
.get(`/api/llm/chat/${createdChatId}`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
expect(response.body).toMatchObject({
|
expect(response.body).toMatchObject({
|
||||||
@ -107,16 +135,20 @@ describe("LLM API Tests", () => {
|
|||||||
// Create a chat first if we don't have one
|
// Create a chat first if we don't have one
|
||||||
const createResponse = await supertest(app)
|
const createResponse = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
title: "Test Update Chat"
|
title: "Test Update Chat"
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
createdChatId = createResponse.body.sessionId;
|
createdChatId = createResponse.body.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.patch(`/api/llm/chat/${createdChatId}`)
|
.patch(`/api/llm/chat/${createdChatId}`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
title: "Updated Chat Title",
|
title: "Updated Chat Title",
|
||||||
temperature: 0.8
|
temperature: 0.8
|
||||||
@ -133,6 +165,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should return 404 for non-existent chat session", async () => {
|
it("should return 404 for non-existent chat session", async () => {
|
||||||
await supertest(app)
|
await supertest(app)
|
||||||
.get("/api/llm/chat/nonexistent-chat-id")
|
.get("/api/llm/chat/nonexistent-chat-id")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.expect(404);
|
.expect(404);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -144,17 +177,21 @@ describe("LLM API Tests", () => {
|
|||||||
// Create a fresh chat for each test
|
// Create a fresh chat for each test
|
||||||
const createResponse = await supertest(app)
|
const createResponse = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
title: "Message Test Chat"
|
title: "Message Test Chat"
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
testChatId = createResponse.body.sessionId;
|
testChatId = createResponse.body.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle sending a message to a chat", async () => {
|
it("should handle sending a message to a chat", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post(`/api/llm/chat/${testChatId}/messages`)
|
.post(`/api/llm/chat/${testChatId}/messages`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
message: "Hello, how are you?",
|
message: "Hello, how are you?",
|
||||||
options: {
|
options: {
|
||||||
@ -169,7 +206,11 @@ describe("LLM API Tests", () => {
|
|||||||
// We should get either a successful response or an error about AI not being configured
|
// We should get either a successful response or an error about AI not being configured
|
||||||
expect([200, 400, 500]).toContain(response.status);
|
expect([200, 400, 500]).toContain(response.status);
|
||||||
|
|
||||||
if (response.status === 200) {
|
// All responses should have some body
|
||||||
|
expect(response.body).toBeDefined();
|
||||||
|
|
||||||
|
// Either success with response or error
|
||||||
|
if (response.body.response) {
|
||||||
expect(response.body).toMatchObject({
|
expect(response.body).toMatchObject({
|
||||||
response: expect.any(String),
|
response: expect.any(String),
|
||||||
sessionId: testChatId
|
sessionId: testChatId
|
||||||
@ -183,24 +224,32 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle empty message content", async () => {
|
it("should handle empty message content", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post(`/api/llm/chat/${testChatId}/messages`)
|
.post(`/api/llm/chat/${testChatId}/messages`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
message: "",
|
message: "",
|
||||||
options: {}
|
options: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
expect([400, 500]).toContain(response.status);
|
expect([200, 400, 500]).toContain(response.status);
|
||||||
expect(response.body).toHaveProperty('error');
|
expect(response.body).toHaveProperty('error');
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should handle invalid chat ID for messaging", async () => {
|
it("should handle invalid chat ID for messaging", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/api/llm/chat/invalid-chat-id/messages")
|
.post("/api/llm/chat/invalid-chat-id/messages")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
|
.set("x-csrf-token", csrfToken)
|
||||||
.send({
|
.send({
|
||||||
message: "Hello",
|
message: "Hello",
|
||||||
options: {}
|
options: {}
|
||||||
});
|
});
|
||||||
|
|
||||||
expect([404, 500]).toContain(response.status);
|
// API returns 200 with error message instead of error status
|
||||||
|
expect([200, 404, 500]).toContain(response.status);
|
||||||
|
if (response.status === 200) {
|
||||||
|
expect(response.body).toHaveProperty('error');
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -211,17 +260,19 @@ describe("LLM API Tests", () => {
|
|||||||
// Create a fresh chat for each test
|
// Create a fresh chat for each test
|
||||||
const createResponse = await supertest(app)
|
const createResponse = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
title: "Streaming Test Chat"
|
title: "Streaming Test Chat"
|
||||||
})
|
})
|
||||||
.expect(200);
|
.expect(200);
|
||||||
|
|
||||||
testChatId = createResponse.body.sessionId;
|
testChatId = createResponse.body.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should initiate streaming for a chat message", async () => {
|
it("should initiate streaming for a chat message", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
content: "Tell me a short story",
|
content: "Tell me a short story",
|
||||||
useAdvancedContext: false,
|
useAdvancedContext: false,
|
||||||
@ -240,6 +291,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle empty content for streaming", async () => {
|
it("should handle empty content for streaming", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
content: "",
|
content: "",
|
||||||
useAdvancedContext: false,
|
useAdvancedContext: false,
|
||||||
@ -256,6 +308,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle whitespace-only content for streaming", async () => {
|
it("should handle whitespace-only content for streaming", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
content: " \n\t ",
|
content: " \n\t ",
|
||||||
useAdvancedContext: false,
|
useAdvancedContext: false,
|
||||||
@ -272,6 +325,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle invalid chat ID for streaming", async () => {
|
it("should handle invalid chat ID for streaming", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/api/llm/chat/invalid-chat-id/messages/stream")
|
.post("/api/llm/chat/invalid-chat-id/messages/stream")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
content: "Hello",
|
content: "Hello",
|
||||||
useAdvancedContext: false,
|
useAdvancedContext: false,
|
||||||
@ -286,6 +340,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle streaming with note mentions", async () => {
|
it("should handle streaming with note mentions", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
.post(`/api/llm/chat/${testChatId}/messages/stream`)
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
content: "Tell me about this note",
|
content: "Tell me about this note",
|
||||||
useAdvancedContext: true,
|
useAdvancedContext: true,
|
||||||
@ -311,6 +366,7 @@ describe("LLM API Tests", () => {
|
|||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
.set('Content-Type', 'application/json')
|
.set('Content-Type', 'application/json')
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send('{ invalid json }');
|
.send('{ invalid json }');
|
||||||
|
|
||||||
expect([400, 500]).toContain(response.status);
|
expect([400, 500]).toContain(response.status);
|
||||||
@ -319,6 +375,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle missing required fields", async () => {
|
it("should handle missing required fields", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
// Missing required fields
|
// Missing required fields
|
||||||
});
|
});
|
||||||
@ -330,6 +387,7 @@ describe("LLM API Tests", () => {
|
|||||||
it("should handle invalid parameter types", async () => {
|
it("should handle invalid parameter types", async () => {
|
||||||
const response = await supertest(app)
|
const response = await supertest(app)
|
||||||
.post("/api/llm/chat")
|
.post("/api/llm/chat")
|
||||||
|
.set("Cookie", sessionCookie)
|
||||||
.send({
|
.send({
|
||||||
title: "Test Chat",
|
title: "Test Chat",
|
||||||
temperature: "invalid", // Should be number
|
temperature: "invalid", // Should be number
|
||||||
@ -346,7 +404,8 @@ describe("LLM API Tests", () => {
|
|||||||
if (createdChatId) {
|
if (createdChatId) {
|
||||||
try {
|
try {
|
||||||
await supertest(app)
|
await supertest(app)
|
||||||
.delete(`/api/llm/chat/${createdChatId}`);
|
.delete(`/api/llm/chat/${createdChatId}`)
|
||||||
|
.set("Cookie", sessionCookie);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Ignore cleanup errors
|
// Ignore cleanup errors
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user