Skip to content

Commit d93964e

Browse files
authored
test: added visual toolbar tests (#768)
1 parent dce8e11 commit d93964e

File tree

31 files changed

+174
-13
lines changed

31 files changed

+174
-13
lines changed

src/toolbar/FlexToolbar.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ export function FlexToolbar<E>(props: FlexToolbarProps<E>) {
6464
{dots?.length && (
6565
<ToolbarListButton
6666
qa="g-md-toolbar-more-action"
67+
qaMenu="g-md-toolbar-more-menu"
6768
data={dots}
6869
icon={{data: Ellipsis}}
6970
title={props.dotsTitle}

src/toolbar/ToolbarListButton.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,10 @@ const b = cn('toolbar-list-button');
2323

2424
export type {ToolbarListButtonData};
2525

26-
export type ToolbarListButtonProps<E> = ToolbarBaseProps<E> & ToolbarListButtonData<E>;
26+
export type ToolbarListButtonProps<E> = ToolbarBaseProps<E> &
27+
ToolbarListButtonData<E> & {
28+
qaMenu?: string;
29+
};
2730

2831
export function ToolbarListButton<E>({
2932
className,
@@ -37,6 +40,7 @@ export function ToolbarListButton<E>({
3740
alwaysActive,
3841
replaceActiveIcon,
3942
qa,
43+
qaMenu,
4044
}: ToolbarListButtonProps<E>) {
4145
const [anchorElement, setAnchorElement] = useElementState();
4246
const [open, , hide, toggleOpen] = useBooleanState(false);
@@ -83,7 +87,7 @@ export function ToolbarListButton<E>({
8387
{buttonContent}
8488
</ToolbarButtonView>
8589
<Popup anchorElement={anchorElement} open={popupOpen} onOpenChange={hide}>
86-
<Menu size="l" className={b('menu')}>
90+
<Menu size="l" className={b('menu')} qa={qaMenu}>
8791
{data
8892
.map((data) => {
8993
const {
@@ -136,6 +140,7 @@ export function ToolbarListButton<E>({
136140
placement="left"
137141
modal={false}
138142
disabled={hideHintWhenDisabled}
143+
qa="g-md-toolbar-action-disabled-hint"
139144
key={id}
140145
>
141146
{(props, ref) => (

tests/playwright/core/editor.ts

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ class MarkdownEditorLocators {
1313
readonly settingsContent;
1414
readonly toolbar;
1515
readonly toolbarMoreActionButton;
16+
readonly toolbarActionDisabledHint;
17+
readonly toolbarMoreMenu;
1618
readonly cmAutocomplete;
1719

1820
constructor(page: Page) {
@@ -29,6 +31,8 @@ class MarkdownEditorLocators {
2931
// editor
3032
this.contenteditable = this.editor.locator('[contenteditable=true]');
3133
this.toolbarMoreActionButton = this.editor.getByTestId('g-md-toolbar-more-action');
34+
this.toolbarActionDisabledHint = page.getByTestId('g-md-toolbar-action-disabled-hint');
35+
this.toolbarMoreMenu = page.getByTestId('g-md-toolbar-more-menu');
3236

3337
this.cmAutocomplete = this.editor.locator('.cm-tooltip-autocomplete');
3438
}
@@ -39,9 +43,9 @@ type PasteData = Partial<Record<DataTransferType, string>>;
3943
type VisibleState = 'attached' | 'detached' | 'visible' | 'hidden' | undefined;
4044

4145
export class MarkdownEditorPage {
46+
readonly locators;
4247
protected readonly page: Page;
4348
protected readonly expect: Expect;
44-
protected readonly locators;
4549

4650
constructor(page: Page, expect: Expect) {
4751
this.page = page;
@@ -175,6 +179,23 @@ export class MarkdownEditorPage {
175179
await this.locators.toolbarMoreActionButton.click();
176180
}
177181

182+
async openToolbarMoreMenu() {
183+
const visible = await this.locators.toolbarMoreMenu.isVisible();
184+
if (!visible) {
185+
await this.clickToolbarMoreActionButton();
186+
await this.locators.toolbarMoreMenu.waitFor({state: 'visible'});
187+
}
188+
}
189+
190+
async hoverToolbarMoreAction(label: string) {
191+
await this.locators.toolbarMoreMenu.waitFor({state: 'visible'});
192+
await this.getToolbarButton(label).hover({force: true});
193+
}
194+
195+
async waitForToolbarActionDisabledHint() {
196+
await this.locators.toolbarActionDisabledHint.waitFor({state: 'visible'});
197+
}
198+
178199
/**
179200
* Clicks a toolbar button using its aria-label
180201
*/

tests/playwright/core/expectScreenshot.ts

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,21 +12,23 @@ export const expectScreenshot: PlaywrightFixture<ExpectScreenshotFixture> = asyn
1212
testInfo,
1313
) => {
1414
const expectScreenshot: ExpectScreenshotFixture = async ({
15+
fullPage,
1516
component,
1617
nameSuffix,
1718
themes: paramsThemes,
1819
...pageScreenshotOptions
1920
} = defaultParams) => {
2021
const captureScreenshot = async () => {
21-
return (
22-
(component || page.locator('.playwright-wrapper-test'))
23-
// TODO: @makhnatkin make more flexible
24-
.locator('.playground__editor-markup')
25-
.screenshot({
26-
animations: 'disabled',
27-
...pageScreenshotOptions,
28-
})
29-
);
22+
const locator = fullPage
23+
? page
24+
: component ||
25+
page.locator('.playwright-wrapper-test').locator('.playground__editor-markup');
26+
27+
return locator.screenshot({
28+
animations: 'disabled',
29+
style: '.playground__pm-selection {display:none;}',
30+
...pageScreenshotOptions,
31+
});
3032
};
3133

3234
const nameScreenshot =
@@ -52,6 +54,8 @@ export const expectScreenshot: PlaywrightFixture<ExpectScreenshotFixture> = asyn
5254

5355
if (themes?.includes('light')) {
5456
await page.emulateMedia({colorScheme: 'light'});
57+
// sometimes theme doesn't change in webkit without timeout
58+
await page.waitForTimeout(100);
5559

5660
expect(await captureScreenshot()).toMatchSnapshot({
5761
name: `${nameScreenshot} light.png`,
@@ -60,6 +64,8 @@ export const expectScreenshot: PlaywrightFixture<ExpectScreenshotFixture> = asyn
6064

6165
if (themes?.includes('dark')) {
6266
await page.emulateMedia({colorScheme: 'dark'});
67+
// sometimes theme doesn't change in webkit without timeout
68+
await page.waitForTimeout(100);
6369

6470
expect(await captureScreenshot()).toMatchSnapshot({
6571
name: `${nameScreenshot} dark.png`,

tests/playwright/core/mount.tsx

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import dd from 'ts-dedent';
2+
13
import type {MountFixture, PlaywrightFixture} from './types';
24

35
export const mount: PlaywrightFixture<MountFixture> = async ({mount: baseMount}, use) => {
@@ -14,10 +16,25 @@ export const mount: PlaywrightFixture<MountFixture> = async ({mount: baseMount},
1416
}}
1517
className="playwright-wrapper-test"
1618
>
19+
{/* reset body styles */}
20+
<style>{'body {margin: 0}'}</style>
1721
{/* Do not scale buttons while clicking. Floating UI might position its elements differently in every test run. */}
1822
<style>{'.g-button, .g-button::after { transform: scale(1) !important; }'}</style>
1923
{/* Do not show ProseMirror dev toolkit. */}
2024
<style>{'.__prosemirror-dev-toolkit__ {display: none;}'}</style>
25+
{options?.hidePlaygroundBlocks && (
26+
<style>
27+
{dd`
28+
.playground__header,
29+
.playground__actions {
30+
display: none;
31+
}
32+
.playground__pm-selection {
33+
pointer-events: none;
34+
}
35+
`}
36+
</style>
37+
)}
2138
{component}
2239
</div>,
2340
options,

tests/playwright/core/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ interface ComponentFixtures {
2323
options?: MountOptions<HooksConfig> & {
2424
width?: number | string;
2525
rootStyle?: React.CSSProperties;
26+
hidePlaygroundBlocks?: boolean;
2627
},
2728
): Promise<MountResult>;
2829
}
@@ -60,5 +61,5 @@ export interface WaitFixture {
6061
export interface CaptureScreenshotParams extends PageScreenshotOptions {
6162
nameSuffix?: string;
6263
component?: Locator | Page;
63-
themes?: Array<'light' | 'dark'>;
64+
themes?: ReadonlyArray<'light' | 'dark'>;
6465
}
Loading
Loading
Loading

0 commit comments

Comments
 (0)