diff --git a/package-lock.json b/package-lock.json index ead6d43..e51f908 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "dependencies": { "@types/mocha": "^10.0.6", "@types/webdriverio": "^5.0.0", + "ajv": "^8.12.0", "appium": "^2.4.1", "dotenv": "^16.3.1", "mocha": "^10.2.0", @@ -709,6 +710,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -719,6 +736,12 @@ "concat-map": "0.0.1" } }, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -2242,13 +2265,13 @@ } }, "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", "dependencies": { "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", "uri-js": "^4.2.2" }, "funding": { @@ -2272,26 +2295,6 @@ } } }, - "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-formats/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/ansi-colors": { "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", @@ -2385,31 +2388,11 @@ "npm": ">=8" } }, - "node_modules/appium/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/appium/node_modules/bluebird": { "version": "3.7.2", "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==" }, - "node_modules/appium/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" - }, "node_modules/appium/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -4208,6 +4191,22 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -4227,6 +4226,12 @@ "node": ">= 4" } }, + "node_modules/eslint/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -4478,7 +4483,8 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -5889,9 +5895,9 @@ "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==" }, "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", diff --git a/package.json b/package.json index 2ea895b..ed1f4a8 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "dependencies": { "@types/mocha": "^10.0.6", "@types/webdriverio": "^5.0.0", + "ajv": "^8.12.0", "appium": "^2.4.1", "dotenv": "^16.3.1", "mocha": "^10.2.0", diff --git a/src/helper/api/apiHelper.ts b/src/helper/api/apiHelper.ts index f6def75..4eb7de5 100644 --- a/src/helper/api/apiHelper.ts +++ b/src/helper/api/apiHelper.ts @@ -68,6 +68,7 @@ export class ApiHelper { try { console.log(`Making GET request to endPoint: ${BASE_URL}${endPoint}`); response = await this.apiContext.get(`${BASE_URL}${endPoint}`); + expect( response.status(), `API : ${BASE_URL}${endPoint} , Expected status : ${statusCode}, Actual status : ${response.status()}` diff --git a/src/helper/web/webHelper.ts b/src/helper/web/webHelper.ts index 6a4ae7c..1bec9e6 100644 --- a/src/helper/web/webHelper.ts +++ b/src/helper/web/webHelper.ts @@ -406,4 +406,6 @@ export class WebHelper { }); }); } + + } diff --git a/src/tests/api/example/api.spec.ts b/src/tests/api/example/api.spec.ts index 1bcb9f3..1fc6bca 100644 --- a/src/tests/api/example/api.spec.ts +++ b/src/tests/api/example/api.spec.ts @@ -1,5 +1,7 @@ -import { expect, test } from "@playwright/test"; +import { expect, test, APIRequestContext } from "@playwright/test"; + import { ApiHelper } from "../../../helper/api/apiHelper"; +import { GeneralPurpose } from "../../../utils/generalPurpose"; let token: string; let bookingId: string; @@ -8,6 +10,7 @@ test.beforeAll(async ({ request }) => { //1. Hit /Auth Api and provide username/password as body //2. fetch token value from JSON response //3. save in token variable + const apiHelper = await new ApiHelper(request); const responseMsg = await apiHelper.invokePostApi("/auth", { username: "admin", @@ -20,15 +23,85 @@ test.beforeAll(async ({ request }) => { console.log(token); }); -test("Get List of booking and verify response", async ({ request }) => { +test("Get booking list and verify response -- No Authentication Required ", async ({ + request, +}) => { /* Test Flow 1. Hit API endpoint 2. Verify API status code - 3. Verify JSON Schema + 3. Verify JSON Response + 4. Verify JSON Schema */ + test.info().annotations.push({ + type: "purpose", + description: + "This will make GET call to https://restful-booker.herokuapp.com/booking with no authentication", + }); const apiHelper = await new ApiHelper(request); // const responseMsg = await apiHelper.invokeGetApi("/booking"); - console.log(responseMsg); + console.log(JSON.stringify(responseMsg)); + for (let index = 0; index < responseMsg.length; index++) { + test.info().annotations.push({ + type: "value", + description: `BookingId : ${responseMsg[index].bookingid}`, + }); + expect(responseMsg[index].bookingid).not.toBeNull(); + } +}); + +test("Get Booking Details using BookingID --> 1914", async ({ request }) => { + /* Test Flow + 1. Hit API endpoint + 2. Verify API status code + 3. Verify JSON Response + 4. Verify JSON Schema + */ + test.info().annotations.push({ + type: "purpose", + description: + "This will make GET call to https://restful-booker.herokuapp.com/booking/:id and verify keys/values in response", + }); + const gs = await new GeneralPurpose(); + const apiHelper = await new ApiHelper(request); // + const bookingDetails = await apiHelper.invokeGetApi("/booking/1914"); + console.log(JSON.stringify(bookingDetails)); + + expect(bookingDetails.firstname).toBe("John"); + expect(bookingDetails.lastname).toBe("Allen"); + expect(bookingDetails.totalprice).toBe(111); + expect(bookingDetails.depositpaid).toBeTruthy(); + expect(gs.isValidDate(bookingDetails.bookingdates.checkin)).toBe(true); + expect(gs.isValidDate(bookingDetails.bookingdates.checkout)).toBe(true); + expect(bookingDetails.additionalneeds).toBe("super bowls"); }); +test("Get booking list, pass to booking/:id API and verify response -- No Authentication Required ", async ({ + request, +}) => { + /* Test Flow + 1. Hit API endpoint + 2. Verify API status code + 3. Verify JSON Response + 4. Verify JSON Schema + */ + test.info().annotations.push({ + type: "purpose", + description: + "This will make GET call to https://restful-booker.herokuapp.com/booking with no authentication", + }); + const apiHelper = await new ApiHelper(request); // + const responseMsg = await apiHelper.invokeGetApi("/booking"); + console.log(JSON.stringify(responseMsg)); + for (let index = 0; index < responseMsg.length; index++) { + test.info().annotations.push({ + type: "value", + description: `BookingId : ${responseMsg[index].bookingid}`, + }); + expect(responseMsg[index].bookingid).not.toBeNull(); + let bookingDetail = await apiHelper.invokeGetApi( + `/booking/${responseMsg[index].bookingid}` + ); + console.log(JSON.stringify(bookingDetail)); + } +}); //API used for writing test code - https://restful-booker.herokuapp.com/apidoc/index.html diff --git a/src/tests/web/orangeHrm.spec.ts b/src/tests/web/orangeHrm.spec.ts new file mode 100644 index 0000000..13e7887 --- /dev/null +++ b/src/tests/web/orangeHrm.spec.ts @@ -0,0 +1,48 @@ +//test 1 -> Login successful - Verify welcome message on Dashboard +//test 2 - Message Invalid credentials +//test 3 -> Error message password can not be empty +//test 4 -> Error message username can not be empty +//test 5 -> Verify Access to HR Administration Panel +//Navigate to HR Administration panel (login as HR admin) +//test 6 -> Verify Employee addition (login as HR admin) +// Navigate to Employee Management section +// Add a new Employee with required details +// Save the employee record +//test 7 -> Verify Employee deletion (login as HR admin) +// Navigate to Employee Management section +//select an existing employee and initiate the deletion process +// confirm the deletion action +//test 8 -> Verify Leave Application Submission (login as Employee) +// Navigate to the leave section +// Apply for leave by providing required details +// submit the leave application +//test 9 -> Verify Leave Approval(login as HR admin) +// Navigate to leave Approval section +// Review pending leave application +// Approve or reject the leave +//test 10 -> Verify Time Tracking Record Creation +//Navigate to Time Tracking module +// Click on Add Time Record button +// Fill the details & Save the record +//test 11 -> Verify Time Tracking Record Deletion +//Navigate to Time Tracking module +// find an existing time tracking record +// Click on delete button +//confirm the deletion +//test 12 -> Validate attendance marking for an employee +//Navigate to attendance module +//Select an employee from the employee list +//Mark attendance for that employee for the current date +//test 13 -> Verify Job posting Creation (login as HR admin) +//Navigate to Recruitment section +//Create a new job posting +//test 14 -> Verify Application Submission(login as job applicant) +//Navigate to career section +//Apply for specific job posting by submitting the application + +//test 15 -> Verify New Employee Onboarding(login as HR admin) +//Navigate to Onboarding section +//Initiate the onboarding process for a newly added employee +//test 16 -> Verify Training Program Creation (login as HR admin) +//Navigate to training section +//create a new training program with all details diff --git a/src/utils/generalPurpose.ts b/src/utils/generalPurpose.ts new file mode 100644 index 0000000..903db38 --- /dev/null +++ b/src/utils/generalPurpose.ts @@ -0,0 +1,9 @@ +export class GeneralPurpose { + async isValidDate(date: string) { + if (Date.parse(date)) { + return true; + } else { + return false; + } + } +}