@le-space/playwright 0.9.2 → 0.9.4

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.
Files changed (3) hide show
  1. package/index.d.ts +60 -0
  2. package/index.js +65 -4
  3. package/package.json +3 -3
package/index.d.ts CHANGED
@@ -133,6 +133,13 @@ interface RelayButtonDriverOptions {
133
133
  deleteButtonName?: string;
134
134
  refreshButtonName?: string;
135
135
  advancedToggleName?: string;
136
+ /**
137
+ * The distance in CSS pixels the widget treats as a drag rather than a tap.
138
+ * Kept as an option because it is the widget's number, not the test's:
139
+ * `dragThreshold` in `fab-position.ts`. A driver that guessed it would drive
140
+ * a press the widget still reads as a click.
141
+ */
142
+ dragThresholdPx?: number;
136
143
  }
137
144
  interface ProvisionRelayOptions {
138
145
  accountAddress: string;
@@ -267,6 +274,59 @@ declare class RelayButtonDriver {
267
274
  readonly page: Page;
268
275
  readonly options: Required<RelayButtonDriverOptions>;
269
276
  constructor(page: Page, options?: RelayButtonDriverOptions);
277
+ /** The launcher itself — the thing a consumer places, and now drags. */
278
+ launcher(): Locator;
279
+ /**
280
+ * Where the launcher is, in viewport coordinates.
281
+ *
282
+ * The widget positions it with `position: fixed` and its own offsets, so
283
+ * there is no layout box on any wrapper to read — an earlier consumer tried
284
+ * exactly that and got 0×0, because a fixed child leaves its parent empty.
285
+ * The launcher's own box is the only honest source.
286
+ */
287
+ launcherBox(): Promise<{
288
+ x: number;
289
+ y: number;
290
+ width: number;
291
+ height: number;
292
+ }>;
293
+ /**
294
+ * Drag the launcher by an offset, as a finger or a mouse would.
295
+ *
296
+ * Several intermediate moves rather than one jump: the widget follows
297
+ * `pointermove` and decides between a tap and a drag on the distance
298
+ * travelled, so a single move from A to B exercises neither the threshold nor
299
+ * the clamping on the way. `steps` is deliberately low by default — enough to
300
+ * cross the threshold and to move afterwards, few enough to stay quick.
301
+ *
302
+ * Returns the box before and after, because every assertion worth making
303
+ * compares the two and reading it twice at the call site invites reading it
304
+ * at the wrong moment.
305
+ */
306
+ dragLauncherBy(dx: number, dy: number, options?: {
307
+ steps?: number;
308
+ }): Promise<{
309
+ before: {
310
+ x: number;
311
+ y: number;
312
+ width: number;
313
+ height: number;
314
+ };
315
+ after: {
316
+ x: number;
317
+ y: number;
318
+ width: number;
319
+ height: number;
320
+ };
321
+ }>;
322
+ /**
323
+ * Press and move less than the threshold — a tap, as far as the widget is
324
+ * concerned, however jittery the hand holding the phone.
325
+ *
326
+ * This is the half that is easy to leave untested and expensive to get wrong:
327
+ * a launcher that reads a one-pixel wobble as a drag never opens at all.
328
+ */
329
+ tapLauncherWithWobble(): Promise<void>;
270
330
  deployButton(): Locator;
271
331
  instance(instanceName: string): Locator;
272
332
  /**
package/index.js CHANGED
@@ -297,9 +297,72 @@ var RelayButtonDriver = class {
297
297
  deployButtonName: options.deployButtonName ?? "Deploy Relay",
298
298
  deleteButtonName: options.deleteButtonName ?? "Delete",
299
299
  refreshButtonName: options.refreshButtonName ?? "Refresh",
300
- advancedToggleName: options.advancedToggleName ?? "Advanced"
300
+ advancedToggleName: options.advancedToggleName ?? "Advanced",
301
+ dragThresholdPx: options.dragThresholdPx ?? 6
301
302
  };
302
303
  }
304
+ /** The launcher itself — the thing a consumer places, and now drags. */
305
+ launcher() {
306
+ return this.page.getByRole("button", { name: this.options.launcherName });
307
+ }
308
+ /**
309
+ * Where the launcher is, in viewport coordinates.
310
+ *
311
+ * The widget positions it with `position: fixed` and its own offsets, so
312
+ * there is no layout box on any wrapper to read — an earlier consumer tried
313
+ * exactly that and got 0×0, because a fixed child leaves its parent empty.
314
+ * The launcher's own box is the only honest source.
315
+ */
316
+ async launcherBox() {
317
+ const launcher = this.launcher();
318
+ await launcher.waitFor({ state: "visible", timeout: 3e4 });
319
+ const box = await launcher.boundingBox();
320
+ if (!box) throw new Error("The relay button launcher has no bounding box; is it rendered?");
321
+ return box;
322
+ }
323
+ /**
324
+ * Drag the launcher by an offset, as a finger or a mouse would.
325
+ *
326
+ * Several intermediate moves rather than one jump: the widget follows
327
+ * `pointermove` and decides between a tap and a drag on the distance
328
+ * travelled, so a single move from A to B exercises neither the threshold nor
329
+ * the clamping on the way. `steps` is deliberately low by default — enough to
330
+ * cross the threshold and to move afterwards, few enough to stay quick.
331
+ *
332
+ * Returns the box before and after, because every assertion worth making
333
+ * compares the two and reading it twice at the call site invites reading it
334
+ * at the wrong moment.
335
+ */
336
+ async dragLauncherBy(dx, dy, options = {}) {
337
+ const before = await this.launcherBox();
338
+ const steps = Math.max(2, options.steps ?? 8);
339
+ const startX = before.x + before.width / 2;
340
+ const startY = before.y + before.height / 2;
341
+ await this.page.mouse.move(startX, startY);
342
+ await this.page.mouse.down();
343
+ for (let step = 1; step <= steps; step += 1) {
344
+ await this.page.mouse.move(startX + dx * step / steps, startY + dy * step / steps);
345
+ }
346
+ await this.page.mouse.up();
347
+ return { before, after: await this.launcherBox() };
348
+ }
349
+ /**
350
+ * Press and move less than the threshold — a tap, as far as the widget is
351
+ * concerned, however jittery the hand holding the phone.
352
+ *
353
+ * This is the half that is easy to leave untested and expensive to get wrong:
354
+ * a launcher that reads a one-pixel wobble as a drag never opens at all.
355
+ */
356
+ async tapLauncherWithWobble() {
357
+ const box = await this.launcherBox();
358
+ const x = box.x + box.width / 2;
359
+ const y = box.y + box.height / 2;
360
+ const wobble = Math.max(1, Math.floor(this.options.dragThresholdPx / 2) - 1);
361
+ await this.page.mouse.move(x, y);
362
+ await this.page.mouse.down();
363
+ await this.page.mouse.move(x + wobble, y + wobble);
364
+ await this.page.mouse.up();
365
+ }
303
366
  deployButton() {
304
367
  return this.page.getByRole("button", {
305
368
  name: this.options.deployButtonName
@@ -322,9 +385,7 @@ var RelayButtonDriver = class {
322
385
  return this.page.getByLabel(this.options.sshPublicKeyLabel).or(this.page.getByPlaceholder(this.options.sshPublicKeyPlaceholder)).first();
323
386
  }
324
387
  async prepare(options) {
325
- const launcher = this.page.getByRole("button", {
326
- name: this.options.launcherName
327
- });
388
+ const launcher = this.launcher();
328
389
  await launcher.waitFor({ state: "visible", timeout: 6e4 });
329
390
  await launcher.click();
330
391
  await this.instanceNameField().fill(options.instanceName);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@le-space/playwright",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Reusable Playwright fixtures and Relay Button lifecycle helpers.",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -27,8 +27,8 @@
27
27
  "url": "https://github.com/NiKrause/relay-button/issues"
28
28
  },
29
29
  "dependencies": {
30
- "@le-space/aleph-bootstrap": "0.9.2",
31
- "@le-space/core": "0.9.2"
30
+ "@le-space/aleph-bootstrap": "0.9.4",
31
+ "@le-space/core": "0.9.4"
32
32
  },
33
33
  "peerDependencies": {
34
34
  "@playwright/test": ">=1.61.1 <1.62.0"