From 170f46fbc3f711ed5d389b082e5ea23878ab6968 Mon Sep 17 00:00:00 2001 From: "Huu Le (Lee)" <39040748+leehuwuj@users.noreply.github.com> Date: Thu, 1 Feb 2024 10:57:10 +0700 Subject: [PATCH] fix(create-llama): generate code option fail (#491) --- e2e/basic.spec.ts | 198 +++++++++++++++++++++++++--------------------- e2e/utils.ts | 21 +++++ helpers/index.ts | 19 +++-- questions.ts | 2 +- 4 files changed, 140 insertions(+), 100 deletions(-) diff --git a/e2e/basic.spec.ts b/e2e/basic.spec.ts index 9d4a09ec..2090e0fe 100644 --- a/e2e/basic.spec.ts +++ b/e2e/basic.spec.ts @@ -6,6 +6,7 @@ import path from "path"; import type { TemplateEngine, TemplateFramework, + TemplatePostInstallAction, TemplateType, TemplateUI, } from "../helpers"; @@ -19,110 +20,123 @@ const templateFrameworks: TemplateFramework[] = [ ]; const templateEngines: TemplateEngine[] = ["simple", "context"]; const templateUIs: TemplateUI[] = ["shadcn", "html"]; +const templatePostInstallActions: TemplatePostInstallAction[] = [ + "none", + "runApp", +]; for (const templateType of templateTypes) { for (const templateFramework of templateFrameworks) { for (const templateEngine of templateEngines) { for (const templateUI of templateUIs) { - if (templateFramework === "nextjs" && templateType === "simple") { - // nextjs doesn't support simple templates - skip tests - continue; - } - const appType: AppType = - templateFramework === "express" || templateFramework === "fastapi" - ? templateType === "simple" - ? "--no-frontend" // simple templates don't have frontends - : "--frontend" - : ""; - if (appType === "--no-frontend" && templateUI !== "html") { - // if there's no frontend, don't iterate over UIs - continue; - } - test.describe(`try create-llama ${templateType} ${templateFramework} ${templateEngine} ${templateUI} ${appType}`, async () => { - let port: number; - let externalPort: number; - let cwd: string; - let name: string; - let appProcess: ChildProcess; - const postInstallAction = "runApp"; + for (const templatePostInstallAction of templatePostInstallActions) { + if (templateFramework === "nextjs" && templateType === "simple") { + // nextjs doesn't support simple templates - skip tests + continue; + } + const appType: AppType = + templateFramework === "express" || templateFramework === "fastapi" + ? templateType === "simple" + ? "--no-frontend" // simple templates don't have frontends + : "--frontend" + : ""; + if (appType === "--no-frontend" && templateUI !== "html") { + // if there's no frontend, don't iterate over UIs + continue; + } + test.describe(`try create-llama ${templateType} ${templateFramework} ${templateEngine} ${templateUI} ${appType} ${templatePostInstallAction}`, async () => { + let port: number; + let externalPort: number; + let cwd: string; + let name: string; + let appProcess: ChildProcess; + // Only test without using vector db for now + const vectorDb = "none"; - test.beforeAll(async () => { - port = Math.floor(Math.random() * 10000) + 10000; - externalPort = port + 1; - cwd = await createTestDir(); - const result = await runCreateLlama( - cwd, - templateType, - templateFramework, - templateEngine, - templateUI, - appType, - port, - externalPort, - postInstallAction, - ); - name = result.projectName; - appProcess = result.appProcess; - }); + test.beforeAll(async () => { + port = Math.floor(Math.random() * 10000) + 10000; + externalPort = port + 1; + cwd = await createTestDir(); + const result = await runCreateLlama( + cwd, + templateType, + templateFramework, + templateEngine, + templateUI, + vectorDb, + appType, + port, + externalPort, + templatePostInstallAction, + ); + name = result.projectName; + appProcess = result.appProcess; + }); - test("App folder should exist", async () => { - const dirExists = fs.existsSync(path.join(cwd, name)); - expect(dirExists).toBeTruthy(); - }); - test("Frontend should have a title", async ({ page }) => { - test.skip(appType === "--no-frontend"); - await page.goto(`http://localhost:${port}`); - await expect(page.getByText("Built by LlamaIndex")).toBeVisible(); - }); + test("App folder should exist", async () => { + const dirExists = fs.existsSync(path.join(cwd, name)); + expect(dirExists).toBeTruthy(); + }); + test("Frontend should have a title", async ({ page }) => { + test.skip(templatePostInstallAction !== "runApp"); + test.skip(appType === "--no-frontend"); + await page.goto(`http://localhost:${port}`); + await expect(page.getByText("Built by LlamaIndex")).toBeVisible(); + }); - test("Frontend should be able to submit a message and receive a response", async ({ - page, - }) => { - test.skip(appType === "--no-frontend"); - await page.goto(`http://localhost:${port}`); - await page.fill("form input", "hello"); - await page.click("form button[type=submit]"); - const response = await page.waitForResponse( - (res) => { - return res.url().includes("/api/chat") && res.status() === 200; - }, - { - timeout: 1000 * 60, - }, - ); - const text = await response.text(); - console.log("AI response when submitting message: ", text); - expect(response.ok()).toBeTruthy(); - }); + test("Frontend should be able to submit a message and receive a response", async ({ + page, + }) => { + test.skip(templatePostInstallAction !== "runApp"); + test.skip(appType === "--no-frontend"); + await page.goto(`http://localhost:${port}`); + await page.fill("form input", "hello"); + await page.click("form button[type=submit]"); + const response = await page.waitForResponse( + (res) => { + return ( + res.url().includes("/api/chat") && res.status() === 200 + ); + }, + { + timeout: 1000 * 60, + }, + ); + const text = await response.text(); + console.log("AI response when submitting message: ", text); + expect(response.ok()).toBeTruthy(); + }); - test("Backend should response when calling API", async ({ - request, - }) => { - test.skip(appType !== "--no-frontend"); - const backendPort = appType === "" ? port : externalPort; - const response = await request.post( - `http://localhost:${backendPort}/api/chat`, - { - data: { - messages: [ - { - role: "user", - content: "Hello", - }, - ], + test("Backend should response when calling API", async ({ + request, + }) => { + test.skip(templatePostInstallAction !== "runApp"); + test.skip(appType !== "--no-frontend"); + const backendPort = appType === "" ? port : externalPort; + const response = await request.post( + `http://localhost:${backendPort}/api/chat`, + { + data: { + messages: [ + { + role: "user", + content: "Hello", + }, + ], + }, }, - }, - ); - const text = await response.text(); - console.log("AI response when calling API: ", text); - expect(response.ok()).toBeTruthy(); - }); + ); + const text = await response.text(); + console.log("AI response when calling API: ", text); + expect(response.ok()).toBeTruthy(); + }); - // clean processes - test.afterAll(async () => { - appProcess?.kill(); + // clean processes + test.afterAll(async () => { + appProcess?.kill(); + }); }); - }); + } } } } diff --git a/e2e/utils.ts b/e2e/utils.ts index d8223278..b06776da 100644 --- a/e2e/utils.ts +++ b/e2e/utils.ts @@ -9,6 +9,7 @@ import { TemplatePostInstallAction, TemplateType, TemplateUI, + TemplateVectorDB, } from "../helpers"; export type AppType = "--frontend" | "--no-frontend" | ""; @@ -67,6 +68,7 @@ export async function runCreateLlama( templateFramework: TemplateFramework, templateEngine: TemplateEngine, templateUI: TemplateUI, + vectorDb: TemplateVectorDB, appType: AppType, port: number, externalPort: number, @@ -100,6 +102,8 @@ export async function runCreateLlama( templateEngine, "--ui", templateUI, + "--vector-db", + vectorDb, "--model", MODEL, "--open-ai-key", @@ -139,6 +143,23 @@ export async function runCreateLlama( externalPort, 1000 * 60 * 5, ); + } else { + // wait create-llama to exit + // we don't test install dependencies for now, so just set timeout for 10 seconds + await new Promise((resolve, reject) => { + const timeout = setTimeout(() => { + reject(new Error("create-llama timeout error")); + }, 1000 * 10); + appProcess.on("exit", (code) => { + if (code !== 0 && code !== null) { + clearTimeout(timeout); + reject(new Error("create-llama command was failed!")); + } else { + clearTimeout(timeout); + resolve(undefined); + } + }); + }); } return { diff --git a/helpers/index.ts b/helpers/index.ts index f5467816..010bc6bd 100644 --- a/helpers/index.ts +++ b/helpers/index.ts @@ -207,13 +207,18 @@ export const installTemplate = async ( if (props.engine === "context") { await copyContextData(props.root, props.dataSource); - await installDependencies( - props.framework, - props.packageManager, - props.openAiKey, - props.vectorDb, - ); - console.log("installed Dependencies"); + if ( + props.postInstallAction === "runApp" || + props.postInstallAction === "dependencies" + ) { + await installDependencies( + props.framework, + props.packageManager, + props.openAiKey, + props.vectorDb, + ); + console.log("installed dependencies"); + } } } else { // this is a frontend for a full-stack app, create .env file with model information diff --git a/questions.ts b/questions.ts index 59aa5151..e1b5824f 100644 --- a/questions.ts +++ b/questions.ts @@ -540,7 +540,7 @@ export const askQuestions = async ( }; } - if (!program.engine && program.engine !== "simple" && !program.vectorDb) { + if (program.engine !== "simple" && !program.vectorDb) { if (ciInfo.isCI) { program.vectorDb = getPrefOrDefault("vectorDb"); } else { -- GitLab