Skip to content

Commit ef1c49c

Browse files
committed
refactored version
1 parent 22536d4 commit ef1c49c

File tree

7 files changed

+91
-90
lines changed

7 files changed

+91
-90
lines changed

infra/api/apiClient/ApiClient.ts

Lines changed: 83 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
1-
import { el } from "@faker-js/faker";
2-
import { APIRequestContext, APIResponse, expect } from "@playwright/test";
1+
import { ur } from '@faker-js/faker';
2+
import { APIRequestContext, APIResponse } from '@playwright/test';
33

4-
export enum RequestMethods {
4+
export enum RequestMethod {
55
GET = 'GET',
66
POST = 'POST',
77
PUT = 'PUT',
@@ -20,6 +20,13 @@ export enum StatusCode {
2020
SERVER_ERROR = 500,
2121
}
2222

23+
export enum PaginationType {
24+
PAGE_PAGINATION = 'page',
25+
OFFSET_PAGINATION = 'offset',
26+
CURSOR_PAGINATION = 'cursor',
27+
}
28+
29+
2330
export interface ApiOptionalParams<T> {
2431
responseDataKey?: string,
2532
queryParams?: { [key: string]: any },
@@ -33,18 +40,21 @@ export interface ApiOptionalParams<T> {
3340
pageNumber?: number,
3441
limit?: number,
3542
offset?: number,
43+
cursor?: boolean,
44+
cursorKey?: string,
45+
paginationType?: PaginationType,
46+
responseKey?: string,
3647
}
3748

38-
3949
export class ApiClient {
40-
constructor(public apiRequestContext: APIRequestContext) {
41-
this.apiRequestContext = apiRequestContext
50+
constructor(public request: APIRequestContext) {
51+
this.request = request;
4252
}
4353

4454
/**
45-
* @description resuable code to add the authorization header if an authorization is requiired to make the request
46-
* @param headers
47-
*/
55+
* @description resuable code to add the authorization header if an authorization is requiired to make the request
56+
* @param headers
57+
*/
4858
private async addAuthorizationHeader(headers: { [key: string]: string }) {
4959
headers['Authorization'] = `Bearer ${process.env.API_TOKEN}`
5060
}
@@ -56,7 +66,7 @@ export class ApiClient {
5666
* @param options
5767
* @returns
5868
*/
59-
private async makeRequest<T>(method: RequestMethods, url: string, options?: ApiOptionalParams<T>): Promise<APIResponse | undefined> {
69+
private async makeRequest<T>(method: RequestMethod, url: string, options?: ApiOptionalParams<T>): Promise<APIResponse | undefined> {
6070
let response: APIResponse | undefined
6171
let headers: Record<string, string> = {
6272
'Accept': '*/*'
@@ -71,106 +81,107 @@ export class ApiClient {
7181
}
7282
switch (method.valueOf()) {
7383
case 'GET':
74-
response = await this.apiRequestContext.get(url, { headers, params: options?.queryParams })
84+
response = await this.request.get(url, { headers, params: options?.queryParams })
7585
break;
7686
case 'POST':
77-
response = await this.apiRequestContext.post(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
87+
response = await this.request.post(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
7888
break;
7989
case 'PUT':
80-
response = await this.apiRequestContext.put(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
90+
response = await this.request.put(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
8191
break;
8292
case 'PATCH':
83-
response = await this.apiRequestContext.patch(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
93+
response = await this.request.patch(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
8494
break;
8595
case 'DELETE':
86-
response = await this.apiRequestContext.delete(url)
96+
response = await this.request.delete(url)
8797
break;
8898
}
8999
return response
90100
}
91101

92-
/**
93-
* @description function that supports pagination via page pagination or by limit and offset pagination
94-
*/
95-
protected async paginateRequest<T>(method: RequestMethods, url: string, options?: ApiOptionalParams<T>) {
96-
let existingQueryParams = { ...options?.queryParams }
97-
let response: APIResponse | undefined
98-
let responses: APIResponse[] = []
99-
try {
100-
while (true) {
101-
if (options?.pagePagination && options?.pageNumber !== undefined) {
102-
existingQueryParams['page'] = options.pageNumber
103-
response = await this.makeRequest(method, url, { queryParams: existingQueryParams, requestData: options.requestData, authoriaztionRequired: options.authoriaztionRequired })
104-
let responseObject = await response?.json()
105-
if (!responseObject || responseObject.length === 0) {
106-
break
107-
}
108-
responses.push(...responseObject)
109-
options.pageNumber++
110-
}
111-
if (options?.limitOffsetPagination) {
112-
existingQueryParams['limit'] = options.limit
113-
existingQueryParams['offset'] = options.offset
114-
response = await this.makeRequest(method, url, { queryParams: existingQueryParams, requestData: options.requestData, authoriaztionRequired: options.authoriaztionRequired })
115-
let responseObject = await response?.json()
116-
if (!responseObject || responseObject.length === 0) {
117-
break
118-
}
119-
if (options.responseDataKey !== undefined) {
120-
let responseKey = responseObject[options.responseDataKey]
121-
if (responseKey.length === 0) {
122-
break;
123-
}
124-
responses.push(...responseKey)
125-
} else {
126-
if (Array.isArray(responseObject)) {
127-
responses.push(...responseObject)
128-
} else {
129-
responses.push(responseObject)
130-
}
131-
}
132-
if (options.offset !== undefined && options.limit !== undefined) {
133-
options.offset += options.limit
134-
}
102+
103+
private async paginateBy<T>(method: RequestMethod, url: string, paginationType: PaginationType, options?: ApiOptionalParams<T>) {
104+
let response: APIResponse | undefined;
105+
let responses: APIResponse[] = [];
106+
let queryParams = options?.queryParams ? { ...options.queryParams } : {};
107+
while (true) {
108+
if (paginationType === PaginationType.PAGE_PAGINATION && options?.pageNumber !== undefined) {
109+
queryParams = { ...queryParams, 'page': options.pageNumber };
110+
} else if (paginationType === PaginationType.OFFSET_PAGINATION && options?.limit !== undefined && options.offset !== undefined) {
111+
queryParams = { ...queryParams, 'limit': options.limit, 'offset': options.offset };
112+
}
113+
response = await this.makeRequest(method, url, { ...options, queryParams });
114+
let responseObj = await response?.json();
115+
if (!responseObj || responseObj.length === 0) {
116+
break;
117+
}
118+
if (options?.responseKey) {
119+
let responseKey = responseObj[options.responseKey];
120+
if (responseKey.length === 0) {
121+
break;
135122
}
123+
await this.handleResponseObject(responses, responseKey);
124+
} else {
125+
await this.handleResponseObject(responses, responseObj);
136126
}
137-
return responses
127+
if (paginationType === PaginationType.PAGE_PAGINATION && options?.pageNumber !== undefined) {
128+
options.pageNumber++;
129+
} else if (paginationType === PaginationType.OFFSET_PAGINATION && options?.offset !== undefined && options.limit !== undefined) {
130+
options.offset += options.limit;
131+
}
132+
}
138133

134+
return responses;
135+
}
136+
/**
137+
* @description handle the response object by spreading it to an existing array if the response is already an array otherwise push directly
138+
* to the array.
139+
* @param responseObj
140+
*/
141+
private async handleResponseObject(responses: APIResponse[], responseObj: any) {
142+
if (Array.isArray(responseObj)) {
143+
responses.push(...responseObj)
144+
} else {
145+
responses.push(responseObj);
146+
}
147+
}
148+
149+
public async paginateRequest<T>(method: RequestMethod, url: string, pagintionType: PaginationType, options: ApiOptionalParams<T>) {
150+
try {
151+
let response = await this.paginateBy(method, url, pagintionType, options);
152+
return response;
139153
} catch (error) {
140-
throw new Error(`caught an error in the paginate request function: ${error}`)
154+
throw new Error(`an error occured in the paginate request function: ${error}`)
141155
}
142156
}
143157

144-
/**
145-
* @description http request that abstracts the logic behind the scenes
146-
*/
147-
private async httpRequest<T>(method: RequestMethods, url: string, options?: ApiOptionalParams<T>) {
158+
private async makeHttpRequest<T>(method: RequestMethod, url: string, options?: ApiOptionalParams<T>) {
148159
let response = await this.makeRequest(method, url, options)
149160
return response;
150161
}
151162

152163
public async get<T>(url: string, options?: ApiOptionalParams<T>) {
153-
let response = await this.httpRequest(RequestMethods.GET, url, options)
154-
return response
164+
let response = await this.makeHttpRequest(RequestMethod.GET, url, options)
165+
return response;
155166
}
156167

157168
public async post<T>(url: string, options?: ApiOptionalParams<T>) {
158-
let response = await this.httpRequest(RequestMethods.POST, url, options)
159-
return response
169+
let response = await this.makeHttpRequest(RequestMethod.POST, url, options)
170+
return response;
160171
}
161172

162173
public async put<T>(url: string, options?: ApiOptionalParams<T>) {
163-
let response = await this.httpRequest(RequestMethods.PUT, url, options);
164-
return response
174+
let response = await this.makeHttpRequest(RequestMethod.PUT, url, options)
175+
return response;
165176
}
166177

167178
public async patch<T>(url: string, options?: ApiOptionalParams<T>) {
168-
let response = await this.httpRequest(RequestMethods.PATCH, url, options);
179+
let response = await this.makeHttpRequest(RequestMethod.PATCH, url, options)
169180
return response;
170181
}
171182

172183
public async delete<T>(url: string, options?: ApiOptionalParams<T>) {
173-
let response = await this.httpRequest(RequestMethods.DELETE, url, options);
184+
let response = await this.makeHttpRequest(RequestMethod.DELETE, url, options)
174185
return response;
175186
}
176187
}

infra/api/entities/gorestapi/Users.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { APIResponse } from "@playwright/test";
2-
import { ApiClient, RequestMethods, StatusCode } from "../../apiClient/ApiClient";
2+
import { ApiClient, PaginationType, RequestMethod } from "../../apiClient/ApiClient";
33
import Randomizer from "../../helpers/faker/Randomizer";
44
import { ApplicationUrl } from "../../helpers/urls/ApplicationUrl";
55
import { ApiEndpoints } from "../../endpoints/ApiEndpoints";
@@ -89,7 +89,7 @@ export class Users extends ApiClient {
8989
* @returns
9090
*/
9191
public async getAllUsers(page: number) {
92-
let response = await this.paginateRequest(RequestMethods.GET, this.usersEnpoint, { paginateRequest: true, pagePagination: true, pageNumber: page })
92+
let response = await this.paginateRequest(RequestMethod.GET, this.usersEnpoint, PaginationType.PAGE_PAGINATION, { paginateRequest: true, pagePagination: true, pageNumber: page })
9393
return response;
9494
}
9595

infra/api/entities/petStore/PetStoreCrudActions.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,5 +47,4 @@ export class PetStoreCrudActions extends ApiClient {
4747
let response = await this.delete(`${this.petStorePetEndpoint}/${petId}`)
4848
return response;
4949
}
50-
5150
}

infra/api/entities/pokemon/PokemonApi.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { APIRequestContext, APIResponse, expect } from "@playwright/test";
2-
import { ApiClient, RequestMethods, StatusCode } from "../../apiClient/ApiClient";
2+
import { ApiClient, PaginationType, RequestMethod, StatusCode } from "../../apiClient/ApiClient";
33
import { ApplicationUrl } from "../../helpers/urls/ApplicationUrl";
44
import { ApiEndpoints } from "../../endpoints/ApiEndpoints";
55

@@ -15,8 +15,8 @@ export class PokemonApi extends ApiClient {
1515
/**
1616
* @description get all pokemon recourses by using pagination - you can choose via page or limit and offset pagination mechanism
1717
*/
18-
public async getAllPokemonRecourses(limit: number, offset: number, options?: { pagePagination?: boolean, limitOffsetPagination?: boolean }) {
19-
let responses = await this.paginateRequest(RequestMethods.GET, this.POKEMON_ENDPOINT, { limit: limit, offset: offset, limitOffsetPagination: options?.limitOffsetPagination, responseDataKey: 'results' })
18+
public async getAllPokemonRecourses(limit: number, offset: number) {
19+
let responses = await this.paginateRequest(RequestMethod.GET, this.POKEMON_ENDPOINT, PaginationType.OFFSET_PAGINATION, { limitOffsetPagination: true, limit: limit, offset: offset, responseKey: 'results' })
2020
return responses;
2121
}
2222
}

tests/api_tests/goRestApi/GoRestApiTests.spec.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@ test.describe('Api tests for GoRestApi endpoints', async () => {
1111
users = new Users(request);
1212
})
1313

14-
15-
test.skip('get all users', { tag: ['@GO_REST_API'] }, async () => {
16-
await test.step('get all users from all pages from users endpoint', async () => {
17-
let res = await users.getAllUsers(pageNumber)
18-
expect(res.every(res => res.status())).toBe(StatusCode.OK)
19-
})
20-
})
21-
22-
2314
test('sanity check', { tag: ['@GO_REST_API'] }, async () => {
2415
await test.step('get users endpoint - validate status, body type of obejct properties and default length of the response', async () => {
2516
let response = await users.getUsers();

tests/api_tests/petStore/PetStoreCrudTests.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ test.describe.serial('CRUD API tests for the Pet Store API', async () => {
2020
let response = await petStoreCrudActions.getPet(id)
2121
let responseJson: Ipet = await response?.json()
2222
expect(response?.status()).toBe(StatusCode.OK)
23-
expect(responseJson.name).toBe('ZAP')
23+
expect(responseJson.name).toBe('doggie')
2424
})
2525
})
2626

tests/api_tests/pokemon/PokemonApiTests.spec.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ test.describe('Pokemon API CRUD tests', async () => {
2929

3030
test('get all pokemon resources', { tag: ['@POKEMON_API'] }, async () => {
3131
await test.step('get all pokemon recourses via limit and offset pagination', async () => {
32-
let response = await pokemonApi.getAllPokemonRecourses(limit, offset, { limitOffsetPagination: true })
33-
let responseLength = response.length
32+
let response = await pokemonApi.getAllPokemonRecourses(limit, offset)
33+
let responseLength = response?.length
3434
expect(responseLength).toBe(1302)
3535
})
3636
})

0 commit comments

Comments
 (0)