139 lines
7.0 KiB
TypeScript
139 lines
7.0 KiB
TypeScript
import type { BlockKind, BlockView } from './types'
|
|
import type { ViewStateStorage } from './viewState'
|
|
import { describe, expect, it } from 'vitest'
|
|
import { collapsedIds, createViewStateStore, propertyItemId, propertyRowId } from './viewState'
|
|
|
|
/** 模拟 VS Code 的 webview 状态:存进去的要能序列化,页面重新加载后原样取回;也能塞进旧版本存的东西 */
|
|
function memoryStorage(initial?: unknown): ViewStateStorage {
|
|
let saved = initial === undefined ? undefined : JSON.stringify(initial)
|
|
return {
|
|
getState: () => saved === undefined ? undefined : JSON.parse(saved) as unknown,
|
|
setState: (state) => {
|
|
saved = JSON.stringify(state)
|
|
},
|
|
}
|
|
}
|
|
|
|
function block(id: string, kind: BlockKind, children: BlockView[] = []): BlockView {
|
|
return { id, kind, startLine: 0, endLine: 0, code: '', codeTokens: [], attributes: { kind }, children, translation: [] }
|
|
}
|
|
|
|
/**
|
|
* 0 import
|
|
* 1 function
|
|
* 1.0 if
|
|
* 1.0.0 function(嵌套函数)
|
|
* 2 class
|
|
* 2.0 function(方法)
|
|
*/
|
|
const BLOCKS = [
|
|
block('0', 'import'),
|
|
block('1', 'function', [block('1.0', 'if', [block('1.0.0', 'function', [block('1.0.0.0', 'return')])])]),
|
|
block('2', 'class', [block('2.0', 'function', [block('2.0.0', 'return')])]),
|
|
]
|
|
|
|
describe('webview 状态', () => {
|
|
it('第一次打开:没有编辑中的块、没点过折叠,也没有滚动位置', () => {
|
|
expect(createViewStateStore(memoryStorage()).get()).toEqual({ editing: [], folds: {} })
|
|
})
|
|
|
|
it('块状态和滚动位置各自更新,互不覆盖', () => {
|
|
const storage = memoryStorage()
|
|
const store = createViewStateStore(storage)
|
|
store.update({ editing: ['2'], folds: { 6.1: true } })
|
|
store.update({ scroll: { line: 12, offset: 30, scrollTop: 480 } })
|
|
store.update({ editing: [], folds: { 6.1: true } })
|
|
expect(storage.getState()).toEqual({ editing: [], folds: { 6.1: true }, scroll: { line: 12, offset: 30, scrollTop: 480 } })
|
|
})
|
|
|
|
it('页面重新加载后取回上次存的全部状态', () => {
|
|
const storage = memoryStorage()
|
|
const store = createViewStateStore(storage)
|
|
store.update({ folds: { 3: true, 4: false } })
|
|
store.update({ scroll: { line: 40, offset: -6, scrollTop: 1210 } })
|
|
expect(createViewStateStore(storage).get()).toEqual({ editing: [], folds: { 3: true, 4: false }, scroll: { line: 40, offset: -6, scrollTop: 1210 } })
|
|
})
|
|
|
|
it('旧版本存的、形状不对的项当没存过,认得的项照旧取回', () => {
|
|
expect(createViewStateStore(memoryStorage({ editing: ['1'], collapsed: ['2'] })).get()).toEqual({ editing: ['1'], folds: {} })
|
|
expect(createViewStateStore(memoryStorage({ editing: 'x', folds: ['2'], scroll: { line: 'a' } })).get()).toEqual({ editing: [], folds: {} })
|
|
expect(createViewStateStore(memoryStorage({ editing: [1, '2'], folds: { 1: true, 2: 'yes' } })).get()).toEqual({ editing: ['2'], folds: { 1: true } })
|
|
expect(createViewStateStore(memoryStorage(42)).get()).toEqual({ editing: [], folds: {} })
|
|
expect(createViewStateStore(memoryStorage(null)).get()).toEqual({ editing: [], folds: {} })
|
|
})
|
|
|
|
it('属性行的折叠 id 是块 id 加行序号,不会和块 id 撞上', () => {
|
|
expect(propertyRowId('6.1.0', 3)).toBe('6.1.0/p3')
|
|
expect(propertyRowId('6', 1)).not.toBe('6.1')
|
|
expect(propertyRowId('6.1', 0)).not.toBe(propertyRowId('6', 10))
|
|
})
|
|
|
|
it('属性行和块的折叠选择存在同一份 folds 里,页面重新加载后都还在', () => {
|
|
const storage = memoryStorage()
|
|
createViewStateStore(storage).update({ folds: { 6.1: false, [propertyRowId('6.1.0', 3)]: true } })
|
|
expect(createViewStateStore(storage).get().folds).toEqual({ '6.1': false, '6.1.0/p3': true })
|
|
})
|
|
|
|
it('子行 id 是上一层的 id 加子行序号,一层层往后接;不同位置的不会撞上,也不会和块 id、属性行 id 撞上', () => {
|
|
const row = propertyRowId('6.1.0', 3)
|
|
expect(propertyItemId(row, 1)).toBe('6.1.0/p3/1')
|
|
expect(propertyItemId(propertyItemId(row, 1), 0)).toBe('6.1.0/p3/1/0')
|
|
const ids = [
|
|
'6',
|
|
'6.1',
|
|
propertyRowId('6', 1),
|
|
propertyRowId('6', 11),
|
|
propertyItemId(propertyRowId('6', 1), 1),
|
|
propertyItemId(propertyRowId('6', 11), 1),
|
|
propertyItemId(propertyItemId(propertyRowId('6', 1), 1), 1),
|
|
propertyItemId(propertyItemId(propertyRowId('6', 1), 11), 1),
|
|
propertyItemId(propertyItemId(propertyRowId('6', 1), 1), 11),
|
|
propertyItemId(propertyRowId('6.1', 1), 1),
|
|
]
|
|
expect(new Set(ids).size).toBe(ids.length)
|
|
})
|
|
|
|
it('嵌套子行的折叠选择也存在 folds 里,页面重新加载后还在', () => {
|
|
const storage = memoryStorage()
|
|
const nested = propertyItemId(propertyItemId(propertyRowId('2', 2), 0), 1)
|
|
createViewStateStore(storage).update({ folds: { [nested]: true, [propertyItemId(propertyRowId('2', 2), 0)]: false } })
|
|
expect(createViewStateStore(storage).get().folds).toEqual({ '2/p2/0/1': true, '2/p2/0': false })
|
|
})
|
|
})
|
|
|
|
describe('眼下折叠着哪些', () => {
|
|
it('没点过:函数块(含方法、嵌套函数)、类块折叠,其余块和属性行展开', () => {
|
|
expect([...collapsedIds(BLOCKS, {})].sort()).toEqual(['1', '1.0.0', '2', '2.0'])
|
|
})
|
|
|
|
it('没点过:库规则认领的块(带 badge)和类块一样折叠,不看种类 id', () => {
|
|
const table: BlockView = { ...block('0', 'if', [block('0.0', 'return')]), kind: 'sqlalchemy.table', badge: { label: '数据表', color: { dark: '#e8a860', light: '#a3590d' }, icon: 'database' } }
|
|
expect([...collapsedIds([table, block('1', 'if')], {})]).toEqual(['0'])
|
|
})
|
|
|
|
it('没点过:枚举块(Python 枚举下面留着方法)和类块一样折叠', () => {
|
|
expect([...collapsedIds([block('0', 'enum', [block('0.0', 'function')]), block('1', 'if')], {})]).toEqual(['0', '0.0'])
|
|
})
|
|
|
|
it('没点过:异常块(下面留着构造函数、方法)和类块一样折叠', () => {
|
|
expect([...collapsedIds([block('0', 'exception', [block('0.0', 'function')]), block('1', 'if')], {})]).toEqual(['0', '0.0'])
|
|
})
|
|
|
|
it('标了改动的块默认展开,用户折叠过的照样折叠', () => {
|
|
expect([...collapsedIds(BLOCKS, {}, new Set(['1', '2']))].sort()).toEqual(['1.0.0', '2.0'])
|
|
expect([...collapsedIds(BLOCKS, { 1: true }, new Set(['1']))].sort()).toEqual(['1', '1.0.0', '2', '2.0'])
|
|
})
|
|
|
|
it('点过的按用户的:展开的函数、类保持展开,折叠的其他块、属性行保持折叠', () => {
|
|
const folds = { '1': false, '2': false, '1.0': true, '1.0.0': false, [propertyRowId('0', 2)]: true, [propertyRowId('2.0', 1)]: false }
|
|
expect([...collapsedIds(BLOCKS, folds)].sort()).toEqual(['0/p2', '1.0', '2.0'])
|
|
})
|
|
|
|
it('带下一层的子行默认展开,用户折叠过的按他的', () => {
|
|
const outer = propertyItemId(propertyRowId('0', 2), 0)
|
|
const inner = propertyItemId(outer, 3)
|
|
expect(collapsedIds(BLOCKS, {}).has(outer)).toBe(false)
|
|
expect([...collapsedIds(BLOCKS, { [outer]: false, [inner]: true })].sort()).toEqual(['0/p2/0/3', '1', '1.0.0', '2', '2.0'])
|
|
})
|
|
})
|