Skip to content

Commit 38a9ec0

Browse files
authored
test: added Link visual tests (#799)
1 parent 2f4bae6 commit 38a9ec0

10 files changed

+204
-95
lines changed

tests/playwright/core/editor.ts

Lines changed: 92 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -17,82 +17,6 @@ type MarkdownEditorToolbarsLocators = Record<
1717
Locator
1818
>;
1919

20-
class YfmTable {
21-
readonly buttonPlusRowLocator;
22-
readonly buttonPlusColumnLocator;
23-
private readonly tableWrapperLocator;
24-
25-
private readonly rowButtonLocator;
26-
private readonly columnButtonLocator;
27-
private readonly cellMenus: Readonly<Record<YfmTableCellMenuType, Locator>>;
28-
private readonly cellMenuActions: Readonly<Record<YfmTableActionKind, Locator>>;
29-
30-
constructor(page: Page) {
31-
this.tableWrapperLocator = page.getByTestId('g-md-yfm-table-wrapper');
32-
this.buttonPlusRowLocator = page.getByTestId('g-md-yfm-table-plus-row');
33-
this.buttonPlusColumnLocator = page.getByTestId('g-md-yfm-table-plus-column');
34-
35-
this.rowButtonLocator = page.getByTestId('g-md-yfm-table-row-btn');
36-
this.columnButtonLocator = page.getByTestId('g-md-yfm-table-column-btn');
37-
this.cellMenus = {
38-
row: page.getByTestId('g-md-yfm-table-row-menu'),
39-
column: page.getByTestId('g-md-yfm-table-column-menu'),
40-
};
41-
this.cellMenuActions = {
42-
'add-column-after': page.getByTestId('g-md-yfm-table-action-add-column-after'),
43-
'add-column-before': page.getByTestId('g-md-yfm-table-action-add-column-before'),
44-
'add-row-after': page.getByTestId('g-md-yfm-table-action-add-row-after'),
45-
'add-row-before': page.getByTestId('g-md-yfm-table-action-add-row-before'),
46-
'remove-column': page.getByTestId('g-md-yfm-table-action-remove-column'),
47-
'remove-row': page.getByTestId('g-md-yfm-table-action-remove-row'),
48-
'remove-table': page.getByTestId('g-md-yfm-table-action-remove-table'),
49-
};
50-
}
51-
52-
getMenuLocator(type: YfmTableCellMenuType) {
53-
return this.cellMenus[type];
54-
}
55-
56-
async getTable(locator?: Locator) {
57-
return locator?.locator(this.tableWrapperLocator) ?? this.tableWrapperLocator;
58-
}
59-
60-
async getRows(table?: Locator) {
61-
return (table || (await this.getTable())).first().locator('table > tbody > tr');
62-
}
63-
64-
async getCells(table?: Locator) {
65-
return (table || (await this.getTable())).first().locator('table > tbody > tr > td');
66-
}
67-
68-
async getRowButtons(table?: Locator) {
69-
return (table || (await this.getTable())).first().locator(this.rowButtonLocator);
70-
}
71-
72-
async getColumnButtons(table?: Locator) {
73-
return (table || (await this.getTable())).first().locator(this.columnButtonLocator);
74-
}
75-
76-
async doCellAction(menuType: YfmTableCellMenuType, kind: YfmTableActionKind) {
77-
const menu = this.cellMenus[menuType];
78-
await menu.waitFor({state: 'visible'});
79-
await menu.locator(this.cellMenuActions[kind]).click();
80-
await menu.waitFor({state: 'hidden'});
81-
}
82-
83-
async clickPlusRow(locator?: Locator) {
84-
const btnLoc = this.buttonPlusRowLocator;
85-
const loc = locator?.locator(btnLoc) ?? btnLoc;
86-
await loc.click();
87-
}
88-
89-
async clickPlusColumn(locator?: Locator) {
90-
const btnLoc = this.buttonPlusColumnLocator;
91-
const loc = locator?.locator(btnLoc) ?? btnLoc;
92-
await loc.click();
93-
}
94-
}
95-
9620
class Colorify {
9721
protected readonly page: Page;
9822
protected readonly expect: Expect;
@@ -166,6 +90,20 @@ class Image {
16690
}
16791
}
16892

93+
class Link {
94+
protected readonly expect: Expect;
95+
protected readonly form: Locator;
96+
97+
constructor(page: Page, expect: Expect) {
98+
this.expect = expect;
99+
this.form = page.getByTestId('g-md-link-form');
100+
}
101+
102+
async assertFormToBeVisible() {
103+
await this.expect(this.form).toBeVisible();
104+
}
105+
}
106+
169107
class YfmNote {
170108
protected readonly yfmNoteToolbar: Locator;
171109

@@ -179,6 +117,82 @@ class YfmNote {
179117
}
180118
}
181119

120+
class YfmTable {
121+
readonly buttonPlusRowLocator;
122+
readonly buttonPlusColumnLocator;
123+
private readonly tableWrapperLocator;
124+
125+
private readonly rowButtonLocator;
126+
private readonly columnButtonLocator;
127+
private readonly cellMenus: Readonly<Record<YfmTableCellMenuType, Locator>>;
128+
private readonly cellMenuActions: Readonly<Record<YfmTableActionKind, Locator>>;
129+
130+
constructor(page: Page) {
131+
this.tableWrapperLocator = page.getByTestId('g-md-yfm-table-wrapper');
132+
this.buttonPlusRowLocator = page.getByTestId('g-md-yfm-table-plus-row');
133+
this.buttonPlusColumnLocator = page.getByTestId('g-md-yfm-table-plus-column');
134+
135+
this.rowButtonLocator = page.getByTestId('g-md-yfm-table-row-btn');
136+
this.columnButtonLocator = page.getByTestId('g-md-yfm-table-column-btn');
137+
this.cellMenus = {
138+
row: page.getByTestId('g-md-yfm-table-row-menu'),
139+
column: page.getByTestId('g-md-yfm-table-column-menu'),
140+
};
141+
this.cellMenuActions = {
142+
'add-column-after': page.getByTestId('g-md-yfm-table-action-add-column-after'),
143+
'add-column-before': page.getByTestId('g-md-yfm-table-action-add-column-before'),
144+
'add-row-after': page.getByTestId('g-md-yfm-table-action-add-row-after'),
145+
'add-row-before': page.getByTestId('g-md-yfm-table-action-add-row-before'),
146+
'remove-column': page.getByTestId('g-md-yfm-table-action-remove-column'),
147+
'remove-row': page.getByTestId('g-md-yfm-table-action-remove-row'),
148+
'remove-table': page.getByTestId('g-md-yfm-table-action-remove-table'),
149+
};
150+
}
151+
152+
getMenuLocator(type: YfmTableCellMenuType) {
153+
return this.cellMenus[type];
154+
}
155+
156+
async getTable(locator?: Locator) {
157+
return locator?.locator(this.tableWrapperLocator) ?? this.tableWrapperLocator;
158+
}
159+
160+
async getRows(table?: Locator) {
161+
return (table || (await this.getTable())).first().locator('table > tbody > tr');
162+
}
163+
164+
async getCells(table?: Locator) {
165+
return (table || (await this.getTable())).first().locator('table > tbody > tr > td');
166+
}
167+
168+
async getRowButtons(table?: Locator) {
169+
return (table || (await this.getTable())).first().locator(this.rowButtonLocator);
170+
}
171+
172+
async getColumnButtons(table?: Locator) {
173+
return (table || (await this.getTable())).first().locator(this.columnButtonLocator);
174+
}
175+
176+
async doCellAction(menuType: YfmTableCellMenuType, kind: YfmTableActionKind) {
177+
const menu = this.cellMenus[menuType];
178+
await menu.waitFor({state: 'visible'});
179+
await menu.locator(this.cellMenuActions[kind]).click();
180+
await menu.waitFor({state: 'hidden'});
181+
}
182+
183+
async clickPlusRow(locator?: Locator) {
184+
const btnLoc = this.buttonPlusRowLocator;
185+
const loc = locator?.locator(btnLoc) ?? btnLoc;
186+
await loc.click();
187+
}
188+
189+
async clickPlusColumn(locator?: Locator) {
190+
const btnLoc = this.buttonPlusColumnLocator;
191+
const loc = locator?.locator(btnLoc) ?? btnLoc;
192+
await loc.click();
193+
}
194+
}
195+
182196
class MarkdownEditorLocators {
183197
readonly component;
184198
readonly contenteditable;
@@ -228,6 +242,7 @@ export class MarkdownEditorPage {
228242
readonly colorify;
229243
readonly yfmNote;
230244
readonly image;
245+
readonly link;
231246
protected readonly page: Page;
232247
protected readonly expect: Expect;
233248

@@ -240,6 +255,7 @@ export class MarkdownEditorPage {
240255
this.colorify = new Colorify(page, expect, this.locators);
241256
this.yfmNote = new YfmNote(page);
242257
this.image = new Image(page);
258+
this.link = new Link(page, expect);
243259
}
244260

245261
/**

tests/visual-tests/playground/Cut.visual.test.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@ test.describe('Cut', () => {
2929
await editor.assertAdditionalToolbarButtonEnabled('Cut');
3030
});
3131

32-
test('should insert via command menu @wysiwyg', async ({page, editor, actions, wait}) => {
33-
await editor.pressSequentially('/c');
34-
await expect(page.getByTestId('g-md-toolbar-command-menu')).toBeVisible();
32+
test('should insert via command menu @wysiwyg', async ({editor, actions, wait}) => {
33+
await editor.openCommandMenuToolbar('cu');
3534

3635
const cutMenu = editor.getByTextInCommandMenu('Cut').first();
3736
await wait.visible(cutMenu);

tests/visual-tests/playground/File.visual.test.tsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,7 @@ test.describe('File', () => {
5555
await editor.press('ArrowDown', 2);
5656
await editor.press('Enter');
5757

58-
await editor.pressSequentially('/fi');
59-
await expect(page.getByTestId('g-md-toolbar-command-menu')).toBeVisible();
58+
await editor.openCommandMenuToolbar('fi');
6059

6160
const fileMenu = editor.getByTextInCommandMenu('File').first();
6261
await wait.visible(fileMenu);

tests/visual-tests/playground/Image.visual.test.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,7 @@ test.describe('Images', () => {
5353
await editor.press('ArrowDown', 2);
5454
await editor.press('Enter');
5555

56-
await editor.pressSequentially('/im');
57-
await expect(page.getByTestId('g-md-toolbar-command-menu')).toBeVisible();
56+
await editor.openCommandMenuToolbar('im');
5857

5958
const imageMenu = editor.getByTextInCommandMenu('Image').first();
6059
await wait.visible(imageMenu);
@@ -148,7 +147,7 @@ test.describe('Images', () => {
148147
expectScreenshot,
149148
browserName,
150149
}) => {
151-
test.skip(browserName === 'webkit', 'Focus does not work correctly in webkit');
150+
test.skip(browserName === 'webkit', 'fillFocused does not work correctly in webkit');
152151

153152
const markup = dd`
154153
some text
Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,135 @@
1+
import dd from 'ts-dedent';
2+
13
import {expect, test} from 'playwright/core';
24

35
import {Playground} from './Playground.helpers';
46

57
test.describe('Link', () => {
6-
test.beforeEach(async ({mount}) => {
8+
test.beforeEach(async ({editor, mount, page}) => {
79
const initialMarkup = ``;
810

9-
await mount(<Playground initial={initialMarkup} />);
11+
await mount(<Playground initial={initialMarkup} width="100%" style={{width: 812}} />);
12+
await page.setViewportSize({height: 500, width: 812});
13+
await editor.switchMode('wysiwyg');
1014
});
1115

12-
test('should insert link via toolbar popup dialog', async ({
16+
test('should insert via toolbar @wysiwyg', async ({browserName, editor, actions, wait}) => {
17+
test.skip(browserName === 'webkit', 'fillFocused does not work correctly in webkit');
18+
19+
await editor.clickMainToolbarButton('Link');
20+
await editor.link.assertFormToBeVisible();
21+
22+
await wait.timeout(300);
23+
await actions.fillFocused('gravity-ui.com');
24+
await actions.pressFocused('Tab', 3);
25+
26+
await actions.fillFocused('gravity');
27+
await actions.pressFocused('Tab', 2);
28+
29+
await actions.pressFocused('Enter');
30+
31+
await expect(editor.getByTextInContenteditable('gravity-ui.com')).toBeHidden();
32+
await expect(editor.getByTextInContenteditable('gravity')).toBeVisible();
33+
});
34+
35+
test('should insert via command menu @wysiwyg', async ({
1336
browserName,
1437
editor,
15-
page,
1638
actions,
1739
wait,
1840
}) => {
1941
test.skip(browserName === 'webkit', 'fillFocused does not work correctly in webkit');
2042

21-
await editor.switchMode('wysiwyg');
22-
await editor.clickAdditionalToolbarButton('Link');
43+
await editor.openCommandMenuToolbar('lin');
44+
45+
const linkMenu = editor.getByTextInCommandMenu('Link').first();
46+
await wait.visible(linkMenu);
2347

24-
await expect(page.getByTestId('g-md-link-form')).toBeVisible();
48+
await linkMenu.click();
49+
await editor.link.assertFormToBeVisible();
2550

2651
await wait.timeout(300);
2752
await actions.fillFocused('gravity-ui.com');
28-
2953
await actions.pressFocused('Tab', 3);
3054

3155
await actions.fillFocused('gravity');
56+
await actions.pressFocused('Tab', 2);
3257

3358
await actions.pressFocused('Enter');
3459

3560
await expect(editor.getByTextInContenteditable('gravity-ui.com')).toBeHidden();
3661
await expect(editor.getByTextInContenteditable('gravity')).toBeVisible();
3762
});
63+
64+
test('should insert via toolbar @markup', async ({editor}) => {
65+
await editor.switchMode('markup');
66+
67+
await editor.clickMainToolbarButton('Link');
68+
69+
await expect(editor.getByTextInContenteditable('[link](url "title")')).toBeVisible();
70+
});
71+
72+
test.describe('mode switch', () => {
73+
test('should remain after mode switch @wysiwyg @markup', async ({editor, wait}) => {
74+
const markup = dd`
75+
some text
76+
77+
[gravity](gravity-ui.com)
78+
79+
text
80+
`;
81+
82+
await editor.switchMode('markup');
83+
await editor.clearContent();
84+
await editor.fill(markup);
85+
await wait.timeout();
86+
87+
await expect(editor.getByTextInContenteditable('some text')).toBeVisible();
88+
await expect(
89+
editor.getByTextInContenteditable('[gravity](gravity-ui.com)'),
90+
).toBeVisible();
91+
92+
await editor.switchMode('wysiwyg');
93+
await wait.timeout(500);
94+
95+
await expect(editor.getByTextInContenteditable('gravity-ui.com')).toBeHidden();
96+
await expect(editor.getByTextInContenteditable('gravity')).toBeVisible();
97+
});
98+
});
99+
100+
test.describe('specific', () => {
101+
test('should open edit popup on link click @wysiwyg', async ({
102+
editor,
103+
expectScreenshot,
104+
wait,
105+
}) => {
106+
const markup = dd`
107+
some text
108+
109+
[gravity](gravity-ui.com)
110+
111+
text
112+
`;
113+
114+
await editor.switchMode('markup');
115+
await editor.clearContent();
116+
await editor.fill(markup);
117+
await wait.timeout();
118+
119+
await expect(editor.getByTextInContenteditable('some text')).toBeVisible();
120+
await expect(
121+
editor.getByTextInContenteditable('[gravity](gravity-ui.com)'),
122+
).toBeVisible();
123+
124+
await editor.switchMode('wysiwyg');
125+
await wait.timeout(500);
126+
127+
await expect(editor.getByTextInContenteditable('gravity-ui.com')).toBeHidden();
128+
await expect(editor.getByTextInContenteditable('gravity')).toBeVisible();
129+
130+
await editor.getByTextInContenteditable('gravity').click();
131+
132+
await expectScreenshot();
133+
});
134+
});
38135
});

tests/visual-tests/playground/Note.visual.test.tsx

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,8 @@ test.describe('Note', () => {
2626
await editor.assertAdditionalToolbarButtonDisabled('Note');
2727
});
2828

29-
test('should insert via command menu @wysiwyg', async ({page, editor, actions, wait}) => {
30-
await editor.pressSequentially('/no');
31-
await expect(page.getByTestId('g-md-toolbar-command-menu')).toBeVisible();
29+
test('should insert via command menu @wysiwyg', async ({editor, actions, wait}) => {
30+
await editor.openCommandMenuToolbar('no');
3231

3332
const noteMenu = editor.getByTextInCommandMenu('Note').first();
3433
await wait.visible(noteMenu);

0 commit comments

Comments
 (0)