DSH-Arch-Setup/plugins/dsh-touched-git/test/editor-route.test.js
Шурупов Илья Викторович cf9443753e Add one-command Arch DSH setup
Package the portable DSH profiles, local plugins, desktop integration, Firefox wrapper, and ownership-aware installer lifecycle. Bundle checksum-pinned OpenVSCode, editor extensions, translation assets, and cloudflared so unreliable upstream artifact downloads cannot break a clean installation.
2026-09-12 19:13:36 +03:00

193 lines
6.1 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { createEditorOpenHandler } from '../lib/editor-route.js'
function trackedEntry(overrides = {}) {
return {
ok: true,
id: 'entry-1',
path: '/repo',
repository: '/repo',
workingDirectory: '/repo/work',
...overrides,
}
}
function makeRequest(overrides = {}) {
return {
method: 'POST',
url: '/touched-git/editor/open?sessionId=s1&path=%2Frepo%2Fwork',
headers: { host: '127.0.0.1:3080', 'x-dsh-editor-action': 'open' },
...overrides,
}
}
function makeResponse() {
return {
statusCode: 0,
headers: {},
body: null,
setHeader(name, value) { this.headers[name] = value },
}
}
function writeJson(response, status, body) {
response.statusCode = status
response.body = body
return body
}
function buildHandler(overrides = {}) {
const calls = { resolved: [], opened: [] }
const deps = {
store: { list: async () => [trackedEntry()] },
resolveDirectoryRepository: async (directory) => {
calls.resolved.push(directory)
return { repository: '/repo', workingDirectory: '/repo/work' }
},
isLoopbackRequest: () => true,
editor: {
open: async (directory) => {
calls.opened.push(directory)
return { url: 'http://127.0.0.1:40000/?tkn=x&folder=/repo/work', directory }
},
},
writeJson,
...overrides,
}
return { handler: createEditorOpenHandler(deps), calls }
}
test('a non-POST request is rejected and never opens an editor', async () => {
const { handler, calls } = buildHandler()
const response = makeResponse()
const body = await handler(makeRequest({ method: 'GET' }), response)
assert.equal(response.statusCode, 405)
assert.equal(body.error.code, 'method-not-allowed')
assert.equal(calls.opened.length, 0)
})
test('a cross-site request without a loopback origin is forbidden', async () => {
const { handler, calls } = buildHandler({ isLoopbackRequest: () => false })
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 403)
assert.equal(body.error.code, 'forbidden')
assert.equal(calls.opened.length, 0)
})
test('a request missing the custom editor-action header is forbidden', async () => {
const { handler, calls } = buildHandler()
const response = makeResponse()
const request = makeRequest({ headers: { host: '127.0.0.1:3080' } })
const body = await handler(request, response)
assert.equal(response.statusCode, 403)
assert.equal(body.error.code, 'forbidden')
assert.equal(calls.opened.length, 0)
})
test('a request missing the session or directory is a bad request', async () => {
const { handler, calls } = buildHandler()
const response = makeResponse()
const request = makeRequest({ url: '/touched-git/editor/open?sessionId=s1' })
const body = await handler(request, response)
assert.equal(response.statusCode, 400)
assert.equal(body.error.code, 'invalid-request')
assert.equal(calls.opened.length, 0)
})
test('a directory the session does not track is refused', async () => {
const { handler, calls } = buildHandler({ store: { list: async () => [] } })
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 403)
assert.equal(body.error.code, 'not-tracked')
assert.equal(calls.opened.length, 0)
})
test('an invalid tracked entry is never matched or opened', async () => {
const invalid = trackedEntry({ ok: false, error: { message: 'Directory is unavailable.' } })
const { handler, calls } = buildHandler({ store: { list: async () => [invalid] } })
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 403)
assert.equal(body.error.code, 'not-tracked')
assert.equal(calls.opened.length, 0)
})
test('a relocated repository is refused before opening', async () => {
const { handler, calls } = buildHandler({
resolveDirectoryRepository: async () => ({ repository: '/moved', workingDirectory: '/moved/work' }),
})
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 409)
assert.equal(body.error.code, 'directory-changed')
assert.equal(calls.opened.length, 0)
})
test('a directory deleted since tracking fails resolution and never opens', async () => {
const { handler, calls } = buildHandler({
resolveDirectoryRepository: async () => { throw new Error('ENOENT: no such file or directory') },
})
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 503)
assert.equal(body.error.code, 'editor-unavailable')
assert.equal(body.error.message, 'ENOENT: no such file or directory')
assert.equal(calls.opened.length, 0)
})
test('a tracked directory opens its resolved working directory only', async () => {
const { handler, calls } = buildHandler()
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 200)
assert.equal(body.ok, true)
assert.equal(body.value.directory, '/repo/work')
assert.deepEqual(calls.resolved, ['/repo/work'])
assert.deepEqual(calls.opened, ['/repo/work'])
assert.equal(response.headers['cache-control'], 'no-store')
})
test('an entry matched by its id still opens the resolved working directory', async () => {
const { handler, calls } = buildHandler()
const response = makeResponse()
const request = makeRequest({ url: '/touched-git/editor/open?sessionId=s1&path=entry-1' })
const body = await handler(request, response)
assert.equal(response.statusCode, 200)
assert.deepEqual(calls.opened, ['/repo/work'])
})
test('an editor failure is reported as an unavailable editor', async () => {
const { handler } = buildHandler({
editor: { open: async () => { throw new Error('runtime is not installed') } },
})
const response = makeResponse()
const body = await handler(makeRequest(), response)
assert.equal(response.statusCode, 503)
assert.equal(body.error.code, 'editor-unavailable')
assert.equal(body.error.message, 'runtime is not installed')
})