-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Expand file tree
/
Copy pathPlaywrightGestures.ts
More file actions
144 lines (129 loc) · 3.8 KB
/
PlaywrightGestures.ts
File metadata and controls
144 lines (129 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
import { PlatformDetector } from './PlatformLocator';
import { PlaywrightElement } from './PlaywrightAdapter';
import { boxedStep, getDriver } from './PlaywrightUtilities';
/**
* PlaywrightGestures - Gesture helpers for WebdriverIO/Playwright
*
* This class provides gesture methods that wrap PlaywrightElement API.
* Currently these are simple wrappers, but can be enhanced with retries,
* stability checks, and logging in the future (similar to Detox Gestures).
*
* @example
* const elem = await PlaywrightMatchers.getByXPath('...');
* await PlaywrightGestures.tap(elem);
* await PlaywrightGestures.fill(elem, 'text');
*/
export default class PlaywrightGestures {
/**
* Swipe element in a direction
*/
@boxedStep
static async swipe(
elem: PlaywrightElement,
direction: 'up' | 'down' | 'left' | 'right',
speed: 'fast' | 'slow' = 'fast',
): Promise<void> {
const location = await elem.unwrap().getLocation();
const size = await elem.unwrap().getSize();
const startX = location.x + size.width / 2;
const startY = location.y + size.height / 2;
let endX = startX;
let endY = startY;
const distance = 200; // pixels
switch (direction) {
case 'up':
endY -= distance;
break;
case 'down':
endY += distance;
break;
case 'left':
endX -= distance;
break;
case 'right':
endX += distance;
break;
}
await elem
.unwrap()
.touchAction([
{ action: 'press', x: startX, y: startY },
{ action: 'wait', ms: speed === 'slow' ? 1000 : 100 },
{ action: 'moveTo', x: endX, y: endY },
'release',
]);
}
/**
* Long press an element
*/
@boxedStep
static async longPress(
elem: PlaywrightElement,
duration = 1000,
): Promise<void> {
const location = await elem.unwrap().getLocation();
const size = await elem.unwrap().getSize();
const x = location.x + size.width / 2;
const y = location.y + size.height / 2;
await elem
.unwrap()
.touchAction([
{ action: 'press', x, y },
{ action: 'wait', ms: duration },
'release',
]);
}
/**
* Double tap an element using native touch actions.
*
* Using explicit touchAction avoids relying on desktop-oriented click
* semantics and keeps both taps within a mobile-appropriate interval.
*/
@boxedStep
static async dblTap(elem: PlaywrightElement, intervalMs = 60): Promise<void> {
const location = await elem.unwrap().getLocation();
const size = await elem.unwrap().getSize();
const x = location.x + size.width / 2;
const y = location.y + size.height / 2;
await elem
.unwrap()
.touchAction([
{ action: 'press', x, y },
'release',
{ action: 'wait', ms: intervalMs },
{ action: 'press', x, y },
'release',
]);
}
/**
* Scroll element into view
*/
@boxedStep
static async scrollIntoView(elem: PlaywrightElement): Promise<void> {
await elem.unwrap().scrollIntoView();
}
/**
* Terminate the app
* @param packageName - The package name of the app to terminate (Android only)
* @param appId - The app id of the app to terminate (iOS only)
*/
@boxedStep
static async terminateApp(
packageName?: string,
appId?: string,
): Promise<void> {
const driver = getDriver();
if (!driver) throw new Error('Driver is not available');
if ((await PlatformDetector.isAndroid()) && packageName) {
await driver.terminateApp(packageName);
} else if ((await PlatformDetector.isIOS()) && appId) {
await driver.terminateApp(appId);
} else {
throw new Error('Package name or app id is not available');
}
}
@boxedStep
static async tap(elem: PlaywrightElement): Promise<void> {
await elem.click();
}
}