Last validated: Langflow 1.10.x
Validates the Prompt Template component end-to-end via 6 scenarios:
- Canvas rendering — the node renders on a blank flow with the correct
promptoutput handle. - Dynamic input handles from
{variable}placeholders — typing{name}and{profession}in the template creates one input handle per placeholder, named after the variable. - Removing a variable removes its handle — replacing
Hello {name}!withHello world!drops thenamehandle and decreases the total handle count. - Replacing a variable updates handles in place — switching
{role}for{title}while keeping{name}causes the old handle to disappear and the new one to appear. - Clearing all variables removes every dynamic handle — replacing
{a} and {b} and {c}with a variable-free string drops the dynamic handle count to zero. - Modal persistence (UI + backend) — text entered in the prompt modal and saved via
genericModalBtnSaveis still present (in the sanitized preview and in the textarea after re-entering edit mode) when the modal is reopened, and the autosaved flow atGET /api/v1/flows/{id}contains the same string innode.data.node.template.template.valuefor the Prompt Template node.
If any of these tests fails, the Prompt Template component is broken in one of its core contracts: rendering on the canvas, the regex that extracts {variable} placeholders from the template, the dynamic handle generation, or the modal's save-and-persist flow.
All 6 tests: @stable @release @regression @components
Every test starts with addPromptComponent(page) which:
- Bootstraps the app (
awaitBootstrapTest) - Clicks
blank-flow - Fills
sidebar-search-inputwithpromptand waits foradd-component-button-prompt-template - Clicks the add button
- Calls
adjustScreenView(page) - Asserts exactly one node is on the canvas
Tests 2–6 use the helper setPromptTemplate(page, value) which:
- Clicks
button_open_prompt_modal - If the sanitized preview
edit-prompt-sanitizedis visible (post-save state), clicks it to re-enter edit mode - Waits for the textarea
modal-promptarea_prompt_template(unique to the prompt modal, used as anchor instead of[role="dialog"]) to be visible - Selects all in the textarea (
Ctrl+A) and fillsvalue - Clicks
genericModalBtnSaveand waits for the textarea testid to be hidden — that disappearance is the reliable signal that the modal closed. Downstream assertions then auto-retry on the expected handle state.
- Asserts
title-Prompt Templateis visible. - Asserts the right-side
handle-prompt template-shownode-prompt-righthandle is visible. - Asserts exactly one node on the canvas (
react-flow__nodecount === 1).
- Calls
setPromptTemplatewithHello {name}, your job is {profession}.. - Asserts both
handle-prompt template-shownode-name-leftandhandle-prompt template-shownode-profession-leftare visible. - Asserts the dynamic-handle locator (
-shownode-*-leftonly) has count exactly 2 — sanity check that no extra handles leaked in.
- Sets the template to
Hello {name}!and asserts thenamehandle is visible and the dynamic-handle count is exactly 1. - Sets the template to
Hello world!. - Asserts the
namehandle has zero matches and the dynamic-handle count is exactly 0.
- Sets the template to
Hello {name}, you are {role}.and asserts bothnameandrolehandles are visible. - Sets the template to
Hello {name}, you are {title}.. - Asserts
nameis still visible,rolehas zero matches, andtitleis visible.
- Sets the template to
{a} and {b} and {c}and asserts the dynamic-handle count is exactly 3. - Sets the template to
No variables here.. - Asserts the dynamic-handle count is exactly 0.
- Sets the template to
Persisted prompt text {topic}.viasetPromptTemplate. - Asserts
handle-prompt template-shownode-topic-leftis visible (confirms save succeeded). - UI layer: reopens the modal, asserts
edit-prompt-sanitizedcontains the saved text, clicks the preview to re-enter edit mode, asserts the textarea has the exact saved value viatoHaveValue. - Backend layer: extracts the flow id from the URL, then polls
GET /api/v1/flows/{id}viapage.request(inherits session cookies — the endpoint requires session auth) until the Prompt Template node'stemplate.template.valueequals the saved string. Catches regressions where the modal shows the value but autosave does not flush it to the database.
title-Prompt Templateis visible after adding the component to a blank flow- The right-side output handle
handle-prompt template-shownode-prompt-rightis visible - For each
{variable}saved in the template, a corresponding left-side handlehandle-prompt template-shownode-{variable}-leftis rendered - Removing a
{variable}from the template removes the corresponding handle - Replacing one variable with another removes the old handle and creates a new one
- Saving a template via
genericModalBtnSavemakes the value retrievable on the next modal open — both in the sanitized preview and in the textarea after re-entering edit mode - The autosaved flow at
GET /api/v1/flows/{id}contains the saved template string atnode.data.node.template.template.valuefor the Prompt Template node
src/frontend/src/modals/promptModal/—genericModalBtnSavebutton,edit-prompt-sanitizedpreview, and the textarea that holds the editable template; changes here break tests 2–6src/frontend/src/CustomNodes/GenericNode/components/parameterRenderComponent/components/promptAreaComponent/—button_open_prompt_modaltrigger on the node inspector; breaks tests 2–6src/lfx/src/lfx/interface/utils.py—extract_input_variables_from_prompt(): derives the variable list from the template string using Python'sstring.Formatter().parse()(not a regex); breaks tests 2–5src/lfx/src/lfx/base/prompts/api_utils.py—validate_prompt()and_check_input_variables(): validation layer around the extracted variables; breaks tests 2–5src/lfx/src/lfx/components/models_and_agents/prompt.py—PromptComponentdefinition (display_name="Prompt Template", template field) andupdate_build_config()that synchronizes template ↔ input fields; breaks tests 2–6 and the backend assertion in test 6src/frontend/src/CustomNodes/GenericNode/— dynamic handle rendering forhandle-{component}-shownode-{var}-left; breaks tests 1–5GET /api/v1/flows/{id}— flow read endpoint backing the autosave round-trip; the response shapedata.nodes[].data.node.template.template.valueis what test 6 asserts. A rename of the innertemplate.templatenesting, or a change tonode.data.typeaway from"Prompt Template", breaks the backend assertion.
- Prompt rendering/execution behind an LLM (covered by
llm-agentsspecs such asmemory-history-regression.spec.ts) - Tool Mode interaction (covered by
tool-mode.spec.ts) - Cross-component data flow (covered by
flow-functionality/specs) - Variable name validation (e.g., reserved keywords, special characters)
- The
use_double_bracketstoggle and the mustache-mode parser (covered byprompt-template-double-brackets-regression.spec.ts)
- Langflow running and accessible at
PLAYWRIGHT_BASE_URL - No API key required — the Prompt Template component is a pure templating layer with no LLM calls
- Auto-login mode is assumed: test 6 uses
page.request.getso the backend call inherits the page's session cookies. In an environment with explicit auth, the test should still work because the page is authenticated via the normal login flow before the assertion runs.
- If the
button_open_prompt_modal,genericModalBtnSave, oredit-prompt-sanitizedtestids are renamed in the prompt modal frontend - If the dynamic handle testid pattern (
handle-prompt template-shownode-{var}-left) changes — e.g., if"prompt template"(with space) is replaced by"prompt-template"(with dash) or a different node-type slug - If the
{variable}extraction regex inextract_input_variables_from_promptchanges its handling of escape sequences, whitespace, or nested braces
- Test 6 (modal persistence) asserts persistence at three layers: the sanitized preview (
edit-prompt-sanitized, which is the post-save render), the textarea value reached by clicking back into edit mode, and the autosaved flow JSON fetched viaGET /api/v1/flows/{id}. All three must match the saved string for the test to pass. - The
setPromptTemplatehelper deliberately handles the post-save "preview" state by detectingedit-prompt-sanitizedand clicking through it. This is what makes the helper safe to call multiple times in a row (tests 3, 4, 5 all rely on this). - All assertions use the literal node-type slug
"prompt template"(with space) in the testid, matching how the frontend renders the type. The leading space insidehandle-prompt template-...is intentional and not a typo.