完成 2.0.0 S4 的外部 AI、admin、account 与 solo SQL 收口,并推进 S5 studio 市场/handoff/旧编辑器入口裁剪。S5 的前端单测、构建与 route-only e2e 已留证;MSW-off 创作主线 e2e 仍因本地后端活体启动口径待修正,已在总账标为未完成验收。
92 lines
3.5 KiB
TypeScript
92 lines
3.5 KiB
TypeScript
import { expect, test, type Page } from '@playwright/test';
|
|
import { Client } from 'pg';
|
|
|
|
test.skip(true, '2.0.0 S5 单人版已移除市场、handoff 或多用户前端入口,本 spec 隔离保留待恢复');
|
|
|
|
/**
|
|
* 市场资产「绑定到作品授权预检」e2e(来源侧 handoff 预检,真实后端,MSW off)。
|
|
*
|
|
* 前置:vite VITE_API_MOCK=false、真实 muse-server 48080、muse_slice_live 有 listed knowledge_base marker 市场资产。
|
|
* 目的:资产详情页先获取授权(acquire)→ 对目标作品做 bind-precheck(targetOwner=knowledge/targetAction=bind),
|
|
* 读回来源侧授权摘要与就绪态(handoffReady),直打真后端(反假绿)。
|
|
* 注:完整交接 token 由知识域消费,本切片只验来源侧预检(Market 不消费 token)。
|
|
*/
|
|
const TOKEN = 'test1';
|
|
const KNOWLEDGE_HANDOFF_ASSET_NAME = '活体市场知识库·handoff e2e';
|
|
|
|
async function seedToken(page: Page): Promise<void> {
|
|
await page.addInitScript((t) => {
|
|
window.localStorage.setItem('accessToken', t);
|
|
window.localStorage.setItem('tenantId', '1');
|
|
}, TOKEN);
|
|
}
|
|
|
|
function createPgClient(): Client {
|
|
return new Client({
|
|
host: process.env.MUSE_POSTGRES_HOST,
|
|
port: Number(process.env.MUSE_POSTGRES_PORT ?? '5433'),
|
|
database: process.env.MUSE_POSTGRES_DATABASE ?? 'muse_slice_live',
|
|
user: process.env.MUSE_POSTGRES_USERNAME ?? 'root',
|
|
password: process.env.MUSE_POSTGRES_PASSWORD,
|
|
ssl: false,
|
|
connectionTimeoutMillis: 10_000,
|
|
});
|
|
}
|
|
|
|
async function readKnowledgeHandoffAssetId(): Promise<number> {
|
|
const client = createPgClient();
|
|
await client.connect();
|
|
try {
|
|
const result = await client.query(
|
|
`SELECT id
|
|
FROM muse_market_asset
|
|
WHERE tenant_id=1
|
|
AND name=$1
|
|
AND asset_type='knowledge_base'
|
|
AND listing_status='listed'
|
|
AND status='active'
|
|
AND deleted=false
|
|
ORDER BY id DESC
|
|
LIMIT 1`,
|
|
[KNOWLEDGE_HANDOFF_ASSET_NAME]
|
|
);
|
|
expect(result.rowCount, '应存在 knowledge_base handoff e2e 市场资产').toBe(1);
|
|
return Number(result.rows[0].id);
|
|
} finally {
|
|
await client.end();
|
|
}
|
|
}
|
|
|
|
test('已授权资产绑定到作品授权预检 → 来源侧就绪(真实后端)', async ({ page, request }) => {
|
|
const assetId = await readKnowledgeHandoffAssetId();
|
|
await seedToken(page);
|
|
|
|
// 前提:确保知识库资产已获取授权(幂等 best-effort;bind-precheck 需授权存在,否则返「Market 授权不存在」)。
|
|
await request
|
|
.post(`http://localhost:48080/app-api/muse/marketplace/assets/${assetId}/purchase`, {
|
|
headers: { Authorization: 'Bearer test1', 'tenant-id': '1', 'X-API-Version': '1' },
|
|
data: { commandId: `e2e-acq-${Date.now()}` },
|
|
})
|
|
.catch(() => undefined);
|
|
|
|
await page.goto(`/market/assets/${assetId}`);
|
|
|
|
// 输入目标作品 + 授权预检,捕获真实 bind-precheck 响应(打真后端,非 mock)。
|
|
await page.getByLabel('目标作品 ID').fill('1');
|
|
const [resp] = await Promise.all([
|
|
page.waitForResponse(
|
|
(r) => new RegExp(`/assets/${assetId}/bind-precheck$`).test(r.url()) && r.request().method() === 'POST',
|
|
{ timeout: 15_000 }
|
|
),
|
|
page.getByRole('button', { name: '授权预检' }).click(),
|
|
]);
|
|
|
|
// Yudao 口径:成功为 HTTP 200 + CommonResult{code:0}。
|
|
expect(resp.status()).toBe(200);
|
|
const body = await resp.json();
|
|
expect(body.code).toBe(0);
|
|
expect(body.data?.handoffReady).toBe(true);
|
|
// 回显:预检就绪态(可绑定)。
|
|
await expect(page.getByText('可绑定(就绪)')).toBeVisible({ timeout: 15_000 });
|
|
});
|