Configuration

Understanding TestFlowKit's YAML configuration system

Configuration

TestFlowKit uses YAML configuration files to define test environments, element selectors, and execution settings. This page covers all configuration options available.

Configuration File

By default, TestFlowKit looks for config.yml in the current directory. You can specify a different file:

tkit run --config my-config.yml

Basic Structure

# Global settings
settings:
  think_time: 1000
  concurrency: 1
  report_format: "html"
  gherkin_location: "features"
  env_file: ".env.yml"  # Optional: external env file

# Environment Variables
# Access these using {{ env.variable_name }} in Gherkin and config
env:
  base_url: "http://localhost:3000"
  jsonplaceholder_base_url: "http://localhost:3001"
  my_graphql_endpoint: "http://localhost:3001/graphql"

# Frontend testing configuration
frontend:
  base_url: "{{ env.base_url }}"
  default_timeout: 1000
  headless: false
  screenshot_on_failure: true
  user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  locale: "en-US"
  timezone_id: "America/New_York"
  pages:
    home: "/"
  elements:
    common:
      submit_button:
        - "#submit-btn"

# API testing configuration
apis:
  default_timeout: 30000
  definitions:
    jsonplaceholder:
      type: rest
      base_url: "{{ env.jsonplaceholder_base_url }}"
      default_headers:
        Content-Type: "application/json"
      endpoints:
        get_users:
          method: "GET"
          path: "/users"
          description: "Get all users"

Environment Variables

Environment variables allow you to define configuration values that can be accessed throughout your tests and configuration files using {{ env.variable_name }} syntax.

Inline Environment Variables

Define variables directly in your config file:

settings:
  concurrency: 1
  gherkin_location: "features"

# Inline environment variables
env:
  base_url: "http://localhost:3000"
  jsonplaceholder_base_url: "http://localhost:3001"
  my_graphql_endpoint: "http://localhost:3001/graphql"
  api_key: "your-api-key"
  
  # Nested variables (accessed with dot notation)
  database:
    host: "localhost"
    port: "5432"
    name: "testdb"

frontend:
  base_url: "{{ env.base_url }}"

External Environment Files

For better organization and environment-specific configurations, use external YAML files:

config.yml:

settings:
  env_file: ".env.local.yml"  # Default env file
  concurrency: 1

.env.local.yml:

base_url: "http://localhost:3000"
jsonplaceholder_base_url: "http://localhost:3001"
my_graphql_endpoint: "http://localhost:3001/graphql"
api_key: "local-dev-key"

database:
  host: "localhost"
  port: "5432"

.env.staging.yml:

base_url: "https://staging.example.com"
jsonplaceholder_base_url: "https://api-staging.example.com"
my_graphql_endpoint: "https://api-staging.example.com/graphql"
api_key: "staging-api-key"

database:
  host: "staging-db.example.com"
  port: "5432"

CLI Override

Override the env file at runtime:

# Use staging environment
tkit run --env-file .env.staging.yml

# Use production environment
tkit run --env-file .env.production.yml

Variable Priority

When the same variable is defined in multiple places, TestFlowKit uses this priority order:

  1. CLI --env-file (highest priority)
  2. Config settings.env_file
  3. Inline env block (lowest priority)

Using Environment Variables

Access environment variables using {{ env.variable_name }} syntax:

In Gherkin:

Given the user goes to "{{ env.base_url }}"
When I prepare a request to "jsonplaceholder.get_user"
And I set the header "Authorization" to "Bearer {{ env.api_key }}"

In Config:

apis:
  definitions:
    jsonplaceholder:
      type: rest
      base_url: "{{ env.jsonplaceholder_base_url }}"
      default_headers:
        Authorization: "Bearer {{ env.api_key }}"
      endpoints:
        get_users:
          method: "GET"
          path: "/users"
          description: "Get all users"

Nested Variables:

# Access nested variables with dot notation
Given I connect to database at "{{ env.database.host }}:{{ env.database.port }}"

Settings Configuration

Global test execution settings:

settings:
  # Delay between actions (ms) - useful for debugging
  think_time: 1000
  
  # Number of parallel test executions (1-20)
  concurrency: 1
  
  # Report output format: html, json, junit
  report_format: "html"
  
  # Location of Gherkin feature files
  gherkin_location: "./features"
  
  # Optional: Path to environment variables file
  env_file: ".env.yml"
  
  # Optional: Filter tests by tags
  tags: "@smoke"

Frontend Configuration

Configure browser-based testing:

frontend:
  # Base URL for the frontend application (required for page navigation)
  # Supports variable interpolation: "{{ env.base_url }}"
  base_url: "http://localhost:3000"
  
  # Default timeout for element interactions (ms)
  default_timeout: 1000
  
  # Run without visible browser window
  headless: false
  
  # Capture screenshots when tests fail
  screenshot_on_failure: true
  
  # Delay between browser actions in milliseconds (simulate human behavior)
  think_time: 1000
  
  # Browser user agent string
  user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  
  # Browser locale (e.g., "en-US", "fr-FR", "de-DE")
  locale: "en-US"
  
  # IANA timezone ID (e.g., "America/New_York", "Europe/Paris", "Asia/Tokyo")
  timezone_id: "America/New_York"
  
  # Page definitions
  pages:
    home: "/"
    login: "/login"
    dashboard: "/dashboard"
    settings: "/settings/profile"
  
  # Element selectors grouped by page or feature
  elements:
    common:
      login_button:
        - "#login-btn"
        - "[data-testid='login']"
        - "button.login"
    
    login_page:
      email_input:
        - "#email"
        - "[name='email']"
      password_input:
        - "#password"
        - "[name='password']"

Browser Configuration

Configure browser behavior for frontend testing:

frontend:
  # Base URL (required) - defines the application URL
  base_url: "http://localhost:3000"
  
  # Timeouts and delays
  default_timeout: 10000      # Element search timeout in milliseconds
  think_time: 1000            # Delay between actions (ms) - simulates human behavior
  
  # Browser mode
  headless: false             # Set to true to run without visible window
  screenshot_on_failure: true # Capture screenshots on test failures
  
  # User agent emulation - customize how the browser identifies itself
  user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  
  # Locale settings - affects language and formatting
  locale: "en-US"             # Browser locale (e.g., "en-US", "fr-FR", "de-DE")
  
  # Timezone - sets the browser timezone
  timezone_id: "America/New_York"  # IANA timezone (e.g., "Europe/Paris", "Asia/Tokyo")

Page Definitions

Define named pages to use in your tests:

frontend:
  pages:
    home: "/"
    login: "/auth/login"
    register: "/auth/register"
    dashboard: "/app/dashboard"
    profile: "/app/settings/profile"

Use in tests:

Given the user goes to the "login" page
# Navigates to https://example.com/auth/login

Element Selectors

Define elements with fallback selectors for robustness. Elements should be grouped by page or feature:

frontend:
  elements:
    # Common elements used across multiple pages
    common:
      header:
        - "#main-header"
      submit_button:
        - "#submit-btn"
        - "[data-testid='submit']"
        - "button[type='submit']"
        - "xpath://button[contains(text(), 'Submit')]"
      user_menu:
        - "[data-testid='user-menu']"
        - ".user-dropdown"
    
    # Login page specific elements
    login_page:
      email_input:
        - "#email"
        - "[name='email']"
        - "input[type='email']"
      password_input:
        - "#password"
        - "[name='password']"
      login_button:
        - "#login-btn"
        - "button[type='submit']"
    
    # Form page elements
    form_page:
      text_field:
        - "xpath://*[@id='text']"
        - "#text-input"
      checkbox:
        - "#checkbox"
        - "input[type='checkbox']"

💡 Selector Priority: TestFlowKit tries selectors in parallel and uses the first one that matches.

💡 Element Grouping: Group elements by their context for better maintainability. Use common for elements shared across pages, or create page-specific groups matching the page names defined in your pages configuration (e.g., if you have a page named login, create a login_page group for its elements).

APIs Configuration

TestFlowKit supports multiple REST and GraphQL APIs with a unified configuration structure. Each API can have its own base URL, headers, timeout, and endpoints/operations.

Structure

apis:
  # Default timeout for all APIs (optional, defaults to 30000ms)
  default_timeout: 30000
  
  # Named API definitions
  definitions:
    # REST API example
    jsonplaceholder:
      type: rest
      base_url: "{{ env.jsonplaceholder_base_url }}"
      timeout: 5000  # Optional: override default timeout
      default_headers:
        Content-Type: "application/json"
        Accept: "application/json"
        User-Agent: "TestFlowKit/1.0"
      endpoints:
        get_users:
          method: "GET"
          path: "/users"
          description: "Retrieve all users"
        
        get_user:
          method: "GET"
          path: "/users/{id}"
          description: "Retrieve a specific user by ID"
        
        create_user:
          method: "POST"
          path: "/users"
          description: "Create a new user"
    
    # GraphQL API example
    my_graphql:
      type: graphql
      endpoint: "{{ env.my_graphql_endpoint }}"
      default_headers:
        Content-Type: "application/json"
        Authorization: "Bearer {{ env.api_token }}"
      operations:
        getUser:
          type: "query"
          operation: |
            query GetUser($id: ID!) {
              user(id: $id) {
                id
                username
                email
              }
            }
          description: "Fetch user by ID"
        
        createPost:
          type: "mutation"
          operation: |
            mutation CreatePost($input: PostInput!) {
              createPost(input: $input) {
                id
                title
                content
              }
            }
          description: "Create a new post"

Using APIs in Tests

Reference APIs using the api_name.endpoint_name syntax:

# REST API
Given I prepare a request to "jsonplaceholder.get_user"
And I set the following path parameters:
  | id | 123 |
When I send the request
Then the response status code should be 200

# GraphQL API
Given I prepare a request to "my_graphql.getUser"
And I set the following GraphQL variables:
  | id | 123 |
When I send the request
Then the GraphQL response should not have errors

REST API Configuration

REST APIs require:

  • type: rest
  • base_url: Base URL for the API (supports environment variables)
  • endpoints: Map of named endpoints with method, path, and description

Optional:

  • default_headers: Headers applied to all requests
  • timeout: Override default timeout for this API

GraphQL API Configuration

GraphQL APIs require:

  • type: graphql
  • endpoint: Full GraphQL endpoint URL (supports environment variables)
  • operations: Map of named operations with type (query/mutation), operation definition, and description

Optional:

  • default_headers: Headers applied to all requests
  • timeout: Override default timeout for this API

Path Parameters

Use {param} syntax for path parameters in REST endpoints:

endpoints:
  get_comment:
    method: GET
    path: "/posts/{postId}/comments/{commentId}"
    description: "Get a specific comment"

Set parameters in tests:

Given I prepare a request to "jsonplaceholder.get_comment"
And I set the following path parameters:
  | postId    | 123 |
  | commentId | 456 |
When I send the request

Header Merging

Headers are merged with this priority (highest to lowest):

  1. Request-specific headers (set in test steps)
  2. API default headers
  3. Global headers
# API default headers are automatically applied
Given I prepare a request to "jsonplaceholder.get_user"
# Additional headers override defaults
And I set the request header "Authorization" to "Bearer custom-token"
When I send the request

Backend Configuration (Deprecated)

⚠️ Deprecated: The old backend configuration is deprecated in favor of the new apis structure. Please migrate to the new format.

The old backend configuration:

backend:
  # Default headers for all API requests
  default_headers:
    Content-Type: "application/json"
  
  # API endpoint definitions
  endpoints:
    get_users:
      method: "GET"
      path: "/users"
      description: "Retrieve all users"
    
    get_user:
      method: "GET"
      path: "/users/{id}"
      description: "Retrieve a specific user by ID"
    
    create_user:
      method: "POST"
      path: "/users"
      description: "Create a new user"
    
    update_user:
      method: "PUT"
      path: "/users/{id}"
      description: "Update an existing user"
    
    delete_user:
      method: "DELETE"
      path: "/users/{id}"
      description: "Delete a user"

💡 Base URL: The API base URL is defined in the environments section as rest_api_base_url.

Endpoint Path Parameters

Use {param} syntax for path parameters:

endpoints:
  get_post:
    method: GET
    path: "/posts/{postId}/comments/{commentId}"

Set parameters in tests:

Given I prepare a request for the "get_post" endpoint
And I set the following path parameters:
  | postId    | 123 |
  | commentId | 456 |
When I send the request

GraphQL Configuration

Configure GraphQL API testing within the backend section. The endpoint URL is defined in the environment variables:

# Environment variables
env:
  graphql_endpoint: "https://graphqlzero.almansi.me/api"

# Backend section
backend:
  graphql:
    # Default headers for GraphQL requests
    default_headers:
      Content-Type: "application/json"
      Authorization: "Bearer ${TOKEN}"
    
    # GraphQL operations
    operations:
      getUser:
        type: "query"
        operation: |
          query GetUser($id: ID!) {
            user(id: $id) {
              id
              username
              email
            }
          }
        description: "Fetch user by ID"
      
      createPost:
        type: "mutation"
        operation: "graphql_queries/create_post.graphql"
        description: "Create a new post"
      
      deletePost:
        type: "mutation"
        operation: |
          mutation DeletePost($id: ID!) {
            deletePost(id: $id)
          }
        description: "Delete a post"

💡 Endpoint Location: The GraphQL endpoint URL must be defined in your environment variables as graphql_endpoint, not in the backend section.

💡 Operation Types: Specify whether each operation is a query or mutation.

💡 Inline vs File: Operations can be defined inline using the | multiline syntax, or reference external .graphql files.

Files Configuration

Configure file paths for file upload testing:

files:
  # Base directory for test files
  base_directory: "./test-files"
  
  # Named file definitions
  definitions:
    avatar_image: "images/avatar.png"
    gallery_image1: "images/gallery/image1.jpg"
    gallery_image2: "images/gallery/image2.jpg"
    test_document: "documents/test.pdf"
    sample_csv: "data/sample.csv"

Use in tests:

When I upload the "avatar_image" file to the "avatar_field" field
And I upload the following files to the "gallery_field" field:
  | gallery_image1 |
  | gallery_image2 |

Switching Environments

Switch between environments using different environment files:

Using default env file in config:

settings:
  env_file: ".env.local.yml"  # Default environment

Override with CLI:

# Use staging environment
tkit run --env-file .env.staging.yml

# Use production environment
tkit run --env-file .env.production.yml

Or use inline env variables:

env:
  base_url: "http://localhost:3000"
  rest_api_base_url: "http://localhost:3001"
  graphql_endpoint: "http://localhost:3001/graphql"

frontend:
  base_url: "{{ env.base_url }}"

Complete Example

settings:
  think_time: 1000
  concurrency: 1
  report_format: "html"
  gherkin_location: "./features"
  tags: "@smoke"
  env_file: ".env.local.yml"  # Optional: default env file

# Inline environment variables (or use external files)
env:
  base_url: "http://localhost:3000"
  rest_api_base_url: "http://localhost:3001"
  graphql_endpoint: "http://localhost:3001/graphql"

frontend:
  base_url: "{{ env.base_url }}"
  default_timeout: 1000
  headless: false
  screenshot_on_failure: true
  user_agent: "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
  locale: "en-US"
  timezone_id: "America/New_York"
  
  pages:
    home: "/"
    login: "/login"
    register: "/register"
    dashboard: "/dashboard"
    profile: "/settings/profile"
  
  elements:
    common:
      nav_home:
        - "[data-testid='nav-home']"
      nav_dashboard:
        - "[data-testid='nav-dashboard']"
      user_menu:
        - "[data-testid='user-menu']"
        - "#user-dropdown"
    
    login_page:
      email_input:
        - "#email"
        - "[name='email']"
        - "input[type='email']"
      password_input:
        - "#password"
        - "[name='password']"
      login_button:
        - "#login-btn"
        - "button[type='submit']"
    
    messages:
      error_message:
        - ".alert-error"
      success_message:
        - ".alert-success"

backend:
  default_headers:
    Content-Type: "application/json"
    Accept: "application/json"
  
  endpoints:
    login:
      method: "POST"
      path: "/auth/login"
      description: "Authenticate user"
    get_profile:
      method: "GET"
      path: "/users/me"
      description: "Get current user profile"
    update_profile:
      method: "PUT"
      path: "/users/{id}"
      description: "Update user profile"
  
  graphql:
    default_headers:
      Content-Type: "application/json"
      Authorization: "Bearer ${TOKEN}"
    operations:
      getUser:
        type: "query"
        operation: |
          query GetUser($id: ID!) {
            user(id: $id) {
              id
              username
              email
            }
          }
        description: "Fetch user by ID"

files:
  base_directory: "./test-files"
  definitions:
    avatar_image: "images/avatar.png"
    test_document: "documents/test.pdf"
    sample_data: "data/sample.csv"

Next Steps