Skip to content

Commit 4487590

Browse files
authored
test: added debug helpers (#703)
1 parent 853302c commit 4487590

File tree

4 files changed

+122
-3
lines changed

4 files changed

+122
-3
lines changed

docs/how-to-add-visual-test.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,31 @@ See more: [Command line](https://playwright.dev/docs/test-cli)
9595
npm run playwright:docker:report
9696
```
9797

98+
## Writing Complex Tests
99+
100+
### Editor helpers
101+
The core also includes helper functions designed to simplify UI interactions, testing, and debugging. These allow you to quickly switch editor modes, paste and clear text, visually highlight elements, and inspect their HTML markup during development.
102+
103+
See:
104+
```
105+
tests/playwright/core/editor.ts
106+
tests/playwright/core/helpers.ts
107+
```
108+
109+
## Clipboard specifics
110+
111+
Playwright clipboard support varies across browsers. Keep this in mind when writing copy-paste tests.
112+
113+
## Click testing
114+
115+
Playwright provides three main ways to perform clicks:
116+
117+
- `locator.click()`
118+
- `element.dispatchEvent('click', params)`
119+
- `page.mouse.click(x, y)`
120+
121+
Choose the method based on your code specifics. For events involving bubbling, consider using `dispatchEvent` with `{ bubbles: true }`.
122+
98123
## Useful Links
99124

100125
- [Playwright API](https://playwright.dev/docs/api/class-test)

tests/playwright/core/helpers.ts

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type {BrowserContext, Page} from '@playwright/test';
1+
import type {BrowserContext, Locator, Page} from '@playwright/test';
22

33
class Keymap {
44
readonly selectAll = 'ControlOrMeta+A';
@@ -31,3 +31,92 @@ export class PlaywrightHelpers {
3131
});
3232
}
3333
}
34+
35+
export class DebugHelpers {
36+
private readonly page;
37+
38+
constructor({page}: {page: Page}) {
39+
this.page = page;
40+
}
41+
42+
/**
43+
* Draws a red dot on the screen at the given (x, y) coordinates.
44+
* Useful for debugging click locations.
45+
*
46+
* Example:
47+
* ```ts
48+
* const box = await element.boundingBox();
49+
* if (box) {
50+
* const { x, y } = box;
51+
* await element.dispatchEvent('click', {
52+
* bubbles: true,
53+
* cancelable: true,
54+
* composed: true,
55+
* clientX: Math.floor(x + 2),
56+
* clientY: Math.floor(y + 2),
57+
* });
58+
* await markClick(page, x + 2, y + 2);
59+
* }
60+
* ```
61+
*/
62+
async markClick(x: number, y: number) {
63+
await this.page.evaluate(
64+
({x, y}) => {
65+
const dot = document.createElement('div');
66+
dot.style.position = 'absolute';
67+
dot.style.width = '6px';
68+
dot.style.height = '6px';
69+
dot.style.borderRadius = '50%';
70+
dot.style.background = 'red';
71+
dot.style.zIndex = '999999';
72+
dot.style.pointerEvents = 'none';
73+
dot.style.left = `${x}px`;
74+
dot.style.top = `${y}px`;
75+
document.body.appendChild(dot);
76+
},
77+
{x, y},
78+
);
79+
}
80+
81+
/**
82+
* Logs the outer HTML of a given locator.
83+
* Useful for debugging or verifying the exact markup of an element.
84+
*/
85+
async logHtml(locator: Locator) {
86+
const html = await locator.evaluate((el) => el.outerHTML);
87+
console.log('Outer HTML:', html);
88+
}
89+
90+
/**
91+
* Highlights a given locator by applying CSS styles.
92+
* Useful for visually identifying elements during testing or debugging.
93+
*/
94+
async highlight(
95+
locator: Locator,
96+
{
97+
outline = true,
98+
background = true,
99+
border = false,
100+
}: {
101+
outline?: boolean;
102+
background?: boolean;
103+
border?: boolean;
104+
} = {},
105+
) {
106+
await locator.evaluate(
107+
(el, opts) => {
108+
if (opts.outline) {
109+
el.style.outline = '2px solid red';
110+
el.style.outlineOffset = '2px';
111+
}
112+
if (opts.border) {
113+
el.style.border = '2px solid red';
114+
}
115+
if (opts.background) {
116+
el.style.backgroundColor = 'rgba(255, 0, 0, 0.05)';
117+
}
118+
},
119+
{outline, background, border},
120+
);
121+
}
122+
}

tests/playwright/core/index.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import {test as base, expect} from '@playwright/experimental-ct-react';
22

33
import {MarkdownEditorPage} from './editor';
44
import {expectScreenshot} from './expectScreenshot';
5-
import {PlaywrightHelpers} from './helpers';
5+
import {DebugHelpers, PlaywrightHelpers} from './helpers';
66
import {mount} from './mount';
77
import type {Fixtures} from './types';
88
import {wait} from './wait';
@@ -19,6 +19,10 @@ export const test = base.extend<Fixtures>({
1919
const helpers = new PlaywrightHelpers({page, context});
2020
await use(helpers);
2121
},
22+
debug: async ({page}, use) => {
23+
const debug = new DebugHelpers({page});
24+
await use(debug);
25+
},
2226
platform: [process.platform, {scope: 'test'}],
2327
});
2428

tests/playwright/core/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
} from '@playwright/test';
1414

1515
import type {MarkdownEditorPage} from './editor';
16-
import type {PlaywrightHelpers} from './helpers';
16+
import type {DebugHelpers, PlaywrightHelpers} from './helpers';
1717

1818
interface ComponentFixtures {
1919
mount<HooksConfig>(
@@ -36,6 +36,7 @@ export type Fixtures = {
3636
wait: WaitFixture;
3737
editor: MarkdownEditorPage;
3838
helpers: PlaywrightHelpers;
39+
debug: DebugHelpers;
3940
platform: NodeJS.Platform;
4041
};
4142

0 commit comments

Comments
 (0)