@web/test-runner-commands 0.5.10 → 0.6.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.
@@ -8,6 +8,7 @@ import {
8
8
  RemoveFilePayload,
9
9
  SnapshotPluginConfig,
10
10
  SaveSnapshotPayload,
11
+ SendMousePayload,
11
12
  } from '../dist/index';
12
13
 
13
14
  /**
@@ -74,6 +75,63 @@ export function setUserAgent(userAgent: string): Promise<void>;
74
75
  **/
75
76
  export function sendKeys(payload: SendKeysPayload): Promise<void>;
76
77
 
78
+ /**
79
+ * Sends an action for the mouse to move it to a specific position or click a mouse button (left, middle, or right).
80
+ *
81
+ * WARNING: When moving the mouse or holding down a mouse button, the mouse stays in this state as long as
82
+ * you do not explicitly move it to another position or release the button. For this reason, it is recommended
83
+ * to reset the mouse state with the `resetMouse` command after each test case manipulating the mouse to avoid
84
+ * unexpected side effects.
85
+ *
86
+ * @param payload An object representing a mouse action specified by the `type` property (move, click, down, up)
87
+ * and including some properties to configure this action.
88
+ *
89
+ * @example
90
+ * ```ts
91
+ * await sendMouse({
92
+ * type: 'move',
93
+ * position: [100, 100]
94
+ * });
95
+ * ```
96
+ *
97
+ * @example
98
+ * ```ts
99
+ * await sendMouse({
100
+ * type: 'click',
101
+ * position: [100, 100],
102
+ * button: 'right'
103
+ * });
104
+ * ```
105
+ *
106
+ * @example
107
+ * ```ts
108
+ * await sendMouse({
109
+ * type: 'down'
110
+ * });
111
+ * ```
112
+ *
113
+ **/
114
+ export function sendMouse(payload: SendMousePayload): Promise<void>;
115
+
116
+ /**
117
+ * Resets the mouse position to (0, 0) and releases mouse buttons.
118
+ *
119
+ * Use this command to reset the mouse state after mouse manipulations by the `sendMouse` command.
120
+ *
121
+ * @example
122
+ * ```
123
+ * it('does something with the mouse', () => {
124
+ * await sendMouse({ type: 'move', position: [150, 150] });
125
+ * await sendMouse({ type: 'down', button: 'middle' });
126
+ * });
127
+ *
128
+ * afterEach(() => {
129
+ * await resetMouse();
130
+ * });
131
+ * ```
132
+ */
133
+ export function resetMouse(): Promise<void>;
134
+
77
135
  /**
78
136
  * Request a snapshot of the Accessibility Tree of the entire page or starting from
79
137
  * the element that is obtained via the `selector` property of the `payload` argument.
@@ -155,7 +213,7 @@ export function writeFile(payload: WriteFilePayload): Promise<void>;
155
213
  * const content = await readFile({ path: 'hello-world.txt' });
156
214
  * ```
157
215
  */
158
- export function readFile(payload: WriteFilePayload): Promise<string | undefined>;
216
+ export function readFile(payload: ReadFilePayload): Promise<string | undefined>;
159
217
 
160
218
  /**
161
219
  * Removes a file from disk.
@@ -69,6 +69,14 @@ export function sendKeys(options) {
69
69
  return executeServerCommand('send-keys', options);
70
70
  }
71
71
 
72
+ export function sendMouse(options) {
73
+ return executeServerCommand('send-mouse', options);
74
+ }
75
+
76
+ export function resetMouse(options) {
77
+ return executeServerCommand('reset-mouse', options);
78
+ }
79
+
72
80
  export function a11ySnapshot(options) {
73
81
  return executeServerCommand('a11y-snapshot', options);
74
82
  }
@@ -123,7 +131,7 @@ const ESCAPE_REGEX = /snapshots\[[^\]]+] = (\n)?(?<content>`[^`]*`)/gm;
123
131
 
124
132
  const escapeContent = content => {
125
133
  [...content.matchAll(ESCAPE_REGEX)].forEach(({ groups: { content: itemContent } }) => {
126
- content = content.replaceAll(itemContent, itemContent.replaceAll(/\n/g, '\\n'));
134
+ content = content.replaceAll(itemContent, encodeURIComponent(itemContent));
127
135
  });
128
136
 
129
137
  return content;
package/dist/index.d.ts CHANGED
@@ -2,6 +2,7 @@ export { Viewport, setViewportPlugin } from './setViewportPlugin';
2
2
  export { Media, emulateMediaPlugin } from './emulateMediaPlugin';
3
3
  export { setUserAgentPlugin } from './setUserAgentPlugin';
4
4
  export { sendKeysPlugin, SendKeysPayload } from './sendKeysPlugin';
5
+ export { sendMousePlugin, SendMousePayload } from './sendMousePlugin';
5
6
  export { a11ySnapshotPlugin, A11ySnapshotPayload } from './a11ySnapshotPlugin';
6
7
  export { WriteFilePayload, ReadFilePayload, RemoveFilePayload, filePlugin } from './filePlugin';
7
8
  export { SaveSnapshotPayload, SnapshotPluginConfig, snapshotPlugin } from './snapshotPlugin';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAClE,OAAO,EAAE,KAAK,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC/E,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,iBAAiB,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAChG,OAAO,EAAE,mBAAmB,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.snapshotPlugin = exports.filePlugin = exports.a11ySnapshotPlugin = exports.sendKeysPlugin = exports.setUserAgentPlugin = exports.emulateMediaPlugin = exports.setViewportPlugin = void 0;
3
+ exports.snapshotPlugin = exports.filePlugin = exports.a11ySnapshotPlugin = exports.sendMousePlugin = exports.sendKeysPlugin = exports.setUserAgentPlugin = exports.emulateMediaPlugin = exports.setViewportPlugin = void 0;
4
4
  var setViewportPlugin_1 = require("./setViewportPlugin");
5
5
  Object.defineProperty(exports, "setViewportPlugin", { enumerable: true, get: function () { return setViewportPlugin_1.setViewportPlugin; } });
6
6
  var emulateMediaPlugin_1 = require("./emulateMediaPlugin");
@@ -9,6 +9,8 @@ var setUserAgentPlugin_1 = require("./setUserAgentPlugin");
9
9
  Object.defineProperty(exports, "setUserAgentPlugin", { enumerable: true, get: function () { return setUserAgentPlugin_1.setUserAgentPlugin; } });
10
10
  var sendKeysPlugin_1 = require("./sendKeysPlugin");
11
11
  Object.defineProperty(exports, "sendKeysPlugin", { enumerable: true, get: function () { return sendKeysPlugin_1.sendKeysPlugin; } });
12
+ var sendMousePlugin_1 = require("./sendMousePlugin");
13
+ Object.defineProperty(exports, "sendMousePlugin", { enumerable: true, get: function () { return sendMousePlugin_1.sendMousePlugin; } });
12
14
  var a11ySnapshotPlugin_1 = require("./a11ySnapshotPlugin");
13
15
  Object.defineProperty(exports, "a11ySnapshotPlugin", { enumerable: true, get: function () { return a11ySnapshotPlugin_1.a11ySnapshotPlugin; } });
14
16
  var filePlugin_1 = require("./filePlugin");
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAkE;AAA/C,sHAAA,iBAAiB,OAAA;AACpC,2DAAiE;AAAjD,wHAAA,kBAAkB,OAAA;AAClC,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,mDAAmE;AAA1D,gHAAA,cAAc,OAAA;AACvB,2DAA+E;AAAtE,wHAAA,kBAAkB,OAAA;AAC3B,2CAAgG;AAAjC,wGAAA,UAAU,OAAA;AACzE,mDAA6F;AAAzC,gHAAA,cAAc,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,yDAAkE;AAA/C,sHAAA,iBAAiB,OAAA;AACpC,2DAAiE;AAAjD,wHAAA,kBAAkB,OAAA;AAClC,2DAA0D;AAAjD,wHAAA,kBAAkB,OAAA;AAC3B,mDAAmE;AAA1D,gHAAA,cAAc,OAAA;AACvB,qDAAsE;AAA7D,kHAAA,eAAe,OAAA;AACxB,2DAA+E;AAAtE,wHAAA,kBAAkB,OAAA;AAC3B,2CAAgG;AAAjC,wGAAA,UAAU,OAAA;AACzE,mDAA6F;AAAzC,gHAAA,cAAc,OAAA"}
@@ -0,0 +1,24 @@
1
+ import { TestRunnerPlugin } from '@web/test-runner-core';
2
+ declare type MousePosition = [number, number];
3
+ declare type MouseButton = 'left' | 'middle' | 'right';
4
+ export declare type SendMousePayload = MovePayload | ClickPayload | DownPayload | UpPayload;
5
+ export declare type MovePayload = {
6
+ type: 'move';
7
+ position: MousePosition;
8
+ };
9
+ export declare type ClickPayload = {
10
+ type: 'click';
11
+ position: MousePosition;
12
+ button?: MouseButton;
13
+ };
14
+ export declare type DownPayload = {
15
+ type: 'down';
16
+ button?: MouseButton;
17
+ };
18
+ export declare type UpPayload = {
19
+ type: 'up';
20
+ button?: MouseButton;
21
+ };
22
+ export declare function sendMousePlugin(): TestRunnerPlugin<SendMousePayload>;
23
+ export {};
24
+ //# sourceMappingURL=sendMousePlugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sendMousePlugin.d.ts","sourceRoot":"","sources":["../src/sendMousePlugin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAKzD,aAAK,aAAa,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACtC,aAAK,WAAW,GAAG,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;AAE/C,oBAAY,gBAAgB,GAAG,WAAW,GAAG,YAAY,GAAG,WAAW,GAAG,SAAS,CAAC;AAEpF,oBAAY,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,CAAC;CACzB,CAAC;AAEF,oBAAY,YAAY,GAAG;IACzB,IAAI,EAAE,OAAO,CAAC;IACd,QAAQ,EAAE,aAAa,CAAC;IACxB,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,oBAAY,WAAW,GAAG;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AAEF,oBAAY,SAAS,GAAG;IACtB,IAAI,EAAE,IAAI,CAAC;IACX,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB,CAAC;AA+CF,wBAAgB,eAAe,IAAI,gBAAgB,CAAC,gBAAgB,CAAC,CAkHpE"}
@@ -0,0 +1,133 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sendMousePlugin = void 0;
4
+ function isObject(payload) {
5
+ return payload != null && typeof payload === 'object';
6
+ }
7
+ function isSendMousePayload(payload) {
8
+ const validTypes = ['move', 'click', 'down', 'up'];
9
+ const validButtons = ['left', 'middle', 'right'];
10
+ if (!isObject(payload)) {
11
+ throw new Error('You must provide a `SendMousePayload` object');
12
+ }
13
+ if (typeof payload.type !== 'string' || !validTypes.includes(payload.type)) {
14
+ throw new Error(`You must provide a type option with one of the following values: ${validTypes.join(', ')}.`);
15
+ }
16
+ if (['click', 'move'].includes(payload.type)) {
17
+ if (!Array.isArray(payload.position) ||
18
+ typeof payload.position[0] !== 'number' ||
19
+ typeof payload.position[1] !== 'number' ||
20
+ !Number.isInteger(payload.position[0]) ||
21
+ !Number.isInteger(payload.position[1])) {
22
+ throw new Error('You must provide a position option as a [x, y] tuple where x and y are integers.');
23
+ }
24
+ }
25
+ if (['click', 'up', 'down'].includes(payload.type)) {
26
+ if (typeof payload.button === 'string' && !validButtons.includes(payload.button)) {
27
+ throw new Error(`The button option must be one of the following values when provided: ${validButtons.join(', ')}.`);
28
+ }
29
+ }
30
+ return true;
31
+ }
32
+ function sendMousePlugin() {
33
+ return {
34
+ name: 'send-mouse-command',
35
+ async executeCommand({ command, payload, session }) {
36
+ if (command === 'send-mouse') {
37
+ if (!payload || !isSendMousePayload(payload)) {
38
+ throw new Error('You must provide a `SendMousePayload` object');
39
+ }
40
+ // handle specific behavior for playwright
41
+ if (session.browser.type === 'playwright') {
42
+ const page = session.browser.getPage(session.id);
43
+ switch (payload.type) {
44
+ case 'move':
45
+ await page.mouse.move(payload.position[0], payload.position[1]);
46
+ return true;
47
+ case 'click':
48
+ await page.mouse.click(payload.position[0], payload.position[1], {
49
+ button: payload.button,
50
+ });
51
+ return true;
52
+ case 'down':
53
+ await page.mouse.down({ button: payload.button });
54
+ return true;
55
+ case 'up':
56
+ await page.mouse.up({ button: payload.button });
57
+ return true;
58
+ }
59
+ }
60
+ // handle specific behavior for puppeteer
61
+ if (session.browser.type === 'puppeteer') {
62
+ const page = session.browser.getPage(session.id);
63
+ switch (payload.type) {
64
+ case 'move':
65
+ await page.mouse.move(payload.position[0], payload.position[1]);
66
+ return true;
67
+ case 'click':
68
+ await page.mouse.click(payload.position[0], payload.position[1], {
69
+ button: payload.button,
70
+ });
71
+ return true;
72
+ case 'down':
73
+ await page.mouse.down({ button: payload.button });
74
+ return true;
75
+ case 'up':
76
+ await page.mouse.up({ button: payload.button });
77
+ return true;
78
+ }
79
+ }
80
+ // handle specific behavior for webdriver
81
+ if (session.browser.type === 'webdriver') {
82
+ const page = session.browser;
83
+ switch (payload.type) {
84
+ case 'move':
85
+ await page.sendMouseMove(session.id, payload.position[0], payload.position[1]);
86
+ return true;
87
+ case 'click':
88
+ await page.sendMouseClick(session.id, payload.position[0], payload.position[1], payload.button);
89
+ return true;
90
+ case 'down':
91
+ await page.sendMouseDown(session.id, payload.button);
92
+ return true;
93
+ case 'up':
94
+ await page.sendMouseUp(session.id, payload.button);
95
+ return true;
96
+ }
97
+ }
98
+ // you might not be able to support all browser launchers
99
+ throw new Error(`Sending mouse is not supported for browser type ${session.browser.type}.`);
100
+ }
101
+ if (command === 'reset-mouse') {
102
+ // handle specific behavior for playwright
103
+ if (session.browser.type === 'playwright') {
104
+ const page = session.browser.getPage(session.id);
105
+ await page.mouse.up({ button: 'left' });
106
+ await page.mouse.up({ button: 'middle' });
107
+ await page.mouse.up({ button: 'right' });
108
+ await page.mouse.move(0, 0);
109
+ return true;
110
+ }
111
+ // handle specific behavior for puppeteer
112
+ if (session.browser.type === 'puppeteer') {
113
+ const page = session.browser.getPage(session.id);
114
+ await page.mouse.up({ button: 'left' });
115
+ await page.mouse.up({ button: 'middle' });
116
+ await page.mouse.up({ button: 'right' });
117
+ await page.mouse.move(0, 0);
118
+ return true;
119
+ }
120
+ // handle specific behavior for webdriver
121
+ if (session.browser.type === 'webdriver') {
122
+ const page = session.browser;
123
+ await page.resetMouse(session.id);
124
+ return true;
125
+ }
126
+ // you might not be able to support all browser launchers
127
+ throw new Error(`Resetting mouse is not supported for browser type ${session.browser.type}.`);
128
+ }
129
+ },
130
+ };
131
+ }
132
+ exports.sendMousePlugin = sendMousePlugin;
133
+ //# sourceMappingURL=sendMousePlugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sendMousePlugin.js","sourceRoot":"","sources":["../src/sendMousePlugin.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@web/test-runner-commands",
3
- "version": "0.5.10",
3
+ "version": "0.6.0",
4
4
  "publishConfig": {
5
5
  "access": "public"
6
6
  },
@@ -50,8 +50,8 @@
50
50
  },
51
51
  "devDependencies": {
52
52
  "@web/test-runner-chrome": "^0.10.2",
53
- "@web/test-runner-playwright": "^0.8.7",
54
- "@web/test-runner-webdriver": "^0.4.2",
53
+ "@web/test-runner-playwright": "^0.8.8",
54
+ "@web/test-runner-webdriver": "^0.5.0",
55
55
  "mocha": "^8.2.1"
56
56
  }
57
57
  }
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ export { Viewport, setViewportPlugin } from './setViewportPlugin';
2
2
  export { Media, emulateMediaPlugin } from './emulateMediaPlugin';
3
3
  export { setUserAgentPlugin } from './setUserAgentPlugin';
4
4
  export { sendKeysPlugin, SendKeysPayload } from './sendKeysPlugin';
5
+ export { sendMousePlugin, SendMousePayload } from './sendMousePlugin';
5
6
  export { a11ySnapshotPlugin, A11ySnapshotPayload } from './a11ySnapshotPlugin';
6
7
  export { WriteFilePayload, ReadFilePayload, RemoveFilePayload, filePlugin } from './filePlugin';
7
8
  export { SaveSnapshotPayload, SnapshotPluginConfig, snapshotPlugin } from './snapshotPlugin';
@@ -0,0 +1,191 @@
1
+ import { TestRunnerPlugin } from '@web/test-runner-core';
2
+ import type { ChromeLauncher } from '@web/test-runner-chrome';
3
+ import type { PlaywrightLauncher } from '@web/test-runner-playwright';
4
+ import type { WebdriverLauncher } from '@web/test-runner-webdriver';
5
+
6
+ type MousePosition = [number, number];
7
+ type MouseButton = 'left' | 'middle' | 'right';
8
+
9
+ export type SendMousePayload = MovePayload | ClickPayload | DownPayload | UpPayload;
10
+
11
+ export type MovePayload = {
12
+ type: 'move';
13
+ position: MousePosition;
14
+ };
15
+
16
+ export type ClickPayload = {
17
+ type: 'click';
18
+ position: MousePosition;
19
+ button?: MouseButton;
20
+ };
21
+
22
+ export type DownPayload = {
23
+ type: 'down';
24
+ button?: MouseButton;
25
+ };
26
+
27
+ export type UpPayload = {
28
+ type: 'up';
29
+ button?: MouseButton;
30
+ };
31
+
32
+ function isObject(payload: unknown): payload is Record<string, unknown> {
33
+ return payload != null && typeof payload === 'object';
34
+ }
35
+
36
+ function isSendMousePayload(payload: unknown): payload is SendMousePayload {
37
+ const validTypes = ['move', 'click', 'down', 'up'];
38
+ const validButtons = ['left', 'middle', 'right'];
39
+
40
+ if (!isObject(payload)) {
41
+ throw new Error('You must provide a `SendMousePayload` object');
42
+ }
43
+
44
+ if (typeof payload.type !== 'string' || !validTypes.includes(payload.type)) {
45
+ throw new Error(
46
+ `You must provide a type option with one of the following values: ${validTypes.join(', ')}.`,
47
+ );
48
+ }
49
+
50
+ if (['click', 'move'].includes(payload.type)) {
51
+ if (
52
+ !Array.isArray(payload.position) ||
53
+ typeof payload.position[0] !== 'number' ||
54
+ typeof payload.position[1] !== 'number' ||
55
+ !Number.isInteger(payload.position[0]) ||
56
+ !Number.isInteger(payload.position[1])
57
+ ) {
58
+ throw new Error(
59
+ 'You must provide a position option as a [x, y] tuple where x and y are integers.',
60
+ );
61
+ }
62
+ }
63
+
64
+ if (['click', 'up', 'down'].includes(payload.type)) {
65
+ if (typeof payload.button === 'string' && !validButtons.includes(payload.button)) {
66
+ throw new Error(
67
+ `The button option must be one of the following values when provided: ${validButtons.join(
68
+ ', ',
69
+ )}.`,
70
+ );
71
+ }
72
+ }
73
+
74
+ return true;
75
+ }
76
+
77
+ export function sendMousePlugin(): TestRunnerPlugin<SendMousePayload> {
78
+ return {
79
+ name: 'send-mouse-command',
80
+ async executeCommand({ command, payload, session }): Promise<any> {
81
+ if (command === 'send-mouse') {
82
+ if (!payload || !isSendMousePayload(payload)) {
83
+ throw new Error('You must provide a `SendMousePayload` object');
84
+ }
85
+
86
+ // handle specific behavior for playwright
87
+ if (session.browser.type === 'playwright') {
88
+ const page = (session.browser as PlaywrightLauncher).getPage(session.id);
89
+ switch (payload.type) {
90
+ case 'move':
91
+ await page.mouse.move(payload.position[0], payload.position[1]);
92
+ return true;
93
+ case 'click':
94
+ await page.mouse.click(payload.position[0], payload.position[1], {
95
+ button: payload.button,
96
+ });
97
+ return true;
98
+ case 'down':
99
+ await page.mouse.down({ button: payload.button });
100
+ return true;
101
+ case 'up':
102
+ await page.mouse.up({ button: payload.button });
103
+ return true;
104
+ }
105
+ }
106
+
107
+ // handle specific behavior for puppeteer
108
+ if (session.browser.type === 'puppeteer') {
109
+ const page = (session.browser as ChromeLauncher).getPage(session.id);
110
+ switch (payload.type) {
111
+ case 'move':
112
+ await page.mouse.move(payload.position[0], payload.position[1]);
113
+ return true;
114
+ case 'click':
115
+ await page.mouse.click(payload.position[0], payload.position[1], {
116
+ button: payload.button,
117
+ });
118
+ return true;
119
+ case 'down':
120
+ await page.mouse.down({ button: payload.button });
121
+ return true;
122
+ case 'up':
123
+ await page.mouse.up({ button: payload.button });
124
+ return true;
125
+ }
126
+ }
127
+
128
+ // handle specific behavior for webdriver
129
+ if (session.browser.type === 'webdriver') {
130
+ const page = session.browser as WebdriverLauncher;
131
+ switch (payload.type) {
132
+ case 'move':
133
+ await page.sendMouseMove(session.id, payload.position[0], payload.position[1]);
134
+ return true;
135
+ case 'click':
136
+ await page.sendMouseClick(
137
+ session.id,
138
+ payload.position[0],
139
+ payload.position[1],
140
+ payload.button,
141
+ );
142
+ return true;
143
+ case 'down':
144
+ await page.sendMouseDown(session.id, payload.button);
145
+ return true;
146
+ case 'up':
147
+ await page.sendMouseUp(session.id, payload.button);
148
+ return true;
149
+ }
150
+ }
151
+
152
+ // you might not be able to support all browser launchers
153
+ throw new Error(`Sending mouse is not supported for browser type ${session.browser.type}.`);
154
+ }
155
+
156
+ if (command === 'reset-mouse') {
157
+ // handle specific behavior for playwright
158
+ if (session.browser.type === 'playwright') {
159
+ const page = (session.browser as PlaywrightLauncher).getPage(session.id);
160
+ await page.mouse.up({ button: 'left' });
161
+ await page.mouse.up({ button: 'middle' });
162
+ await page.mouse.up({ button: 'right' });
163
+ await page.mouse.move(0, 0);
164
+ return true;
165
+ }
166
+
167
+ // handle specific behavior for puppeteer
168
+ if (session.browser.type === 'puppeteer') {
169
+ const page = (session.browser as ChromeLauncher).getPage(session.id);
170
+ await page.mouse.up({ button: 'left' });
171
+ await page.mouse.up({ button: 'middle' });
172
+ await page.mouse.up({ button: 'right' });
173
+ await page.mouse.move(0, 0);
174
+ return true;
175
+ }
176
+
177
+ // handle specific behavior for webdriver
178
+ if (session.browser.type === 'webdriver') {
179
+ const page = session.browser as WebdriverLauncher;
180
+ await page.resetMouse(session.id);
181
+ return true;
182
+ }
183
+
184
+ // you might not be able to support all browser launchers
185
+ throw new Error(
186
+ `Resetting mouse is not supported for browser type ${session.browser.type}.`,
187
+ );
188
+ }
189
+ },
190
+ };
191
+ }
package/CHANGELOG.md DELETED
@@ -1,290 +0,0 @@
1
- # @web/test-runner-commands
2
-
3
- ## 0.5.10
4
-
5
- ### Patch Changes
6
-
7
- - 33ada3d8: Align @web/test-runner-core version
8
-
9
- ## 0.5.9
10
-
11
- ### Patch Changes
12
-
13
- - 056ba8c8: Add sendKeys support for webdriver
14
-
15
- ## 0.5.8
16
-
17
- ### Patch Changes
18
-
19
- - 687d4750: Downgrade @rollup/plugin-node-resolve to v11
20
-
21
- ## 0.5.7
22
-
23
- ### Patch Changes
24
-
25
- - 09af51ac: Escape the snapshot contents to avoid problems in Firrefox and Webkit
26
-
27
- ## 0.5.6
28
-
29
- ### Patch Changes
30
-
31
- - cb693c71: Use block comments in snapshots to make them work in all browsers
32
-
33
- ## 0.5.5
34
-
35
- ### Patch Changes
36
-
37
- - b362288a: make snapshots work on all browsers
38
-
39
- ## 0.5.4
40
-
41
- ### Patch Changes
42
-
43
- - 270a633a: dynamic import web socket module
44
-
45
- ## 0.5.3
46
-
47
- ### Patch Changes
48
-
49
- - 3af6ff86: improve snapshot formatting
50
-
51
- ## 0.5.2
52
-
53
- ### Patch Changes
54
-
55
- - 91e0e617: add compareSnapshot function
56
-
57
- ## 0.5.1
58
-
59
- ### Patch Changes
60
-
61
- - 339d05f7: add snapshots plugin
62
-
63
- ## 0.5.0
64
-
65
- ### Minor Changes
66
-
67
- - c3ead4fa: Added support for holding and releasing keys to the sendKeys command. The command now supports two additional actions `down` and `up` which hold down, or release a key. This effectively allows to hold down modifier keys while pressing other keys, which allows key combinations such as `Shift+Tab`.
68
-
69
- @example
70
-
71
- ```ts
72
- await sendKeys({
73
- down: 'Shift',
74
- });
75
- await sendKeys({
76
- press: 'Tab',
77
- });
78
- await sendKeys({
79
- up: 'Shift',
80
- });
81
- ```
82
-
83
- ## 0.4.5
84
-
85
- ### Patch Changes
86
-
87
- - 21f53211: add commands for reading/writing files
88
-
89
- ## 0.4.4
90
-
91
- ### Patch Changes
92
-
93
- - a6a018da: fix type references
94
-
95
- ## 0.4.3
96
-
97
- ### Patch Changes
98
-
99
- - 1d9411a3: Export `sendKeysPlugin` from `@web/test-runner-commands/plugins`.
100
- Loosen the typing of the command payload.
101
- - d2389bac: Add a11ySnapshotPlugin to acquire the current accessibility tree from the browser:
102
-
103
- ```js
104
- import { a11ySnapshot, findAccessibilityNode } from '@web/test-runner-commands';
105
-
106
- // ...
107
-
108
- const nodeName = 'Label Text';
109
- const snapshot = await a11ySnapshot();
110
- const foundNode = findAccessibilityNode(snapshot, node => node.name === nodeName);
111
- expect(foundNode).to.not.be.null;
112
- ```
113
-
114
- ## 0.4.2
115
-
116
- ### Patch Changes
117
-
118
- - ce90c7c3: Add the `sendKeys` command
119
-
120
- Sends a string of keys for the browser to press (all at once, as with single keys
121
- or shortcuts; e.g. `{press: 'Tab'}` or `{press: 'Shift+a'}` or
122
- `{press: 'Option+ArrowUp}`) or type (in sequence, e.g. `{type: 'Your name'}`) natively.
123
-
124
- For specific documentation of the strings to leverage here, see the Playwright documentation,
125
- here:
126
-
127
- - `press`: https://playwright.dev/docs/api/class-keyboard#keyboardpresskey-options
128
- - `type`: https://playwright.dev/docs/api/class-keyboard#keyboardtypetext-options
129
-
130
- Or, the Puppeter documentation, here:
131
-
132
- - `press`: https://pptr.dev/#?product=Puppeteer&show=api-keyboardpresskey-options
133
- - `type`: https://pptr.dev/#?product=Puppeteer&show=api-keyboardtypetext-options
134
-
135
- @param payload An object including a `press` or `type` property an the associated string
136
- for the browser runner to apply via that input method.
137
-
138
- @example
139
-
140
- ```ts
141
- await sendKeys({
142
- press: 'Tab',
143
- });
144
- ```
145
-
146
- @example
147
-
148
- ```ts
149
- await sendKeys({
150
- type: 'Your address',
151
- });
152
- ```
153
-
154
- - Updated dependencies [ce90c7c3]
155
- - @web/test-runner-core@0.10.14
156
-
157
- ## 0.4.1
158
-
159
- ### Patch Changes
160
-
161
- - e3314b02: update dependency on core
162
-
163
- ## 0.4.0
164
-
165
- ### Minor Changes
166
-
167
- - a7d74fdc: drop support for node v10 and v11
168
- - 1dd7cd0e: version bump after breaking change in @web/test-runner-core
169
-
170
- ### Patch Changes
171
-
172
- - Updated dependencies [1dd7cd0e]
173
- - Updated dependencies [a7d74fdc]
174
- - @web/test-runner-core@0.10.0
175
-
176
- ## 0.3.0
177
-
178
- ### Minor Changes
179
-
180
- - 6e313c18: merged @web/test-runner-cli package into @web/test-runner
181
-
182
- ### Patch Changes
183
-
184
- - Updated dependencies [6e313c18]
185
- - Updated dependencies [0f613e0e]
186
- - @web/test-runner-core@0.9.0
187
-
188
- ## 0.2.1
189
-
190
- ### Patch Changes
191
-
192
- - 416c0d2: Update dependencies
193
- - Updated dependencies [aadf0fe]
194
- - @web/test-runner-core@0.8.4
195
-
196
- ## 0.2.0
197
-
198
- ### Minor Changes
199
-
200
- - 2291ca1: replaced HTTP with websocket for server-browser communication
201
-
202
- this improves test speed, especially when a test file makes a lot of concurrent requests
203
- it lets us us catch more errors during test execution, and makes us catch them faster
204
-
205
- ### Patch Changes
206
-
207
- - Updated dependencies [2291ca1]
208
- - @web/test-runner-core@0.8.0
209
-
210
- ## 0.1.6
211
-
212
- ### Patch Changes
213
-
214
- - ab97aa8: publish browser folder
215
- - Updated dependencies [ab97aa8]
216
- - @web/test-runner-core@0.7.13
217
-
218
- ## 0.1.5
219
-
220
- ### Patch Changes
221
-
222
- - abf811f: improved error message when session id is missing
223
- - Updated dependencies [431ec8f]
224
- - @web/test-runner-core@0.7.9
225
-
226
- ## 0.1.4
227
-
228
- ### Patch Changes
229
-
230
- - 632eb67: export browser and node types
231
-
232
- ## 0.1.3
233
-
234
- ### Patch Changes
235
-
236
- - ce2a2e6: align dependencies
237
-
238
- ## 0.1.2
239
-
240
- ### Patch Changes
241
-
242
- - 519e6e2: made the plugins import work on node v10
243
-
244
- ## 0.1.1
245
-
246
- ### Patch Changes
247
-
248
- - aa65fd1: run build before publishing
249
- - Updated dependencies [aa65fd1]
250
- - @web/test-runner-core@0.7.1
251
-
252
- ## 0.1.0
253
-
254
- ### Minor Changes
255
-
256
- - fdcf2e5: Merged test runner server into core, and made it no longer possible configure a different server.
257
-
258
- The test runner relies on the server for many things, merging it into core makes the code more maintainable. The server is composable, you can proxy requests to other servers and we can look into adding more composition APIs later.
259
-
260
- - 9be1f95: Added native node es module entrypoints. This is a breaking change. Before, native node es module imports would import a CJS module as a default import and require destructuring afterwards:
261
-
262
- ```js
263
- import playwrightModule from '@web/test-runner-playwright';
264
-
265
- const { playwrightLauncher } = playwrightModule;
266
- ```
267
-
268
- Now, the exports are only available directly as a named export:
269
-
270
- ```js
271
- import { playwrightLauncher } from '@web/test-runner-playwright';
272
- ```
273
-
274
- ### Patch Changes
275
-
276
- - 62ff8b2: make tests work on windows
277
- - Updated dependencies [cdddf68]
278
- - Updated dependencies [fdcf2e5]
279
- - Updated dependencies [62ff8b2]
280
- - Updated dependencies [9be1f95]
281
- - @web/test-runner-core@0.7.0
282
-
283
- ## 0.0.1
284
-
285
- ### Patch Changes
286
-
287
- - 74cc129: implement commands API
288
- - Updated dependencies [02a3926]
289
- - Updated dependencies [74cc129]
290
- - @web/test-runner-core@0.6.22