|
|
import { expect, Page, test } from "@playwright/test"; |
|
|
import uaParser from "ua-parser-js"; |
|
|
|
|
|
|
|
|
test( |
|
|
"user should interact with link component", |
|
|
{ tag: ["@release", "@workspace"] }, |
|
|
async ({ context, page }) => { |
|
|
await page.goto("/"); |
|
|
await page.waitForSelector('[data-testid="mainpage_title"]', { |
|
|
timeout: 30000, |
|
|
}); |
|
|
|
|
|
await page.waitForSelector('[id="new-project-btn"]', { |
|
|
timeout: 30000, |
|
|
}); |
|
|
|
|
|
let modalCount = 0; |
|
|
try { |
|
|
const modalTitleElement = await page?.getByTestId("modal-title"); |
|
|
if (modalTitleElement) { |
|
|
modalCount = await modalTitleElement.count(); |
|
|
} |
|
|
} catch (error) { |
|
|
modalCount = 0; |
|
|
} |
|
|
|
|
|
while (modalCount === 0) { |
|
|
await page.getByText("New Flow", { exact: true }).click(); |
|
|
await page.waitForSelector('[data-testid="modal-title"]', { |
|
|
timeout: 3000, |
|
|
}); |
|
|
modalCount = await page.getByTestId("modal-title")?.count(); |
|
|
} |
|
|
|
|
|
const getUA = await page.evaluate(() => navigator.userAgent); |
|
|
const userAgentInfo = uaParser(getUA); |
|
|
|
|
|
await page.waitForSelector('[data-testid="blank-flow"]', { |
|
|
timeout: 30000, |
|
|
}); |
|
|
await page.getByTestId("blank-flow").click(); |
|
|
|
|
|
await page.waitForSelector( |
|
|
'[data-testid="sidebar-custom-component-button"]', |
|
|
{ |
|
|
timeout: 3000, |
|
|
}, |
|
|
); |
|
|
|
|
|
await page.getByTestId("sidebar-custom-component-button").click(); |
|
|
await page.getByTitle("fit view").click(); |
|
|
await page.getByTitle("zoom out").click(); |
|
|
|
|
|
await page.getByTestId("title-Custom Component").first().click(); |
|
|
|
|
|
await page.waitForSelector('[data-testid="code-button-modal"]', { |
|
|
timeout: 3000, |
|
|
}); |
|
|
|
|
|
await page.getByTestId("code-button-modal").click(); |
|
|
|
|
|
let cleanCode = await extractAndCleanCode(page); |
|
|
|
|
|
|
|
|
cleanCode = updateComponentCode(cleanCode, { |
|
|
imports: ["MessageTextInput", "Output", "LinkInput"], |
|
|
inputs: [ |
|
|
{ |
|
|
name: "MessageTextInput", |
|
|
config: { |
|
|
name: "input_value", |
|
|
display_name: "Input Value", |
|
|
info: "This is a custom component Input", |
|
|
value: "Hello, World!", |
|
|
tool_mode: true, |
|
|
}, |
|
|
}, |
|
|
{ |
|
|
name: "LinkInput", |
|
|
config: { |
|
|
name: "link", |
|
|
display_name: "BUTTON", |
|
|
value: "https://www.datastax.com", |
|
|
text: "Click me", |
|
|
}, |
|
|
}, |
|
|
], |
|
|
}); |
|
|
|
|
|
await page.locator("textarea").last().press(`ControlOrMeta+a`); |
|
|
await page.keyboard.press("Backspace"); |
|
|
await page.locator("textarea").last().fill(cleanCode); |
|
|
await page.locator('//*[@id="checkAndSaveBtn"]').click(); |
|
|
|
|
|
await page.waitForSelector('[data-testid="fit_view"]', { |
|
|
timeout: 3000, |
|
|
}); |
|
|
|
|
|
await page.getByTestId("fit_view").click(); |
|
|
await page.getByTestId("zoom_out").click(); |
|
|
|
|
|
expect(await page.getByText("BUTTON").isVisible()).toBeTruthy(); |
|
|
expect(await page.getByText("Click me").isVisible()).toBeTruthy(); |
|
|
expect(await page.getByTestId("link_link_link")).toBeEnabled(); |
|
|
await page.getByTestId("link_link_link").click(); |
|
|
}, |
|
|
); |
|
|
|
|
|
async function extractAndCleanCode(page: Page): Promise<string> { |
|
|
const outerHTML = await page |
|
|
.locator('//*[@id="codeValue"]') |
|
|
.evaluate((el) => el.outerHTML); |
|
|
|
|
|
const valueMatch = outerHTML.match(/value="([\s\S]*?)"/); |
|
|
if (!valueMatch) { |
|
|
throw new Error("Could not find value attribute in the HTML"); |
|
|
} |
|
|
|
|
|
let codeContent = valueMatch[1] |
|
|
.replace(/"/g, '"') |
|
|
.replace(/&/g, "&") |
|
|
.replace(/</g, "<") |
|
|
.replace(/>/g, ">") |
|
|
.replace(/'/g, "'") |
|
|
.replace(///g, "/"); |
|
|
|
|
|
return codeContent; |
|
|
} |
|
|
|
|
|
function updateComponentCode( |
|
|
code: string, |
|
|
updates: { |
|
|
imports?: string[]; |
|
|
inputs?: Array<{ name: string; config: Record<string, any> }>; |
|
|
}, |
|
|
): string { |
|
|
let updatedCode = code; |
|
|
|
|
|
|
|
|
if (updates.imports) { |
|
|
const importPattern = /from\s+langflow\.io\s+import\s+([^;\n]+)/; |
|
|
const newImports = updates.imports.join(", "); |
|
|
updatedCode = updatedCode.replace( |
|
|
importPattern, |
|
|
`from langflow.io import ${newImports}`, |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
if (updates.inputs) { |
|
|
const inputsPattern = /inputs\s*=\s*\[([\s\S]*?)\]/; |
|
|
const newInputs = updates.inputs |
|
|
.map(({ name, config }) => { |
|
|
const params = Object.entries(config) |
|
|
.map(([key, value]) => `${key}=${JSON.stringify(value)}`) |
|
|
.join(",\n "); |
|
|
return ` ${name}(\n ${params}\n )`; |
|
|
}) |
|
|
.join(",\n"); |
|
|
updatedCode = updatedCode.replace( |
|
|
inputsPattern, |
|
|
`inputs = [\n${newInputs}\n ]`, |
|
|
); |
|
|
updatedCode = updatedCode.replace("true", "True"); |
|
|
updatedCode = updatedCode.replace("false", "False"); |
|
|
} |
|
|
|
|
|
return updatedCode; |
|
|
} |
|
|
|