@rnw-community/wdio 0.49.2 → 0.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/readme.md +280 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rnw-community/wdio",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.50.0",
|
|
4
4
|
"description": "WDIO commands, page objects and utils",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"wdio",
|
|
@@ -43,9 +43,9 @@
|
|
|
43
43
|
"engines": {
|
|
44
44
|
"node": ">=14.0.0"
|
|
45
45
|
},
|
|
46
|
-
"gitHead": "
|
|
46
|
+
"gitHead": "f5d105c1a22590f3ba6e3e2cd6a56a3f2c0f2eb9",
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@rnw-community/shared": "^0.
|
|
48
|
+
"@rnw-community/shared": "^0.50.0",
|
|
49
49
|
"@wdio/globals": "^8.5.1",
|
|
50
50
|
"@wdio/protocols": "^8.3.11",
|
|
51
51
|
"expect-type": "^0.13.0",
|
package/readme.md
CHANGED
|
@@ -32,7 +32,7 @@ import { Text } from 'react-native';
|
|
|
32
32
|
|
|
33
33
|
import { IOSTestIDProps, setTestId } from '@rnw-community/wdio';
|
|
34
34
|
|
|
35
|
-
export const DynamicComponent:
|
|
35
|
+
export const DynamicComponent: = ({ testID = 'ParentTestID' }:IOSTestIDProps) => (
|
|
36
36
|
<Text {...setTestId(testID, `Text`)}>Text</Text>
|
|
37
37
|
);
|
|
38
38
|
```
|
|
@@ -42,3 +42,282 @@ Which will generate `ParentTestID_Text`;
|
|
|
42
42
|
### getTestID
|
|
43
43
|
|
|
44
44
|
### setPropTestID
|
|
45
|
+
|
|
46
|
+
Setting _testID_ similar to `setTestID` but with overriding default _testID_.
|
|
47
|
+
|
|
48
|
+
```tsx
|
|
49
|
+
import React from 'react';
|
|
50
|
+
import { Text } from 'react-native';
|
|
51
|
+
import { TestIDProps } from '@rnw-community/wdio';
|
|
52
|
+
|
|
53
|
+
interface Props extends TestIDProps, React.PropsWithChildren {
|
|
54
|
+
testID?: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const defaultTestID = 'DynamicComponent.Root';
|
|
58
|
+
|
|
59
|
+
export const DynamicComponent = ({children, ...props}:Props) => (
|
|
60
|
+
<View {...setPropTestID(defaultTestID, props)}>
|
|
61
|
+
{children}
|
|
62
|
+
</View>);
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Commands
|
|
66
|
+
|
|
67
|
+
### Setup
|
|
68
|
+
#### copy 2 d.ts files into root of your e2e project
|
|
69
|
+
|
|
70
|
+
* [wdio.d.ts](https://github.com/rnw-community/rnw-community/blob/9294a867193951b8f37310ef0f7092c74f6b87f2/packages/wdio/src/wdio.d.ts)
|
|
71
|
+
* [webdriverio.d.ts](https://github.com/rnw-community/rnw-community/blob/9294a867193951b8f37310ef0f7092c74f6b87f2/packages/wdio/src/wevdriverio.d.ts)
|
|
72
|
+
|
|
73
|
+
#### add wdio.config.js to your e2e project
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
import { addWdioCommands } from '@rnw-community/wdio';
|
|
77
|
+
|
|
78
|
+
export const wdioBaseConfiguration = (): WebdriverIO.Config => ({
|
|
79
|
+
//...your config
|
|
80
|
+
before(_capabilities, _specs, browser: WebdriverIO.Browser) {
|
|
81
|
+
addWdioCommands(browser);
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
```
|
|
86
|
+
### Usage
|
|
87
|
+
|
|
88
|
+
#### openDeepLink
|
|
89
|
+
|
|
90
|
+
No more manually open safary, locate address and enter link with unicode enter in the end
|
|
91
|
+
|
|
92
|
+
```ts
|
|
93
|
+
import driver from '@wdio/globals';
|
|
94
|
+
|
|
95
|
+
describe('DeepLink', () => {
|
|
96
|
+
it('should open deep link', async () => {
|
|
97
|
+
await driver.openDeepLink('myapp://products/1234');
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
#### testID$ and testID$$
|
|
103
|
+
|
|
104
|
+
`testID$` and `testID$$` are the same as `$` and `$$` but with support for testID selector
|
|
105
|
+
|
|
106
|
+
```ts
|
|
107
|
+
import driver from '@wdio/globals';
|
|
108
|
+
|
|
109
|
+
describe('DynamicComponent', () => {
|
|
110
|
+
it('should find component', async () => {
|
|
111
|
+
await expect(driver.testID$('DynamicComponent.Root')).toBeDisplayed();
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
#### testID$$Index
|
|
117
|
+
|
|
118
|
+
`testID$$Index` is the same as `$$` but with support for testID selector and index. Returns element by index
|
|
119
|
+
|
|
120
|
+
```ts
|
|
121
|
+
import driver from '@wdio/globals';
|
|
122
|
+
|
|
123
|
+
describe('DynamicComponent', () => {
|
|
124
|
+
it('should find root element', async () => {
|
|
125
|
+
await expect(driver.testID$$Index('DynamicComponent.Root', 0)).toBeDisplayed();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
```
|
|
129
|
+
#### slowInput
|
|
130
|
+
|
|
131
|
+
`slowInput` is the same as `setValue` but with support for typing speed
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
import driver from '@wdio/globals';
|
|
135
|
+
import { FormSelectors } from 'my-react-native-project/src/form.selectors';
|
|
136
|
+
|
|
137
|
+
describe('Form', () => {
|
|
138
|
+
it('should input test slowly', async () => {
|
|
139
|
+
await driver.testID$(FormSelectors.Input).slowInput('test', 100);
|
|
140
|
+
});
|
|
141
|
+
});
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### clearInput
|
|
145
|
+
|
|
146
|
+
`clearInput` does several things:
|
|
147
|
+
- clearValue which usually doesn't work
|
|
148
|
+
- setValue('') which usually doesn't work either
|
|
149
|
+
- gets text and deletes it character by character
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
import driver from '@wdio/globals';
|
|
153
|
+
import { FormSelectors } from 'my-react-native-project/src/form.selectors';
|
|
154
|
+
|
|
155
|
+
describe('Form', () => {
|
|
156
|
+
it('should clear input', async () => {
|
|
157
|
+
await driver.testID$(FormSelectors.Input).clearInput();
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
#### relativeClick
|
|
163
|
+
|
|
164
|
+
`relativeClick` clicks on element relative to it's size in percents
|
|
165
|
+
|
|
166
|
+
```ts
|
|
167
|
+
import driver from '@wdio/globals';
|
|
168
|
+
import { FormSelectors } from 'my-react-native-project/src/form.selectors';
|
|
169
|
+
|
|
170
|
+
describe('Form', () => {
|
|
171
|
+
it('should click on the center of the element', async () => {
|
|
172
|
+
await driver.testID$(FormSelectors.Button).relativeClick(50, 50);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
## Components
|
|
179
|
+
|
|
180
|
+
### createComponent
|
|
181
|
+
|
|
182
|
+
`createComponent` is a helper function to create wdio components with testID support
|
|
183
|
+
|
|
184
|
+
```ts
|
|
185
|
+
import { createComponent } from '@rnw-community/wdio';
|
|
186
|
+
import { CardSelectors } from 'my-react-native-project/src/card.selectors';
|
|
187
|
+
|
|
188
|
+
describe('Card', () => {
|
|
189
|
+
it('should find component', async () => {
|
|
190
|
+
const card = createComponent(CardSelectors);
|
|
191
|
+
const cards = await card.els();
|
|
192
|
+
await expect(cards).toHaveLength(3);
|
|
193
|
+
|
|
194
|
+
const lastCard = await card.byIdx(2);
|
|
195
|
+
await expect(lastCard.Root).toBeDisplayed();
|
|
196
|
+
await expect(lastCard.Text).toHaveText('Card 3');
|
|
197
|
+
await lastCard.CloseButton.click();
|
|
198
|
+
await expect(card.els()).resolves.toHaveLength(2);
|
|
199
|
+
});
|
|
200
|
+
});
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### getComponent
|
|
204
|
+
|
|
205
|
+
`getComponent` is a helper function to get wdio component class with testID support
|
|
206
|
+
|
|
207
|
+
#### card.component.ts
|
|
208
|
+
```ts
|
|
209
|
+
import { getComponent } from '@rnw-community/wdio';
|
|
210
|
+
import { CardSelectors } from 'my-react-native-project/src/card.selectors';
|
|
211
|
+
|
|
212
|
+
export class Card extends getComponent(CardSelectors) {
|
|
213
|
+
public async close() {
|
|
214
|
+
await this.CloseButton.click();
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
```
|
|
218
|
+
#### card.spec.ts
|
|
219
|
+
```ts
|
|
220
|
+
import { Card } from './card.component';
|
|
221
|
+
|
|
222
|
+
describe('Card', () => {
|
|
223
|
+
it('should find component', async () => {
|
|
224
|
+
const card = new Card();
|
|
225
|
+
const cards = await card.els();
|
|
226
|
+
await expect(cards).toHaveLength(3);
|
|
227
|
+
|
|
228
|
+
const lastCard = await card.byIdx(2);
|
|
229
|
+
await expect(lastCard.Root).toBeDisplayed();
|
|
230
|
+
await expect(lastCard.Text).toHaveText('Card 3');
|
|
231
|
+
// no need to use lastCard.CloseButton.click();
|
|
232
|
+
await lastCard.close();
|
|
233
|
+
await expect(card.els()).resolves.toHaveLength(2);
|
|
234
|
+
});
|
|
235
|
+
});
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### createRootedComponent
|
|
239
|
+
|
|
240
|
+
`createRootedComponent` is a helper function to create wdio components with testID support and root element
|
|
241
|
+
|
|
242
|
+
```ts
|
|
243
|
+
import { createRootedComponent } from '@rnw-community/wdio';
|
|
244
|
+
import { CardSelectors } from 'my-react-native-project/src/card.selectors';
|
|
245
|
+
|
|
246
|
+
describe('Card', () => {
|
|
247
|
+
it('should find component', async () => {
|
|
248
|
+
const card = createRootedComponent(CardSelectors);
|
|
249
|
+
const cards = await card.els();
|
|
250
|
+
await expect(cards).toHaveLength(3);
|
|
251
|
+
|
|
252
|
+
const lastCard = await card.byIdx(2);
|
|
253
|
+
// no need to use lastCard.Root because it's already in the Card class
|
|
254
|
+
await expect(lastCard).toBeDisplayed();
|
|
255
|
+
await expect(lastCard.Text).toHaveText('Card 3');
|
|
256
|
+
await lastCard.CloseButton.click();
|
|
257
|
+
await expect(card.els()).resolves.toHaveLength(2);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
```
|
|
261
|
+
### getRootedComponent
|
|
262
|
+
|
|
263
|
+
`getRootedComponent` is a helper function to get wdio component class with testID support and root element
|
|
264
|
+
|
|
265
|
+
#### card.component.ts
|
|
266
|
+
```ts
|
|
267
|
+
import { getRootedComponent } from '@rnw-community/wdio';
|
|
268
|
+
import { CardSelectors } from 'my-react-native-project/src/card.selectors';
|
|
269
|
+
|
|
270
|
+
export class Card extends getRootedComponent(CardSelectors) {
|
|
271
|
+
public async close() {
|
|
272
|
+
await this.CloseButton.click();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
#### card.spec.ts
|
|
277
|
+
```ts
|
|
278
|
+
import { Card } from './card.component';
|
|
279
|
+
|
|
280
|
+
describe('Card', () => {
|
|
281
|
+
it('should find component', async () => {
|
|
282
|
+
const card = new Card();
|
|
283
|
+
const cards = await card.els();
|
|
284
|
+
await expect(cards).toHaveLength(3);
|
|
285
|
+
|
|
286
|
+
const lastCard = await card.byIdx(2);
|
|
287
|
+
// no need to use lastCard.Root because it's already in the Card class
|
|
288
|
+
await expect(lastCard).toBeDisplayed();
|
|
289
|
+
await expect(lastCard.Text).toHaveText('Card 3');
|
|
290
|
+
// no need to use lastCard.CloseButton.click();
|
|
291
|
+
await lastCard.close();
|
|
292
|
+
await expect(card.els()).resolves.toHaveLength(2);
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
```
|
|
296
|
+
## Recommendations
|
|
297
|
+
|
|
298
|
+
### Create Selectors enum for each component close to the component file
|
|
299
|
+
|
|
300
|
+
#### card.selectors.ts
|
|
301
|
+
```tsx
|
|
302
|
+
export enum CardSelectors {
|
|
303
|
+
Root = 'Root',
|
|
304
|
+
Text = 'Text',
|
|
305
|
+
}
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### card.tsx
|
|
309
|
+
```tsx
|
|
310
|
+
import { CardSelectors as Selectors } from './card.selectors';
|
|
311
|
+
export const Card = () => (
|
|
312
|
+
<View {...setTestID(CardSelectors.Root)}>
|
|
313
|
+
<Text {...setTestID(CardSelectors.Text)}>Text</Text>
|
|
314
|
+
</View>
|
|
315
|
+
);
|
|
316
|
+
```
|
|
317
|
+
### Export all selectors from your project in selectors.ts file in your src folder
|
|
318
|
+
|
|
319
|
+
#### selectors.ts
|
|
320
|
+
```tsx
|
|
321
|
+
export * from './card/card.selectors';
|
|
322
|
+
```
|
|
323
|
+
|