From 1a201454363b5014d2d12c2b8da1bf7e19c03c20 Mon Sep 17 00:00:00 2001 From: Darvin Date: Tue, 17 Sep 2024 17:41:27 +1000 Subject: [PATCH] initial commit --- .env | 10 + .github/workflows/playwright.yml | 27 + .gitignore | 4 + README.md | 57 +++ .../restful-booker.createBooking.test.ts | 31 ++ .../restful-booker.deleteBooking.test.ts | 36 ++ .../restful-booker.getBooking.test.ts | 135 +++++ .../restful-booker.getBookings.test.ts | 33 ++ .../restful-booker.healthcheck.test.ts | 7 + .../restful-booker.partialUpdateBooking.ts | 44 ++ .../restful-booker.updateBooking.test.ts | 50 ++ global-setup.ts | 18 + package-lock.json | 161 ++++++ package.json | 32 ++ playwright.config.ts | 43 ++ test-data/booking.json | 11 + test-data/post-booking.json | 11 + test-data/update-booking.json | 11 + test-result.json | 460 ++++++++++++++++++ tsconfig.json | 21 + 20 files changed, 1202 insertions(+) create mode 100644 .env create mode 100644 .github/workflows/playwright.yml create mode 100644 .gitignore create mode 100644 README.md create mode 100644 apitest/createBooking/restful-booker.createBooking.test.ts create mode 100644 apitest/deleteBooking/restful-booker.deleteBooking.test.ts create mode 100644 apitest/getBooking/restful-booker.getBooking.test.ts create mode 100644 apitest/getBooking/restful-booker.getBookings.test.ts create mode 100644 apitest/smokeTests/restful-booker.healthcheck.test.ts create mode 100644 apitest/updateBooking/restful-booker.partialUpdateBooking.ts create mode 100644 apitest/updateBooking/restful-booker.updateBooking.test.ts create mode 100644 global-setup.ts create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 playwright.config.ts create mode 100644 test-data/booking.json create mode 100644 test-data/post-booking.json create mode 100644 test-data/update-booking.json create mode 100644 test-result.json create mode 100644 tsconfig.json diff --git a/.env b/.env new file mode 100644 index 0000000..fb43fa7 --- /dev/null +++ b/.env @@ -0,0 +1,10 @@ +USERNAME_ADMIN=admin +USER_ADMIN_PASSWORD=password123 +TOKEN= +BOOKING_ID_1= +BOOKING_ID_2= +BOOKING_ID_3= +BOOKING_ID_4= +BOOKING_ID_5= +BOOKING_ID_6= +BOOKING_ID_7= \ No newline at end of file diff --git a/.github/workflows/playwright.yml b/.github/workflows/playwright.yml new file mode 100644 index 0000000..041160c --- /dev/null +++ b/.github/workflows/playwright.yml @@ -0,0 +1,27 @@ +name: Playwright Tests +on: + push: + branches: [ main, master ] + pull_request: + branches: [ main, master ] +jobs: + test: + timeout-minutes: 60 + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - uses: actions/setup-node@v3 + with: + node-version: 16 + - name: Install dependencies + run: npm ci + - name: Install Playwright Browsers + run: npx playwright install --with-deps + - name: Run Playwright tests + run: npx playwright test + - uses: actions/upload-artifact@v3 + if: always() + with: + name: playwright-report + path: playwright-report/ + retention-days: 30 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..75e854d --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +node_modules/ +/test-results/ +/playwright-report/ +/playwright/.cache/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..63b4b00 --- /dev/null +++ b/README.md @@ -0,0 +1,57 @@ +

+ Practice api test automation with Playwright Logo on Restful-booker +

+ +> **Note** +> +> + **Restful-booker** is a public REST API that you can use to learn more about API Testing or try out API testing tools against. Restful-booker is a Create Read Update Delete Web API that comes with authentication features and loaded with a bunch of bugs for you to explore. +> + +## PLaywright features +API testing using: + +- Playwright https://playwright.dev/ +- TypeScript https://www.typescriptlang.org/ + +This tests are purely for Playwright features practice. + + +## Getting Started +### Prerequisites +You need to have Node.js installed on your machine. + +## Useful Commands + +### Run all tests in Playwright + +```shell +npm run test +``` +### Run all tests and show test report +```shell +npm run report +``` +### Run smoke tests +```shell +npm run smoke-tests +``` +### Run api tests for get operation +```shell +npm run test-get +``` +### Run api tests for post operation +```shell +npm run test-post +``` +### Run api tests for put operation +```shell +npm run test-put +``` +### Run api tests for patch operation +```shell +npm run test-patch +``` +### Run api tests for delete operation +```shell +npm run test-delete +``` \ No newline at end of file diff --git a/apitest/createBooking/restful-booker.createBooking.test.ts b/apitest/createBooking/restful-booker.createBooking.test.ts new file mode 100644 index 0000000..c37812b --- /dev/null +++ b/apitest/createBooking/restful-booker.createBooking.test.ts @@ -0,0 +1,31 @@ +import { expect, test } from "playwright/test"; +import bookingData = require("../../test-data/post-booking.json"); + +test("Create Booking", async ({ request, baseURL }) => { + const response = await request.post(`${baseURL}/booking`, { + data: bookingData, + }); + + const responseBody = await response.json(); + process.env.BOOKING_ID_1 = responseBody.bookingid; + + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + expect(responseBody.booking).toHaveProperty( + "firstname", + bookingData.firstname + ); + expect(responseBody.booking).toHaveProperty("lastname", bookingData.lastname); + expect(responseBody.booking).toHaveProperty( + "totalprice", + bookingData.totalprice + ); + expect(responseBody.booking).toHaveProperty( + "depositpaid", + bookingData.depositpaid + ); + expect(responseBody.booking).toHaveProperty( + "additionalneeds", + bookingData.additionalneeds + ); +}); diff --git a/apitest/deleteBooking/restful-booker.deleteBooking.test.ts b/apitest/deleteBooking/restful-booker.deleteBooking.test.ts new file mode 100644 index 0000000..e443a5c --- /dev/null +++ b/apitest/deleteBooking/restful-booker.deleteBooking.test.ts @@ -0,0 +1,36 @@ +import { expect, test } from "playwright/test"; +import bookingData = require("../../test-data/booking.json"); + +test.beforeEach("Create Booking", async ({ request, baseURL }) => { + const response = await request.post(`${baseURL}/booking`, { + data: bookingData, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + + const responseBody = await response.json(); + process.env.BOOKING_ID_2 = responseBody.bookingid; +}); + +test("Delete Booking @delete", async ({ request, baseURL }) => { + let ID = process.env.BOOKING_ID_2; + const url = `${baseURL}/booking/`; + const response2 = await request.get(url + ID, {}); + expect(response2.status()).toBe(200); + + const response = await request.delete(url + ID, { + headers: { + Cookie: `token=${process.env.TOKEN}`, + Accept: "application/json", + }, + }); + + expect(response.ok()).toBeTruthy(); + expect(response.status()).toBe(201); + expect(response.statusText()).toBe("Created"); + + const getUrl = `${baseURL}/booking/`; + const getResponse = await request.get(getUrl + ID, {}); + expect(getResponse.status()).toBe(404); + expect(getResponse.statusText()).toBe("Not Found"); +}); diff --git a/apitest/getBooking/restful-booker.getBooking.test.ts b/apitest/getBooking/restful-booker.getBooking.test.ts new file mode 100644 index 0000000..1ef8620 --- /dev/null +++ b/apitest/getBooking/restful-booker.getBooking.test.ts @@ -0,0 +1,135 @@ +import { expect, test } from "playwright/test"; +import bookingData = require("../../test-data/booking.json"); + +test.beforeEach("Create Booking", async ({ request, baseURL }) => { + const response = await request.post(`${baseURL}/booking`, { + data: bookingData, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + + const responseBody = await response.json(); + process.env.BOOKING_ID_3 = responseBody.bookingid; +}); + +test("Get Booking By Lastname @get", async ({ request, baseURL }) => { + const response = await request.get(`${baseURL}/booking`, { + params: { + lastname: "Brown", + }, + }); + expect(response.ok()).toBeTruthy(); + expect(response.status()).toBe(200); + + let responseAsString = await response.body().then((b) => { + let data = JSON.parse(b.toString()); + return data.filter( + (d: { bookingid: string | undefined }) => + d.bookingid == process.env.BOOKING_ID_3 + ); + }); + + let ID = process.env.BOOKING_ID_3; + const a = ID; + + expect(responseAsString[0] !== undefined).toBe(true); + + if (a) { + expect(responseAsString[0]).toHaveProperty("bookingid", +a); + } +}); + +test("Get Booking By Firstname @get", async ({ request, baseURL }) => { + const response = await request.get(`${baseURL}/booking`, { + params: { + firstname: "Sally", + }, + }); + expect(response.ok()).toBeTruthy(); + expect(response.status()).toBe(200); + + let responseAsString = await response.body().then((b) => { + let data = JSON.parse(b.toString()); + return data.filter( + (d: { bookingid: string | undefined }) => + d.bookingid == process.env.BOOKING_ID_3 + ); + }); + + let ID = process.env.BOOKING_ID_3; + const a = ID; + + expect(responseAsString[0] !== undefined).toBe(true); + + if (a) { + expect(responseAsString[0]).toHaveProperty("bookingid", +a); + } +}); + +test.skip("Get Booking By Checkin Date @get", async ({ request, baseURL }) => { + const response = await request.get(`${baseURL}/booking`, { + params: { + checkin: "2013-02-25", + }, + }); + expect(response.ok()).toBeTruthy(); + expect(response.status()).toBe(200); + + let responseAsString = await response.body().then((b) => { + let data = JSON.parse(b.toString()); + return data.filter( + (d: { bookingid: string | undefined }) => + d.bookingid == process.env.BOOKING_ID_3 + ); + }); + + let ID = process.env.BOOKING_ID_3; + const a = ID; + + expect(responseAsString[0] !== undefined).toBe(true); + + if (responseAsString[0] !== undefined && a) { + expect(responseAsString[0]).toHaveProperty("bookingid", +a); + } +}); + +test("Get Booking By Checkout Date @get", async ({ request, baseURL }) => { + const response = await request.get(`${baseURL}/booking`, { + params: { + checkout: "2014-10-23", + }, + }); + expect(response.ok()).toBeTruthy(); + expect(response.status()).toBe(200); + + let responseAsString = await response.body().then((b) => { + let data = JSON.parse(b.toString()); + return data.filter( + (d: { bookingid: string | undefined }) => + d.bookingid == process.env.BOOKING_ID_3 + ); + }); + + let ID = process.env.BOOKING_ID_3; + const a = ID; + + expect(responseAsString[0] !== undefined).toBe(true); + + if (a) { + expect(responseAsString[0]).toHaveProperty("bookingid", +a); + } +}); + +test("Get Booking By ID @get", async ({ request, baseURL }) => { + let ID = process.env.BOOKING_ID_3; + const url = `${baseURL}/booking/`; + const response = await request.get(url + ID, {}); + const responseBody = await response.json(); + + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + expect(responseBody).toHaveProperty("firstname", bookingData.firstname); + expect(responseBody).toHaveProperty("lastname", bookingData.lastname); + expect(responseBody).toHaveProperty("totalprice", bookingData.totalprice); + expect(responseBody).toHaveProperty("depositpaid", bookingData.depositpaid); +}); diff --git a/apitest/getBooking/restful-booker.getBookings.test.ts b/apitest/getBooking/restful-booker.getBookings.test.ts new file mode 100644 index 0000000..5681803 --- /dev/null +++ b/apitest/getBooking/restful-booker.getBookings.test.ts @@ -0,0 +1,33 @@ +import { expect, test } from "playwright/test"; +import bookingData = require("../../test-data/booking.json"); + +test.beforeEach("Create Booking", async ({ request, baseURL }) => { + const response = await request.post(`${baseURL}/booking`, { + data: bookingData, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + + const responseBody = await response.json(); + process.env.BOOKING_ID_4 = responseBody.bookingid; +}); + +test("Get BookingIds", async ({ request, baseURL }) => { + const response = await request.get(`${baseURL}/booking`); + expect(response.ok()).toBeTruthy(); + expect(response.status()).toBe(200); + + let responseAsString = await response.body().then((b) => { + let data = JSON.parse(b.toString()); + return data.filter( + (d: { bookingid: string | undefined }) => + d.bookingid == process.env.BOOKING_ID_4 + ); + }); + + let ID = process.env.BOOKING_ID_4; + const a = ID; + if (a) { + expect(responseAsString[0]).toHaveProperty("bookingid", +a); + } +}); diff --git a/apitest/smokeTests/restful-booker.healthcheck.test.ts b/apitest/smokeTests/restful-booker.healthcheck.test.ts new file mode 100644 index 0000000..0b0712b --- /dev/null +++ b/apitest/smokeTests/restful-booker.healthcheck.test.ts @@ -0,0 +1,7 @@ +import { expect, test } from "playwright/test"; + +test("@smoke - Service HealthCheck", async ({ request, baseURL }) => { + const response = await request.get(`${baseURL}/ping`); + expect(response.status()).toBe(201); + expect(response.ok()).toBeTruthy(); +}); diff --git a/apitest/updateBooking/restful-booker.partialUpdateBooking.ts b/apitest/updateBooking/restful-booker.partialUpdateBooking.ts new file mode 100644 index 0000000..5e936dc --- /dev/null +++ b/apitest/updateBooking/restful-booker.partialUpdateBooking.ts @@ -0,0 +1,44 @@ +import { expect, test } from "playwright/test"; +import bookingData = require("../../test-data/update-booking.json"); + +test.beforeEach("Create Booking", async ({ request, baseURL }) => { + const response = await request.post(`${baseURL}/booking`, { + data: bookingData, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + + const responseBody = await response.json(); + process.env.BOOKING_ID_5 = responseBody.bookingid; +}); + +test("Update Booking Partially - Udpate firstname and lastname @patch", async ({ request, baseURL }) => { + let ID = process.env.BOOKING_ID_5; + const url = `${baseURL}/booking/`; + const response2 = await request.get(url + ID, {}); + expect(response2.status()).toBe(200); + + const response = await request.put(url + ID, { + headers: { + Cookie: `token=${process.env.TOKEN}`, + Accept: "application/json", + }, + data: { + firstname: "James", + lastname: "Brown", + }, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + const responseBody = await response.json(); + + console.log(responseBody); + expect(responseBody).toHaveProperty("firstname", "James"); + expect(responseBody).toHaveProperty("lastname", "Brown"); + expect(responseBody).toHaveProperty("totalprice", bookingData.totalprice); + expect(responseBody).toHaveProperty("depositpaid", bookingData.depositpaid); + expect(responseBody).toHaveProperty( + "additionalneeds", + bookingData.additionalneeds + ); +}); diff --git a/apitest/updateBooking/restful-booker.updateBooking.test.ts b/apitest/updateBooking/restful-booker.updateBooking.test.ts new file mode 100644 index 0000000..5185dac --- /dev/null +++ b/apitest/updateBooking/restful-booker.updateBooking.test.ts @@ -0,0 +1,50 @@ +import { expect, test } from "playwright/test"; +import bookingData = require("../../test-data/update-booking.json"); + +test.beforeEach("Create Booking", async ({ request, baseURL }) => { + const response = await request.post(`${baseURL}/booking`, { + data: bookingData, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + + const responseBody = await response.json(); + process.env.BOOKING_ID_5 = responseBody.bookingid; +}); + +test("Update Booking @put", async ({ request, baseURL }) => { + let ID = process.env.BOOKING_ID_5; + const url = `${baseURL}/booking/`; + const response2 = await request.get(url + ID, {}); + expect(response2.status()).toBe(200); + + const response = await request.put(url + ID, { + headers: { + Cookie: `token=${process.env.TOKEN}`, + Accept: "*/*", + }, + data: bookingData, + }); + expect(response.status()).toBe(200); + expect(response.ok()).toBeTruthy(); + const responseBody = await response.json(); + + console.log(responseBody); + expect(responseBody).toHaveProperty( + "firstname", + bookingData.firstname + ); + expect(responseBody).toHaveProperty("lastname", bookingData.lastname); + expect(responseBody).toHaveProperty( + "totalprice", + bookingData.totalprice + ); + expect(responseBody).toHaveProperty( + "depositpaid", + bookingData.depositpaid + ); + expect(responseBody).toHaveProperty( + "additionalneeds", + bookingData.additionalneeds + ); +}); diff --git a/global-setup.ts b/global-setup.ts new file mode 100644 index 0000000..90f97da --- /dev/null +++ b/global-setup.ts @@ -0,0 +1,18 @@ +import { PlaywrightTestConfig, request } from "@playwright/test"; + +async function globalSetup(config: PlaywrightTestConfig) { + const url = "https://restful-booker.herokuapp.com/auth"; + + const requestContext = await request.newContext(); + const response = await requestContext.post(`${url}`, { + data: { + username: `${process.env.USERNAME_ADMIN}`, + password: `${process.env.USER_ADMIN_PASSWORD}`, + }, + }); + + const body = await response.json(); + process.env.TOKEN = body.token; +} + +export default globalSetup; diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..6feeeed --- /dev/null +++ b/package-lock.json @@ -0,0 +1,161 @@ +{ + "name": "playwright-ts-api-testing", + "version": "1.0.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "playwright-ts-api-testing", + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "dotenv": "^16.3.1" + }, + "devDependencies": { + "@playwright/test": "^1.39.0", + "@types/node": "^20.16.5" + } + }, + "node_modules/@playwright/test": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", + "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "dev": true, + "dependencies": { + "playwright": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@types/node": { + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~6.19.2" + } + }, + "node_modules/dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/motdotla/dotenv?sponsor=1" + } + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/playwright": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", + "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "dev": true, + "dependencies": { + "playwright-core": "1.39.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", + "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true, + "license": "MIT" + } + }, + "dependencies": { + "@playwright/test": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.39.0.tgz", + "integrity": "sha512-3u1iFqgzl7zr004bGPYiN/5EZpRUSFddQBra8Rqll5N0/vfpqlP9I9EXqAoGacuAbX6c9Ulg/Cjqglp5VkK6UQ==", + "dev": true, + "requires": { + "playwright": "1.39.0" + } + }, + "@types/node": { + "version": "20.16.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.5.tgz", + "integrity": "sha512-VwYCweNo3ERajwy0IUlqqcyZ8/A7Zwa9ZP3MnENWcB11AejO+tLy3pu850goUW2FC/IJMdZUfKpX/yxL1gymCA==", + "dev": true, + "requires": { + "undici-types": "~6.19.2" + } + }, + "dotenv": { + "version": "16.3.1", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.1.tgz", + "integrity": "sha512-IPzF4w4/Rd94bA9imS68tZBaYyBWSCE47V1RGuMrB94iyTOIEwRmVL2x/4An+6mETpLrKJ5hQkB8W4kFAadeIQ==" + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "playwright": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.39.0.tgz", + "integrity": "sha512-naE5QT11uC/Oiq0BwZ50gDmy8c8WLPRTEWuSSFVG2egBka/1qMoSqYQcROMT9zLwJ86oPofcTH2jBY/5wWOgIw==", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.39.0" + } + }, + "playwright-core": { + "version": "1.39.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.39.0.tgz", + "integrity": "sha512-+k4pdZgs1qiM+OUkSjx96YiKsXsmb59evFoqv8SKO067qBA+Z2s/dCzJij/ZhdQcs2zlTAgRKfeiiLm8PQ2qvw==", + "dev": true + }, + "undici-types": { + "version": "6.19.8", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", + "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..f6c5d83 --- /dev/null +++ b/package.json @@ -0,0 +1,32 @@ +{ + "name": "playwright-ts-api-testing", + "version": "1.0.0", + "description": "This repository will include practice project for api tests with the usage of Playwright & TS.", + "main": "index.js", + "scripts": { + "report": "npx playwright test --reporter=html && npx playwright show-report", + "debug": "npx playwright test --debug", + "test": "npx playwright test", + "smoke-tests": "npx playwright test --grep @smoke", + "test-get": "npx playwright test --grep @get", + "test-post": "npx playwright test --grep @post", + "test-delete": "npx playwright test --grep @delete", + "test-put": "npx playwright test --grep @put", + "test-patch": "npx playwright test --grep @patch" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/darvinpatel/playwright-demo-api" + }, + "keywords": [], + "author": "", + "license": "ISC", + "homepage": "https://github.com/monikakonieczna/playwright-js-api-testing#readme", + "devDependencies": { + "@playwright/test": "^1.39.0", + "@types/node": "^20.16.5" + }, + "dependencies": { + "dotenv": "^16.3.1" + } +} diff --git a/playwright.config.ts b/playwright.config.ts new file mode 100644 index 0000000..d0176a7 --- /dev/null +++ b/playwright.config.ts @@ -0,0 +1,43 @@ +import { devices, PlaywrightTestConfig } from "@playwright/test"; +require('dotenv').config({path: '.env'}); + + +const config: PlaywrightTestConfig = { + use: { + viewport: null, + headless: !true, + screenshot: "on", + video: "on", + // trace: "on", + baseURL: "https://restful-booker.herokuapp.com", + extraHTTPHeaders: { + "Authorization": "Basic YWRtaW46cGFzc3dvcmQxMjM=" + } + // contextOptions: { + // permissions: ["clipboard-read"] + // } + , + launchOptions: { + args: ["--start-maximized"], + + // logger: { + // // isEnabled: (name, severity) => true, + // // log: (name, severity, message, args) => console.log(name, severity) + // } + } + }, + // timeout: 60000, + // grep: [new RegExp("@smoke"), new RegExp("@reg")], + // testMatch: ["harDemo/trackRequest.test.ts"], + retries: 0, + // reporter: "./customReport/myReporter.ts" + reporter: [ + ["dot"], // -> console + ["json", { outputFile: "test-result.json" }], // -> JSON + ['html', { + open: "always" + }] + ], + globalSetup: require.resolve('./global-setup') +} +export default config; \ No newline at end of file diff --git a/test-data/booking.json b/test-data/booking.json new file mode 100644 index 0000000..cbb3261 --- /dev/null +++ b/test-data/booking.json @@ -0,0 +1,11 @@ +{ + "firstname": "Sally", + "lastname": "Brown", + "totalprice": 111, + "depositpaid": true, + "bookingdates": { + "checkin": "2013-02-23", + "checkout": "2014-10-23" + }, + "additionalneeds": "Breakfast" +} \ No newline at end of file diff --git a/test-data/post-booking.json b/test-data/post-booking.json new file mode 100644 index 0000000..e71b89a --- /dev/null +++ b/test-data/post-booking.json @@ -0,0 +1,11 @@ +{ + "firstname": "Monika", + "lastname": "Klak", + "totalprice": 98, + "depositpaid": true, + "bookingdates": { + "checkin": "2023-10-10", + "checkout": "2023-10-15" + }, + "additionalneeds": "Breakfast" +} \ No newline at end of file diff --git a/test-data/update-booking.json b/test-data/update-booking.json new file mode 100644 index 0000000..cb96f6a --- /dev/null +++ b/test-data/update-booking.json @@ -0,0 +1,11 @@ +{ + "firstname": "Krystian", + "lastname": "Wafel", + "totalprice": 22, + "depositpaid": true, + "bookingdates": { + "checkin": "2023-10-18", + "checkout": "2023-10-25" + }, + "additionalneeds": "Towels" +} \ No newline at end of file diff --git a/test-result.json b/test-result.json new file mode 100644 index 0000000..a1c96b1 --- /dev/null +++ b/test-result.json @@ -0,0 +1,460 @@ +{ + "config": { + "configFile": "/Users/darwinpatel/Desktop/PortFoliosSourcecode/playwright-demo-api/playwright.config.ts", + "rootDir": "/Users/darwinpatel/Desktop/PortFoliosSourcecode/playwright-demo-api", + "forbidOnly": false, + "fullyParallel": false, + "globalSetup": "/Users/darwinpatel/Desktop/PortFoliosSourcecode/playwright-demo-api/global-setup.ts", + "globalTeardown": null, + "globalTimeout": 0, + "grep": {}, + "grepInvert": null, + "maxFailures": 0, + "metadata": { + "actualWorkers": 4 + }, + "preserveOutput": "always", + "reporter": [ + [ + "dot", + null + ], + [ + "json", + { + "outputFile": "test-result.json" + } + ], + [ + "html", + { + "open": "always" + } + ] + ], + "reportSlowTests": { + "max": 5, + "threshold": 15000 + }, + "quiet": false, + "projects": [ + { + "outputDir": "/Users/darwinpatel/Desktop/PortFoliosSourcecode/playwright-demo-api/test-results", + "repeatEach": 1, + "retries": 0, + "id": "", + "name": "", + "testDir": "/Users/darwinpatel/Desktop/PortFoliosSourcecode/playwright-demo-api", + "testIgnore": [], + "testMatch": [ + "**/*.@(spec|test).?(c|m)[jt]s?(x)" + ], + "timeout": 30000 + } + ], + "shard": null, + "updateSnapshots": "missing", + "version": "1.39.0", + "workers": 4, + "webServer": null + }, + "suites": [ + { + "title": "apitest/createBooking/restful-booker.createBooking.test.ts", + "file": "apitest/createBooking/restful-booker.createBooking.test.ts", + "column": 0, + "line": 0, + "specs": [ + { + "title": "Create Booking", + "ok": true, + "tags": [], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 0, + "status": "passed", + "duration": 1018, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:49.124Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "3770cac8e7c4e09a5bd2-2ba7347b3565c41227b7", + "file": "apitest/createBooking/restful-booker.createBooking.test.ts", + "line": 4, + "column": 5 + } + ] + }, + { + "title": "apitest/deleteBooking/restful-booker.deleteBooking.test.ts", + "file": "apitest/deleteBooking/restful-booker.deleteBooking.test.ts", + "column": 0, + "line": 0, + "specs": [ + { + "title": "Delete Booking @delete", + "ok": true, + "tags": [ + "delete" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 1, + "status": "passed", + "duration": 3717, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:49.123Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "743742a913ab42b99cec-fb1f2ba8288cd72871f8", + "file": "apitest/deleteBooking/restful-booker.deleteBooking.test.ts", + "line": 15, + "column": 5 + } + ] + }, + { + "title": "apitest/getBooking/restful-booker.getBooking.test.ts", + "file": "apitest/getBooking/restful-booker.getBooking.test.ts", + "column": 0, + "line": 0, + "specs": [ + { + "title": "Get Booking By Lastname @get", + "ok": true, + "tags": [ + "get" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 2, + "status": "passed", + "duration": 1926, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:49.126Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "c420f95386d17f6059ad-8f1fa40f990171bd51da", + "file": "apitest/getBooking/restful-booker.getBooking.test.ts", + "line": 15, + "column": 5 + }, + { + "title": "Get Booking By Firstname @get", + "ok": true, + "tags": [ + "get" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 2, + "status": "passed", + "duration": 1835, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:51.054Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "c420f95386d17f6059ad-689565ee04999abe5ac9", + "file": "apitest/getBooking/restful-booker.getBooking.test.ts", + "line": 42, + "column": 5 + }, + { + "title": "Get Booking By Checkin Date @get", + "ok": true, + "tags": [ + "get" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [ + { + "type": "skip" + } + ], + "expectedStatus": "skipped", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 2, + "status": "skipped", + "duration": 0, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:52.890Z", + "attachments": [] + } + ], + "status": "skipped" + } + ], + "id": "c420f95386d17f6059ad-d2e7d8a369f5118cdb8c", + "file": "apitest/getBooking/restful-booker.getBooking.test.ts", + "line": 69, + "column": 6 + }, + { + "title": "Get Booking By Checkout Date @get", + "ok": true, + "tags": [ + "get" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 2, + "status": "passed", + "duration": 2014, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:52.891Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "c420f95386d17f6059ad-d3e3a9f32e1b47dcf384", + "file": "apitest/getBooking/restful-booker.getBooking.test.ts", + "line": 96, + "column": 5 + }, + { + "title": "Get Booking By ID @get", + "ok": true, + "tags": [ + "get" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 2, + "status": "passed", + "duration": 2141, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:54.906Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "c420f95386d17f6059ad-399aee7919fd9622b2c0", + "file": "apitest/getBooking/restful-booker.getBooking.test.ts", + "line": 123, + "column": 5 + } + ] + }, + { + "title": "apitest/getBooking/restful-booker.getBookings.test.ts", + "file": "apitest/getBooking/restful-booker.getBookings.test.ts", + "column": 0, + "line": 0, + "specs": [ + { + "title": "Get BookingIds", + "ok": true, + "tags": [], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 3, + "status": "passed", + "duration": 2345, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:49.128Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "0272691100a6ce1a40f0-4f67501706f2cd0826ba", + "file": "apitest/getBooking/restful-booker.getBookings.test.ts", + "line": 15, + "column": 5 + } + ] + }, + { + "title": "apitest/smokeTests/restful-booker.healthcheck.test.ts", + "file": "apitest/smokeTests/restful-booker.healthcheck.test.ts", + "column": 0, + "line": 0, + "specs": [ + { + "title": "@smoke - Service HealthCheck", + "ok": true, + "tags": [ + "smoke" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 0, + "status": "passed", + "duration": 902, + "errors": [], + "stdout": [], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:50.145Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "ab74f74f813e12ecc3a8-52746abcc46dfabcb69e", + "file": "apitest/smokeTests/restful-booker.healthcheck.test.ts", + "line": 3, + "column": 5 + } + ] + }, + { + "title": "apitest/updateBooking/restful-booker.updateBooking.test.ts", + "file": "apitest/updateBooking/restful-booker.updateBooking.test.ts", + "column": 0, + "line": 0, + "specs": [ + { + "title": "Update Booking @put", + "ok": true, + "tags": [ + "put" + ], + "tests": [ + { + "timeout": 30000, + "annotations": [], + "expectedStatus": "passed", + "projectId": "", + "projectName": "", + "results": [ + { + "workerIndex": 0, + "status": "passed", + "duration": 2837, + "errors": [], + "stdout": [ + { + "text": "{\n firstname: \u001b[32m'Krystian'\u001b[39m,\n lastname: \u001b[32m'Wafel'\u001b[39m,\n totalprice: \u001b[33m22\u001b[39m,\n depositpaid: \u001b[33mtrue\u001b[39m,\n bookingdates: { checkin: \u001b[32m'2023-10-18'\u001b[39m, checkout: \u001b[32m'2023-10-25'\u001b[39m },\n additionalneeds: \u001b[32m'Towels'\u001b[39m\n}\n" + } + ], + "stderr": [], + "retry": 0, + "startTime": "2024-09-17T07:38:51.053Z", + "attachments": [] + } + ], + "status": "expected" + } + ], + "id": "03dbe4d146e0f4491156-0508c8f1f5ddd58e23ff", + "file": "apitest/updateBooking/restful-booker.updateBooking.test.ts", + "line": 15, + "column": 5 + } + ] + } + ], + "errors": [], + "stats": { + "startTime": "2024-09-17T07:38:47.809Z", + "duration": 9244.223 + } +} \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..9605bde --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "es6", + "strict": true, + "module": "commonjs", + "sourceMap": true, + "resolveJsonModule": true, + "baseUrl": ".", + "paths": { + "@pages/*": [ + "pom/letcodemodules/credentials/*" + ], + "@fixtures/*": [ + "fixtures/*" + ], + "@files/*": [ + "uploadFolder/*" + ] + } + } +} \ No newline at end of file