.agents/skills/e2e-testing/references/helpers.md
All helpers are located in src/frontend/tests/utils/. Import them by name.
awaitBootstrapTest(page, options?)Call this at the start of EVERY test. Waits for the app to fully load and optionally opens the new project modal.
import { awaitBootstrapTest } from "../../utils/await-bootstrap-test";
// Default: waits for load + opens new project modal
await awaitBootstrapTest(page);
// Skip opening modal (for tests that start on an existing page)
await awaitBootstrapTest(page, { skipModal: true });
Why: Without this, tests race against the app's initialization. Components may not be rendered, stores may not be hydrated, and API calls may not be complete. Every flaky "element not found" failure is likely a missing awaitBootstrapTest.
initialGPTsetup(page, options?)Full OpenAI setup pipeline. Calls 6 steps in order:
adjustScreenView — fit view + zoom outupdateOldComponents — update any outdated componentsselectGptModel — select gpt-4o-mini for all Language Model nodesaddOpenAiInputKey — fill OPENAI_API_KEY in all openai_api_key fieldsadjustScreenView — fit again (components may have moved)unselectNodes — click empty canvas to deselect// All steps
await initialGPTsetup(page);
// Skip specific steps
await initialGPTsetup(page, {
skipAdjustScreenView: true,
skipUpdateOldComponents: true,
skipSelectGptModel: true,
});
Why: Many tests need a working OpenAI-connected flow. This helper standardizes the setup so test authors don't reinvent it. The order matters — updating components before selecting models prevents stale model dropdowns.
adjustScreenView(page, options?)Clicks "fit view" then zooms out. Ensures all nodes are visible and interactable.
await adjustScreenView(page); // Default: fit + 1 zoom out
await adjustScreenView(page, { numberOfZoomOut: 3 }); // Fit + 3 zoom outs
Why: After adding components, some may be off-screen or overlapping. Fit view centers them; zoom out ensures click targets are large enough for Playwright to hit reliably.
zoomOut(page, times)Zooms out the canvas a specific number of times.
await zoomOut(page, 5);
unselectNodes(page)Clicks the empty canvas area at position (0, 0) to deselect all nodes.
await unselectNodes(page);
Why: Selected nodes show selection UI (toolbars, handles) that can overlay other elements. Deselecting before interacting with other elements prevents click interception.
selectGptModel(page)Finds all Language Model nodes and selects gpt-4o-mini in their model dropdown.
Why: Tests that require LLM execution need a specific model. Using gpt-4o-mini keeps costs low and responses fast.
addOpenAiInputKey(page)Finds all fields with data-testid="popover-anchor-input-openai_api_key" and fills them with process.env.OPENAI_API_KEY.
Warning: Only works when the field renders as an <input>. If a global variable is selected (badge mode), this helper won't find the field. Check the template's load_from_db setting.
updateOldComponents(page)If the canvas shows an "Update all" button (outdated components), clicks it and waits for update to complete.
Why: Saved flows from older versions may have outdated component definitions. Updating them ensures the test runs against current component behavior, not stale cached versions.
enableInspectPanel(page)Opens the canvas controls dropdown and toggles the inspection panel ON.
MUST be called BEFORE any interaction with edit-fields-button. Without it, the inspection panel is hidden and edit-fields-button does not exist in the DOM.
await enableInspectPanel(page);
await page.getByTestId("title-OpenAI").click(); // Select a node
await page.getByTestId("edit-fields-button").click(); // Now visible
disableInspectPanel(page)Toggles the inspection panel OFF. Use for cleanup or when testing canvas-only behavior.
renameFlow(page, options)Renames the current flow in the workspace.
await renameFlow(page, { flowName: "My Test Flow" });
uploadFile(page, filename)Uploads a file from the tests/assets/ directory.
await uploadFile(page, "test-document.pdf");
withEventDeliveryModes(title, config, testFn, options?)Wraps a test function to run it 3 times: once for each event delivery mode (streaming, polling, direct). Each mode is configured by intercepting the /api/v1/config route.
import { withEventDeliveryModes } from "../../utils/withEventDeliveryModes";
withEventDeliveryModes(
"Document Q&A should process and respond",
{ tag: ["@release", "@starter-projects"] },
async ({ page }) => {
// Test body — runs 3 times with different delivery modes
await page.getByTestId("input-chat-playground").fill("What is this about?");
await page.keyboard.press("Enter");
await expect(page.getByTestId("div-chat-message")).toBeVisible({ timeout: 60000 });
},
{ timeout: 10000 }, // Optional delay between mode switches
);
Why: Langflow supports 3 event delivery modes. A bug that only appears in polling mode would be missed if tests only run in streaming mode. This helper ensures all modes are covered without writing 3x the tests.
openAdvancedOptions(page) (LEGACY)Opens the old edit modal for component configuration. Deprecated — use enableInspectPanel + edit-fields-button for new tests.
closeAdvancedOptions(page) (LEGACY)Closes the old edit modal. Deprecated.
When to create a new helper:
When NOT to create a helper:
Place new helpers in src/frontend/tests/utils/ with kebab-case naming: my-new-helper.ts.