What is the best way to set a value for a variable that is asynchronous by design?

I'm currently working on an Appium automation framework that is typescript based. The element locator strategy used in this framework is async due to the nature of the plugin I am using, which requires the use of await. However, I encountered some errors when trying to access the settings_button value in the methods.

Visual code indicates that findElementByText should return a promise with the following signature: (method) AppiumDriver.findElementByText(text: string, match?: SearchOptions, waitForElement?: number): Promise

export class HomeScreen extends BasePage {

settings_button = this._driver.findElementByText('Settings',10);

async isDisplayedSettings(){
    await (await this.settings_button).isDisplayed();
}

async openSettings(){
    await (await this.settings_button).click();

}

}

This setup is utilized within the mocha test framework as shown below.

describe("Firmware Update", () => {

let scanDevices: ScanDevices, genFunc: GenericFunctions, settings: SettingsScreen, homeScreen: HomeScreen;

const defaultWaitTime = 5000;
let driver: AppiumDriver;

before(async () => {
    driver = await createDriver();
    scanDevices = new ScanDevices(driver);
    homeScreen = new HomeScreen(driver);
    settings = new SettingsScreen(driver);
    genFunc = new GenericFunctions();
    await genFunc.timeDelay(10000); //Delay for the headset scan
    await scanDevices.clickHeadset();
});

after(async () => {
    await driver.quit();
    console.log("Quit driver!");
});


afterEach(async function () {
    if (this.currentTest.state === "failed") {
        await driver.logScreenshot(this.currentTest.title);
    }
});

it("should display settings option", async () => {
    assert.isTrue(await homeScreen.isDisplayedSettings(),"Option should be displayed");

});

it("should tap settings option", async () => {
    await homeScreen.openSettings();
    assert.isTrue(await settings.isDisplayeUpdatebutton(),"Expecting Settings screen to open");    

});

Answer №1

After analyzing your feedback, it appears that the warning is triggered by the promise associated with the settings_button variable.

The issue arises when an instance of HomeScreen is created but no methods are called on that instance. This means that any potential error in the settings_button promise will go unnoticed, which is considered a critical error by the nodejs team. Unfortunately, there is no way to guarantee that one of these methods will be invoked in the future within the constructor.

In your scenario, the settings_button promise always resolves before the isDisplayedSettings method is executed due to the delay in the before block.

To address this issue, you have two options for restructuring the code:

  • Update the initialization method to await the element query. Since async constructors are not supported, you will need to use an async factory instead. This approach is suggested for resolving the problem.
  • Delay the element query until it is first utilized. While functionally similar to your current implementation, this method helps prevent unhandled errors when no methods are called.

Outlined below are the proposed solutions in pseudocode:

Solution 1:

export class HomeScreen extends BasePage {
    settings_button : UIElement? = null;
    async init() {
        settings_button = await this._driver.findElementByText('Settings', 10);
    }
    static async create(driver) {
        const result = new HomeScreen(driver);
        await result.init();
        return result;
    }

    // ...
}

// ...

before(async() => {
    // ...
    homeScreen = await HomeScreen.create(driver);
    // ...
});

Solution 2:

export class HomeScreen extends BasePage {
    _settingsButtonPromise : Promise<UIElement>? = null;
    async getSettingsButton() {
        if (!this._settingsButtonPromise) {
            this._settingsButtonPromise = this._driver.findElementByText('Settings', 10);
        }
        return await this._settingsButtonPromise;
    }

    async isDisplayedSettings(){
        return await (await this.getSettingsButton()).isDisplayed();
    }

    // ...
}

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

Instead of showing the data in the variable "ionic", there is a display of "[object object]"

Here is the code snippet I'm working with: this.facebook.login(['email', 'public_profile']).then((response: FacebookLoginResponse) => { this.facebook.api('me?fields=id,name,email,first_name,picture.width(720).height( ...

Working with JSON data in AngularJS2's templates

Is there a way for me to process JSON from the template in a manner similar to the second code I provided? First code. This method works well when using .json and .map () @Component({ ..// template: `..// <li *ngFor="#user of users"> ...

What steps do I need to take to integrate the Firebase Admin SDK into my Angular project?

Is there a way to integrate Firebase Admin SDK into my Angular application? Currently, I am using Firebase Authentication services in my application and everything I need for user registration and authentication is handled by Angularfire2. I've read ...

Error: To execute NPX command locally from Google Maps API documentation, make sure to call npm.load(callback) as required

Attempting to execute the Google Maps API example locally using this command: npx @googlemaps/js-samples init directions-waypoints googlemapssample However, every time I try to run the npx command locally, it fails after a short period and I encounter the ...

How do I add a new item to an object using Ionic 2?

example item: this.advData = { 'title': this.addAdvS2.value.title , 'breadcrumb': this.suggestData.breadcrumb, 'price': this.addAdvS2.value.price ...

Is OnPush Change Detection failing to detect state changes?

Curious about the issue with the OnPush change detection strategy not functioning properly in this demonstration. My understanding is that OnPush change detection should activate when a property reference changes. To ensure this, a new array must be set e ...

Exploring async componentDidMount testing using Jest and Enzyme with React

angular:12.4.0 mocha: "8.1.2" puppeteer: 6.6.0 babel: 7.3.1 sample code: class Example extends Angular.Component<undefined,undefined>{ test:number; async componentWillMount() { this.test = 50; let jest = await import('jest&apos ...

The dropdown cannot be disabled because it is being passed as an input parameter

We are currently utilizing PrimeNG along with Angular 15. Scenarios: According to the requirements, we need the ability to disable the PrimeNG dropdown control based on a selection. Problem: The disabled property of <p.dropdown> is not functioning ...

What are some ways to specialize a generic class during its creation in TypeScript?

I have a unique class method called continue(). This method takes a callback and returns the same type of value as the given callback. Here's an example: function continue<T>(callback: () => T): T { // ... } Now, I'm creating a clas ...

Is there a way to insert a secured page right before accessing the dashboard?

I am trying to create a locked page that will display a message when users access the web app from a mobile device and load a mobile layout page displaying a message like mobile is not supported. I was considering using document.addEventListener('DOMC ...

Tips for incorporating auth0 into a vue application with typescript

Being a beginner in TypeScript, I've successfully integrated Auth0 with JavaScript thanks to their provided sample code. However, I'm struggling to find any sample applications for using Vue with TypeScript. Any recommendations or resources would ...

Errors occur when attempting to parse Uint8Array in Typescript

I received the following object as a response from calling the AWS Lambda client in NodeJS. { '$metadata': { httpStatusCode: 200, requestId: '1245', extendedRequestId: undefined, cfId: undefined, attempts: 1, tot ...

Creating fixtures with Playwright is a simple process that can greatly enhance

I have a requirement to set up fixtures where the first fixture is always available (acting as a base class) and the second fixture will vary in different test files (like a derived class). I've implemented the following code which seems to be working ...

Utilizing Angular's Dependency Injection to Provide Services to External Libraries

I'm currently developing an NPM package that enhances the functionalities of Material Datatable. One standout feature is the ability to specify a method that will be triggered when a user clicks on a specific cell. Here is how the property is defined ...

What are the best practices for transpiling code using Parcel-bundler?

Currently, I am attempting to transpile both .ts (TYPESCRIPT) and .scss (SASS) files. However, I am encountering two main issues: 1) Instead of generating my file in the designated dist directory, it is creating a dist directory within the build folder. ...

Different ways to pass a component function's return value to a service in Angular

On my HTML page, I am presenting job details within Bootstrap panels sourced from a JSON array using an ngFor loop. Each panel showcases specific job information along with a unique job ID. The panel is equipped with a click event which triggers the execut ...

Struggling with TypeScript compilation in a Vue.js project? Encounter error code TS2352

Here is my code snippet from window.ts import Vue from 'vue' interface BrowserWindow extends Window { app: Vue } const browserWindow = window as BrowserWindow export default browserWindow Encountering a compilation error Error message: TS2 ...

Starting a fresh Angular project yields a series of NPM warnings, notably one that mentions skipping an optional dependency with the message: "npm

Upon creating a new Angular project, I encounter warning messages from NPM: npm WARN optional SKIPPING OPTIONAL DEPENDENCY: <a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="68e01b0d1e0d061c7518d7">[email protecte ...

"Experience the power of utilizing TypeScript with the seamless compatibility provided by the

I'm attempting to utilize jsymal.safeDump(somedata). So far, I've executed npm install --save-dev @types/js-yaml I've also configured my tsconfig file as: { "compilerOptions": { "types": [ "cypress" ...

execute the function once the filereader has completed reading the files

submitTCtoDB(updateTagForm:any){ for(let i=0;i<this.selectedFileList.length;i++){ let file=this.selectedFileList[i]; this.readFile(file, function(selectedFileList) { this.submitTC(updateTagForm,selectedFileList); }); } } } ...