Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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: 25 additions & 0 deletions doc/agent-smoke-cases.md
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,31 @@ bash scripts/agent-smoke.sh --cdp-port 9222 --cases AGENT-CHROME-001,AGENT-CHROM
3. 刷新完成后按钮恢复为 `刷新`
4. 过程中 `location.href` 保持在列表页,抽屉不关闭

### AGENT-CHROME-013:抽屉滚动不穿透页面

范围:
`#8` 回归用例,2026-03-20 新增

状态:
当前不在默认批量脚本中

建议目标:
优先选一条抽屉内容足够长、可稳定滚动的公开主题

步骤:

1. 打开任一列表话题抽屉
2. 在 `选项` 中切到 `浮层模式`
3. 让外层列表页保持在非顶部位置
4. 把抽屉内容滚到底
5. 将鼠标保持在抽屉内容区内,继续向下滚轮

断言:

1. 外层页面滚动位置保持不变,不应被抽屉内滚动带着继续下移
2. 抽屉保持打开
3. `location.href` 仍然停留在列表页

## 3. 记录格式

执行完用例后,建议按下面格式留证据:
Expand Down
2 changes: 2 additions & 0 deletions doc/testing-standard.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,8 @@ bash scripts/agent-smoke.sh --cdp-port 9222

1. `AGENT-CHROME-006`
浮层模式下,抽屉打开时点击另一个列表主题,应直接切换抽屉内容,不能先关闭再第二次打开
2. `AGENT-CHROME-013`
抽屉内容滚到底后继续滚轮时,外层列表页不应继续跟着滚动

## 4. PR 证据格式

Expand Down
142 changes: 142 additions & 0 deletions scripts/agent-smoke.sh
Original file line number Diff line number Diff line change
Expand Up @@ -737,6 +737,147 @@ run_010() {
fi
}

drawer_body_state() {
local script
script=$(cat <<'EOF'
(() => {
const body = document.querySelector("#ld-drawer-root .ld-drawer-body");
if (!(body instanceof HTMLElement)) {
return { ok: false, reason: "drawer-body-not-found" };
}

const rect = body.getBoundingClientRect();
return {
ok: true,
bodyTop: Math.round(body.scrollTop),
maxScrollTop: Math.round(body.scrollHeight - body.clientHeight),
clientHeight: Math.round(body.clientHeight),
centerX: Math.round(rect.left + rect.width / 2),
centerY: Math.round(rect.top + Math.min(rect.height / 2, 300))
};
})()
EOF
)
ab_eval "$script"
}

page_scroll_state() {
local script
script=$(cat <<'EOF'
(() => ({
docTop: Math.round(document.scrollingElement?.scrollTop || 0),
pageOpen: document.body.classList.contains("ld-drawer-page-open"),
overlay: document.body.classList.contains("ld-drawer-mode-overlay"),
title: document.querySelector("#ld-drawer-root .ld-drawer-title")?.textContent?.trim() || null
}))()
EOF
)
ab_eval "$script"
}

set_page_scroll_top() {
local top=$1
local top_json script
top_json=$(printf '%s' "$top" | jq -Rs 'tonumber')
script=$(cat <<EOF
(() => {
const top = $top_json;
window.scrollTo(0, top);
return {
docTop: Math.round(document.scrollingElement?.scrollTop || 0),
windowY: Math.round(window.scrollY)
};
})()
EOF
)
ab_eval "$script"
}

prepare_scrollable_drawer_topic() {
local index=0
local open_result body_state

while [ "$index" -lt 5 ]; do
open_result=$(open_topic_by_index "$index") || {
index=$((index + 1))
continue
}
ensure_settings_closed
body_state=$(drawer_body_state)

if [ "$(echo "$body_state" | jq -r '.ok')" = "true" ] \
&& [ "$(echo "$body_state" | jq -r '.maxScrollTop')" -ge 1200 ]; then
echo "$open_result"
return 0
fi

index=$((index + 1))
done

return 1
}

run_013() {
local case_id="AGENT-CHROME-013"
local open_result overlay_result scroll_result body_state before after
local center_x center_y before_doc_top after_doc_top

open_result=$(prepare_scrollable_drawer_topic) || {
record_fail "$case_id" "前 5 个列表主题里没有足够长、可滚动的抽屉内容"
return 0
}

overlay_result=$(set_overlay_mode)
if [ "$(echo "$overlay_result" | jq -r '.ok')" != "true" ]; then
record_fail "$case_id" "无法切到浮层模式"
return 0
fi

ensure_settings_closed
scroll_result=$(set_page_scroll_top 900)
body_state=$(ab_eval '(() => {
const body = document.querySelector("#ld-drawer-root .ld-drawer-body");
if (!(body instanceof HTMLElement)) {
return { ok: false, reason: "drawer-body-not-found" };
}

body.scrollTop = body.scrollHeight;
const rect = body.getBoundingClientRect();
return {
ok: true,
bodyTop: Math.round(body.scrollTop),
maxScrollTop: Math.round(body.scrollHeight - body.clientHeight),
centerX: Math.round(rect.left + rect.width / 2),
centerY: Math.round(rect.top + Math.min(rect.height / 2, 300))
};
})()')

if [ "$(echo "$body_state" | jq -r '.ok')" != "true" ]; then
record_fail "$case_id" "无法读取抽屉滚动容器"
return 0
fi

center_x=$(echo "$body_state" | jq -r '.centerX')
center_y=$(echo "$body_state" | jq -r '.centerY')
ab mouse move "$center_x" "$center_y" >/dev/null
before=$(page_scroll_state)
ab mouse wheel 1200 >/dev/null
ab wait 300 >/dev/null
after=$(page_scroll_state)
before_doc_top=$(echo "$before" | jq -r '.docTop')
after_doc_top=$(echo "$after" | jq -r '.docTop')

if [ "$(echo "$scroll_result" | jq -r '.docTop')" -ge 800 ] \
&& [ "$before_doc_top" -ge 800 ] \
&& [ "$after_doc_top" = "$before_doc_top" ] \
&& [ "$(echo "$after" | jq -r '.pageOpen')" = "true" ] \
&& [ "$(echo "$after" | jq -r '.overlay')" = "true" ]; then
record_pass "$case_id" "title=$(echo "$after" | jq -r '.title // empty') docTop=$after_doc_top"
else
record_fail "$case_id" "scroll=$(echo "$scroll_result" | jq -c '.') body=$(echo "$body_state" | jq -c '{bodyTop, maxScrollTop, centerX, centerY}') before=$(echo "$before" | jq -c '{docTop, pageOpen, overlay, title}') after=$(echo "$after" | jq -c '{docTop, pageOpen, overlay, title}')"
fi
}

run_case() {
local case_id=$1
case "$case_id" in
Expand All @@ -749,6 +890,7 @@ run_case() {
AGENT-CHROME-008) run_008 ;;
AGENT-CHROME-009) run_009 ;;
AGENT-CHROME-010) run_010 ;;
AGENT-CHROME-013) run_013 ;;
*)
record_fail "$case_id" "未知用例 ID"
;;
Expand Down
20 changes: 20 additions & 0 deletions src/content.css
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,26 @@ body.ld-drawer-page-open #ld-drawer-root {
flex: 1;
min-height: 0;
overflow: auto;
overscroll-behavior: contain;
scrollbar-width: thin;
scrollbar-color: color-mix(in srgb, var(--tertiary, #3b82f6) 40%, transparent) transparent;
}

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overscroll-behavior is not inherited. Since there are other scrollable containers inside the drawer (e.g. .ld-drawer-settings-card also has overflow: auto), scroll chaining can still propagate to the outer page when the user wheels/touches at the top/bottom of those inner scrollers. Consider applying overscroll-behavior: contain (or overscroll-behavior-y) to each scrollable drawer container, or set it on a higher-level wrapper that actually scrolls in all modes.

Suggested change
#ld-drawer-root .ld-drawer-body * {
overscroll-behavior: contain;
}

Copilot uses AI. Check for mistakes.
#ld-drawer-root .ld-drawer-body::-webkit-scrollbar {
width: 6px;
}

#ld-drawer-root .ld-drawer-body::-webkit-scrollbar-track {
background: transparent;
}

#ld-drawer-root .ld-drawer-body::-webkit-scrollbar-thumb {
background: color-mix(in srgb, var(--tertiary, #3b82f6) 40%, transparent);
border-radius: 999px;
}

#ld-drawer-root .ld-drawer-body::-webkit-scrollbar-thumb:hover {
background: color-mix(in srgb, var(--tertiary, #3b82f6) 64%, transparent);
Comment on lines +365 to +379

Copilot AI Mar 20, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scrollbar styling here is WebKit-only (::-webkit-scrollbar*). This extension declares Gecko support in manifest.json, so Firefox users will not see the custom drawer scrollbar. If cross-browser consistency is desired, add the Gecko equivalents (e.g. scrollbar-width / scrollbar-color) on .ld-drawer-body so the drawer scrollbar is customized in Firefox too.

Copilot uses AI. Check for mistakes.
}

#ld-drawer-root .ld-drawer-content {
Expand Down
Loading