this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 323 lines 12 kB view raw
1/** 2 * Playwright test for js_top_worker demo page 3 * Run with: node test/browser/test_demo.js 4 */ 5 6const { chromium } = require('playwright'); 7 8async function runTests() { 9 console.log('Launching browser...'); 10 const browser = await chromium.launch({ 11 headless: true, 12 args: ['--no-sandbox', '--disable-setuid-sandbox'] 13 }); 14 15 const context = await browser.newContext(); 16 const page = await context.newPage(); 17 18 // Collect console messages 19 const consoleMessages = []; 20 page.on('console', msg => { 21 consoleMessages.push({ type: msg.type(), text: msg.text() }); 22 console.log(`[browser ${msg.type()}] ${msg.text()}`); 23 }); 24 25 // Collect page errors 26 const pageErrors = []; 27 page.on('pageerror', err => { 28 pageErrors.push(err.message); 29 console.log(`[page error] ${err.message}`); 30 }); 31 32 console.log('Navigating to demo page...'); 33 await page.goto('http://localhost:8000/demo.html', { timeout: 30000 }); 34 35 // Wait for initialization 36 console.log('Waiting for toplevel to initialize...'); 37 try { 38 await page.waitForFunction( 39 () => document.getElementById('status-indicator')?.classList.contains('ready'), 40 { timeout: 60000 } 41 ); 42 console.log('✓ Toplevel initialized successfully'); 43 } catch (e) { 44 const status = await page.$eval('#status-text', el => el.textContent); 45 console.log(`✗ Initialization failed. Status: ${status}`); 46 47 // Print relevant console messages 48 const errors = consoleMessages.filter(m => m.type === 'error' || m.text.includes('error')); 49 if (errors.length > 0) { 50 console.log('Console errors:'); 51 errors.slice(0, 10).forEach(m => console.log(` [${m.type}] ${m.text}`)); 52 } 53 54 await browser.close(); 55 process.exit(1); 56 } 57 58 const results = { 59 passed: [], 60 failed: [] 61 }; 62 63 // Test 1: Basic Execution 64 console.log('\nTesting Basic Execution...'); 65 try { 66 await page.click('button:has-text("Execute"):near(#exec-input)'); 67 await page.waitForFunction( 68 () => !document.getElementById('exec-output')?.textContent.includes('Executing...'), 69 { timeout: 10000 } 70 ); 71 const execOutput = await page.$eval('#exec-output', el => el.textContent); 72 if (execOutput.includes('Hello, OCaml!')) { 73 console.log('✓ Basic Execution works'); 74 results.passed.push('Basic Execution'); 75 } else { 76 console.log(`✗ Basic Execution failed. Output: ${execOutput}`); 77 results.failed.push({ name: 'Basic Execution', error: execOutput }); 78 } 79 } catch (e) { 80 console.log(`✗ Basic Execution error: ${e.message}`); 81 results.failed.push({ name: 'Basic Execution', error: e.message }); 82 } 83 84 // Test 2: Multiple Environments 85 console.log('\nTesting Multiple Environments...'); 86 try { 87 await page.click('button:has-text("+ New Env")'); 88 await page.waitForTimeout(1000); 89 90 const envButtons = await page.$$eval('#env-selector .env-btn', btns => btns.map(b => b.textContent)); 91 if (envButtons.length > 1) { 92 console.log('✓ Environment creation works'); 93 results.passed.push('Multiple Environments'); 94 } else { 95 console.log(`✗ Environment creation failed. Buttons: ${envButtons.join(', ')}`); 96 results.failed.push({ name: 'Multiple Environments', error: 'No new env button appeared' }); 97 } 98 } catch (e) { 99 console.log(`✗ Multiple Environments error: ${e.message}`); 100 results.failed.push({ name: 'Multiple Environments', error: e.message }); 101 } 102 103 // Test 3: MIME Output 104 console.log('\nTesting MIME Output...'); 105 try { 106 await page.click('button:has-text("Execute"):near(#mime-input)'); 107 await page.waitForFunction( 108 () => !document.getElementById('mime-output')?.textContent.includes('Executing...'), 109 { timeout: 10000 } 110 ); 111 112 // Check if rendered MIME content is visible 113 const mimeRendered = await page.$('#mime-rendered'); 114 const isHidden = await mimeRendered?.evaluate(el => el.classList.contains('hidden')); 115 const mimeOutput = await page.$eval('#mime-output', el => el.textContent); 116 117 if (!isHidden) { 118 const svgContent = await mimeRendered?.evaluate(el => el.innerHTML); 119 if (svgContent?.includes('svg') || svgContent?.includes('circle')) { 120 console.log('✓ MIME Output works (SVG rendered)'); 121 results.passed.push('MIME Output'); 122 } else { 123 console.log(`✗ MIME Output - SVG not rendered. Content: ${svgContent?.substring(0, 100)}`); 124 results.failed.push({ name: 'MIME Output', error: 'SVG not rendered' }); 125 } 126 } else { 127 console.log(`✗ MIME Output - rendered area hidden. Output: ${mimeOutput}`); 128 results.failed.push({ name: 'MIME Output', error: mimeOutput }); 129 } 130 } catch (e) { 131 console.log(`✗ MIME Output error: ${e.message}`); 132 results.failed.push({ name: 'MIME Output', error: e.message }); 133 } 134 135 // Test 4: Autocomplete 136 console.log('\nTesting Autocomplete...'); 137 try { 138 await page.click('button:has-text("Complete")'); 139 await page.waitForFunction( 140 () => !document.getElementById('complete-output')?.textContent.includes('Loading...'), 141 { timeout: 10000 } 142 ); 143 144 const completions = await page.$eval('#complete-output', el => el.textContent); 145 if (completions.includes('map') || completions.includes('mapi')) { 146 console.log('✓ Autocomplete works'); 147 results.passed.push('Autocomplete'); 148 } else { 149 console.log(`✗ Autocomplete failed. Output: ${completions}`); 150 results.failed.push({ name: 'Autocomplete', error: completions }); 151 } 152 } catch (e) { 153 console.log(`✗ Autocomplete error: ${e.message}`); 154 results.failed.push({ name: 'Autocomplete', error: e.message }); 155 } 156 157 // Test 5: Type Information 158 console.log('\nTesting Type Information...'); 159 try { 160 await page.click('button:has-text("Get Type")'); 161 await page.waitForFunction( 162 () => !document.getElementById('type-output')?.textContent.includes('Loading...'), 163 { timeout: 10000 } 164 ); 165 166 const typeOutput = await page.$eval('#type-output', el => el.textContent); 167 if (typeOutput.includes('int') || typeOutput.includes('list') || typeOutput.includes('->')) { 168 console.log('✓ Type Information works'); 169 results.passed.push('Type Information'); 170 } else { 171 console.log(`✗ Type Information failed. Output: ${typeOutput}`); 172 results.failed.push({ name: 'Type Information', error: typeOutput }); 173 } 174 } catch (e) { 175 console.log(`✗ Type Information error: ${e.message}`); 176 results.failed.push({ name: 'Type Information', error: e.message }); 177 } 178 179 // Test 6: Error Reporting 180 console.log('\nTesting Error Reporting...'); 181 try { 182 await page.click('button:has-text("Check Errors")'); 183 await page.waitForFunction( 184 () => !document.getElementById('errors-output')?.textContent.includes('Analyzing...'), 185 { timeout: 10000 } 186 ); 187 188 const errorsOutput = await page.$eval('#errors-output', el => el.textContent); 189 // Should find type error or unknown identifier 190 if (errorsOutput.includes('Line') || errorsOutput.includes('error') || errorsOutput.includes('Error')) { 191 console.log('✓ Error Reporting works'); 192 results.passed.push('Error Reporting'); 193 } else { 194 console.log(`✗ Error Reporting failed. Output: ${errorsOutput}`); 195 results.failed.push({ name: 'Error Reporting', error: errorsOutput }); 196 } 197 } catch (e) { 198 console.log(`✗ Error Reporting error: ${e.message}`); 199 results.failed.push({ name: 'Error Reporting', error: e.message }); 200 } 201 202 // Test 7: Directives - #show List 203 console.log('\nTesting Directives...'); 204 try { 205 await page.click('button:has-text("show List")'); 206 await page.waitForFunction( 207 () => !document.getElementById('directive-output')?.textContent.includes('Executing...'), 208 { timeout: 10000 } 209 ); 210 211 const directiveOutput = await page.$eval('#directive-output', el => el.textContent); 212 if (directiveOutput.includes('module') || directiveOutput.includes('List') || directiveOutput.includes('val')) { 213 console.log('✓ Directives work'); 214 results.passed.push('Directives'); 215 } else { 216 console.log(`✗ Directives failed. Output: ${directiveOutput}`); 217 results.failed.push({ name: 'Directives', error: directiveOutput }); 218 } 219 } catch (e) { 220 console.log(`✗ Directives error: ${e.message}`); 221 results.failed.push({ name: 'Directives', error: e.message }); 222 } 223 224 // Test 8: Custom Printers 225 console.log('\nTesting Custom Printers...'); 226 try { 227 await page.click('button:has-text("Execute"):near(#printer-input)'); 228 await page.waitForFunction( 229 () => !document.getElementById('printer-output')?.textContent.includes('Executing...'), 230 { timeout: 15000 } 231 ); 232 233 const printerOutput = await page.$eval('#printer-output', el => el.textContent); 234 if (printerOutput.includes('[COLOR:') || printerOutput.includes('pp_color')) { 235 console.log('✓ Custom Printers work'); 236 results.passed.push('Custom Printers'); 237 } else { 238 console.log(`✗ Custom Printers failed. Output: ${printerOutput.substring(0, 200)}`); 239 results.failed.push({ name: 'Custom Printers', error: printerOutput.substring(0, 200) }); 240 } 241 } catch (e) { 242 console.log(`✗ Custom Printers error: ${e.message}`); 243 results.failed.push({ name: 'Custom Printers', error: e.message }); 244 } 245 246 // Test 9: Library Loading (#require) 247 console.log('\nTesting Library Loading...'); 248 try { 249 await page.click('button:has-text("Execute"):near(#require-input)'); 250 await page.waitForFunction( 251 () => !document.getElementById('require-output')?.textContent.includes('Executing'), 252 { timeout: 30000 } 253 ); 254 255 const requireOutput = await page.$eval('#require-output', el => el.textContent); 256 // Str.split should return a list 257 if (requireOutput.includes('["a"; "b"; "c"]') || requireOutput.includes('string list')) { 258 console.log('✓ Library Loading works'); 259 results.passed.push('Library Loading'); 260 } else if (requireOutput.includes('Error') || requireOutput.includes('not found')) { 261 console.log(`✗ Library Loading failed (library not available). Output: ${requireOutput}`); 262 results.failed.push({ name: 'Library Loading', error: requireOutput }); 263 } else { 264 console.log(`? Library Loading unclear. Output: ${requireOutput}`); 265 results.failed.push({ name: 'Library Loading', error: requireOutput }); 266 } 267 } catch (e) { 268 console.log(`✗ Library Loading error: ${e.message}`); 269 results.failed.push({ name: 'Library Loading', error: e.message }); 270 } 271 272 // Test 10: Toplevel Script Execution 273 console.log('\nTesting Toplevel Script Execution...'); 274 try { 275 await page.click('button:has-text("Execute Script")'); 276 await page.waitForFunction( 277 () => !document.getElementById('toplevel-output')?.textContent.includes('Executing script...'), 278 { timeout: 15000 } 279 ); 280 281 const toplevelOutput = await page.$eval('#toplevel-output', el => el.textContent); 282 // Should show the squared numbers [1; 4; 9; 16; 25] 283 if (toplevelOutput.includes('[1; 4; 9; 16; 25]') || toplevelOutput.includes('square')) { 284 console.log('✓ Toplevel Script Execution works'); 285 results.passed.push('Toplevel Script Execution'); 286 } else { 287 console.log(`✗ Toplevel Script Execution failed. Output: ${toplevelOutput.substring(0, 200)}`); 288 results.failed.push({ name: 'Toplevel Script Execution', error: toplevelOutput.substring(0, 200) }); 289 } 290 } catch (e) { 291 console.log(`✗ Toplevel Script Execution error: ${e.message}`); 292 results.failed.push({ name: 'Toplevel Script Execution', error: e.message }); 293 } 294 295 // Summary 296 console.log('\n' + '='.repeat(50)); 297 console.log('SUMMARY'); 298 console.log('='.repeat(50)); 299 console.log(`Passed: ${results.passed.length}`); 300 console.log(`Failed: ${results.failed.length}`); 301 302 if (results.failed.length > 0) { 303 console.log('\nFailed tests:'); 304 results.failed.forEach(f => { 305 console.log(` - ${f.name}: ${f.error.substring(0, 100)}`); 306 }); 307 } 308 309 // Print any page errors 310 if (pageErrors.length > 0) { 311 console.log('\nPage errors encountered:'); 312 pageErrors.forEach(e => console.log(` ${e}`)); 313 } 314 315 await browser.close(); 316 317 process.exit(results.failed.length > 0 ? 1 : 0); 318} 319 320runTests().catch(e => { 321 console.error('Test runner error:', e); 322 process.exit(1); 323});