qwen-code/packages/web-shell/client/e2e/web-shell.channels.spec.ts
qqqys 7836c919bf
fix(web-shell): polish Channel pairing requests (#7997)
* fix(web-shell): polish Channel pairing requests

* fix(web-shell): localize pairing transport failures

---------

Co-authored-by: qwen-code-dev-bot <269191875+qwen-code-dev-bot@users.noreply.github.com>
2026-07-29 06:36:10 +00:00

176 lines
4.9 KiB
TypeScript

/**
* @license
* Copyright 2026 Qwen Team
* SPDX-License-Identifier: Apache-2.0
*/
import { expect, test } from '@playwright/test';
import {
createWebShellDaemonScenario,
installMockDaemon,
replayCompleteEvent,
} from './utils/mockDaemon';
test('creates and deletes a typed Channel configuration', async ({
page,
}, testInfo) => {
const scenario = createWebShellDaemonScenario({
capabilities: {
features: [
'session_events',
'permission_vote',
'session_permission_vote',
'session_scope_override',
'session_source_metadata',
'workspace_settings',
'workspace_voice',
'channel_management',
],
},
channelTypes: [
{
type: 'dingtalk',
displayName: 'DingTalk',
manageable: true,
fields: [
{
key: 'clientId',
label: 'Client ID',
kind: 'string',
required: true,
envResolvable: true,
},
{
key: 'clientSecret',
label: 'Client Secret',
kind: 'secret',
required: true,
envResolvable: true,
},
],
},
{
type: 'wecom',
displayName: 'WeCom',
manageable: true,
fields: [],
},
{
type: 'feishu',
displayName: 'Feishu',
manageable: true,
fields: [],
},
],
pairingRequests: {
'release-bot': [
{
senderId: 'user-42',
senderName: 'Ada',
code: 'ABCD1234',
createdAt: Date.parse('2026-07-28T00:00:00.000Z'),
},
],
},
});
await page.addInitScript(() => {
window.sessionStorage.setItem('qwen-daemon-token', 'e2e-token');
});
const daemon = await installMockDaemon(page, scenario, {
baseURL: String(testInfo.project.use.baseURL),
});
await page.goto(`/session/${encodeURIComponent(scenario.sessionId)}`);
await expect(page.locator('[data-web-shell-root]')).toBeVisible();
const connection = await daemon.sse.waitForConnection(scenario.sessionId);
await daemon.sendEvent(
replayCompleteEvent({ sessionId: connection.sessionId }),
);
await expect(page.getByText('Loading...')).toHaveCount(0);
await page.getByRole('button', { name: 'Channels' }).click();
await page.getByRole('button', { name: 'Configure DingTalk' }).click();
await expect(
page.getByRole('heading', { name: 'Configure DingTalk' }),
).toBeVisible();
await page.getByLabel('Instance name').fill('release-bot');
await page.getByLabel('Client ID (AppKey)').fill('ding-client-id');
await page.getByLabel('Client Secret (AppSecret)').fill('ding-client-secret');
await page.getByRole('button', { name: 'Save' }).click();
await expect(
page.getByRole('heading', { name: 'Configure DingTalk' }),
).toHaveCount(0);
await expect(page.getByText('release-bot', { exact: true })).toBeVisible();
await expect
.poll(() =>
daemon.requests.filter(
(request) =>
request.method === 'PUT' &&
request.path.endsWith('/channels/release-bot'),
),
)
.toEqual([
expect.objectContaining({
body: {
expectedRevision: '1',
config: {
type: 'dingtalk',
clientId: 'ding-client-id',
senderPolicy: 'pairing',
},
secrets: {
clientSecret: {
operation: 'replace',
value: 'ding-client-secret',
},
},
},
}),
]);
await page.getByRole('button', { name: 'Edit release-bot' }).click();
await expect(
page.getByRole('heading', { name: 'Edit DingTalk' }),
).toBeVisible();
await expect(page.getByText('Ada', { exact: true })).toBeVisible();
await expect(page.getByText('ABCD1234', { exact: true })).toBeVisible();
await page
.getByRole('button', { name: 'Approve Ada, code ABCD1234' })
.click();
await expect(page.getByText('No pending requests')).toBeVisible();
await expect
.poll(() =>
daemon.requests.filter(
(request) =>
request.method === 'POST' &&
request.path.endsWith(
'/channels/release-bot/pairing-requests/approve',
),
),
)
.toEqual([
expect.objectContaining({
body: { code: 'ABCD1234' },
}),
]);
await page.getByRole('button', { name: 'Close' }).click();
await page.getByRole('button', { name: 'Delete release-bot' }).click();
const confirmation = page.getByRole('alertdialog');
await confirmation.getByRole('button', { name: 'Delete' }).click();
await expect(page.getByText('release-bot', { exact: true })).toHaveCount(0);
await expect
.poll(() =>
daemon.requests.filter(
(request) =>
request.method === 'DELETE' &&
request.path.endsWith('/channels/release-bot'),
),
)
.toEqual([
expect.objectContaining({
body: { expectedRevision: '2' },
}),
]);
});