Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled
112 lines
3.8 KiB
JavaScript
112 lines
3.8 KiB
JavaScript
"use strict";
|
|
|
|
const assert = require("node:assert/strict");
|
|
|
|
const {zrequire} = require("./lib/namespace.cjs");
|
|
const {run_test} = require("./lib/test.cjs");
|
|
|
|
const sidebar_header_sticky_shadow = zrequire("sidebar_header_sticky_shadow");
|
|
|
|
function make_header(top) {
|
|
const classes = new Set();
|
|
return {
|
|
getBoundingClientRect: () => ({top}),
|
|
classList: {
|
|
toggle(name, on) {
|
|
if (on) {
|
|
classes.add(name);
|
|
} else {
|
|
classes.delete(name);
|
|
}
|
|
},
|
|
has: (name) => classes.has(name),
|
|
},
|
|
};
|
|
}
|
|
|
|
function make_scroll_container({scrollTop, container_top, headers}) {
|
|
let scroll_listener;
|
|
const container = {
|
|
scrollTop,
|
|
getBoundingClientRect: () => ({top: container_top}),
|
|
querySelectorAll: () => headers,
|
|
addEventListener(event, callback, options) {
|
|
assert.equal(event, "scroll");
|
|
assert.deepEqual(options, {passive: true});
|
|
scroll_listener = callback;
|
|
},
|
|
};
|
|
return {
|
|
$wrapper: {length: 1, 0: container},
|
|
get scroll_listener() {
|
|
return scroll_listener;
|
|
},
|
|
container,
|
|
};
|
|
}
|
|
|
|
run_test("install toggles shadow based on stickiness", ({override}) => {
|
|
override(globalThis, "getComputedStyle", () => ({top: "40px"}));
|
|
|
|
// Container has been scrolled; pin line is at container_top + sticky_top = 50.
|
|
// Header sitting exactly at the pin line: stuck, shadow on.
|
|
const stuck_header = make_header(50);
|
|
// Header that has been pushed above the pin line by the next section
|
|
// arriving from below; shadow suppressed to avoid a visible seam at
|
|
// the junction.
|
|
const pushed_out_header = make_header(45);
|
|
// Header still below the pin line, not yet stuck.
|
|
const below_pin_line_header = make_header(500);
|
|
|
|
const scroll = make_scroll_container({
|
|
scrollTop: 120,
|
|
container_top: 10,
|
|
headers: [stuck_header, pushed_out_header, below_pin_line_header],
|
|
});
|
|
|
|
sidebar_header_sticky_shadow.initialize(scroll.$wrapper, ".header");
|
|
|
|
assert.ok(stuck_header.classList.has("sidebar-header-drop-shadow"));
|
|
assert.ok(!pushed_out_header.classList.has("sidebar-header-drop-shadow"));
|
|
assert.ok(!below_pin_line_header.classList.has("sidebar-header-drop-shadow"));
|
|
|
|
// The scroll listener re-runs the update logic.
|
|
assert.ok(typeof scroll.scroll_listener === "function");
|
|
scroll.scroll_listener();
|
|
assert.ok(stuck_header.classList.has("sidebar-header-drop-shadow"));
|
|
});
|
|
|
|
run_test("install leaves shadow off before any scroll", ({override}) => {
|
|
override(globalThis, "getComputedStyle", () => ({top: "40px"}));
|
|
|
|
// Same geometry as the stuck case above (header top=50, pin line=50),
|
|
// but scrollTop=0. Pre-set the shadow class so we can see install()
|
|
// actively removes it, proving the has_scrolled guard is doing its job.
|
|
const header = make_header(50);
|
|
header.classList.toggle("sidebar-header-drop-shadow", true);
|
|
const scroll = make_scroll_container({
|
|
scrollTop: 0,
|
|
container_top: 10,
|
|
headers: [header],
|
|
});
|
|
|
|
sidebar_header_sticky_shadow.initialize(scroll.$wrapper, ".header");
|
|
assert.ok(!header.classList.has("sidebar-header-drop-shadow"));
|
|
});
|
|
|
|
run_test("install handles missing computed top", ({override}) => {
|
|
override(globalThis, "getComputedStyle", () => ({top: "auto"}));
|
|
|
|
// With sticky_top defaulting to 0, a header at container_top is stuck.
|
|
const container_top = 10;
|
|
const header = make_header(container_top);
|
|
const scroll = make_scroll_container({
|
|
scrollTop: 50,
|
|
container_top,
|
|
headers: [header],
|
|
});
|
|
|
|
sidebar_header_sticky_shadow.initialize(scroll.$wrapper, ".header");
|
|
assert.ok(header.classList.has("sidebar-header-drop-shadow"));
|
|
});
|