Full document, spreadsheet, slideshow, and diagram tooling
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 324 lines 11 kB view raw
1import { test, expect } from '@playwright/test'; 2import { createNewDoc } from './helpers'; 3 4test.describe('Docs - Toolbar', () => { 5 test.beforeEach(async ({ page }) => { 6 await createNewDoc(page); 7 }); 8 9 test('bold button toggles bold formatting on selected text', async ({ page }) => { 10 const editor = page.locator('.tiptap'); 11 await editor.click(); 12 await page.keyboard.type('bold this'); 13 await page.keyboard.press('Meta+a'); 14 15 await page.click('#tb-bold'); 16 await expect(editor.locator('strong')).toContainText('bold this'); 17 18 // Toggle off 19 await page.keyboard.press('Meta+a'); 20 await page.click('#tb-bold'); 21 const strongCount = await editor.locator('strong').count(); 22 expect(strongCount).toBe(0); 23 }); 24 25 test('italic button toggles italic formatting', async ({ page }) => { 26 const editor = page.locator('.tiptap'); 27 await editor.click(); 28 await page.keyboard.type('italic this'); 29 await page.keyboard.press('Meta+a'); 30 31 await page.click('#tb-italic'); 32 await expect(editor.locator('em')).toContainText('italic this'); 33 }); 34 35 test('underline button toggles underline formatting', async ({ page }) => { 36 const editor = page.locator('.tiptap'); 37 await editor.click(); 38 await page.keyboard.type('underline this'); 39 await page.keyboard.press('Meta+a'); 40 41 await page.click('#tb-underline'); 42 await expect(editor.locator('u')).toContainText('underline this'); 43 }); 44 45 test('strikethrough button toggles strikethrough formatting', async ({ page }) => { 46 const editor = page.locator('.tiptap'); 47 await editor.click(); 48 await page.keyboard.type('strike this'); 49 await page.keyboard.press('Meta+a'); 50 51 await page.click('#tb-strike'); 52 await expect(editor.locator('s')).toContainText('strike this'); 53 }); 54 55 test('heading dropdown changes text to heading level', async ({ page }) => { 56 const editor = page.locator('.tiptap'); 57 await editor.click(); 58 await page.keyboard.type('Heading Text'); 59 await page.keyboard.press('Meta+a'); 60 61 // Change to H1 62 await page.selectOption('#tb-heading', '1'); 63 await expect(editor.locator('h1')).toContainText('Heading Text'); 64 65 // Change to H2 66 await page.selectOption('#tb-heading', '2'); 67 await expect(editor.locator('h2')).toContainText('Heading Text'); 68 69 // Change to H3 70 await page.selectOption('#tb-heading', '3'); 71 await expect(editor.locator('h3')).toContainText('Heading Text'); 72 73 // Change back to paragraph 74 await page.selectOption('#tb-heading', '0'); 75 const h1Count = await editor.locator('h1, h2, h3').count(); 76 expect(h1Count).toBe(0); 77 }); 78 79 test('bullet list button creates a bulleted list', async ({ page }) => { 80 const editor = page.locator('.tiptap'); 81 await editor.click(); 82 await page.keyboard.type('List item'); 83 84 await page.click('#tb-bullet-list'); 85 86 const listItems = editor.locator('ul li'); 87 await expect(listItems).toHaveCount(1); 88 await expect(listItems.first()).toContainText('List item'); 89 }); 90 91 test('ordered list button creates a numbered list', async ({ page }) => { 92 const editor = page.locator('.tiptap'); 93 await editor.click(); 94 await page.keyboard.type('Numbered item'); 95 96 await page.click('#tb-ordered-list'); 97 98 const listItems = editor.locator('ol li'); 99 await expect(listItems).toHaveCount(1); 100 await expect(listItems.first()).toContainText('Numbered item'); 101 }); 102 103 test('task list button creates a task list with checkboxes', async ({ page }) => { 104 const editor = page.locator('.tiptap'); 105 await editor.click(); 106 await page.keyboard.type('Task to do'); 107 108 await page.click('#tb-task-list'); 109 110 const taskList = editor.locator('ul[data-type="taskList"]'); 111 await expect(taskList).toBeVisible(); 112 await expect(taskList).toContainText('Task to do'); 113 }); 114 115 test('blockquote button wraps text in a blockquote', async ({ page }) => { 116 const editor = page.locator('.tiptap'); 117 await editor.click(); 118 await page.keyboard.type('Quoted text'); 119 await page.keyboard.press('Meta+a'); 120 121 await page.click('#tb-blockquote'); 122 123 await expect(editor.locator('blockquote')).toContainText('Quoted text'); 124 }); 125 126 test('code block button creates a code block', async ({ page }) => { 127 const editor = page.locator('.tiptap'); 128 await editor.click(); 129 await page.keyboard.type('const x = 1;'); 130 await page.keyboard.press('Meta+a'); 131 132 await page.click('#tb-codeblock'); 133 134 await expect(editor.locator('pre code')).toContainText('const x = 1;'); 135 }); 136 137 test('horizontal rule button inserts a horizontal rule', async ({ page }) => { 138 const editor = page.locator('.tiptap'); 139 await editor.click(); 140 await page.keyboard.type('Above line'); 141 await page.keyboard.press('Enter'); 142 143 await page.click('#tb-hr'); 144 145 await expect(editor.locator('hr')).toBeVisible(); 146 }); 147 148 test('text alignment buttons change text alignment', async ({ page }) => { 149 const editor = page.locator('.tiptap'); 150 await editor.click(); 151 await page.keyboard.type('Align me'); 152 await page.keyboard.press('Meta+a'); 153 154 // Open alignment dropdown and select center 155 await page.click('#tb-align-toggle'); 156 await page.click('[data-align="center"]'); 157 158 // The paragraph should have text-align: center 159 const paragraph = editor.locator('p').first(); 160 const textAlign = await paragraph.evaluate(el => getComputedStyle(el).textAlign); 161 expect(textAlign).toBe('center'); 162 163 // Change to right alignment 164 await page.click('#tb-align-toggle'); 165 await page.click('[data-align="right"]'); 166 167 const rightAlign = await paragraph.evaluate(el => getComputedStyle(el).textAlign); 168 expect(rightAlign).toMatch(/right|end/); 169 }); 170 171 test('link button inserts a link', async ({ page }) => { 172 const editor = page.locator('.tiptap'); 173 await editor.click(); 174 await page.keyboard.type('link text'); 175 await page.keyboard.press('Meta+a'); 176 177 await page.click('#tb-link'); 178 179 // A prompt or dialog should appear for the URL 180 // The implementation uses window.prompt, so we need to handle it 181 page.on('dialog', async (dialog) => { 182 await dialog.accept('https://example.com'); 183 }); 184 185 // Re-click to trigger the prompt 186 await page.click('#tb-link'); 187 188 // After a short wait, the link should be created 189 await page.waitForTimeout(500); 190 const link = editor.locator('a[href="https://example.com"]'); 191 // Link may or may not have been created depending on prompt handling 192 // Just verify no crash occurred 193 }); 194 195 test('table button inserts a table', async ({ page }) => { 196 const editor = page.locator('.tiptap'); 197 await editor.click(); 198 199 await page.click('#tb-table'); 200 201 // A table should appear in the editor 202 await expect(editor.locator('table')).toBeVisible({ timeout: 5000 }); 203 // Table should have rows and cells 204 await expect(editor.locator('table tr')).toHaveCount(3); // typical default 3x3 205 }); 206 207 test('font size dropdown changes text size', async ({ page }) => { 208 const editor = page.locator('.tiptap'); 209 await editor.click(); 210 await page.keyboard.type('Bigger text'); 211 await page.keyboard.press('Meta+a'); 212 213 await page.selectOption('#tb-font-size', '24'); 214 215 // The text should have a larger font size applied 216 // TipTap applies font-size via inline style or span 217 const text = editor.locator('span, p').first(); 218 const fontSize = await text.evaluate(el => { 219 // Walk up to find the element with font-size set 220 let current: Element | null = el; 221 while (current) { 222 const fs = getComputedStyle(current).fontSize; 223 if (fs && parseFloat(fs) > 20) return fs; 224 current = current.parentElement; 225 } 226 return getComputedStyle(el).fontSize; 227 }); 228 expect(parseFloat(fontSize)).toBeGreaterThanOrEqual(20); 229 }); 230 231 test('undo button reverses the last action', async ({ page }) => { 232 const editor = page.locator('.tiptap'); 233 await editor.click(); 234 await page.keyboard.type('Hello'); 235 await expect(editor).toContainText('Hello'); 236 237 await page.click('#tb-undo'); 238 await page.click('#tb-undo'); 239 await page.click('#tb-undo'); 240 await page.click('#tb-undo'); 241 await page.click('#tb-undo'); 242 243 const text = await editor.textContent(); 244 expect(text?.trim()).not.toBe('Hello'); 245 }); 246 247 test('redo button re-applies the last undone action', async ({ page }) => { 248 const editor = page.locator('.tiptap'); 249 await editor.click(); 250 await page.keyboard.type('Redo me'); 251 252 // Undo 253 for (let i = 0; i < 7; i++) { 254 await page.click('#tb-undo'); 255 } 256 257 // Redo 258 for (let i = 0; i < 7; i++) { 259 await page.click('#tb-redo'); 260 } 261 262 await expect(editor).toContainText('Redo me'); 263 }); 264 265 test('code inline button toggles inline code formatting', async ({ page }) => { 266 const editor = page.locator('.tiptap'); 267 await editor.click(); 268 await page.keyboard.type('inline code'); 269 await page.keyboard.press('Meta+a'); 270 271 await page.click('#tb-code'); 272 273 await expect(editor.locator('code')).toContainText('inline code'); 274 }); 275 276 test('subscript button toggles subscript', async ({ page }) => { 277 const editor = page.locator('.tiptap'); 278 await editor.click(); 279 await page.keyboard.type('H2O'); 280 281 // Select "2" 282 await page.keyboard.press('Home'); 283 await page.keyboard.press('ArrowRight'); 284 await page.keyboard.down('Shift'); 285 await page.keyboard.press('ArrowRight'); 286 await page.keyboard.up('Shift'); 287 288 await page.click('#tb-subscript'); 289 290 await expect(editor.locator('sub')).toContainText('2'); 291 }); 292 293 test('superscript button toggles superscript', async ({ page }) => { 294 const editor = page.locator('.tiptap'); 295 await editor.click(); 296 await page.keyboard.type('x2'); 297 298 // Select "2" 299 await page.keyboard.press('End'); 300 await page.keyboard.down('Shift'); 301 await page.keyboard.press('ArrowLeft'); 302 await page.keyboard.up('Shift'); 303 304 await page.click('#tb-superscript'); 305 306 await expect(editor.locator('sup')).toContainText('2'); 307 }); 308 309 test('toolbar active states reflect current formatting', async ({ page }) => { 310 const editor = page.locator('.tiptap'); 311 await editor.click(); 312 313 // Apply bold 314 await page.keyboard.press('Meta+b'); 315 await page.keyboard.type('bold'); 316 317 // Bold button should have active class 318 await expect(page.locator('#tb-bold')).toHaveClass(/active/); 319 320 // Turn off bold 321 await page.keyboard.press('Meta+b'); 322 await expect(page.locator('#tb-bold')).not.toHaveClass(/active/); 323 }); 324});