Files
lms-fe/scripts/test-platform-availability.cjs
T

97 lines
5.1 KiB
JavaScript

const { test } = require('node:test')
const assert = require('node:assert/strict')
const fs = require('node:fs')
const vm = require('node:vm')
const ts = require('typescript')
const source = ts.createSourceFile('App.tsx', fs.readFileSync(require.resolve('../src/renderer/src/App.tsx'), 'utf8'), ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX)
const names = ['isRemotePlatformStatusPending', 'filteredPlatformOptions', 'platformFilterCounts']
const declarations = new Map()
function visit(node) {
if (ts.isVariableDeclaration(node) && names.includes(node.name.getText(source))) {
declarations.set(node.name.getText(source), node.getText(source))
}
ts.forEachChild(node, visit)
}
visit(source)
for (const name of names) assert.ok(declarations.has(name), `missing ${name}`)
const filterScript = ts.transpileModule(`${names.map(name => `const ${declarations.get(name)}`).join('\n')}
result = { counts: platformFilterCounts, ids: filteredPlatformOptions.map(platform => platform.id) }`, {
compilerOptions: { target: ts.ScriptTarget.ES2022 }
}).outputText
const controlSource = fs.readFileSync(require.resolve('../src/renderer/src/features/platforms/platformControl.ts'), 'utf8')
const control = {}
vm.runInNewContext(ts.transpileModule(controlSource, { compilerOptions: { module: ts.ModuleKind.CommonJS } }).outputText, {
exports: control,
require: name => {
assert.equal(name, '../../config/appConfig')
return { LMS_API_BASE_URL: 'http://unused.invalid' }
}
})
function classify(platformOptions, checkedIds = ['mini'], platformFilter = 'all') {
const context = {
platformOptions, platformFilter,
checkedRemotePlatformStatusIds: new Set(checkedIds),
isPlatformUnavailable: control.isPlatformUnavailable
}
vm.runInNewContext(filterScript, context)
return JSON.parse(JSON.stringify(context.result))
}
const simulation = { id: 'sim', platformKey: 'futuredrive-local-pc', state: 'ready', status: '사용 가능', action: '시작' }
const mini = { id: 'mini', platformKey: 'mkmini', state: 'ready', status: '사용 가능', action: '제어권 요청', connection: { headscaleOnline: true, agentHealthy: true } }
test('multiple vehicles of the same platform kind remain independently selectable', () => {
const second = { ...mini, id: 'mini-2', title: 'MK-mini #02' }
const platforms = [simulation, mini, second]
assert.deepEqual(classify(platforms, ['mini', 'mini-2']).ids, ['sim', 'mini', 'mini-2'])
assert.deepEqual(classify(platforms, ['mini', 'mini-2']).counts, { all: 3, available: 3, unavailable: 0 })
const disconnected = { ...mini, status: '연결 끊김', connection: { headscaleOnline: false, agentHealthy: false } }
assert.deepEqual(classify([simulation, disconnected, second], ['mini', 'mini-2'], 'available').ids, ['sim', 'mini-2'])
assert.deepEqual(classify([simulation, disconnected, second], ['mini', 'mini-2'], 'unavailable').ids, ['mini'])
})
test('disconnected ready platform counts as unavailable and appears only in that tab', () => {
const disconnected = { ...mini, status: '연결 끊김', connection: { headscaleOnline: false, agentHealthy: false } }
const platforms = [simulation, disconnected]
assert.deepEqual(classify(platforms), { counts: { all: 2, available: 1, unavailable: 1 }, ids: ['sim', 'mini'] })
assert.deepEqual(classify(platforms, ['mini'], 'available').ids, ['sim'])
assert.deepEqual(classify(platforms, ['mini'], 'unavailable').ids, ['mini'])
})
test('offline network, unhealthy agent and explicit unavailability all exclude ready platforms', () => {
for (const patch of [
{ connection: { headscaleOnline: false, agentHealthy: true } },
{ connection: { headscaleOnline: true, agentHealthy: false } },
{ connection: undefined, status: '연결 끊김' },
{ connection: undefined, status: '연결 불가' },
{ connection: undefined, action: '연결 불가' }
]) {
const platforms = [simulation, { ...mini, ...patch }]
assert.deepEqual(classify(platforms).counts, { all: 2, available: 1, unavailable: 1 })
assert.deepEqual(classify(platforms, ['mini'], 'unavailable').ids, ['mini'])
}
})
test('pending remote status remains in All without prematurely entering either availability tab', () => {
const platforms = [simulation, mini]
assert.deepEqual(classify(platforms, []).counts, { all: 2, available: 1, unavailable: 0 })
assert.deepEqual(classify(platforms, [], 'available').ids, ['sim'])
assert.deepEqual(classify(platforms, [], 'unavailable').ids, [])
})
test('reconnecting moves a platform back to available without changing All', () => {
assert.deepEqual(classify([simulation, mini]).counts, { all: 2, available: 2, unavailable: 0 })
assert.deepEqual(classify([simulation, mini], ['mini'], 'available').ids, ['sim', 'mini'])
assert.deepEqual(classify([simulation, mini], ['mini'], 'unavailable').ids, [])
})
test('locked, requested and reserved platform classifications are preserved', () => {
for (const state of ['locked', 'request', 'reserved']) {
const platforms = [simulation, { ...mini, state }]
assert.deepEqual(classify(platforms).counts, { all: 2, available: 1, unavailable: 1 })
assert.deepEqual(classify(platforms, ['mini'], 'unavailable').ids, ['mini'])
}
})