variable header size
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||
import { flushPromises } from '@vue/test-utils'
|
||||
import axios from 'axios'
|
||||
import { useFeeds } from '../useFeeds'
|
||||
|
||||
@@ -12,7 +13,7 @@ class FakeIntersectionObserver {
|
||||
vi.stubGlobal('IntersectionObserver', FakeIntersectionObserver)
|
||||
|
||||
describe('useFeeds', () => {
|
||||
const { feeds, showMessage, message, showModal, fetchData, sync, getReadable, setInitialLoad, handleIntersection } = useFeeds()
|
||||
const { feeds, showMessage, message, showModal, fetchData, sync, getReadable, setInitialLoad, handleIntersection, consumeScrollCorrection } = useFeeds()
|
||||
|
||||
beforeEach(() => {
|
||||
localStorage.setItem('user-token', 'test-token')
|
||||
@@ -116,6 +117,36 @@ describe('useFeeds', () => {
|
||||
setInitialLoad(false)
|
||||
})
|
||||
|
||||
it('flags a scroll correction when marking an article read repositions the list', async () => {
|
||||
// Regression coverage for the header-compacting glitch: AppNav's scroll
|
||||
// handler needs a way to tell "the page moved because content was
|
||||
// removed" apart from a real user scroll. jsdom's getBoundingClientRect()
|
||||
// defaults every element's top to 0, so any topbarHeight > 0 exercises
|
||||
// the same "first article now sits above the header" branch that fires
|
||||
// in a real browser.
|
||||
feeds.value = [{ id: 101, title: 'First' }, { id: 102, title: 'Second' }]
|
||||
setInitialLoad(true)
|
||||
axios.put.mockResolvedValue({ status: 200 })
|
||||
|
||||
const observeDiv = document.createElement('div')
|
||||
observeDiv.className = 'observe'
|
||||
document.body.appendChild(observeDiv)
|
||||
|
||||
expect(consumeScrollCorrection()).toBe(false)
|
||||
|
||||
await handleIntersection([
|
||||
{ isIntersecting: false, boundingClientRect: { y: -10 }, target: { id: '0' } },
|
||||
], 60)
|
||||
await flushPromises()
|
||||
|
||||
expect(consumeScrollCorrection()).toBe(true)
|
||||
// Consume-once: asking again without another correction reports false.
|
||||
expect(consumeScrollCorrection()).toBe(false)
|
||||
|
||||
document.body.removeChild(observeDiv)
|
||||
setInitialLoad(false)
|
||||
})
|
||||
|
||||
it('strips leftover embedded-video placeholder headings', async () => {
|
||||
feeds.value = [{
|
||||
id: 1,
|
||||
|
||||
@@ -14,6 +14,13 @@ const layout = ref(localStorage.getItem('layout') || 'list') // 'list' | 'cards'
|
||||
|
||||
let observer; // Declare observer outside the setup function
|
||||
let initialLoad = false
|
||||
// Set right before the scroll-position correction below, so AppNav's
|
||||
// scroll-driven header compacting can tell "the page just moved because
|
||||
// content was removed" apart from a real user scroll — otherwise every
|
||||
// article marked read (which resets scrollY toward the top of the
|
||||
// now-shorter list) would look identical to the user manually scrolling
|
||||
// back to the top.
|
||||
let scrollCorrectionPending = false
|
||||
|
||||
export function authHeaders() {
|
||||
return {
|
||||
@@ -265,6 +272,7 @@ function handleIntersection(entries, topbarHeight = 0) {
|
||||
if (first) {
|
||||
const top = first.getBoundingClientRect().top
|
||||
if (top < topbarHeight) {
|
||||
scrollCorrectionPending = true
|
||||
window.scrollBy(0, top - topbarHeight)
|
||||
}
|
||||
}
|
||||
@@ -272,6 +280,17 @@ function handleIntersection(entries, topbarHeight = 0) {
|
||||
})
|
||||
}
|
||||
|
||||
// Consume-once: returns whether a scroll-position correction is pending
|
||||
// (and clears it), so a caller can tell this scroll event apart from a
|
||||
// real user scroll without the flag lingering into later, unrelated ones.
|
||||
function consumeScrollCorrection() {
|
||||
if (scrollCorrectionPending) {
|
||||
scrollCorrectionPending = false
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
function disconnectObserver() {
|
||||
if (observer) {
|
||||
observer.disconnect()
|
||||
@@ -386,6 +405,7 @@ export function useFeeds() {
|
||||
markAllRead,
|
||||
showMessageForXSeconds,
|
||||
setupIntersectionObserver,
|
||||
consumeScrollCorrection,
|
||||
disconnectObserver,
|
||||
setInitialLoad,
|
||||
handleIntersection,
|
||||
|
||||
Reference in New Issue
Block a user