214 lines
5.6 KiB
JavaScript
214 lines
5.6 KiB
JavaScript
const {
|
|
test: it, expect
|
|
} = require('@playwright/test')
|
|
const { describe } = it
|
|
const { listWidgets, runWidget, stopWidget } = require('../../src/app/widgets/load-widget')
|
|
const os = require('os')
|
|
const path = require('path')
|
|
const fs = require('fs/promises')
|
|
const axios = require('axios')
|
|
it.setTimeout(100000)
|
|
|
|
describe('load-widget', function () {
|
|
let serverInstance = null
|
|
let testDir = null
|
|
let serverUrl = null
|
|
|
|
// Helper to create test files
|
|
async function createTestFiles () {
|
|
testDir = path.join(os.tmpdir(), 'electerm-test-' + Date.now())
|
|
await fs.mkdir(testDir)
|
|
|
|
// Create a test index.html
|
|
const htmlContent = `
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<title>
|
|
Test Page
|
|
|
|
</title>
|
|
</head>
|
|
<body>
|
|
<h1>
|
|
Hello from Electerm Test
|
|
|
|
</h1>
|
|
<p>
|
|
This is a test page served by local-file-server widget.
|
|
|
|
</p>
|
|
<p>
|
|
Timestamp: ${new Date().toISOString()}
|
|
|
|
</p>
|
|
</body>
|
|
</html>
|
|
`
|
|
await fs.writeFile(path.join(testDir, 'index.html'), htmlContent)
|
|
}
|
|
|
|
// Cleanup helper
|
|
async function cleanup () {
|
|
if (serverInstance) {
|
|
await stopWidget(serverInstance)
|
|
serverInstance = null
|
|
}
|
|
if (testDir) {
|
|
try {
|
|
await fs.rm(testDir, { recursive: true, force: true })
|
|
} catch (err) {
|
|
console.error('Cleanup error:', err)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Setup before tests
|
|
it.beforeEach(async () => {
|
|
await createTestFiles()
|
|
})
|
|
|
|
// Cleanup after tests
|
|
it.afterEach(async () => {
|
|
await cleanup()
|
|
})
|
|
|
|
// Test listWidgets function
|
|
it('listWidgets should list available widgets', async function () {
|
|
const widgets = listWidgets()
|
|
console.log(widgets)
|
|
expect(Array.isArray(widgets)).toBe(true)
|
|
expect(widgets.length).toBeGreaterThan(0)
|
|
|
|
const fileServer = widgets.find(w => w.id === 'local-file-server')
|
|
expect(fileServer).toBeTruthy()
|
|
})
|
|
|
|
// Test runWidget function with file serving
|
|
it('should run local-file-server widget and serve files', async function () {
|
|
const config = {
|
|
directory: testDir,
|
|
port: 3457,
|
|
host: '127.0.0.1',
|
|
maxAge: 365 * 24 * 60 * 60 * 1000,
|
|
cacheControl: true,
|
|
lastModified: true,
|
|
etag: true,
|
|
dotfiles: 'allow',
|
|
redirect: true,
|
|
acceptRanges: true,
|
|
index: 'index.html'
|
|
}
|
|
|
|
try {
|
|
const result = await runWidget('local-file-server', config)
|
|
expect(result).toBeTruthy()
|
|
expect(result.instanceId).toBeTruthy()
|
|
expect(result.serverInfo).toBeTruthy()
|
|
expect(result.serverInfo.url).toBe(`http://${config.host}:${config.port}`)
|
|
expect(result.serverInfo.path).toBe(config.directory)
|
|
|
|
serverInstance = result.instanceId
|
|
serverUrl = result.serverInfo.url
|
|
|
|
// Test file serving
|
|
const response = await axios.get(serverUrl)
|
|
expect(response.status).toBe(200)
|
|
expect(response.headers['content-type']).toMatch(/text\/html/)
|
|
expect(response.data).toContain('Hello from Electerm Test')
|
|
|
|
// Test caching headers
|
|
expect(response.headers['cache-control']).toBeTruthy()
|
|
expect(response.headers.etag).toBeTruthy()
|
|
expect(response.headers['last-modified']).toBeTruthy()
|
|
|
|
// Test non-existent file
|
|
try {
|
|
await axios.get(`${serverUrl}/non-existent.html`)
|
|
throw new Error('Should have thrown 404')
|
|
} catch (err) {
|
|
expect(err.response.status).toBe(404)
|
|
}
|
|
} catch (err) {
|
|
console.log('run widget error:', err)
|
|
throw err
|
|
}
|
|
})
|
|
|
|
// Test directory listing (if enabled)
|
|
it('should handle directory requests properly', async function () {
|
|
if (!serverInstance || !serverUrl) {
|
|
const config = {
|
|
directory: testDir,
|
|
port: 3457,
|
|
host: '127.0.0.1',
|
|
maxAge: 365 * 24 * 60 * 60 * 1000,
|
|
cacheControl: true,
|
|
lastModified: true,
|
|
etag: true,
|
|
dotfiles: 'allow',
|
|
redirect: true,
|
|
acceptRanges: true,
|
|
index: 'index.html'
|
|
}
|
|
const result = await runWidget('local-file-server', config)
|
|
serverInstance = result.instanceId
|
|
serverUrl = result.serverInfo.url
|
|
}
|
|
|
|
// Create a subdirectory with a file
|
|
const subDir = path.join(testDir, 'subdir')
|
|
await fs.mkdir(subDir)
|
|
await fs.writeFile(path.join(subDir, 'index.html'), 'Test content')
|
|
|
|
// Test directory redirect (should redirect to index.html)
|
|
const response = await axios.get(`${serverUrl}/subdir/`)
|
|
expect(response.status).toBe(200)
|
|
})
|
|
|
|
// Test stopWidget function
|
|
it('should stop running widget', async function () {
|
|
if (!serverInstance) {
|
|
console.log('No server instance to stop')
|
|
return
|
|
}
|
|
|
|
const result = await stopWidget(serverInstance)
|
|
expect(result).toBeTruthy()
|
|
expect(result.instanceId).toBe(serverInstance)
|
|
expect(result.status).toBe('stopped')
|
|
|
|
// Verify server is actually stopped
|
|
try {
|
|
await axios.get(serverUrl)
|
|
throw new Error('Server should be stopped')
|
|
} catch (err) {
|
|
expect(err.code).toBe('ECONNREFUSED')
|
|
}
|
|
})
|
|
|
|
// Test error cases
|
|
it('should handle stopping non-existent widget', async function () {
|
|
const result = await stopWidget('non-existent-id')
|
|
expect(result).toBeUndefined()
|
|
})
|
|
|
|
it('should handle invalid widget ID', async function () {
|
|
try {
|
|
await runWidget('non-existent-widget', {})
|
|
throw new Error('Should have thrown an error')
|
|
} catch (error) {
|
|
expect(error).toBeTruthy()
|
|
}
|
|
})
|
|
|
|
it('should reject traversed widget IDs', async function () {
|
|
try {
|
|
await runWidget('../../../../../tmp/evil', {})
|
|
throw new Error('Should have thrown an error')
|
|
} catch (error) {
|
|
expect(error.message).toContain('Invalid widget ID')
|
|
}
|
|
})
|
|
})
|