Although the cucumber tests indicate success, protractor fails to interact with the elements on the webpage

Recently, I delved into the realm of Protractor+Cucumber+Typescript and devised a sample framework utilizing Page Object Design along with a small script to execute some click actions. URL:

My endeavor to click on the "Customer Login" button seems futile as it fails to interact with the element while Cucumber still displays the test as passed.

I attempted to leverage async/await for promise handling but unfortunately without success. Protractor Version: 5.4.2 TypeScript Version: 3.3.4000 Node Version: v10.15.3 NPM version: 6.4.1

Feature File:
Feature: Authentication at XYZ bank

@OutlineScenario
Scenario: Customer Access

Given I navigate to XYZ Bank's homepage
Then I initiate the Customer Login process
Then I specify the Customer Name
Then I proceed with the login action

Page Object:

    import { element, by } from "protractor";
    import { Select } from "../utilities/selectClass";
  export class loginPage {

        //elements

        customerLoginButton = element(by.cssContainingText('.btn btn-primary btn-lg', 'Customer Login'));
        loginButton = element(by.className('btn btn-default'));
        yourNameDropDown = element(by.model('custId'));
        bankManagerLoginButton = element(by.xpath("//button[contains(text(),'Bank Manager Login')]"));
        homeButton = element(by.className('btn home'));

        //function to trigger Customer Login
        customerLogin() {
            this.customerLoginButton.click();
        }

        //function to choose a Name from the Dropdown
        selectName() {
            const select: Select = new Select(this.yourNameDropDown);
            select.selectByVisibleText("Harry Potter");
        }

        //function to execute the Login action
        clickLogin() {
            this.loginButton.click();
        }

        //function to activate Bank Manager Login
        bankManagerLogin() {
            this.bankManagerLoginButton.click();
        }

        clickHome() {
            this.homeButton.click();
        }
    }

StepDefinition:

import {loginPage} from "../pages/loginPage";
import {addCustomer} from "../pages/addCustomer";
import { browser } from "protractor";
import { Then, Given } from "cucumber";
const chai = require("chai").use(require("chai-as-promised"));
const expect = chai.expect;
const login: loginPage = new loginPage();
const addcustomer: addCustomer = new addCustomer();

Given('I navigate to XYZ Bank\'s homepage', function() {
    expect(browser.getTitle()).to.eventually.equal("Protractor practice website - Banking App");
   });

Then(/^I initiate the Customer Login process$/, function() {
   login.customerLogin();
  });

  Then('I specify the Customer Name', function() {
   login.selectName();
 });

 Then('I proceed with the login action', function () {
   login.clickLogin();
 });

config.ts

import { browser, Config } from "protractor";
import { Reporter } from "../utilities/reporter";
const jsonReports = process.cwd() + "/reports/json";

export const config: Config = {
    seleniumAddress: "http://127.0.0.1:4444/wd/hub",

    SELENIUM_PROMISE_MANAGER: false,

    baseUrl: "http://www.way2automation.com/angularjs-protractor/banking/#/login",

    capabilities: {
        browserName: "chrome",
    },

    framework: "custom",
    frameworkPath: require.resolve("protractor-cucumber-framework"),

    specs: [
        "../../features/*.feature",
    ],

    onPrepare: () => {
        browser.ignoreSynchronization = true;
        browser.manage().window().maximize();
        Reporter.createDirectory(jsonReports);
    },

    cucumberOpts: {
        compiler: "ts:ts-node/register",
        format: "json:./reports/json/cucumber_report.json",
        require: ["../../typeScript/stepdefinitions/*.js", "../../typeScript/utilities/*.js"],
        strict: true,
        tags: "@CucumberScenario or @ProtractorScenario or @TypeScriptScenario or @OutlineScenario",
    },

    onComplete: () => {
        Reporter.createHTMLReport();
    },
}

Answer №1

If you are utilizing the Control Flow in webdriver (as opposed to async/await), it is necessary to ensure that you return the last line of each step, even when using expects that involve eventually. For instance, if login.customerLogin() returns a promise that remains unresolved, you must use return login.customerLogin() so Cucumber can handle its resolution.

On a related note, we have observed that transitioning to async/await instead of control flow has significantly alleviated the challenges associated with writing tests in protractor. It is remarkable how many times a simple omission of returning a single step or assertion resulted in false positives or obscure errors.

Answer №2

When working with Protractor, it's important to remember that its functions run asynchronously. This means you need to wait for the promises to be resolved before moving on. One way to do this is by using the then function. If you're looking for a guide on promises, check out this resource.

Another approach to handling promises in Protractor is through the use of async/await. This method is recommended as it makes your code more readable. Simply make all your step definition functions async and call Protractor functions with await, which will pause execution until the promise is resolved. Your 'customer login' function and step should look something like this:

async customerLogin() {
    await this.customerLoginButton.click();
}

Then(/^I click Customer Login$/, async function() {
    await login.customerLogin();
}

If you opt for async/await, there's no need to use chai-as-promised because using await on an async function returns the value similarly to how chai's eventually works. This effectively waits for a promise to resolve. Therefore, replace your current 'I am on XYZ Bank home page' step with the following:

expect(await browser.getTitle()).to.equal("Title");

For further reading, here are some useful sources:

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error in Directive: NgControl Provider Not Found

I encountered an issue with my Directive while attempting to inject 'NgControl' and received a 'No provider for NgControl' error. Here is the structure of my File Directory: app folder |--directives folder |--myDirec ...

Error in Compiling HTML Elements Collection<<Element>

Currently, I am developing an eCommerce application that features a popup window for users when they click on "Add to Cart." This popup allows users to select product variations and quantities before adding the item to their cart. The popup consists of a s ...

Unable to retrieve text from the list

I am facing an issue while trying to retrieve the text content, as it is unexpectedly returning empty. The text I am trying to fetch belongs to a readonly field named theater, followed by a list of 28 numbers. Despite attempting various methods such as get ...

Access values of keys in an array of objects using TypeScript during array initialization

In my TypeScript code, I am initializing an array of objects. I need to retrieve the id parameter of a specific object that I am initializing. vacancies: Array<Vacancy> = [{ id: 1, is_fav: this.favouritesService.favourites.find(fav = ...

Removing API request in React.js

My approach: deleteSample = () => { this.sampleService .deleteCall(this.props.id) .then((response) => { window.location.reload(false); }) .catch((error) => { console.log ...

Use Vue 2 with TypeScript to prevent directly changing Props in a class-based component using vue-property-decorator

Is there a way to declare a Prop using vue-property-decorator in a class-based component without the need to initialize it? Currently, I'm facing a dilemma: If I don't provide an initializer, TypeScript throws an error during compilation: ...

Encountering a Typescript error while trying to implement a custom palette color with the Chip component in Material-UI

I have created a unique theme where I included my own custom colors in the palette. I was expecting the color prop to work with a custom color. I tested it with the Button component and it performed as expected. However, when I attempted the same with the ...

Material UI TreeView: Organize and present node data with multiple columns in a tree structure

const treeItems = [ { id: 1, name: 'English', country: 'US', children: [ { id: 4, name: 'Spring', country: 'Uk', ...

What could be the reason for the component not receiving data from the service?

After attempting to send data from one component to another using a service, I followed the guidance provided in this answer. Unfortunately, the data is not being received by the receiver component. I also explored the solution suggested in this question. ...

Tips on optimizing data processing for quicker display with ngFor

I am currently facing an issue with loading a JSON file containing 3500 data. The data appears very slowly on the view, causing the application to work sluggishly. Below is a snippet of the JSON: export class Service { private items = new Arr ...

Inactive function

I have a function that inserts my articles and I call this function on my page. There are no errors, but the next function retrieveAllArticles() is not being executed. public saveAllArticles(article) { for(let data in article) { this.db.exec ...

Unlocking the power of variables in Next.js inline sass styles

Is there a way to utilize SASS variables in inline styles? export default function (): JSX.Element { return ( <MainLayout title={title} robots={false}> <nav> <a href="href">Title</a> ...

Utilize a single component across various instances for enhanced efficiency

After thorough research, I couldn't find a solution to my problem despite similar questions being asked. I've developed an angular component for styled radio buttons and need to use it multiple times on different instances. To get a better unde ...

Populating datasets with relative indexing

I am working on a code where I need to fill the datasets with the property isProjected set to 1. There are 3 datasets - lower estimate, projected, and upper estimate. The goal is to fill the Lower Estimate and Upper Estimate with a background color of rgba ...

How is it possible for TypeScript to enable the importing of dependencies that it ultimately cannot utilize during runtime?

Take a look at my sample project by following this link: https://github.com/DanKaplanSES/typescript-stub-examples/tree/JavaScript-import-invalid I have developed a file named main.ts: import uuid from "uuid"; console.log(uuid.v4()); While type ...

Exploring URL Parameters in Angular Unit Testing

My goal is to execute a test to check for the presence of a specific string in URL parameters. Inside my TypeScript file, I have defined the following method: checkURLParams() { if (this.route.parent) { this.route.parent.params.subscribe((params) ...

Discover the best method for retrieving or accessing data from an array using Angular

In my data processing task, I have two sets of information. The first set serves as the header data, providing the names of the columns to be displayed. The second set is the actual data source itself. My challenge lies in selecting only the data from th ...

Angular 2 GET request returns a 404 error

I have been attempting to reproduce the ngPrime datatable demo from this Github repository. Currently, I am working with the most recent version of Angular (4) and using angular-cli in development mode. Placing a JSON file into my app folder where the serv ...

typescriptExtract generic type from TypedDocumentNode<MyType, unknown> using introspection

I am currently utilizing a library that allows me to retrieve the type from a returned variable within a function. const myVar = gql(somestring) // The library function is called gql type myVarType = typeof myVar // The resultant value of myVarType is Typ ...

The useEffect hook in React is signaling a missing dependency issue

Any tips on how to resolve warnings such as this one src\components\pages\badge\BadgeScreen.tsx Line 87:6: React Hook useEffect has a missing dependency: 'loadData'. Either include it or remove the dependency array react-hoo ...