Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
03f6cf9
test(ui): delete presentation-only suites
Astro-Han Aug 8, 2026
aa21314
test(desktop): remove obsolete presentation coverage
Astro-Han Aug 8, 2026
b4be0fb
test(core): drop low-value helper contracts
Astro-Han Aug 8, 2026
696a166
test(cli): remove presentation helper coverage
Astro-Han Aug 8, 2026
cfdbfcc
test(headless): trim legacy matrix coverage
Astro-Han Aug 8, 2026
5a1f2e6
test(desktop): remove presentation-only coverage
Astro-Han Aug 8, 2026
de12917
test(core): drop redundant smoke coverage
Astro-Han Aug 8, 2026
ecb42e7
test(headless): remove obsolete prompt fixtures
Astro-Han Aug 8, 2026
e953d5c
test(ui): trim presentation-only assertions
Astro-Han Aug 8, 2026
ce43d44
test(cli): trim display-only contracts
Astro-Han Aug 8, 2026
531a17a
test(computer-use): remove duplicate positive paths
Astro-Han Aug 8, 2026
fab15f9
test(runtime): drop renderer alias pin
Astro-Han Aug 8, 2026
604554c
test(runtime-host): drop provider matrix mirror
Astro-Han Aug 8, 2026
a825a12
test(desktop): trim redundant fixture coverage
Astro-Han Aug 8, 2026
eafdb86
test(core): trim duplicate graph parser cases
Astro-Han Aug 8, 2026
b527d52
test(headless): remove report presentation pins
Astro-Han Aug 8, 2026
449244c
test(ui): remove low-value rendering helpers
Astro-Han Aug 8, 2026
ec9d925
test(cli): remove remaining display pins
Astro-Han Aug 8, 2026
4068b6e
test(computer-use): trim duplicate prose coverage
Astro-Han Aug 8, 2026
8ff9e2c
test(runtime): trim benchmark and provider mirrors
Astro-Han Aug 8, 2026
46ebeef
test(runtime-host): trim registry mirrors
Astro-Han Aug 8, 2026
e334383
test: drop redundant Astryx theme unit pin
Astro-Han Aug 8, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 0 additions & 25 deletions apps/desktop/e2e/attachment.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,37 +105,12 @@ test('a mixed attachment send has the Astryx message hierarchy', async ({ window

const sentMessage = page.getByLabel('你发送的消息').last();
const fileToken = sentMessage.locator('.maka-user-attachment-tokens .astryx-token');
const fileIcon = fileToken.locator('.astryx-icon');
const image = sentMessage.locator('.maka-user-attachments .astryx-thumbnail');
const bubble = sentMessage.locator('.maka-chat-message-bubble-user');
await expect(fileToken).toContainText('note.txt');
await expect(fileIcon).toHaveCSS('width', '16px');
await expect(fileIcon).toHaveCSS('height', '16px');
await expect(image).toBeVisible();
await expect(image).toHaveCSS('width', '64px');
await expect(bubble).toContainText('sending mixed attachments');

const [fileBox, imageBox, bubbleBox] = await Promise.all([
fileToken.boundingBox(),
image.boundingBox(),
bubble.boundingBox(),
]);
expect(fileBox).not.toBeNull();
expect(imageBox).not.toBeNull();
expect(bubbleBox).not.toBeNull();
// The token declares display:inline-flex + align-items:center; as a flex
// item of the attachment row it computes display:flex (blockification) on
// every platform. Assert the centering contract, not geometry: token height
// resolves from line-height, which varies with font metrics (Linux CI can
// drop below the 16px icon, overflowing a correctly centered icon by 2px).
// A tolerance-based centerline check was rejected — a baseline regression
// drifts exactly 2.00px, the tolerance boundary. display:flex is load-
// bearing: align-items computes as declared even on non-flex boxes.
await expect(fileToken).toHaveCSS('display', 'flex');
await expect(fileToken).toHaveCSS('align-items', 'center');
expect(fileBox!.y + fileBox!.height).toBeLessThanOrEqual(bubbleBox!.y);
expect(imageBox!.y + imageBox!.height).toBeLessThanOrEqual(bubbleBox!.y);

await image.getByRole('button').click();
const lightbox = page.locator('.astryx-lightbox');
await expect(lightbox).toBeVisible();
Expand Down
6 changes: 0 additions & 6 deletions apps/desktop/e2e/composer-mention-token.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -26,12 +26,6 @@ test('a picked file mention becomes an inline token and sends as its path', asyn
'data-astryx-token-value',
'@.maka/skills/agent-write/SKILL.md',
);
const [tokenWidth, lineWidth] = await Promise.all([
token.evaluate((element) => element.getBoundingClientRect().width),
composer.evaluate((element) => element.getBoundingClientRect().width),
]);
expect(tokenWidth).toBeLessThan(lineWidth / 2);

await composer.press('Enter');
const bubble = page.getByLabel('你发送的消息').first();
await expect(bubble).toBeVisible();
Expand Down
56 changes: 0 additions & 56 deletions apps/desktop/e2e/default-thinking-level.spec.ts

This file was deleted.

18 changes: 0 additions & 18 deletions apps/desktop/e2e/keyboard-help.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -22,24 +22,6 @@ test('the help modal opens from its entry points and keeps its styled layout', a
await page.keyboard.press(MOD_SLASH);
await expect(body).toBeVisible();

// Description/keys resolve into a two-column grid…
const rows = page.locator('.maka-help-section dl').first();
await expect(rows).toHaveCSS('display', 'grid');
const columns = await rows.evaluate((el) => getComputedStyle(el).gridTemplateColumns.split(' ').length);
expect(columns).toBe(2);
// …headings carry the caption typography, not default heading bulk…
const heading = page.locator('.maka-help-section h3').first();
await expect(heading).toHaveCSS('font-size', '12px');
await expect(heading).toHaveCSS('font-weight', '600');
// …multi-key combos keep their distinct separator…
const plus = page.locator('.maka-help-plus').first();
await expect(plus).toBeVisible();
await expect(plus).toHaveText('+');
// …and Kbd chips carry real keycap chrome.
const keycap = page.locator('.maka-help-section .astryx-kbd kbd').first();
await expect(keycap).not.toHaveCSS('background-color', 'rgba(0, 0, 0, 0)');
await expect(keycap).not.toHaveCSS('border-radius', '0px');

// The platform's own modifier is what the sheet documents — ⌘ on macOS,
// Ctrl elsewhere. (This harness boots with healthy UA-CH; the blank-UA-CH
// environment is pinned by the dedicated test below.)
Expand Down
149 changes: 0 additions & 149 deletions apps/desktop/e2e/mcp.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,155 +6,6 @@ const fixtureServer = path.resolve(
'../../packages/mcp/dist/__fixtures__/stdio-server.js',
);

test('module navigation removes the hidden chat surface from layout and hit testing', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await expect(page.getByRole('main', { name: '扩展' })).toBeVisible();

const hiddenChat = page.locator('.maka-chat-layout[hidden]');
await expect(hiddenChat).toHaveCount(1);
await expect(hiddenChat).toHaveCSS('display', 'none');
expect(await hiddenChat.boundingBox()).toBeNull();
expect(
await page.evaluate(() => {
const target = document.elementFromPoint(window.innerWidth * 0.75, window.innerHeight - 100);
return Boolean(target?.closest('.maka-chat-layout'));
}),
).toBe(false);
});

test('MCP module page keeps one centred column without horizontal overflow', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();
await expect(page.getByRole('toolbar', { name: 'MCP 浏览操作' })).toBeVisible();

for (const width of [1440, 1280, 861, 860, 761]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await page.evaluate(() => {
const main = document.querySelector<HTMLElement>('.maka-module-main');
const content = main?.querySelector<HTMLElement>('.astryx-layout-content');
if (!main || !content) throw new Error('Expected the MCP module layout');
const rows = content.querySelector<HTMLElement>('.maka-module-page-rows')
?? content.querySelector<HTMLElement>('.maka-module-page-panel');
if (!rows) throw new Error('Expected the MCP module content');
const rowsRect = rows.getBoundingClientRect();
const contentRect = content.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
// Centring is measured against the content scroller's inner box, not
// the page: a classic (non-overlay) vertical scrollbar takes width
// out of the scroller, and the column centres in what remains.
centerDelta: Math.abs(
rowsRect.left + rowsRect.width / 2
- (contentRect.left + content.clientWidth / 2),
),
rowsWidth: rowsRect.width,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
// Centred and capped at every width, not just wide ones: below the clamp
// the column fills the plate, which is centring too.
expect(geometry.rowsWidth, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(900);
expect(geometry.centerDelta, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
}
});

test('MCP server descriptions truncate with an ellipsis at 700px and 500px', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const endpoint = `https://example.com/${'narrow-description-segment/'.repeat(12)}mcp`;
await page.evaluate(async (url) => {
await window.maka.mcp.upsert('long-endpoint', {
enabled: false,
url,
transport: 'streamable-http',
});
}, endpoint);
await page.getByRole('button', { name: '刷新', exact: true }).click();
await page.getByRole('radio', { name: '已安装' }).click();

const row = page.getByRole('listitem').filter({ hasText: 'long-endpoint' });
const description = row.locator('[data-maka-contract="mcp-server-description"]');
await expect(description).toBeVisible();
await expect(description.getByTitle(endpoint)).toHaveText(endpoint);

for (const width of [700, 500]) {
await page.setViewportSize({ width, height: 700 });
await expect.poll(() => page.evaluate(() => window.innerWidth)).toBe(width);

const geometry = await description.evaluate((content) => {
const slot = content.parentElement;
const main = content.closest<HTMLElement>('.maka-module-main');
const item = content.closest<HTMLElement>('li');
if (!slot || !main || !item) throw new Error('Expected the MCP server description layout');
const contentStyle = getComputedStyle(content);
const slotRect = slot.getBoundingClientRect();
const itemRect = item.getBoundingClientRect();
return {
mainOverflow: main.scrollWidth - main.clientWidth,
contentOverflow: content.scrollWidth - content.clientWidth,
slotRightOverflow: slotRect.right - itemRect.right,
contentOverflowStyle: contentStyle.overflow,
contentTextOverflow: contentStyle.textOverflow,
contentWhiteSpace: contentStyle.whiteSpace,
};
});

expect(geometry.mainOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBe(0);
expect(geometry.contentOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeGreaterThan(0);
expect(geometry.slotRightOverflow, `${width}px: ${JSON.stringify(geometry)}`).toBeLessThanOrEqual(1);
expect(geometry.contentOverflowStyle).toBe('hidden');
expect(geometry.contentTextOverflow).toBe('ellipsis');
expect(geometry.contentWhiteSpace).toBe('nowrap');
}
});

test('credentialed MCP editor fits a compact desktop viewport without incidental scrolling', async ({ window: page }) => {
await page.setViewportSize({ width: 1164, height: 700 });
await page.getByRole('button', { name: '展开侧边栏' }).click();
await page.getByRole('navigation', { name: '对话列表' }).getByRole('button', { name: '扩展', exact: true }).click();
await page.locator('.maka-module-hub-selector').getByRole('button', { name: 'MCP' }).click();

const slackRow = page.locator('[data-maka-contract="mcp-market-row"]').filter({ hasText: 'Slack' });
await slackRow.getByRole('button', { name: '安装 Slack' }).click();
await slackRow.getByRole('button', { name: '管理' }).click();

const editor = page.getByRole('dialog', { name: '编辑 slack' });
await expect(editor).toBeVisible();
await expect.poll(() => editor.evaluate((element) => (
element.getAnimations().every((animation) => animation.playState === 'finished')
))).toBe(true);
const overflow = await editor.evaluate((dialog) => {
const fields = dialog.querySelector<HTMLElement>('.maka-mcp-form-fields');
if (!fields) throw new Error('Expected MCP editor fields');
return {
dialog: dialog.scrollHeight - dialog.clientHeight,
fields: fields.scrollHeight - fields.clientHeight,
};
});

expect(overflow.dialog, JSON.stringify(overflow)).toBeLessThanOrEqual(1);
expect(overflow.fields, JSON.stringify(overflow)).toBeLessThanOrEqual(1);

const selectedTransportSpacing = await editor.getByRole('radio', { name: '本地 stdio' }).evaluate((radio) => {
const radioWrapper = radio.parentElement;
const icon = radioWrapper?.nextElementSibling;
if (!(radioWrapper instanceof HTMLElement) || !(icon instanceof SVGElement)) {
throw new Error('Expected selected transport radio and icon');
}
return icon.getBoundingClientRect().left - radioWrapper.getBoundingClientRect().right;
});
expect(selectedTransportSpacing).toBeGreaterThanOrEqual(4);
});

test('MCP module completes stdio add, discovery, disable, JSON import, and delete', async ({ window: page }) => {
await page.getByRole('button', { name: '展开侧边栏' }).click();
const sidebar = page.getByRole('navigation', { name: '对话列表' });
Expand Down
10 changes: 0 additions & 10 deletions apps/desktop/e2e/onboarding.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -6,16 +6,6 @@ test('first run connects a provider and starts the first task without workspace
await expect(onboarding.getByRole('heading', { name: '接入一个 AI,开始第一项任务。' })).toBeVisible();
await expect(onboarding.locator('.maka-onboarding-provider-row')).toHaveCount(4);

await page.setViewportSize({ width: 480, height: 900 });
const cardRect = await onboarding.boundingBox();
const layoutRect = await page.locator('[data-chat-scroll-container="true"]').boundingBox();
expect(cardRect).not.toBeNull();
expect(layoutRect).not.toBeNull();
expect(cardRect?.x).toBeGreaterThanOrEqual(layoutRect?.x ?? 0);
expect((cardRect?.x ?? 0) + (cardRect?.width ?? 0)).toBeLessThanOrEqual(
(layoutRect?.x ?? 0) + (layoutRect?.width ?? 0),
);

await onboarding.locator('.maka-onboarding-provider-row[data-provider="opencode-free"]').click();

await expect(page.locator('[data-maka-contract="provider-setup"]')).toBeVisible();
Expand Down
57 changes: 0 additions & 57 deletions apps/desktop/e2e/providers.spec.ts
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,16 +44,12 @@ async function openCatalog(page: Page, options: { category: string; search: stri
const search = catalog.getByPlaceholder('搜索服务商');
const category = catalog.getByRole('combobox', { name: '分类', exact: true });
await expect(search).toBeFocused();
const searchIcon = search.locator('xpath=..').locator('svg').first();
await expect(searchIcon).toHaveCSS('width', '16px');
await expect(searchIcon).toHaveCSS('height', '16px');
// These are independent filters, not one composite toolbar: ordinary Tab
// order must move between them in both directions.
await page.keyboard.press('Tab');
await expect(category).toBeFocused();
await page.keyboard.press('Shift+Tab');
await expect(search).toBeFocused();
await expect(catalog.getByRole('toolbar')).toHaveCount(0);
await category.click();
await page.getByRole('option', { name: options.category, exact: true }).click();
await catalog.getByPlaceholder('搜索服务商').fill(options.search);
Expand All@@ -75,45 +71,6 @@ async function expectNoDialog(page: Page) {
await expect(page.getByRole('dialog')).toHaveCount(0);
}

test('Models collection header matches its collection', async ({ window: page }) => {
await openModelsPage(page);
const panel = page.locator('[data-maka-contract="providers-panel"]');
await expect(panel.locator('ul')).toBeVisible();

const geometry = await panel.evaluate((element) => {
const heading = element.querySelector('h3')?.getBoundingClientRect();
const add = element.querySelector('[data-maka-contract="add-connection"]')?.getBoundingClientRect();
const list = element.querySelector('ul')?.getBoundingClientRect();
if (!heading || !add || !list) return null;
return {
headingLeft: heading.left,
addRight: add.right,
listLeft: list.left,
listRight: list.right,
headerBottom: Math.max(heading.bottom, add.bottom),
listTop: list.top,
};
});

expect(geometry).not.toBeNull();
if (!geometry) return;
expect(Math.abs(geometry.headingLeft - geometry.listLeft)).toBeLessThanOrEqual(0.5);
expect(Math.abs(geometry.addRight - geometry.listRight)).toBeLessThanOrEqual(0.5);
expect(geometry.listTop - geometry.headerBottom).toBeGreaterThanOrEqual(7.5);
expect(geometry.listTop - geometry.headerBottom).toBeLessThanOrEqual(8.5);

await expect(panel.getByRole('heading', { name: '模型连接', exact: true })).toBeVisible();
await expect(panel.getByText('· 1', { exact: true })).toBeVisible();

await page.evaluate(async () => {
await window.maka.connections.delete('e2e');
});
await page.reload();
await page.getByRole('button', { name: '设置' }).click();
await page.locator('[aria-label="设置分组"]').getByText('模型', { exact: true }).click();
await expect(panel.getByText(/^· \d+$/)).toHaveCount(0);
});

// Canonical API-key add journey. Cerebras is the concrete stand-in only because
// it is the strongest exercise of the color-asset render contract (a real
// upstream <img> mark that must stay untouched in BOTH light and dark themes);
Expand DownExpand Up@@ -159,20 +116,6 @@ test('adds a catalog provider through the canonical API-key setup page', async (
await expect(setup.getByLabel('服务地址', { exact: true })).toHaveCount(0);
await expect(setup.getByLabel('默认模型', { exact: true })).toHaveCount(0);

// A 300-character key scrolls inside the field instead of growing it. The
// before/after values are the oracle; the field's width is a design token,
// not this contract.
const inputBox = await keyInput.boundingBox();
await keyInput.fill(`sk-${'a'.repeat(300)}`);
const longKeyLayout = await keyInput.evaluate((input) => ({
clientWidth: input.clientWidth,
scrollWidth: input.scrollWidth,
clientHeight: input.clientHeight,
scrollHeight: input.scrollHeight,
}));
expect(longKeyLayout.scrollWidth).toBeGreaterThan(longKeyLayout.clientWidth);
expect(longKeyLayout.scrollHeight).toBe(longKeyLayout.clientHeight);
expect((await keyInput.boundingBox())?.height).toBe(inputBox?.height);
});

await test.step('saving creates the connection and lands on its detail level', async () => {
Expand Down
Loading
Loading