WDIO commands and utils.
- [ ] 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
$
toCSS
to make things more clear, leave backward compatibility - [ ] Remove all dependencies from
@wdio
, library should be agnostic, and supportwdio
andplaywright
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
Install additional peer dependencies:
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
;
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>
);
import { addWdioCommands } from '@rnw-community/wdio';
export const wdioBaseConfiguration = (): WebdriverIO.Config => ({
//...your config
before(_capabilities, _specs, browser: WebdriverIO.Browser) {
addWdioCommands(browser);
},
});
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$$
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
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
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
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
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);
});
});
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
is a helper function to get wdio component class with testID support
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();
}
}
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
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
is a helper function to get wdio component class with testID support and root element
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();
}
}
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);
});
});
export enum CardSelectors {
Root = 'Root',
Text = 'Text',
}
import { CardSelectors as Selectors } from './card.selectors';
export const Card = () => (
<View {...setTestID(CardSelectors.Root)}>
<Text {...setTestID(CardSelectors.Text)}>Text</Text>
</View>
);
export * from './card/card.selectors';
This library is licensed under The MIT License.