fix: complete marketplace client remediation
This commit is contained in:
@@ -56,4 +56,126 @@ test.describe('Plugin Marketplace', () => {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
});
|
||||
|
||||
test('keeps Beta explicit and exposes bounded unavailable, disabled, and device-delete states', async ({ launchElectronApp }) => {
|
||||
const app = await launchElectronApp({ skipSetup: true });
|
||||
try {
|
||||
const page = await getStableWindow(app);
|
||||
await app.evaluate(({ ipcMain }) => {
|
||||
let installedChannel: 'stable' | 'beta' | null = 'stable';
|
||||
const installedVersion = '1.0.0';
|
||||
const requests: string[] = [];
|
||||
const library = {
|
||||
items: [
|
||||
{
|
||||
pluginId: 'makelore.notes', title: '灵感笔记', summary: '整理项目灵感。', category: '效率',
|
||||
acquisition: 'free', acquisitionMode: 'user_acquired', catalogStatus: 'active', runtimeStatus: 'enabled',
|
||||
acquiredAt: '2026-08-28T00:00:00Z', removedAt: null, stableVersion: '1.0.0', betaVersion: '2.0.0-beta.1',
|
||||
},
|
||||
{
|
||||
pluginId: 'makelore.paused', title: '暂停插件', summary: '暂时暂停。', category: '效率',
|
||||
acquisition: 'free', acquisitionMode: 'user_acquired', catalogStatus: 'active', runtimeStatus: 'suspended',
|
||||
acquiredAt: '2026-08-28T00:00:00Z', removedAt: null, stableVersion: '1.0.0', betaVersion: null,
|
||||
},
|
||||
{
|
||||
pluginId: 'makelore.unavailable', title: '不可用插件', summary: '服务不可用。', category: '效率',
|
||||
acquisition: 'free', acquisitionMode: 'user_acquired', catalogStatus: 'active', runtimeStatus: 'enabled',
|
||||
acquiredAt: '2026-08-28T00:00:00Z', removedAt: null, stableVersion: '1.0.0', betaVersion: null,
|
||||
},
|
||||
],
|
||||
total: 3,
|
||||
stale: false,
|
||||
fetchedAt: 1,
|
||||
};
|
||||
const projection = () => ({
|
||||
library,
|
||||
installations: [
|
||||
...(installedChannel ? [{
|
||||
status: 'installed', pluginId: 'makelore.notes', releaseId: installedChannel === 'beta' ? 'beta-2' : 'stable-1',
|
||||
version: installedChannel === 'beta' ? '2.0.0-beta.1' : installedVersion, channel: installedChannel,
|
||||
}] : []),
|
||||
{ status: 'unavailable', pluginId: 'makelore.unavailable', reason: 'plugin_backend_unavailable' },
|
||||
],
|
||||
});
|
||||
const result = (json: unknown) => ({ ok: true, data: { status: 200, ok: true, json } });
|
||||
(globalThis as typeof globalThis & { __marketplaceE2E?: { requests: string[] } }).__marketplaceE2E = { requests };
|
||||
ipcMain.removeHandler('hostapi:fetch');
|
||||
ipcMain.handle('hostapi:fetch', async (_event, request: { path?: string; method?: string }) => {
|
||||
const requestPath = request.path ?? '';
|
||||
const method = (request.method ?? 'GET').toUpperCase();
|
||||
requests.push(`${method} ${requestPath}`);
|
||||
if (requestPath === '/api/auth/session/sync') {
|
||||
const response = result({
|
||||
success: true,
|
||||
session: {
|
||||
accessToken: 'marketplace-e2e-token', tokenType: 'Bearer',
|
||||
expiresAt: Date.now() + 3_600_000, lastActiveAt: Date.now(), canRefresh: false,
|
||||
},
|
||||
});
|
||||
return response;
|
||||
}
|
||||
if (requestPath === '/api/auth/me') return result({ success: true, moduleAccess: { programming: true } });
|
||||
if (requestPath === '/api/coding/plugin-marketplace/library') return result(projection());
|
||||
if (requestPath === '/api/coding/plugin-marketplace/install/makelore.notes/beta' && method === 'POST') {
|
||||
installedChannel = 'beta';
|
||||
return result({ status: 'installed', pluginId: 'makelore.notes', releaseId: 'beta-2', version: '2.0.0-beta.1', channel: 'beta' });
|
||||
}
|
||||
if (requestPath === '/api/coding/plugin-marketplace/install/makelore.notes' && method === 'DELETE') {
|
||||
installedChannel = null;
|
||||
return result({ status: 'removed', pluginId: 'makelore.notes', releaseId: 'beta-2', version: '2.0.0-beta.1', channel: 'beta' });
|
||||
}
|
||||
return { ok: false, error: { message: `Unexpected Host API request: ${method} ${requestPath}` } };
|
||||
});
|
||||
});
|
||||
await page.addInitScript(({ key, value }) => {
|
||||
localStorage.setItem(key, value);
|
||||
}, {
|
||||
key: 'niancode-auth',
|
||||
value: JSON.stringify({
|
||||
state: {
|
||||
authBase: 'https://biz.nianxx.cn/auth/', clientId: 'app', accessToken: 'marketplace-e2e-token',
|
||||
tokenType: 'Bearer', expiresAt: Date.now() + 3_600_000, lastActiveAt: Date.now(), canRefresh: false,
|
||||
legacyRefreshToken: null,
|
||||
user: { username: 'marketplace-e2e', userId: 'marketplace-e2e-user', tenantId: null, deptId: null, authorities: [] },
|
||||
moduleAccess: { programming: true, design: true, learning: true, robot: true },
|
||||
},
|
||||
version: 2,
|
||||
}),
|
||||
});
|
||||
await page.reload({ waitUntil: 'domcontentloaded' });
|
||||
await expect(page.getByTestId('ai-module-option-programming')).toBeVisible();
|
||||
const programmingOption = page.getByTestId('ai-module-option-programming');
|
||||
await programmingOption.click();
|
||||
await expect(page.getByTestId('main-layout')).toBeVisible();
|
||||
await page.keyboard.press('Escape');
|
||||
await page.getByTestId('sidebar-nav-my-plugins').click();
|
||||
await expect(page.getByTestId('my-plugins-page')).toBeVisible();
|
||||
await expect.poll(async () => app.evaluate(() => (
|
||||
((globalThis as typeof globalThis & { __marketplaceE2E?: { requests: string[] } }).__marketplaceE2E?.requests ?? [])
|
||||
.filter((requestPath) => requestPath.includes('/api/auth') || requestPath.includes('/plugin-marketplace'))
|
||||
))).toEqual(expect.arrayContaining([
|
||||
'GET /api/auth/me',
|
||||
'GET /api/coding/plugin-marketplace/library',
|
||||
]));
|
||||
await expect(page.getByRole('heading', { name: '暂停插件' })).toBeVisible();
|
||||
await expect(page.getByText('运行已暂停')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: '下载暂停插件' })).toBeDisabled();
|
||||
await expect(page.getByText('Marketplace 服务暂不可用,设备版本未替换。')).toBeVisible();
|
||||
|
||||
await page.getByRole('button', { name: '安装 Beta灵感笔记' }).click();
|
||||
await expect(page.getByText('当前频道:Beta')).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: '安装 Beta灵感笔记' })).toHaveCount(0);
|
||||
await page.getByRole('button', { name: '删除设备上的灵感笔记' }).click();
|
||||
const notesCard = page.locator('article').filter({ has: page.getByRole('heading', { name: '灵感笔记' }) });
|
||||
await expect(notesCard.getByText('尚未下载到设备')).toBeVisible();
|
||||
await expect(notesCard.getByRole('button', { name: '下载灵感笔记' })).toBeVisible();
|
||||
const requests = await app.evaluate(() => (
|
||||
(globalThis as typeof globalThis & { __marketplaceE2E?: { requests: string[] } }).__marketplaceE2E?.requests ?? []
|
||||
));
|
||||
expect(requests).toContain('POST /api/coding/plugin-marketplace/install/makelore.notes/beta');
|
||||
expect(requests).toContain('DELETE /api/coding/plugin-marketplace/install/makelore.notes');
|
||||
} finally {
|
||||
await closeElectronApp(app);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user