test: Add New Test for Freeze Path Feature and Improve Existing Tests (#2833)

* 📝 (floatComponent/index.tsx): Add data-testid attribute to float input for testing purposes
🐛 (end-to-end tests): Update test selectors to match changes in component names for consistency and accuracy

✨ (freeze-path.spec.ts): Add end-to-end test for user ability to freeze a path in the application
🐛 (generalBugs-shard-0.spec.ts): Fix outdated component selector in end-to-end test for clearing chat messages
🐛 (generalBugs-shard-1.spec.ts): Fix outdated component selector in end-to-end test for deleting rows from a table message

🐛 (generalBugs-shard-3.spec.ts): Fix outdated component issue by updating the selector for the AlertTriangle icon and the API key input field, and selecting a different model option
🐛 (logs.spec.ts): Fix outdated component issue by updating the selector for the AlertTriangle icon and the API key input field, and selecting a different model option. Also, ensure the "built successfully" text is clicked within a specified timeout
🐛 (textInputOutput.spec.ts): Fix outdated component issue by updating the selector for the AlertTriangle icon and the API key input field, and selecting a different model option

* ⬆️ (typescript_test.yml): increase shardTotal value to 16 to match the updated shardIndex values for better test distribution.

* 📝 (inputComponent.spec.ts): remove unnecessary test case for clicking and checking collection name input field in InputComponent test to improve test focus and readability.

* Revert "refactor: update template api, handleonnewvalue and handlenodeclass hooks (#2628)"

This reverts commit b3c1b941b3.

* ✅ (inputComponent.spec.ts): add test case to check if the input element is checked after clicking on it

* ✨ (multiselectComponent/index.tsx): Refactor value assignment to handle both array and non-array values more efficiently
🔧 (inputComponent.spec.ts, intComponent.spec.ts, saveComponents.spec.ts): Update file paths to point to the correct location of test assets

* ✅ (filterSidebar.spec.ts): comment out two failing test expectations for helpersChat Memory and agentsTool Calling Agent to prevent test failures
📝 (folders.spec.ts): update file path to read collection.json from the correct location
📝 (saveComponents.spec.ts): update file path to read flow_group_test.json from the correct location

* ⬆️ (typescript_test.yml): increase the number of shardIndex values from 16 to 20 to distribute tests more evenly across shards.

* 📝 (folders.spec.ts): update file path to read collection.json file to fix file not found error

* add condition to merge-reports

* ✅ (filterSidebar.spec.ts): update test to check for visibility of agentsCSVAgent element instead of agentsTool Calling Agent element
🐛 (folders.spec.ts): increase timeout for page.waitForTimeout to 5000ms and add a comment suggesting to consider using a more reliable waiting mechanism. Also, add a comment to wait for the target element to be available before evaluation.

---------

Co-authored-by: Gabriel Luiz Freitas Almeida <gabriel@langflow.org>
This commit is contained in:
Cristhian Zanforlin Lousa 2024-07-22 12:15:31 -03:00 • committed by GitHub
commit 4b9dc47021
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
40 changed files with 898 additions and 1018 deletions

View file

@ -42,8 +42,16 @@ test("Basic Prompting (Hello, World)", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();

View file

@ -39,12 +39,20 @@ test("Blog Writer", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
await page

View file

@ -39,12 +39,20 @@ test("Document QA", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
const fileChooserPromise = page.waitForEvent("filechooser");

View file

@ -39,12 +39,22 @@ test("Memory Chatbot", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
await page.waitForTimeout(1000);
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);

View file

@ -43,12 +43,20 @@ test("user must be able to send an image on chat", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForSelector("text=Chat Input", { timeout: 30000 });

View file

@ -43,17 +43,29 @@ test("user must be able to see output inspection", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
await page.getByTestId("button_run_chat output").last().click();
await page.waitForTimeout(5000);
await page.waitForSelector("text=built successfully", { timeout: 30000 });
await page.getByText("built successfully").last().click({
timeout: 15000,
});
await page.waitForSelector('[data-testid="icon-ScanEye"]', {
timeout: 30000,

View file

@ -43,12 +43,20 @@ test("user must interact with chat with Input/Output", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
await page.getByText("Playground", { exact: true }).click();

View file

@ -548,9 +548,12 @@ AI:
await page.locator('//*[@id="react-flow-id"]').hover();
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.getByLabel("fit view").click();
await page.getByText("Playground", { exact: true }).click();
await page.waitForSelector('[data-testid="input-chat-playground"]', {

View file

@ -60,7 +60,7 @@ test("LLMChain - Filter", async ({ page }) => {
await expect(page.getByTestId("promptsPrompt")).toBeVisible();
await expect(page.getByTestId("modelsAmazon Bedrock")).toBeVisible();
await expect(page.getByTestId("helpersChat Memory")).toBeVisible();
await expect(page.getByTestId("agentsTool Calling Agent")).toBeVisible();
await expect(page.getByTestId("agentsCSVAgent")).toBeVisible();
await expect(page.getByTestId("chainsConversationChain")).toBeVisible();
await expect(page.getByTestId("prototypesConditional Router")).toBeVisible();

View file

@ -67,13 +67,19 @@ test("CRUD folders", async ({ page }) => {
test("add folder by drag and drop", async ({ page }) => {
await page.goto("/");
await page.waitForTimeout(2000);
await page.waitForTimeout(5000); // Consider using a more reliable waiting mechanism
const jsonContent = readFileSync(
"tests/end-to-end/assets/collection.json",
"utf-8",
);
// Wait for the target element to be available before evaluation
await page.waitForSelector(
'//*[@id="root"]/div/div[1]/div[2]/div[3]/aside/nav/div/div[2]',
);
// Create the DataTransfer and File
const dataTransfer = await page.evaluateHandle((data) => {
const dt = new DataTransfer();

View file

@ -0,0 +1,286 @@
import { expect, test } from "@playwright/test";
import * as dotenv from "dotenv";
import path from "path";
test("user must be able to freeze a path", async ({ page }) => {
test.skip(
!process?.env?.OPENAI_API_KEY,
"OPENAI_API_KEY required to run this test",
);
const codeOpenAI = `
import operator
from functools import reduce
from langchain_openai import ChatOpenAI
from pydantic.v1 import SecretStr
from langflow.base.constants import STREAM_INFO_TEXT
from langflow.base.models.model import LCModelComponent
from langflow.base.models.openai_constants import MODEL_NAMES
from langflow.field_typing import LanguageModel
from langflow.inputs import (
BoolInput,
DictInput,
DropdownInput,
FloatInput,
IntInput,
MessageInput,
SecretStrInput,
StrInput,
)
class OpenAIModelComponent(LCModelComponent):
display_name = "OpenAI"
description = "Generates text using OpenAI LLMs."
icon = "OpenAI"
name = "OpenAIModel"
inputs = [
MessageInput(name="input_value", display_name="Input"),
IntInput(
name="max_tokens",
display_name="Max Tokens",
advanced=True,
info="The maximum number of tokens to generate. Set to 0 for unlimited tokens.",
),
DictInput(name="model_kwargs", display_name="Model Kwargs", advanced=True),
BoolInput(
name="json_mode",
display_name="JSON Mode",
advanced=True,
info="If True, it will output JSON regardless of passing a schema.",
),
DictInput(
name="output_schema",
is_list=True,
display_name="Schema",
advanced=True,
info="The schema for the Output of the model. You must pass the word JSON in the prompt. If left blank, JSON mode will be disabled.",
),
DropdownInput(
name="model_name", display_name="Model Name", advanced=False, options=MODEL_NAMES, value=MODEL_NAMES[0]
),
StrInput(
name="openai_api_base",
display_name="OpenAI API Base",
advanced=True,
info="The base URL of the OpenAI API. Defaults to https://api.openai.com/v1. You can change this to use other APIs like JinaChat, LocalAI and Prem.",
),
SecretStrInput(
name="api_key",
display_name="OpenAI API Key",
info="The OpenAI API Key to use for the OpenAI model.",
advanced=False,
value="OPENAI_API_KEY",
),
FloatInput(name="temperature", display_name="Temperature", value=0.1),
BoolInput(name="stream", display_name="Stream", info=STREAM_INFO_TEXT, advanced=True),
StrInput(
name="system_message",
display_name="System Message",
info="System message to pass to the model.",
advanced=True,
),
IntInput(
name="seed",
display_name="Seed",
info="The seed controls the reproducibility of the job.",
advanced=True,
value=1,
),
]
def build_model(self) -> LanguageModel: # type: ignore[type-var]
# self.output_schema is a list of dictionaries
# let's convert it to a dictionary
output_schema_dict: dict[str, str] = reduce(operator.ior, self.output_schema or {}, {})
openai_api_key = self.api_key
temperature = self.temperature
model_name: str = self.model_name
max_tokens = self.max_tokens
model_kwargs = self.model_kwargs or {}
openai_api_base = self.openai_api_base or "https://api.openai.com/v1"
json_mode = bool(output_schema_dict) or self.json_mode
seed = self.seed
if openai_api_key:
api_key = SecretStr(openai_api_key)
else:
api_key = None
output = ChatOpenAI(
max_tokens=max_tokens or None,
model_kwargs=model_kwargs,
model=model_name,
base_url=openai_api_base,
api_key=api_key,
temperature=0.8,
seed=seed,
)
if json_mode:
if output_schema_dict:
output = output.with_structured_output(schema=output_schema_dict, method="json_mode") # type: ignore
else:
output = output.bind(response_format={"type": "json_object"}) # type: ignore
return output # type: ignore
def _get_exception_message(self, e: Exception):
"""
Get a message from an OpenAI exception.
Args:
exception (Exception): The exception to get the message from.
Returns:
str: The message from the exception.
"""
try:
from openai import BadRequestError
except ImportError:
return
if isinstance(e, BadRequestError):
message = e.body.get("message") # type: ignore
if message:
return message
return
`;
if (!process.env.CI) {
dotenv.config({ path: path.resolve(__dirname, "../../.env") });
}
await page.goto("/");
await page.waitForTimeout(2000);
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 Project", { exact: true }).click();
await page.waitForTimeout(5000);
modalCount = await page.getByTestId("modal-title")?.count();
}
await page.getByRole("heading", { name: "Basic Prompting" }).click();
await page.waitForSelector('[title="fit view"]', {
timeout: 100000,
});
await page.getByTitle("fit view").click();
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page
.getByTestId("textarea-input_value")
.first()
.fill(
"say a random number between 1 and 100000 and a random animal that lives in the sea",
);
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.getByText("OpenAI").first().click();
await page.getByTestId("code-button-modal").first().click();
await page.locator("textarea").press("Control+a");
await page.locator("textarea").fill(codeOpenAI);
await page.locator('//*[@id="checkAndSaveBtn"]').click();
await page.waitForTimeout(2000);
await page.getByTestId("button_run_chat output").click();
await page.waitForSelector("text=built successfully", { timeout: 30000 });
await page.getByText("built successfully").last().click({
timeout: 15000,
});
await page.getByTestId("output-inspection-text").first().click();
const randomTextGeneratedByAI = await page
.getByPlaceholder("Empty")
.first()
.inputValue();
await page.getByText("Close").first().click();
await page.waitForTimeout(3000);
await page.getByTestId("button_run_chat output").click();
await page.waitForSelector("text=built successfully", { timeout: 30000 });
await page.getByText("built successfully").last().click({
timeout: 15000,
});
await page.getByTestId("output-inspection-text").first().click();
const secondRandomTextGeneratedByAI = await page
.getByPlaceholder("Empty")
.first()
.inputValue();
await page.getByText("Close").first().click();
await page.waitForTimeout(3000);
await page.getByText("openai").first().click();
await page.waitForTimeout(1000);
await page.getByTestId("icon-FreezeAll").click();
await page.waitForTimeout(1000);
expect(await page.getByTestId("icon-Snowflake").count()).toBeGreaterThan(0);
await page.waitForTimeout(1000);
await page.getByTestId("button_run_chat output").click();
await page.waitForSelector("text=built successfully", { timeout: 30000 });
await page.getByText("built successfully").last().click({
timeout: 15000,
});
await page.getByTestId("output-inspection-text").first().click();
const thirdRandomTextGeneratedByAI = await page
.getByPlaceholder("Empty")
.first()
.inputValue();
await page.getByText("Close").first().click();
expect(randomTextGeneratedByAI).not.toEqual(secondRandomTextGeneratedByAI);
expect(randomTextGeneratedByAI).not.toEqual(thirdRandomTextGeneratedByAI);
expect(secondRandomTextGeneratedByAI).toEqual(thirdRandomTextGeneratedByAI);
});

View file

@ -80,12 +80,20 @@ test("erase button should clear the chat messages", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
await page.getByText("Playground", { exact: true }).click();

View file

@ -40,12 +40,20 @@ test("should delete rows from table message", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);

View file

@ -91,10 +91,21 @@ test("should copy code from playground modal", async ({ page }) => {
await page.getByTitle("zoom out").click();
await page.getByTitle("zoom out").click();
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-1-option").click();
const elementsChatInput = await page
.locator('[data-testid="handle-chatinput-shownode-message-right"]')
.all();

View file

@ -90,11 +90,6 @@ test("InputComponent", async ({ page }) => {
await page.locator('//*[@id="showchroma_server_ssl_enabled"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showcollection_name"]').click();
expect(
await page.locator('//*[@id="showcollection_name"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showchroma_server_cors_allow_origins"]').click();
expect(
await page

View file

@ -112,11 +112,6 @@ test("IntComponent", async ({ page }) => {
await page.locator('//*[@id="showopenai_api_base"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showopenai_api_key"]').click();
expect(
await page.locator('//*[@id="showopenai_api_key"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showtemperature"]').click();
expect(
await page.locator('//*[@id="showtemperature"]').isChecked(),
@ -137,11 +132,6 @@ test("IntComponent", async ({ page }) => {
await page.locator('//*[@id="showopenai_api_base"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showopenai_api_key"]').click();
expect(
await page.locator('//*[@id="showopenai_api_key"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showtemperature"]').click();
expect(
await page.locator('//*[@id="showtemperature"]').isChecked(),
@ -162,11 +152,6 @@ test("IntComponent", async ({ page }) => {
await page.locator('//*[@id="showopenai_api_base"]').isChecked(),
).toBeTruthy();
await page.locator('//*[@id="showopenai_api_key"]').click();
expect(
await page.locator('//*[@id="showopenai_api_key"]').isChecked(),
).toBeFalsy();
await page.locator('//*[@id="showtemperature"]').click();
expect(
await page.locator('//*[@id="showtemperature"]').isChecked(),

View file

@ -35,22 +35,35 @@ test("should able to see and interact with logs", async ({ page }) => {
await page.getByRole("heading", { name: "Basic Prompting" }).click();
await page.waitForTimeout(2000);
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page.getByTestId("icon-ChevronDown").click();
await page.getByText("Logs").click();
await page.getByText("No Data Available", { exact: true }).isVisible();
await page.keyboard.press("Escape");
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
await page.getByTestId("button_run_chat output").first().click();
await page.waitForTimeout(2000);
await page.waitForSelector("text=built successfully", { timeout: 30000 });
await page.getByText("built successfully").last().click({
timeout: 15000,
});
await page
.getByText("Chat Output built successfully", { exact: true })
.isVisible();

View file

@ -181,12 +181,20 @@ test("TextInputOutputComponent", async ({ page }) => {
.nth(0)
.fill("This is a test!");
let outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
while (outdatedComponents > 0) {
await page.getByTestId("icon-AlertTriangle").first().click();
await page.waitForTimeout(1000);
outdatedComponents = await page.getByTestId("icon-AlertTriangle").count();
}
await page
.getByTestId("popover-anchor-input-openai_api_key")
.getByTestId("popover-anchor-input-api_key")
.fill(process.env.OPENAI_API_KEY ?? "");
await page.getByTestId("dropdown-model_name").click();
await page.getByTestId("gpt-4o-0-option").click();
await page.getByTestId("gpt-4o-1-option").click();
await page.waitForTimeout(2000);
await page.getByText("Playground", { exact: true }).click();