Spaces:
Sleeping
Sleeping
File size: 12,976 Bytes
31226fd dcd5bb9 31226fd 76af1af 31226fd 76af1af 31226fd 850ee3d 31226fd 76af1af 31226fd 990036c 31226fd 850ee3d 31226fd | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 | import { test, expect } from '@playwright/test';
import { selectRoute, selectLabStage, selectResearchView } from './routes.js';
test.use({ baseURL: 'http://127.0.0.1:4174' });
for (const port of [4174, 4175]) {
test(`real server ${port}: routing, catalog, MSBA and shared file/chat renderer`, async ({ page }) => {
const errors = [];
page.on('pageerror', error => errors.push(error.message));
await page.goto(`http://127.0.0.1:${port}/`);
await selectLabStage(page, 'question');
await expect(page.locator('#workflow-research-results')).toBeVisible();
await page.locator('#workflow-research-search').fill('RQ-MSBA-E01');
await expect(page.locator('.research-rq-card')).toHaveCount(1);
await page.locator('.research-rq-card').click();
await expect(page.locator('#workflow-research-results')).toContainText('OPERATIONAL');
await page.locator('#workflow-research-detail-close').click();
await expect(page.locator('#workflow-research-detail')).toBeHidden();
await page.locator('#workflow-research-operational').check();
await expect(page.locator('.research-rq-card')).toHaveCount(1);
await page.locator('#workflow-research-operational').uncheck();
await selectRoute(page, 'old', 'wesen-symbiosis');
await expect(page.locator('#wesen-neural-symbiosis')).toBeVisible();
await expect(page.locator('#wesen-msba-pathways')).toContainText('Audio');
await selectRoute(page, 'old', 'wesen-profile');
await expect(page.locator('#wesen-profile-identity')).toBeVisible();
await expect(page.locator('#wesen-profile-identity')).toContainText('Profile & Identität');
await selectLabStage(page, 'question');
await selectResearchView(page, 'files');
await page.locator('#fm-popup-toggle').uncheck();
await page.locator('.fm-source-btn[data-source="docs"]').click();
const preview = page.locator('.fm-tree-file').filter({ has: page.locator('.fm-file-label', { hasText: 'preview.md' }) });
const csv = page.locator('.fm-tree-file').filter({ has: page.locator('.fm-file-label', { hasText: 'data.csv' }) });
await expect(preview).toBeVisible();
await expect(csv).toBeVisible();
await page.locator('.fm-filter-chip').filter({ hasText: /^Markdown$/ }).click();
await expect(preview).toBeVisible();
await expect(csv).toBeHidden();
await page.locator('.fm-filter-chip').filter({ hasText: /^All$/ }).click();
await expect(csv).toBeVisible();
await preview.locator('.fm-file-label').click();
const viewer = page.locator('#fm-viewer');
await expect(viewer).toHaveAttribute('data-render-state', 'ready');
await expect(viewer.locator('.file-renderer-body h2')).toHaveText('Gemeinsamer Renderer');
await expect(viewer.locator('.file-renderer-body script')).toHaveCount(0);
expect(await page.evaluate(() => window.unsafeExecuted)).toBeUndefined();
await viewer.getByRole('button', { name: 'Im Chat anzeigen', exact: true }).click();
const card = page.locator('#research-chat-log .chat-file-card .file-renderer');
await expect(card).toHaveAttribute('data-render-state', 'ready');
await expect(card.locator('.file-renderer-body')).toContainText(/Dateiinhalt|File content/);
await expect(card.getByRole('button', { name: 'Bearbeiten', exact: true })).toHaveCount(0);
await card.getByRole('button', { name: 'Messdaten', exact: true }).click();
await expect(page.locator('[data-file-key="docs/sample.json"] .file-renderer')).toHaveAttribute('data-file-kind', 'json');
await page.screenshot({ path: `test-results/fullstack-${port}.png`, fullPage: true });
expect(errors).toEqual([]);
});
}
test('real file service: edits persist, stale writers fail, originals stream', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
const reference = 'notes/browser-edit.md';
const url = `/api/files/document/${encodeURIComponent(reference)}?source=docs`;
const created = await page.request.put(url, { data: { action: 'create', content: '# Original\n' } });
expect(created.ok()).toBeTruthy();
const data = await created.json();
const edited = await page.request.put(url, { data: { action: 'write', content: '# Updated\n', expected_sha256: data.file.sha256 } });
expect(edited.ok()).toBeTruthy();
const stale = await page.request.put(url, { data: { action: 'write', content: 'stale', expected_sha256: data.file.sha256 } });
expect(stale.status()).toBe(409);
const raw = await page.request.get(`/api/files/raw/${encodeURIComponent(reference)}?source=docs`, { headers: { Range: 'bytes=0-8' } });
expect(raw.status()).toBe(206);
expect(await raw.text()).toBe('# Updated');
const protectedWrite = await page.request.put('/api/files/document/registry%2Fquestions.yaml?source=research', { data: { action: 'write', content: '[]', expected_sha256: 'invalid' } });
expect(protectedWrite.status()).toBe(403);
const unknown = await page.request.get('/api/files/preview/unknown.b5d?source=docs');
expect((await unknown.json()).kind).toBe('binary');
});
test('real registered batch: runner, manifest, DATA, report and central rendering', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
const id = `EXP-BROWSER-${Date.now()}`;
const response = await page.request.post('/api/experiment/workflow/batch', { data: {
batch_id: id, protocols: ['temporal_order_spiking_v1'],
protocol_options: { temporal_order_spiking_v1: { seeds: '101-120', ticks: 32 } },
}, timeout: 30_000 });
expect(response.ok()).toBeTruthy();
const result = await response.json();
expect(result.failed, JSON.stringify(result)).toBe(0);
expect(result.completed).toBe(1);
const path = `experiments/${id}-01/manifest.json`;
const manifestResponse = await page.request.get(`/api/files/preview/${encodeURIComponent(path)}?source=research`);
expect(manifestResponse.ok()).toBeTruthy();
const descriptor = await manifestResponse.json();
const manifest = JSON.parse(descriptor.content);
expect(manifest.experiment_status).toBe('completed');
expect(manifest.epistemic_layers.evid).toContain('not_created');
expect(descriptor.read_only).toBe(true);
await selectLabStage(page, 'question');
await page.evaluate(async (filePath) => {
const module = await import('/file-renderer.js');
const host = document.createElement('section'); host.id = 'fullstack-artifact'; document.querySelector('#tab-research').prepend(host);
await module.renderFile(host, { source: 'research', path: filePath });
}, path);
await expect(page.locator('#fullstack-artifact')).toHaveAttribute('data-render-state', 'ready');
await expect(page.locator('#fullstack-artifact')).toContainText('temporal_order_spiking_v1');
});
test('real inventory changes reach the Wesen pipeline view without authorizing devices', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
await selectRoute(page, 'old', 'wesen-symbiosis');
await page.request.post('/__test__/inventory', { data: { available: true } });
const camera = page.locator('#wesen-symbiosis-pipelines .wesen-symbiosis-item').filter({ hasText: 'Camera' });
const robot = page.locator('#wesen-symbiosis-pipelines .wesen-symbiosis-item').filter({ hasText: 'Robotics' });
await expect(camera).toHaveClass(/reachable/);
await expect(camera).toContainText('endpoint reachable');
await expect(robot).toContainText('endpoint reachable');
await expect.poll(async () => {
const response = await page.request.get('/api/embodiment/connections');
const data = await response.json();
return data.connections.find(item => item.connection_id === 'sensor.camera.browser')?.available;
}).toBe(true);
await page.request.post('/__test__/inventory', { data: { available: false } });
await expect.poll(async () => {
const response = await page.request.get('/api/embodiment/connections');
const data = await response.json();
const item = data.connections.find(item => item.connection_id === 'sensor.camera.browser');
return item && !item.available && !item.authorized && !item.active;
}).toBe(true);
await expect(camera).toContainText('endpoint unavailable');
await expect(robot).toContainText('endpoint unavailable');
await expect(page.locator('#wesen-neural-symbiosis')).toContainText('EXPERIMENT CONTROL');
await expect(page.locator('#wesen-neural-symbiosis')).toContainText('Productive Gateway: LOCKED');
});
test('canonical file viewer: split editor live preview and stale-write conflict diff', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
const reference = `notes/split-editor-${Date.now()}.md`;
const url = `/api/files/document/${encodeURIComponent(reference)}?source=docs`;
const created = await page.request.put(url, { data: { action: 'create', content: '# Initial\n\nBody\n' } });
expect(created.ok()).toBeTruthy();
const createdData = await created.json();
await selectRoute(page, 'files', 'browse');
await page.locator('#fm-popup-toggle').uncheck();
// Exercise the actual shared viewer and its layout, not an orphan body child
// placed underneath fixed chrome by the test itself.
await page.evaluate(filePath => window.openBrain5DFile('docs', filePath), reference);
const host = page.locator('#fm-viewer');
await expect(host).toHaveAttribute('data-render-state', 'ready');
await host.getByRole('button', { name: 'Bearbeiten', exact: true }).click();
await expect(host.locator('.file-renderer-editor-split')).toBeVisible();
const editor = host.locator('.file-renderer-editor');
await editor.fill('# Live Preview\n\nUpdated in browser');
await expect(host.locator('.file-renderer-editor-preview')).toContainText('Live Preview');
await expect(host.locator('.file-renderer-editor-preview')).toContainText('Updated in browser');
const remote = await page.request.put(url, {
data: { action: 'write', content: '# Remote Version\n', expected_sha256: createdData.file.sha256 },
});
expect(remote.ok()).toBeTruthy();
await host.getByRole('button', { name: 'Speichern', exact: true }).click();
await expect(host.locator('.file-renderer-body')).toContainText('Speicherkonflikt');
await expect(host.locator('.file-renderer-body')).toContainText('Remote Version');
await expect(host.locator('.file-renderer-body')).toContainText('Live Preview');
});
test('central research review inbox exposes human review actions', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
await selectRoute(page, 'review', 'inbox');
await expect(page.locator('#review-inbox-list')).toBeVisible();
const inboxResponse = await page.request.get('/api/research/reviews');
expect(inboxResponse.ok()).toBeTruthy();
const inbox = await inboxResponse.json();
expect(Array.isArray(inbox.items)).toBeTruthy();
await expect(page.locator('#review-open-count')).toHaveText(String(inbox.open ?? 0));
if (inbox.items.length) {
await expect(page.locator('#review-inbox-list [data-review-reviewer]').first()).toBeVisible();
await expect(page.locator('#review-inbox-list [data-review-comments]').first()).toBeVisible();
await expect(page.locator('#review-inbox-list [data-review-decision="accepted_as_interpretation"]').first()).toBeVisible();
await expect(page.locator('#review-inbox-list [data-review-decision="rejected"]').first()).toBeVisible();
}
});
test('external review: subtab, public readiness and central viewer without private responses', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
await selectLabStage(page, 'question');
await selectResearchView(page, 'external');
const panel = page.locator('#external-review-status');
await expect(panel).toBeVisible();
await expect(panel).toContainText(/135 (Questions|Fragen)/);
await expect(panel).toContainText('Beurteilung ausstehend');
const metadata = await (await page.request.get('/api/research/external-review')).json();
expect(metadata.response_count).toBeNull();
expect(metadata.scientific_evidence).toBe(false);
await panel.locator('#external-review-method').click();
await expect(page.locator('#fm-viewer-dialog')).toBeVisible();
await expect(page.locator('#fm-dialog-viewer')).toHaveAttribute('data-render-state', 'ready');
await expect(page.locator('#fm-dialog-viewer')).toContainText('Abschlusskriterien');
});
test('external review: stale success is cleared after failed status fetch', async ({ page }) => {
await page.goto('http://127.0.0.1:4174/');
await selectLabStage(page, 'question');
await selectResearchView(page, 'external');
await expect(page.locator('#external-review-summary')).toContainText(/135 (Questions|Fragen)/);
await page.route('**/api/research/external-review', route => route.fulfill({ status: 503, body: '{}' }));
await page.locator('#external-review-refresh').click();
await expect(page.locator('#external-review-summary')).toContainText('Nicht verf\u00fcgbar');
await expect(page.locator('#external-review-stages dt')).toHaveCount(0);
});
|