Files
tolaria/src/components/editorSchema.webkit.test.ts
2026-05-29 20:35:53 +02:00

165 lines
5.5 KiB
TypeScript

import { afterEach, describe, expect, it, vi } from 'vitest'
import { EXTRA_CODE_BLOCK_LANGUAGES } from '../utils/codeBlockLanguageCatalog'
const nativeRegExpDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'RegExp')
const NativeRegExp = RegExp
function setRegExpConstructor(value: RegExpConstructor) {
Object.defineProperty(globalThis, 'RegExp', {
configurable: true,
writable: true,
value,
})
}
function restoreRegExpConstructor() {
if (nativeRegExpDescriptor) {
Object.defineProperty(globalThis, 'RegExp', nativeRegExpDescriptor)
}
}
function installMockRegExp(shouldReject: (pattern: string | RegExp | undefined, flags: string | undefined) => boolean) {
const LegacyWebKitRegExp = function (pattern?: string | RegExp, flags?: string) {
if (shouldReject(pattern, flags)) {
throw new SyntaxError('Invalid regular expression: invalid group specifier name')
}
return new NativeRegExp(pattern, flags)
} as RegExpConstructor
Object.setPrototypeOf(LegacyWebKitRegExp, NativeRegExp)
LegacyWebKitRegExp.prototype = NativeRegExp.prototype
setRegExpConstructor(LegacyWebKitRegExp)
}
function installLegacyWebKitRegExp() {
installMockRegExp((_pattern, flags) => Boolean(flags?.includes('d') || flags?.includes('v')))
}
function installLookbehindMissingRegExp() {
installMockRegExp((pattern) => typeof pattern === 'string' && pattern.includes('(?<'))
}
afterEach(() => {
document.documentElement.classList.remove('dark')
delete document.documentElement.dataset.theme
restoreRegExpConstructor()
vi.resetModules()
})
describe('editor schema code block highlighting', () => {
it('uses the light Shiki theme first in light mode', async () => {
vi.resetModules()
document.documentElement.classList.remove('dark')
document.documentElement.dataset.theme = 'light'
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
const highlighter = await createTolariaCodeBlockOptions().createHighlighter?.()
expect(highlighter?.getLoadedThemes()[0]).toBe('github-light')
})
it('uses the dark Shiki theme first in dark mode', async () => {
vi.resetModules()
document.documentElement.classList.add('dark')
document.documentElement.dataset.theme = 'dark'
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
const highlighter = await createTolariaCodeBlockOptions().createHighlighter?.()
expect(highlighter?.getLoadedThemes()[0]).toBe('github-dark')
})
it('registers Go as a selectable Shiki code block language', async () => {
vi.resetModules()
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
const options = createTolariaCodeBlockOptions()
expect(options.supportedLanguages?.go).toMatchObject({
name: 'Go',
aliases: ['go', 'golang'],
})
})
it('registers additional common Shiki code block languages', async () => {
vi.resetModules()
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
const options = createTolariaCodeBlockOptions()
expect(options.supportedLanguages?.powershell).toMatchObject({
name: 'PowerShell',
aliases: ['powershell', 'ps', 'ps1'],
})
expect(options.supportedLanguages?.vbscript).toMatchObject({
name: 'VBScript',
aliases: ['vbscript', 'vbs', 'vb', 'vba', 'visual-basic', 'visualbasic'],
})
expect(options.supportedLanguages?.dart).toMatchObject({
name: 'Dart',
aliases: ['dart'],
})
expect(options.supportedLanguages?.hcl).toMatchObject({
name: 'HCL',
aliases: ['hcl'],
})
expect(options.supportedLanguages?.terraform).toMatchObject({
name: 'Terraform',
aliases: ['terraform', 'tf', 'tfvars'],
})
expect(options.supportedLanguages?.dockerfile).toMatchObject({
name: 'Dockerfile',
aliases: ['dockerfile', 'docker'],
})
expect(options.supportedLanguages?.php).toMatchObject({
name: 'PHP',
aliases: ['php'],
})
})
it('loads the Go Shiki grammar for Go code blocks', async () => {
vi.resetModules()
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
const highlighter = await createTolariaCodeBlockOptions().createHighlighter?.()
await expect(highlighter?.loadLanguage('go')).resolves.toBeUndefined()
expect(highlighter?.getLoadedLanguages()).toContain('go')
})
it.each([
...EXTRA_CODE_BLOCK_LANGUAGES.map(language => [language.id, language.id]),
['ps1', 'ps1'],
['vb', 'vb'],
['php', 'php'],
])('loads the %s Shiki grammar for code blocks', async (language, loadedLanguage) => {
vi.resetModules()
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
const highlighter = await createTolariaCodeBlockOptions().createHighlighter?.()
await expect(highlighter?.loadLanguage(language)).resolves.toBeUndefined()
expect(highlighter?.getLoadedLanguages()).toContain(loadedLanguage)
})
it('omits the Shiki highlighter when WebKit lacks precompiled regex flags', async () => {
installLegacyWebKitRegExp()
vi.resetModules()
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
expect(createTolariaCodeBlockOptions()).not.toHaveProperty('createHighlighter')
})
it('omits the Shiki highlighter when WebKit lacks regex lookbehind syntax', async () => {
installLookbehindMissingRegExp()
vi.resetModules()
const { createTolariaCodeBlockOptions } = await import('./codeBlockOptions')
expect(createTolariaCodeBlockOptions()).not.toHaveProperty('createHighlighter')
})
})