Files
lexgo/spikes/selection/ui.test.mjs

54 lines
2.9 KiB
JavaScript

import test from 'node:test'
import assert from 'node:assert/strict'
import {readFile} from 'node:fs/promises'
import {JSDOM} from '../../learner/node_modules/jsdom/lib/api.js'
let serial=0
async function page(run){
const html=await readFile(new URL('./index.html',import.meta.url),'utf8')
const dom=new JSDOM(html,{url:'http://127.0.0.1:5184/'})
globalThis.window=dom.window;globalThis.document=dom.window.document
dom.window.scrollTo=()=>{}
dom.window.HTMLElement.prototype.scrollIntoView=()=>{}
await import(`./app.mjs?test=${++serial}`)
const $=id=>document.getElementById(id)
try{await run($,dom.window)}finally{await new Promise(resolve=>setTimeout(resolve,120));dom.window.close()}
}
test('close preserves keyboard cursor: next arrow continues at the adjacent word',()=>page(($,w)=>{
const span=[...$('reader').children].find(n=>n.textContent==='workshop')
span.click();assert.equal($('term').textContent,'workshop')
$('close').click();assert.equal($('panel').hidden,true)
$('reader').dispatchEvent(new w.KeyboardEvent('keydown',{key:'ArrowRight',bubbles:true}))
assert.equal($('term').textContent,'before')
}))
test('native punctuation-only selection clears stale word and cannot save it',()=>page(async($,w)=>{
[...$('reader').children].find(n=>n.textContent==='curiosity').click()
const dot=[...$('reader').children].find(n=>n.textContent==='.')
const range=document.createRange();range.selectNodeContents(dot)
w.getSelection().removeAllRanges();w.getSelection().addRange(range)
document.dispatchEvent(new w.Event('selectionchange'))
await new Promise(resolve=>setTimeout(resolve,130))
assert.equal($('panel').hidden,true)
assert.equal($('reader').querySelectorAll('.selected').length,0)
}))
test('native selection maps DOM text through spans and expands to full token endpoints',()=>page(async($,w)=>{
const spans=[...$('reader').children]
const start=spans.find(n=>n.textContent==='Mira'),end=spans.find(n=>n.textContent==='workshop')
const range=document.createRange();range.setStart(start.firstChild,2);range.setEnd(end.firstChild,3)
w.getSelection().removeAllRanges();w.getSelection().addRange(range)
document.dispatchEvent(new w.Event('selectionchange'))
await new Promise(resolve=>setTimeout(resolve,130))
assert.equal($('term').textContent,'Mira opened the workshop')
const result=JSON.parse($('range-output').textContent)
assert.equal($('reader').textContent.slice(...result.utf16),result.text)
}))
test('explicit save updates repeated words; unsaved edits are discarded on close',()=>page(($)=>{
const words=[...$('reader').children].filter(n=>n.textContent==='curiosity')
words[0].click();$('meaning').value='虚构释义';$('save').click()
assert.ok(words.every(n=>n.classList.contains('learning')))
$('meaning').value='未保存修改';$('close').click();words[1].click()
assert.equal($('meaning').value,'虚构释义')
$('next').click();assert.equal($('panel').hidden,true)
}))