Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
The diff you're trying to view is too large. We only load the first 3000 changed files.
Binary file modified .DS_Store
Binary file not shown.
2 changes: 1 addition & 1 deletion .env
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,5 @@ PASSWORD=test_pass


# New API test variables
API_BASE_URL=https://api.example.com
API_BASE_URL=https://postman-echo.com
API_TOKEN=your_api_token_here
2 changes: 1 addition & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
* text=auto
55 changes: 55 additions & 0 deletions .github/workflows/api-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: Echo API Tests

on:
push:
branches: [main, master]
pull_request:
branches: [main, master]
workflow_dispatch:

jobs:
test:
runs-on: ubuntu-latest
permissions:
contents: read
actions: write

steps:
- name: Checkout repository
uses: actions/checkout@v4

- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'

- name: Clean npm cache
run: npm cache clean --force

- name: Install dependencies
run: |
rm -rf node_modules
rm -f package-lock.json
npm install

- name: Create reports directory
run: mkdir -p reports

- name: Run Echo API tests
run: |
npm run pretest
npm run test:echo
env:
API_BASE_URL: 'https://postman-echo.com'

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: echo-api-test-reports
path: |
reports/cucumber-report.json
reports/cucumber-report.html
retention-days: 30
if-no-files-found: warn
37 changes: 34 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,37 @@
node_modules
.env

# Dependencies
node_modules/
package-lock.json

# TypeScript compiled output
dist/
*.js.map

# Test reports
reports/
cucumber-report.html
cucumber-report.json

# Environment files
.env
.env.*

# IDE files
.idea/
.vscode/
*.swp
*.swo

# OS files
.DS_Store
Thumbs.db

# Debug logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*

package.json
dist
reports/
reports/

26 changes: 26 additions & 0 deletions api-tests/features/echo-api.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
@api @users
Feature: Postman Echo API Testing

Scenario: Successfully retrieve data from echo GET endpoint
When I send a GET request to the echo endpoint
Then the echo response status code should be 200
And the response should contain the request details

Scenario: Successfully send data to echo POST endpoint
Given I have valid POST request data
When I send a POST request to the echo endpoint
Then the echo response status code should be 200
And the POST response should contain the sent data
And the response should contain the request details

Scenario: Send POST request with invalid Content-Type
Given I have valid POST request data
And I set the Content-Type header to "text/plain"
When I send a POST request to the echo endpoint
Then the echo response status code should be 200
And the POST response should show different Content-Type

Scenario: Send POST request with empty body
Given I have empty POST request data
When I send a POST request to the echo endpoint
Then the echo response status code should be 200
24 changes: 24 additions & 0 deletions api-tests/features/user-api.feature
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# @users
# Feature: Users API Testing

# @smoke @get
# Scenario: Get user details successfully
# Given I have a valid user ID
# When I send a GET request to fetch user details
# Then the response status code should be 200
# And the response should contain user information

# @smoke @post @create
# Scenario: Create a new user
# Given I have valid user creation payload
# When I send a POST request to create user
# Then the response status code should be 201
# And the response should contain the created user details

# @regression @put @update
# Scenario: Update user details
# Given I have a valid user ID
# And I have valid user update payload
# When I send a PUT request to update user
# Then the response status code should be 200
# And the response should contain updated information
27 changes: 27 additions & 0 deletions api-tests/generate-report.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import fs from 'fs';
import path from 'path';
import { ReportGenerator } from './support/report-generator';

try {
const jsonReportPath = path.join(
process.cwd(),
'reports',
'cucumber-report.json'
);

// Create reports directory if it doesn't exist
if (!fs.existsSync('reports')) {
fs.mkdirSync('reports', { recursive: true });
}

// Check if report exists
if (fs.existsSync(jsonReportPath)) {
const jsonReport = JSON.parse(fs.readFileSync(jsonReportPath, 'utf8'));
ReportGenerator.generateCustomReport(jsonReport);
console.log('Report generated successfully');
} else {
console.log('No cucumber-report.json found');
}
} catch (error) {
console.error('Error generating report:', error);
}
135 changes: 135 additions & 0 deletions api-tests/steps/echo-api.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import {
Given,
When,
Then,
Before,
After,
ITestCaseHookParameter,
} from '@cucumber/cucumber';
import { expect } from 'chai';
import { APIClient } from '../support/api-client';
import { CustomWorld } from '../support/world';
import { AxiosError } from 'axios';
import { CurlFormatter } from '../support/curl-formatter';

// Initialize API client and response object before each scenario
Before(function (this: CustomWorld) {
this.apiClient = new APIClient();
this.response = null; // Initialize response
this.requestData = null;
this.headers = {};
});

When(
'I send a GET request to the echo endpoint',
async function (this: CustomWorld) {
try {
this.response = await this.apiClient.get('/get');
} catch (error) {
console.error('API request failed:', error);
throw error;
}
}
);

Then(
'the echo response status code should be {int}',
async function (this: CustomWorld, statusCode: number) {
console.log(this.response);
expect(this.response).to.not.be.null;
expect(this.response?.status).to.equal(statusCode);
}
);

Then(
'the response should contain the request details',
async function (this: CustomWorld) {
expect(this.response).to.not.be.null;
expect(this.response!.data).to.have.property('url');
expect(this.response!.data).to.have.property('headers');
expect(this.response!.data).to.have.property('args');
console.log(this.response!.data);
}
);

Given('I have valid POST request data', function (this: CustomWorld) {
this.requestData = {
method: 'POST',
};
});

Given('I have empty POST request data', function (this: CustomWorld) {
this.requestData = {};
});

Given(
'I set the Content-Type header to {string}',
function (this: CustomWorld, contentType: string) {
this.headers = {
'Content-Type': contentType,
};
}
);

When(
'I send a POST request to the echo endpoint',
async function (this: CustomWorld) {
try {
this.response = await this.apiClient.post('/post', {
data: this.requestData,
headers: this.headers,
});
} catch (error) {
if (error instanceof AxiosError) {
this.response = error.response || null;
} else {
throw error;
}
}
}
);

Then(
'the POST response should contain the sent data',
async function (this: CustomWorld) {
expect(this.response).to.not.be.null;
expect(this.response!.data).to.have.property('json');
expect(this.response!.data.json).to.deep.equal(this.requestData);
}
);

Then(
'the POST response should show different Content-Type',
async function (this: CustomWorld) {
expect(this.response).to.not.be.null;
expect(this.response!.data).to.have.property('headers');
expect(this.response!.data.headers['content-type']).to.equal('text/plain');
}
);

Then(
'the POST response should contain empty data',
async function (this: CustomWorld) {
expect(this.response).to.not.be.null;
expect(this.response!.data).to.have.property('json');
expect(this.response!.data.json).to.deep.equal({});
}
);

After(async function (this: CustomWorld, scenario: ITestCaseHookParameter) {
if (this.response) {
const curlCommand = CurlFormatter.generateCurlCommand(this.response);

// Use attach method from the World context
await this.attach(curlCommand, 'text/plain');

// Store for report generation
if (!this.curlCommands) {
this.curlCommands = [];
}
this.curlCommands.push({
scenarioName: scenario.pickle.name,
curl: curlCommand,
});
}
});
67 changes: 67 additions & 0 deletions api-tests/steps/users-api.steps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import { Given, When, Then } from '@cucumber/cucumber';
import { expect } from 'chai';
import { APIClient } from '../support/api-client';
import { CustomWorld } from '../support/world';

const apiClient = new APIClient();
let response: any;
let userId: string;
let userPayload: any;

Given('I have a valid user ID', function () {
userId = '123'; // This could come from test data or environment
});

Given('I have valid user creation payload', function () {
userPayload = {
name: 'John Doe',
email: 'john.doe@example.com',
role: 'user',
};
});

Given('I have valid user update payload', function () {
userPayload = {
name: 'John Updated',
email: 'john.updated@example.com',
};
});

When('I send a GET request to fetch user details', async function () {
response = await apiClient.get(`/users/${userId}`);
});

When('I send a POST request to create user', async function () {
response = await apiClient.post('/users', userPayload);
});

When('I send a PUT request to update user', async function () {
response = await apiClient.put(`/users/${userId}`, userPayload);
});

Then(
'the response status code should be {int}',
async function (this: CustomWorld, statusCode: number) {
console.log(this.response);
expect(this.response).to.not.be.null;
expect(this.response?.status).to.equal(statusCode);
// expect(this.response?.status).to.equal(404);
}
);

Then('the response should contain user information', function () {
expect(response.data).to.have.property('id');
expect(response.data).to.have.property('name');
expect(response.data).to.have.property('email');
});

Then('the response should contain the created user details', function () {
expect(response.data).to.have.property('id');
expect(response.data.name).to.equal(userPayload.name);
expect(response.data.email).to.equal(userPayload.email);
});

Then('the response should contain updated information', function () {
expect(response.data.name).to.equal(userPayload.name);
expect(response.data.email).to.equal(userPayload.email);
});
Loading