Restore Ultracite + fix sidebar (#1233)
This commit is contained in:
parent
8fbfc253fa
commit
947ed094a6
177 changed files with 6908 additions and 8306 deletions
|
|
@ -1,8 +1,8 @@
|
|||
import { expect, test } from '../fixtures';
|
||||
import { ChatPage } from '../pages/chat';
|
||||
import { ArtifactPage } from '../pages/artifact';
|
||||
import { expect, test } from "../fixtures";
|
||||
import { ArtifactPage } from "../pages/artifact";
|
||||
import { ChatPage } from "../pages/chat";
|
||||
|
||||
test.describe('Artifacts activity', () => {
|
||||
test.describe("Artifacts activity", () => {
|
||||
let chatPage: ChatPage;
|
||||
let artifactPage: ArtifactPage;
|
||||
|
||||
|
|
@ -13,12 +13,12 @@ test.describe('Artifacts activity', () => {
|
|||
await chatPage.createNewChat();
|
||||
});
|
||||
|
||||
test('Create a text artifact', async () => {
|
||||
test("Create a text artifact", async () => {
|
||||
test.fixme();
|
||||
await chatPage.createNewChat();
|
||||
|
||||
await chatPage.sendUserMessage(
|
||||
'Help me write an essay about Silicon Valley',
|
||||
"Help me write an essay about Silicon Valley"
|
||||
);
|
||||
await artifactPage.isGenerationComplete();
|
||||
|
||||
|
|
@ -26,18 +26,18 @@ test.describe('Artifacts activity', () => {
|
|||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toBe(
|
||||
'A document was created and is now visible to the user.',
|
||||
"A document was created and is now visible to the user."
|
||||
);
|
||||
|
||||
await chatPage.hasChatIdInUrl();
|
||||
});
|
||||
|
||||
test('Toggle artifact visibility', async () => {
|
||||
test("Toggle artifact visibility", async () => {
|
||||
test.fixme();
|
||||
await chatPage.createNewChat();
|
||||
|
||||
await chatPage.sendUserMessage(
|
||||
'Help me write an essay about Silicon Valley',
|
||||
"Help me write an essay about Silicon Valley"
|
||||
);
|
||||
await artifactPage.isGenerationComplete();
|
||||
|
||||
|
|
@ -45,19 +45,19 @@ test.describe('Artifacts activity', () => {
|
|||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toBe(
|
||||
'A document was created and is now visible to the user.',
|
||||
"A document was created and is now visible to the user."
|
||||
);
|
||||
|
||||
await artifactPage.closeArtifact();
|
||||
await chatPage.isElementNotVisible('artifact');
|
||||
await chatPage.isElementNotVisible("artifact");
|
||||
});
|
||||
|
||||
test('Send follow up message after generation', async () => {
|
||||
test("Send follow up message after generation", async () => {
|
||||
test.fixme();
|
||||
await chatPage.createNewChat();
|
||||
|
||||
await chatPage.sendUserMessage(
|
||||
'Help me write an essay about Silicon Valley',
|
||||
"Help me write an essay about Silicon Valley"
|
||||
);
|
||||
await artifactPage.isGenerationComplete();
|
||||
|
||||
|
|
@ -65,10 +65,10 @@ test.describe('Artifacts activity', () => {
|
|||
|
||||
const assistantMessage = await artifactPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toBe(
|
||||
'A document was created and is now visible to the user.',
|
||||
"A document was created and is now visible to the user."
|
||||
);
|
||||
|
||||
await artifactPage.sendUserMessage('Thanks!');
|
||||
await artifactPage.sendUserMessage("Thanks!");
|
||||
await artifactPage.isGenerationComplete();
|
||||
|
||||
const secondAssistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ChatPage } from '../pages/chat';
|
||||
import { test, expect } from '../fixtures';
|
||||
import { expect, test } from "../fixtures";
|
||||
import { ChatPage } from "../pages/chat";
|
||||
|
||||
test.describe('Chat activity', () => {
|
||||
test.describe("Chat activity", () => {
|
||||
let chatPage: ChatPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
|
|
@ -9,16 +9,16 @@ test.describe('Chat activity', () => {
|
|||
await chatPage.createNewChat();
|
||||
});
|
||||
|
||||
test('Send a user message and receive response', async () => {
|
||||
await chatPage.sendUserMessage('Why is grass green?');
|
||||
test("Send a user message and receive response", async () => {
|
||||
await chatPage.sendUserMessage("Why is grass green?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toContain("It's just green duh!");
|
||||
});
|
||||
|
||||
test('Redirect to /chat/:id after submitting message', async () => {
|
||||
await chatPage.sendUserMessage('Why is grass green?');
|
||||
test("Redirect to /chat/:id after submitting message", async () => {
|
||||
await chatPage.sendUserMessage("Why is grass green?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
|
@ -26,21 +26,21 @@ test.describe('Chat activity', () => {
|
|||
await chatPage.hasChatIdInUrl();
|
||||
});
|
||||
|
||||
test('Send a user message from suggestion', async () => {
|
||||
test("Send a user message from suggestion", async () => {
|
||||
await chatPage.sendUserMessageFromSuggestion();
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toContain(
|
||||
'With Next.js, you can ship fast!',
|
||||
"With Next.js, you can ship fast!"
|
||||
);
|
||||
});
|
||||
|
||||
test('Toggle between send/stop button based on activity', async () => {
|
||||
test("Toggle between send/stop button based on activity", async () => {
|
||||
await expect(chatPage.sendButton).toBeVisible();
|
||||
await expect(chatPage.sendButton).toBeDisabled();
|
||||
|
||||
await chatPage.sendUserMessage('Why is grass green?');
|
||||
await chatPage.sendUserMessage("Why is grass green?");
|
||||
|
||||
await expect(chatPage.sendButton).not.toBeVisible();
|
||||
await expect(chatPage.stopButton).toBeVisible();
|
||||
|
|
@ -51,22 +51,22 @@ test.describe('Chat activity', () => {
|
|||
await expect(chatPage.sendButton).toBeVisible();
|
||||
});
|
||||
|
||||
test('Stop generation during submission', async () => {
|
||||
await chatPage.sendUserMessage('Why is grass green?');
|
||||
test("Stop generation during submission", async () => {
|
||||
await chatPage.sendUserMessage("Why is grass green?");
|
||||
await expect(chatPage.stopButton).toBeVisible();
|
||||
await chatPage.stopButton.click();
|
||||
await expect(chatPage.sendButton).toBeVisible();
|
||||
});
|
||||
|
||||
test('Edit user message and resubmit', async () => {
|
||||
await chatPage.sendUserMessage('Why is grass green?');
|
||||
test("Edit user message and resubmit", async () => {
|
||||
await chatPage.sendUserMessage("Why is grass green?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toContain("It's just green duh!");
|
||||
|
||||
const userMessage = await chatPage.getRecentUserMessage();
|
||||
await userMessage.edit('Why is the sky blue?');
|
||||
await userMessage.edit("Why is the sky blue?");
|
||||
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
|
|
@ -74,20 +74,20 @@ test.describe('Chat activity', () => {
|
|||
expect(updatedAssistantMessage.content).toContain("It's just blue duh!");
|
||||
});
|
||||
|
||||
test('Hide suggested actions after sending message', async () => {
|
||||
await chatPage.isElementVisible('suggested-actions');
|
||||
test("Hide suggested actions after sending message", async () => {
|
||||
await chatPage.isElementVisible("suggested-actions");
|
||||
await chatPage.sendUserMessageFromSuggestion();
|
||||
await chatPage.isElementNotVisible('suggested-actions');
|
||||
await chatPage.isElementNotVisible("suggested-actions");
|
||||
});
|
||||
|
||||
test('Upload file and send image attachment with message', async () => {
|
||||
test("Upload file and send image attachment with message", async () => {
|
||||
await chatPage.addImageAttachment();
|
||||
|
||||
await chatPage.isElementVisible('attachments-preview');
|
||||
await chatPage.isElementVisible('input-attachment-loader');
|
||||
await chatPage.isElementNotVisible('input-attachment-loader');
|
||||
await chatPage.isElementVisible("attachments-preview");
|
||||
await chatPage.isElementVisible("input-attachment-loader");
|
||||
await chatPage.isElementNotVisible("input-attachment-loader");
|
||||
|
||||
await chatPage.sendUserMessage('Who painted this?');
|
||||
await chatPage.sendUserMessage("Who painted this?");
|
||||
|
||||
const userMessage = await chatPage.getRecentUserMessage();
|
||||
expect(userMessage.attachments).toHaveLength(1);
|
||||
|
|
@ -95,22 +95,22 @@ test.describe('Chat activity', () => {
|
|||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toBe('This painting is by Monet!');
|
||||
expect(assistantMessage.content).toBe("This painting is by Monet!");
|
||||
});
|
||||
|
||||
test('Call weather tool', async () => {
|
||||
test("Call weather tool", async () => {
|
||||
await chatPage.sendUserMessage("What's the weather in sf?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
||||
expect(assistantMessage.content).toBe(
|
||||
'The current temperature in San Francisco is 17°C.',
|
||||
"The current temperature in San Francisco is 17°C."
|
||||
);
|
||||
});
|
||||
|
||||
test('Upvote message', async () => {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
test("Upvote message", async () => {
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
|
@ -118,8 +118,8 @@ test.describe('Chat activity', () => {
|
|||
await chatPage.isVoteComplete();
|
||||
});
|
||||
|
||||
test('Downvote message', async () => {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
test("Downvote message", async () => {
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
|
@ -127,8 +127,8 @@ test.describe('Chat activity', () => {
|
|||
await chatPage.isVoteComplete();
|
||||
});
|
||||
|
||||
test('Update vote', async () => {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
test("Update vote", async () => {
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
|
@ -139,25 +139,25 @@ test.describe('Chat activity', () => {
|
|||
await chatPage.isVoteComplete();
|
||||
});
|
||||
|
||||
test('Create message from url query', async ({ page }) => {
|
||||
await page.goto('/?query=Why is the sky blue?');
|
||||
test("Create message from url query", async ({ page }) => {
|
||||
await page.goto("/?query=Why is the sky blue?");
|
||||
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const userMessage = await chatPage.getRecentUserMessage();
|
||||
expect(userMessage.content).toBe('Why is the sky blue?');
|
||||
expect(userMessage.content).toBe("Why is the sky blue?");
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toContain("It's just blue duh!");
|
||||
});
|
||||
|
||||
test('auto-scrolls to bottom after submitting new messages', async () => {
|
||||
test("auto-scrolls to bottom after submitting new messages", async () => {
|
||||
test.fixme();
|
||||
await chatPage.sendMultipleMessages(5, (i) => `filling message #${i}`);
|
||||
await chatPage.waitForScrollToBottom();
|
||||
});
|
||||
|
||||
test('scroll button appears when user scrolls up, hides on click', async () => {
|
||||
test("scroll button appears when user scrolls up, hides on click", async () => {
|
||||
test.fixme();
|
||||
await chatPage.sendMultipleMessages(5, (i) => `filling message #${i}`);
|
||||
await expect(chatPage.scrollToBottomButton).not.toBeVisible();
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { ChatPage } from '../pages/chat';
|
||||
import { test, expect } from '../fixtures';
|
||||
import { expect, test } from "../fixtures";
|
||||
import { ChatPage } from "../pages/chat";
|
||||
|
||||
test.describe('chat activity with reasoning', () => {
|
||||
test.describe("chat activity with reasoning", () => {
|
||||
let chatPage: ChatPage;
|
||||
|
||||
test.beforeEach(async ({ curieContext }) => {
|
||||
|
|
@ -9,25 +9,25 @@ test.describe('chat activity with reasoning', () => {
|
|||
await chatPage.createNewChat();
|
||||
});
|
||||
|
||||
test('Curie can send message and generate response with reasoning', async () => {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
test("Curie can send message and generate response with reasoning", async () => {
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
expect(assistantMessage.content).toBe("It's just blue duh!");
|
||||
|
||||
expect(assistantMessage.reasoning).toBe(
|
||||
'The sky is blue because of rayleigh scattering!',
|
||||
"The sky is blue because of rayleigh scattering!"
|
||||
);
|
||||
});
|
||||
|
||||
test('Curie can toggle reasoning visibility', async () => {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
test("Curie can toggle reasoning visibility", async () => {
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
const reasoningElement =
|
||||
assistantMessage.element.getByTestId('message-reasoning');
|
||||
assistantMessage.element.getByTestId("message-reasoning");
|
||||
expect(reasoningElement).toBeVisible();
|
||||
|
||||
await assistantMessage.toggleReasoningVisibility();
|
||||
|
|
@ -37,18 +37,18 @@ test.describe('chat activity with reasoning', () => {
|
|||
await expect(reasoningElement).toBeVisible();
|
||||
});
|
||||
|
||||
test('Curie can edit message and resubmit', async () => {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
test("Curie can edit message and resubmit", async () => {
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const assistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
const reasoningElement =
|
||||
assistantMessage.element.getByTestId('message-reasoning');
|
||||
assistantMessage.element.getByTestId("message-reasoning");
|
||||
expect(reasoningElement).toBeVisible();
|
||||
|
||||
const userMessage = await chatPage.getRecentUserMessage();
|
||||
|
||||
await userMessage.edit('Why is grass green?');
|
||||
await userMessage.edit("Why is grass green?");
|
||||
await chatPage.isGenerationComplete();
|
||||
|
||||
const updatedAssistantMessage = await chatPage.getRecentAssistantMessage();
|
||||
|
|
@ -56,7 +56,7 @@ test.describe('chat activity with reasoning', () => {
|
|||
expect(updatedAssistantMessage.content).toBe("It's just green duh!");
|
||||
|
||||
expect(updatedAssistantMessage.reasoning).toBe(
|
||||
'Grass is green because of chlorophyll absorption!',
|
||||
"Grass is green because of chlorophyll absorption!"
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,23 +1,23 @@
|
|||
import { expect, test } from '../fixtures';
|
||||
import { AuthPage } from '../pages/auth';
|
||||
import { generateRandomTestUser } from '../helpers';
|
||||
import { ChatPage } from '../pages/chat';
|
||||
import { getMessageByErrorCode } from '@/lib/errors';
|
||||
import { getMessageByErrorCode } from "@/lib/errors";
|
||||
import { expect, test } from "../fixtures";
|
||||
import { generateRandomTestUser } from "../helpers";
|
||||
import { AuthPage } from "../pages/auth";
|
||||
import { ChatPage } from "../pages/chat";
|
||||
|
||||
test.describe
|
||||
.serial('Guest Session', () => {
|
||||
test('Authenticate as guest user when a new session is loaded', async ({
|
||||
.serial("Guest Session", () => {
|
||||
test("Authenticate as guest user when a new session is loaded", async ({
|
||||
page,
|
||||
}) => {
|
||||
const response = await page.goto('/');
|
||||
const response = await page.goto("/");
|
||||
|
||||
if (!response) {
|
||||
throw new Error('Failed to load page');
|
||||
throw new Error("Failed to load page");
|
||||
}
|
||||
|
||||
let request = response.request();
|
||||
|
||||
const chain = [];
|
||||
const chain: string[] = [];
|
||||
|
||||
while (request) {
|
||||
chain.unshift(request.url());
|
||||
|
|
@ -25,185 +25,185 @@ test.describe
|
|||
}
|
||||
|
||||
expect(chain).toEqual([
|
||||
'http://localhost:3000/',
|
||||
'http://localhost:3000/api/auth/guest?redirectUrl=http%3A%2F%2Flocalhost%3A3000%2F',
|
||||
'http://localhost:3000/',
|
||||
"http://localhost:3000/",
|
||||
"http://localhost:3000/api/auth/guest?redirectUrl=http%3A%2F%2Flocalhost%3A3000%2F",
|
||||
"http://localhost:3000/",
|
||||
]);
|
||||
});
|
||||
|
||||
test('Log out is not available for guest users', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
test("Log out is not available for guest users", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
||||
const sidebarToggleButton = page.getByTestId('sidebar-toggle-button');
|
||||
const sidebarToggleButton = page.getByTestId("sidebar-toggle-button");
|
||||
await sidebarToggleButton.click();
|
||||
|
||||
const userNavButton = page.getByTestId('user-nav-button');
|
||||
const userNavButton = page.getByTestId("user-nav-button");
|
||||
await expect(userNavButton).toBeVisible();
|
||||
|
||||
await userNavButton.click();
|
||||
const userNavMenu = page.getByTestId('user-nav-menu');
|
||||
const userNavMenu = page.getByTestId("user-nav-menu");
|
||||
await expect(userNavMenu).toBeVisible();
|
||||
|
||||
const authMenuItem = page.getByTestId('user-nav-item-auth');
|
||||
await expect(authMenuItem).toContainText('Login to your account');
|
||||
const authMenuItem = page.getByTestId("user-nav-item-auth");
|
||||
await expect(authMenuItem).toContainText("Login to your account");
|
||||
});
|
||||
|
||||
test('Do not authenticate as guest user when an existing non-guest session is active', async ({
|
||||
test("Do not authenticate as guest user when an existing non-guest session is active", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const response = await adaContext.page.goto('/');
|
||||
const response = await adaContext.page.goto("/");
|
||||
|
||||
if (!response) {
|
||||
throw new Error('Failed to load page');
|
||||
throw new Error("Failed to load page");
|
||||
}
|
||||
|
||||
let request = response.request();
|
||||
|
||||
const chain = [];
|
||||
const chain: string[] = [];
|
||||
|
||||
while (request) {
|
||||
chain.unshift(request.url());
|
||||
request = request.redirectedFrom();
|
||||
}
|
||||
|
||||
expect(chain).toEqual(['http://localhost:3000/']);
|
||||
expect(chain).toEqual(["http://localhost:3000/"]);
|
||||
});
|
||||
|
||||
test('Allow navigating to /login as guest user', async ({ page }) => {
|
||||
await page.goto('/login');
|
||||
await page.waitForURL('/login');
|
||||
await expect(page).toHaveURL('/login');
|
||||
test("Allow navigating to /login as guest user", async ({ page }) => {
|
||||
await page.goto("/login");
|
||||
await page.waitForURL("/login");
|
||||
await expect(page).toHaveURL("/login");
|
||||
});
|
||||
|
||||
test('Allow navigating to /register as guest user', async ({ page }) => {
|
||||
await page.goto('/register');
|
||||
await page.waitForURL('/register');
|
||||
await expect(page).toHaveURL('/register');
|
||||
test("Allow navigating to /register as guest user", async ({ page }) => {
|
||||
await page.goto("/register");
|
||||
await page.waitForURL("/register");
|
||||
await expect(page).toHaveURL("/register");
|
||||
});
|
||||
|
||||
test('Do not show email in user menu for guest user', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
test("Do not show email in user menu for guest user", async ({ page }) => {
|
||||
await page.goto("/");
|
||||
|
||||
const sidebarToggleButton = page.getByTestId('sidebar-toggle-button');
|
||||
const sidebarToggleButton = page.getByTestId("sidebar-toggle-button");
|
||||
await sidebarToggleButton.click();
|
||||
|
||||
const userEmail = page.getByTestId('user-email');
|
||||
await expect(userEmail).toContainText('Guest');
|
||||
const userEmail = page.getByTestId("user-email");
|
||||
await expect(userEmail).toContainText("Guest");
|
||||
});
|
||||
});
|
||||
|
||||
test.describe
|
||||
.serial('Login and Registration', () => {
|
||||
.serial("Login and Registration", () => {
|
||||
let authPage: AuthPage;
|
||||
|
||||
const testUser = generateRandomTestUser();
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.beforeEach(({ page }) => {
|
||||
authPage = new AuthPage(page);
|
||||
});
|
||||
|
||||
test('Register new account', async () => {
|
||||
test("Register new account", async () => {
|
||||
await authPage.register(testUser.email, testUser.password);
|
||||
await authPage.expectToastToContain('Account created successfully!');
|
||||
await authPage.expectToastToContain("Account created successfully!");
|
||||
});
|
||||
|
||||
test('Register new account with existing email', async () => {
|
||||
test("Register new account with existing email", async () => {
|
||||
await authPage.register(testUser.email, testUser.password);
|
||||
await authPage.expectToastToContain('Account already exists!');
|
||||
await authPage.expectToastToContain("Account already exists!");
|
||||
});
|
||||
|
||||
test('Log into account that exists', async ({ page }) => {
|
||||
test("Log into account that exists", async ({ page }) => {
|
||||
await authPage.login(testUser.email, testUser.password);
|
||||
|
||||
await page.waitForURL('/');
|
||||
await expect(page.getByPlaceholder('Send a message...')).toBeVisible();
|
||||
await page.waitForURL("/");
|
||||
await expect(page.getByPlaceholder("Send a message...")).toBeVisible();
|
||||
});
|
||||
|
||||
test('Display user email in user menu', async ({ page }) => {
|
||||
test("Display user email in user menu", async ({ page }) => {
|
||||
await authPage.login(testUser.email, testUser.password);
|
||||
|
||||
await page.waitForURL('/');
|
||||
await expect(page.getByPlaceholder('Send a message...')).toBeVisible();
|
||||
await page.waitForURL("/");
|
||||
await expect(page.getByPlaceholder("Send a message...")).toBeVisible();
|
||||
|
||||
const userEmail = await page.getByTestId('user-email');
|
||||
const userEmail = await page.getByTestId("user-email");
|
||||
await expect(userEmail).toHaveText(testUser.email);
|
||||
});
|
||||
|
||||
test('Log out as non-guest user', async () => {
|
||||
test("Log out as non-guest user", async () => {
|
||||
await authPage.logout(testUser.email, testUser.password);
|
||||
});
|
||||
|
||||
test('Do not force create a guest session if non-guest session already exists', async ({
|
||||
test("Do not force create a guest session if non-guest session already exists", async ({
|
||||
page,
|
||||
}) => {
|
||||
await authPage.login(testUser.email, testUser.password);
|
||||
await page.waitForURL('/');
|
||||
await page.waitForURL("/");
|
||||
|
||||
const userEmail = await page.getByTestId('user-email');
|
||||
const userEmail = await page.getByTestId("user-email");
|
||||
await expect(userEmail).toHaveText(testUser.email);
|
||||
|
||||
await page.goto('/api/auth/guest');
|
||||
await page.waitForURL('/');
|
||||
await page.goto("/api/auth/guest");
|
||||
await page.waitForURL("/");
|
||||
|
||||
const updatedUserEmail = await page.getByTestId('user-email');
|
||||
const updatedUserEmail = await page.getByTestId("user-email");
|
||||
await expect(updatedUserEmail).toHaveText(testUser.email);
|
||||
});
|
||||
|
||||
test('Log out is available for non-guest users', async ({ page }) => {
|
||||
test("Log out is available for non-guest users", async ({ page }) => {
|
||||
await authPage.login(testUser.email, testUser.password);
|
||||
await page.waitForURL('/');
|
||||
await page.waitForURL("/");
|
||||
|
||||
authPage.openSidebar();
|
||||
|
||||
const userNavButton = page.getByTestId('user-nav-button');
|
||||
const userNavButton = page.getByTestId("user-nav-button");
|
||||
await expect(userNavButton).toBeVisible();
|
||||
|
||||
await userNavButton.click();
|
||||
const userNavMenu = page.getByTestId('user-nav-menu');
|
||||
const userNavMenu = page.getByTestId("user-nav-menu");
|
||||
await expect(userNavMenu).toBeVisible();
|
||||
|
||||
const authMenuItem = page.getByTestId('user-nav-item-auth');
|
||||
await expect(authMenuItem).toContainText('Sign out');
|
||||
const authMenuItem = page.getByTestId("user-nav-item-auth");
|
||||
await expect(authMenuItem).toContainText("Sign out");
|
||||
});
|
||||
|
||||
test('Do not navigate to /register for non-guest users', async ({
|
||||
test("Do not navigate to /register for non-guest users", async ({
|
||||
page,
|
||||
}) => {
|
||||
await authPage.login(testUser.email, testUser.password);
|
||||
await page.waitForURL('/');
|
||||
await page.waitForURL("/");
|
||||
|
||||
await page.goto('/register');
|
||||
await expect(page).toHaveURL('/');
|
||||
await page.goto("/register");
|
||||
await expect(page).toHaveURL("/");
|
||||
});
|
||||
|
||||
test('Do not navigate to /login for non-guest users', async ({ page }) => {
|
||||
test("Do not navigate to /login for non-guest users", async ({ page }) => {
|
||||
await authPage.login(testUser.email, testUser.password);
|
||||
await page.waitForURL('/');
|
||||
await page.waitForURL("/");
|
||||
|
||||
await page.goto('/login');
|
||||
await expect(page).toHaveURL('/');
|
||||
await page.goto("/login");
|
||||
await expect(page).toHaveURL("/");
|
||||
});
|
||||
});
|
||||
|
||||
test.describe('Entitlements', () => {
|
||||
test.describe("Entitlements", () => {
|
||||
let chatPage: ChatPage;
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.beforeEach(({ page }) => {
|
||||
chatPage = new ChatPage(page);
|
||||
});
|
||||
|
||||
test('Guest user cannot send more than 20 messages/day', async () => {
|
||||
test("Guest user cannot send more than 20 messages/day", async () => {
|
||||
test.fixme();
|
||||
await chatPage.createNewChat();
|
||||
|
||||
for (let i = 0; i <= 20; i++) {
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.isGenerationComplete();
|
||||
}
|
||||
|
||||
await chatPage.sendUserMessage('Why is the sky blue?');
|
||||
await chatPage.sendUserMessage("Why is the sky blue?");
|
||||
await chatPage.expectToastToContain(
|
||||
getMessageByErrorCode('rate_limit:chat'),
|
||||
getMessageByErrorCode("rate_limit:chat")
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { expect as baseExpect, test as baseTest } from '@playwright/test';
|
||||
import { createAuthenticatedContext, type UserContext } from './helpers';
|
||||
import { getUnixTime } from 'date-fns';
|
||||
import { expect as baseExpect, test as baseTest } from "@playwright/test";
|
||||
import { getUnixTime } from "date-fns";
|
||||
import { createAuthenticatedContext, type UserContext } from "./helpers";
|
||||
|
||||
interface Fixtures {
|
||||
type Fixtures = {
|
||||
adaContext: UserContext;
|
||||
babbageContext: UserContext;
|
||||
curieContext: UserContext;
|
||||
}
|
||||
};
|
||||
|
||||
export const test = baseTest.extend<{}, Fixtures>({
|
||||
export const test = baseTest.extend<object, Fixtures>({
|
||||
adaContext: [
|
||||
async ({ browser }, use, workerInfo) => {
|
||||
const ada = await createAuthenticatedContext({
|
||||
|
|
@ -19,7 +19,7 @@ export const test = baseTest.extend<{}, Fixtures>({
|
|||
await use(ada);
|
||||
await ada.context.close();
|
||||
},
|
||||
{ scope: 'worker' },
|
||||
{ scope: "worker" },
|
||||
],
|
||||
babbageContext: [
|
||||
async ({ browser }, use, workerInfo) => {
|
||||
|
|
@ -31,20 +31,19 @@ export const test = baseTest.extend<{}, Fixtures>({
|
|||
await use(babbage);
|
||||
await babbage.context.close();
|
||||
},
|
||||
{ scope: 'worker' },
|
||||
{ scope: "worker" },
|
||||
],
|
||||
curieContext: [
|
||||
async ({ browser }, use, workerInfo) => {
|
||||
const curie = await createAuthenticatedContext({
|
||||
browser,
|
||||
name: `curie-${workerInfo.workerIndex}-${getUnixTime(new Date())}`,
|
||||
chatModel: 'chat-model-reasoning',
|
||||
});
|
||||
|
||||
await use(curie);
|
||||
await curie.context.close();
|
||||
},
|
||||
{ scope: 'worker' },
|
||||
{ scope: "worker" },
|
||||
],
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import {
|
||||
type APIRequestContext,
|
||||
type Browser,
|
||||
type BrowserContext,
|
||||
expect,
|
||||
type Page,
|
||||
} from '@playwright/test';
|
||||
import { generateId } from 'ai';
|
||||
import { ChatPage } from './pages/chat';
|
||||
import { getUnixTime } from 'date-fns';
|
||||
} from "@playwright/test";
|
||||
import { generateId } from "ai";
|
||||
import { getUnixTime } from "date-fns";
|
||||
import { ChatPage } from "./pages/chat";
|
||||
|
||||
export type UserContext = {
|
||||
context: BrowserContext;
|
||||
|
|
@ -20,13 +20,11 @@ export type UserContext = {
|
|||
export async function createAuthenticatedContext({
|
||||
browser,
|
||||
name,
|
||||
chatModel = 'chat-model',
|
||||
}: {
|
||||
browser: Browser;
|
||||
name: string;
|
||||
chatModel?: 'chat-model' | 'chat-model-reasoning';
|
||||
}): Promise<UserContext> {
|
||||
const directory = path.join(__dirname, '../playwright/.sessions');
|
||||
const directory = path.join(__dirname, "../playwright/.sessions");
|
||||
|
||||
if (!fs.existsSync(directory)) {
|
||||
fs.mkdirSync(directory, { recursive: true });
|
||||
|
|
@ -40,21 +38,21 @@ export async function createAuthenticatedContext({
|
|||
const email = `test-${name}@playwright.com`;
|
||||
const password = generateId();
|
||||
|
||||
await page.goto('http://localhost:3000/register');
|
||||
await page.getByPlaceholder('user@acme.com').click();
|
||||
await page.getByPlaceholder('user@acme.com').fill(email);
|
||||
await page.getByLabel('Password').click();
|
||||
await page.getByLabel('Password').fill(password);
|
||||
await page.getByRole('button', { name: 'Sign Up' }).click();
|
||||
await page.goto("http://localhost:3000/register");
|
||||
await page.getByPlaceholder("user@acme.com").click();
|
||||
await page.getByPlaceholder("user@acme.com").fill(email);
|
||||
await page.getByLabel("Password").click();
|
||||
await page.getByLabel("Password").fill(password);
|
||||
await page.getByRole("button", { name: "Sign Up" }).click();
|
||||
|
||||
await expect(page.getByTestId('toast')).toContainText(
|
||||
'Account created successfully!',
|
||||
await expect(page.getByTestId("toast")).toContainText(
|
||||
"Account created successfully!"
|
||||
);
|
||||
|
||||
const chatPage = new ChatPage(page);
|
||||
await chatPage.createNewChat();
|
||||
await chatPage.chooseModelFromSelector('chat-model-reasoning');
|
||||
await expect(chatPage.getSelectedModel()).resolves.toEqual('Reasoning model');
|
||||
await chatPage.chooseModelFromSelector("chat-model-reasoning");
|
||||
await expect(chatPage.getSelectedModel()).resolves.toEqual("Reasoning model");
|
||||
|
||||
await page.waitForTimeout(1000);
|
||||
await context.storageState({ path: storageFile });
|
||||
|
|
|
|||
|
|
@ -1,58 +1,66 @@
|
|||
import { expect, type Page } from '@playwright/test';
|
||||
import { expect, type Page } from "@playwright/test";
|
||||
|
||||
export class ArtifactPage {
|
||||
constructor(private page: Page) {}
|
||||
private readonly page: Page;
|
||||
|
||||
public get artifact() {
|
||||
return this.page.getByTestId('artifact');
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public get sendButton() {
|
||||
return this.artifact.getByTestId('send-button');
|
||||
get artifact() {
|
||||
return this.page.getByTestId("artifact");
|
||||
}
|
||||
|
||||
public get stopButton() {
|
||||
return this.page.getByTestId('stop-button');
|
||||
get sendButton() {
|
||||
return this.artifact.getByTestId("send-button");
|
||||
}
|
||||
|
||||
public get multimodalInput() {
|
||||
return this.page.getByTestId('multimodal-input');
|
||||
get stopButton() {
|
||||
return this.page.getByTestId("stop-button");
|
||||
}
|
||||
|
||||
get multimodalInput() {
|
||||
return this.page.getByTestId("multimodal-input");
|
||||
}
|
||||
|
||||
async isGenerationComplete() {
|
||||
const response = await this.page.waitForResponse((response) =>
|
||||
response.url().includes('/api/chat'),
|
||||
const response = await this.page.waitForResponse((currentResponse) =>
|
||||
currentResponse.url().includes("/api/chat")
|
||||
);
|
||||
|
||||
await response.finished();
|
||||
}
|
||||
|
||||
async sendUserMessage(message: string) {
|
||||
await this.artifact.getByTestId('multimodal-input').click();
|
||||
await this.artifact.getByTestId('multimodal-input').fill(message);
|
||||
await this.artifact.getByTestId('send-button').click();
|
||||
await this.artifact.getByTestId("multimodal-input").click();
|
||||
await this.artifact.getByTestId("multimodal-input").fill(message);
|
||||
await this.artifact.getByTestId("send-button").click();
|
||||
}
|
||||
|
||||
async getRecentAssistantMessage() {
|
||||
const messageElements = await this.artifact
|
||||
.getByTestId('message-assistant')
|
||||
.getByTestId("message-assistant")
|
||||
.all();
|
||||
const lastMessageElement = messageElements[messageElements.length - 1];
|
||||
const lastMessageElement = messageElements.at(-1);
|
||||
|
||||
if (!lastMessageElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = await lastMessageElement
|
||||
.getByTestId('message-content')
|
||||
.getByTestId("message-content")
|
||||
.innerText()
|
||||
.catch(() => null);
|
||||
|
||||
const reasoningElement = await lastMessageElement
|
||||
.getByTestId('message-reasoning')
|
||||
.getByTestId("message-reasoning")
|
||||
.isVisible()
|
||||
.then(async (visible) =>
|
||||
visible
|
||||
? await lastMessageElement
|
||||
.getByTestId('message-reasoning')
|
||||
.getByTestId("message-reasoning")
|
||||
.innerText()
|
||||
: null,
|
||||
: null
|
||||
)
|
||||
.catch(() => null);
|
||||
|
||||
|
|
@ -62,7 +70,7 @@ export class ArtifactPage {
|
|||
reasoning: reasoningElement,
|
||||
async toggleReasoningVisibility() {
|
||||
await lastMessageElement
|
||||
.getByTestId('message-reasoning-toggle')
|
||||
.getByTestId("message-reasoning-toggle")
|
||||
.click();
|
||||
},
|
||||
};
|
||||
|
|
@ -70,19 +78,23 @@ export class ArtifactPage {
|
|||
|
||||
async getRecentUserMessage() {
|
||||
const messageElements = await this.artifact
|
||||
.getByTestId('message-user')
|
||||
.getByTestId("message-user")
|
||||
.all();
|
||||
const lastMessageElement = messageElements[messageElements.length - 1];
|
||||
const lastMessageElement = messageElements.at(-1);
|
||||
|
||||
if (!lastMessageElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = await lastMessageElement.innerText();
|
||||
|
||||
const hasAttachments = await lastMessageElement
|
||||
.getByTestId('message-attachments')
|
||||
.getByTestId("message-attachments")
|
||||
.isVisible()
|
||||
.catch(() => false);
|
||||
|
||||
const attachments = hasAttachments
|
||||
? await lastMessageElement.getByTestId('message-attachments').all()
|
||||
? await lastMessageElement.getByTestId("message-attachments").all()
|
||||
: [];
|
||||
|
||||
const page = this.artifact;
|
||||
|
|
@ -92,17 +104,17 @@ export class ArtifactPage {
|
|||
content,
|
||||
attachments,
|
||||
async edit(newMessage: string) {
|
||||
await page.getByTestId('message-edit-button').click();
|
||||
await page.getByTestId('message-editor').fill(newMessage);
|
||||
await page.getByTestId('message-editor-send-button').click();
|
||||
await page.getByTestId("message-edit-button").click();
|
||||
await page.getByTestId("message-editor").fill(newMessage);
|
||||
await page.getByTestId("message-editor-send-button").click();
|
||||
await expect(
|
||||
page.getByTestId('message-editor-send-button'),
|
||||
page.getByTestId("message-editor-send-button")
|
||||
).not.toBeVisible();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async closeArtifact() {
|
||||
return this.page.getByTestId('artifact-close-button').click();
|
||||
closeArtifact() {
|
||||
return this.page.getByTestId("artifact-close-button").click();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,65 +1,69 @@
|
|||
import type { Page } from '@playwright/test';
|
||||
import { expect } from '../fixtures';
|
||||
import type { Page } from "@playwright/test";
|
||||
import { expect } from "../fixtures";
|
||||
|
||||
export class AuthPage {
|
||||
constructor(private page: Page) {}
|
||||
private readonly page: Page;
|
||||
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async gotoLogin() {
|
||||
await this.page.goto('/login');
|
||||
await expect(this.page.getByRole('heading')).toContainText('Sign In');
|
||||
await this.page.goto("/login");
|
||||
await expect(this.page.getByRole("heading")).toContainText("Sign In");
|
||||
}
|
||||
|
||||
async gotoRegister() {
|
||||
await this.page.goto('/register');
|
||||
await expect(this.page.getByRole('heading')).toContainText('Sign Up');
|
||||
await this.page.goto("/register");
|
||||
await expect(this.page.getByRole("heading")).toContainText("Sign Up");
|
||||
}
|
||||
|
||||
async register(email: string, password: string) {
|
||||
await this.gotoRegister();
|
||||
await this.page.getByPlaceholder('user@acme.com').click();
|
||||
await this.page.getByPlaceholder('user@acme.com').fill(email);
|
||||
await this.page.getByLabel('Password').click();
|
||||
await this.page.getByLabel('Password').fill(password);
|
||||
await this.page.getByRole('button', { name: 'Sign Up' }).click();
|
||||
await this.page.getByPlaceholder("user@acme.com").click();
|
||||
await this.page.getByPlaceholder("user@acme.com").fill(email);
|
||||
await this.page.getByLabel("Password").click();
|
||||
await this.page.getByLabel("Password").fill(password);
|
||||
await this.page.getByRole("button", { name: "Sign Up" }).click();
|
||||
}
|
||||
|
||||
async login(email: string, password: string) {
|
||||
await this.gotoLogin();
|
||||
await this.page.getByPlaceholder('user@acme.com').click();
|
||||
await this.page.getByPlaceholder('user@acme.com').fill(email);
|
||||
await this.page.getByLabel('Password').click();
|
||||
await this.page.getByLabel('Password').fill(password);
|
||||
await this.page.getByRole('button', { name: 'Sign In' }).click();
|
||||
await this.page.getByPlaceholder("user@acme.com").click();
|
||||
await this.page.getByPlaceholder("user@acme.com").fill(email);
|
||||
await this.page.getByLabel("Password").click();
|
||||
await this.page.getByLabel("Password").fill(password);
|
||||
await this.page.getByRole("button", { name: "Sign In" }).click();
|
||||
}
|
||||
|
||||
async logout(email: string, password: string) {
|
||||
await this.login(email, password);
|
||||
await this.page.waitForURL('/');
|
||||
await this.page.waitForURL("/");
|
||||
|
||||
await this.openSidebar();
|
||||
|
||||
const userNavButton = this.page.getByTestId('user-nav-button');
|
||||
const userNavButton = this.page.getByTestId("user-nav-button");
|
||||
await expect(userNavButton).toBeVisible();
|
||||
|
||||
await userNavButton.click();
|
||||
const userNavMenu = this.page.getByTestId('user-nav-menu');
|
||||
const userNavMenu = this.page.getByTestId("user-nav-menu");
|
||||
await expect(userNavMenu).toBeVisible();
|
||||
|
||||
const authMenuItem = this.page.getByTestId('user-nav-item-auth');
|
||||
await expect(authMenuItem).toContainText('Sign out');
|
||||
const authMenuItem = this.page.getByTestId("user-nav-item-auth");
|
||||
await expect(authMenuItem).toContainText("Sign out");
|
||||
|
||||
await authMenuItem.click();
|
||||
|
||||
const userEmail = this.page.getByTestId('user-email');
|
||||
await expect(userEmail).toContainText('Guest');
|
||||
const userEmail = this.page.getByTestId("user-email");
|
||||
await expect(userEmail).toContainText("Guest");
|
||||
}
|
||||
|
||||
async expectToastToContain(text: string) {
|
||||
await expect(this.page.getByTestId('toast')).toContainText(text);
|
||||
await expect(this.page.getByTestId("toast")).toContainText(text);
|
||||
}
|
||||
|
||||
async openSidebar() {
|
||||
const sidebarToggleButton = this.page.getByTestId('sidebar-toggle-button');
|
||||
const sidebarToggleButton = this.page.getByTestId("sidebar-toggle-button");
|
||||
await sidebarToggleButton.click();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,36 +1,43 @@
|
|||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { chatModels } from '@/lib/ai/models';
|
||||
import { expect, type Page } from '@playwright/test';
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { expect, type Page } from "@playwright/test";
|
||||
import { chatModels } from "@/lib/ai/models";
|
||||
|
||||
const CHAT_ID_REGEX =
|
||||
/^http:\/\/localhost:3000\/chat\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;
|
||||
|
||||
export class ChatPage {
|
||||
constructor(private page: Page) {}
|
||||
private readonly page: Page;
|
||||
|
||||
public get sendButton() {
|
||||
return this.page.getByTestId('send-button');
|
||||
constructor(page: Page) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
public get stopButton() {
|
||||
return this.page.getByTestId('stop-button');
|
||||
get sendButton() {
|
||||
return this.page.getByTestId("send-button");
|
||||
}
|
||||
|
||||
public get multimodalInput() {
|
||||
return this.page.getByTestId('multimodal-input');
|
||||
get stopButton() {
|
||||
return this.page.getByTestId("stop-button");
|
||||
}
|
||||
|
||||
public get scrollContainer() {
|
||||
return this.page.locator('.overflow-y-scroll');
|
||||
get multimodalInput() {
|
||||
return this.page.getByTestId("multimodal-input");
|
||||
}
|
||||
|
||||
public get scrollToBottomButton() {
|
||||
return this.page.getByTestId('scroll-to-bottom-button');
|
||||
get scrollContainer() {
|
||||
return this.page.locator(".overflow-y-scroll");
|
||||
}
|
||||
|
||||
get scrollToBottomButton() {
|
||||
return this.page.getByTestId("scroll-to-bottom-button");
|
||||
}
|
||||
|
||||
async createNewChat() {
|
||||
await this.page.goto('/');
|
||||
await this.page.goto("/");
|
||||
}
|
||||
|
||||
public getCurrentURL(): string {
|
||||
getCurrentURL(): string {
|
||||
return this.page.url();
|
||||
}
|
||||
|
||||
|
|
@ -41,30 +48,28 @@ export class ChatPage {
|
|||
}
|
||||
|
||||
async isGenerationComplete() {
|
||||
const response = await this.page.waitForResponse((response) =>
|
||||
response.url().includes('/api/chat'),
|
||||
const response = await this.page.waitForResponse((currentResponse) =>
|
||||
currentResponse.url().includes("/api/chat")
|
||||
);
|
||||
|
||||
await response.finished();
|
||||
}
|
||||
|
||||
async isVoteComplete() {
|
||||
const response = await this.page.waitForResponse((response) =>
|
||||
response.url().includes('/api/vote'),
|
||||
const response = await this.page.waitForResponse((currentResponse) =>
|
||||
currentResponse.url().includes("/api/vote")
|
||||
);
|
||||
|
||||
await response.finished();
|
||||
}
|
||||
|
||||
async hasChatIdInUrl() {
|
||||
await expect(this.page).toHaveURL(
|
||||
/^http:\/\/localhost:3000\/chat\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/,
|
||||
);
|
||||
await expect(this.page).toHaveURL(CHAT_ID_REGEX);
|
||||
}
|
||||
|
||||
async sendUserMessageFromSuggestion() {
|
||||
await this.page
|
||||
.getByRole('button', { name: 'What are the advantages of' })
|
||||
.getByRole("button", { name: "What are the advantages of" })
|
||||
.click();
|
||||
}
|
||||
|
||||
|
|
@ -77,55 +82,53 @@ export class ChatPage {
|
|||
}
|
||||
|
||||
async addImageAttachment() {
|
||||
this.page.on('filechooser', async (fileChooser) => {
|
||||
this.page.on("filechooser", async (fileChooser) => {
|
||||
const filePath = path.join(
|
||||
process.cwd(),
|
||||
'public',
|
||||
'images',
|
||||
'mouth of the seine, monet.jpg',
|
||||
"public",
|
||||
"images",
|
||||
"mouth of the seine, monet.jpg"
|
||||
);
|
||||
const imageBuffer = fs.readFileSync(filePath);
|
||||
|
||||
await fileChooser.setFiles({
|
||||
name: 'mouth of the seine, monet.jpg',
|
||||
mimeType: 'image/jpeg',
|
||||
name: "mouth of the seine, monet.jpg",
|
||||
mimeType: "image/jpeg",
|
||||
buffer: imageBuffer,
|
||||
});
|
||||
});
|
||||
|
||||
await this.page.getByTestId('attachments-button').click();
|
||||
await this.page.getByTestId("attachments-button").click();
|
||||
}
|
||||
|
||||
public async getSelectedModel() {
|
||||
const modelId = await this.page.getByTestId('model-selector').innerText();
|
||||
async getSelectedModel() {
|
||||
const modelId = await this.page.getByTestId("model-selector").innerText();
|
||||
return modelId;
|
||||
}
|
||||
|
||||
public async chooseModelFromSelector(chatModelId: string) {
|
||||
async chooseModelFromSelector(chatModelId: string) {
|
||||
const chatModel = chatModels.find(
|
||||
(chatModel) => chatModel.id === chatModelId,
|
||||
(currentChatModel) => currentChatModel.id === chatModelId
|
||||
);
|
||||
|
||||
if (!chatModel) {
|
||||
throw new Error(`Model with id ${chatModelId} not found`);
|
||||
}
|
||||
|
||||
await this.page.getByTestId('model-selector').click();
|
||||
await this.page.getByTestId("model-selector").click();
|
||||
await this.page.getByTestId(`model-selector-item-${chatModelId}`).click();
|
||||
expect(await this.getSelectedModel()).toBe(chatModel.name);
|
||||
}
|
||||
|
||||
public async getSelectedVisibility() {
|
||||
async getSelectedVisibility() {
|
||||
const visibilityId = await this.page
|
||||
.getByTestId('visibility-selector')
|
||||
.getByTestId("visibility-selector")
|
||||
.innerText();
|
||||
return visibilityId;
|
||||
}
|
||||
|
||||
public async chooseVisibilityFromSelector(
|
||||
chatVisibility: 'public' | 'private',
|
||||
) {
|
||||
await this.page.getByTestId('visibility-selector').click();
|
||||
async chooseVisibilityFromSelector(chatVisibility: "public" | "private") {
|
||||
await this.page.getByTestId("visibility-selector").click();
|
||||
await this.page
|
||||
.getByTestId(`visibility-selector-item-${chatVisibility}`)
|
||||
.click();
|
||||
|
|
@ -134,24 +137,28 @@ export class ChatPage {
|
|||
|
||||
async getRecentAssistantMessage() {
|
||||
const messageElements = await this.page
|
||||
.getByTestId('message-assistant')
|
||||
.getByTestId("message-assistant")
|
||||
.all();
|
||||
const lastMessageElement = messageElements[messageElements.length - 1];
|
||||
const lastMessageElement = messageElements.at(-1);
|
||||
|
||||
if (!lastMessageElement) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const content = await lastMessageElement
|
||||
.getByTestId('message-content')
|
||||
.getByTestId("message-content")
|
||||
.innerText()
|
||||
.catch(() => null);
|
||||
|
||||
const reasoningElement = await lastMessageElement
|
||||
.getByTestId('message-reasoning')
|
||||
.getByTestId("message-reasoning")
|
||||
.isVisible()
|
||||
.then(async (visible) =>
|
||||
visible
|
||||
? await lastMessageElement
|
||||
.getByTestId('message-reasoning')
|
||||
.getByTestId("message-reasoning")
|
||||
.innerText()
|
||||
: null,
|
||||
: null
|
||||
)
|
||||
.catch(() => null);
|
||||
|
||||
|
|
@ -161,38 +168,38 @@ export class ChatPage {
|
|||
reasoning: reasoningElement,
|
||||
async toggleReasoningVisibility() {
|
||||
await lastMessageElement
|
||||
.getByTestId('message-reasoning-toggle')
|
||||
.getByTestId("message-reasoning-toggle")
|
||||
.click();
|
||||
},
|
||||
async upvote() {
|
||||
await lastMessageElement.getByTestId('message-upvote').click();
|
||||
await lastMessageElement.getByTestId("message-upvote").click();
|
||||
},
|
||||
async downvote() {
|
||||
await lastMessageElement.getByTestId('message-downvote').click();
|
||||
await lastMessageElement.getByTestId("message-downvote").click();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async getRecentUserMessage() {
|
||||
const messageElements = await this.page.getByTestId('message-user').all();
|
||||
const messageElements = await this.page.getByTestId("message-user").all();
|
||||
const lastMessageElement = messageElements.at(-1);
|
||||
|
||||
if (!lastMessageElement) {
|
||||
throw new Error('No user message found');
|
||||
throw new Error("No user message found");
|
||||
}
|
||||
|
||||
const content = await lastMessageElement
|
||||
.getByTestId('message-content')
|
||||
.getByTestId("message-content")
|
||||
.innerText()
|
||||
.catch(() => null);
|
||||
|
||||
const hasAttachments = await lastMessageElement
|
||||
.getByTestId('message-attachments')
|
||||
.getByTestId("message-attachments")
|
||||
.isVisible()
|
||||
.catch(() => false);
|
||||
|
||||
const attachments = hasAttachments
|
||||
? await lastMessageElement.getByTestId('message-attachments').all()
|
||||
? await lastMessageElement.getByTestId("message-attachments").all()
|
||||
: [];
|
||||
|
||||
const page = this.page;
|
||||
|
|
@ -202,45 +209,47 @@ export class ChatPage {
|
|||
content,
|
||||
attachments,
|
||||
async edit(newMessage: string) {
|
||||
await page.getByTestId('message-edit-button').click();
|
||||
await page.getByTestId('message-editor').fill(newMessage);
|
||||
await page.getByTestId('message-editor-send-button').click();
|
||||
await page.getByTestId("message-edit-button").click();
|
||||
await page.getByTestId("message-editor").fill(newMessage);
|
||||
await page.getByTestId("message-editor-send-button").click();
|
||||
await expect(
|
||||
page.getByTestId('message-editor-send-button'),
|
||||
page.getByTestId("message-editor-send-button")
|
||||
).not.toBeVisible();
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
async expectToastToContain(text: string) {
|
||||
await expect(this.page.getByTestId('toast')).toContainText(text);
|
||||
await expect(this.page.getByTestId("toast")).toContainText(text);
|
||||
}
|
||||
|
||||
async openSideBar() {
|
||||
const sidebarToggleButton = this.page.getByTestId('sidebar-toggle-button');
|
||||
const sidebarToggleButton = this.page.getByTestId("sidebar-toggle-button");
|
||||
await sidebarToggleButton.click();
|
||||
}
|
||||
|
||||
public async isScrolledToBottom(): Promise<boolean> {
|
||||
isScrolledToBottom(): Promise<boolean> {
|
||||
return this.scrollContainer.evaluate(
|
||||
(el) => Math.abs(el.scrollHeight - el.scrollTop - el.clientHeight) < 1,
|
||||
(el) => Math.abs(el.scrollHeight - el.scrollTop - el.clientHeight) < 1
|
||||
);
|
||||
}
|
||||
|
||||
public async waitForScrollToBottom(timeout = 5_000): Promise<void> {
|
||||
async waitForScrollToBottom(timeout = 5000): Promise<void> {
|
||||
const start = Date.now();
|
||||
|
||||
while (Date.now() - start < timeout) {
|
||||
if (await this.isScrolledToBottom()) return;
|
||||
if (await this.isScrolledToBottom()) {
|
||||
return;
|
||||
}
|
||||
await this.page.waitForTimeout(100);
|
||||
}
|
||||
|
||||
throw new Error(`Timed out waiting for scroll bottom after ${timeout}ms`);
|
||||
}
|
||||
|
||||
public async sendMultipleMessages(
|
||||
async sendMultipleMessages(
|
||||
count: number,
|
||||
makeMessage: (i: number) => string,
|
||||
makeMessage: (i: number) => string
|
||||
) {
|
||||
for (let i = 0; i < count; i++) {
|
||||
await this.sendUserMessage(makeMessage(i));
|
||||
|
|
@ -248,7 +257,7 @@ export class ChatPage {
|
|||
}
|
||||
}
|
||||
|
||||
public async scrollToTop(): Promise<void> {
|
||||
async scrollToTop(): Promise<void> {
|
||||
await this.scrollContainer.evaluate((element) => {
|
||||
element.scrollTop = 0;
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,143 +1,143 @@
|
|||
import type { ModelMessage } from 'ai';
|
||||
import type { ModelMessage } from "ai";
|
||||
|
||||
export const TEST_PROMPTS: Record<string, ModelMessage> = {
|
||||
USER_SKY: {
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: 'Why is the sky blue?' }],
|
||||
role: "user",
|
||||
content: [{ type: "text", text: "Why is the sky blue?" }],
|
||||
},
|
||||
USER_GRASS: {
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: 'Why is grass green?' }],
|
||||
role: "user",
|
||||
content: [{ type: "text", text: "Why is grass green?" }],
|
||||
},
|
||||
USER_THANKS: {
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: 'Thanks!' }],
|
||||
role: "user",
|
||||
content: [{ type: "text", text: "Thanks!" }],
|
||||
},
|
||||
USER_NEXTJS: {
|
||||
role: 'user',
|
||||
role: "user",
|
||||
content: [
|
||||
{ type: 'text', text: 'What are the advantages of using Next.js?' },
|
||||
{ type: "text", text: "What are the advantages of using Next.js?" },
|
||||
],
|
||||
},
|
||||
USER_IMAGE_ATTACHMENT: {
|
||||
role: 'user',
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: 'file',
|
||||
mediaType: '...',
|
||||
data: '...',
|
||||
type: "file",
|
||||
mediaType: "...",
|
||||
data: "...",
|
||||
},
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Who painted this?',
|
||||
type: "text",
|
||||
text: "Who painted this?",
|
||||
},
|
||||
],
|
||||
},
|
||||
USER_TEXT_ARTIFACT: {
|
||||
role: 'user',
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Help me write an essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Help me write an essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
},
|
||||
CREATE_DOCUMENT_TEXT_CALL: {
|
||||
role: 'user',
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
},
|
||||
CREATE_DOCUMENT_TEXT_RESULT: {
|
||||
role: 'tool',
|
||||
role: "tool",
|
||||
content: [
|
||||
{
|
||||
type: 'tool-result',
|
||||
toolCallId: 'call_123',
|
||||
toolName: 'createDocument',
|
||||
type: "tool-result",
|
||||
toolCallId: "call_123",
|
||||
toolName: "createDocument",
|
||||
output: {
|
||||
type: 'json',
|
||||
type: "json",
|
||||
value: {
|
||||
id: '3ca386a4-40c6-4630-8ed1-84cbd46cc7eb',
|
||||
title: 'Essay about Silicon Valley',
|
||||
kind: 'text',
|
||||
content: 'A document was created and is now visible to the user.',
|
||||
id: "3ca386a4-40c6-4630-8ed1-84cbd46cc7eb",
|
||||
title: "Essay about Silicon Valley",
|
||||
kind: "text",
|
||||
content: "A document was created and is now visible to the user.",
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
GET_WEATHER_CALL: {
|
||||
role: 'user',
|
||||
role: "user",
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
type: "text",
|
||||
text: "What's the weather in sf?",
|
||||
},
|
||||
],
|
||||
},
|
||||
GET_WEATHER_RESULT: {
|
||||
role: 'tool',
|
||||
role: "tool",
|
||||
content: [
|
||||
{
|
||||
type: 'tool-result',
|
||||
toolCallId: 'call_456',
|
||||
toolName: 'getWeather',
|
||||
type: "tool-result",
|
||||
toolCallId: "call_456",
|
||||
toolName: "getWeather",
|
||||
output: {
|
||||
type: 'json',
|
||||
type: "json",
|
||||
value: {
|
||||
latitude: 37.763283,
|
||||
longitude: -122.41286,
|
||||
generationtime_ms: 0.06449222564697266,
|
||||
utc_offset_seconds: -25200,
|
||||
timezone: 'America/Los_Angeles',
|
||||
timezone_abbreviation: 'GMT-7',
|
||||
latitude: 37.763_283,
|
||||
longitude: -122.412_86,
|
||||
generationtime_ms: 0.064_492_225_646_972_66,
|
||||
utc_offset_seconds: -25_200,
|
||||
timezone: "America/Los_Angeles",
|
||||
timezone_abbreviation: "GMT-7",
|
||||
elevation: 18,
|
||||
current_units: {
|
||||
time: 'iso8601',
|
||||
interval: 'seconds',
|
||||
temperature_2m: '°C',
|
||||
time: "iso8601",
|
||||
interval: "seconds",
|
||||
temperature_2m: "°C",
|
||||
},
|
||||
current: {
|
||||
time: '2025-03-10T14:00',
|
||||
time: "2025-03-10T14:00",
|
||||
interval: 900,
|
||||
temperature_2m: 17,
|
||||
},
|
||||
daily_units: {
|
||||
time: 'iso8601',
|
||||
sunrise: 'iso8601',
|
||||
sunset: 'iso8601',
|
||||
time: "iso8601",
|
||||
sunrise: "iso8601",
|
||||
sunset: "iso8601",
|
||||
},
|
||||
daily: {
|
||||
time: [
|
||||
'2025-03-10',
|
||||
'2025-03-11',
|
||||
'2025-03-12',
|
||||
'2025-03-13',
|
||||
'2025-03-14',
|
||||
'2025-03-15',
|
||||
'2025-03-16',
|
||||
"2025-03-10",
|
||||
"2025-03-11",
|
||||
"2025-03-12",
|
||||
"2025-03-13",
|
||||
"2025-03-14",
|
||||
"2025-03-15",
|
||||
"2025-03-16",
|
||||
],
|
||||
sunrise: [
|
||||
'2025-03-10T07:27',
|
||||
'2025-03-11T07:25',
|
||||
'2025-03-12T07:24',
|
||||
'2025-03-13T07:22',
|
||||
'2025-03-14T07:21',
|
||||
'2025-03-15T07:19',
|
||||
'2025-03-16T07:18',
|
||||
"2025-03-10T07:27",
|
||||
"2025-03-11T07:25",
|
||||
"2025-03-12T07:24",
|
||||
"2025-03-13T07:22",
|
||||
"2025-03-14T07:21",
|
||||
"2025-03-15T07:19",
|
||||
"2025-03-16T07:18",
|
||||
],
|
||||
sunset: [
|
||||
'2025-03-10T19:12',
|
||||
'2025-03-11T19:13',
|
||||
'2025-03-12T19:14',
|
||||
'2025-03-13T19:15',
|
||||
'2025-03-14T19:16',
|
||||
'2025-03-15T19:17',
|
||||
'2025-03-16T19:17',
|
||||
"2025-03-10T19:12",
|
||||
"2025-03-11T19:13",
|
||||
"2025-03-12T19:14",
|
||||
"2025-03-13T19:15",
|
||||
"2025-03-14T19:16",
|
||||
"2025-03-15T19:17",
|
||||
"2025-03-16T19:17",
|
||||
],
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { generateUUID } from '@/lib/utils';
|
||||
import { generateUUID } from "@/lib/utils";
|
||||
|
||||
export const TEST_PROMPTS = {
|
||||
SKY: {
|
||||
MESSAGE: {
|
||||
id: generateUUID(),
|
||||
createdAt: new Date().toISOString(),
|
||||
role: 'user',
|
||||
content: 'Why is the sky blue?',
|
||||
parts: [{ type: 'text', text: 'Why is the sky blue?' }],
|
||||
role: "user",
|
||||
content: "Why is the sky blue?",
|
||||
parts: [{ type: "text", text: "Why is the sky blue?" }],
|
||||
},
|
||||
OUTPUT_STREAM: [
|
||||
'data: {"type":"start-step"}',
|
||||
|
|
@ -19,16 +19,16 @@ export const TEST_PROMPTS = {
|
|||
'data: {"type":"text-end","id":"STATIC_ID"}',
|
||||
'data: {"type":"finish-step"}',
|
||||
'data: {"type":"finish"}',
|
||||
'data: [DONE]',
|
||||
"data: [DONE]",
|
||||
],
|
||||
},
|
||||
GRASS: {
|
||||
MESSAGE: {
|
||||
id: generateUUID(),
|
||||
createdAt: new Date().toISOString(),
|
||||
role: 'user',
|
||||
content: 'Why is grass green?',
|
||||
parts: [{ type: 'text', text: 'Why is grass green?' }],
|
||||
role: "user",
|
||||
content: "Why is grass green?",
|
||||
parts: [{ type: "text", text: "Why is grass green?" }],
|
||||
},
|
||||
OUTPUT_STREAM: [
|
||||
'data: {"type":"start-step"}',
|
||||
|
|
@ -40,7 +40,7 @@ export const TEST_PROMPTS = {
|
|||
'data: {"type":"text-end","id":"STATIC_ID"}',
|
||||
'data: {"type":"finish-step"}',
|
||||
'data: {"type":"finish"}',
|
||||
'data: [DONE]',
|
||||
"data: [DONE]",
|
||||
],
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import { generateId, type ModelMessage } from 'ai';
|
||||
import { TEST_PROMPTS } from './basic';
|
||||
import type { LanguageModelV2StreamPart } from '@ai-sdk/provider';
|
||||
import type { LanguageModelV2StreamPart } from "@ai-sdk/provider";
|
||||
import { generateId, type ModelMessage } from "ai";
|
||||
import { TEST_PROMPTS } from "./basic";
|
||||
|
||||
export function compareMessages(
|
||||
firstMessage: ModelMessage,
|
||||
secondMessage: ModelMessage,
|
||||
secondMessage: ModelMessage
|
||||
): boolean {
|
||||
if (firstMessage.role !== secondMessage.role) return false;
|
||||
if (firstMessage.role !== secondMessage.role) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (
|
||||
!Array.isArray(firstMessage.content) ||
|
||||
|
|
@ -23,15 +25,21 @@ export function compareMessages(
|
|||
const item1 = firstMessage.content[i];
|
||||
const item2 = secondMessage.content[i];
|
||||
|
||||
if (item1.type !== item2.type) return false;
|
||||
if (item1.type !== item2.type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (item1.type === 'file' && item2.type === 'file') {
|
||||
if (item1.type === "file" && item2.type === "file") {
|
||||
// if (item1.image.toString() !== item2.image.toString()) return false;
|
||||
// if (item1.mimeType !== item2.mimeType) return false;
|
||||
} else if (item1.type === 'text' && item2.type === 'text') {
|
||||
if (item1.text !== item2.text) return false;
|
||||
} else if (item1.type === 'tool-result' && item2.type === 'tool-result') {
|
||||
if (item1.toolCallId !== item2.toolCallId) return false;
|
||||
} else if (item1.type === "text" && item2.type === "text") {
|
||||
if (item1.text !== item2.text) {
|
||||
return false;
|
||||
}
|
||||
} else if (item1.type === "tool-result" && item2.type === "tool-result") {
|
||||
if (item1.toolCallId !== item2.toolCallId) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -43,61 +51,63 @@ export function compareMessages(
|
|||
const textToDeltas = (text: string): LanguageModelV2StreamPart[] => {
|
||||
const id = generateId();
|
||||
|
||||
const deltas = text.split(' ').map((char) => ({
|
||||
const deltas = text.split(" ").map((char) => ({
|
||||
id,
|
||||
type: 'text-delta' as const,
|
||||
type: "text-delta" as const,
|
||||
delta: `${char} `,
|
||||
}));
|
||||
|
||||
return [{ id, type: 'text-start' }, ...deltas, { id, type: 'text-end' }];
|
||||
return [{ id, type: "text-start" }, ...deltas, { id, type: "text-end" }];
|
||||
};
|
||||
|
||||
const reasoningToDeltas = (text: string): LanguageModelV2StreamPart[] => {
|
||||
const id = generateId();
|
||||
|
||||
const deltas = text.split(' ').map((char) => ({
|
||||
const deltas = text.split(" ").map((char) => ({
|
||||
id,
|
||||
type: 'reasoning-delta' as const,
|
||||
type: "reasoning-delta" as const,
|
||||
delta: `${char} `,
|
||||
}));
|
||||
|
||||
return [
|
||||
{ id, type: 'reasoning-start' },
|
||||
{ id, type: "reasoning-start" },
|
||||
...deltas,
|
||||
{ id, type: 'reasoning-end' },
|
||||
{ id, type: "reasoning-end" },
|
||||
];
|
||||
};
|
||||
|
||||
export const getResponseChunksByPrompt = (
|
||||
prompt: ModelMessage[],
|
||||
isReasoningEnabled = false,
|
||||
isReasoningEnabled = false
|
||||
): LanguageModelV2StreamPart[] => {
|
||||
const recentMessage = prompt.at(-1);
|
||||
|
||||
if (!recentMessage) {
|
||||
throw new Error('No recent message found!');
|
||||
throw new Error("No recent message found!");
|
||||
}
|
||||
|
||||
if (isReasoningEnabled) {
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_SKY)) {
|
||||
return [
|
||||
...reasoningToDeltas('The sky is blue because of rayleigh scattering!'),
|
||||
...reasoningToDeltas("The sky is blue because of rayleigh scattering!"),
|
||||
...textToDeltas("It's just blue duh!"),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.USER_GRASS)) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_GRASS)) {
|
||||
return [
|
||||
...reasoningToDeltas(
|
||||
'Grass is green because of chlorophyll absorption!',
|
||||
"Grass is green because of chlorophyll absorption!"
|
||||
),
|
||||
...textToDeltas("It's just green duh!"),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
|
|
@ -108,90 +118,98 @@ export const getResponseChunksByPrompt = (
|
|||
return [
|
||||
...textToDeltas("You're welcome!"),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.USER_GRASS)) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_GRASS)) {
|
||||
return [
|
||||
...textToDeltas("It's just green duh!"),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.USER_SKY)) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_SKY)) {
|
||||
return [
|
||||
...textToDeltas("It's just blue duh!"),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.USER_NEXTJS)) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_NEXTJS)) {
|
||||
return [
|
||||
...textToDeltas('With Next.js, you can ship fast!'),
|
||||
...textToDeltas("With Next.js, you can ship fast!"),
|
||||
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (
|
||||
compareMessages(recentMessage, TEST_PROMPTS.USER_IMAGE_ATTACHMENT)
|
||||
) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_IMAGE_ATTACHMENT)) {
|
||||
return [
|
||||
...textToDeltas('This painting is by Monet!'),
|
||||
...textToDeltas("This painting is by Monet!"),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.USER_TEXT_ARTIFACT)) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.USER_TEXT_ARTIFACT)) {
|
||||
const toolCallId = generateId();
|
||||
|
||||
return [
|
||||
{
|
||||
id: toolCallId,
|
||||
type: 'tool-input-start',
|
||||
toolName: 'createDocument',
|
||||
type: "tool-input-start",
|
||||
toolName: "createDocument",
|
||||
},
|
||||
{
|
||||
id: toolCallId,
|
||||
type: 'tool-input-delta',
|
||||
type: "tool-input-delta",
|
||||
delta: JSON.stringify({
|
||||
title: 'Essay about Silicon Valley',
|
||||
kind: 'text',
|
||||
title: "Essay about Silicon Valley",
|
||||
kind: "text",
|
||||
}),
|
||||
},
|
||||
{
|
||||
id: toolCallId,
|
||||
type: 'tool-input-end',
|
||||
type: "tool-input-end",
|
||||
},
|
||||
{
|
||||
toolCallId: toolCallId,
|
||||
type: 'tool-result',
|
||||
toolName: 'createDocument',
|
||||
toolCallId,
|
||||
type: "tool-result",
|
||||
toolName: "createDocument",
|
||||
result: {
|
||||
id: 'doc_123',
|
||||
title: 'Essay about Silicon Valley',
|
||||
kind: 'text',
|
||||
id: "doc_123",
|
||||
title: "Essay about Silicon Valley",
|
||||
kind: "text",
|
||||
},
|
||||
},
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (
|
||||
compareMessages(recentMessage, TEST_PROMPTS.CREATE_DOCUMENT_TEXT_CALL)
|
||||
) {
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.CREATE_DOCUMENT_TEXT_CALL)) {
|
||||
return [
|
||||
...textToDeltas(`\n
|
||||
# Silicon Valley: The Epicenter of Innovation
|
||||
|
|
@ -213,46 +231,52 @@ Despite its remarkable success, Silicon Valley faces significant challenges incl
|
|||
As we move forward, Silicon Valley continues to reinvent itself. While some predict its decline due to remote work trends and competition from other tech hubs, the region's adaptability and innovative spirit suggest it will remain influential in shaping our technological future for decades to come.
|
||||
`),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (
|
||||
compareMessages(recentMessage, TEST_PROMPTS.CREATE_DOCUMENT_TEXT_RESULT)
|
||||
) {
|
||||
return [
|
||||
...textToDeltas('A document was created and is now visible to the user.'),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.GET_WEATHER_CALL)) {
|
||||
return [
|
||||
{
|
||||
type: 'tool-call',
|
||||
toolCallId: 'call_456',
|
||||
toolName: 'getWeather',
|
||||
input: JSON.stringify({ latitude: 37.7749, longitude: -122.4194 }),
|
||||
},
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
} else if (compareMessages(recentMessage, TEST_PROMPTS.GET_WEATHER_RESULT)) {
|
||||
return [
|
||||
...textToDeltas('The current temperature in San Francisco is 17°C.'),
|
||||
{
|
||||
type: 'finish',
|
||||
finishReason: 'stop',
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [{ id: '6', type: 'text-delta', delta: 'Unknown test prompt!' }];
|
||||
if (
|
||||
compareMessages(recentMessage, TEST_PROMPTS.CREATE_DOCUMENT_TEXT_RESULT)
|
||||
) {
|
||||
return [
|
||||
...textToDeltas("A document was created and is now visible to the user."),
|
||||
{
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.GET_WEATHER_CALL)) {
|
||||
return [
|
||||
{
|
||||
type: "tool-call",
|
||||
toolCallId: "call_456",
|
||||
toolName: "getWeather",
|
||||
input: JSON.stringify({ latitude: 37.7749, longitude: -122.4194 }),
|
||||
},
|
||||
{
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (compareMessages(recentMessage, TEST_PROMPTS.GET_WEATHER_RESULT)) {
|
||||
return [
|
||||
...textToDeltas("The current temperature in San Francisco is 17°C."),
|
||||
{
|
||||
type: "finish",
|
||||
finishReason: "stop",
|
||||
usage: { inputTokens: 3, outputTokens: 10, totalTokens: 13 },
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
return [{ id: "6", type: "text-delta", delta: "Unknown test prompt!" }];
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,19 +1,19 @@
|
|||
import { generateUUID } from '@/lib/utils';
|
||||
import { expect, test } from '../fixtures';
|
||||
import { TEST_PROMPTS } from '../prompts/routes';
|
||||
import { getMessageByErrorCode } from '@/lib/errors';
|
||||
import { getMessageByErrorCode } from "@/lib/errors";
|
||||
import { generateUUID } from "@/lib/utils";
|
||||
import { expect, test } from "../fixtures";
|
||||
import { TEST_PROMPTS } from "../prompts/routes";
|
||||
|
||||
const chatIdsCreatedByAda: Array<string> = [];
|
||||
const chatIdsCreatedByAda: string[] = [];
|
||||
|
||||
// Helper function to normalize stream data for comparison
|
||||
function normalizeStreamData(lines: string[]): string[] {
|
||||
return lines.map((line) => {
|
||||
if (line.startsWith('data: ')) {
|
||||
if (line.startsWith("data: ")) {
|
||||
try {
|
||||
const data = JSON.parse(line.slice(6)); // Remove 'data: ' prefix
|
||||
if (data.id) {
|
||||
// Replace dynamic id with a static one for comparison
|
||||
return `data: ${JSON.stringify({ ...data, id: 'STATIC_ID' })}`;
|
||||
return `data: ${JSON.stringify({ ...data, id: "STATIC_ID" })}`;
|
||||
}
|
||||
return line;
|
||||
} catch {
|
||||
|
|
@ -25,40 +25,40 @@ function normalizeStreamData(lines: string[]): string[] {
|
|||
}
|
||||
|
||||
test.describe
|
||||
.serial('/api/chat', () => {
|
||||
test('Ada cannot invoke a chat generation with empty request body', async ({
|
||||
.serial("/api/chat", () => {
|
||||
test("Ada cannot invoke a chat generation with empty request body", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const response = await adaContext.request.post('/api/chat', {
|
||||
const response = await adaContext.request.post("/api/chat", {
|
||||
data: JSON.stringify({}),
|
||||
});
|
||||
expect(response.status()).toBe(400);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('bad_request:api');
|
||||
expect(message).toEqual(getMessageByErrorCode('bad_request:api'));
|
||||
expect(code).toEqual("bad_request:api");
|
||||
expect(message).toEqual(getMessageByErrorCode("bad_request:api"));
|
||||
});
|
||||
|
||||
test('Ada can invoke chat generation', async ({ adaContext }) => {
|
||||
test("Ada can invoke chat generation", async ({ adaContext }) => {
|
||||
const chatId = generateUUID();
|
||||
|
||||
const response = await adaContext.request.post('/api/chat', {
|
||||
const response = await adaContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: TEST_PROMPTS.SKY.MESSAGE,
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'private',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "private",
|
||||
},
|
||||
});
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
const text = await response.text();
|
||||
const lines = text.split('\n');
|
||||
const lines = text.split("\n");
|
||||
|
||||
const [_, ...rest] = lines;
|
||||
const actualNormalized = normalizeStreamData(rest.filter(Boolean));
|
||||
const expectedNormalized = normalizeStreamData(
|
||||
TEST_PROMPTS.SKY.OUTPUT_STREAM,
|
||||
TEST_PROMPTS.SKY.OUTPUT_STREAM
|
||||
);
|
||||
|
||||
expect(actualNormalized).toEqual(expectedNormalized);
|
||||
|
|
@ -71,39 +71,39 @@ test.describe
|
|||
}) => {
|
||||
const [chatId] = chatIdsCreatedByAda;
|
||||
|
||||
const response = await babbageContext.request.post('/api/chat', {
|
||||
const response = await babbageContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: TEST_PROMPTS.GRASS.MESSAGE,
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'private',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "private",
|
||||
},
|
||||
});
|
||||
expect(response.status()).toBe(403);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('forbidden:chat');
|
||||
expect(message).toEqual(getMessageByErrorCode('forbidden:chat'));
|
||||
expect(code).toEqual("forbidden:chat");
|
||||
expect(message).toEqual(getMessageByErrorCode("forbidden:chat"));
|
||||
});
|
||||
|
||||
test("Babbage cannot delete Ada's chat", async ({ babbageContext }) => {
|
||||
const [chatId] = chatIdsCreatedByAda;
|
||||
|
||||
const response = await babbageContext.request.delete(
|
||||
`/api/chat?id=${chatId}`,
|
||||
`/api/chat?id=${chatId}`
|
||||
);
|
||||
expect(response.status()).toBe(403);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('forbidden:chat');
|
||||
expect(message).toEqual(getMessageByErrorCode('forbidden:chat'));
|
||||
expect(code).toEqual("forbidden:chat");
|
||||
expect(message).toEqual(getMessageByErrorCode("forbidden:chat"));
|
||||
});
|
||||
|
||||
test('Ada can delete her own chat', async ({ adaContext }) => {
|
||||
test("Ada can delete her own chat", async ({ adaContext }) => {
|
||||
const [chatId] = chatIdsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.delete(
|
||||
`/api/chat?id=${chatId}`,
|
||||
`/api/chat?id=${chatId}`
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -111,42 +111,42 @@ test.describe
|
|||
expect(deletedChat).toMatchObject({ id: chatId });
|
||||
});
|
||||
|
||||
test('Ada cannot resume stream of chat that does not exist', async ({
|
||||
test("Ada cannot resume stream of chat that does not exist", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const response = await adaContext.request.get(
|
||||
`/api/chat/${generateUUID()}/stream`,
|
||||
`/api/chat/${generateUUID()}/stream`
|
||||
);
|
||||
expect(response.status()).toBe(404);
|
||||
});
|
||||
|
||||
test('Ada can resume chat generation', async ({ adaContext }) => {
|
||||
test("Ada can resume chat generation", async ({ adaContext }) => {
|
||||
const chatId = generateUUID();
|
||||
|
||||
const firstRequest = adaContext.request.post('/api/chat', {
|
||||
const firstRequest = adaContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: {
|
||||
id: generateUUID(),
|
||||
role: 'user',
|
||||
content: 'Help me write an essay about Silcon Valley',
|
||||
role: "user",
|
||||
content: "Help me write an essay about Silcon Valley",
|
||||
parts: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Help me write an essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Help me write an essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'private',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "private",
|
||||
},
|
||||
});
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
const secondRequest = adaContext.request.get(
|
||||
`/api/chat/${chatId}/stream`,
|
||||
`/api/chat/${chatId}/stream`
|
||||
);
|
||||
|
||||
const [firstResponse, secondResponse] = await Promise.all([
|
||||
|
|
@ -168,37 +168,37 @@ test.describe
|
|||
]);
|
||||
|
||||
expect(firstResponseBody.toString()).toEqual(
|
||||
secondResponseBody.toString(),
|
||||
secondResponseBody.toString()
|
||||
);
|
||||
});
|
||||
|
||||
test('Ada can resume chat generation that has ended during request', async ({
|
||||
test("Ada can resume chat generation that has ended during request", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const chatId = generateUUID();
|
||||
|
||||
const firstRequest = await adaContext.request.post('/api/chat', {
|
||||
const firstRequest = await adaContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: {
|
||||
id: generateUUID(),
|
||||
role: 'user',
|
||||
content: 'Help me write an essay about Silcon Valley',
|
||||
role: "user",
|
||||
content: "Help me write an essay about Silcon Valley",
|
||||
parts: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Help me write an essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Help me write an essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'private',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "private",
|
||||
},
|
||||
});
|
||||
|
||||
const secondRequest = adaContext.request.get(
|
||||
`/api/chat/${chatId}/stream`,
|
||||
`/api/chat/${chatId}/stream`
|
||||
);
|
||||
|
||||
const [firstResponse, secondResponse] = await Promise.all([
|
||||
|
|
@ -219,31 +219,31 @@ test.describe
|
|||
secondResponse.text(),
|
||||
]);
|
||||
|
||||
expect(secondResponseContent).toContain('appendMessage');
|
||||
expect(secondResponseContent).toContain("appendMessage");
|
||||
});
|
||||
|
||||
test('Ada cannot resume chat generation that has ended', async ({
|
||||
test("Ada cannot resume chat generation that has ended", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const chatId = generateUUID();
|
||||
|
||||
const firstResponse = await adaContext.request.post('/api/chat', {
|
||||
const firstResponse = await adaContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: {
|
||||
id: generateUUID(),
|
||||
role: 'user',
|
||||
content: 'Help me write an essay about Silcon Valley',
|
||||
role: "user",
|
||||
content: "Help me write an essay about Silcon Valley",
|
||||
parts: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Help me write an essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Help me write an essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'private',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "private",
|
||||
},
|
||||
});
|
||||
|
||||
|
|
@ -252,48 +252,48 @@ test.describe
|
|||
|
||||
await firstResponse.text();
|
||||
await new Promise((resolve) => setTimeout(resolve, 15 * 1000));
|
||||
await new Promise((resolve) => setTimeout(resolve, 15000));
|
||||
await new Promise((resolve) => setTimeout(resolve, 15_000));
|
||||
const secondResponse = await adaContext.request.get(
|
||||
`/api/chat/${chatId}/stream`,
|
||||
`/api/chat/${chatId}/stream`
|
||||
);
|
||||
|
||||
const secondStatusCode = secondResponse.status();
|
||||
expect(secondStatusCode).toBe(200);
|
||||
|
||||
const secondResponseContent = await secondResponse.text();
|
||||
expect(secondResponseContent).toEqual('');
|
||||
expect(secondResponseContent).toEqual("");
|
||||
});
|
||||
|
||||
test('Babbage cannot resume a private chat generation that belongs to Ada', async ({
|
||||
test("Babbage cannot resume a private chat generation that belongs to Ada", async ({
|
||||
adaContext,
|
||||
babbageContext,
|
||||
}) => {
|
||||
const chatId = generateUUID();
|
||||
|
||||
const firstRequest = adaContext.request.post('/api/chat', {
|
||||
const firstRequest = adaContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: {
|
||||
id: generateUUID(),
|
||||
role: 'user',
|
||||
content: 'Help me write an essay about Silcon Valley',
|
||||
role: "user",
|
||||
content: "Help me write an essay about Silcon Valley",
|
||||
parts: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Help me write an essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Help me write an essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'private',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "private",
|
||||
},
|
||||
});
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 1000));
|
||||
|
||||
const secondRequest = babbageContext.request.get(
|
||||
`/api/chat/${chatId}/stream`,
|
||||
`/api/chat/${chatId}/stream`
|
||||
);
|
||||
|
||||
const [firstResponse, secondResponse] = await Promise.all([
|
||||
|
|
@ -310,37 +310,37 @@ test.describe
|
|||
expect(secondStatusCode).toBe(403);
|
||||
});
|
||||
|
||||
test('Babbage can resume a public chat generation that belongs to Ada', async ({
|
||||
test("Babbage can resume a public chat generation that belongs to Ada", async ({
|
||||
adaContext,
|
||||
babbageContext,
|
||||
}) => {
|
||||
test.fixme();
|
||||
const chatId = generateUUID();
|
||||
|
||||
const firstRequest = adaContext.request.post('/api/chat', {
|
||||
const firstRequest = adaContext.request.post("/api/chat", {
|
||||
data: {
|
||||
id: chatId,
|
||||
message: {
|
||||
id: generateUUID(),
|
||||
role: 'user',
|
||||
content: 'Help me write an essay about Silicon Valley',
|
||||
role: "user",
|
||||
content: "Help me write an essay about Silicon Valley",
|
||||
parts: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'Help me write an essay about Silicon Valley',
|
||||
type: "text",
|
||||
text: "Help me write an essay about Silicon Valley",
|
||||
},
|
||||
],
|
||||
createdAt: new Date().toISOString(),
|
||||
},
|
||||
selectedChatModel: 'chat-model',
|
||||
selectedVisibilityType: 'public',
|
||||
selectedChatModel: "chat-model",
|
||||
selectedVisibilityType: "public",
|
||||
},
|
||||
});
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 10 * 1000));
|
||||
|
||||
const secondRequest = babbageContext.request.get(
|
||||
`/api/chat/${chatId}/stream`,
|
||||
`/api/chat/${chatId}/stream`
|
||||
);
|
||||
|
||||
const [firstResponse, secondResponse] = await Promise.all([
|
||||
|
|
|
|||
|
|
@ -1,52 +1,52 @@
|
|||
import type { Document } from '@/lib/db/schema';
|
||||
import { generateUUID } from '@/lib/utils';
|
||||
import { expect, test } from '../fixtures';
|
||||
import { getMessageByErrorCode } from '@/lib/errors';
|
||||
import type { Document } from "@/lib/db/schema";
|
||||
import { getMessageByErrorCode } from "@/lib/errors";
|
||||
import { generateUUID } from "@/lib/utils";
|
||||
import { expect, test } from "../fixtures";
|
||||
|
||||
const documentsCreatedByAda: Array<Document> = [];
|
||||
const documentsCreatedByAda: Document[] = [];
|
||||
|
||||
test.describe
|
||||
.serial('/api/document', () => {
|
||||
test('Ada cannot retrieve a document without specifying an id', async ({
|
||||
.serial("/api/document", () => {
|
||||
test("Ada cannot retrieve a document without specifying an id", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const response = await adaContext.request.get('/api/document');
|
||||
const response = await adaContext.request.get("/api/document");
|
||||
expect(response.status()).toBe(400);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('bad_request:api');
|
||||
expect(code).toEqual("bad_request:api");
|
||||
expect(message).toEqual(getMessageByErrorCode(code));
|
||||
});
|
||||
|
||||
test('Ada cannot retrieve a document that does not exist', async ({
|
||||
test("Ada cannot retrieve a document that does not exist", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const documentId = generateUUID();
|
||||
|
||||
const response = await adaContext.request.get(
|
||||
`/api/document?id=${documentId}`,
|
||||
`/api/document?id=${documentId}`
|
||||
);
|
||||
expect(response.status()).toBe(404);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('not_found:document');
|
||||
expect(code).toEqual("not_found:document");
|
||||
expect(message).toEqual(getMessageByErrorCode(code));
|
||||
});
|
||||
|
||||
test('Ada can create a document', async ({ adaContext }) => {
|
||||
test("Ada can create a document", async ({ adaContext }) => {
|
||||
const documentId = generateUUID();
|
||||
|
||||
const draftDocument = {
|
||||
title: "Ada's Document",
|
||||
kind: 'text',
|
||||
content: 'Created by Ada',
|
||||
kind: "text",
|
||||
content: "Created by Ada",
|
||||
};
|
||||
|
||||
const response = await adaContext.request.post(
|
||||
`/api/document?id=${documentId}`,
|
||||
{
|
||||
data: draftDocument,
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -56,11 +56,11 @@ test.describe
|
|||
documentsCreatedByAda.push(createdDocument);
|
||||
});
|
||||
|
||||
test('Ada can retrieve a created document', async ({ adaContext }) => {
|
||||
test("Ada can retrieve a created document", async ({ adaContext }) => {
|
||||
const [document] = documentsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.get(
|
||||
`/api/document?id=${document.id}`,
|
||||
`/api/document?id=${document.id}`
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -71,22 +71,22 @@ test.describe
|
|||
expect(retrievedDocument).toMatchObject(document);
|
||||
});
|
||||
|
||||
test('Ada can save a new version of the document', async ({
|
||||
test("Ada can save a new version of the document", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const [firstDocument] = documentsCreatedByAda;
|
||||
|
||||
const draftDocument = {
|
||||
title: "Ada's Document",
|
||||
kind: 'text',
|
||||
content: 'Updated by Ada',
|
||||
kind: "text",
|
||||
content: "Updated by Ada",
|
||||
};
|
||||
|
||||
const response = await adaContext.request.post(
|
||||
`/api/document?id=${firstDocument.id}`,
|
||||
{
|
||||
data: draftDocument,
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -96,13 +96,13 @@ test.describe
|
|||
documentsCreatedByAda.push(createdDocument);
|
||||
});
|
||||
|
||||
test('Ada can retrieve all versions of her documents', async ({
|
||||
test("Ada can retrieve all versions of her documents", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const [firstDocument, secondDocument] = documentsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.get(
|
||||
`/api/document?id=${firstDocument.id}`,
|
||||
`/api/document?id=${firstDocument.id}`
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -115,39 +115,39 @@ test.describe
|
|||
expect(secondRetrievedDocument).toMatchObject(secondDocument);
|
||||
});
|
||||
|
||||
test('Ada cannot delete a document without specifying an id', async ({
|
||||
test("Ada cannot delete a document without specifying an id", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const response = await adaContext.request.delete(`/api/document`);
|
||||
const response = await adaContext.request.delete("/api/document");
|
||||
expect(response.status()).toBe(400);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('bad_request:api');
|
||||
expect(code).toEqual("bad_request:api");
|
||||
expect(message).toEqual(getMessageByErrorCode(code));
|
||||
});
|
||||
|
||||
test('Ada cannot delete a document without specifying a timestamp', async ({
|
||||
test("Ada cannot delete a document without specifying a timestamp", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const [firstDocument] = documentsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.delete(
|
||||
`/api/document?id=${firstDocument.id}`,
|
||||
`/api/document?id=${firstDocument.id}`
|
||||
);
|
||||
expect(response.status()).toBe(400);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('bad_request:api');
|
||||
expect(code).toEqual("bad_request:api");
|
||||
expect(message).toEqual(getMessageByErrorCode(code));
|
||||
});
|
||||
|
||||
test('Ada can delete a document by specifying id and timestamp', async ({
|
||||
test("Ada can delete a document by specifying id and timestamp", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const [firstDocument, secondDocument] = documentsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.delete(
|
||||
`/api/document?id=${firstDocument.id}×tamp=${firstDocument.createdAt}`,
|
||||
`/api/document?id=${firstDocument.id}×tamp=${firstDocument.createdAt}`
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -158,13 +158,13 @@ test.describe
|
|||
expect(deletedDocument).toMatchObject(secondDocument);
|
||||
});
|
||||
|
||||
test('Ada can retrieve documents without deleted versions', async ({
|
||||
test("Ada can retrieve documents without deleted versions", async ({
|
||||
adaContext,
|
||||
}) => {
|
||||
const [firstDocument] = documentsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.get(
|
||||
`/api/document?id=${firstDocument.id}`,
|
||||
`/api/document?id=${firstDocument.id}`
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
@ -180,20 +180,20 @@ test.describe
|
|||
|
||||
const draftDocument = {
|
||||
title: "Babbage's Document",
|
||||
kind: 'text',
|
||||
content: 'Created by Babbage',
|
||||
kind: "text",
|
||||
content: "Created by Babbage",
|
||||
};
|
||||
|
||||
const response = await babbageContext.request.post(
|
||||
`/api/document?id=${firstDocument.id}`,
|
||||
{
|
||||
data: draftDocument,
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(response.status()).toBe(403);
|
||||
|
||||
const { code, message } = await response.json();
|
||||
expect(code).toEqual('forbidden:document');
|
||||
expect(code).toEqual("forbidden:document");
|
||||
expect(message).toEqual(getMessageByErrorCode(code));
|
||||
});
|
||||
|
||||
|
|
@ -201,7 +201,7 @@ test.describe
|
|||
const [firstDocument] = documentsCreatedByAda;
|
||||
|
||||
const response = await adaContext.request.get(
|
||||
`/api/document?id=${firstDocument.id}`,
|
||||
`/api/document?id=${firstDocument.id}`
|
||||
);
|
||||
expect(response.status()).toBe(200);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue