Dependency audit / audit (push) Canceled after 0s
CI / plan (push) Canceled after 0s
Gitoxide helper admission / macos-latest (push) Canceled after 0s
Gitoxide helper admission / ubuntu-latest (push) Canceled after 0s
Gitoxide helper admission / windows-latest (push) Canceled after 0s
Runtime Host peer admission / quality (push) Canceled after 0s
Windows recovery / windows_recovery (push) Canceled after 0s
CI / heavy (push) Canceled after 0s
CI / test (push) Canceled after 0s
126 lines
4.7 KiB
TypeScript
126 lines
4.7 KiB
TypeScript
/*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
import { expect, test, COMPOSER_INPUT } from './fixtures';
|
|
|
|
test('a one-line Markdown code block exposes native and selection horizontal scrolling', async ({
|
|
window: page,
|
|
}) => {
|
|
await page.setViewportSize({ width: 900, height: 700 });
|
|
const longLine = Array.from(
|
|
{ length: 80 },
|
|
(_, index) => `word-${String(index).padStart(3, '0')}`,
|
|
).join(' ');
|
|
const composer = page.locator(COMPOSER_INPUT);
|
|
await composer.fill([
|
|
'show these keys',
|
|
'',
|
|
'```',
|
|
'short-key',
|
|
'```',
|
|
'',
|
|
'```',
|
|
longLine,
|
|
'```',
|
|
].join('\n'));
|
|
await composer.press('Enter');
|
|
|
|
const codeBlocks = page.locator('.maka-markdown-code[data-maka-code-layout="single-line"]');
|
|
const viewport = codeBlocks.last().locator('[role="group"]');
|
|
await expect(viewport).toBeVisible();
|
|
await expect(page.getByRole('button', { name: '重新生成' })).toHaveCount(1, {
|
|
timeout: 20_000,
|
|
});
|
|
|
|
const metrics = await viewport.evaluate((element) => {
|
|
const node = element as HTMLElement;
|
|
const rect = node.getBoundingClientRect();
|
|
const code = node.querySelector('code');
|
|
const line = code?.querySelector(':scope > [data-line]');
|
|
if (!code || !line) throw new Error('code viewport has no line content');
|
|
const codeRect = code.getBoundingClientRect();
|
|
const lineRect = line.getBoundingClientRect();
|
|
return {
|
|
rect: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
clientWidth: node.clientWidth,
|
|
scrollWidth: node.scrollWidth,
|
|
lineTopInset: lineRect.top - codeRect.top,
|
|
lineBottomInset: codeRect.bottom - lineRect.bottom,
|
|
};
|
|
});
|
|
expect(metrics.scrollWidth).toBeGreaterThan(metrics.clientWidth);
|
|
expect(Math.abs(metrics.lineTopInset - metrics.lineBottomInset)).toBeLessThanOrEqual(1);
|
|
|
|
const overflowX = await viewport.evaluate((element) => getComputedStyle(element).overflowX);
|
|
expect(overflowX).toBe('auto');
|
|
|
|
const viewportBox = await viewport.boundingBox();
|
|
if (!viewportBox) throw new Error('native scroll viewport has no visible bounds');
|
|
await page.mouse.move(
|
|
viewportBox.x + viewportBox.width / 2,
|
|
viewportBox.y + viewportBox.height / 2,
|
|
);
|
|
await page.mouse.wheel(240, 0);
|
|
await expect.poll(
|
|
() => viewport.evaluate((element) => (element as HTMLElement).scrollLeft),
|
|
).toBeGreaterThan(0);
|
|
const afterWheelScroll = await viewport.evaluate(
|
|
(element) => (element as HTMLElement).scrollLeft,
|
|
);
|
|
|
|
await viewport.evaluate((element) => {
|
|
(element as HTMLElement).scrollLeft = 0;
|
|
});
|
|
await viewport.focus();
|
|
await viewport.press('ArrowRight');
|
|
await expect.poll(
|
|
() => viewport.evaluate((element) => (element as HTMLElement).scrollLeft),
|
|
).toBeGreaterThan(0);
|
|
const afterKeyboardScroll = await viewport.evaluate(
|
|
(element) => (element as HTMLElement).scrollLeft,
|
|
);
|
|
|
|
await viewport.evaluate((element) => {
|
|
(element as HTMLElement).scrollLeft = 0;
|
|
window.getSelection()?.removeAllRanges();
|
|
});
|
|
const code = viewport.locator('code');
|
|
const codeBox = await code.boundingBox();
|
|
if (!codeBox) throw new Error('code line has no visible bounds');
|
|
const textY = codeBox.y + Math.min(codeBox.height / 2, 18);
|
|
await page.mouse.move(codeBox.x + 24, textY);
|
|
await page.mouse.down();
|
|
await page.mouse.move(metrics.rect.x + metrics.rect.width + 50, textY, { steps: 20 });
|
|
await expect.poll(
|
|
() => viewport.evaluate((element) => (element as HTMLElement).scrollLeft),
|
|
).toBeGreaterThan(0);
|
|
await expect.poll(
|
|
() => viewport.evaluate(() => window.getSelection()?.toString().length ?? 0),
|
|
).toBeGreaterThan(10);
|
|
const afterSelectionDrag = await viewport.evaluate((element) => ({
|
|
scrollLeft: (element as HTMLElement).scrollLeft,
|
|
selection: window.getSelection()?.toString() ?? '',
|
|
}));
|
|
await page.mouse.up();
|
|
expect(afterWheelScroll).toBeGreaterThan(0);
|
|
expect(afterKeyboardScroll).toBeGreaterThan(0);
|
|
expect(afterSelectionDrag.scrollLeft).toBeGreaterThan(0);
|
|
expect(afterSelectionDrag.selection.length).toBeGreaterThan(10);
|
|
});
|