|
@@ -20,6 +20,9 @@ const TEST_PORT = 3334;
|
|
|
const TEST_DIR = '/tmp/brainstorm-test';
|
|
const TEST_DIR = '/tmp/brainstorm-test';
|
|
|
const CONTENT_DIR = path.join(TEST_DIR, 'content');
|
|
const CONTENT_DIR = path.join(TEST_DIR, 'content');
|
|
|
const STATE_DIR = path.join(TEST_DIR, 'state');
|
|
const STATE_DIR = path.join(TEST_DIR, 'state');
|
|
|
|
|
+// Fixed session key so the test client can authenticate (see auth.test.js for
|
|
|
|
|
+// the security behavior itself; here we just need authorized requests).
|
|
|
|
|
+const TOKEN = 'testtoken-server-0123456789abcdef';
|
|
|
|
|
|
|
|
function cleanup() {
|
|
function cleanup() {
|
|
|
if (fs.existsSync(TEST_DIR)) {
|
|
if (fs.existsSync(TEST_DIR)) {
|
|
@@ -32,8 +35,9 @@ async function sleep(ms) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
async function fetch(url) {
|
|
async function fetch(url) {
|
|
|
|
|
+ const authed = url + (url.includes('?') ? '&' : '?') + 'key=' + TOKEN;
|
|
|
return new Promise((resolve, reject) => {
|
|
return new Promise((resolve, reject) => {
|
|
|
- http.get(url, (res) => {
|
|
|
|
|
|
|
+ http.get(authed, (res) => {
|
|
|
let data = '';
|
|
let data = '';
|
|
|
res.on('data', chunk => data += chunk);
|
|
res.on('data', chunk => data += chunk);
|
|
|
res.on('end', () => resolve({
|
|
res.on('end', () => resolve({
|
|
@@ -47,7 +51,7 @@ async function fetch(url) {
|
|
|
|
|
|
|
|
function startServer() {
|
|
function startServer() {
|
|
|
return spawn('node', [SERVER_PATH], {
|
|
return spawn('node', [SERVER_PATH], {
|
|
|
- env: { ...process.env, BRAINSTORM_PORT: TEST_PORT, BRAINSTORM_DIR: TEST_DIR }
|
|
|
|
|
|
|
+ env: { ...process.env, BRAINSTORM_PORT: TEST_PORT, BRAINSTORM_DIR: TEST_DIR, BRAINSTORM_TOKEN: TOKEN }
|
|
|
});
|
|
});
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -207,7 +211,7 @@ async function runTests() {
|
|
|
console.log('\n--- WebSocket Communication ---');
|
|
console.log('\n--- WebSocket Communication ---');
|
|
|
|
|
|
|
|
await test('accepts WebSocket upgrade on /', async () => {
|
|
await test('accepts WebSocket upgrade on /', async () => {
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise((resolve, reject) => {
|
|
await new Promise((resolve, reject) => {
|
|
|
ws.on('open', resolve);
|
|
ws.on('open', resolve);
|
|
|
ws.on('error', reject);
|
|
ws.on('error', reject);
|
|
@@ -217,7 +221,7 @@ async function runTests() {
|
|
|
|
|
|
|
|
await test('relays user events to stdout with source field', async () => {
|
|
await test('relays user events to stdout with source field', async () => {
|
|
|
stdoutAccum = '';
|
|
stdoutAccum = '';
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
ws.send(JSON.stringify({ type: 'click', text: 'Test Button' }));
|
|
ws.send(JSON.stringify({ type: 'click', text: 'Test Button' }));
|
|
@@ -233,7 +237,7 @@ async function runTests() {
|
|
|
const eventsFile = path.join(STATE_DIR, 'events');
|
|
const eventsFile = path.join(STATE_DIR, 'events');
|
|
|
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
|
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
|
|
|
|
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
ws.send(JSON.stringify({ type: 'click', choice: 'b', text: 'Option B' }));
|
|
ws.send(JSON.stringify({ type: 'click', choice: 'b', text: 'Option B' }));
|
|
@@ -251,7 +255,7 @@ async function runTests() {
|
|
|
const eventsFile = path.join(STATE_DIR, 'events');
|
|
const eventsFile = path.join(STATE_DIR, 'events');
|
|
|
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
|
if (fs.existsSync(eventsFile)) fs.unlinkSync(eventsFile);
|
|
|
|
|
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
ws.send(JSON.stringify({ type: 'hover', text: 'Something' }));
|
|
ws.send(JSON.stringify({ type: 'hover', text: 'Something' }));
|
|
@@ -263,8 +267,8 @@ async function runTests() {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
await test('handles multiple concurrent WebSocket clients', async () => {
|
|
await test('handles multiple concurrent WebSocket clients', async () => {
|
|
|
- const ws1 = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
- const ws2 = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws1 = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
|
|
+ const ws2 = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await Promise.all([
|
|
await Promise.all([
|
|
|
new Promise(resolve => ws1.on('open', resolve)),
|
|
new Promise(resolve => ws1.on('open', resolve)),
|
|
|
new Promise(resolve => ws2.on('open', resolve))
|
|
new Promise(resolve => ws2.on('open', resolve))
|
|
@@ -289,7 +293,7 @@ async function runTests() {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
await test('cleans up closed clients from broadcast list', async () => {
|
|
await test('cleans up closed clients from broadcast list', async () => {
|
|
|
- const ws1 = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws1 = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws1.on('open', resolve));
|
|
await new Promise(resolve => ws1.on('open', resolve));
|
|
|
ws1.close();
|
|
ws1.close();
|
|
|
await sleep(100);
|
|
await sleep(100);
|
|
@@ -301,7 +305,7 @@ async function runTests() {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
await test('handles malformed JSON from client gracefully', async () => {
|
|
await test('handles malformed JSON from client gracefully', async () => {
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
// Send invalid JSON — server should not crash
|
|
// Send invalid JSON — server should not crash
|
|
@@ -318,7 +322,7 @@ async function runTests() {
|
|
|
console.log('\n--- File Watching ---');
|
|
console.log('\n--- File Watching ---');
|
|
|
|
|
|
|
|
await test('sends reload on new .html file', async () => {
|
|
await test('sends reload on new .html file', async () => {
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
let gotReload = false;
|
|
let gotReload = false;
|
|
@@ -338,7 +342,7 @@ async function runTests() {
|
|
|
fs.writeFileSync(filePath, '<h2>Original</h2>');
|
|
fs.writeFileSync(filePath, '<h2>Original</h2>');
|
|
|
await sleep(500);
|
|
await sleep(500);
|
|
|
|
|
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
let gotReload = false;
|
|
let gotReload = false;
|
|
@@ -354,7 +358,7 @@ async function runTests() {
|
|
|
});
|
|
});
|
|
|
|
|
|
|
|
await test('does NOT send reload for non-.html files', async () => {
|
|
await test('does NOT send reload for non-.html files', async () => {
|
|
|
- const ws = new WebSocket(`ws://localhost:${TEST_PORT}`);
|
|
|
|
|
|
|
+ const ws = new WebSocket(`ws://localhost:${TEST_PORT}/?key=${TOKEN}`);
|
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
await new Promise(resolve => ws.on('open', resolve));
|
|
|
|
|
|
|
|
let gotReload = false;
|
|
let gotReload = false;
|