Full document, spreadsheet, slideshow, and diagram tooling
1import { test, expect } from '@playwright/test';
2import { createNewDoc } from './helpers';
3
4test.describe('Docs - Editing', () => {
5 test.beforeEach(async ({ page }) => {
6 await createNewDoc(page);
7 });
8
9 test('editor loads and is editable', async ({ page }) => {
10 const editor = page.locator('.tiptap');
11 await expect(editor).toBeVisible();
12 await expect(editor).toHaveAttribute('contenteditable', 'true');
13 });
14
15 test('type text and verify it appears', async ({ page }) => {
16 const editor = page.locator('.tiptap');
17 await editor.click();
18 await page.keyboard.type('Hello, World!');
19 await expect(editor).toContainText('Hello, World!');
20 });
21
22 test('bold text with Cmd+B', async ({ page }) => {
23 const editor = page.locator('.tiptap');
24 await editor.click();
25 await page.keyboard.type('normal ');
26 await page.keyboard.press('Meta+b');
27 await page.keyboard.type('bold text');
28 await page.keyboard.press('Meta+b');
29
30 // Verify bold element exists
31 await expect(editor.locator('strong')).toContainText('bold text');
32 });
33
34 test('italic text with Cmd+I', async ({ page }) => {
35 const editor = page.locator('.tiptap');
36 await editor.click();
37 await page.keyboard.press('Meta+i');
38 await page.keyboard.type('italic text');
39 await page.keyboard.press('Meta+i');
40
41 await expect(editor.locator('em')).toContainText('italic text');
42 });
43
44 test('underline text with Cmd+U', async ({ page }) => {
45 const editor = page.locator('.tiptap');
46 await editor.click();
47 await page.keyboard.press('Meta+u');
48 await page.keyboard.type('underlined');
49 await page.keyboard.press('Meta+u');
50
51 await expect(editor.locator('u')).toContainText('underlined');
52 });
53
54 test('create heading with # + space', async ({ page }) => {
55 const editor = page.locator('.tiptap');
56 await editor.click();
57 await page.keyboard.type('# Heading One');
58
59 // TipTap autoformat converts "# " to h1
60 await expect(editor.locator('h1')).toContainText('Heading One');
61 });
62
63 test('create h2 heading with ## + space', async ({ page }) => {
64 const editor = page.locator('.tiptap');
65 await editor.click();
66 await page.keyboard.type('## Heading Two');
67
68 await expect(editor.locator('h2')).toContainText('Heading Two');
69 });
70
71 test('create bullet list with - + space', async ({ page }) => {
72 const editor = page.locator('.tiptap');
73 await editor.click();
74 await page.keyboard.type('- First item');
75 await page.keyboard.press('Enter');
76 await page.keyboard.type('Second item');
77
78 // Verify list was created
79 const listItems = editor.locator('ul li');
80 await expect(listItems).toHaveCount(2);
81 await expect(listItems.first()).toContainText('First item');
82 await expect(listItems.last()).toContainText('Second item');
83 });
84
85 test('create numbered list with 1. + space', async ({ page }) => {
86 const editor = page.locator('.tiptap');
87 await editor.click();
88 await page.keyboard.type('1. First item');
89 await page.keyboard.press('Enter');
90 await page.keyboard.type('Second item');
91
92 const listItems = editor.locator('ol li');
93 await expect(listItems).toHaveCount(2);
94 await expect(listItems.first()).toContainText('First item');
95 });
96
97 test('insert horizontal rule with ---', async ({ page }) => {
98 const editor = page.locator('.tiptap');
99 await editor.click();
100 await page.keyboard.type('Above the line');
101 await page.keyboard.press('Enter');
102 await page.keyboard.type('---');
103
104 // TipTap should render an hr element
105 await expect(editor.locator('hr')).toBeVisible();
106 });
107
108 test('undo with Cmd+Z', async ({ page }) => {
109 const editor = page.locator('.tiptap');
110 await editor.click();
111 await page.keyboard.type('Hello');
112 await expect(editor).toContainText('Hello');
113
114 // Undo the typing
115 await page.keyboard.press('Meta+z');
116 await page.keyboard.press('Meta+z');
117 await page.keyboard.press('Meta+z');
118 await page.keyboard.press('Meta+z');
119 await page.keyboard.press('Meta+z');
120
121 // Content should be empty or at least not contain the full text
122 const text = await editor.textContent();
123 expect(text?.trim()).not.toBe('Hello');
124 });
125
126 test('redo with Cmd+Shift+Z', async ({ page }) => {
127 const editor = page.locator('.tiptap');
128 await editor.click();
129 await page.keyboard.type('Hello');
130
131 // Undo
132 for (let i = 0; i < 5; i++) {
133 await page.keyboard.press('Meta+z');
134 }
135
136 // Redo
137 for (let i = 0; i < 5; i++) {
138 await page.keyboard.press('Meta+Shift+z');
139 }
140
141 await expect(editor).toContainText('Hello');
142 });
143
144 test('bold toolbar button works', async ({ page }) => {
145 const editor = page.locator('.tiptap');
146 await editor.click();
147 await page.keyboard.type('select me');
148
149 // Select all text
150 await page.keyboard.press('Meta+a');
151
152 // Click bold button in toolbar
153 await page.click('#tb-bold');
154
155 await expect(editor.locator('strong')).toContainText('select me');
156 });
157
158 test('italic toolbar button works', async ({ page }) => {
159 const editor = page.locator('.tiptap');
160 await editor.click();
161 await page.keyboard.type('italicize me');
162 await page.keyboard.press('Meta+a');
163 await page.click('#tb-italic');
164
165 await expect(editor.locator('em')).toContainText('italicize me');
166 });
167});