大更新

This commit is contained in:
2026-08-08 19:16:58 +08:00
parent d289f8d6e2
commit ae5dc3eb46
178 changed files with 69427 additions and 525 deletions
+129
View File
@@ -0,0 +1,129 @@
import {expect, test} from '@playwright/test';
test('gallery exposes every capability section', async ({page}) => {
await page.goto('/');
await expect(page.getByText('ADMINIVE CAPABILITY GALLERY')).toBeVisible();
for(const section of ['backend', 'frontend', 'form', 'collection', 'adapters', 'managed', 'transaction', 'boundaries', 'runtime', 'docs']) {
await page.locator(`[data-section="${section}"]`).click();
await expect(page.locator(`[data-section="${section}"]`)).toHaveClass(/active/);
}
});
test('frontend-owned layout renders one manifest five ways', async ({page}) => {
await page.goto('/');
await page.locator('[data-section="frontend"]').click();
await expect(page.locator('[data-layout]')).toHaveCount(5);
await expect(page.getByText('Renderer Registry', {exact: true})).toBeVisible();
for(const layout of ['horizontal', 'vertical', 'list', 'cards', 'table']) {
await expect(page.locator(`[data-layout="${layout}"]`)).toContainText('alpha');
await expect(page.locator(`[data-layout="${layout}"]`)).toContainText('beta');
await expect(page.locator(`[data-layout="${layout}"]`)).toContainText('gamma');
}
});
test('form gallery switches display create and edit modes', async ({page}) => {
await page.goto('/');
await page.locator('[data-section="form"]').click();
for(const mode of ['Display', 'Create', 'Edit']) {
await page.getByRole('button', {name: mode, exact: true}).click();
await expect(page.locator('.content')).toContainText(`"mode": "${mode.toLowerCase()}"`);
}
await expect(page.getByText('Field Policy Matrix', {exact: true})).toBeVisible();
await expect(page.locator('.content')).toContainText('backend_only');
await expect(page.locator('.content')).toContainText('"include_default": false');
});
test('collection lab executes paging sort search filter reorder and status', async ({page}) => {
await page.goto('/');
await page.locator('[data-section="collection"]').click();
await page.getByRole('button', {name: /分页 perPage=2/}).click();
await expect(page.locator('body')).toContainText('"http_status": 200');
await page.getByRole('button', {name: /^排序 /}).click();
await expect(page.locator('body')).toContainText('orderDir=desc');
await page.getByRole('button', {name: /^搜索 /}).click();
await expect(page.locator('body')).toContainText('"total": 1');
await page.getByRole('button', {name: /^筛选 /}).click();
await expect(page.locator('body')).toContainText('"http_status": 200');
await page.getByRole('button', {name: '真实 Row Reorder'}).click();
await expect(page.locator('body')).toContainText('/admin/gallery/items/order');
await page.getByRole('button', {name: 'Column Reorder'}).click();
await expect(page.locator('body')).toContainText('列顺序属于前端表现状态');
await page.getByRole('button', {name: 'Item Status'}).click();
await expect(page.locator('body')).toContainText('enabled');
await page.getByRole('button', {name: 'Overview Status'}).click();
await expect(page.locator('body')).toContainText('service_state');
await page.getByRole('button', {name: /非法排序/}).click();
await expect(page.locator('body')).toContainText('table query field is not sortable');
await page.getByRole('button', {name: '非法筛选字段'}).click();
await expect(page.locator('body')).toContainText('table query field is not searchable or filterable');
});
test('browser api covers collection crud validation sensitive output and runtime transaction', async ({request}) => {
const sensitive = await request.get('/admin/gallery/advanced/adapter/data');
expect(sensitive.status()).toBe(200);
expect((await sensitive.json()).data).not.toHaveProperty('secret');
const invalid = await request.post('/admin/gallery/config/data', {data: {even_number: 3, number_value: 101, nested: {port: 70000}}});
expect(invalid.status()).toBe(422);
const invalid_body = await invalid.json();
expect(invalid_body.errors).toHaveProperty('even_number');
expect(invalid_body.errors).toHaveProperty(['nested.port']);
const created = await request.post('/admin/gallery/items', {data: {name: 'Playwright', category: 'primary', score: 88, enabled: true, color: '#2563eb'}});
expect(created.status()).toBe(200);
const created_body = await created.json();
const id = created_body.data.id as number;
const read = await request.get(`/admin/gallery/items/${id}`);
expect((await read.json()).data.name).toBe('Playwright');
const put = await request.put(`/admin/gallery/items/${id}`, {data: {score: 89}});
expect(put.status()).toBe(200);
const patch = await request.patch(`/admin/gallery/items/${id}`, {data: {name: 'Playwright Patched'}});
expect(patch.status()).toBe(200);
const searched = await request.get('/admin/gallery/items?name=Playwright%20Patched');
expect((await searched.json()).data.total).toBe(1);
const sorted = await request.get('/admin/gallery/items?orderBy=score&orderDir=desc');
expect(sorted.status()).toBe(200);
const filtered = await request.get('/admin/gallery/items?category=primary');
expect(filtered.status()).toBe(200);
const before_runtime = (await (await request.get('/admin/gallery/advanced/object/data')).json()).data;
const runtime_update = await request.post('/admin/gallery/advanced/object/data', {data: {name: 'Playwright Runtime'}});
expect(runtime_update.status()).toBe(200);
const after_runtime = (await (await request.get('/admin/gallery/advanced/object/data')).json()).data;
expect(after_runtime.transaction_commits).toBe(before_runtime.transaction_commits + 1);
expect(after_runtime.apply_count).toBe(before_runtime.apply_count + 1);
const removed = await request.delete(`/admin/gallery/items/${id}`);
expect(removed.status()).toBe(200);
});
test('transaction lab shows commit failure and rollback', async ({page}) => {
await page.goto('/');
await page.locator('[data-section="transaction"]').click();
await page.getByRole('button', {name: 'Commit 失败并回滚'}).click();
await expect(page.locator('body')).toContainText('external commit failed');
await expect(page.locator('body')).toContainText('rollback');
});
test('protocol boundary page exposes nested and manifest errors', async ({page}) => {
await page.goto('/');
await page.locator('[data-section="boundaries"]').click();
await expect(page.locator('body')).toContainText('multi-field-validation');
await expect(page.locator('body')).toContainText('manifest-duplicate-slot');
await page.getByRole('button', {name: '重新执行全部边界用例'}).click();
await expect(page.locator('body')).toContainText('duplicate composition slot reference');
});
test('status services are live and change sequence', async ({request}) => {
const first = await request.get('/admin/status');
const second = await request.get('/admin/status');
expect(first.status()).toBe(200);
expect(second.status()).toBe(200);
const first_data = (await first.json()).data;
const second_data = (await second.json()).data;
expect(second_data.poll_sequence.value).toBeGreaterThan(first_data.poll_sequence.value);
});
test('html is no-store while hashed and versioned assets are immutable', async ({request}) => {
const index = await request.get('/');
expect(index.status()).toBe(200);
expect(index.headers()['cache-control']).toContain('no-store');
const html = await index.text();
const asset = html.match(/src="(\/assets\/[^"]+\.js)"/);
expect(asset).not.toBeNull();
const module = await request.get(asset![1]);
expect(module.status()).toBe(200);
expect(module.headers()['cache-control']).toContain('immutable');
const amis_asset = html.match(/src="(\/vendor\/amis\/[^/]+\/sdk\.js)"/);
expect(amis_asset).not.toBeNull();
const amis = await request.get(amis_asset![1]);
expect(amis.status()).toBe(200);
expect(amis.headers()['cache-control']).toContain('immutable');
});