Files
maka/apps/desktop/e2e/composer-skill-invocation.spec.ts
agent-radar 7be535059e
Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 19:05:14 +08:00

75 lines
3.4 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import { expect, test, COMPOSER_INPUT } from './fixtures';
test('staged Skills come back as chips after leaving and returning', async ({
invocableSkillsWindow: page,
}) => {
const composer = page.locator(COMPOSER_INPUT);
const projectChip = page.locator('[data-astryx-token-value="/skill:project-only"]');
const workspaceChip = page.locator('[data-astryx-token-value="/skill:workspace-only"]');
const pick = async (query: string, name: RegExp) => {
await composer.click();
await composer.pressSequentially(` /${query}`);
const option = page.getByRole('listbox', { name: /技能/ }).getByRole('option', { name });
await expect(option).toBeVisible();
// This journey owns draft restoration, while keyboard selection is covered
// separately. Select the exact option without coupling setup to the
// popover's transient highlighted-item state under concurrent workers.
await option.click();
};
await composer.fill('alpha-marker');
await composer.press('Enter');
await expect(page.getByText(/Fake backend received: alpha-marker/)).toBeVisible();
await pick('project', /Project Only/);
await composer.pressSequentially('run it');
await pick('workspace', /Workspace Only/);
await expect(projectChip).toContainText('Project Only');
// Both chips must land before navigating away: leaving while the second
// token is still committing races the draft snapshot and loses the chip.
await expect(workspaceChip).toContainText('Workspace Only');
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '任务列表' });
await sidebar.getByRole('button', { name: '新任务', exact: true }).click();
await expect(composer).toHaveText('');
await sidebar.locator('[data-session-id]').first().click();
await expect(composer).toContainText('run it');
await expect(projectChip).toContainText('Project Only');
await expect(workspaceChip).toContainText('Workspace Only');
// The token text itself is gone: a chip drawn beside the text it renders
// would mean the draft now carried the Skill twice.
await expect(composer).not.toContainText('/skill:');
await composer.click();
await composer.press('Enter');
await expect(
page.getByLabel('你发送的消息').last().locator('.astryx-badge'),
).toHaveText(['Project Only', 'Workspace Only']);
});
// The starter-skill window, three phases in dependency order: the blocked
// invocation pins zero turns and zero sessions so it must run before any
// send; the chip-only send then re-enables the Skill and owns the first
// message; the + entry phases send nothing and run last.