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.

344 lines (343 loc) 13.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.When_I_type_random = exports.When_I_type_stored = exports.When_I_type = void 0; exports.When_I_check = When_I_check; exports.When_I_uncheck = When_I_uncheck; exports.When_I_check_input = When_I_check_input; exports.When_I_uncheck_input = When_I_uncheck_input; exports.When_I_set_value = When_I_set_value; exports.When_I_clear = When_I_clear; exports.When_I_submit = When_I_submit; exports.When_I_select_option = When_I_select_option; exports.When_I_select_file = When_I_select_file; // e2e/step_definitions/common/actions/inputSteps.ts const cucumber_1 = require("@cucumber/cucumber"); const fakerUtils_1 = require("../helpers/utils/fakerUtils"); // Assuming this path is correct const optionsUtils_1 = require("../helpers/utils/optionsUtils"); // Assuming this path is correct // ============================= // WHEN I CHECK / UNCHECK // ============================= /** * Checks the previously selected element (e.g., a checkbox or radio button). * * ```gherkin * When I check * ``` * * @example * When I find element by label text "Remember me" * And I check * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to a checkbox or radio button. It will mark the element as checked. Optional Playwright * `CheckOptions` can be provided via a data table. */ async function When_I_check(...rest) { if (!this.element) throw new Error("No element selected to check."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseCheckOptions)(maybeTable) : {}; await this.element.check(options); this.log?.("✅ Checked stored element."); } (0, cucumber_1.When)("I check", When_I_check); /** * Unchecks the previously selected element (e.g., a checkbox). * * ```gherkin * When I uncheck * ``` * * @example * When I find element by label text "Agree to terms" * And I uncheck * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to a checkbox. It will mark the element as unchecked. Optional Playwright * `CheckOptions` can be provided via a data table. */ async function When_I_uncheck(...rest) { if (!this.element) throw new Error("No element selected to uncheck."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseCheckOptions)(maybeTable) : {}; await this.element.uncheck(options); this.log?.("✅ Unchecked stored element."); } (0, cucumber_1.When)("I uncheck", When_I_uncheck); /** * Checks a specific input element, requiring a preceding step to select it. * * ```gherkin * When I check input * ``` * * @example * When I find element by selector "input#myCheckbox" * And I check input * * @remarks * This is an alias for "I check". It requires a preceding step that sets the * {@link CustomWorld.element | current element} to an input element (like a checkbox or radio). * Optional Playwright `CheckOptions` can be provided via a data table. */ async function When_I_check_input(...rest) { if (!this.element) throw new Error("No input selected to check."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseCheckOptions)(maybeTable) : {}; await this.element.check(options); this.log?.("✅ Checked stored input."); } (0, cucumber_1.When)("I check input", When_I_check_input); /** * Unchecks a specific input element, requiring a preceding step to select it. * * ```gherkin * When I uncheck input * ``` * * @example * When I find element by selector "input#newsletter" * And I uncheck input * * @remarks * This is an alias for "I uncheck". It requires a preceding step that sets the * {@link CustomWorld.element | current element} to an input element (like a checkbox). * Optional Playwright `CheckOptions` can be provided via a data table. */ async function When_I_uncheck_input(...rest) { if (!this.element) throw new Error("No input selected to uncheck."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseCheckOptions)(maybeTable) : {}; await this.element.uncheck(options); this.log?.("✅ Unchecked stored input."); } (0, cucumber_1.When)("I uncheck input", When_I_uncheck_input); // ============================= // WHEN I TYPE / SET VALUE // ============================= /** * Shared implementation for typing steps. * @internal */ const typeStepImplementation = async function (textOrAlias, ...rest) { if (!this.element) throw new Error("No element selected to type into."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseFillOptions)(maybeTable) : {}; const text = textOrAlias.startsWith("@") ? (this.data[textOrAlias.slice(1)] ?? (() => { throw new Error(`No value found for alias "${textOrAlias}".`); })()) : (0, fakerUtils_1.evaluateFaker)(textOrAlias); // Evaluate faker directly here if it's not an alias // Playwright's fill clears the field by default, but explicitly clearing can be safer // await this.element.fill(""); // This explicit clear might not be necessary depending on Playwright version/behavior await this.element.fill(text, options); this.data.lastTyped = text; // Store the actual text typed for potential later use this.log?.(`⌨️ Typed "${text}" into selected element.`); }; /** * Types the given text into the previously selected element. * * ```gherkin * When I type {string} * ``` * * @example * When I find element by selector "input[name='email']" * And I type "user@example.com" * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to an input field (or any element that supports `fill`). The provided text can be a literal * string or a faker expression (e.g., `{{internet.email}}`). * Optional Playwright `FillOptions` can be provided via a data table. */ exports.When_I_type = typeStepImplementation; (0, cucumber_1.When)("I type {string}", exports.When_I_type); /** * Types the value stored in an alias into the previously selected element. * * ```gherkin * When I type stored {string} * ``` * * @example * Given I store "my.user@example.com" as "userEmail" * When I find element by selector "input[name='email']" * And I type stored "userEmail" * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to an input field. The `string` argument must be an alias (e.g., `userEmail`). * The value associated with this alias in `this.data` will be typed into the element. * Optional Playwright `FillOptions` can be provided via a data table. */ exports.When_I_type_stored = typeStepImplementation; (0, cucumber_1.When)("I type stored {string}", exports.When_I_type_stored); /** * Types a randomly generated value (using Faker.js) into the previously selected element. * * ```gherkin * When I type random {string} * ``` * * @example * When I find element by selector "input[name='username']" * And I type random "internet.userName" * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to an input field. The `string` argument should be a Faker.js path (e.g., `internet.email`, * `person.firstName`). A random value generated by Faker will be typed into the element. * Optional Playwright `FillOptions` can be provided via a data table. */ exports.When_I_type_random = typeStepImplementation; (0, cucumber_1.When)("I type random {string}", exports.When_I_type_random); /** * Sets the value of the previously selected element. * * ```gherkin * When I set value {string} * ``` * * @example * When I find element by selector "input[name='password']" * And I set value "@userPassword" * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to an input field (or any element that supports `fill`). The provided `valueOrAlias` can be * a literal string, an alias (prefixed with `@`), or a Faker expression. This will directly * set the input's value, which is generally faster than typing for non-interactive scenarios. * Optional Playwright `FillOptions` can be provided via a data table. */ async function When_I_set_value(valueOrAlias, ...rest) { if (!this.element) throw new Error("No element selected to set value."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseFillOptions)(maybeTable) : {}; const value = valueOrAlias.startsWith("@") ? (this.data[valueOrAlias.slice(1)] ?? (() => { throw new Error(`No value found for alias "${valueOrAlias}".`); })()) : (0, fakerUtils_1.evaluateFaker)(valueOrAlias); // Evaluate faker directly here if it's not an alias await this.element.fill(value, options); this.data.lastValueSet = value; // Store the actual value set for potential later use this.log?.(`📝 Set value of selected element to "${value}".`); } (0, cucumber_1.When)("I set value {string}", When_I_set_value); /** * Clears the value of the previously selected element. * * ```gherkin * When I clear * ``` * * @example * When I find element by selector "input[name='search']" * And I clear * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to an input field (or any element that supports `fill`). It effectively empties the input field. */ async function When_I_clear() { if (!this.element) throw new Error("No element selected to clear."); await this.element.fill(""); this.log?.("🧼 Cleared value of selected element."); } (0, cucumber_1.When)("I clear", When_I_clear); /** * Submits the form associated with the previously selected element, or the first form on the page. * * ```gherkin * When I submit * ``` * * @example * When I find element by selector "form#loginForm" * And I submit * # OR (submits the first form found if no element is selected) * When I go to "/login" * And I submit * * @remarks * This step will find a form to submit. If {@link CustomWorld.element | this.element} * is a form or an element within a form, that form will be submitted. Otherwise, it will * attempt to submit the first `<form>` element found on the page. * It uses a direct DOM `submit()` call, which bypasses Playwright's default event handling * and can be useful for testing native form submission behavior. */ async function When_I_submit() { // Use the current element if it's a form or within a form, otherwise default to the first form on the page. const formLocator = this.element ? this.element.locator("xpath=ancestor-or-self::form") : this.page.locator("form").first(); if (!(await formLocator.isVisible())) { throw new Error("No visible form found to submit. Ensure an element within a form is selected, or a form exists on the page."); } await formLocator.evaluate((f) => f.submit()); this.log?.("📨 Submitted form."); } (0, cucumber_1.When)("I submit", When_I_submit); /** * Selects an option by its visible text label in a `<select>` element. * * ```gherkin * When I select option {string} * ``` * * @example * When I find element by selector "select[name='role']" * And I select option "Administrator" * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to a `<select>` HTML element. It will then select the option whose visible text matches * the provided `option` string. * Optional Playwright `SelectOptionOptions` can be provided via a data table. */ async function When_I_select_option(option, ...rest) { if (!this.element) throw new Error("No select element stored to select an option."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseSelectOptions)(maybeTable) : {}; await this.element.selectOption({ label: option }, options); this.log?.(`🔽 Selected option "${option}".`); } (0, cucumber_1.When)("I select option {string}", When_I_select_option); /** * Sets the file input of the previously selected element to the specified file path. * * ```gherkin * When I select file {string} * ``` * * @example * When I find element by selector "input[type='file']" * And I select file "path/to/my/document.pdf" * * @remarks * This step requires a preceding step that sets the {@link CustomWorld.element | current element} * to an `input` element of `type="file"`. The `filePath` should be relative to your project's * root or an absolute path. Playwright will automatically handle making the file available * for upload. * Optional Playwright `SetInputFilesOptions` can be provided via a data table. */ async function When_I_select_file(filePath, ...rest) { if (!this.element) throw new Error("No file input selected to set a file."); const maybeTable = rest[0]; const options = maybeTable?.rowsHash ? (0, optionsUtils_1.parseSelectOptions)(maybeTable) : {}; // Note: parseSelectOptions is used here, assuming it returns `SetInputFilesOptions` compatible object or is generic enough. If not, a new parser for SetInputFilesOptions would be ideal. await this.element.setInputFiles(filePath, options); this.log?.(`📁 Set input file to "${filePath}".`); } (0, cucumber_1.When)("I select file {string}", When_I_select_file);