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

The type 'RefObject<HTMLDivElement>' cannot be matched with type 'RefObject<HTMLInputElement>' in this context

Encountered an error message: Issue with assigning types: Type '{ placeholder: string | undefined; autoComplete: string | undefined; "data-testid": string | undefined; onChange?: ChangeEventHandler<HTMLInputElement | HTMLTextAreaElement&g ...

Is there a way to locate all projects impacted by `nx`?

Currently, I am utilizing the nx tool to manage a mono repo specifically designed for typescript projects. The nx comes equipped with a command called affected, which allows me to focus solely on the changed project and any other projects that rely on it. ...

registering a back button action in Ionic2 for multiple pages

Currently, I am in the process of developing my Ionic2 app and have encountered a dilemma regarding the functionality of registerBackButtonAction. On one page, let's call it pageA, I have implemented this function and everything is functioning as exp ...

Comparison between Destructuring in TypeScript and JavaScript

Starting my journey with TypeScript after a background in JavaScript. In the realm of modern JavaScript, one can easily destructure objects like this: let {n,s} = {n:42, s:'test'}; console.log(n, s); // 42 test Assuming TypeScript follows su ...

When using the .concat method on an array, props may display as unidentified

When I log the items array in my props, it contains items. However, when I try to add to the array using .concat, I encounter an error stating Cannot read property 'concat' of undefined export default (props) => { const { items } = props; ...

Struggling to get the bindings to work in my Angular 2 single-page application template project

I have recently started using the latest SPA template within Visual Studio 2017: https://blogs.msdn.microsoft.com/webdev/2017/02/14/building-single-page-applications-on-asp.net-core-with-javascriptservices/ The template project is functioning properly. ...

Implementing Default Language in Next.js 14 for Static Export without URL Prefix: A Step-by-Step Guide

Currently, I am in the process of developing a website using Next.js 14, with the intention of exporting it as a static site for distribution through a CDN (Cloudflare Pages). The website I am working on requires support for internationalization (i18n) to ...

Vercel seems to be having trouble detecting TypeScript or the "@types/react" package when deploying a Next.js project

Suddenly, my deployment of Next.js to Vercel has hit a snag after the latest update and is now giving me trouble for not having @types/react AND typescript installed. Seems like you're attempting to utilize TypeScript but are missing essential package ...

Creating an array of objects data is a breeze with Vue.js

I have an array of data containing selected items, and I need to extract the IDs from this array into a new array so that I can send only the IDs to the back-end. Sample Code method toggleSelection(rows) { console.log('this.multipleSelection : &a ...

Reorganize code in JavaScript and TypeScript files using VSCode

Is there a way to efficiently organize the code within a .js / .ts file using Vscode? Specifically, when working inside a Class, my goal is to have static variables at the top, followed by variables, then methods, and so on automatically. I did some resea ...

Angular functions fail to update the loop variable

Using the documentSnapshot function in Firestore to verify the existence of a document. The function is executed in a loop up to a value of 5. However, even though the function runs 5 times, the value of 'i' always reflects the last value. The ...

Guide to developing a versatile Icon Wrapper component for FontAwesome Icons in React that adapts to changing needs

I'm looking to develop a customized React Icon-Component where I can simply input the icon name as a string and have the icon display automatically. After following the guidelines provided here: https://fontawesome.com/docs/web/use-with/react/add-ico ...

Combining Repetitive Elements in an Array

Trying to combine an array of products with the same order_id while also including all objects from a second products array. Below are some sample orders: const orders = [ { "order_details": { }, "order_id": "1", ...

Using the tensorflow library with vite

Greetings and apologies for any inconvenience caused by my relatively trivial inquiries. I am currently navigating the introductory stages of delving into front-end development. Presently, I have initiated a hello-world vite app, which came to life throug ...

Is it possible to meet the requirements of a specific interface using an enum field as the criteria?

I've been struggling to create a versatile function that can return a specific interface based on an enum argument, but all my attempts have failed. Could it be possible that I missed something or am simply approaching it the wrong way? If I try to ...

Error: Attempting to access the value property of a null object within a React Form is not possible

I am currently developing a form that includes an HTML input field allowing only numbers or letters to be entered. The abbreviated version of my state interface is outlined below: interface State { location: string; startDate: Date; } To initiali ...

Invalid sequencing of Nest.js async onModuleInit causing issues

I am dealing with a scenario where ServiceA relies on RedisService. In order for ServiceA to be fully operational, it must wait for RedisService to complete its initialization process (specifically, for RedisService.onModuleInit to be called and awaited). ...

Is it necessary to use ReplaySubject after using location.back() in Angular 6 to avoid requesting data multiple times?

I'm currently utilizing a BehaviorSubject in my service to retrieve data from the BackEnd, which I subscribe to in my mainComponent using the async pipe. However, whenever I navigate to another subComponent and then return to my mainComponent by clic ...

"Can you share a method to extract the value from a TextField component in a React hook-based Material-

Currently, I am using Material-UI within a React project and have a component set up like this: const UserDetail = (props: ListDetailProps) => { const oldpassword = useRef<TextFieldProps>(null); const newpassword = useRef<TextFieldProps ...

Issue encountered while conducting tests with Jest and React Testing Library on a React component containing an SVG: the type is not recognized in React.jsx

In my Next.js 12.1.4 project, I am using Typescript, React Testing Library, and SVGR for importing icons like this: import ChevronLeftIcon from './chevron-left.svg' The issue arises when running a test on a component that includes an SVG import, ...