1
0
mirror of https://github.com/twbs/bootstrap.git synced 2025-08-10 07:37:27 +02:00

tests: replace 'done' callback with 'Promise' to fix deprecation errors (#35659)

Reference:

https://jasmine.github.io/tutorials/async

'DEPRECATION: An asynchronous function called its 'done' callback more than once. This is a bug in the spec, beforeAll, beforeEach, afterAll, or afterEach function in question. This will be treated as an error in a future version. See<https://jasmine.github.io/tutorials/upgrading_to_Jasmine_4.0#deprecations-due-to-calling-done-multiple-times> for more information.
This commit is contained in:
GeoSot
2022-01-30 14:30:04 +02:00
committed by GitHub
parent d092817059
commit aa650f0f1e
20 changed files with 7154 additions and 6571 deletions

View File

@@ -1,6 +1,6 @@
import ScrollSpy from '../../src/scrollspy'
import Manipulator from '../../src/dom/manipulator'
import { getFixture, clearFixture, createEvent, jQueryMock } from '../helpers/fixture'
import { clearFixture, createEvent, getFixture, jQueryMock } from '../helpers/fixture'
describe('ScrollSpy', () => {
let fixtureEl
@@ -85,418 +85,436 @@ describe('ScrollSpy', () => {
expect(scrollSpy._targets).toHaveSize(2)
})
it('should only switch "active" class on current target', done => {
fixtureEl.innerHTML = [
'<div id="root" class="active" style="display: block">',
' <div class="topbar">',
' <div class="topbar-inner">',
' <div class="container" id="ss-target">',
' <ul class="nav">',
' <li class="nav-item"><a href="#masthead">Overview</a></li>',
' <li class="nav-item"><a href="#detail">Detail</a></li>',
' </ul>',
' </div>',
' </div>',
' </div>',
' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
' <div style="height: 200px;">',
' <h4 id="masthead">Overview</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' <div style="height: 200px;">',
' <h4 id="detail">Detail</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' </div>',
'</div>'
].join('')
it('should only switch "active" class on current target', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div id="root" class="active" style="display: block">',
' <div class="topbar">',
' <div class="topbar-inner">',
' <div class="container" id="ss-target">',
' <ul class="nav">',
' <li class="nav-item"><a href="#masthead">Overview</a></li>',
' <li class="nav-item"><a href="#detail">Detail</a></li>',
' </ul>',
' </div>',
' </div>',
' </div>',
' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
' <div style="height: 200px;">',
' <h4 id="masthead">Overview</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' <div style="height: 200px;">',
' <h4 id="detail">Detail</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' </div>',
'</div>'
].join('')
const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example')
const rootEl = fixtureEl.querySelector('#root')
const scrollSpy = new ScrollSpy(scrollSpyEl, {
target: 'ss-target'
})
const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example')
const rootEl = fixtureEl.querySelector('#root')
const scrollSpy = new ScrollSpy(scrollSpyEl, {
target: 'ss-target'
})
spyOn(scrollSpy, '_process').and.callThrough()
spyOn(scrollSpy, '_process').and.callThrough()
scrollSpyEl.addEventListener('scroll', () => {
expect(rootEl).toHaveClass('active')
expect(scrollSpy._process).toHaveBeenCalled()
done()
})
scrollSpyEl.addEventListener('scroll', () => {
expect(rootEl).toHaveClass('active')
expect(scrollSpy._process).toHaveBeenCalled()
resolve()
})
scrollSpyEl.scrollTop = 350
})
it('should only switch "active" class on current target specified w element', done => {
fixtureEl.innerHTML = [
'<div id="root" class="active" style="display: block">',
' <div class="topbar">',
' <div class="topbar-inner">',
' <div class="container" id="ss-target">',
' <ul class="nav">',
' <li class="nav-item"><a href="#masthead">Overview</a></li>',
' <li class="nav-item"><a href="#detail">Detail</a></li>',
' </ul>',
' </div>',
' </div>',
' </div>',
' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
' <div style="height: 200px;">',
' <h4 id="masthead">Overview</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' <div style="height: 200px;">',
' <h4 id="detail">Detail</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' </div>',
'</div>'
].join('')
const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example')
const rootEl = fixtureEl.querySelector('#root')
const scrollSpy = new ScrollSpy(scrollSpyEl, {
target: fixtureEl.querySelector('#ss-target')
})
spyOn(scrollSpy, '_process').and.callThrough()
scrollSpyEl.addEventListener('scroll', () => {
expect(rootEl).toHaveClass('active')
expect(scrollSpy._process).toHaveBeenCalled()
done()
})
scrollSpyEl.scrollTop = 350
})
it('should correctly select middle navigation option when large offset is used', done => {
fixtureEl.innerHTML = [
'<div id="header" style="height: 500px;"></div>',
'<nav id="navigation" class="navbar">',
' <ul class="navbar-nav">',
' <li class="nav-item"><a class="nav-link active" id="one-link" href="#one">One</a></li>',
' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>',
' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>',
' </ul>',
'</nav>',
'<div id="content" style="height: 200px; overflow-y: auto;">',
' <div id="one" style="height: 500px;"></div>',
' <div id="two" style="height: 300px;"></div>',
' <div id="three" style="height: 10px;"></div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('#content')
const scrollSpy = new ScrollSpy(contentEl, {
target: '#navigation',
offset: Manipulator.position(contentEl).top
})
spyOn(scrollSpy, '_process').and.callThrough()
contentEl.addEventListener('scroll', () => {
expect(fixtureEl.querySelector('#one-link')).not.toHaveClass('active')
expect(fixtureEl.querySelector('#two-link')).toHaveClass('active')
expect(fixtureEl.querySelector('#three-link')).not.toHaveClass('active')
expect(scrollSpy._process).toHaveBeenCalled()
done()
})
contentEl.scrollTop = 550
})
it('should add the active class to the correct element', done => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <ul class="nav">',
' <li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>',
' <li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>',
' </ul>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
testElementIsActiveAfterScroll({
elementSelector: '#a-1',
targetSelector: '#div-1',
contentEl,
scrollSpy,
spy,
cb: () => {
testElementIsActiveAfterScroll({
elementSelector: '#a-2',
targetSelector: '#div-2',
contentEl,
scrollSpy,
spy,
cb: () => done()
})
}
scrollSpyEl.scrollTop = 350
})
})
it('should add the active class to the correct element (nav markup)', done => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <nav class="nav">',
' <a class="nav-link" id="a-1" href="#div-1">div 1</a>',
' <a class="nav-link" id="a-2" href="#div-2">div 2</a>',
' </nav>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
'</div>'
].join('')
it('should only switch "active" class on current target specified w element', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div id="root" class="active" style="display: block">',
' <div class="topbar">',
' <div class="topbar-inner">',
' <div class="container" id="ss-target">',
' <ul class="nav">',
' <li class="nav-item"><a href="#masthead">Overview</a></li>',
' <li class="nav-item"><a href="#detail">Detail</a></li>',
' </ul>',
' </div>',
' </div>',
' </div>',
' <div id="scrollspy-example" style="height: 100px; overflow: auto;">',
' <div style="height: 200px;">',
' <h4 id="masthead">Overview</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' <div style="height: 200px;">',
' <h4 id="detail">Detail</h4>',
' <p style="height: 200px;"></p>',
' </div>',
' </div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
const scrollSpyEl = fixtureEl.querySelector('#scrollspy-example')
const rootEl = fixtureEl.querySelector('#root')
const scrollSpy = new ScrollSpy(scrollSpyEl, {
target: fixtureEl.querySelector('#ss-target')
})
testElementIsActiveAfterScroll({
elementSelector: '#a-1',
targetSelector: '#div-1',
contentEl,
scrollSpy,
spy,
cb: () => {
testElementIsActiveAfterScroll({
elementSelector: '#a-2',
targetSelector: '#div-2',
contentEl,
scrollSpy,
spy,
cb: () => done()
})
}
spyOn(scrollSpy, '_process').and.callThrough()
scrollSpyEl.addEventListener('scroll', () => {
expect(rootEl).toHaveClass('active')
expect(scrollSpy._process).toHaveBeenCalled()
resolve()
})
scrollSpyEl.scrollTop = 350
})
})
it('should add the active class to the correct element (list-group markup)', done => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <div class="list-group">',
' <a class="list-group-item" id="a-1" href="#div-1">div 1</a>',
' <a class="list-group-item" id="a-2" href="#div-2">div 2</a>',
' </div>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
'</div>'
].join('')
it('should correctly select middle navigation option when large offset is used', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div id="header" style="height: 500px;"></div>',
'<nav id="navigation" class="navbar">',
' <ul class="navbar-nav">',
' <li class="nav-item"><a class="nav-link active" id="one-link" href="#one">One</a></li>',
' <li class="nav-item"><a class="nav-link" id="two-link" href="#two">Two</a></li>',
' <li class="nav-item"><a class="nav-link" id="three-link" href="#three">Three</a></li>',
' </ul>',
'</nav>',
'<div id="content" style="height: 200px; overflow-y: auto;">',
' <div id="one" style="height: 500px;"></div>',
' <div id="two" style="height: 300px;"></div>',
' <div id="three" style="height: 10px;"></div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
const contentEl = fixtureEl.querySelector('#content')
const scrollSpy = new ScrollSpy(contentEl, {
target: '#navigation',
offset: Manipulator.position(contentEl).top
})
testElementIsActiveAfterScroll({
elementSelector: '#a-1',
targetSelector: '#div-1',
contentEl,
scrollSpy,
spy,
cb: () => {
testElementIsActiveAfterScroll({
elementSelector: '#a-2',
targetSelector: '#div-2',
contentEl,
scrollSpy,
spy,
cb: () => done()
})
}
spyOn(scrollSpy, '_process').and.callThrough()
contentEl.addEventListener('scroll', () => {
expect(fixtureEl.querySelector('#one-link')).not.toHaveClass('active')
expect(fixtureEl.querySelector('#two-link')).toHaveClass('active')
expect(fixtureEl.querySelector('#three-link')).not.toHaveClass('active')
expect(scrollSpy._process).toHaveBeenCalled()
resolve()
})
contentEl.scrollTop = 550
})
})
it('should clear selection if above the first section', done => {
fixtureEl.innerHTML = [
'<div id="header" style="height: 500px;"></div>',
'<nav id="navigation" class="navbar">',
' <ul class="navbar-nav">',
' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
' </ul>',
'</nav>',
'<div id="content" style="height: 200px; overflow-y: auto;">',
' <div id="spacer" style="height: 100px;"></div>',
' <div id="one" style="height: 100px;"></div>',
' <div id="two" style="height: 100px;"></div>',
' <div id="three" style="height: 100px;"></div>',
' <div id="spacer" style="height: 100px;"></div>',
'</div>'
].join('')
it('should add the active class to the correct element', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <ul class="nav">',
' <li class="nav-item"><a class="nav-link" id="a-1" href="#div-1">div 1</a></li>',
' <li class="nav-item"><a class="nav-link" id="a-2" href="#div-2">div 2</a></li>',
' </ul>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('#content')
const scrollSpy = new ScrollSpy(contentEl, {
target: '#navigation',
offset: Manipulator.position(contentEl).top
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
testElementIsActiveAfterScroll({
elementSelector: '#a-1',
targetSelector: '#div-1',
contentEl,
scrollSpy,
spy,
cb: () => {
testElementIsActiveAfterScroll({
elementSelector: '#a-2',
targetSelector: '#div-2',
contentEl,
scrollSpy,
spy,
cb: resolve
})
}
})
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
let firstTime = true
contentEl.addEventListener('scroll', () => {
const active = fixtureEl.querySelector('.active')
expect(spy).toHaveBeenCalled()
spy.calls.reset()
if (firstTime) {
expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1)
expect(active.getAttribute('id')).toEqual('two-link')
firstTime = false
contentEl.scrollTop = 0
} else {
expect(active).toBeNull()
done()
}
})
contentEl.scrollTop = 201
})
it('should not clear selection if above the first section and first section is at the top', done => {
fixtureEl.innerHTML = [
'<div id="header" style="height: 500px;"></div>',
'<nav id="navigation" class="navbar">',
' <ul class="navbar-nav">',
' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
' </ul>',
'</nav>',
'<div id="content" style="height: 200px; overflow-y: auto;">',
' <div id="one" style="height: 100px;"></div>',
' <div id="two" style="height: 100px;"></div>',
' <div id="three" style="height: 100px;"></div>',
' <div id="spacer" style="height: 100px;"></div>',
'</div>'
].join('')
it('should add the active class to the correct element (nav markup)', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <nav class="nav">',
' <a class="nav-link" id="a-1" href="#div-1">div 1</a>',
' <a class="nav-link" id="a-2" href="#div-2">div 2</a>',
' </nav>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
'</div>'
].join('')
const negativeHeight = -10
const startOfSectionTwo = 101
const contentEl = fixtureEl.querySelector('#content')
const scrollSpy = new ScrollSpy(contentEl, {
target: '#navigation',
offset: contentEl.offsetTop
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
testElementIsActiveAfterScroll({
elementSelector: '#a-1',
targetSelector: '#div-1',
contentEl,
scrollSpy,
spy,
cb: () => {
testElementIsActiveAfterScroll({
elementSelector: '#a-2',
targetSelector: '#div-2',
contentEl,
scrollSpy,
spy,
cb: resolve
})
}
})
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
let firstTime = true
contentEl.addEventListener('scroll', () => {
const active = fixtureEl.querySelector('.active')
expect(spy).toHaveBeenCalled()
spy.calls.reset()
if (firstTime) {
expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1)
expect(active.getAttribute('id')).toEqual('two-link')
firstTime = false
contentEl.scrollTop = negativeHeight
} else {
expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1)
expect(active.getAttribute('id')).toEqual('one-link')
done()
}
})
contentEl.scrollTop = startOfSectionTwo
})
it('should correctly select navigation element on backward scrolling when each target section height is 100%', done => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <ul class="nav">',
' <li class="nav-item"><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>',
' <li class="nav-item"><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>',
' <li class="nav-item"><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>',
' <li class="nav-item"><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>',
' <li class="nav-item"><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>',
' </ul>',
'</nav>',
'<div class="content" style="position: relative; overflow: auto; height: 100px">',
' <div id="div-100-1" style="position: relative; height: 100%; padding: 0; margin: 0">div 1</div>',
' <div id="div-100-2" style="position: relative; height: 100%; padding: 0; margin: 0">div 2</div>',
' <div id="div-100-3" style="position: relative; height: 100%; padding: 0; margin: 0">div 3</div>',
' <div id="div-100-4" style="position: relative; height: 100%; padding: 0; margin: 0">div 4</div>',
' <div id="div-100-5" style="position: relative; height: 100%; padding: 0; margin: 0">div 5</div>',
'</div>'
].join('')
it('should add the active class to the correct element (list-group markup)', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <div class="list-group">',
' <a class="list-group-item" id="a-1" href="#div-1">div 1</a>',
' <a class="list-group-item" id="a-2" href="#div-2">div 2</a>',
' </div>',
'</nav>',
'<div class="content" style="overflow: auto; height: 50px">',
' <div id="div-1" style="height: 100px; padding: 0; margin: 0">div 1</div>',
' <div id="div-2" style="height: 200px; padding: 0; margin: 0">div 2</div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
testElementIsActiveAfterScroll({
elementSelector: '#a-1',
targetSelector: '#div-1',
contentEl,
scrollSpy,
spy,
cb: () => {
testElementIsActiveAfterScroll({
elementSelector: '#a-2',
targetSelector: '#div-2',
contentEl,
scrollSpy,
spy,
cb: resolve
})
}
})
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
})
testElementIsActiveAfterScroll({
elementSelector: '#li-100-5',
targetSelector: '#div-100-5',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-4',
targetSelector: '#div-100-4',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-3',
targetSelector: '#div-100-3',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-2',
targetSelector: '#div-100-2',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-1',
targetSelector: '#div-100-1',
scrollSpy,
spy,
contentEl,
cb: done
})
}
})
}
})
}
})
}
it('should clear selection if above the first section', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div id="header" style="height: 500px;"></div>',
'<nav id="navigation" class="navbar">',
' <ul class="navbar-nav">',
' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
' </ul>',
'</nav>',
'<div id="content" style="height: 200px; overflow-y: auto;">',
' <div id="spacer" style="height: 100px;"></div>',
' <div id="one" style="height: 100px;"></div>',
' <div id="two" style="height: 100px;"></div>',
' <div id="three" style="height: 100px;"></div>',
' <div id="spacer" style="height: 100px;"></div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('#content')
const scrollSpy = new ScrollSpy(contentEl, {
target: '#navigation',
offset: Manipulator.position(contentEl).top
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
let firstTime = true
contentEl.addEventListener('scroll', () => {
const active = fixtureEl.querySelector('.active')
expect(spy).toHaveBeenCalled()
spy.calls.reset()
if (firstTime) {
expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1)
expect(active.getAttribute('id')).toEqual('two-link')
firstTime = false
contentEl.scrollTop = 0
} else {
expect(active).toBeNull()
resolve()
}
})
contentEl.scrollTop = 201
})
})
it('should not clear selection if above the first section and first section is at the top', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<div id="header" style="height: 500px;"></div>',
'<nav id="navigation" class="navbar">',
' <ul class="navbar-nav">',
' <li class="nav-item"><a id="one-link" class="nav-link active" href="#one">One</a></li>',
' <li class="nav-item"><a id="two-link" class="nav-link" href="#two">Two</a></li>',
' <li class="nav-item"><a id="three-link" class="nav-link" href="#three">Three</a></li>',
' </ul>',
'</nav>',
'<div id="content" style="height: 200px; overflow-y: auto;">',
' <div id="one" style="height: 100px;"></div>',
' <div id="two" style="height: 100px;"></div>',
' <div id="three" style="height: 100px;"></div>',
' <div id="spacer" style="height: 100px;"></div>',
'</div>'
].join('')
const negativeHeight = -10
const startOfSectionTwo = 101
const contentEl = fixtureEl.querySelector('#content')
const scrollSpy = new ScrollSpy(contentEl, {
target: '#navigation',
offset: contentEl.offsetTop
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
let firstTime = true
contentEl.addEventListener('scroll', () => {
const active = fixtureEl.querySelector('.active')
expect(spy).toHaveBeenCalled()
spy.calls.reset()
if (firstTime) {
expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1)
expect(active.getAttribute('id')).toEqual('two-link')
firstTime = false
contentEl.scrollTop = negativeHeight
} else {
expect(fixtureEl.querySelectorAll('.active')).toHaveSize(1)
expect(active.getAttribute('id')).toEqual('one-link')
resolve()
}
})
contentEl.scrollTop = startOfSectionTwo
})
})
it('should correctly select navigation element on backward scrolling when each target section height is 100%', () => {
return new Promise(resolve => {
fixtureEl.innerHTML = [
'<nav class="navbar">',
' <ul class="nav">',
' <li class="nav-item"><a id="li-100-1" class="nav-link" href="#div-100-1">div 1</a></li>',
' <li class="nav-item"><a id="li-100-2" class="nav-link" href="#div-100-2">div 2</a></li>',
' <li class="nav-item"><a id="li-100-3" class="nav-link" href="#div-100-3">div 3</a></li>',
' <li class="nav-item"><a id="li-100-4" class="nav-link" href="#div-100-4">div 4</a></li>',
' <li class="nav-item"><a id="li-100-5" class="nav-link" href="#div-100-5">div 5</a></li>',
' </ul>',
'</nav>',
'<div class="content" style="position: relative; overflow: auto; height: 100px">',
' <div id="div-100-1" style="position: relative; height: 100%; padding: 0; margin: 0">div 1</div>',
' <div id="div-100-2" style="position: relative; height: 100%; padding: 0; margin: 0">div 2</div>',
' <div id="div-100-3" style="position: relative; height: 100%; padding: 0; margin: 0">div 3</div>',
' <div id="div-100-4" style="position: relative; height: 100%; padding: 0; margin: 0">div 4</div>',
' <div id="div-100-5" style="position: relative; height: 100%; padding: 0; margin: 0">div 5</div>',
'</div>'
].join('')
const contentEl = fixtureEl.querySelector('.content')
const scrollSpy = new ScrollSpy(contentEl, {
offset: 0,
target: '.navbar'
})
const spy = spyOn(scrollSpy, '_process').and.callThrough()
testElementIsActiveAfterScroll({
elementSelector: '#li-100-5',
targetSelector: '#div-100-5',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-4',
targetSelector: '#div-100-4',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-3',
targetSelector: '#div-100-3',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-2',
targetSelector: '#div-100-2',
scrollSpy,
spy,
contentEl,
cb() {
contentEl.scrollTop = 0
testElementIsActiveAfterScroll({
elementSelector: '#li-100-1',
targetSelector: '#div-100-1',
scrollSpy,
spy,
contentEl,
cb: resolve
})
}
})
}
})
}
})
}
})
})
})