Testcafe: Unable to use `typeText` when selecting a field with specific attribute

Created on 5 Jul 2019  路  12Comments  路  Source: DevExpress/testcafe

What is your Test Scenario?

Keep up the good work!

I have a form with 10 input fields. Each input has their own data-test attribute with a specific name. What I want to do is find a specific input by using the attribute and type text inside.

The problem is the Selector needs to return a Promise and using Selector('input').withAttribute('data-test', 'movieName') does not return a promise i.e. t.typeText(Selector('input').withAttribute('data-test', 'movieName'), 'Batman') fails

I have struggled to find information how to implement that specific scenario. If it exists place do share.

What are you suggesting?

I would expect to use Selector with attributes. I find it more common now to not use ids for selecting a field rather using data-x attributes for that.

What alternatives have you considered?

N/A

Additional context

N/A

TypeScript definitions level 1 HELP WANTED Auto-locked bug

All 12 comments

Hi @zsid

I've created a simple example according your description.
It works fine with the latest TestCafe version 1.3.0.

HTML page

<html>
    <body>
        <input data-test="1">
        <input data-test="2">
        <input data-test="3">
        <input data-test="4">
        <input data-test="5">
        <input data-test="6">
        <input data-test="movieName" placeholder="Type movie name">
        <input data-test="7">
        <input data-test="8">
        <input data-test="9">
        <input data-test="10">
    </body>
</html>

Test code

import { Selector } from 'testcafe';

fixture `Fixture`
    .page('http://localhost:8080/index.html');


test('test', async t => {
    const targetInput = Selector('input').withAttribute('data-test', 'movieName');

    await t
        .typeText(targetInput, 'Batman')
        .wait(5000);
});

Could you please provide a simple example in which I can reproduce the problem on my machine?

Thanks for coming back to me so quickly. We are using react + typescript and when calling the selector like that we even get typescript error. Let me create a github repo or codesanbox and I will share it with you.

OK, I understand you. Our bot will close this issue in 10 days. If your example is ready after that time, feel free to reopen the issue.

I found what the issue was. Because we are using 'testcafe-react-selectors'; and react + typescript when we use Selector as an interface it picks up the global one defined in testcafe-react-selectors. For example:

import { Selector } from 'testcafe';

export default class MoviePage {
  movieName: Selector;
   this.movieName = Selector('input').withAttribute(
      'data-test',
      'movieName'
    );
}

The error is Type 'SelectorPromise' is missing the following properties from type 'Selector': getReact, withProps, withKey, findReactts(2739) which means the interface for Selector is:

declare global {
    interface Selector {
        getReact<C extends DefaultReactComponent, T = any>(filter?: (reactInternal: C) => T): Promise<T>;
        getReact<C extends DefaultReactComponent>(): Promise<C>;

        withProps<P extends { [name: string]: any }>(propName: keyof P, propValue?: Partial<P[keyof P]>, options?: { exactObjectMatch: boolean }): any;

        withProps<P extends { [name: string]: any }>(props: Partial<P>, options?: { exactObjectMatch: boolean }): any;

        withKey(key: string): any;

        findReact(selector: string): Selector;
    }
}

Instead of picking up the selector interface from testcafe which is:

    export function Selector(
        init:
            | string
            | ((...args: any[]) => Node | Node[] | NodeList | HTMLCollection)
            | Selector
            | NodeSnapshot
            | SelectorPromise,
        options?: SelectorOptions
    ): Selector;

interface Selector extends SelectorAPI {
    /**
     * Creates parametrized selector.
     *
     * @param args - Selector parameters.
     */
    (...args: any[]): SelectorPromise;
}

I couldn't find the normal Selector being exported from testcafe. It would be great if both Selector interfaces are available so that we can specify which one we want to use.

Apart from the interface problems if I use any for the interface of movie name (movieName: any;) the typeText works as expected.

Thank you for the additional information. However, this is still not sufficient to find the cause of the issue. Could you please change my example below to illustrate the error?

import { Selector } from 'testcafe';

fixture`3987`
    .page`http://todomvc.com/examples/react/#/`;

test('test', async t => {
    await t
        .typeText(Selector('input').withAttribute('placeholder', 'What needs to be done?'), '123')
        .wait(5e3);
});

You are doing that directly in typeText in the test example. You would need to be using testcafe-react-selectors and react + typescript and in pages folder, create a new page called MoviePage.ts. Paste the code below and you will see the error.

import { Selector } from 'testcafe';

export default class MoviePage {
  movieName: Selector;
   this.movieName = Selector('input').withAttribute(
      'data-test',
      'movieName'
    );
}

Thank you for the additional information. I've found the problem with our type definitions. All our selector methods such as nth, withText, filter return the Selector instance but the withAttribute method returns SelectorPromise.

Great. I am glad you can replicate it. Let me know if more information is needed 馃槃

@jaypea Thank you for pointing this out.

This thread has been automatically locked since it is closed and there has not been any recent activity. Please open a new issue for related bugs or feature requests. We recommend you ask TestCafe API, usage and configuration inquiries on StackOverflow.

Was this page helpful?
0 / 5 - 0 ratings