|
|
@ -1,6 +1,11 @@ |
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'; |
|
|
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; |
|
|
|
|
|
|
|
|
import { getElementVisibleRect } from '../dom'; |
|
|
import { ELEMENT_ID_LAYOUT_SCROLL } from '../../constants'; |
|
|
|
|
|
import { |
|
|
|
|
|
getElementVisibleRect, |
|
|
|
|
|
getLayoutScrollElement, |
|
|
|
|
|
needsScrollbar, |
|
|
|
|
|
} from '../dom'; |
|
|
|
|
|
|
|
|
describe('getElementVisibleRect', () => { |
|
|
describe('getElementVisibleRect', () => { |
|
|
// 设置浏览器视口尺寸的 mock
|
|
|
// 设置浏览器视口尺寸的 mock
|
|
|
@ -15,6 +20,10 @@ describe('getElementVisibleRect', () => { |
|
|
vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1000); |
|
|
vi.spyOn(window, 'innerWidth', 'get').mockReturnValue(1000); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
afterEach(() => { |
|
|
|
|
|
vi.restoreAllMocks(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
it('should return default rect if element is undefined', () => { |
|
|
it('should return default rect if element is undefined', () => { |
|
|
expect(getElementVisibleRect()).toEqual({ |
|
|
expect(getElementVisibleRect()).toEqual({ |
|
|
bottom: 0, |
|
|
bottom: 0, |
|
|
@ -125,3 +134,75 @@ describe('getElementVisibleRect', () => { |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
describe('getLayoutScrollElement', () => { |
|
|
|
|
|
afterEach(() => { |
|
|
|
|
|
document.body.innerHTML = ''; |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should return the layout scroll element', () => { |
|
|
|
|
|
const element = document.createElement('div'); |
|
|
|
|
|
element.id = ELEMENT_ID_LAYOUT_SCROLL; |
|
|
|
|
|
document.body.append(element); |
|
|
|
|
|
|
|
|
|
|
|
expect(getLayoutScrollElement()).toBe(element); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should return null when the layout scroll element is missing', () => { |
|
|
|
|
|
expect(getLayoutScrollElement()).toBeNull(); |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
describe('needsScrollbar', () => { |
|
|
|
|
|
afterEach(() => { |
|
|
|
|
|
vi.restoreAllMocks(); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should check scrollbar state from target element', () => { |
|
|
|
|
|
const element = document.createElement('div'); |
|
|
|
|
|
vi.spyOn(element, 'clientHeight', 'get').mockReturnValue(100); |
|
|
|
|
|
vi.spyOn(element, 'scrollHeight', 'get').mockReturnValue(120); |
|
|
|
|
|
vi.spyOn(window, 'getComputedStyle').mockReturnValue({ |
|
|
|
|
|
overflowY: 'auto', |
|
|
|
|
|
} as CSSStyleDeclaration); |
|
|
|
|
|
|
|
|
|
|
|
expect(needsScrollbar(element)).toBe(true); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it('should return false when target content does not overflow', () => { |
|
|
|
|
|
const element = document.createElement('div'); |
|
|
|
|
|
vi.spyOn(element, 'clientHeight', 'get').mockReturnValue(100); |
|
|
|
|
|
vi.spyOn(element, 'scrollHeight', 'get').mockReturnValue(100); |
|
|
|
|
|
vi.spyOn(window, 'getComputedStyle').mockReturnValue({ |
|
|
|
|
|
overflowY: 'auto', |
|
|
|
|
|
} as CSSStyleDeclaration); |
|
|
|
|
|
|
|
|
|
|
|
expect(needsScrollbar(element)).toBe(false); |
|
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
|
|
it.each(['clip', 'hidden'])( |
|
|
|
|
|
'should ignore %s overflow targets', |
|
|
|
|
|
(overflowY) => { |
|
|
|
|
|
const element = document.createElement('div'); |
|
|
|
|
|
vi.spyOn(element, 'clientHeight', 'get').mockReturnValue(100); |
|
|
|
|
|
vi.spyOn(element, 'scrollHeight', 'get').mockReturnValue(120); |
|
|
|
|
|
vi.spyOn(window, 'getComputedStyle').mockReturnValue({ |
|
|
|
|
|
overflowY, |
|
|
|
|
|
} as CSSStyleDeclaration); |
|
|
|
|
|
|
|
|
|
|
|
expect(needsScrollbar(element)).toBe(false); |
|
|
|
|
|
}, |
|
|
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
it('should fall back to document scrollbar state', () => { |
|
|
|
|
|
vi.spyOn(document.documentElement, 'scrollHeight', 'get').mockReturnValue( |
|
|
|
|
|
120, |
|
|
|
|
|
); |
|
|
|
|
|
vi.spyOn(window, 'innerHeight', 'get').mockReturnValue(100); |
|
|
|
|
|
vi.spyOn(window, 'getComputedStyle').mockReturnValue({ |
|
|
|
|
|
overflowY: 'auto', |
|
|
|
|
|
} as CSSStyleDeclaration); |
|
|
|
|
|
|
|
|
|
|
|
expect(needsScrollbar()).toBe(true); |
|
|
|
|
|
}); |
|
|
|
|
|
}); |
|
|
|