feat: update desktop workflows and app center
This commit is contained in:
@@ -1,5 +1,3 @@
|
||||
import { join, resolve } from 'node:path';
|
||||
import { pathToFileURL } from 'node:url';
|
||||
import {
|
||||
closeElectronApp,
|
||||
expect,
|
||||
@@ -8,9 +6,6 @@ import {
|
||||
test,
|
||||
} from './fixtures/electron';
|
||||
|
||||
const repoRoot = resolve(process.cwd());
|
||||
const rendererEntry = pathToFileURL(join(repoRoot, 'dist/index.html')).toString();
|
||||
|
||||
function hostJson(json: unknown) {
|
||||
return {
|
||||
ok: true,
|
||||
@@ -26,8 +21,17 @@ function hostKey(path: string, method = 'GET') {
|
||||
return JSON.stringify([path, method]);
|
||||
}
|
||||
|
||||
function stableStringify(value: unknown): string {
|
||||
if (value == null || typeof value !== 'object') return JSON.stringify(value);
|
||||
if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(',')}]`;
|
||||
const entries = Object.entries(value as Record<string, unknown>)
|
||||
.sort(([left], [right]) => left.localeCompare(right))
|
||||
.map(([key, entryValue]) => `${JSON.stringify(key)}:${stableStringify(entryValue)}`);
|
||||
return `{${entries.join(',')}}`;
|
||||
}
|
||||
|
||||
test.describe('Zhinian delivery smoke', () => {
|
||||
test('covers setup, login, chat, quick tasks, history, workspace pages, and NianxxPlay shell', async ({ launchElectronApp }) => {
|
||||
test('covers setup, login, chat quick capabilities, history, workspace pages, Travel Resource Ordering, and Quick Video Creation shell', async ({ launchElectronApp }) => {
|
||||
const app = await launchElectronApp();
|
||||
|
||||
await installIpcMocks(app, {
|
||||
@@ -36,7 +40,28 @@ test.describe('Zhinian delivery smoke', () => {
|
||||
port: 18789,
|
||||
pid: 12345,
|
||||
},
|
||||
gatewayRpc: {
|
||||
[stableStringify(['sessions.list', {}])]: {
|
||||
success: true,
|
||||
result: {
|
||||
sessions: [{ key: 'agent:main:main', displayName: '桌面对话', updatedAt: Date.now() }],
|
||||
},
|
||||
},
|
||||
[stableStringify(['chat.history', { sessionKey: 'agent:main:main', limit: 200 }])]: {
|
||||
success: true,
|
||||
result: { messages: [] },
|
||||
},
|
||||
[stableStringify(['chat.history', { sessionKey: 'agent:main:main', limit: 1000 }])]: {
|
||||
success: true,
|
||||
result: { messages: [] },
|
||||
},
|
||||
},
|
||||
hostApi: {
|
||||
[hostKey('/api/gateway/status')]: hostJson({
|
||||
state: 'running',
|
||||
port: 18789,
|
||||
pid: 12345,
|
||||
}),
|
||||
[hostKey('/api/apps/nianxx-play/status')]: hostJson({
|
||||
success: true,
|
||||
running: true,
|
||||
@@ -54,18 +79,27 @@ test.describe('Zhinian delivery smoke', () => {
|
||||
port: 3000,
|
||||
}),
|
||||
[hostKey('/api/channels/accounts')]: hostJson({ success: true, channels: [] }),
|
||||
[hostKey('/api/cron/jobs')]: hostJson({ jobs: [] }),
|
||||
[hostKey('/api/cron/jobs')]: hostJson({
|
||||
jobs: [{
|
||||
id: 'cron-daily',
|
||||
name: '每日经营日报',
|
||||
message: '使用日报生成助手 skill 生成日报',
|
||||
schedule: '0 9 * * *',
|
||||
delivery: { mode: 'none' },
|
||||
enabled: true,
|
||||
createdAt: '2026-05-13T00:00:00.000Z',
|
||||
updatedAt: '2026-05-13T00:00:00.000Z',
|
||||
agentId: 'main',
|
||||
}],
|
||||
}),
|
||||
[hostKey('/api/cron/trigger', 'POST')]: hostJson({ success: true }),
|
||||
},
|
||||
});
|
||||
|
||||
try {
|
||||
const page = await getStableWindow(app);
|
||||
await page.setViewportSize({ width: 1280, height: 800 });
|
||||
|
||||
await expect(page.getByTestId('setup-page')).toBeVisible();
|
||||
await page.getByTestId('setup-skip-button').click();
|
||||
await expect(page.getByTestId('yinian-login-page')).toBeVisible();
|
||||
await page.evaluate(() => {
|
||||
await page.addInitScript(() => {
|
||||
window.localStorage.setItem('yinian:quick-tasks', JSON.stringify({
|
||||
state: {
|
||||
tasks: [
|
||||
@@ -91,9 +125,14 @@ test.describe('Zhinian delivery smoke', () => {
|
||||
},
|
||||
version: 3,
|
||||
}));
|
||||
window.localStorage.setItem('yinian:pinned-task-ids', JSON.stringify(['cron-daily']));
|
||||
});
|
||||
await page.reload();
|
||||
|
||||
await expect(page.getByTestId('setup-page')).toBeVisible();
|
||||
await page.getByTestId('setup-skip-button').click();
|
||||
await expect(page.getByTestId('yinian-login-page')).toBeVisible();
|
||||
|
||||
await page.goto(`${rendererEntry}#/login`);
|
||||
await expect(page.getByTestId('yinian-login-page')).toBeVisible();
|
||||
await page.locator('#account').fill('admin');
|
||||
await page.locator('#password').fill('123456');
|
||||
@@ -102,9 +141,6 @@ test.describe('Zhinian delivery smoke', () => {
|
||||
await captchaInput.fill('5678');
|
||||
}
|
||||
await page.locator('form button[type="submit"]').click();
|
||||
await expect(page.getByTestId('today-page')).toBeVisible();
|
||||
|
||||
await page.getByTestId('sidebar-new-chat').click();
|
||||
await expect(page.getByTestId('chat-composer-input')).toBeVisible();
|
||||
await expect(page.getByTestId('chat-quick-task-qt-docx')).toBeVisible();
|
||||
await expect(page.getByTestId('chat-quick-task-qt-docx')).toBeEnabled({ timeout: 60_000 });
|
||||
@@ -116,20 +152,39 @@ test.describe('Zhinian delivery smoke', () => {
|
||||
|
||||
await page.getByTestId('sidebar-chat-history').click();
|
||||
await expect(page.getByTestId('sidebar-chat-history-panel')).toBeVisible();
|
||||
await expect(page.getByTestId('sidebar-pinned-task-cron-daily')).toBeVisible();
|
||||
await page.getByTestId('sidebar-pinned-task-cron-daily').click();
|
||||
|
||||
await page.goto(`${rendererEntry}#/knowledge`);
|
||||
await page.getByTestId('sidebar-nav-knowledge').click();
|
||||
await expect(page.getByTestId('knowledge-page')).toBeVisible();
|
||||
|
||||
await page.goto(`${rendererEntry}#/cron`);
|
||||
await expect(page.getByTestId('cron-page')).toBeVisible();
|
||||
await page.getByTestId('sidebar-nav-tasks').click();
|
||||
await expect(page.getByTestId('tasks-page')).toBeVisible();
|
||||
await expect(page.getByTestId('tasks-tab-scheduled')).toBeVisible();
|
||||
await expect(page.getByTestId('tasks-tab-quick')).toHaveCount(0);
|
||||
await page.evaluate(() => {
|
||||
window.location.hash = '#/cron';
|
||||
});
|
||||
await expect(page.getByTestId('tasks-page')).toBeVisible();
|
||||
await expect(page.getByTestId('tasks-tab-scheduled')).toBeVisible();
|
||||
|
||||
await page.goto(`${rendererEntry}#/settings/skills`);
|
||||
await page.evaluate(() => {
|
||||
window.location.hash = '#/settings/skills';
|
||||
});
|
||||
await expect(page.getByTestId('settings-page')).toBeVisible();
|
||||
await expect(page.getByTestId('yinian-skills-page')).toBeVisible();
|
||||
await expect(page.getByTestId('yinian-skills-tab-quickTasks')).toBeVisible();
|
||||
await expect(page.getByTestId('yinian-skills-tab-server')).toBeVisible();
|
||||
await expect(page.getByTestId('yinian-skills-tab-local')).toBeVisible();
|
||||
|
||||
await page.getByTestId('sidebar-nav-app-center').click();
|
||||
await expect(page.getByTestId('app-center-page')).toBeVisible();
|
||||
await expect(page.getByTestId('app-center-item-product-center')).toBeVisible();
|
||||
await page.getByTestId('app-center-item-product-center').click();
|
||||
await expect(page.getByTestId('product-center-page')).toBeVisible();
|
||||
await expect(page.getByTestId('product-center-frame')).toHaveAttribute('src', /https:\/\/ticket\.nianxx\.cn\/.*zhinianEmbed=1/);
|
||||
await expect(page.getByTestId('product-center-frame')).toHaveAttribute('partition', 'persist:yinian-travel-resource-ordering');
|
||||
await page.getByTestId('product-center-back').click();
|
||||
await expect(page.getByTestId('app-center-page')).toBeVisible();
|
||||
await expect(page.getByTestId('app-center-item-nianxx-play')).toBeVisible();
|
||||
await page.getByTestId('app-center-item-nianxx-play').click();
|
||||
await expect(page.getByTestId('nianxx-play-page')).toBeVisible();
|
||||
|
||||
@@ -66,10 +66,11 @@ test('captures the core Zhinian production UI surfaces', async () => {
|
||||
const page = await getStableWindow(app);
|
||||
await page.setViewportSize({ width: 1440, height: 900 });
|
||||
|
||||
// The main process stays in E2E mode to avoid startup side effects, while
|
||||
// the renderer is reloaded without the e2e query so the production YINIAN
|
||||
// login and tenant flow are exercised.
|
||||
await page.goto(rendererEntry);
|
||||
// Keep the renderer in E2E mode so the first-run setup can be skipped
|
||||
// deterministically before capturing the authenticated product shell.
|
||||
await page.goto(`${rendererEntry}?e2e=1`);
|
||||
await expect(page.getByTestId('setup-page')).toBeVisible();
|
||||
await page.getByTestId('setup-skip-button').click();
|
||||
await expect(page.getByTestId('yinian-login-page')).toBeVisible();
|
||||
await page.screenshot({ path: join(screenshotDir, '01-login.png'), fullPage: true });
|
||||
|
||||
@@ -80,12 +81,12 @@ test('captures the core Zhinian production UI surfaces', async () => {
|
||||
await captchaInput.fill('5678');
|
||||
}
|
||||
await page.getByRole('button', { name: /^登录$/ }).click();
|
||||
await expect(page.getByTestId('today-page')).toBeVisible();
|
||||
await page.getByTestId('sidebar-chat-history').hover();
|
||||
await expect(page.getByTestId('sidebar-chat-history-popover')).toBeVisible();
|
||||
await page.screenshot({ path: join(screenshotDir, '02-today.png'), fullPage: true });
|
||||
await expect(page.getByTestId('chat-composer-input')).toBeVisible();
|
||||
await page.screenshot({ path: join(screenshotDir, '02-chat.png'), fullPage: true });
|
||||
|
||||
await page.getByTestId('sidebar-nav-skills').click();
|
||||
await page.evaluate(() => {
|
||||
window.location.hash = '#/settings/skills';
|
||||
});
|
||||
await expect(page.getByTestId('yinian-skills-page')).toBeVisible();
|
||||
await page.screenshot({ path: join(screenshotDir, '03-skills.png'), fullPage: true });
|
||||
|
||||
|
||||
Reference in New Issue
Block a user