Boosting API Reliability: TDD and Playwright for TypeScript Projects

Test-Driven Development (TDD)

What is TDD?

Test-Driven Development (TDD) is a software development practice where tests are written before the actual implementation. The process follows a cycle:

  1. Write a test – Define what the function or feature should do.
  2. Run the test – Ensure it fails since the functionality is not implemented yet.
  3. Write the code – Implement the minimum code required to pass the test.
  4. Refactor – Improve the code while ensuring the test still passes.
  5. Repeat – Continue adding more tests and refining the code.

Why Use TDD?

  • Reliability: Ensures your code meets the intended requirements.
  • Maintainability: Encourages better design and cleaner code.
  • Bug Prevention: Catches issues early, reducing debugging time later.
  • Confidence in Refactoring: Allows developers to modify code without fear of breaking existing functionality.
  • Improved Collaboration: Provides clear specifications for team members.

How to Use TDD in TypeScript with Playwright

Part 1: Setting Up Playwright

Steps to Follow:

  1. Install Playwright and NYC for test coverage:
npm install -D @playwright/test nyc
  1. Create a playwright.config.ts file with the following configuration:
import { defineConfig } from '@playwright/test';
import fs from 'fs';
import path from 'path';

// Function to dynamically scan test directories
const testRootDir = 'tests/'; // Adjust if needed
const testDirs = fs
  .readdirSync(testRootDir, { withFileTypes: true })
  .filter(dir => dir.isDirectory() && dir.name.startsWith('test-')) // Include only test folders
  .map(dir => ({
    name: dir.name,
    testDir: path.join(testRootDir, dir.name),
  }));

export default defineConfig({
  testDir: '.', // Root directory
  timeout: 30000, // 30s timeout
  expect: { timeout: 5000 }, // Assertion timeout
  fullyParallel: false,
  workers: 2, // Adjust based on system resources
  reporter: [['list'], ['html', { outputFile: 'test-results.html' }]], // Reporters
  globalSetup: require.resolve('./tests/global-setup'),  // ✅ Adjusted path
  globalTeardown: require.resolve('./tests/global-teardown'),  // ✅ Adjusted path
  use: {
    baseURL: 'https://your-api-url.com', // Set your API base URL
    extraHTTPHeaders: {
      'Content-Type': 'application/json',
      'Authorization': process.env.SDST_TOKEN || 'invalid', // Use env variables instead of hardcoding
    },
    ignoreHTTPSErrors: true,
  },
  projects: testDirs, // Dynamically generated projects
});
  1. Update package.json to include the test script:
"scripts": {
  "test": "nyc --reporter=html --reporter=text playwright test"
}

Part 2: Configuring Pre-requisites

*Create a tests directory

Setting Up the Database

Since our backend uses AWS RDS/MongoDB inside a VPC, we cannot directly call the handlers as the connection would fail. To resolve this, we create mock databases inside a Docker container for testing purposes.

docker-compose.yaml

Create a docker-compose.yaml file to set up PostgreSQL and MongoDB containers:

version: '3.1'

services:
  db:
    image: postgres:latest
    restart: always
    environment:
      POSTGRES_USER: ABC233
      POSTGRES_PASSWORD: ABC0012
      POSTGRES_DB: test
    ports:
      - "5433:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

  mongodb:
    image: mongo
    container_name: mongodb
    restart: unless-stopped
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db
    environment:
      MONGO_INITDB_ROOT_USERNAME: admin
      MONGO_INITDB_ROOT_PASSWORD: password

volumes:
  mongo-data:
    driver: local
  postgres_data:

Create the containers by running:

docker-compose up -d

Make sure you keep your docker desktop running.

After setting up docker if you are using rds you can run alembic to create all the tables required for your project.

Global Setup and Teardown

global-setup.ts

This file is responsible for creating a test user at the beginning of the test execution so that it can be used dynamically.

import { request } from '@playwright/test';
import fs from 'fs';
import path from 'path';
import { v4 as uuidv4 } from 'uuid'
import { z } from 'zod';

const userFilePath = path.join(__dirname, 'user-data.json');

const generateValidData = () => {
  return {
    first_name: 'Test',
    last_name: 'User',
    country_code: '+91',
    phone_number: `9${Math.floor(Math.random() * 1000000000).toString().padStart(9, '0')}`,
    email_address: `shrinit.poojary+${uuidv4().substring(0, 8)}@7edge.com`,
    signature_photo: 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP8z8BQDwAEhQGAhKmMIQAAAABJRU5ErkJggg==',
    extras: { deactivate_reason: '' }
  };
};

async function globalSetup() {
  const apiRequest = await request.newContext();
  const validData = generateValidData();

  const response = await apiRequest.post(`${process.env.BASE_API_URL}/sdst/create`, {
    data: validData,
    headers: { 'Content-Type': 'application/json' }
  });

  if (response.status() !== 201) {
    throw new Error('Failed to create user');
  }

  const userData = await response.json();
  fs.writeFileSync(userFilePath, JSON.stringify(userData));
}

export default globalSetup;

global-teardown.ts

This file is responsible for cleaning up test data after execution. It deletes any records created by global-setup.ts .

import { request } from '@playwright/test';
import fs from 'fs';
import path from 'path';

const userFilePath = path.join(__dirname, 'user-data.json');

async function globalTeardown() {
  if (!fs.existsSync(userFilePath)) {
    console.log('No user data found for deletion.');
    return;
  }

  const userData = JSON.parse(fs.readFileSync(userFilePath, 'utf8'));
  const apiRequest = await request.newContext();

  const response = await apiRequest.delete(`${process.env.BASE_API_URL}/sdst-bdd`, {
    data: { 'username': userData.data.phone_number },
    headers: { 'Content-Type': 'application/json' }
  });

  if (response.status() === 200) {
    console.log(`User ${userData.id} deleted successfully.`);
  }

  fs.unlinkSync(userFilePath);
}

export default globalTeardown;

Exporting Environment Variables

Ensure all required environment variables are exported, including AWS credentials for authentication.

Step 3: Folder Structure and Test Cases

3.1 Folder Structure Overview

.
├── docker-compose.yaml
├── global-setup.ts
├── global-teardown.ts
├── mongo-test.ts
├── test-sdst
│      ├── mongo-test.spec.ts
│      └── subdistributer-create.spec.ts
└── test-sdst-registration
    ├── basic-details.spec.ts
    ├── business-details.spec.ts
    └── send-otp.spec.ts

Explanation

This folder structure is designed to maintain a structured and scalable testing framework. Each folder represents a specific service, and within each service folder, test files correspond to the different APIs being tested.

  • docker-compose.yaml - Defines the database services (PostgreSQL and MongoDB) that run inside Docker containers for isolated testing.
  • global-setup.ts - Creates a test user dynamically before test execution.
  • global-teardown.ts - Cleans up the test user data after test execution.
  • mongo-test.ts - Contains MongoDB-specific handlers for testing.
  • test-sdst/ - Contains test cases related to sub-distributor APIs.
    • mongo-test.spec.ts - Tests MongoDB insert operations.
    • subdistributer-create.spec.ts - Tests sub-distributor creation.
  • test-sdst-registration/ - Contains test cases for sub-distributor registration processes.
    • basic-details.spec.ts - Tests the basic details submission.
    • business-details.spec.ts - Tests business details submission.
    • send-otp.spec.ts - Tests the OTP sending functionality.

3.2 Example Test Case: send-otp.spec.ts

This test verifies the OTP sending functionality by making API calls to the otp_send handler.

File: send-otp.spec.ts

import { test, expect } from '@playwright/test';
import fs from 'fs';
import path from 'path';
// @ts-ignore
const { handler } = require('../../services/Sub_Distributor_Mobile/sdst/dist/handlers/otp_send');

const userFilePath = '../user-data.json';
const userData = JSON.parse(fs.readFileSync(userFilePath, 'utf8')).data;

test.describe('User Verification Handler Tests', () => {

  test('should successfully send OTP when valid email is provided @email-otp', async () => {
    const validData = {
      email_address: "shrinit.poojary12+6aa28308@gmail.com",
      name: 'Shrinit Poojary',
      user_type: 'sdst'
    };
    const event = { body: JSON.stringify(validData) };
    const response = await handler(event);
    
    expect(response.statusCode).toBe(200);
    const responseBody = JSON.parse(response.body);
    expect(responseBody.message).toBe('OTP sent successfully');
  });

  test('should fail with invalid email format', async () => {
    const invalidData = { email_address: 'invalid-email' };
    const event = { body: JSON.stringify(invalidData) };
    const response = await handler(event);
    
    expect(response.statusCode).toBe(400);
    const responseBody = JSON.parse(response.body);
    expect(responseBody.message).toBe('Invalid email address format');
  });

  test('should fail when neither email nor phone number is provided', async () => {
    const event = { body: JSON.stringify({}) };
    const response = await handler(event);
    
    expect(response.statusCode).toBe(400);
    const responseBody = JSON.parse(response.body);
    expect(responseBody.message).toBe('Email or Phone Number is required');
  });
});

Explanation of Imports

  • import { test, expect } from '@playwright/test'; - Imports Playwright’s testing framework.
  • import fs from 'fs'; import path from 'path'; - Imports Node.js modules for file handling.
  • const { handler } = require('../../services/Sub_Distributor_Mobile/sdst/dist/handlers/otp_send'); - Imports the otp_send handler that processes OTP requests.

Test Breakdown

  1. Valid Email OTP Test
  • Sends an OTP using a valid email.
  • Expects a 200 response and a success message.
  1. Invalid Email Format Test
  • Sends a malformed email address.
  • Expects a 400 response with an error message.
  1. Missing Email and Phone Number Test
  • Sends an empty request.
  • Expects a 400 response indicating missing fields.

3.3 Example Test Case: mongo-test.spec.ts

This test validates MongoDB insertion operations.

File: mongo-test.spec.ts

import { test, expect } from '@playwright/test';
// @ts-ignore
const { handler } = require('../mongo-test.ts');

test.describe('MongoDB Insert Handler Tests', () => {
  
  test('should successfully insert item into MongoDB @insert-mongo', async () => {
    const validData = { name: 'Test Item', value: 100 };
    const event = { body: JSON.stringify(validData) };

    const response = await handler(event);

    expect(response.statusCode).toBe(201);
    const responseBody = JSON.parse(response.body);
    expect(responseBody.message).toBe('Item inserted');
    expect(responseBody.data.name).toBe(validData.name);
    expect(responseBody.data.value).toBe(validData.value);
  });

  test('should fail when name is missing', async () => {
    const invalidData = { value: 100 };
    const event = { body: JSON.stringify(invalidData) };

    const response = await handler(event);

    expect(response.statusCode).toBe(400);
    const responseBody = JSON.parse(response.body);
    expect(responseBody.message).toBe('Missing required fields: name, value');
  });
});

Explanation of Imports

  • import { test, expect } from '@playwright/test'; - Imports Playwright’s testing framework.
  • const { handler } = require('../mongo-test.ts'); - Imports the MongoDB handler for database operations.

Test Breakdown

  1. Successful Insert Test
  • Sends valid data to the MongoDB insert function.
  • Expects a 201 response and confirms data insertion.
  1. Missing Name Test
  • Sends a request missing the name field.
  • Expects a 400 response with an error message.

Running the Tests

Run the following command in the root directory:

npm test

This will execute all test cases inside the test folder.
Here’s your cleaned test output with unnecessary debug statements removed:

> Product-backend-apis@1.0.0 test
> nyc --reporter=html --reporter=text playwright test

Running 10 tests using 2 workers

  ✓  1 …n] › tests/test-sdst-registration/mongo-test.spec.ts:7:7 › MongoDB Insert Handler Tests › should successfully insert item into MongoDB @insert-mongo (115ms)
  ✓  2 [test-sdst-registration] › tests/test-sdst-registration/mongo-test.spec.ts:20:7 › MongoDB Insert Handler Tests › should fail when name is missing (6ms)
  ✓  3 [test-sdst-registration] › tests/test-sdst-registration/mongo-test.spec.ts:31:7 › MongoDB Insert Handler Tests › should fail when value is missing (4ms)
  ✓  4 [test-sdst-registration] › tests/test-sdst-registration/mongo-test.spec.ts:42:7 › MongoDB Insert Handler Tests › should fail with invalid JSON payload (9ms)
  ✓  5 …test-sdst-registration/send-otp.spec.ts:12:7 › User Verification Handler Tests › should successfully send OTP when valid email is provided @email-otp (1.4s)
  ✓  6 [test-sdst-registration] › tests/test-sdst-registration/send-otp.spec.ts:26:7 › User Verification Handler Tests › should fail with invalid email format (9ms)
  ✓  7 …] › tests/test-sdst-registration/send-otp.spec.ts:36:7 › User Verification Handler Tests › should fail when neither email nor phone number is provided (7ms)
  ✓  8 …on] › tests/test-sdst-registration/send-otp.spec.ts:45:7 › User Verification Handler Tests › should fail when both email and phone number are provided (4ms)
  ✓  9 … › tests/test-sdst-registration/send-otp.spec.ts:59:7 › User Verification Handler Tests › should fail when user does not exist in forgot password flow (7ms)
  ✓  10 …ion] › tests/test-sdst-registration/send-otp.spec.ts:74:7 › User Verification Handler Tests › should successfully send OTP for a valid phone number (893ms)

  10 passed (12.0s)

To open last HTML report run:

  npx playwright show-report

------------------------------------------------------------------------------------|---------|----------|---------|---------|--------------------------------------
File                                                                                | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s                    
------------------------------------------------------------------------------------|---------|----------|---------|---------|--------------------------------------
All files                                                                           |    40.7 |     41.3 |   23.07 |   41.89 |                                      
 Product-Backend-APIs                                                               |     100 |      100 |     100 |     100 |                                      
  playwright.config.ts                                                              |     100 |      100 |     100 |     100 |                                      
 Product-Backend-APIs/services/Sub_Distributor_Mobile/sdst/dist/handlers            |   91.37 |    77.14 |     100 |   91.37 |                                      
  otp_send.js                                                                       |   91.37 |    77.14 |     100 |   91.37 | 60,99,112,159-160                    
 Product-Backend-APIs/services/Sub_Distributor_Mobile/sdst/dist/lib                 |   15.97 |        0 |       0 |   16.77 |                                      
  helper.js                                                                         |   15.97 |        0 |       0 |   16.77 | ...6-507,519-537,542,545-559,564-581 
 Product-Backend-APIs/services/Sub_Distributor_Mobile/sdst/dist/lib/aws             |      46 |       60 |   44.44 |   47.42 |                                      
  rds_knex.js                                                                       |   35.13 |    74.07 |      30 |   37.14 | 42-43,58-107                         
  ses.js                                                                            |   39.02 |    33.33 |      25 |      40 | 44-45,50,55-82                       
  sns.js                                                                            |   77.27 |       25 |     100 |   77.27 | 22,28,48-50                          
 Product-Backend-APIs/services/Sub_Distributor_Mobile/sdst/dist/utils/sms-templates |     100 |      100 |     100 |     100 |                                      
  sdst_verify_otp.js                                                                |     100 |      100 |     100 |     100 |                                      
------------------------------------------------------------------------------------|---------|----------|---------|---------|--------------------------------------

Step 4: Open the Coverage Report

  • Right-click on index.html in the coverage folder.
  • Select “Open with Live Server” (if using VS Code with the Live Server extension) or open it in a browser manually.
  • The coverage report will display overall test coverage percentages for statements, branches, functions, and lines.

Step 5: Analyze the Code Coverage Report

The report shows:

  • Fully tested files (highlighted in green)
  • Partially tested files (highlighted in yellow)
  • Files with poor test coverage (highlighted in red)

Click on any file to explore line-by-line test coverage.

Step 6: Improve Test Coverage

If certain files have low test coverage:

  • Identify untested code blocks.
  • Write additional test cases to cover them.
  • Re-run npm test and verify the updated coverage.

Open the Playwright Report

Navigate to the playwright-report directory and open index.html in a browser:
playwright-report folder

npx playwright show-report

This command launches a browser displaying the Playwright test results.

Conclusion

By following this structured approach to Test-Driven Development (TDD) with TypeScript, Playwright, and API testing, we have established a robust and scalable testing framework for our backend services.

We began by setting up mock databases using Docker to simulate real-world environments and ensure our handlers work as expected. Then, we implemented global setup and teardown scripts to create and clean up test data dynamically, ensuring isolated and repeatable tests. Finally, we structured our test suite to mirror our service architecture, allowing seamless organization and efficient test execution.

With Playwright, we not only tested APIs for correctness but also enforced strict validation through schema validation (Zod) and real-time API assertions. This ensures that every request and response meets the required standards before being deployed.

Adopting TDD brings multiple benefits:

  • Faster debugging with early issue detection
  • Consistent API behavior across services
  • Scalability and maintainability as the application grows
  • Confidence in deployments with automated test execution

By incorporating these practices into your development workflow, you can significantly improve the reliability, security, and efficiency of your backend APIs. Whether you’re working on a small service or a large-scale distributed system, this approach will help ensure seamless integration and a smooth user experience.

Now, with a well-structured and automated testing pipeline, you can ship features faster without compromising quality.

7 Likes

Hey @Shrinit great blog :raised_hands: could please add the dynamodb configuration for the docker-compose.yaml for easier local dynamodb access.

2 Likes

Hey @Sonal, thanks for the appreciation! :raised_hands: Since we are using DynamoDB for session and OTP storage, which have TTL enabled, I didn’t include it in the docker-compose.yaml. The stored data gets automatically removed after a certain period to maintain data hygiene. However, if you need local access for specific use cases, I can help with a workaround. Let me know!

Very informative post on TDD, @Shrinit ! Thanks for sharing! :raised_hands:

@Shrinit Good information around TDD and its integration with Playwright. :clap:

1 Like

Thank you @swasthik :raised_hands:

Thank you @ashu-kajekar !!

1 Like

In Test-Driven Development (TDD), several manual steps can be automated to streamline the workflow and improve efficiency:

  1. Token Generation: Automating token generation ensures that developers don’t have to manually fetch access tokens for each test run, saving time and reducing the risk of errors in token management.
  2. Environment Variable Setup: By automating the export of environment variables for databases and Docker containers, we ensure a consistent and error-free setup for the test environment.
  3. TypeScript Building: Automating the TypeScript build process ensures that the latest code is compiled correctly before running tests. It also eliminates the need to manually build each service or specify a service name, as all services are built automatically.
  4. Playwright Test Execution: Automating the execution of Playwright tests ensures that the tests are consistently run for each service. With the proper environment variables and compiled code in place, the automated test execution ensures reliable and repeatable results.

By automating these steps, we eliminate the risks associated with manual processes and make the TDD workflow faster, more reliable, and easier to maintain.

Automation Script

Here’s the corresponding .sh file to automate the process:

#!/bin/bash
export NODE_TLS_REJECT_UNAUTHORIZED=0

# === Parse all args manually ===
while [[ $# -gt 0 ]]; do
  case "$1" in
    -s|--service)
      service="$2"
      shift 2
      ;;
    -*)
      echo "Unknown option: $1"
      exit 1
      ;;
    *)
      if [ -z "$interface" ]; then
        interface="$1"
        shift
      else
        echo "Unexpected argument: $1"
        exit 1
      fi
      ;;
  esac
done

# === Validation ===
if [ -z "$interface" ]; then
  echo "Please specify an interface name (e.g., Admin_Web / Sub_Distributor_Mobile)."
  exit 1
fi

echo "Generating Access Token for Interface: $interface"
[ -n "$service" ] && echo "Service: $service"

# === Token generation ===
result=$(python3 access_token_generation.py $interface > logins.sh)
logins_file="logins.sh"

# Check if the file exists and is readable
if [ -r "$logins_file" ]; then
  # Read and export all environment variables
  while IFS= read -r line; do
    case "$line" in export*) 
        eval "$line"
        ;;
    esac
  done < "$logins_file"

  echo "All tokens have been exported successfully!"
else
  echo "Error: $logins_file does not exist or is not readable."
fi

# === Build TypeScript for the interface ===
if [ -n "$service" ]; then
  if [[ "$service" == *.ts ]]; then
    # Extract top-level folder (e.g., "agents" from "agents/view.ts")
    service=$(echo "$service" | cut -d'/' -f1)
  fi
  ./ts-build.sh "$interface" "$service"
else
  ./ts-build.sh "$interface"
fi

# === Load .env variables ===
export_env_file() {
  echo "Exporting environment variables from $1"
  set -a
  [ -f "$1" ] && . "$1"
  set +a
}

# === Run tests ===
test_function() {
    echo "Running Playwright tests for $interface"
    echo "Exporting the ENVs from .env file"
    export_env_file "./tests/.env"

    echo "Exporting TEST_DIR and SERVICE variables"
    export TEST_DIR="$interface"
    export SERVICE="$service"

    echo "Running tests only for service: $service"
    if ! npm test; then
        echo "Tests failed for $interface (service: $service)"
        exit 1
    fi
    echo "Tests passed for $interface"
}

# === Execute the test function ===
test_function

Best Practices for Test Structure

Additionally, several best practices can be implemented to structure the tests for maximum efficiency and maintainability:

Static Data with Fixtures

The fixtures directory contains static test data files like admins.json, agents.json, etc. These files store predefined test data that can be reused across multiple test cases.

{
  "minimalAgent": {
    "basic_details": {
      "first_name": "BDD",
      "last_name": "TEST",
      "country_code": "+91",
      "phone_number": "DYNAMIC_PHONE",
      "email_address": "DYNAMIC_EMAIL"
    }
  }
}

Dynamic Data Generation

The dynamic_data.ts file replaces placeholders (like DYNAMIC_PHONE, DYNAMIC_EMAIL) with actual dynamic values, ensuring that each test runs with unique data every time.

private replacePlaceholder(value: string): string {
    return value
        .replace(/DYNAMIC_PHONE/g, faker.string.numeric({ length: 10 }))
        .replace(/DYNAMIC_EMAIL/g, faker.internet.email({ firstName: "apitest" }))
        .replace(/DYNAMIC_NAME/g, faker.person.firstName());
}

Lambda Event Factory

The lambda_event_factory.ts module generates the structure of the Lambda event, allowing us to easily create events with different parameters (body, path parameters, query parameters) for testing Lambda handlers.

static createEvent(body: RequestBody = null, decodedClaims: DecodedClaims | null = null): LambdaEvent {
    const event: LambdaEvent = { requestContext: { authorizer: decodedClaims ? { claims: decodedClaims } : undefined } };
    if (body) event.body = typeof body === 'string' ? body : JSON.stringify(body);
    return event;
}

Environment Variable Loader

The env_loader.ts module loads environment variables specific to each service from .env files, ensuring that the correct configuration is used for each service during testing. Sensitive keys are excluded from the process to prevent accidental exposure.

export function loadEnvironmentVariables(serviceBasePath: string) {
    const envFilePath = path.resolve(process.cwd(), `${serviceBasePath}/.env`);
    if (fs.existsSync(envFilePath)) {
        const envContent = fs.readFileSync(envFilePath, 'utf-8');
        const envFromFile = dotenv.parse(envContent);
        for (const [key, value] of Object.entries(envFromFile)) {
            if (!protectedKeys.has(key)) {
                process.env[key] = value;
            }
        }
    }
}

Sample Test Implementation

Below is a sample test file demonstrating how the helpers are utilized for a test scenario:

import { loadEnvironmentVariables } from '../lib/env_loader'
import { LambdaEventFactory } from '../lib/lamda_event_factory'
import { agentTestData } from '../lib/dynamic_data'


// Before all tests, create an agent to be used for view scenarios
test.beforeAll(async () => {
    loadEnvironmentVariables('services/Admin_Web/agents')

    const { handler: createHandler } = require('../../../services/Admin_Web/agents/dist/handlers/create')
    
    const agentData = agentTestData.getData('validAgent')
    const event = LambdaEventFactory.createPostEvent(agentData, claims)

    const response = await createHandler(event)
    const body = JSON.parse(response.body)
    createdAgentId = body.data.id
})

test.describe('Agent View Handler Tests', () => {

    test('should return 403 if user has no access', async () => {
        // Create GET event without claims
        const event = LambdaEventFactory.createGetEvent(null, { id: createdAgentId })

        const response = await viewHandler(event)

        expect(response.statusCode).toBe(403)

        const body = JSON.parse(response.body)
        expect(body.message).toBe('Access Denied')
    })
})

In this example, the following helpers are used:

  • LambdaEventFactory.createPostEvent: Generates a Lambda event for the POST request to create an agent.
  • LambdaEventFactory.createGetEvent: Generates a Lambda event for the GET request, used for testing the agent view handler.
  • agentTestData.getData: Retrieves static test data (like validAgent) for creating the agent.
  • loadEnvironmentVariables: Loads the environment variables for the specific service (in this case, the Admin_Web/agents service).
6 Likes