From 7723b3dc9fb69f916271ff677d41b295e7103c68 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 3 Sep 2025 05:28:56 +0000 Subject: [PATCH 1/2] I have created all the necessary files for the 'Core Concepts' section of the documentation, including the meta.json and all the .mdx files for the different topics. I have created the files for the 'DSL Reference' section as outlined in Phase 1 of the documentation plan. I have created all the necessary files for the 'Variables & Environment' section of the documentation, as part of Phase 1. I have created all the necessary files for the 'CLI Reference' section of the documentation, as part of Phase 1. I have updated the main meta.json file to include the new documentation sections and have reviewed and corrected the content in the 'Getting Started' section to be consistent with the new documentation. --- docs/content/docs/cli/command-overview.mdx | 48 ++++++++++ docs/content/docs/cli/meta.json | 7 ++ docs/content/docs/cli/run-command.mdx | 72 +++++++++++++++ .../docs/core-concepts/assertions-basics.mdx | 68 ++++++++++++++ .../content/docs/core-concepts/dsl-basics.mdx | 48 ++++++++++ .../core-concepts/environment-management.mdx | 48 ++++++++++ .../docs/core-concepts/flows-and-steps.mdx | 45 +++++++++ docs/content/docs/core-concepts/meta.json | 10 ++ .../docs/core-concepts/variables-overview.mdx | 55 +++++++++++ .../dsl-reference/assertions-reference.mdx | 92 +++++++++++++++++++ docs/content/docs/dsl-reference/meta.json | 7 ++ .../docs/dsl-reference/syntax-overview.mdx | 85 +++++++++++++++++ .../docs/getting-started/quick-start.mdx | 59 +++--------- docs/content/docs/meta.json | 10 +- .../docs/variables/built-in-variables.mdx | 82 +++++++++++++++++ .../docs/variables/environment-files.mdx | 51 ++++++++++ docs/content/docs/variables/meta.json | 8 ++ .../content/docs/variables/variable-types.mdx | 59 ++++++++++++ 18 files changed, 807 insertions(+), 47 deletions(-) create mode 100644 docs/content/docs/cli/command-overview.mdx create mode 100644 docs/content/docs/cli/meta.json create mode 100644 docs/content/docs/cli/run-command.mdx create mode 100644 docs/content/docs/core-concepts/assertions-basics.mdx create mode 100644 docs/content/docs/core-concepts/dsl-basics.mdx create mode 100644 docs/content/docs/core-concepts/environment-management.mdx create mode 100644 docs/content/docs/core-concepts/flows-and-steps.mdx create mode 100644 docs/content/docs/core-concepts/meta.json create mode 100644 docs/content/docs/core-concepts/variables-overview.mdx create mode 100644 docs/content/docs/dsl-reference/assertions-reference.mdx create mode 100644 docs/content/docs/dsl-reference/meta.json create mode 100644 docs/content/docs/dsl-reference/syntax-overview.mdx create mode 100644 docs/content/docs/variables/built-in-variables.mdx create mode 100644 docs/content/docs/variables/environment-files.mdx create mode 100644 docs/content/docs/variables/meta.json create mode 100644 docs/content/docs/variables/variable-types.mdx diff --git a/docs/content/docs/cli/command-overview.mdx b/docs/content/docs/cli/command-overview.mdx new file mode 100644 index 0000000..09948ee --- /dev/null +++ b/docs/content/docs/cli/command-overview.mdx @@ -0,0 +1,48 @@ +--- +title: Command Overview +description: An overview of all available CLI commands +--- + +The Restflow CLI is the primary way to execute your API tests. The base command is `restflow`. + +You can get help at any time by running: +```bash +restflow --help +``` + +### Main Commands + +Restflow has a few main commands for different tasks. + +#### `restflow run` + +This is the most important command. It is used to execute one or more `.flow` files. + +```bash +# Run a single flow +restflow run path/to/your.flow + +# Run all flows in a directory +restflow run path/to/your/flows/ +``` + +This command has many options for controlling the execution, which are detailed on the `run` command page. + +#### `restflow init` + +The `init` command helps you set up a new Restflow project or add Restflow to an existing one. It can create a sample project structure with example flows and an environment file. + +```bash +# Initialize a new Restflow project in the current directory +restflow init +``` + +This is a great way to get started quickly. + +### Global Options + +These options can be used with any command. + +- `--help`: Show help information. +- `--version`: Show the installed version of Restflow. +- `--verbose`: Enable detailed logging, which can be useful for debugging. diff --git a/docs/content/docs/cli/meta.json b/docs/content/docs/cli/meta.json new file mode 100644 index 0000000..d42120d --- /dev/null +++ b/docs/content/docs/cli/meta.json @@ -0,0 +1,7 @@ +{ + "title": "CLI Reference", + "pages": [ + "command-overview", + "run-command" + ] +} diff --git a/docs/content/docs/cli/run-command.mdx b/docs/content/docs/cli/run-command.mdx new file mode 100644 index 0000000..0025afc --- /dev/null +++ b/docs/content/docs/cli/run-command.mdx @@ -0,0 +1,72 @@ +--- +title: The 'run' Command +description: Running flows with various options +--- + +The `restflow run` command is used to execute your `.flow` files. You can specify one or more files or directories as arguments. + +### Basic Usage + +```bash +# Run a single flow file +restflow run my-test.flow + +# Run multiple specific flow files +restflow run test1.flow test2.flow + +# Run all flow files in a directory (and its subdirectories) +restflow run ./tests/ +``` + +### Command Options + +The `run` command has several options to customize its behavior. + +#### `--env ` or `-e ` + +Load environment variables from a specific file. + +```bash +restflow run tests/ --env .env.staging +``` + +#### `--format ` or `-f ` + +Specify the output format. +- `console` (default): Human-readable, colored output. +- `json`: Machine-readable JSON output. +- `summary`: A concise table of results. + +```bash +restflow run tests/ --format json > results.json +``` + +#### `--timeout ` + +Set a timeout in milliseconds for each HTTP request. The default is typically 30 seconds (30000 ms). + +```bash +# Set a 10-second timeout +restflow run tests/ --timeout 10000 +``` + +#### `--show-body` + +Include the request and response bodies in the output. This is very useful for debugging. + +#### `--show-headers` + +Include the request and response headers in the output. + +#### `--verbose` + +Enable verbose logging for more detailed output about the execution process. + +### Combining Options + +You can combine these options to suit your needs. + +```bash +# Run tests against staging, with a 5s timeout, and show bodies and headers +restflow run tests/ --env .env.staging --timeout 5000 --show-body --show-headers +``` diff --git a/docs/content/docs/core-concepts/assertions-basics.mdx b/docs/content/docs/core-concepts/assertions-basics.mdx new file mode 100644 index 0000000..ac55157 --- /dev/null +++ b/docs/content/docs/core-concepts/assertions-basics.mdx @@ -0,0 +1,68 @@ +--- +title: Assertions Basics +description: Writing basic assertions and validations +--- + +Assertions are used to verify that your API is behaving as expected. In Restflow, you use the `assert` directive to check the status code, headers, and body of a response. + +### The `assert` Directive + +The `assert` directive has the following structure: + +`> assert ` + +- **source**: The part of the response to check (e.g., `status`, `body.id`, `headers["content-type"]`). +- **operator**: The comparison to perform (e.g., `==`, `!=`, `>`, `contains`). +- **value**: The expected value. + +If an assertion fails, the step is marked as failed, and the execution of the flow may stop depending on your configuration. + +### Common Assertions + +Here are some of the most common assertions you'll use: + +#### Checking the Status Code + +This is the most fundamental assertion. You should almost always check the status code. + +```flow +### Get a resource +GET https://api.example.com/items/1 + +> assert status == 200 +``` + +#### Checking the Response Body + +You can use JSONPath to access values in a JSON response body. + +```flow +### Get a user +GET https://api.example.com/users/123 + +> assert body.id == 123 +> assert body.name == "John Doe" +> assert body.address.city == "New York" +``` + +#### Checking for Existence + +You can check if a field exists in the response. + +```flow +> assert body.id != null +``` + +#### Checking Array Length + +```flow +> assert body.items.length > 0 +``` + +#### Checking Headers + +```flow +> assert headers["content-type"] contains "application/json" +``` + +These are just the basics. The "DSL Reference" section has a complete guide to all the available assertion operators and advanced techniques. diff --git a/docs/content/docs/core-concepts/dsl-basics.mdx b/docs/content/docs/core-concepts/dsl-basics.mdx new file mode 100644 index 0000000..b1dd6c4 --- /dev/null +++ b/docs/content/docs/core-concepts/dsl-basics.mdx @@ -0,0 +1,48 @@ +--- +title: DSL Basics +description: Introduction to the .flow file syntax +--- + +The Restflow DSL (Domain-Specific Language) is designed to be simple, readable, and easy to write. All tests are written in `.flow` files using a plain text format. + +### Basic Structure + +A `.flow` file is composed of one or more steps. Each step has the following structure: + +``` +### Step Name +HTTP_METHOD URL +Header-Name: Header-Value + +Request Body + +> directive +``` + +- **Step Name**: A descriptive name for your step, starting with `###`. +- **HTTP Method and URL**: The HTTP method (e.g., `GET`, `POST`) and the endpoint URL. +- **Headers**: Optional HTTP headers, one per line. +- **Request Body**: The body of the request, separated from the headers by a blank line. +- **Directives**: Actions to perform after the request, such as assertions or capturing variables. Each directive starts with `>`. + +### Example + +Here's a complete example of a `.flow` file with a single step: + +```flow +### Create a new user +POST https://api.example.com/users +Content-Type: application/json +Authorization: Bearer {{api_key}} + +{ + "name": "John Doe", + "email": "john.doe@example.com" +} + +> assert status == 201 +> assert body.id != null +> capture userId = body.id +``` + +This example demonstrates all the basic components of the DSL in action. As you can see, it's designed to be self-documenting and easy to understand at a glance. diff --git a/docs/content/docs/core-concepts/environment-management.mdx b/docs/content/docs/core-concepts/environment-management.mdx new file mode 100644 index 0000000..ec1b812 --- /dev/null +++ b/docs/content/docs/core-concepts/environment-management.mdx @@ -0,0 +1,48 @@ +--- +title: Environment Management +description: Managing environments and configurations +--- + +Real-world API testing requires running the same tests against different environments, such as development, staging, and production. Restflow makes this easy with its support for `.env` files. + +### What is an `.env` file? + +An `.env` file is a simple text file that contains key-value pairs for your environment-specific variables. + +Here is an example `.env` file: + +```env +# .env.staging +BASE_URL=https://staging.api.example.com +API_KEY=staging-secret-key +TEST_USER=staging_user +``` + +### Using Environment Variables + +You can use the variables from your `.env` file in your flows using the `{{variable_name}}` syntax. + +```flow +### Get data from a protected endpoint +GET {{BASE_URL}}/data +Api-Key: {{API_KEY}} + +> assert status == 200 +``` + +### Running with an Environment + +To run your flows with a specific environment file, use the `--env` flag on the command line: + +```bash +restflow run my-flow.flow --env .env.staging +``` + +When you run this command, Restflow will load the variables from `.env.staging` and make them available in your flow. + +This allows you to keep your `.flow` files clean and free of environment-specific details. You can have multiple `.env` files for your different environments: +- `.env.dev` +- `.env.staging` +- `.env.prod` + +And switch between them easily using the `--env` flag. This is a powerful feature for creating portable and maintainable API tests. diff --git a/docs/content/docs/core-concepts/flows-and-steps.mdx b/docs/content/docs/core-concepts/flows-and-steps.mdx new file mode 100644 index 0000000..5ba0adf --- /dev/null +++ b/docs/content/docs/core-concepts/flows-and-steps.mdx @@ -0,0 +1,45 @@ +--- +title: Flows and Steps +description: Understanding the basic structure of Restflow tests +--- + +In Restflow, your API tests are organized into **flows** and **steps**. This structure helps you create readable, maintainable, and powerful tests. + +### Flows + +A **flow** is a single `.flow` file that contains a sequence of steps. It represents a complete user journey or a set of related API tests. For example, a `login.flow` file could contain all the steps required to authenticate a user. + +Flows are executed from top to bottom. You can run a single flow or multiple flows at once. + +### Steps + +A **step** is a single API request within a flow. Each step has a name, an HTTP request, and optional directives for assertions and variable capturing. + +A step is defined using `###` followed by the step name. + +Here is an example of a flow with two steps: + +```flow +### Step 1: Get a post +GET https://jsonplaceholder.typicode.com/posts/1 + +> assert status == 200 + +### Step 2: Create a new post +POST https://jsonplaceholder.typicode.com/posts +Content-Type: application/json + +{ + "title": "My new post", + "body": "A great post" +} + +> assert status == 201 +``` + +In this example: +- The file itself represents the flow. +- "Get a post" is the first step. +- "Create a new post" is the second step. + +Each step is independent by default, but you can use variables to pass data between steps, creating powerful testing workflows. diff --git a/docs/content/docs/core-concepts/meta.json b/docs/content/docs/core-concepts/meta.json new file mode 100644 index 0000000..827250c --- /dev/null +++ b/docs/content/docs/core-concepts/meta.json @@ -0,0 +1,10 @@ +{ + "title": "Core Concepts", + "pages": [ + "flows-and-steps", + "dsl-basics", + "variables-overview", + "assertions-basics", + "environment-management" + ] +} diff --git a/docs/content/docs/core-concepts/variables-overview.mdx b/docs/content/docs/core-concepts/variables-overview.mdx new file mode 100644 index 0000000..61fc2de --- /dev/null +++ b/docs/content/docs/core-concepts/variables-overview.mdx @@ -0,0 +1,55 @@ +--- +title: Variables Overview +description: A brief introduction to variables in Restflow +--- + +Variables are a key feature of Restflow, allowing you to create dynamic and flexible API tests. You can use variables to pass data between steps, use environment-specific values, and generate random data. + +### Variable Syntax + +Variables in Restflow use the `{{variable_name}}` syntax. When a flow is executed, Restflow replaces these placeholders with their corresponding values. + +```flow +### Get user profile +GET https://api.example.com/users/{{userId}} +Authorization: Bearer {{auth_token}} +``` + +### Types of Variables + +Restflow supports several types of variables: + +- **Environment Variables**: Loaded from `.env` files. Useful for storing environment-specific data like API keys and base URLs. +- **Captured Variables**: Extracted from the response of a previous step using the `capture` directive. This is how you chain requests together. +- **Built-in Variables**: Provided by Restflow for generating dynamic data like `{{uuid}}`, `{{timestamp}}`, and `{{randomString}}`. +- **CLI Variables**: Passed from the command line when running a flow. + +### A Simple Workflow + +Here's an example of how variables connect steps in a workflow: + +```flow +### 1. Login and get a token +POST https://api.example.com/login +Content-Type: application/json + +{ + "username": "{{test_user}}", + "password": "{{test_password}}" +} + +> capture auth_token = body.token + +### 2. Use the token to access a protected resource +GET https://api.example.com/profile +Authorization: Bearer {{auth_token}} + +> assert status == 200 +``` + +In this example: +1. `{{test_user}}` and `{{test_password}}` are likely defined in an environment file. +2. The `capture` directive saves the `token` from the login response into the `auth_token` variable. +3. The `auth_token` variable is then used in the `Authorization` header of the next request. + +This is just a brief overview. The "Variables & Environment" section provides more in-depth information on each variable type. diff --git a/docs/content/docs/dsl-reference/assertions-reference.mdx b/docs/content/docs/dsl-reference/assertions-reference.mdx new file mode 100644 index 0000000..1968d11 --- /dev/null +++ b/docs/content/docs/dsl-reference/assertions-reference.mdx @@ -0,0 +1,92 @@ +--- +title: Assertions Reference +description: A complete guide to assertions in Restflow +--- + +Assertions are the core of API testing in Restflow. They allow you to validate the responses from your API. This page covers all the types of assertions available. + +### Assertion Syntax + +All assertions use the `assert` directive: + +`> assert ` + +### Status Code Assertions + +You can use standard comparison operators to check the HTTP status code. + +```flow +> assert status == 200 +> assert status != 404 +> assert status >= 200 +> assert status < 500 +``` + +### Response Body Assertions + +For JSON responses, you can use JSONPath to access nested values in the response body. The `body` keyword represents the root of the JSON response. + +```flow +# For a response like: { "user": { "id": 123, "name": "John" }, "posts": [...] } +> assert body.user.id == 123 +> assert body.user.name == "John" +> assert body.posts.length > 0 +``` + +### Response Header Assertions + +You can access response headers using the `headers` keyword. Header names are case-insensitive. + +```flow +> assert headers["content-type"] contains "application/json" +> assert headers["x-request-id"] != null +``` + +### Regular Expression Assertions + +The `matches` operator allows you to use regular expressions for more complex string validations. + +```flow +# Check that a message starts with "Success" +> assert body.message matches "^Success" + +# Check that an ID is a number +> assert body.id matches "\\d+" +``` + +### Existence and Type Assertions + +You can check for the existence or non-existence of a field, or check its type. + +```flow +# Check that a token field exists +> assert body.token != null + +# Check that an error field does not exist +> assert body.error == null + +# Check the type of a value +> assert body.user.id is number +> assert body.user.name is string +> assert body.user.isActive is boolean +> assert body.posts is array +``` + +### Comparison Operators + +Restflow supports a rich set of comparison operators: + +| Operator | Description | +|---|---| +| `==` | Equal | +| `!=` | Not equal | +| `>` | Greater than | +| `>=` | Greater than or equal to | +| `<` | Less than | +| `<=` | Less than or equal to | +| `contains` | String or array contains a value | +| `not contains` | String or array does not contain a value | +| `matches` | Regular expression match | +| `not matches` | Regular expression non-match | +| `is` | Type check (e.g., `is number`, `is string`) | +| `is not`| Negated type check | diff --git a/docs/content/docs/dsl-reference/meta.json b/docs/content/docs/dsl-reference/meta.json new file mode 100644 index 0000000..17a9a8e --- /dev/null +++ b/docs/content/docs/dsl-reference/meta.json @@ -0,0 +1,7 @@ +{ + "title": "DSL Reference", + "pages": [ + "syntax-overview", + "assertions-reference" + ] +} diff --git a/docs/content/docs/dsl-reference/syntax-overview.mdx b/docs/content/docs/dsl-reference/syntax-overview.mdx new file mode 100644 index 0000000..2d862a8 --- /dev/null +++ b/docs/content/docs/dsl-reference/syntax-overview.mdx @@ -0,0 +1,85 @@ +--- +title: Syntax Overview +description: A complete reference for the Restflow DSL syntax +--- + +The Restflow DSL is designed to be as readable and intuitive as possible. This page provides a comprehensive reference for all the components of the `.flow` file syntax. + +### File Structure + +A `.flow` file is a plain text file that consists of one or more steps. Comments can be added on any line by starting the line with a `#`. + +### Step Declaration + +Every step must begin with a level-3 markdown header (`###`). + +```flow +### This is a valid step name +``` + +### HTTP Request + +The line immediately following the step name defines the HTTP request. + +```flow +METHOD /path/to/resource +``` + +- **Supported Methods**: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`. +- **URL**: Can be a relative path (e.g., `/users/1`) or a full URL (e.g., `https://api.example.com/users/1`). Relative paths are automatically prefixed with the `BASE_URL` from your environment file. + +### Headers + +HTTP headers are specified as key-value pairs, one per line, after the request line. + +```flow +Content-Type: application/json +Authorization: Bearer {{token}} +``` + +### Request Body + +The request body is placed after the headers, separated by a single blank line. + +```flow +{ + "name": "John Doe", + "email": "john@example.com" +} +``` + +### Directives + +Directives are special commands that are executed after the HTTP request is complete. They always start with a `>` character. + +The two main directives are `assert` and `capture`. + +```flow +> assert status == 200 +> capture userId = body.id +``` + +### A Complete Example + +Putting it all together, here is a complete, valid step: + +```flow +# This flow registers a new user and captures their ID. +### Register New User +POST /users +Content-Type: application/json + +{ + "name": "Jane Doe", + "email": "jane.doe@example.com", + "password": "a-secure-password" +} + +# Verify that the user was created successfully +> assert status == 201 +> assert body.id != null +> assert body.email == "jane.doe@example.com" + +# Capture the new user's ID for use in subsequent steps +> capture userId = body.id +``` diff --git a/docs/content/docs/getting-started/quick-start.mdx b/docs/content/docs/getting-started/quick-start.mdx index 8fc4ab7..1b4b394 100644 --- a/docs/content/docs/getting-started/quick-start.mdx +++ b/docs/content/docs/getting-started/quick-start.mdx @@ -11,8 +11,7 @@ Create a new file called `api-test.flow`: ```flow ### Test User API -GET /users/1 -Host: jsonplaceholder.typicode.com +GET https://jsonplaceholder.typicode.com/users/1 > assert status == 200 > assert body.id == 1 @@ -44,9 +43,8 @@ Tests: 1 passed, 0 failed Make your tests dynamic with variables: ```flow -### Create and Get User -POST /users -Host: jsonplaceholder.typicode.com +### Create a User +POST https://jsonplaceholder.typicode.com/users Content-Type: application/json { @@ -54,11 +52,10 @@ Content-Type: application/json "email": "test-{{uuid}}@example.com" } -> capture body.id as userId +> capture userId = body.id ### Get Created User -GET /users/{{userId}} -Host: jsonplaceholder.typicode.com +GET https://jsonplaceholder.typicode.com/users/{{userId}} > assert status == 200 > assert body.id == {{userId}} @@ -66,25 +63,25 @@ Host: jsonplaceholder.typicode.com ## 4. Environment Configuration -Create `.env` file for environment-specific settings: +Create a `.env` file for environment-specific settings: -```bash +```env # .env BASE_URL=https://jsonplaceholder.typicode.com API_KEY=your-api-key ``` -Update your flow: +Update your flow to use the `BASE_URL`: ```flow ### Get User with Environment -GET /users/1 +GET {{BASE_URL}}/users/1 Authorization: Bearer {{API_KEY}} > assert status == 200 ``` -Run with environment: +Run with the environment: ```bash restflow run api-test.flow --env .env @@ -94,44 +91,16 @@ restflow run api-test.flow --env .env **JSON Output:** ```bash -restflow run api-test.flow --output json +restflow run api-test.flow --format json ``` **Summary View:** ```bash -restflow run api-test.flow --output summary -``` - -## Common Patterns - -**Testing API Endpoints:** -```flow -### Test Multiple Endpoints -GET /users -> assert status == 200 -> assert body.length > 0 - -### Check Individual User -GET /users/1 -> assert body.name == "Leanne Graham" -``` - -**Using Built-in Variables:** -```flow -### Dynamic Test Data -POST /posts -Content-Type: application/json - -{ - "title": "Test Post {{timestamp}}", - "userId": {{randomNumber}} -} - -> assert status == 201 +restflow run api-test.flow --format summary ``` ## Next Steps - [Set up a complete project](/docs/getting-started/project-setup) -- [Learn the Flow syntax](/docs/writing-flows/basics) -- [Explore variables and environments](/docs/writing-flows/variables) \ No newline at end of file +- [Learn the DSL syntax](/docs/dsl-reference/syntax-overview) +- [Explore variables and environments](/docs/variables/variable-types) \ No newline at end of file diff --git a/docs/content/docs/meta.json b/docs/content/docs/meta.json index 2553a00..e2615cc 100644 --- a/docs/content/docs/meta.json +++ b/docs/content/docs/meta.json @@ -1,4 +1,10 @@ { - "title": "Documentation", - "pages": ["getting-started", "dsl-reference", "variables", "cli", "examples"] + "title": "Documentation", + "pages": [ + "getting-started", + "core-concepts", + "dsl-reference", + "variables", + "cli" + ] } \ No newline at end of file diff --git a/docs/content/docs/variables/built-in-variables.mdx b/docs/content/docs/variables/built-in-variables.mdx new file mode 100644 index 0000000..fe69b9a --- /dev/null +++ b/docs/content/docs/variables/built-in-variables.mdx @@ -0,0 +1,82 @@ +--- +title: Built-in Variables +description: Using Restflow's built-in dynamic variables +--- + +Restflow includes a set of built-in variables that you can use to generate dynamic data for your tests. This is incredibly useful for creating unique resources or for testing with random values. + +**Important Note**: A new, unique value is generated every time a built-in variable is referenced. If you need to use the same generated value in multiple places, you should capture it first. + +### `{{uuid}}` + +Generates a standard Version 4 UUID (Universally Unique Identifier). + +**Use case**: Creating resources that require a unique identifier, or for `X-Request-ID` headers. + +```flow +### Create a new user with a unique email +POST /users +Content-Type: application/json + +{ + "email": "user-{{uuid}}@example.com", + "password": "password123" +} +``` + +### `{{timestamp}}` + +Generates the current Unix timestamp (the number of seconds since the Unix epoch). + +**Use case**: Timestamps for created resources, or for testing time-based functionality. + +```flow +### Create a post with a dynamic title +POST /posts +Content-Type: application/json + +{ + "title": "Post created at {{timestamp}}", + "body": "This is the content." +} +``` + +### `{{randomString}}` + +Generates a random alphanumeric string of a variable length. + +**Use case**: Creating unique usernames, names, or other text fields. + +```flow +### Register a user with a random username +POST /register +Content-Type: application/json + +{ + "username": "user_{{randomString}}", + "email": "email_{{randomString}}@example.com" +} +``` + +### `{{randomNumber}}` + +Generates a random integer between 0 and 999999. + +**Use case**: Testing with random numerical data, such as quantities or ratings. + +```flow +### Add an item to a cart with a random quantity +POST /cart/items +Content-Type: application/json + +{ + "item_id": 123, + "quantity": {{randomNumber}} +} +``` + +### Ensuring Consistency + +If you need to use the same random value in multiple places, capture it from a header or body. A common pattern is to send it in a request header and capture it from the response if the API echoes it back. + +A simpler way is to use it in an environment variable, but that is a more advanced topic. diff --git a/docs/content/docs/variables/environment-files.mdx b/docs/content/docs/variables/environment-files.mdx new file mode 100644 index 0000000..31cebb8 --- /dev/null +++ b/docs/content/docs/variables/environment-files.mdx @@ -0,0 +1,51 @@ +--- +title: Environment Files +description: .env file structure and best practices +--- + +Environment files (or `.env` files) are the standard way to manage environment-specific configuration in Restflow. They allow you to keep your `.flow` files clean and portable across different environments like development, staging, and production. + +### File Format + +An `.env` file is a simple text file with `KEY=VALUE` pairs. + +```env +# This is a comment +BASE_URL=https://api.example.com +API_KEY=your-secret-api-key +TEST_USER_EMAIL=test@example.com +``` + +- Comments start with `#`. +- Keys are typically uppercase, but this is not required. +- Values are everything after the `=`. Do not use quotes unless they are part of the value. + +### Naming Conventions + +While you can name your environment files anything, a common convention is to use `.env.`. + +- `.env.development` +- `.env.staging` +- `.env.production` +- `.env.local` (for local overrides) + +### Loading an Environment File + +Use the `--env` or `-e` flag when running Restflow to specify which environment file to load. + +```bash +# Run tests against the staging environment +restflow run tests/ --env .env.staging + +# Run tests against the production environment +restflow run tests/ --env .env.production +``` + +If you don't specify an `--env` flag, Restflow will automatically look for a file named `.env` in the current directory. + +### Best Practices + +1. **Never commit secrets**: Add your `.env` files with sensitive information (like API keys and passwords) to your `.gitignore` file. +2. **Create a template file**: Create an example file like `.env.example` with all the required keys but with placeholder values. Commit this file to your repository so other developers know what variables are needed. +3. **Use `BASE_URL`**: Define a `BASE_URL` in your environment files and use relative paths in your flows. This makes your tests highly portable. +4. **Keep it flat for now**: While Restflow supports advanced features like variable chaining in `.env` files, it's best to start with a simple, flat list of key-value pairs. diff --git a/docs/content/docs/variables/meta.json b/docs/content/docs/variables/meta.json new file mode 100644 index 0000000..97b7ed1 --- /dev/null +++ b/docs/content/docs/variables/meta.json @@ -0,0 +1,8 @@ +{ + "title": "Variables & Environment", + "pages": [ + "variable-types", + "built-in-variables", + "environment-files" + ] +} diff --git a/docs/content/docs/variables/variable-types.mdx b/docs/content/docs/variables/variable-types.mdx new file mode 100644 index 0000000..662b9ee --- /dev/null +++ b/docs/content/docs/variables/variable-types.mdx @@ -0,0 +1,59 @@ +--- +title: Variable Types +description: Understanding the different types of variables in Restflow +--- + +Restflow has a powerful variable system with several types of variables. Understanding each type will help you write more dynamic and maintainable tests. + +### Variable Resolution Priority + +When a variable is used, Restflow searches for its value in the following order of priority (from highest to lowest): + +1. **CLI Variables**: Passed via the command line. +2. **Captured Variables**: Extracted from a previous step's response. +3. **Environment Variables**: Loaded from `.env` files. +4. **Built-in Variables**: Provided by Restflow for dynamic data generation. + +This means that a CLI variable will override an environment variable with the same name. + +### 1. CLI Variables + +You can pass variables directly from the command line when you run a flow. This is useful for overriding default values or for use in CI/CD pipelines. + +*(Note: The exact syntax for passing CLI variables will be covered in the CLI Reference section.)* + +### 2. Captured Variables + +These variables are created using the `capture` directive. They allow you to extract a value from an HTTP response and use it in subsequent requests. This is the primary way to chain requests together. + +```flow +### Login and capture token +POST /login +... +> capture auth_token = body.token + +### Use the captured token +GET /profile +Authorization: Bearer {{auth_token}} +``` + +### 3. Environment Variables + +Environment variables are loaded from `.env` files and are typically used for environment-specific configuration like API keys, base URLs, or test user credentials. + +```env +# .env.staging +BASE_URL=https://staging.api.example.com +API_KEY=my-secret-key +``` + +### 4. Built-in Variables + +Restflow provides a set of built-in variables for generating common types of dynamic data. + +- `{{uuid}}`: A version 4 UUID. +- `{{timestamp}}`: A Unix timestamp. +- `{{randomString}}`: A random alphanumeric string. +- `{{randomNumber}}`: A random number. + +Each time a built-in variable is used, it generates a new, unique value. From 41e8a90daf80bab80b77f9ba7496985c9523efb5 Mon Sep 17 00:00:00 2001 From: mxvsh Date: Wed, 3 Sep 2025 11:21:38 +0530 Subject: [PATCH 2/2] chore: improve docs --- .../core-concepts/environment-management.mdx | 2 +- .../docs/getting-started/installation.mdx | 2 +- .../docs/getting-started/quick-start.mdx | 6 +- docs/content/docs/index.mdx | 2 +- docs/content/docs/meta.json | 31 ++++-- .../docs/variables/environment-files.mdx | 2 +- .../content/docs/variables/variable-types.mdx | 2 +- docs/source.config.ts | 1 + docs/src/routeTree.gen.ts | 34 +++--- docs/src/routes/$.tsx | 100 ++++++++++++++++++ docs/src/routes/index.tsx | 24 ----- 11 files changed, 148 insertions(+), 58 deletions(-) create mode 100644 docs/src/routes/$.tsx delete mode 100644 docs/src/routes/index.tsx diff --git a/docs/content/docs/core-concepts/environment-management.mdx b/docs/content/docs/core-concepts/environment-management.mdx index ec1b812..c23c4f6 100644 --- a/docs/content/docs/core-concepts/environment-management.mdx +++ b/docs/content/docs/core-concepts/environment-management.mdx @@ -11,7 +11,7 @@ An `.env` file is a simple text file that contains key-value pairs for your envi Here is an example `.env` file: -```env +```dotenv # .env.staging BASE_URL=https://staging.api.example.com API_KEY=staging-secret-key diff --git a/docs/content/docs/getting-started/installation.mdx b/docs/content/docs/getting-started/installation.mdx index a5141cd..0213274 100644 --- a/docs/content/docs/getting-started/installation.mdx +++ b/docs/content/docs/getting-started/installation.mdx @@ -92,4 +92,4 @@ npm cache clean --force ## Next Steps -Ready to create your first flow? Continue to [Quick Start](/docs/getting-started/quick-start). \ No newline at end of file +Ready to create your first flow? Continue to [Quick Start](/docs/getting-started/quick-start). diff --git a/docs/content/docs/getting-started/quick-start.mdx b/docs/content/docs/getting-started/quick-start.mdx index 1b4b394..af63dd9 100644 --- a/docs/content/docs/getting-started/quick-start.mdx +++ b/docs/content/docs/getting-started/quick-start.mdx @@ -32,7 +32,7 @@ You should see output like: ✓ Test User API ✓ GET /users/1 (200ms) ✓ status == 200 - ✓ body.id == 1 + ✓ body.id == 1 ✓ body.name != null Tests: 1 passed, 0 failed @@ -65,7 +65,7 @@ GET https://jsonplaceholder.typicode.com/users/{{userId}} Create a `.env` file for environment-specific settings: -```env +```dotenv # .env BASE_URL=https://jsonplaceholder.typicode.com API_KEY=your-api-key @@ -103,4 +103,4 @@ restflow run api-test.flow --format summary - [Set up a complete project](/docs/getting-started/project-setup) - [Learn the DSL syntax](/docs/dsl-reference/syntax-overview) -- [Explore variables and environments](/docs/variables/variable-types) \ No newline at end of file +- [Explore variables and environments](/docs/variables/variable-types) diff --git a/docs/content/docs/index.mdx b/docs/content/docs/index.mdx index c76264f..001cc75 100644 --- a/docs/content/docs/index.mdx +++ b/docs/content/docs/index.mdx @@ -1,5 +1,5 @@ --- -title: Documentation +title: Welcome description: Complete guide to using Restflow for API testing --- diff --git a/docs/content/docs/meta.json b/docs/content/docs/meta.json index e2615cc..1b313c1 100644 --- a/docs/content/docs/meta.json +++ b/docs/content/docs/meta.json @@ -1,10 +1,23 @@ { - "title": "Documentation", - "pages": [ - "getting-started", - "core-concepts", - "dsl-reference", - "variables", - "cli" - ] -} \ No newline at end of file + "pages": [ + "getting-started/introduction", + "getting-started/installation", + "getting-started/quick-start", + "getting-started/project-setup", + "---Core Concepts---", + "core-concepts/flows-and-steps", + "core-concepts/dsl-basics", + "core-concepts/variables-overview", + "core-concepts/assertions-basics", + "core-concepts/environment-management", + "---DSL Reference---", + "dsl-reference", + "---Variables & Environment---", + "variables/variable-types", + "variables/built-in-variables", + "variables/environment-files", + "---CLI---", + "cli" + ], + "defaultOpen": true +} diff --git a/docs/content/docs/variables/environment-files.mdx b/docs/content/docs/variables/environment-files.mdx index 31cebb8..1b09887 100644 --- a/docs/content/docs/variables/environment-files.mdx +++ b/docs/content/docs/variables/environment-files.mdx @@ -9,7 +9,7 @@ Environment files (or `.env` files) are the standard way to manage environment-s An `.env` file is a simple text file with `KEY=VALUE` pairs. -```env +```dotenv # This is a comment BASE_URL=https://api.example.com API_KEY=your-secret-api-key diff --git a/docs/content/docs/variables/variable-types.mdx b/docs/content/docs/variables/variable-types.mdx index 662b9ee..ac135fc 100644 --- a/docs/content/docs/variables/variable-types.mdx +++ b/docs/content/docs/variables/variable-types.mdx @@ -41,7 +41,7 @@ Authorization: Bearer {{auth_token}} Environment variables are loaded from `.env` files and are typically used for environment-specific configuration like API keys, base URLs, or test user credentials. -```env +```dotenv # .env.staging BASE_URL=https://staging.api.example.com API_KEY=my-secret-key diff --git a/docs/source.config.ts b/docs/source.config.ts index 6c88a47..1f179fb 100644 --- a/docs/source.config.ts +++ b/docs/source.config.ts @@ -16,6 +16,7 @@ export default defineConfig({ "javascript", "typescript", "json", + "dotenv", { name: "flow", scopeName: "source.flow", diff --git a/docs/src/routeTree.gen.ts b/docs/src/routeTree.gen.ts index 4597ec3..c657276 100644 --- a/docs/src/routeTree.gen.ts +++ b/docs/src/routeTree.gen.ts @@ -11,15 +11,15 @@ import { createServerRootRoute } from '@tanstack/react-start/server' import { Route as rootRouteImport } from './routes/__root' -import { Route as IndexRouteImport } from './routes/index' +import { Route as SplatRouteImport } from './routes/$' import { Route as DocsSplatRouteImport } from './routes/docs/$' import { ServerRoute as ApiSearchServerRouteImport } from './routes/api/search' const rootServerRouteImport = createServerRootRoute() -const IndexRoute = IndexRouteImport.update({ - id: '/', - path: '/', +const SplatRoute = SplatRouteImport.update({ + id: '/$', + path: '/$', getParentRoute: () => rootRouteImport, } as any) const DocsSplatRoute = DocsSplatRouteImport.update({ @@ -34,28 +34,28 @@ const ApiSearchServerRoute = ApiSearchServerRouteImport.update({ } as any) export interface FileRoutesByFullPath { - '/': typeof IndexRoute + '/$': typeof SplatRoute '/docs/$': typeof DocsSplatRoute } export interface FileRoutesByTo { - '/': typeof IndexRoute + '/$': typeof SplatRoute '/docs/$': typeof DocsSplatRoute } export interface FileRoutesById { __root__: typeof rootRouteImport - '/': typeof IndexRoute + '/$': typeof SplatRoute '/docs/$': typeof DocsSplatRoute } export interface FileRouteTypes { fileRoutesByFullPath: FileRoutesByFullPath - fullPaths: '/' | '/docs/$' + fullPaths: '/$' | '/docs/$' fileRoutesByTo: FileRoutesByTo - to: '/' | '/docs/$' - id: '__root__' | '/' | '/docs/$' + to: '/$' | '/docs/$' + id: '__root__' | '/$' | '/docs/$' fileRoutesById: FileRoutesById } export interface RootRouteChildren { - IndexRoute: typeof IndexRoute + SplatRoute: typeof SplatRoute DocsSplatRoute: typeof DocsSplatRoute } export interface FileServerRoutesByFullPath { @@ -82,11 +82,11 @@ export interface RootServerRouteChildren { declare module '@tanstack/react-router' { interface FileRoutesByPath { - '/': { - id: '/' - path: '/' - fullPath: '/' - preLoaderRoute: typeof IndexRouteImport + '/$': { + id: '/$' + path: '/$' + fullPath: '/$' + preLoaderRoute: typeof SplatRouteImport parentRoute: typeof rootRouteImport } '/docs/$': { @@ -111,7 +111,7 @@ declare module '@tanstack/react-start/server' { } const rootRouteChildren: RootRouteChildren = { - IndexRoute: IndexRoute, + SplatRoute: SplatRoute, DocsSplatRoute: DocsSplatRoute, } export const routeTree = rootRouteImport diff --git a/docs/src/routes/$.tsx b/docs/src/routes/$.tsx new file mode 100644 index 0000000..8c2f245 --- /dev/null +++ b/docs/src/routes/$.tsx @@ -0,0 +1,100 @@ +import { createFileRoute, notFound } from "@tanstack/react-router"; +import { createServerFn } from "@tanstack/react-start"; +import type { PageTree } from "fumadocs-core/server"; +import { createClientLoader } from "fumadocs-mdx/runtime/vite"; +import { DocsLayout } from "fumadocs-ui/layouts/docs"; +import defaultMdxComponents from "fumadocs-ui/mdx"; +import { + DocsBody, + DocsDescription, + DocsPage, + DocsTitle, +} from "fumadocs-ui/page"; +import { useMemo } from "react"; +import { baseOptions } from "@/lib/layout.shared"; +import { source } from "@/lib/source"; +import { docs } from "../../source.generated"; + +export const Route = createFileRoute("/$")({ + component: Page, + loader: async ({ params }) => { + const data = await loader({ data: params._splat?.split("/") ?? [] }); + await clientLoader.preload(data.path); + return data; + }, +}); + +const loader = createServerFn({ + method: "GET", +}) + .validator((slugs: string[]) => slugs) + .handler(async ({ data: slugs }) => { + const page = source.getPage(slugs); + if (!page) throw notFound(); + + return { + tree: source.pageTree as object, + path: page.path, + }; + }); + +const clientLoader = createClientLoader(docs.doc, { + id: "docs", + component({ toc, frontmatter, default: MDX }) { + return ( + + {frontmatter.title} + {frontmatter.description} + + + + + ); + }, +}); + +function Page() { + const data = Route.useLoaderData(); + const Content = clientLoader.getComponent(data.path); + const tree = useMemo( + () => transformPageTree(data.tree as PageTree.Folder), + [data.tree], + ); + + return ( + + + + ); +} + +function transformPageTree(tree: PageTree.Folder): PageTree.Folder { + function transform(item: T) { + if (typeof item.icon !== "string") return item; + + return { + ...item, + icon: ( + + ), + }; + } + + return { + ...tree, + index: tree.index ? transform(tree.index) : undefined, + children: tree.children.map((item) => { + if (item.type === "folder") return transformPageTree(item); + return transform(item); + }), + }; +} diff --git a/docs/src/routes/index.tsx b/docs/src/routes/index.tsx deleted file mode 100644 index c1c7ce2..0000000 --- a/docs/src/routes/index.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import { createFileRoute, Link } from "@tanstack/react-router"; -import { HomeLayout } from "fumadocs-ui/layouts/home"; -import { baseOptions } from "@/lib/layout.shared"; - -export const Route = createFileRoute("/")({ - component: Home, -}); - -function Home() { - return ( - -

Fumadocs on Tanstack Start.

- - Open Docs - -
- ); -}