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 = `
This is a test page served by local-file-server widget.
Timestamp: ${new Date().toISOString()}
` 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') } }) })