Fix 3 OCaml bugs that caused spec explorer to hang: - sx_types: inspect outputs quoted string for SxExpr (not bare symbol) - sx_primitives: serialize/to_string extract SxExpr/RawHTML content - sx_render: handle SxExpr in both render-to-html paths Restructure spec explorer for performance: - Lightweight overview: name + kind only (was full source for 141 defs) - Drill-in detail: click definition → params, effects, signature - explore() page function accepts optional second arg for drill-in - spec() passes through non-string slugs from nested routing Fix aser map result wrapping: - aser-special map now wraps results in fragment (<> ...) via aser-fragment - Prevents ((div ...) (div ...)) nested lists that caused client "Not callable" 5 Playwright tests: overview load, no errors, SPA nav, drill-in detail+params Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
75 lines
3.0 KiB
JavaScript
75 lines
3.0 KiB
JavaScript
const { test, expect } = require('playwright/test');
|
|
const { BASE_URL, trackErrors } = require('./helpers');
|
|
|
|
const LOAD_TIMEOUT = 30000;
|
|
|
|
async function loadExplorer(page, path) {
|
|
await page.goto(BASE_URL + '/sx/' + path, {
|
|
waitUntil: 'domcontentloaded',
|
|
timeout: LOAD_TIMEOUT,
|
|
});
|
|
await page.waitForSelector('h1, .sx-render-error, [data-sx-boundary]', {
|
|
timeout: LOAD_TIMEOUT,
|
|
});
|
|
}
|
|
|
|
test.describe('Spec Explorer', () => {
|
|
test('overview loads with evaluator definitions', async ({ page }) => {
|
|
await loadExplorer(page, '(language.(spec.(explore.evaluator)))');
|
|
|
|
await expect(page.locator('h1')).toHaveText('Evaluator');
|
|
await expect(page.locator('text=141 defines')).toBeVisible();
|
|
await expect(page.locator('text=2501 lines')).toBeVisible();
|
|
await expect(page.locator('h2:has-text("Definitions")')).toBeVisible();
|
|
await expect(page.locator('#fn-make-cek-state')).toBeVisible();
|
|
await expect(page.locator('#fn-cek-step')).toBeVisible();
|
|
// eval-expr has 2 entries (forward decl + real), just check at least 1
|
|
await expect(page.locator('#fn-eval-expr').first()).toBeVisible();
|
|
await expect(page.locator('.sx-render-error')).toHaveCount(0);
|
|
});
|
|
|
|
test('no errors on initial load', async ({ page }) => {
|
|
const tracker = trackErrors(page);
|
|
await loadExplorer(page, '(language.(spec.(explore.evaluator)))');
|
|
await expect(page.locator('h1')).toHaveText('Evaluator');
|
|
expect(tracker.errors()).toEqual([]);
|
|
});
|
|
|
|
test('SPA nav to explorer has no render error', async ({ page }) => {
|
|
await page.goto(BASE_URL + '/sx/(language.(spec))', {
|
|
waitUntil: 'domcontentloaded',
|
|
timeout: LOAD_TIMEOUT,
|
|
});
|
|
await page.waitForSelector('h1, h2', { timeout: LOAD_TIMEOUT });
|
|
|
|
const link = page.locator('a[href*="explore.evaluator"]');
|
|
if (await link.count() > 0) {
|
|
await link.click();
|
|
await page.waitForSelector('#fn-cek-step', { timeout: LOAD_TIMEOUT });
|
|
await expect(page.locator('h1')).toHaveText('Evaluator');
|
|
|
|
const content = await page.locator('#sx-content').textContent();
|
|
expect(content).not.toContain('Render error');
|
|
expect(content).not.toContain('Not callable');
|
|
}
|
|
});
|
|
|
|
test('drill-in shows definition detail', async ({ page }) => {
|
|
await loadExplorer(page, '(language.(spec.(explore.evaluator.cek-step)))');
|
|
|
|
await expect(page.locator('text=cek-step').first()).toBeVisible();
|
|
await expect(page.locator('text=function').first()).toBeVisible();
|
|
await expect(page.locator('a:has-text("Back to evaluator")')).toBeVisible();
|
|
await expect(page.locator('text=define cek-step')).toBeVisible();
|
|
});
|
|
|
|
test('drill-in shows params and pure badge', async ({ page }) => {
|
|
await loadExplorer(page, '(language.(spec.(explore.evaluator.make-cek-state)))');
|
|
|
|
await expect(page.locator('text=control').first()).toBeVisible();
|
|
await expect(page.locator('text=env').first()).toBeVisible();
|
|
await expect(page.locator('text=kont').first()).toBeVisible();
|
|
await expect(page.locator('text=pure').first()).toBeVisible();
|
|
});
|
|
});
|