Skip to content
Binary file modified .DS_Store
Binary file not shown.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ main.ts
.idea
.ide
.vscode
vscode
vscode
.early.coverage
183 changes: 82 additions & 101 deletions infra/api/apiClient/ApiClient.ts
Original file line number Diff line number Diff line change
@@ -1,62 +1,50 @@
import { ur } from '@faker-js/faker';
import { APIRequestContext, APIResponse } from '@playwright/test';
import { ApiOptionalParams, PaginationType, IRequestOptions } from '../helpers/types/api-types';
import { RequestMethod } from '../helpers/types/api-request-types';

export enum RequestMethod {
GET = 'GET',
POST = 'POST',
PUT = 'PUT',
PATCH = 'PATCH',
DELETE = 'DELETE',
}
export class ApiClient {

export enum StatusCode {
OK = 200,
CREATED = 201,
NO_CONTENT = 204,
BAD_REQUEST = 400,
UNAUTHORIZED = 401,
FORBIDDEN = 403,
NOT_FOUND = 404,
SERVER_ERROR = 500,
}
constructor(public request: APIRequestContext) {
this.request = request;
}

export enum PaginationType {
PAGE_PAGINATION = 'page',
OFFSET_PAGINATION = 'offset',
CURSOR_PAGINATION = 'cursor',
}
public async get<T>(url: string, options: ApiOptionalParams<T> = {}) {
let response = await this.makeRequest(RequestMethod.GET, url, options)
return response;
}

public async post<T>(url: string, options: ApiOptionalParams<T> = {}) {
let response = await this.makeRequest(RequestMethod.POST, url, options)
return response;
}

export interface ApiOptionalParams<T> {
responseDataKey?: string,
queryParams?: { [key: string]: any },
requestData?: { [key: string]: T },
authoriaztionRequired?: boolean,
isMultiPart?: boolean,
multiPartData?: { [key: string]: any },
paginateRequest?: boolean,
pagePagination?: boolean,
limitOffsetPagination?: boolean,
pageNumber?: number,
limit?: number,
offset?: number,
cursor?: boolean,
cursorKey?: string,
paginationType?: PaginationType,
responseKey?: string,
}
public async put<T>(url: string, options: ApiOptionalParams<T> = {}) {
let response = await this.makeRequest(RequestMethod.PUT, url, options)
return response;
}

export class ApiClient {
constructor(public request: APIRequestContext) {
this.request = request;
public async patch<T>(url: string, options: ApiOptionalParams<T> = {}) {
let response = await this.makeRequest(RequestMethod.PATCH, url, options)
return response;
}

/**
* @description resuable code to add the authorization header if an authorization is requiired to make the request
* @param headers
*/
private async addAuthorizationHeader(headers: { [key: string]: string }) {
headers['Authorization'] = `Bearer ${process.env.API_TOKEN}`;
public async delete<T>(url: string, options: ApiOptionalParams<T> = {}) {
let response = await this.makeRequest(RequestMethod.DELETE, url, options)
return response;
}

public async paginateRequest<T>(
method: RequestMethod,
url: string,
paginationType: PaginationType,
options: ApiOptionalParams<T>
) {
try {
let response = await this.paginateBy(method, url, paginationType, options);
return response;
} catch (error) {
throw new Error(`an error occurred in the paginate request function: ${error}`)
}
}

/**
Expand All @@ -66,31 +54,34 @@ export class ApiClient {
* @param options
* @returns
*/
private async makeRequest<T>(method: RequestMethod, url: string, options?: ApiOptionalParams<T>): Promise<APIResponse | undefined> {
private async makeRequest<T>(
method: RequestMethod,
url: string,
options: ApiOptionalParams<T> = {}
): Promise<APIResponse | undefined> {
let response: APIResponse | undefined
let headers: Record<string, string> = {
'Content-Type': 'application/json',
'Accept': '*/*'
}
if (options?.isMultiPart) {
headers["Content-Type"] = 'multipart/form-data'
} else {
headers["Content-Type"] = 'application/json'
}
if (options?.authoriaztionRequired) {
if (options?.isAuthorizationRequired && method !== RequestMethod.GET) {
await this.addAuthorizationHeader(headers)
}
switch (method.valueOf()) {
case 'GET':
response = await this.request.get(url, { headers, params: options?.queryParams })
response = await this.request.get(url, { headers, params: options.queryParams })
break;
case 'POST':
response = await this.request.post(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
response = await this.request.post(url, { headers, data: options.requestData, multipart: options.multiPartData })
break;
case 'PUT':
response = await this.request.put(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
response = await this.request.put(url, { headers, data: options.requestData, multipart: options.multiPartData })
break;
case 'PATCH':
response = await this.request.patch(url, { headers, data: options?.requestData, multipart: options?.multiPartData! })
response = await this.request.patch(url, { headers, data: options.requestData, multipart: options.multiPartData })
break;
case 'DELETE':
response = await this.request.delete(url)
Expand All @@ -99,18 +90,25 @@ export class ApiClient {
return response;
}

/**
* @description reusable code to add the authorization header if an authorization is required to make the request
* @param headers
*/
private async addAuthorizationHeader(headers: { [key: string]: string }) {
headers['Authorization'] = `Bearer ${process.env.API_TOKEN}`;
}

private async paginateBy<T>(method: RequestMethod, url: string, paginationType: PaginationType, options?: ApiOptionalParams<T>) {
private async paginateBy<T>(
method: RequestMethod,
url: string,
paginationType: PaginationType,
options: ApiOptionalParams<T> = {}
) {
let response: APIResponse | undefined;
let responses: APIResponse[] = [];
let queryParams = options?.queryParams ? { ...options.queryParams } : {};
while (true) {
if (paginationType === PaginationType.PAGE_PAGINATION && options?.pageNumber !== undefined) {
queryParams = { ...queryParams, 'page': options.pageNumber };
} else if (paginationType === PaginationType.OFFSET_PAGINATION && options?.limit !== undefined && options.offset !== undefined) {
queryParams = { ...queryParams, 'limit': options.limit, 'offset': options.offset };
}
response = await this.makeRequest(method, url, { ...options, queryParams });
await this.updatePaginationQueryParams(paginationType, options);
response = await this.makeRequest(method, url, options);
let responseObj = await response?.json();
if (!responseObj || responseObj.length === 0) {
break;
Expand All @@ -124,11 +122,7 @@ export class ApiClient {
} else {
await this.handleResponseObject(responses, responseObj);
}
if (paginationType === PaginationType.PAGE_PAGINATION && options?.pageNumber !== undefined) {
options.pageNumber++;
} else if (paginationType === PaginationType.OFFSET_PAGINATION && options?.offset !== undefined && options.limit !== undefined) {
options.offset += options.limit;
}
await this.updatePaginationOptions(paginationType, options);
}

return responses;
Expand All @@ -138,45 +132,32 @@ export class ApiClient {
* to the array.
* @param responseObj
*/
private async handleResponseObject(responses: APIResponse[], responseObj: any) {
private async handleResponseObject(responses: APIResponse[], responseObj: APIResponse) {
if (Array.isArray(responseObj)) {
responses.push(...responseObj)
} else {
responses.push(responseObj);
}
}

public async paginateRequest<T>(method: RequestMethod, url: string, pagintionType: PaginationType, options: ApiOptionalParams<T>) {
try {
let response = await this.paginateBy(method, url, pagintionType, options);
return response;
} catch (error) {
throw new Error(`an error occured in the paginate request function: ${error}`)
private async updatePaginationQueryParams<T>(paginationType: PaginationType, options: ApiOptionalParams<T> = {}) {
if (paginationType === PaginationType.PAGE_PAGINATION && options.pageNumber !== undefined) {
options.queryParams = { ...options.queryParams, 'page': options.pageNumber }
} else if (paginationType === PaginationType.OFFSET_PAGINATION && options.limit !== undefined && options.offset !== undefined) {
options.queryParams = { ...options.queryParams, 'limit': options.limit, 'offset': options.offset }
}
}

public async get<T>(url: string, options?: ApiOptionalParams<T>) {
let response = await this.makeRequest(RequestMethod.GET, url, options)
return response;
}

public async post<T>(url: string, options?: ApiOptionalParams<T>) {
let response = await this.makeRequest(RequestMethod.POST, url, options)
return response;
}

public async put<T>(url: string, options?: ApiOptionalParams<T>) {
let response = await this.makeRequest(RequestMethod.PUT, url, options)
return response;
}

public async patch<T>(url: string, options?: ApiOptionalParams<T>) {
let response = await this.makeRequest(RequestMethod.PATCH, url, options)
return response;
}

public async delete<T>(url: string, options?: ApiOptionalParams<T>) {
let response = await this.makeRequest(RequestMethod.DELETE, url, options)
return response;
/**
* @description update the pagination options based on the pagination type - page or offset pagination at the moment
* @param paginationType
* @param options
*/
private async updatePaginationOptions<T>(paginationType: PaginationType, options: ApiOptionalParams<T> = {}) {
if (paginationType === PaginationType.PAGE_PAGINATION && options.pageNumber !== undefined) {
options.pageNumber++;
} else if (paginationType === PaginationType.OFFSET_PAGINATION && options.limit !== undefined && options.offset !== undefined) {
options.offset += options.limit;
}
}
}
43 changes: 26 additions & 17 deletions infra/api/entities/gorestapi/Users.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,21 @@
import { APIResponse } from "@playwright/test";
import { ApiClient, PaginationType, RequestMethod } from "../../apiClient/ApiClient";
import { ApiClient } from "../../apiClient/ApiClient";
import Randomizer from "../../helpers/faker/Randomizer";
import { ApplicationUrl } from "../../helpers/urls/ApplicationUrl";
import { ApiEndpoints } from "../../endpoints/ApiEndpoints";
import { RequestMethod } from "../../helpers/types/api-request-types";
import { PaginationType } from "../../helpers/types/api-types";

export class Users extends ApiClient {
private usersEnpoint = `${ApplicationUrl.GO_REST_API}/${ApiEndpoints.USERS_ENDPOINT}`
private usersEndpoint = `${ApplicationUrl.GO_REST_API}/${ApiEndpoints.USERS_ENDPOINT}`

public async getUsers() {
let response = await this.get(this.usersEnpoint)
let response = await this.get(this.usersEndpoint)
return response;
}

public async getGender(gender: string) {
let response = await this.get(this.usersEnpoint)
let response = await this.get(this.usersEndpoint)
let responseObject = await response?.json()
let genderFilter = responseObject.filter((el: any) => el.gender === gender).length
return genderFilter
Expand All @@ -28,43 +30,43 @@ export class Users extends ApiClient {
let maleUsers = await this.getGender('male');
let femaleUsers = await this.getGender('female');
try {
let differrence = Math.abs(maleUsers - femaleUsers)
let difference = Math.abs(maleUsers - femaleUsers)
if (maleUsers === femaleUsers) {
return;
} else if (maleUsers > femaleUsers) {
for (let i = 0; i < differrence; i++) {
for (let i = 0; i < difference; i++) {
let femaleData = {
id: Randomizer.getRandomNumber(),
name: Randomizer.getRandomFemaleFirstName(),
email: Randomizer.getRandomEmail(),
gender: 'female',
status: 'active',
}
response = await this.post(this.usersEnpoint, { requestData: femaleData, authoriaztionRequired: true })
response = await this.post(this.usersEndpoint, { requestData: femaleData, isAuthorizationRequired: true })
}
} else {
for (let i = 0; i < differrence; i++) {
for (let i = 0; i < difference; i++) {
let maleData = {
id: Randomizer.getRandomNumber(),
name: Randomizer.getRandomMaleFirstName(),
email: Randomizer.getRandomEmail(),
gender: 'male',
status: 'active',
}
response = await this.post(this.usersEnpoint, { requestData: maleData, authoriaztionRequired: true })
response = await this.post(this.usersEndpoint, { requestData: maleData, isAuthorizationRequired: true })
}
}
return response;
} catch (error) {
throw new Error(`an error occured in makeBothGendersEven function: ${error}`)
throw new Error(`an error occurred in makeBothGendersEven function: ${error}`)
}
}

private async getUserStatus(status: string) {
let users = await this.get(this.usersEnpoint)
let users = await this.get(this.usersEndpoint)
let usersJsonObject = await users?.json()
let inactiveUsesrs = usersJsonObject.filter((user: { status: string; }) => user.status === status)
return inactiveUsesrs
let inactiveUsers = usersJsonObject.filter((user: { status: string; }) => user.status === status)
return inactiveUsers
}

public async getInActiveUsers() {
Expand All @@ -76,7 +78,7 @@ export class Users extends ApiClient {
let response: APIResponse | undefined
let inActiveUsers = await this.getInActiveUsers()
for (let user of inActiveUsers) {
response = await this.delete(`${this.usersEnpoint}/${user.id}`, { authoriaztionRequired: true })
response = await this.delete(`${this.usersEndpoint}/${user.id}`, { isAuthorizationRequired: true })
}
return response;
}
Expand All @@ -86,11 +88,18 @@ export class Users extends ApiClient {
* @returns
*/
public async getAllUsers(page: number) {
let response = await this.paginateRequest(RequestMethod.GET, this.usersEnpoint, PaginationType.PAGE_PAGINATION, { paginateRequest: true, pagePagination: true, pageNumber: page })
let response = await this.paginateRequest(
RequestMethod.GET,
this.usersEndpoint,
PaginationType.PAGE_PAGINATION,
{
pageNumber: page
}
)
return response;
}

public async getTypeOfUserProperies() {
public async getTypeOfUserProperties() {
let users = await this.getUsers();
let userObject = await users?.json()
let types: any = [];
Expand Down Expand Up @@ -120,7 +129,7 @@ export class Users extends ApiClient {
if (emailExtension && emailExtension !== 'co.il') {
let newEmail = await email.replace(emailExtension, 'co.il');
let newEmailProperty = { email: newEmail }
response = await this.patch(`${this.usersEnpoint}/${user.id}`, { requestData: newEmailProperty, authoriaztionRequired: true })
response = await this.patch(`${this.usersEndpoint}/${user.id}`, { requestData: newEmailProperty, isAuthorizationRequired: true })
}
}
return response
Expand Down
Loading
Loading