Core Concepts & Philosophy
Before you write your first test, it is critical to understand how Flowstride executes automation. Flowstride is not just a wrapper around Playwright and Undici; it is a flow first domain specific language (DSL) designed to force tests to read like actual user journeys, rather than brittle software projects.
Here are the core principles that drive the framework.
1. Test Anatomy: Feature and Scenario
If you are coming from traditional JavaScript testing frameworks like Jest, Mocha, or Cypress, the outer structure of a .flow file will feel very familiar. Flowstride uses Feature and Scenario blocks to group and define your tests.
Feature: Think of this as yourdescribeblock. It sits at the top of your.flowfile and defines the high level grouping or the main application component under test (e.g.,Feature: User Authentication).Scenario: Think of this as youritblock. It represents a single, independent test case within that feature (e.g.,Scenario: Verify Valid Account Access).
These structural containers not only organise your test runs but also form the foundation of the management ready reports and testcase tables that Flowstride automatically generates.
2. The Strict Lifecycle Engine (Given, When, And, Then)
Inside every Scenario, Flowstride enforces a strict block order constraint to prevent messy, procedural code. When you write a .flow file, the parser engine guarantees that your test follows a definitive resolution path governed by an internal state machine:
Given: This block must always be the absolute first step in your scenario. It establishes the initial state, such as navigating to a page, injecting a session, or seeding a database. You cannot start a scenario with any other block.And: This block can comfortably chain after aGivenblock (before aWhenblock), or after aWhenblock (before aThenblock) to extend the current context. However, it can never start a scenario, and it can never follow aThenblock.When: This block must strictly follow aGivenblock (or anAndblock that is attached to aGiven). It defines the primary action or event the user is taking, such as submitting a form or making a network request.Then: This block must strictly follow aWhenblock (or anAndblock that is attached to aWhen). It is reserved exclusively for evaluating the outcome of the action and resolving the scenario. It is the absolute final block of any testcase. Nothing can ever come after theThenblock.
3. Conditional And Execution Locks
While Flowstride introduces the And block to chain multiple steps together seamlessly, it operates under a strict execution lock system based on its placement context to prevent bad testing practices:
- The Assertion Lock: The
Andblock is highly restricted. It can exclusively accept assertions (e.g.,flow.expect) or custom plugins. You cannot use anAndblock to execute standard UI commands like clicking or typing. - The Chain Limit: An
Andblock cannot start a scenario, and crucially, it cannot follow aThenblock. It must only chain onto an activeGivenorWhenblock.
4. The Terminal Lock
Flowstride enforces a safety concept known as the Terminal Lock to ensure tests remain concise and focused. The Then block represents the absolute end of a testcase.
- Permanent Lock State: Once the parser transitions into a
Thenblock, the internal state machine locks the scenario permanently. Absolutely nothing can follow it. - Terminal Lock Violation: If you attempt to write an
Andblock after aThenblock, the engine will immediately reject it and throw a Terminal Lock Violation. - Validation Placement: Because the scenario ends strictly at the
Thenstage, you can equally place your finalflow.expectvalidations directly inside theThenblock itself to safely evaluate and terminate the testcase.
5. Smart Selectors: Text, Intent, and Spatial Mathematics
Traditional frameworks rely heavily on brittle CSS classes or long XPath strings that break every time the UI changes. Flowstride utilises a native Smart Selector Engine that prioritises human readable intent, accessibility attributes, and spatial relationships.
When you issue a command like flow.click button "Login", the engine scans the DOM using a strict heuristic approach:
- Accessibility Attributes: It immediately checks for exact matches against
placeholder,aria-label,title,name, orvalue. - Semantic Mappings: It maps
<label>text to its corresponding input field or text area. - Role and Text Fallbacks: It targets specific actionable roles (e.g.,
<button>or<a>) containing the target text. - Geometric Spatial Selectors: If a single string isn't enough, you can anchor elements using visual proximity (e.g.,
flow.type near "Username"orflow.click rightOf "Submit"). - CSS / XPath Fallbacks: Raw CSS paths (
#idor.class) are fully supported but inherently deprioritised over accessible text.
Whenever possible, use plain text or accessibility labels to ensure your tests survive modern UI framework updates.
6. Unified Web and API Execution
Testing a modern application usually requires two separate tools: one for the user interface and another for the backend data pipes. Flowstride unifies these layers into a single synchronised execution thread.
Within the exact same .flow scenario, you can:
- Send a native
flow.postrequest via the Undici engine to create a test user in your database. - Extract or save the API response payload into a local or global variable using the
flow.extractorflow.save sessionmodifier. - Immediately use a UI command like
flow.typevia the Playwright engine to log that newly created user into the visual interface.
7. The Persistent Session Vault
Authentication boilerplate is the leading cause of wasted test execution time. Instead of logging into the application before every single scenario, Flowstride introduces the Session Vault.
Using the flow.save session and flow.use session commands, the framework captures all active browser cookies, local storage, and session storage, merging them safely with your active API headers.
- In Memory Sessions: By default, saved sessions are held in memory for rapid sharing across the current test run.
- Persisted Sessions: By appending the
persistkeyword (e.g.,flow.save global session "Auth" persist), Flowstride writes the hybrid state securely to disk. The engine can seamlessly inject this VIP pass into future parallel workers, eliminating repetitive login steps entirely.
8. Zero Dependency Native Integrations
In traditional automation, interacting with complex elements often requires stringing together unreliable third party plugins. Flowstride is built with a zero dependency philosophy for complex test scenarios.
The engine natively supports advanced operations directly within the DSL syntax:
- Cross Domain iFrames: The engine automatically pierces iFrame boundaries during selector resolution without requiring context switching commands.
- Email OTP Interception: Using the
flow.mail.getotpengine, you can intercept and extract authentication codes from private inboxes natively. - Media Stream Injection: You can mock microphone inputs and bypass physical hardware prompts using
flow.injectAudio. - Native OS File Dialogs: The
flow.uploadcommand safely bypasses the operating system file explorer to attach documents directly to the DOM.
These features are treated as first class citizens in the language, ensuring your test suites remain stable without the burden of external package management.
