diff --git a/infra/api/apiClient/ApiClient.ts b/infra/api/apiClient/ApiClient.ts index a75e91c..5f6e320 100644 --- a/infra/api/apiClient/ApiClient.ts +++ b/infra/api/apiClient/ApiClient.ts @@ -1,7 +1,5 @@ import { APIRequestContext, APIResponse } from '@playwright/test'; -import { ApiOptionalParams, PaginationType, IRequestOptions } from '../helpers/types/api-types'; -import { RequestMethod } from '../helpers/types/api-request-types'; - +import { ApiOptionalParams, PaginationType, RequestMethod } from '@api-helpers'; export class ApiClient { constructor(public request: APIRequestContext) { diff --git a/infra/api/apiClient/index.ts b/infra/api/apiClient/index.ts new file mode 100644 index 0000000..24ecdf5 --- /dev/null +++ b/infra/api/apiClient/index.ts @@ -0,0 +1 @@ +export * from './ApiClient'; \ No newline at end of file diff --git a/infra/api/endpoints/ApiEndpoints.ts b/infra/api/endpoints/ApiEndpoints.ts index 28e09d1..6edd51e 100644 --- a/infra/api/endpoints/ApiEndpoints.ts +++ b/infra/api/endpoints/ApiEndpoints.ts @@ -1,12 +1,11 @@ export enum ApiEndpoints { - //======================================== - //--------PET STORE endpoints------------- + // PET STORE endpoints PET = 'pet', UPLOAD_IMAGE = 'uploadImage', - //======================================= - //-----------POKEMON endpoints------------ + + // POKEMON endpoints POKEMON = 'pokemon', - //======================================= - //-----------GO REST API endpoints------- + + // GO REST API endpoints USERS_ENDPOINT = 'users', } \ No newline at end of file diff --git a/infra/api/endpoints/index.ts b/infra/api/endpoints/index.ts new file mode 100644 index 0000000..df6a038 --- /dev/null +++ b/infra/api/endpoints/index.ts @@ -0,0 +1 @@ +export * from './ApiEndpoints'; \ No newline at end of file diff --git a/infra/api/entities/index.ts b/infra/api/entities/index.ts new file mode 100644 index 0000000..5a509c2 --- /dev/null +++ b/infra/api/entities/index.ts @@ -0,0 +1,3 @@ +export * from './users-api/Users'; +export * from './petStore/PetStore'; +export * from './pokemon/PokemonApi'; \ No newline at end of file diff --git a/infra/api/entities/petStore/PetStoreCrudActions.ts b/infra/api/entities/petStore/PetStore.ts similarity index 80% rename from infra/api/entities/petStore/PetStoreCrudActions.ts rename to infra/api/entities/petStore/PetStore.ts index 8d69746..74bfa0b 100644 --- a/infra/api/entities/petStore/PetStoreCrudActions.ts +++ b/infra/api/entities/petStore/PetStore.ts @@ -1,12 +1,11 @@ -import { APIRequestContext, APIResponse } from "@playwright/test"; -import { ApiClient } from "../../apiClient/ApiClient"; -import { ApiEndpoints } from "../../endpoints/ApiEndpoints"; -import { ApplicationUrl } from "../../helpers/urls/ApplicationUrl"; +import { APIResponse } from "@playwright/test"; +import { ApiClient } from "@api-client"; +import { ApiEndpoints } from "@api-endpoints"; +import { ApplicationUrl } from "@api-helpers"; import path from "path"; -import Randomizer from "../../helpers/faker/Randomizer"; import fs from 'fs' -export class PetStoreCrudActions extends ApiClient { +export class PetStoreApi extends ApiClient { private petStorePetEndpoint = `${ApplicationUrl.PET_STORE_URL}/${ApiEndpoints.PET}` @@ -17,7 +16,7 @@ export class PetStoreCrudActions extends ApiClient { public async createNewPet(petData: { [key: string]: T }) { let response = await this.post(this.petStorePetEndpoint, { requestData: petData }) - return response; + return response; } /** diff --git a/infra/api/entities/pokemon/PokemonApi.ts b/infra/api/entities/pokemon/PokemonApi.ts index 7dc0db7..b720628 100644 --- a/infra/api/entities/pokemon/PokemonApi.ts +++ b/infra/api/entities/pokemon/PokemonApi.ts @@ -1,8 +1,7 @@ -import { ApiClient } from "../../apiClient/ApiClient"; -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"; +import { ApiClient } from "@api-client"; +import { ApplicationUrl } from "@api-helpers"; +import { ApiEndpoints } from "@api-endpoints"; +import { RequestMethod, PaginationType } from "@api-helpers"; export class PokemonApi extends ApiClient { private POKEMON_BASE_URL = ApplicationUrl.POKEMON_URL; diff --git a/infra/api/entities/gorestapi/Users.ts b/infra/api/entities/users-api/Users.ts similarity index 87% rename from infra/api/entities/gorestapi/Users.ts rename to infra/api/entities/users-api/Users.ts index a63d4a6..250587f 100644 --- a/infra/api/entities/gorestapi/Users.ts +++ b/infra/api/entities/users-api/Users.ts @@ -1,10 +1,7 @@ import { APIResponse } from "@playwright/test"; -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"; +import { ApiClient } from "@api-client"; +import MockDataGenerator, { ApplicationUrl, RequestMethod, PaginationType } from "@api-helpers"; +import { ApiEndpoints } from "@api-endpoints"; export class Users extends ApiClient { private usersEndpoint = `${ApplicationUrl.GO_REST_API}/${ApiEndpoints.USERS_ENDPOINT}` @@ -36,9 +33,9 @@ export class Users extends ApiClient { } else if (maleUsers > femaleUsers) { for (let i = 0; i < difference; i++) { let femaleData = { - id: Randomizer.getRandomNumber(), - name: Randomizer.getRandomFemaleFirstName(), - email: Randomizer.getRandomEmail(), + id: MockDataGenerator.getRandomNumber(), + name: MockDataGenerator.getRandomFemaleFirstName(), + email: MockDataGenerator.getRandomEmail(), gender: 'female', status: 'active', } @@ -47,9 +44,9 @@ export class Users extends ApiClient { } else { for (let i = 0; i < difference; i++) { let maleData = { - id: Randomizer.getRandomNumber(), - name: Randomizer.getRandomMaleFirstName(), - email: Randomizer.getRandomEmail(), + id: MockDataGenerator.getRandomNumber(), + name: MockDataGenerator.getRandomMaleFirstName(), + email: MockDataGenerator.getRandomEmail(), gender: 'male', status: 'active', } diff --git a/infra/api/helpers/index.ts b/infra/api/helpers/index.ts new file mode 100644 index 0000000..4ea5c0f --- /dev/null +++ b/infra/api/helpers/index.ts @@ -0,0 +1,5 @@ +export { default } from './mocks/mocks'; +export * from './urls/ApplicationUrl'; +export * from './types/api-request-types'; +export * from './types/api-types'; +export * from './test-tags/test-tags'; \ No newline at end of file diff --git a/infra/api/helpers/faker/Randomizer.ts b/infra/api/helpers/mocks/mocks.ts similarity index 90% rename from infra/api/helpers/faker/Randomizer.ts rename to infra/api/helpers/mocks/mocks.ts index 7f32e93..87f378a 100644 --- a/infra/api/helpers/faker/Randomizer.ts +++ b/infra/api/helpers/mocks/mocks.ts @@ -1,6 +1,6 @@ -import { fa, faker } from "@faker-js/faker"; +import { faker } from "@faker-js/faker"; -export default class Randomizer { +export default class MockDataGenerator { public static getDogNameBreed(): string { return faker.animal.dog() diff --git a/infra/api/helpers/test-tags/test-tags.ts b/infra/api/helpers/test-tags/test-tags.ts new file mode 100644 index 0000000..3716f4f --- /dev/null +++ b/infra/api/helpers/test-tags/test-tags.ts @@ -0,0 +1,5 @@ +export enum TestTags { + GO_REST_API = '@GoRestApi', + PET_STORE = '@PetStore', + POKEMON_API = '@PokemonApi', +} \ No newline at end of file diff --git a/infra/api/helpers/types/api-types.ts b/infra/api/helpers/types/api-types.ts index 111c634..27444f4 100644 --- a/infra/api/helpers/types/api-types.ts +++ b/infra/api/helpers/types/api-types.ts @@ -1,4 +1,4 @@ -export interface Ipet { +export interface IPet { id?: number, category?: { [key: string]: any }, name: string, diff --git a/tests/api_tests/goRestApi/GoRestApiTests.spec.ts b/tests/api_tests/goRestApi/GoRestApiTests.spec.ts index 02bff35..68d6e2b 100644 --- a/tests/api_tests/goRestApi/GoRestApiTests.spec.ts +++ b/tests/api_tests/goRestApi/GoRestApiTests.spec.ts @@ -1,7 +1,6 @@ -import { test, request, expect } from '@playwright/test' -import { IUser } from '../../../infra/api/helpers/types/api-types'; -import { Users } from '../../../infra/api/entities/gorestapi/Users'; -import { StatusCode } from '../../../infra/api/helpers/types/api-request-types'; +import { test, expect } from '@playwright/test' +import { Users } from '@api-entities'; +import { StatusCode, TestTags } from '@api-helpers'; test.describe('Api tests for GoRestApi endpoints', async () => { let users: Users; @@ -11,7 +10,7 @@ test.describe('Api tests for GoRestApi endpoints', async () => { users = new Users(request); }) - test('sanity check', { tag: ['@GO_REST_API'] }, async () => { + test('sanity check', { tag: [TestTags.GO_REST_API] }, async () => { await test.step('get users endpoint - validate status, body type of obejct properties and default length of the response', async () => { let response = await users.getUsers(); expect(response?.status()).toBe(StatusCode.OK) @@ -25,7 +24,7 @@ test.describe('Api tests for GoRestApi endpoints', async () => { /** * @description there is a bug with this endpoint - it does not authorize any generated toke=n whatsoever */ - test('gender equality', { tag: ['@GO_REST_API'] }, async () => { + test('gender equality', { tag: [TestTags.GO_REST_API] }, async () => { await test.step('make an api request to make both male and female genders equal', async () => { await users.makeBothGendersEven(); let maleGender = await users.getGender('male') @@ -34,7 +33,7 @@ test.describe('Api tests for GoRestApi endpoints', async () => { }) }) - test('replace email extension of users', { tag: ['@GO_REST_API'] }, async () => { + test('replace email extension of users', { tag: [TestTags.GO_REST_API] }, async () => { await test.step('extract extension of each user email and replace each extension with co.il', async () => { let response = await users.replaceEmailExtensionForUsers() expect(response?.status()).toBe(StatusCode.OK) @@ -46,7 +45,7 @@ test.describe('Api tests for GoRestApi endpoints', async () => { }) }) - test('delete inactive users', { tag: ['@GO_REST_API'] }, async () => { + test('delete inactive users', { tag: [TestTags.GO_REST_API] }, async () => { await test.step('make a request to delete all users that have an inactive status', async () => { let response = await users.deleteInactiveUsers() expect(response?.status()).toBe(StatusCode.UNAUTHORIZED) diff --git a/tests/api_tests/petStore/PetStoreCrudTests.spec.ts b/tests/api_tests/petStore/PetStoreCrudTests.spec.ts index c687e51..ad6ea39 100644 --- a/tests/api_tests/petStore/PetStoreCrudTests.spec.ts +++ b/tests/api_tests/petStore/PetStoreCrudTests.spec.ts @@ -1,24 +1,21 @@ import { expect, test } from '@playwright/test' -import { PetStoreCrudActions } from '../../../infra/api/entities/petStore/PetStoreCrudActions' -import { STATUS_CODES } from 'http'; -import { Ipet } from '../../../infra/api/helpers/types/api-types'; -import Randomizer from '../../../infra/api/helpers/faker/Randomizer'; -import { StatusCode } from '../../../infra/api/helpers/types/api-request-types'; +import { PetStoreApi } from '@api-entities' +import MockDataGenerator, { IPet, StatusCode } from '@api-helpers'; test.describe.serial('CRUD API tests for the Pet Store API', async () => { - let petStoreCrudActions: PetStoreCrudActions; + let petStoreCrudActions: PetStoreApi; let id: number = 10; let petId: number = 3193; test.beforeEach(async ({ request }) => { - petStoreCrudActions = new PetStoreCrudActions(request) + petStoreCrudActions = new PetStoreApi(request) }) test('get a specific pet for sanity checkup', { tag: ['@PET_STORE_API'] }, async () => { await test.step('make an api request to a specific pet ID', async () => { let response = await petStoreCrudActions.getPet(id) - let responseJson: Ipet = await response?.json() + let responseJson: IPet = await response?.json() expect(response?.status()).toBe(StatusCode.OK) expect(responseJson.name).toBe('doggie') }) @@ -29,21 +26,21 @@ test.describe.serial('CRUD API tests for the Pet Store API', async () => { let petData = { id: petId, category: { - id: Randomizer.getRandomLongNumber(), - name: Randomizer.getRandomName() + id: MockDataGenerator.getRandomLongNumber(), + name: MockDataGenerator.getRandomName() }, name: 'Pikachu', photoUrls: ['https://ibb.co/wLWCrSX'], tags: [ { - id: Randomizer.getRandomLongNumber(), - name: Randomizer.getRandomName(), + id: MockDataGenerator.getRandomLongNumber(), + name: MockDataGenerator.getRandomName(), } ], status: 'available' } let response = await petStoreCrudActions.createNewPet(petData) - let responseBody: Ipet = await response?.json(); + let responseBody: IPet = await response?.json(); expect(response?.status()).toBe(StatusCode.OK); expect(responseBody).toEqual(petData); expect(response?.statusText()).toBe('OK'); @@ -53,7 +50,7 @@ test.describe.serial('CRUD API tests for the Pet Store API', async () => { test('validate the pet existance', { tag: ['@PET_STORE_API'] }, async () => { await test.step('validate the pet that was created from previous test now exists', async () => { let response = await petStoreCrudActions.getPet(petId) - let responseBody: Ipet = await response?.json(); + let responseBody: IPet = await response?.json(); expect(response).toBeTruthy() expect(response?.status()).toBe(StatusCode.OK) expect(responseBody.id).toEqual(petId) @@ -74,21 +71,21 @@ test.describe.serial('CRUD API tests for the Pet Store API', async () => { let petData = { id: petId, category: { - id: Randomizer.getRandomLongNumber(), - name: Randomizer.getRandomName() + id: MockDataGenerator.getRandomLongNumber(), + name: MockDataGenerator.getRandomName() }, name: 'Pokey', photoUrls: ['https://ibb.co/0Z9v02Z'], tags: [ { - id: Randomizer.getRandomLongNumber(), - name: Randomizer.getRandomName(), + id: MockDataGenerator.getRandomLongNumber(), + name: MockDataGenerator.getRandomName(), } ], status: 'available' } let response = await petStoreCrudActions.updatePet(petData) - let responseBody: Ipet = await response?.json(); + let responseBody: IPet = await response?.json(); expect(response?.status()).toBe(StatusCode.OK) expect(responseBody.name).toEqual('Pokey'); }) diff --git a/tests/api_tests/pokemon/PokemonApiTests.spec.ts b/tests/api_tests/pokemon/PokemonApiTests.spec.ts index f262a4a..f6bf867 100644 --- a/tests/api_tests/pokemon/PokemonApiTests.spec.ts +++ b/tests/api_tests/pokemon/PokemonApiTests.spec.ts @@ -1,6 +1,7 @@ -import { expect, test } from '@playwright/test' -import { PokemonApi } from '../../../infra/api/entities/pokemon/PokemonApi' -import { StatusCode } from '../../../infra/api/helpers/types/api-request-types'; +import { expect, test } from '@playwright/test'; +import { PokemonApi } from '@api-entities'; +import { StatusCode } from '@api-helpers'; +import { TestTags } from '@api-helpers'; test.describe('Pokemon API CRUD tests', async () => { let pokemonApi: PokemonApi @@ -11,7 +12,7 @@ test.describe('Pokemon API CRUD tests', async () => { pokemonApi = new PokemonApi(request); }) - test('GET the pokemon resources', { tag: ['@POKEMON_API'] }, async () => { + test('GET the pokemon resources', { tag: [TestTags.POKEMON_API] }, async () => { await test.step('GET first 20 pokemon resources by default and validate initial response', async () => { let res = await pokemonApi.getPokemon(); let jsonResponse = await res?.json() @@ -26,7 +27,7 @@ test.describe('Pokemon API CRUD tests', async () => { }) }) - test('get all pokemon resources', { tag: ['@POKEMON_API'] }, async () => { + test('get all pokemon resources', { tag: [TestTags.POKEMON_API] }, async () => { await test.step('get all pokemon recourses via limit and offset pagination', async () => { let response = await pokemonApi.getAllPokemonRecourses(limit, offset) let responseLength = response?.length @@ -35,7 +36,7 @@ test.describe('Pokemon API CRUD tests', async () => { }) - test('response keys type validation', { tag: ['@POKEMON_API'] }, async () => { + test('response keys type validation', { tag: [TestTags.POKEMON_API] }, async () => { await test.step('validate that each key in the results response object are equals to strings', async () => { let res = await pokemonApi.getPokemon() let resJson = await res?.json() diff --git a/tsconfig.json b/tsconfig.json index e075f97..0affc28 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,8 +28,13 @@ "module": "commonjs", /* Specify what module code is generated. */ // "rootDir": "./", /* Specify the root folder within your source files. */ // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ - // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ - // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + "paths": { + "@api-client": ["infra/api/apiClient/index"], + "@api-endpoints": ["infra/api/endpoints/index"], + "@api-entities": ["infra/api/entities/index"], + "@api-helpers": ["infra/api/helpers/index"], + }, /* Specify a set of entries that re-map imports to additional lookup locations. */ // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ // "types": [], /* Specify type package names to be included without being referenced in a source file. */