fix: guard whiteboard permission rejections
This commit is contained in:
@@ -125,6 +125,13 @@ function mockEditor(): Editor {
|
||||
} as unknown as Editor
|
||||
}
|
||||
|
||||
function dispatchUnhandledRejection(reason: unknown): Event {
|
||||
const event = new Event('unhandledrejection', { cancelable: true })
|
||||
Object.defineProperty(event, 'reason', { value: reason })
|
||||
window.dispatchEvent(event)
|
||||
return event
|
||||
}
|
||||
|
||||
function measuredTextElement(): HTMLElement {
|
||||
const element = document.createElement('div')
|
||||
element.textContent = 'Label'
|
||||
@@ -246,6 +253,31 @@ describe('TldrawWhiteboard', () => {
|
||||
expect(() => editor.textMeasure.measureElementTextNodeSpans(measuredTextElement())).toThrow('top')
|
||||
})
|
||||
|
||||
it('suppresses whiteboard platform permission rejections while mounted', () => {
|
||||
render(
|
||||
<TldrawWhiteboard
|
||||
boardId="board-1"
|
||||
height="520"
|
||||
snapshot=""
|
||||
width=""
|
||||
onSizeChange={vi.fn()}
|
||||
onSnapshotChange={vi.fn()}
|
||||
/>
|
||||
)
|
||||
|
||||
const cleanup = renderedTldrawProps().onMount(mockEditor())
|
||||
const denied = {
|
||||
name: 'NotAllowedError',
|
||||
message: 'The request is not allowed by the user agent or the platform in the current context, possibly because the user denied permission.',
|
||||
}
|
||||
|
||||
expect(dispatchUnhandledRejection(denied).defaultPrevented).toBe(true)
|
||||
expect(dispatchUnhandledRejection(new Error('save failed')).defaultPrevented).toBe(false)
|
||||
|
||||
cleanup()
|
||||
expect(dispatchUnhandledRejection(denied).defaultPrevented).toBe(false)
|
||||
})
|
||||
|
||||
it('resets the drawing store when switching to a blank board snapshot', () => {
|
||||
const boardASnapshot = { records: { shape: 'from-board-a' } }
|
||||
const { rerender } = render(
|
||||
|
||||
@@ -101,6 +101,50 @@ function ignoreTldrawUserPreferencesUpdate(preferences: TLUserPreferences) {
|
||||
void preferences
|
||||
}
|
||||
|
||||
function rejectionName(error: unknown): string {
|
||||
if (error instanceof Error) return error.name
|
||||
if (typeof error !== 'object' || error === null || !('name' in error)) return ''
|
||||
|
||||
const { name } = error
|
||||
return typeof name === 'string' ? name : ''
|
||||
}
|
||||
|
||||
function rejectionMessage(error: unknown): string {
|
||||
if (error instanceof Error) return error.message
|
||||
if (typeof error === 'string') return error
|
||||
if (typeof error !== 'object' || error === null || !('message' in error)) return ''
|
||||
|
||||
const { message } = error
|
||||
return typeof message === 'string' ? message : ''
|
||||
}
|
||||
|
||||
function isWhiteboardPlatformPermissionRejection(reason: unknown): boolean {
|
||||
const name = rejectionName(reason).toLowerCase()
|
||||
const message = rejectionMessage(reason).toLowerCase()
|
||||
if (name === 'notallowederror') return true
|
||||
|
||||
return message.includes('notallowederror') || (
|
||||
message.includes('not allowed')
|
||||
&& (
|
||||
message.includes('permission')
|
||||
|| message.includes('platform')
|
||||
|| message.includes('user agent')
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
function installTldrawPlatformPermissionGuard(): () => void {
|
||||
const handleUnhandledRejection = (event: PromiseRejectionEvent) => {
|
||||
if (!isWhiteboardPlatformPermissionRejection(event.reason)) return
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
window.addEventListener('unhandledrejection', handleUnhandledRejection)
|
||||
return () => {
|
||||
window.removeEventListener('unhandledrejection', handleUnhandledRejection)
|
||||
}
|
||||
}
|
||||
|
||||
function parseSnapshot(source: string): TLStoreSnapshot | null {
|
||||
if (!source.trim()) return null
|
||||
|
||||
@@ -211,8 +255,10 @@ function installZoomAwareViewport(editor: Editor): () => void {
|
||||
function installWhiteboardRuntimeGuards(editor: Editor): () => void {
|
||||
const cleanupTextMeasurementGuard = installTldrawTextMeasurementGuard(editor)
|
||||
const cleanupZoomAwareViewport = installZoomAwareViewport(editor)
|
||||
const cleanupPlatformPermissionGuard = installTldrawPlatformPermissionGuard()
|
||||
|
||||
return () => {
|
||||
cleanupPlatformPermissionGuard()
|
||||
cleanupZoomAwareViewport()
|
||||
cleanupTextMeasurementGuard()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user