mirror of
https://github.com/go-vikunja/vikunja.git
synced 2026-04-24 22:25:15 +00:00
fix(editor): prevent TypeError when typing mentions in comments (#1997)
Fix TypeError when typing `@` mentions in task comments, add null checks for `component` variable in `mentionSuggestion.ts` to handle race conditions where `onUpdate` or `onKeyDown` fire before `onStart` completes
This commit is contained in:
@@ -145,7 +145,7 @@ export default function mentionSuggestionSetup(projectId: number) {
|
||||
items: MentionItem[]
|
||||
command: (item: MentionItem) => void
|
||||
}) {
|
||||
component.updateProps(props)
|
||||
component?.updateProps(props)
|
||||
|
||||
if (!props.clientRect || !popupElement) {
|
||||
return
|
||||
@@ -171,7 +171,7 @@ export default function mentionSuggestionSetup(projectId: number) {
|
||||
return true
|
||||
}
|
||||
|
||||
return component.ref?.onKeyDown(props)
|
||||
return component?.ref?.onKeyDown(props)
|
||||
},
|
||||
|
||||
onExit() {
|
||||
|
||||
79
frontend/tests/e2e/task/mention-in-comment.spec.ts
Normal file
79
frontend/tests/e2e/task/mention-in-comment.spec.ts
Normal file
@@ -0,0 +1,79 @@
|
||||
import {test, expect} from '../../support/fixtures'
|
||||
import {ProjectFactory} from '../../factories/project'
|
||||
import {TaskFactory} from '../../factories/task'
|
||||
import {TaskCommentFactory} from '../../factories/task_comment'
|
||||
import {createDefaultViews} from '../project/prepareProjects'
|
||||
|
||||
test.describe('Mention in task comment', () => {
|
||||
test.beforeEach(async ({authenticatedPage: page}) => {
|
||||
await ProjectFactory.create(1)
|
||||
await createDefaultViews(1)
|
||||
await TaskFactory.create(1, {id: 1})
|
||||
await TaskCommentFactory.truncate()
|
||||
})
|
||||
|
||||
test('typing @ in comment editor does not throw TypeError', async ({authenticatedPage: page}) => {
|
||||
// Collect console errors
|
||||
const consoleErrors: string[] = []
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') {
|
||||
consoleErrors.push(msg.text())
|
||||
}
|
||||
})
|
||||
|
||||
await page.goto('/tasks/1')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
// Wait for comment input editor to be visible (the editable one)
|
||||
const commentEditor = page.locator('.task-view .comments .media.comment .tiptap__editor .tiptap.ProseMirror[contenteditable="true"]')
|
||||
await expect(commentEditor).toBeVisible({timeout: 10000})
|
||||
|
||||
// Click to focus the editor
|
||||
await commentEditor.click()
|
||||
|
||||
// Type @ to trigger mention suggestion
|
||||
await commentEditor.pressSequentially('@', {delay: 50})
|
||||
|
||||
// Wait a bit for any async operations
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
// Type more characters to trigger updates
|
||||
await commentEditor.pressSequentially('test', {delay: 50})
|
||||
|
||||
// Wait for debounce and any potential errors
|
||||
await page.waitForTimeout(500)
|
||||
|
||||
// Press Escape to close any mention popup
|
||||
await page.keyboard.press('Escape')
|
||||
|
||||
// Verify no TypeErrors related to mention component were logged
|
||||
const mentionErrors = consoleErrors.filter(err =>
|
||||
err.includes('TypeError') &&
|
||||
(err.includes('updateProps') || err.includes('onKeyDown') || err.includes('ref')),
|
||||
)
|
||||
|
||||
expect(mentionErrors).toHaveLength(0)
|
||||
})
|
||||
|
||||
test('can type mention without error notifications appearing', async ({authenticatedPage: page}) => {
|
||||
await page.goto('/tasks/1')
|
||||
await page.waitForLoadState('networkidle')
|
||||
|
||||
// Wait for comment input editor to be visible (the editable one)
|
||||
const commentEditor = page.locator('.task-view .comments .media.comment .tiptap__editor .tiptap.ProseMirror[contenteditable="true"]')
|
||||
await expect(commentEditor).toBeVisible({timeout: 10000})
|
||||
|
||||
// Click to focus the editor
|
||||
await commentEditor.click()
|
||||
|
||||
// Type @ to trigger mention suggestion
|
||||
await commentEditor.pressSequentially('@user', {delay: 50})
|
||||
|
||||
// Wait for potential error notifications to appear
|
||||
await page.waitForTimeout(1000)
|
||||
|
||||
// Verify no error notification appeared
|
||||
const errorNotification = page.locator('.global-notification.is-danger, .global-notification.error')
|
||||
await expect(errorNotification).not.toBeVisible()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user