UNPKG

playwright-cucumber-ts-steps

Version:

A collection of reusable Playwright step definitions for Cucumber in TypeScript, designed to streamline end-to-end testing across web, API, and mobile applications.

594 lines (593 loc) 25.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.Then_I_should_see_response_status = Then_I_should_see_response_status; exports.Then_I_see_response_status_is_not = Then_I_see_response_status_is_not; exports.Then_I_should_see_response_body_contains = Then_I_should_see_response_body_contains; exports.Then_I_see_response_body = Then_I_see_response_body; exports.Then_I_see_response_body_does_not_contain = Then_I_see_response_body_does_not_contain; exports.Then_I_see_response_body_is_empty = Then_I_see_response_body_is_empty; exports.Then_I_see_response_body_is_not_empty = Then_I_see_response_body_is_not_empty; exports.Then_I_see_response_body_is_JSON = Then_I_see_response_body_is_JSON; exports.Then_I_see_response_body_is_not_JSON = Then_I_see_response_body_is_not_JSON; exports.Then_I_see_response_body_matches_JSON_schema_path = Then_I_see_response_body_matches_JSON_schema_path; exports.Then_I_see_response_body_matches_JSON_schema_object = Then_I_see_response_body_matches_JSON_schema_object; exports.Then_I_see_response_header_equals = Then_I_see_response_header_equals; exports.Then_I_see_response_header_contains = Then_I_see_response_header_contains; exports.Then_I_see_response_header_does_not_contain = Then_I_see_response_header_does_not_contain; exports.Then_I_see_response_header_does_not_equal = Then_I_see_response_header_does_not_equal; exports.Then_I_see_response_header_exists = Then_I_see_response_header_exists; exports.Then_I_see_response_header_does_not_exist = Then_I_see_response_header_does_not_exist; const cucumber_1 = require("@cucumber/cucumber"); const test_1 = require("@playwright/test"); // Helper to ensure lastResponse is available and correctly typed function getValidatedLastResponse(world) { const response = world.data.lastResponse; if (!response) { throw new Error("No API response available in 'this.data.lastResponse'. Make sure a request step was executed."); } // Ensure the structure matches our expected LastResponse interface if (typeof response.status !== "number" || typeof response.body !== "string" || typeof response.headers !== "object") { throw new Error("Invalid 'lastResponse' structure. Expected properties: status (number), body (string), headers (object)."); } return response; } // =================================================================================== // ASSERTIONS: API RESPONSE STATUS // =================================================================================== /** * Asserts that the status code of the last API response matches the expected number. * * ```gherkin * Then I should see response status {int} * ``` * * @param expectedStatus - The expected HTTP status code (e.g., 200, 404). * * @example * When I make request to "https://api.example.com/data" * Then I should see response status 200 * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It uses `expect().toBe()` for robust assertion. * @category API Response Assertion Steps */ function Then_I_should_see_response_status(expectedStatus) { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.status).toBe(expectedStatus); this.log?.(`✅ Verified response status is ${expectedStatus}.`); } (0, cucumber_1.Then)("I should see response status {int}", Then_I_should_see_response_status); /** * Asserts that the status code of the last API response does NOT match the given number. * * ```gherkin * Then I see response status is not {int} * ``` * * @param unexpectedStatus - The HTTP status code that is NOT expected. * * @example * When I make request to "https://api.example.com/data" * Then I see response status is not 404 * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It uses `expect().not.toBe()` for robust assertion. * @category API Response Assertion Steps */ function Then_I_see_response_status_is_not(unexpectedStatus) { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.status).not.toBe(unexpectedStatus); this.log?.(`✅ Verified response status is NOT ${unexpectedStatus}.`); } (0, cucumber_1.Then)("I see response status is not {int}", Then_I_see_response_status_is_not); // =================================================================================== // ASSERTIONS: API RESPONSE BODY // =================================================================================== /** * Asserts that the body of the last API response contains the expected text substring. * * ```gherkin * Then I should see response body contains {string} * ``` * * @param expectedText - The substring expected to be present in the response body. * * @example * When I make request to "https://api.example.com/users" * Then I should see response body contains "John Doe" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It uses `expect().toContain()` for robust assertion. * @category API Response Assertion Steps */ function Then_I_should_see_response_body_contains(expectedText) { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.body).toContain(expectedText); this.log?.(`✅ Verified response body contains "${expectedText}".`); } // Note: You had two steps "I should see response body contains" and "I see response body contains". // I've consolidated them to this single export function and will link both When patterns to it. (0, cucumber_1.Then)("I should see response body contains {string}", Then_I_should_see_response_body_contains); (0, cucumber_1.Then)("I see response body contains {string}", Then_I_should_see_response_body_contains); /** * Asserts that the body of the last API response strictly matches the expected string. * * ```gherkin * Then I see response body {string} * ``` * * @param expectedBody - The exact string expected to be the response body. * * @example * When I make request to "https://api.example.com/status" * Then I see response body "OK" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It performs a strict equality check on the entire response body string. * @category API Response Assertion Steps */ function Then_I_see_response_body(expectedBody) { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.body).toBe(expectedBody); this.log?.(`✅ Verified response body is exactly "${expectedBody}".`); } // Note: You had "I see response body {string}" and "I see response body matches {string}". // I've consolidated them to this single export function and will link both Then patterns to it. (0, cucumber_1.Then)("I see response body {string}", Then_I_see_response_body); (0, cucumber_1.Then)("I see response body matches {string}", Then_I_see_response_body); /** * Asserts that the body of the last API response does NOT contain the given substring. * * ```gherkin * Then I see response body does not contain {string} * ``` * * @param unexpectedPart - The substring expected NOT to be present in the response body. * * @example * When I make request to "https://api.example.com/error" * Then I see response body does not contain "internal server error" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It checks for the absence of the substring within the response body. * @category API Response Assertion Steps */ function Then_I_see_response_body_does_not_contain(unexpectedPart) { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.body).not.toContain(unexpectedPart); this.log?.(`✅ Verified response body does NOT contain "${unexpectedPart}".`); } (0, cucumber_1.Then)("I see response body does not contain {string}", Then_I_see_response_body_does_not_contain); /** * Asserts that the body of the last API response is empty (contains only whitespace or is empty). * * ```gherkin * Then I see response body is empty * ``` * * @example * When I make request to "https://api.example.com/no-content" * Then I see response body is empty * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It trims whitespace and checks if the resulting string is empty. * @category API Response Assertion Steps */ function Then_I_see_response_body_is_empty() { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.body.trim()).toBe(""); this.log?.(`✅ Verified response body is empty.`); } (0, cucumber_1.Then)("I see response body is empty", Then_I_see_response_body_is_empty); /** * Asserts that the body of the last API response is NOT empty (contains non-whitespace characters). * * ```gherkin * Then I see response body is not empty * ``` * * @example * When I make request to "https://api.example.com/data" * Then I see response body is not empty * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It trims whitespace and checks if the resulting string is not empty. * @category API Response Assertion Steps */ function Then_I_see_response_body_is_not_empty() { const res = getValidatedLastResponse(this); (0, test_1.expect)(res.body.trim()).not.toBe(""); this.log?.(`✅ Verified response body is not empty.`); } (0, cucumber_1.Then)("I see response body is not empty", Then_I_see_response_body_is_not_empty); /** * Asserts that the body of the last API response is valid JSON. * * ```gherkin * Then I see response body is JSON * ``` * * @example * When I make request to "https://api.example.com/json-data" * Then I see response body is JSON * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It attempts to parse the response body as JSON. If parsing fails, the step fails. * @category API Response Assertion Steps */ function Then_I_see_response_body_is_JSON() { const res = getValidatedLastResponse(this); try { JSON.parse(res.body); this.log?.(`✅ Verified response body is valid JSON.`); } catch (e) { const message = e instanceof Error ? e.message : String(e); throw new Error(`Response body is not valid JSON: ${message}`); } } (0, cucumber_1.Then)("I see response body is JSON", Then_I_see_response_body_is_JSON); /** * Asserts that the body of the last API response is NOT valid JSON. * * ```gherkin * Then I see response body is not JSON * ``` * * @example * When I make request to "https://api.example.com/plain-text" * Then I see response body is not JSON * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It attempts to parse the response body as JSON and expects the parsing to fail. * @category API Response Assertion Steps */ function Then_I_see_response_body_is_not_JSON() { const res = getValidatedLastResponse(this); let isJson = true; try { JSON.parse(res.body); } catch (e) { isJson = false; e instanceof Error ? e.message : String(e); } if (isJson) { throw new Error(`Expected response body to not be JSON, but it is.`); } this.log?.(`✅ Verified response body is NOT JSON.`); } (0, cucumber_1.Then)("I see response body is not JSON", Then_I_see_response_body_is_not_JSON); /** * Asserts that the body of the last API response matches the given JSON schema. * * ```gherkin * Then I see response body matches JSON schema {string} * ``` * * @param schemaPath - The path to the JSON schema file (e.g., "schemas/responseSchema.js"). * * @example * When I make request to "https://api.example.com/users/1" * Then I see response body matches JSON schema "schemas/userSchema.js" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It dynamically imports the schema file and uses `ajv` to validate the JSON response body. * Ensure `ajv` is installed (`npm install ajv`) and your schema files are accessible. * @category API Response Assertion Steps */ async function Then_I_see_response_body_matches_JSON_schema_path(schemaPath) { const res = getValidatedLastResponse(this); const body = res.body; // Body is already a string from getValidatedLastResponse // Dynamically import Ajv and the schema const AjvModule = await Promise.resolve().then(() => __importStar(require("ajv"))); const Ajv = AjvModule.default || AjvModule; // Handle potential default export differences const ajv = new Ajv(); // Dynamically import the schema, handling both CommonJS and ES Module exports let schema; try { const schemaModule = await Promise.resolve(`${schemaPath}`).then(s => __importStar(require(s))); schema = schemaModule.default || schemaModule; } catch (error) { throw new Error(`Failed to load JSON schema from "${schemaPath}": ${error.message}`); } const validate = ajv.compile(schema); let parsedBody; try { parsedBody = JSON.parse(body); } catch (e) { throw new Error(`Response body is not valid JSON and cannot be validated against schema: ${e.message}`); } const valid = validate(parsedBody); if (!valid) { throw new Error(`Response body does not match schema: ${ajv.errorsText(validate.errors)}`); } this.log?.(`✅ Verified response body matches JSON schema from "${schemaPath}".`); } (0, cucumber_1.Then)("I see response body matches JSON schema {string}", Then_I_see_response_body_matches_JSON_schema_path); /** * Asserts that the body of the last API response matches the given JSON schema object directly provided in the step. * * ```gherkin * Then I see response body matches JSON schema: * """ * { "type": "object", "properties": { "id": { "type": "number" } } } * """ * ``` * * @param schema - The JSON schema object (provided as a Cucumber DocString). * * @example * When I make request to "https://api.example.com/users/latest" * Then I see response body matches JSON schema: * """ * { * "type": "object", * "properties": { * "id": { "type": "number" }, * "name": { "type": "string" } * }, * "required": ["id", "name"] * } * """ * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It expects the schema as a direct JSON string (DocString) in the Gherkin step. * Uses `ajv` to validate the JSON response body against this inline schema. * Ensure `ajv` is installed (`npm install ajv`). * @category API Response Assertion Steps */ async function Then_I_see_response_body_matches_JSON_schema_object(schemaString) { const res = getValidatedLastResponse(this); const body = res.body; const AjvModule = await Promise.resolve().then(() => __importStar(require("ajv"))); const Ajv = AjvModule.default || AjvModule; const ajv = new Ajv(); let schema; try { schema = JSON.parse(schemaString); } catch (e) { throw new Error(`Failed to parse inline JSON schema: ${e.message}. Ensure it is valid JSON.`); } const validate = ajv.compile(schema); let parsedBody; try { parsedBody = JSON.parse(body); } catch (e) { throw new Error(`Response body is not valid JSON and cannot be validated against inline schema: ${e.message}`); } const valid = validate(parsedBody); if (!valid) { throw new Error(`Response body does not match inline schema: ${ajv.errorsText(validate.errors)}`); } this.log?.(`✅ Verified response body matches inline JSON schema.`); } (0, cucumber_1.Then)("I see response body matches JSON schema", Then_I_see_response_body_matches_JSON_schema_object); // =================================================================================== // ASSERTIONS: API RESPONSE HEADERS // =================================================================================== /** * Asserts that a specific header in the last API response strictly equals an expected value. * * ```gherkin * Then I see response header {string} equals {string} * ``` * * @param headerName - The name of the header (case-insensitive, e.g., "Content-Type"). * @param expectedValue - The exact expected value of the header. * * @example * When I make request to "https://api.example.com/data" * Then I see response header "content-type" equals "application/json" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It retrieves the header value and performs a strict equality check. * @category API Response Assertion Steps */ function Then_I_see_response_header_equals(headerName, expectedValue) { const res = getValidatedLastResponse(this); const headerValue = res.headers[headerName.toLowerCase()]; // Access from plain object (0, test_1.expect)(headerValue, `Expected header "${headerName}" to be "${expectedValue}", but got "${headerValue}".`).toBe(expectedValue); this.log?.(`✅ Verified response header "${headerName}" equals "${expectedValue}".`); } (0, cucumber_1.Then)("I see response header {string} equals {string}", Then_I_see_response_header_equals); /** * Asserts that a specific header in the last API response contains a given substring. * * ```gherkin * Then I see response header {string} contains {string} * ``` * * @param headerName - The name of the header (case-insensitive, e.g., "Set-Cookie"). * @param expectedPart - The substring expected to be contained within the header's value. * * @example * When I make request to "https://api.example.com/login" * Then I see response header "set-cookie" contains "session_id" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It retrieves the header value and checks if it includes the `expectedPart`. * @category API Response Assertion Steps */ function Then_I_see_response_header_contains(headerName, expectedPart) { const res = getValidatedLastResponse(this); const headerValue = res.headers[headerName.toLowerCase()]; // Access from plain object (0, test_1.expect)(headerValue, `Header "${headerName}" not found or is empty. Expected to contain "${expectedPart}".`).toBeDefined(); // Ensure header exists before checking content (0, test_1.expect)(headerValue, `Expected header "${headerName}" to contain "${expectedPart}", but got "${headerValue}".`).toContain(expectedPart); this.log?.(`✅ Verified response header "${headerName}" contains "${expectedPart}".`); } (0, cucumber_1.Then)("I see response header {string} contains {string}", Then_I_see_response_header_contains); /** * Asserts that a specific header in the last API response does NOT contain a given substring. * * ```gherkin * Then I see response header {string} does not contain {string} * ``` * * @param headerName - The name of the header (case-insensitive). * @param unexpectedPart - The substring expected NOT to be present within the header's value. * * @example * When I make request to "https://api.example.com/no-cache" * Then I see response header "cache-control" does not contain "no-store" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It retrieves the header value and asserts that it does not include the `unexpectedPart`. * @category API Response Assertion Steps */ function Then_I_see_response_header_does_not_contain(headerName, unexpectedPart) { const res = getValidatedLastResponse(this); const headerValue = res.headers[headerName.toLowerCase()]; // Access from plain object if (headerValue !== undefined) { // Only check if header exists (0, test_1.expect)(headerValue, `Expected header "${headerName}" to NOT contain "${unexpectedPart}", but it does.`).not.toContain(unexpectedPart); } this.log?.(`✅ Verified response header "${headerName}" does NOT contain "${unexpectedPart}".`); } (0, cucumber_1.Then)("I see response header {string} does not contain {string}", Then_I_see_response_header_does_not_contain); /** * Asserts that a specific header in the last API response does NOT strictly equal a given value. * * ```gherkin * Then I see response header {string} does not equal {string} * ``` * * @param headerName - The name of the header (case-insensitive). * @param unexpectedValue - The value that is NOT expected for the header. * * @example * When I make request to "https://api.example.com/html-page" * Then I see response header "content-type" does not equal "application/json" * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It retrieves the header value and asserts that it does not strictly match `unexpectedValue`. * @category API Response Assertion Steps */ function Then_I_see_response_header_does_not_equal(headerName, unexpectedValue) { const res = getValidatedLastResponse(this); const headerValue = res.headers[headerName.toLowerCase()]; // Access from plain object (0, test_1.expect)(headerValue, `Expected header "${headerName}" to NOT be "${unexpectedValue}", but it is.`).not.toBe(unexpectedValue); this.log?.(`✅ Verified response header "${headerName}" does NOT equal "${unexpectedValue}".`); } (0, cucumber_1.Then)("I see response header {string} does not equal {string}", Then_I_see_response_header_does_not_equal); /** * Asserts that a specific header in the last API response exists (is present). * * ```gherkin * Then I see response header {string} exists * ``` * * @param headerName - The name of the header expected to exist. * * @example * When I make request to "https://api.example.com/data" * Then I see response header "content-length" exists * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It checks if the header value is defined (not `undefined` or `null`). * @category API Response Assertion Steps */ function Then_I_see_response_header_exists(headerName) { const res = getValidatedLastResponse(this); const headerValue = res.headers[headerName.toLowerCase()]; // Access from plain object (0, test_1.expect)(headerValue, `Header "${headerName}" should exist but was not found.`).toBeDefined(); this.log?.(`✅ Verified response header "${headerName}" exists.`); } (0, cucumber_1.Then)("I see response header {string} exists", Then_I_see_response_header_exists); /** * Asserts that a specific header in the last API response does NOT exist (is not present). * * ```gherkin * Then I see response header {string} does not exist * ``` * * @param headerName - The name of the header expected NOT to exist. * * @example * When I make request to "https://api.example.com/simple" * Then I see response header "x-powered-by" does not exist * * @remarks * This step requires a preceding step that stores the API response in * {@link CustomWorld.data.lastResponse | this.data.lastResponse}. * It checks if the header value is `undefined` or `null`. * @category API Response Assertion Steps */ function Then_I_see_response_header_does_not_exist(headerName) { const res = getValidatedLastResponse(this); const headerValue = res.headers[headerName.toLowerCase()]; // Access from plain object (0, test_1.expect)(headerValue, `Header "${headerName}" should NOT exist but was found.`).toBeUndefined(); this.log?.(`✅ Verified response header "${headerName}" does NOT exist.`); } (0, cucumber_1.Then)("I see response header {string} does not exist", Then_I_see_response_header_does_not_exist);