mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 08:02:28 +00:00
test(terminal): remove IME assertion lint findings
This commit is contained in:
+51
-25
@@ -3,6 +3,11 @@ import { Unicode11Addon } from '@xterm/addon-unicode11'
|
||||
import { Terminal } from '@xterm/xterm'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
type ImeTerminalCore = {
|
||||
_renderService: { dimensions: { css: { cell: { width: number } } } }
|
||||
_compositionHelper: { updateCompositionElements: (dontRecurse: boolean) => void }
|
||||
}
|
||||
|
||||
let terminal: Terminal
|
||||
let view: HTMLElement
|
||||
let assignedSpacing: WeakMap<CSSStyleDeclaration, string>
|
||||
@@ -27,19 +32,39 @@ function compose(text: string): HTMLElement {
|
||||
function runs(preedit: HTMLElement): { text: string | null; spacing: string | undefined }[] {
|
||||
return Array.from(preedit.children, (child) => ({
|
||||
text: child.textContent,
|
||||
spacing: assignedSpacing.get((child as HTMLElement).style)
|
||||
spacing: assignedSpacing.get(elementStyle(child))
|
||||
}))
|
||||
}
|
||||
|
||||
function elementStyle(element: Element): CSSStyleDeclaration {
|
||||
if (!(element instanceof HTMLElement)) {
|
||||
throw new Error('Expected an HTML element')
|
||||
}
|
||||
return element.style
|
||||
}
|
||||
|
||||
function rendering() {
|
||||
const core: unknown = Reflect.get(terminal, '_core')
|
||||
if (!isImeTerminalCore(core)) {
|
||||
throw new Error('xterm internals are unavailable')
|
||||
}
|
||||
return core
|
||||
}
|
||||
|
||||
function isImeTerminalCore(value: unknown): value is ImeTerminalCore {
|
||||
const renderService = objectProperty(value, '_renderService')
|
||||
const dimensions = objectProperty(renderService, 'dimensions')
|
||||
const css = objectProperty(dimensions, 'css')
|
||||
const cell = objectProperty(css, 'cell')
|
||||
const compositionHelper = objectProperty(value, '_compositionHelper')
|
||||
return (
|
||||
terminal as unknown as {
|
||||
_core: {
|
||||
_renderService: { dimensions: { css: { cell: { width: number } } } }
|
||||
_compositionHelper: { updateCompositionElements: (dontRecurse: boolean) => void }
|
||||
}
|
||||
}
|
||||
)._core
|
||||
typeof objectProperty(cell, 'width') === 'number' &&
|
||||
typeof objectProperty(compositionHelper, 'updateCompositionElements') === 'function'
|
||||
)
|
||||
}
|
||||
|
||||
function objectProperty(value: unknown, key: string): unknown {
|
||||
return typeof value === 'object' && value !== null ? Reflect.get(value, key) : undefined
|
||||
}
|
||||
|
||||
describe('IME preedit advances on the terminal cell grid (#19315)', () => {
|
||||
@@ -58,22 +83,23 @@ describe('IME preedit advances on the terminal cell grid (#19315)', () => {
|
||||
setter.call(this, value)
|
||||
}
|
||||
)
|
||||
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockImplementation(
|
||||
() =>
|
||||
({
|
||||
font: '13px monospace',
|
||||
measureText(this: { font: string }, text: string) {
|
||||
measurements.push(text)
|
||||
const fontSize = Number(this.font.match(/([\d.]+)px/)?.[1] ?? 13)
|
||||
const naturalWidth = /^[\uac00-\ud7a3]$/u.test(text)
|
||||
? 11.25
|
||||
: /^[\x20-\x7e\uff61-\uff9f]$/u.test(text)
|
||||
? 6.5
|
||||
: 13
|
||||
return { width: naturalWidth * (fontSize / 13) * fontScale }
|
||||
}
|
||||
}) as unknown as CanvasRenderingContext2D
|
||||
)
|
||||
vi.spyOn(HTMLCanvasElement.prototype, 'getContext').mockImplementation(() => {
|
||||
const context: CanvasRenderingContext2D = Object.create(null)
|
||||
context.font = '13px monospace'
|
||||
context.measureText = function (text: string) {
|
||||
measurements.push(text)
|
||||
const fontSize = Number(this.font.match(/([\d.]+)px/)?.[1] ?? 13)
|
||||
const naturalWidth = /^[\uac00-\ud7a3]$/u.test(text)
|
||||
? 11.25
|
||||
: /^[\x20-\x7e\uff61-\uff9f]$/u.test(text)
|
||||
? 6.5
|
||||
: 13
|
||||
return Object.assign(Object.create(null), {
|
||||
width: naturalWidth * (fontSize / 13) * fontScale
|
||||
})
|
||||
}
|
||||
return context
|
||||
})
|
||||
const container = document.createElement('div')
|
||||
document.body.appendChild(container)
|
||||
terminal = new Terminal({ cols: 80, rows: 24, fontSize: 13, allowProposedApi: true })
|
||||
@@ -100,7 +126,7 @@ describe('IME preedit advances on the terminal cell grid (#19315)', () => {
|
||||
{ text: 'ア', spacing: 'calc(var(--xterm-composition-cell-width) * 1 - 6.5px)' }
|
||||
])
|
||||
for (const child of Array.from(preedit.children)) {
|
||||
const style = (child as HTMLElement).style
|
||||
const style = elementStyle(child)
|
||||
expect(style.position).toBe('')
|
||||
expect(style.display).toBe('')
|
||||
expect(style.width).toBe('')
|
||||
|
||||
@@ -6,10 +6,6 @@ import {
|
||||
writeToActiveTerminal
|
||||
} from './terminal-ime-midline-occlusion-probe'
|
||||
|
||||
type TerminalGrid = {
|
||||
_core: { _renderService: { dimensions: { css: { cell: { width: number } } } } }
|
||||
}
|
||||
|
||||
for (const dpr of [1, 1.25, 2]) {
|
||||
for (const gpu of ['on', 'off'] as const) {
|
||||
test.describe(`IME preedit grid DPR ${dpr} GPU ${gpu}`, () => {
|
||||
@@ -59,8 +55,7 @@ for (const dpr of [1, 1.25, 2]) {
|
||||
const screen = terminal.element!.querySelector<HTMLElement>('.xterm-screen')!
|
||||
const preedit = screen.querySelector<HTMLElement>('.xterm-composition-preedit')!
|
||||
// The canvas width rounds independently of fractional WebGL cell widths.
|
||||
const cellWidth = (terminal as unknown as TerminalGrid)._core._renderService
|
||||
.dimensions.css.cell.width
|
||||
const cellWidth = terminal._core._renderService.dimensions.css.cell.width
|
||||
const line = terminal.buffer.active.getLine(terminal.buffer.active.baseY)!
|
||||
const committed: { text: string; column: number; width: number }[] = []
|
||||
const end = line.translateToString(true).length
|
||||
@@ -169,8 +164,7 @@ for (const dpr of [1, 1.25, 2]) {
|
||||
const terminal = window
|
||||
.__paneManagers!.get(state.activeTabId!)!
|
||||
.getActivePane()!.terminal
|
||||
const cellWidth = (terminal as unknown as TerminalGrid)._core._renderService
|
||||
.dimensions.css.cell.width
|
||||
const cellWidth = terminal._core._renderService.dimensions.css.cell.width
|
||||
const preedit = terminal.element!.querySelector('.xterm-composition-preedit')!
|
||||
return Math.abs(preedit.getBoundingClientRect().width - 16 * cellWidth)
|
||||
})
|
||||
@@ -222,8 +216,7 @@ test('preserves native shaping for mixed text, complex scripts, and emoji', asyn
|
||||
const actual = await preedit.screenshot()
|
||||
|
||||
// Compare against the original single-text-node browser rendering.
|
||||
await preedit.evaluate((element, text) => {
|
||||
const span = element as HTMLElement
|
||||
await preedit.evaluate((span: HTMLElement, text) => {
|
||||
span.textContent = `${text}`
|
||||
for (const property of ['width', 'white-space', 'display', 'position']) {
|
||||
span.style.removeProperty(property)
|
||||
|
||||
Reference in New Issue
Block a user