0.67.0 • Published 2 months ago

@rnw-community/wdio v0.67.0

Weekly downloads
-
License
MIT
Repository
github
Last release
2 months ago

WDIO commands and utils

WDIO commands and utils.

npm version npm downloads

TODO

  • Refactor tests to mock MockElement(rename to MockElementPromise), use it instead of mockElement object
  • Rename all tests its properly after API stabilizes
  • Write docs with the examples
  • Add tests for extended class instance ctor return from async function - it resolves to WDIO element =)
  • Rename everything with $ to CSS to make things more clear, leave backward compatibility
  • Remove all dependencies from @wdio, library should be agnostic, and support wdio and playwright via adapters(maybe others):
  • Create generic adapter and element interface
  • Playwright does not support ChainablePromise, find a best way for this API(we still can have it btw)
  • Add wdio adapter
  • Add playwright adapter
  • Add puppeteer adapter
  • Add check and human readable error for stale/missing RootEl in the rooted component and tests/docs for this case
  • rename get*Component* mixins to community standard
  • refactor Component classes proxy approach, add more tests
  • add documentation and tests for each custom command, make writing this streamlined and extendable
  • add documentation and tests for parent component inheritance and tests

Installation

Install additional peer dependencies:

Usage

Utils

setTestID

Setting testID for each platform can produce warning, setTestID(...ids) fixes it and has support for dynamically generated components.

Example usage:

import React, { FC } from 'react';
import { Text } from 'react-native';

import { IOSTestIDProps, setTestId } from '@rnw-community/wdio';

export const DynamicComponent: = ({ testID = 'ParentTestID' }:IOSTestIDProps) => (
    <Text {...setTestId(testID, `Text`)}>Text</Text>
);

Which will generate ParentTestID_Text;

getTestID

setPropTestID

Setting testID similar to setTestID but with overriding default testID.

import React from 'react';
import { Text } from 'react-native';
import { TestIDProps } from '@rnw-community/wdio';

interface Props extends TestIDProps, React.PropsWithChildren {
    testID?: string;
}

const defaultTestID = 'DynamicComponent.Root';

export const DynamicComponent = ({ children, ...props }: Props) => (
    <View {...setPropTestID(defaultTestID, props)}>{children}</View>
);

Commands

Setup

copy 2 d.ts files into root of your e2e project

add wdio.config.js to your e2e project

import { addWdioCommands } from '@rnw-community/wdio';

export const wdioBaseConfiguration = (): WebdriverIO.Config => ({
    //...your config
    before(_capabilities, _specs, browser: WebdriverIO.Browser) {
        addWdioCommands(browser);
    },
});

Usage

openDeepLink

No more manually open safary, locate address and enter link with unicode enter in the end

import driver from '@wdio/globals';

describe('DeepLink', () => {
    it('should open deep link', async () => {
        await driver.openDeepLink('myapp://products/1234');
    });
});

testID$ and testID$$

testID$ and testID$$ are the same as $ and $$ but with support for testID selector

import driver from '@wdio/globals';

describe('DynamicComponent', () => {
    it('should find component', async () => {
        await expect(driver.testID$('DynamicComponent.Root')).toBeDisplayed();
    });
});

testID$$Index

testID$$Index is the same as $$ but with support for testID selector and index. Returns element by index

import driver from '@wdio/globals';

describe('DynamicComponent', () => {
    it('should find root element', async () => {
        await expect(driver.testID$$Index('DynamicComponent.Root', 0)).toBeDisplayed();
    });
});

slowInput

slowInput is the same as setValue but with support for typing speed

import driver from '@wdio/globals';
import { FormSelectors } from 'my-react-native-project/src/form.selectors';

describe('Form', () => {
    it('should input test slowly', async () => {
        await driver.testID$(FormSelectors.Input).slowInput('test', 100);
    });
});

clearInput

clearInput does several things:

  • clearValue which usually doesn't work
  • setValue('') which usually doesn't work either
  • gets text and deletes it character by character
import driver from '@wdio/globals';
import { FormSelectors } from 'my-react-native-project/src/form.selectors';

describe('Form', () => {
    it('should clear input', async () => {
        await driver.testID$(FormSelectors.Input).clearInput();
    });
});

relativeClick

relativeClick clicks on element relative to it's size in percents

import driver from '@wdio/globals';
import { FormSelectors } from 'my-react-native-project/src/form.selectors';

describe('Form', () => {
    it('should click on the center of the element', async () => {
        await driver.testID$(FormSelectors.Button).relativeClick(50, 50);
    });
});

Components

createComponent

createComponent is a helper function to create wdio components with testID support

import { createComponent } from '@rnw-community/wdio';
import { CardSelectors } from 'my-react-native-project/src/card.selectors';

describe('Card', () => {
    it('should find component', async () => {
        const card = createComponent(CardSelectors);
        const cards = await card.els();
        await expect(cards).toHaveLength(3);

        const lastCard = await card.byIdx(2);
        await expect(lastCard.Root).toBeDisplayed();
        await expect(lastCard.Text).toHaveText('Card 3');
        await lastCard.CloseButton.click();
        await expect(card.els()).resolves.toHaveLength(2);
    });
});

getComponent

getComponent is a helper function to get wdio component class with testID support

card.component.ts

import { getComponent } from '@rnw-community/wdio';
import { CardSelectors } from 'my-react-native-project/src/card.selectors';

export class Card extends getComponent(CardSelectors) {
    public async close() {
        await this.CloseButton.click();
    }
}

card.spec.ts

import { Card } from './card.component';

describe('Card', () => {
    it('should find component', async () => {
        const card = new Card();
        const cards = await card.els();
        await expect(cards).toHaveLength(3);

        const lastCard = await card.byIdx(2);
        await expect(lastCard.Root).toBeDisplayed();
        await expect(lastCard.Text).toHaveText('Card 3');
        // no need to use lastCard.CloseButton.click();
        await lastCard.close();
        await expect(card.els()).resolves.toHaveLength(2);
    });
});

createRootedComponent

createRootedComponent is a helper function to create wdio components with testID support and root element

import { createRootedComponent } from '@rnw-community/wdio';
import { CardSelectors } from 'my-react-native-project/src/card.selectors';

describe('Card', () => {
    it('should find component', async () => {
        const card = createRootedComponent(CardSelectors);
        const cards = await card.els();
        await expect(cards).toHaveLength(3);

        const lastCard = await card.byIdx(2);
        // no need to use lastCard.Root because it's already in the Card class
        await expect(lastCard).toBeDisplayed();
        await expect(lastCard.Text).toHaveText('Card 3');
        await lastCard.CloseButton.click();
        await expect(card.els()).resolves.toHaveLength(2);
    });
});

getRootedComponent

getRootedComponent is a helper function to get wdio component class with testID support and root element

card.component.ts

import { getRootedComponent } from '@rnw-community/wdio';
import { CardSelectors } from 'my-react-native-project/src/card.selectors';

export class Card extends getRootedComponent(CardSelectors) {
    public async close() {
        await this.CloseButton.click();
    }
}

card.spec.ts

import { Card } from './card.component';

describe('Card', () => {
    it('should find component', async () => {
        const card = new Card();
        const cards = await card.els();
        await expect(cards).toHaveLength(3);

        const lastCard = await card.byIdx(2);
        // no need to use lastCard.Root because it's already in the Card class
        await expect(lastCard).toBeDisplayed();
        await expect(lastCard.Text).toHaveText('Card 3');
        // no need to use lastCard.CloseButton.click();
        await lastCard.close();
        await expect(card.els()).resolves.toHaveLength(2);
    });
});

Recommendations

Create Selectors enum for each component close to the component file

card.selectors.ts

export enum CardSelectors {
    Root = 'Root',
    Text = 'Text',
}

card.tsx

import { CardSelectors as Selectors } from './card.selectors';
export const Card = () => (
    <View {...setTestID(CardSelectors.Root)}>
        <Text {...setTestID(CardSelectors.Text)}>Text</Text>
    </View>
);

Export all selectors from your project in selectors.ts file in your src folder

selectors.ts

export * from './card/card.selectors';

License

This library is licensed under The MIT License.

0.67.0

2 months ago

0.66.0

2 months ago

0.65.2

4 months ago

0.65.3

4 months ago

0.64.0

4 months ago

0.65.1

4 months ago

0.65.0

4 months ago

0.63.0

4 months ago

0.62.1

6 months ago

0.62.0

6 months ago

0.62.2

6 months ago

0.59.3

6 months ago

0.55.0

7 months ago

0.59.6

6 months ago

0.59.4

6 months ago

0.59.5

6 months ago

0.56.0

6 months ago

0.60.0

6 months ago

0.57.2

6 months ago

0.57.3

6 months ago

0.57.0

6 months ago

0.57.1

6 months ago

0.54.12

9 months ago

0.61.0

6 months ago

0.51.0

1 year ago

0.52.3

1 year ago

0.52.0

1 year ago

0.49.1

1 year ago

0.49.2

1 year ago

0.49.0

1 year ago

0.53.0

1 year ago

0.54.0

1 year ago

0.50.0

1 year ago

0.43.0

2 years ago

0.46.4

2 years ago

0.48.0

2 years ago

0.48.1

1 year ago

0.46.3

2 years ago

0.46.0

2 years ago

0.44.2

2 years ago

0.46.1

2 years ago

0.44.3

2 years ago

0.44.0

2 years ago

0.44.1

2 years ago

0.42.0

2 years ago

0.42.1

2 years ago

0.43.3

2 years ago

0.47.0

2 years ago

0.43.1

2 years ago

0.45.0

2 years ago

0.43.2

2 years ago

0.41.1

2 years ago

0.41.0

2 years ago

0.38.2

2 years ago

0.38.1

2 years ago

0.38.0

2 years ago

0.36.1

2 years ago

0.36.0

2 years ago

0.34.0

2 years ago

0.32.1

2 years ago

0.38.3

2 years ago

0.32.0

2 years ago

0.40.0

2 years ago

0.39.1

2 years ago

0.39.0

2 years ago

0.35.3

2 years ago

0.37.0

2 years ago

0.35.2

2 years ago

0.35.1

2 years ago

0.35.0

2 years ago

0.33.0

2 years ago

0.39.2

2 years ago

0.31.0

2 years ago

0.30.0

2 years ago

0.29.0

2 years ago

0.28.0

2 years ago

0.27.4

2 years ago

0.27.3

2 years ago

0.27.2

2 years ago

0.27.1

2 years ago

0.27.0

2 years ago

0.26.10

2 years ago

0.26.9

2 years ago

0.26.8

2 years ago

0.26.7

2 years ago

0.26.5

2 years ago

0.26.4

2 years ago

0.26.3

2 years ago

0.26.2

2 years ago

0.26.1

2 years ago

0.26.0

2 years ago

0.25.0

2 years ago

0.24.10

2 years ago

0.24.9

2 years ago

0.24.8

2 years ago

0.24.7

2 years ago

0.24.6

2 years ago

0.24.5

2 years ago

0.24.4

2 years ago

0.24.3

2 years ago

0.24.2

2 years ago

0.24.1

2 years ago

0.24.0

2 years ago

0.23.1

2 years ago

0.23.0

2 years ago

0.22.0

2 years ago

0.21.0

2 years ago

0.20.0

2 years ago

0.19.1

2 years ago

0.19.0

2 years ago

0.18.4

2 years ago

0.18.3

2 years ago

0.18.1

2 years ago

0.18.0

2 years ago

0.17.1

2 years ago

0.17.0

2 years ago

0.16.0

2 years ago

0.15.0

2 years ago

0.14.2

2 years ago

0.14.1

2 years ago

0.14.0

2 years ago

0.13.0

2 years ago

0.12.1

2 years ago

0.12.0

2 years ago