A scalable API testing framework for Bahmni built with Mocha, Chai, and Supertest. Features automated reporting, dynamic authentication, and practical guides for rapid test development.
- Quick Setup
- Project Structure
- Quick Start
- Reports
- Framework Architecture
- Running Tests
- Configuration
- Additional Guides
- Node.js 18.x+
- Yarn 1.x+
git clone https://github.com/Bahmni/bahmni-api-test-automation.git
cd bahmni-api-test-automation
yarn installCreate .env file:
# Required
TEST_ENV=dev
SUPERADMIN_USERNAME=admin
SUPERADMIN_PASSWORD=Admin123yarn testView report: mochawesome-report/mochawesome.html
bahmni-api-test-automation/
βββ src/
β βββ config/ # Environment configs, auth, API clients
β βββ services/ # API endpoint methods (service layer)
β βββ helpers/ # Utilities (API tracker, email OTP, etc.)
βββ tests/
β βββ specs/ # Test files (organized by feature)
β βββ fixtures/ # Test helpers, hooks, utilities
β βββ testdata/ # Credentials & request payloads
βββ mochawesome-report/ # Generated HTML reports
Key Concepts:
src/services/- All API calls go here. One service file per domain/moduletests/specs/- Test files organized by featuretests/fixtures/- Reusable helpers and utilitiestests/testdata/- Test data (credentials, payloads) separated for reusability
Create tests/specs/bahmni/myTest.spec.js:
import { getAllServiceDetails } from "../../../src/services/openmrs/appointmentService.js";
import { addTestLog, addApiDetailsToReport } from "../../fixtures/rootHooks.js";
describe("My First Test", function () {
it("should fetch appointment services", async function () {
addTestLog(this, "Fetching appointment services");
const response = await getAllServiceDetails();
addApiDetailsToReport(this);
expect(response.status).to.equal(200);
expect(response.body).to.be.an("array");
});
});Run: yarn test
Add to src/services/openmrs/appointmentService.js:
import { authenticatedRequest } from "../../config/apiClient.js";
import { handleApiResponse } from "../../helpers/apiResponseHandler.js";
import { lastApiCall } from "../../helpers/apiTracker.js";
import { config } from "../../config/index.js";
export async function getServiceByName(serviceName) {
const endpoint = "openmrs/ws/rest/v1/appointmentService";
const fullEndpoint = `${config.baseURI}${endpoint}`;
const queryParams = { name: serviceName };
lastApiCall.method = "GET";
lastApiCall.endpoint = fullEndpoint;
lastApiCall.payload = null;
lastApiCall.queryParams = queryParams;
return handleApiResponse(
authenticatedRequest().get(endpoint).query(queryParams),
200,
"GET",
fullEndpoint,
null,
queryParams,
);
}Key Points:
- Use
handleApiResponse()for automatic API tracking & error handling - Use
authenticatedRequest()for basic auth - Use
lastApiCallto track request details for reports - Set method, endpoint, payload, and queryParams before making the call
π Details: API Tracker Guide
General helpers: tests/fixtures/testHelpers.js
export function myGeneralHelper() {
// Logic used across all tests
}Domain-specific helpers: tests/fixtures/testHelpers.js
export function generateServiceName(prefix = "Test-Service") {
const timestamp = Date.now();
return `${prefix}-${timestamp}`;
}Usage:
import { generateServiceName } from "../../fixtures/testHelpers.js";
it("test with unique service name", async function () {
const serviceName = generateServiceName();
// Use in test
});Payloads: tests/testdata/payloads/bahmni/createServicePayload.js
export const appointmentServicePayload = {
name: "Test-Service",
description: "Test service description",
startTime: "09:00:00",
endTime: "17:00:00",
maxAppointmentsLimit: 10,
};Environment-specific data:
import { config } from "../../../src/config/index.js";
export const testData = {
dev: { locationId: "dev-123" },
qa: { locationId: "qa-456" },
uat: { locationId: "uat-789" },
};
// Usage: testData[config.env].locationIdCredentials: tests/testdata/credentials/myCredentials.js
export const myCredentials = {
user1: {
username: process.env.YOUR_USERNAME_VAR || "defaultUsername",
password: process.env.YOUR_PASSWORD_VAR || "",
},
};Framework uses Mochawesome for HTML reports with:
- Test summary (pass/fail/duration)
- Custom logs via
addTestLog(this, "message") - API details via
addApiDetailsToReport(this) - Error stack traces (automatic)
it("my test", async function () {
addTestLog(this, "Step 1: Starting");
const response = await apiCall();
addApiDetailsToReport(this); // Adds API request/response
addTestLog(this, `Received ${response.body.length} items`);
});Note: Failed tests automatically include API details.
After tests run: Open mochawesome-report/mochawesome.html
3-Layer Pattern:
Tests (specs/) β Services (src/services/) β Config/Helpers (src/config/, src/helpers/)
1. API Tracker - Auto-captures API details for reports (reduces code by 70%)
2. Auth Manager - Dynamic credential switching during tests
3. Response Handler - Centralized error handling with detailed logging
π Details: API Tracker Guide
# All tests
yarn test
# Specific suite
yarn test:bahmni
# With environment
TEST_ENV=qa yarn test
# Specific file
npx mocha tests/specs/bahmni/appointmentService.spec.js
# Generate report only
yarn report:generate# .env file
TEST_ENV=dev # Required: dev, qa, uat, local
SUPERADMIN_USERNAME=admin # Required
SUPERADMIN_PASSWORD=Admin123 # RequiredConfigured in src/config/environments.js:
export let environments = {
local: {
baseUri: "https://localhost/",
},
dev: {
baseUri: "https://dev.bahmni.org/",
userName: "",
password: "",
},
qa: {
baseUri: "https://qa.bahmni.org/",
userName: "",
password: "",
},
// ...
};describe("Feature", function () {
before(async function () {
/* Setup */
});
it("should do something", async function () {
const response = await apiCall();
addApiDetailsToReport(this);
expect(response.status).to.equal(200);
});
afterEach(function () {
resetAuthCredentials();
});
});import {
setAuthCredentials,
resetAuthCredentials,
} from "../../src/config/authManager.js";
it("test with user", async function () {
setAuthCredentials("user", "pass");
const response = await apiCall();
expect(response.status).to.equal(200);
// Auto-reset in afterEach
});expect(response.status).to.equal(200);
expect(response.body).to.be.an("array");
expect(response.body).to.have.property("uuid");
expect(actualArray).to.have.members(expectedArray);
expect(actualObject).to.deep.equal(expectedObject);- API Tracker Guide - Complete API tracking & service creation
- Service Layer First - Create service methods, never direct HTTP calls in tests
- Use API Tracker Pattern - Follow the
lastApiCall+handleApiResponse()pattern for all service methods - Reset Auth - Always reset credentials in
afterEach - Add Logs - Use
addTestLog()for debugging - Separate Data - Keep payloads/credentials in testdata/
- Environment Variables - Never hardcode sensitive data
- Clean Up - Delete test data in
afterhooks - One Concept - Test one thing per test case
- Follow existing folder structure
- Use API Tracker pattern for services
- Add test logs for debugging
- Update docs if needed
- Test in multiple environments
MPL-2.0
Happy Testing! π