Skip to content

Commit 090c46c

Browse files
author
hoggu-sudo
committed
Add CI workflow for Playwright API tests
1 parent acd52cf commit 090c46c

30 files changed

Lines changed: 433 additions & 109 deletions

.github/workflows/playwright.yml

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,27 @@ name: Playwright API Tests
33
on:
44
push:
55
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
68

79
jobs:
810
test:
911
runs-on: ubuntu-latest
1012

1113
steps:
12-
- uses: actions/checkout@v3
14+
- name: Checkout repo
15+
uses: actions/checkout@v4
16+
17+
- name: Setup Node
18+
uses: actions/setup-node@v4
19+
with:
20+
node-version: 20
1321

14-
- name: Install Node
15-
uses: actions/setup-node@v3
16-
with:
17-
node-version: 18
22+
- name: Install dependencies
23+
run: npm install
1824

19-
- run: npm install
20-
- run: npx playwright install --with-deps
25+
- name: Install Playwright browsers
26+
run: npx playwright install --with-deps
2127

22-
- run: npx playwright test
28+
- name: Run API tests
29+
run: npx playwright test tests/api

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Playwright TypeScript API Automation Framework
22

3+
![CI](https://github.com/hoggu-sudo/playwright-ts-api-framework/actions/workflows/playwright.yml/badge.svg)
4+
5+
# Playwright TypeScript API Automation Framework
6+
37
A production-style API automation framework built using **Playwright + TypeScript**, designed to demonstrate scalable test architecture, reusable API abstractions, validation layers, payload builders, and end-to-end workflow validation.
48

59
---

package-lock.json

Lines changed: 138 additions & 13 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,16 @@
1111
"report": "playwright show-report"
1212
},
1313
"keywords": [],
14-
"author": "",
14+
"author": "Hemasundar Oggu",
1515
"license": "ISC",
1616
"devDependencies": {
17-
"@playwright/test": "^latest",
18-
"@types/node": "^latest",
19-
"ts-node": "^latest",
20-
"typescript": "^latest"
17+
"@playwright/test": "^1.53.0",
18+
"@types/node": "^22.15.3",
19+
"ts-node": "^10.9.2",
20+
"typescript": "^5.8.3",
21+
"xlsx": "^0.18.5"
22+
},
23+
"dependencies": {
24+
"zod": "^4.3.6"
2125
}
22-
}
26+
}

playwright.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import { defineConfig } from '@playwright/test';
2+
import path from 'path';
23

34
export default defineConfig({
45
testDir: './tests',
56
timeout: 30000,
67
fullyParallel: false,
78
reporter: [['html'], ['list']],
89
use: {
9-
baseURL: 'https://reqres.in',
10+
baseURL: 'https://dummyjson.com',
1011
extraHTTPHeaders: {
1112
'Content-Type': 'application/json'
1213
}

src/api/clients/baseClient.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
import { request, APIRequestContext, APIResponse } from '@playwright/test';
2-
import { ENV } from '../../config/env';
3-
import { Logger } from '../../utils/logger';
2+
import { ENV } from '@config/env';
3+
import { Logger } from '@utils/logger';
44

55
export class BaseClient {
66
private requestContext!: APIRequestContext;
77

8-
async init() {
9-
this.requestContext = await request.newContext({
10-
baseURL: ENV.BASE_URL,
11-
extraHTTPHeaders: {
12-
'Content-Type': 'application/json'
13-
}
14-
});
15-
}
8+
async init(token?: string) {
9+
this.requestContext = await request.newContext({
10+
baseURL: ENV.BASE_URL,
11+
extraHTTPHeaders: {
12+
'Content-Type': 'application/json',
13+
...(token ? { Authorization: `Bearer ${token}` } : {})
14+
}
15+
});
16+
}
1617

1718
private ensureInitialized() {
1819
if (!this.requestContext) {
@@ -44,7 +45,10 @@ export class BaseClient {
4445
this.ensureInitialized();
4546
Logger.logRequest('POST', endpoint, body);
4647

47-
const response = await this.requestContext.post(endpoint, { data: body });
48+
// const response = await this.requestContext.post(endpoint, { data: body });
49+
const response = await this.retryRequest(() =>
50+
this.requestContext.post(endpoint, { data: body })
51+
);
4852
const data = await this.parseResponse(response);
4953

5054
Logger.logResponse(response.status(), data);
@@ -79,4 +83,18 @@ export class BaseClient {
7983
async dispose() {
8084
await this.requestContext?.dispose();
8185
}
86+
87+
private async retryRequest(fn: () => Promise<any>, retries = 2) {
88+
let attempt = 0;
89+
90+
while (attempt <= retries) {
91+
try {
92+
return await fn();
93+
} catch (error) {
94+
if (attempt === retries) throw error;
95+
console.log(`Retrying request... attempt ${attempt + 1}`);
96+
attempt++;
97+
}
98+
}
99+
}
82100
}

src/api/clients/userClient.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { BaseClient } from './baseClient';
2-
import { UserPayload } from '../models/user.types';
1+
import { BaseClient } from '@api/clients/baseClient';
2+
import { UserPayload } from '@api/models/user.types';
33

44
export class UserClient {
55
private baseClient: BaseClient;

src/api/models/user.schema.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { z } from 'zod';
2+
3+
export const UserResponseSchema = z.object({
4+
id: z.number(),
5+
firstName: z.string(),
6+
lastName: z.string(),
7+
age: z.number()
8+
});

0 commit comments

Comments
 (0)