import Popper from '../../src/index.js';
import '@popperjs/test-utils';
const jasmineWrapper = document.getElementById('jasmineWrapper');
// Utils
import appendNewPopper from '@popperjs/test-utils/utils/appendNewPopper';
import appendNewRef from '@popperjs/test-utils/utils/appendNewRef';
import simulateScroll from '@popperjs/test-utils/utils/simulateScroll';
import prepend from '@popperjs/test-utils/utils/prepend';
import isMSBrowser from '@popperjs/test-utils/utils/isMSBrowser';
import getRect from '../utils/getRect';
const isIE10 = navigator.appVersion.indexOf('MSIE 10') !== -1;
const isIPHONE = window.navigator.userAgent.match(/iPhone/i);
const arrowSize = 5;
describe('[core]', () => {
afterEach(function() {
jasmineWrapper.scrollTop = 0;
jasmineWrapper.scrollLeft = 0;
});
it('can access the AMD module to create a new instance', () => {
// append popper element
const popper = document.createElement('div');
popper.style.width = '100px';
popper.style.height = '100px';
jasmineWrapper.appendChild(popper);
// append trigger element
const trigger = document.createElement('div');
jasmineWrapper.appendChild(trigger);
// initialize new popper instance
const pop = new Popper(trigger, popper);
expect(pop).toBeDefined();
pop.destroy();
});
it('inits a bottom popper', () => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper);
const top = getRect(popper).top;
expect(top).toBeApprox(getRect(reference).bottom + arrowSize);
pop.destroy();
});
it('inits a bottom popper inside document with margins', done => {
const doc = document.documentElement;
doc.style.marginLeft = '300px';
doc.style.marginTop = '300px';
const wrp = document.createElement('div');
wrp.innerHTML = `
1
`.trim();
const popper = wrp.childNodes[1];
const reference = wrp.childNodes[0];
prepend(reference, document.body);
prepend(popper, document.body);
new Popper(reference, popper, {
placement: 'top',
onCreate(data) {
const bottom = getRect(popper).bottom;
expect(bottom).toBeApprox(getRect(reference).top);
data.instance.destroy();
document.body.removeChild(popper);
document.body.removeChild(reference);
doc.style.cssText = null;
done();
},
});
});
it('inits a bottom popper inside document with margins, it should correctly flip', done => {
if (isIPHONE) {
pending();
}
const doc = document.documentElement;
doc.style.marginLeft = '50vw';
doc.style.marginTop = '100vh';
const wrp = document.createElement('div');
wrp.innerHTML = `
1
`.trim();
const popper = wrp.childNodes[1];
const reference = wrp.childNodes[0];
prepend(reference, document.body);
prepend(popper, document.body);
new Popper(reference, popper, {
onCreate(data) {
const bottom = getRect(popper).bottom;
expect(bottom).toBeApprox(getRect(reference).top);
data.instance.destroy();
document.body.removeChild(popper);
document.body.removeChild(reference);
doc.style.cssText = null;
done();
},
});
});
it('inits a top popper inside body with margins relative to absolute reference rotated by 90 degs', done => {
const wrp = document.createElement('div');
wrp.innerHTML = `
1
`.trim();
const popper = wrp.childNodes[1];
const reference = wrp.childNodes[0];
prepend(reference, document.body);
prepend(popper, document.body);
new Popper(reference, popper, {
placement: 'top',
onCreate(data) {
const pop = getRect(popper);
const ref = getRect(reference);
expect(pop.bottom).toBeApprox(ref.top);
expect(pop.left).toBe(ref.left);
data.instance.destroy();
document.body.style.cssText = null;
document.body.removeChild(popper);
document.body.removeChild(reference);
done();
},
});
});
it('inits a right scrollable popper ', done => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2);
popper.style.overflow = 'auto';
const pop = new Popper(reference, popper, {
placement: 'right',
onCreate() {
const left = getRect(popper).left;
expect(left).toBeApprox(getRect(reference).right + arrowSize);
pop.destroy();
done();
},
});
});
describe(['inner modifier'], () => {
it('inits a bottom inner popper', done => {
const reference = appendNewRef(1);
reference.style.height = '200px';
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper, {
modifiers: { inner: { enabled: true } },
onCreate() {
const bottom = getRect(popper).bottom + arrowSize;
expect(bottom).toBeApprox(getRect(reference).bottom);
pop.destroy();
done();
},
});
});
it('inits a top inner popper', done => {
const reference = appendNewRef(1);
reference.style.height = '200px';
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper, {
placement: 'top',
modifiers: { inner: { enabled: true } },
onCreate() {
const top = getRect(popper).top - arrowSize;
expect(top).toBeApprox(getRect(reference).top);
pop.destroy();
done();
},
});
});
it('inits a right inner popper', done => {
const reference = appendNewRef(1);
reference.style.height = '200px';
reference.style.width = '200px';
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper, {
placement: 'right',
modifiers: { inner: { enabled: true } },
onCreate() {
const right = getRect(popper).right + arrowSize;
expect(right).toBeApprox(getRect(reference).right);
pop.destroy();
done();
},
});
});
it('inits a left inner popper', done => {
const reference = appendNewRef(1);
reference.style.height = '200px';
reference.style.width = '200px';
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper, {
placement: 'left',
modifiers: { inner: { enabled: true } },
onCreate() {
const left = getRect(popper).left - arrowSize;
expect(left).toBeApprox(getRect(reference).left);
pop.destroy();
done();
},
});
});
it('inits a right-start inner popper', done => {
const reference = appendNewRef(1);
reference.style.height = '200px';
reference.style.width = '200px';
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper, {
placement: 'right-start',
modifiers: { inner: { enabled: true } },
onCreate() {
const right = getRect(popper).right + arrowSize;
expect(right).toBeApprox(getRect(reference).right);
pop.destroy();
done();
},
});
});
});
describe('[auto placement]', () => {
it('should be computed to `top`', done => {
const parent = document.createElement('div');
parent.style.overflow = 'auto';
parent.style.position = 'relative';
parent.style.width = '500px';
parent.style.height = '500px';
parent.style.backgroundColor = 'green';
const reference = appendNewRef(1, 'ref', parent);
reference.style.position = 'absolute';
reference.style.bottom = '0';
reference.style.left = '50%';
const popper = appendNewPopper(2, 'pop', parent);
jasmineWrapper.appendChild(parent);
const pop = new Popper(reference, popper, {
placement: 'auto',
modifiers: { flip: { boundariesElement: 'scrollParent' } },
onCreate: () => {
const bottom = getRect(popper).bottom + arrowSize;
expect(bottom).toBeApprox(getRect(reference).top);
pop.destroy();
done();
},
});
});
it('should be computed to `right`', done => {
const parent = document.createElement('div');
parent.style.overflow = 'auto';
parent.style.position = 'relative';
parent.style.width = '500px';
parent.style.height = '500px';
parent.style.backgroundColor = 'green';
const reference = appendNewRef(1, 'ref', parent);
reference.style.position = 'absolute';
reference.style.left = '0';
reference.style.top = '50%';
const popper = appendNewPopper(2, 'pop', parent);
jasmineWrapper.appendChild(parent);
const pop = new Popper(reference, popper, {
placement: 'auto',
modifiers: { flip: { boundariesElement: 'scrollParent' } },
onCreate: () => {
const left = getRect(popper).left - arrowSize;
expect(left).toBeApprox(getRect(reference).right);
pop.destroy();
done();
},
});
});
it('should be computed to `bottom`', done => {
const parent = document.createElement('div');
parent.style.overflow = 'auto';
parent.style.position = 'relative';
parent.style.width = '500px';
parent.style.height = '500px';
parent.style.backgroundColor = 'green';
const reference = appendNewRef(1, 'ref', parent);
reference.style.position = 'absolute';
reference.style.top = '0';
reference.style.left = '50%';
const popper = appendNewPopper(2, 'pop', parent);
jasmineWrapper.appendChild(parent);
const pop = new Popper(reference, popper, {
placement: 'auto',
modifiers: { flip: { boundariesElement: 'scrollParent' } },
onCreate: () => {
const top = getRect(popper).top - arrowSize;
expect(top).toBeApprox(getRect(reference).bottom);
pop.destroy();
done();
},
});
});
it('should be computed to `left`', done => {
const parent = document.createElement('div');
parent.style.overflow = 'auto';
parent.style.position = 'relative';
parent.style.width = '500px';
parent.style.height = '500px';
parent.style.backgroundColor = 'green';
const reference = appendNewRef(1, 'ref', parent);
reference.style.position = 'absolute';
reference.style.right = '0';
reference.style.top = '50%';
const popper = appendNewPopper(2, 'pop', parent);
jasmineWrapper.appendChild(parent);
const pop = new Popper(reference, popper, {
placement: 'auto',
modifiers: { flip: { boundariesElement: 'scrollParent' } },
onCreate: () => {
const right = getRect(popper).right + arrowSize;
expect(right).toBeApprox(getRect(reference).left);
pop.destroy();
done();
},
});
});
});
it('inits a bottom popper attached to an inline reference', done => {
const reference = appendNewRef(1);
reference.style.display = 'inline';
const popper = appendNewPopper(2);
const pop = new Popper(reference, popper);
// give some time to the browser to render...
// otherwise `getBoundingClientRect` returns wrong values
setTimeout(() => {
const top = getRect(popper).top;
expect(top).toBeApprox(getRect(reference).bottom + arrowSize);
pop.destroy();
done();
}, 10);
});
it('inits a bottom-start popper', done => {
const reference = appendNewRef(1);
reference.style.marginLeft = '200px';
const popper = appendNewPopper(2);
new Popper(reference, popper, {
placement: 'bottom-start',
onCreate: data => {
expect(getRect(popper).left).toBeApprox(getRect(reference).left);
data.instance.destroy();
done();
},
});
});
it('inits a right popper', done => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2);
new Popper(reference, popper, {
placement: 'right',
onCreate: data => {
expect(getRect(popper).left - arrowSize).toBeApprox(
getRect(reference).right
);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a scrolling div, contained in a relative div', done => {
const relative = document.createElement('div');
relative.style.width = '800px';
relative.style.height = '700px';
relative.style.position = 'relative';
relative.style.backgroundColor = 'green';
relative.style.border = '1px solid';
jasmineWrapper.appendChild(relative);
const scrolling = document.createElement('div');
scrolling.style.width = '800px';
scrolling.style.height = '500px';
scrolling.style.overflow = 'auto';
scrolling.style.backgroundColor = 'blue';
scrolling.style.marginTop = '100px';
relative.appendChild(scrolling);
const superHigh1 = document.createElement('div');
superHigh1.style.width = '800px';
superHigh1.style.height = '450px';
scrolling.appendChild(superHigh1);
const ref = appendNewRef(1, 'ref', scrolling);
const popper = appendNewPopper(2, 'popper', scrolling);
const superHigh2 = document.createElement('div');
superHigh2.style.width = '800px';
superHigh2.style.height = '500px';
scrolling.appendChild(superHigh2);
simulateScroll(scrolling, { scrollTop: 400 });
new Popper(ref, popper, {
placement: 'top',
onCreate: () => {
// placement should be top
expect(getRect(popper).bottom + arrowSize).toBeApprox(getRect(ref).top);
simulateScroll(scrolling, { scrollTop: 100, delay: 10 });
},
onUpdate: data => {
// placement should be top
expect(getRect(popper).bottom + arrowSize).toBeApprox(getRect(ref).top);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a scrolling div with an huge border', done => {
const scrolling = document.createElement('div');
scrolling.style.width = '800px';
scrolling.style.height = '500px';
scrolling.style.overflow = 'auto';
scrolling.style.backgroundColor = 'blue';
scrolling.style.border = '50px green solid';
jasmineWrapper.appendChild(scrolling);
const superHigh1 = document.createElement('div');
superHigh1.style.width = '800px';
superHigh1.style.height = '450px';
scrolling.appendChild(superHigh1);
const ref = appendNewRef(1, 'ref', scrolling);
const popper = appendNewPopper(2, 'popper', scrolling);
const superHigh2 = document.createElement('div');
superHigh2.style.width = '800px';
superHigh2.style.height = '500px';
scrolling.appendChild(superHigh2);
simulateScroll(scrolling, { scrollTop: 400 });
new Popper(ref, popper, {
placement: 'top',
onCreate: () => {
//placement should be top
expect(getRect(popper).bottom + arrowSize).toBeApprox(getRect(ref).top);
simulateScroll(scrolling, { scrollTop: 100, delay: 10 });
},
onUpdate: data => {
// placement should be top
expect(getRect(popper).bottom + arrowSize).toBeApprox(getRect(ref).top);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a body, with its reference element inside a relative div', done => {
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
jasmineWrapper.appendChild(relative);
const ref = appendNewRef(1, 'ref', relative);
const popper = appendNewPopper(2, 'popper');
new Popper(ref, popper, {
onCreate: data => {
expect(getRect(popper).top - arrowSize).toBeApprox(getRect(ref).bottom);
expect(getRect(popper).left).toBeApprox(5);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a body without any positioned or scrollable parents and scrolls the body', done => {
const ref = appendNewRef(1, 'ref');
const popper = appendNewPopper(2, 'popper');
document.body.scrollTop = 100;
new Popper(ref, popper, {
onCreate: data => {
expect(getRect(popper).top - arrowSize).toBeApprox(getRect(ref).bottom);
expect(getRect(popper).left).toBeApprox(5);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a scrolled body, with its reference element inside a relative div', done => {
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.height = '300vh';
jasmineWrapper.appendChild(relative);
simulateScroll(document.body, { scrollTop: 300 });
const ref = appendNewRef(1, 'ref', relative);
ref.style.marginTop = '300px';
const popper = appendNewPopper(2, 'popper');
new Popper(ref, popper, {
onCreate: data => {
expect(getRect(popper).top - arrowSize).toBeApprox(getRect(ref).bottom);
expect(getRect(popper).left).toBeApprox(5);
data.instance.destroy();
done();
},
});
});
it('inits a popper near a reference element, both inside a fixed element, inside a scrolled body', done => {
const fixed = document.createElement('div');
fixed.style.position = 'fixed';
fixed.style.margin = '20px';
fixed.style.height = '50px';
fixed.style.width = '100%';
fixed.style.backgroundColor = 'grey';
jasmineWrapper.appendChild(fixed);
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.height = '200vh';
jasmineWrapper.appendChild(relative);
simulateScroll(document.body, { scrollTop: 800 });
const ref = appendNewRef(1, 'ref', fixed);
const popper = appendNewPopper(2, 'popper', fixed);
new Popper(ref, popper, {
onCreate: data => {
expect(getRect(popper).top - arrowSize).toBeApprox(getRect(ref).bottom);
expect(getRect(popper).left).toBeApprox(5);
data.instance.destroy();
done();
},
});
});
it('inits a popper near a reference element, both inside a fixed element with CSS transforms, inside a scrolled body', done => {
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.height = '200vh';
relative.style.background = 'rgba(100, 100, 100, 0.5)';
const fixed = document.createElement('div');
fixed.style.position = 'fixed';
fixed.style.margin = '20px';
fixed.style.height = '50px';
fixed.style.width = '100%';
fixed.style.transform = 'translateX(0.1)';
fixed.style.background = 'green';
relative.appendChild(fixed);
jasmineWrapper.appendChild(relative);
const ref = appendNewRef(1, 'ref', fixed);
const popper = appendNewPopper(2, 'popper', fixed);
simulateScroll(document.body, { scrollTop: 800 });
new Popper(ref, popper, {
onCreate: data => {
expect(getRect(popper).top - arrowSize).toBeApprox(getRect(ref).bottom);
expect(getRect(popper).left).toBeApprox(5);
data.instance.destroy();
done();
},
});
});
it('inits a popper near a reference element, both inside a fixed element on bottom of viewport, inside a scrolled body', done => {
const fixed = document.createElement('div');
fixed.style.position = 'fixed';
fixed.style.bottom = '5px';
fixed.style.height = '38px';
fixed.style.width = '100%';
jasmineWrapper.appendChild(fixed);
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.height = '200vh';
jasmineWrapper.appendChild(relative);
simulateScroll(document.body, { scrollTop: 800 });
const ref = appendNewRef(1, 'ref', fixed);
const popper = appendNewPopper(2, 'popper', fixed);
new Popper(ref, popper, {
placement: 'top',
onCreate: data => {
expect(getRect(popper).bottom + arrowSize).toBeApprox(getRect(ref).top);
expect(getRect(popper).left).toBeApprox(5);
expect(popper.getAttribute('x-placement')).toBe('top');
data.instance.destroy();
done();
},
});
});
it('inits a popper and destroy it using its callback', done => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2);
new Popper(reference, popper, {
onCreate: data => {
data.instance.destroy();
expect(popper.style.top).toBe('');
done();
},
});
});
it('inits a popper with an empty form as parent, then auto remove it on destroy', done => {
const form = document.createElement('form');
const reference = appendNewRef(1, 'ref', form);
const popper = appendNewPopper(2, 'test', form);
jasmineWrapper.appendChild(form);
new Popper(reference, popper, {
removeOnDestroy: true,
onCreate: data => {
expect(data.instance.popper).toBeDefined();
expect(data.instance.popper.innerText.trim()).toBe('test');
data.instance.destroy();
expect(document.body.contains(data.instance.popper)).toBeFalsy();
done();
},
});
});
it('inits a popper with a not empty form as parent, then auto remove it on destroy', done => {
const form = document.createElement('form');
const input = document.createElement('input');
const popper = appendNewPopper(2, 'test', form);
form.appendChild(input);
const reference = appendNewRef(1, 'ref', form);
jasmineWrapper.appendChild(form);
new Popper(reference, popper, {
removeOnDestroy: true,
onCreate: data => {
expect(data.instance.popper).toBeDefined();
expect(data.instance.popper.innerText.trim()).toBe('test');
data.instance.destroy();
expect(document.body.contains(data.instance.popper)).toBeFalsy();
done();
},
});
});
it('inits a popper and make sure its position is correct on init', done => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2, 'popper');
new Popper(reference, popper, {
placement: 'right',
removeOnDestroy: true,
onCreate: data => {
expect(getRect(popper).left - arrowSize).toBeApprox(
getRect(reference).right
);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a scrolled body, with its reference element inside a scrolling div, wrapped in a relative div', done => {
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.height = '200vh';
relative.style.paddingTop = '100px';
relative.style.backgroundColor = 'yellow';
jasmineWrapper.appendChild(relative);
simulateScroll(document.body, { scrollTop: 100 });
const scrolling = document.createElement('div');
scrolling.style.width = '100%';
scrolling.style.height = '100vh';
scrolling.style.overflow = 'auto';
scrolling.style.backgroundColor = 'green';
relative.appendChild(scrolling);
const superHigh = document.createElement('div');
superHigh.style.width = '1px';
superHigh.style.float = 'right';
superHigh.style.height = '300vh';
scrolling.appendChild(superHigh);
simulateScroll(scrolling, { scrollTop: 100 });
const ref = appendNewRef(1, 'ref', scrolling);
ref.style.width = '100px';
ref.style.height = '100px';
ref.style.marginTop = '100px';
const popper = appendNewPopper(2, 'popper', scrolling);
new Popper(ref, popper, {
placement: 'right-start',
onCreate: data => {
expect(getRect(popper).top).toBeApprox(getRect(ref).top + 5); // 5 is the boundaries margin
expect(getRect(popper).left - arrowSize).toBeApprox(getRect(ref).right);
data.instance.destroy();
done();
},
});
});
it('inits a popper and its reference element inside of an offsetParent, which is inside of an offsetParent', done => {
const outterWrapper = document.createElement('div');
outterWrapper.style.position = 'relative';
outterWrapper.style.left = '90vw';
outterWrapper.style.backgroundColor = 'yellow';
jasmineWrapper.appendChild(outterWrapper);
const wrapper = document.createElement('div');
wrapper.style.position = 'relative';
wrapper.style.left = '5vw';
wrapper.style.backgroundColor = 'green';
outterWrapper.appendChild(wrapper);
const ref = appendNewRef(1, 'ref', wrapper);
ref.style.width = '100px';
ref.style.height = '100px';
ref.style.marginTop = '100px';
wrapper.appendChild(ref);
const popper = document.createElement('div');
popper.style.width = '100px';
popper.style.height = '100px';
wrapper.appendChild(popper);
new Popper(ref, popper, {
modifiers: {
preventOverflow: {
boundariesElement: 'viewport',
},
},
onCreate: data => {
expect(getRect(popper).right).toBeApprox(window.innerWidth - 5); // 5 is the boundaries margin
data.instance.destroy();
done();
},
});
});
it('inits a popper with boundariesElement set to viewport, the popper should not be in the viewport', done => {
if (isIPHONE) {
pending();
}
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.margin = '20px';
relative.style.paddingTop = '100px';
relative.style.backgroundColor = 'yellow';
jasmineWrapper.appendChild(relative);
simulateScroll(document.body, { scrollTop: 100 });
const ref = appendNewRef(1, 'ref', relative);
ref.style.width = '100px';
ref.style.height = '100px';
ref.style.marginTop = '2000px';
ref.style.marginBottom = '200px';
const popper = appendNewPopper(2, 'popper', relative);
new Popper(ref, popper, {
placement: 'bottom',
modifiers: {
flip: {
boundariesElement: 'viewport',
},
},
onCreate: () => {
expect(getRect(popper).bottom + arrowSize).toBeApprox(getRect(ref).top);
simulateScroll(document.body, { scrollTop: getRect(ref).top });
},
onUpdate: data => {
expect(getRect(popper).top - arrowSize).toBeApprox(getRect(ref).bottom);
data.instance.destroy();
done();
},
});
});
it('inits a popper with a custom modifier that should hide it', done => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2);
function hidePopper(data) {
data.styles.display = 'none';
return data;
}
new Popper(reference, popper, {
modifiers: {
hidePopper: { order: 790, enabled: true, fn: hidePopper },
},
onCreate: data => {
expect(popper.style.display).toBe('none');
data.instance.destroy();
done();
},
});
});
it('inits a popper with a custom modifier that set its top to 3px', done => {
const reference = appendNewRef(1);
const popper = appendNewPopper(2);
function movePopper(data) {
data.styles.top = '3px';
return data;
}
new Popper(reference, popper, {
modifiers: {
movePopper: { order: 690, enabled: true, fn: movePopper },
},
onCreate: data => {
expect(popper.style.top).toBe('3px');
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a Shadow DOM with its reference element inside DOM', done => {
if (!document.head.createShadowRoot) {
return done();
}
const reference = appendNewRef(1);
const shadowParent = document.createElement('div');
jasmineWrapper.appendChild(shadowParent);
const shadow = shadowParent.createShadowRoot();
const popper = appendNewPopper(2, 'popper', shadow);
new Popper(reference, popper, {
placement: 'right',
onCreate: data => {
expect(getRect(popper).left).toBeApprox(getRect(reference).right);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside DOM with its reference element inside Shadow DOM', done => {
if (!document.head.createShadowRoot) {
return done();
}
const shadowParent1 = document.createElement('div');
jasmineWrapper.appendChild(shadowParent1);
const shadow1 = shadowParent1.createShadowRoot();
const reference = appendNewRef(1, 'reference', shadow1);
reference.style.display = 'block';
reference.style.width = '100px';
const popper = appendNewPopper(2, 'popper');
new Popper(reference, popper, {
placement: 'right',
onCreate: data => {
expect(getRect(popper).left - arrowSize).toBeApprox(
getRect(reference).right
);
data.instance.destroy();
done();
},
});
});
it('inits a popper inside a Shadow DOM with its reference element inside different Shadow DOM', done => {
if (!document.head.createShadowRoot) {
return done();
}
const shadowParent1 = document.createElement('div');
jasmineWrapper.appendChild(shadowParent1);
const shadow1 = shadowParent1.createShadowRoot();
const reference = appendNewRef(1, 'reference', shadow1);
reference.style.display = 'block';
reference.style.width = '100px';
const shadowParent2 = document.createElement('div');
jasmineWrapper.appendChild(shadowParent2);
const shadow2 = shadowParent2.createShadowRoot();
const popper = appendNewPopper(2, 'popper', shadow2);
new Popper(reference, popper, {
placement: 'right',
onCreate: data => {
expect(getRect(popper).left).toBeApprox(getRect(reference).right);
data.instance.destroy();
done();
},
});
});
it('init a bottom-end popper near the right side of its container and make sure it stays between boundaries', done => {
const container = document.createElement('div');
container.style.width = '800px';
container.style.height = '600px';
container.style.background = 'grey';
container.style.position = 'relative';
container.style.overflow = 'scroll';
const scroller = document.createElement('div');
scroller.style.width = '2000px';
scroller.style.height = '1px';
const button = document.createElement('div');
button.style.width = '20px';
button.style.height = '50px';
button.style.position = 'absolute';
button.style.top = 0;
button.style.right = 0;
button.style.background = 'green';
const dropdown = document.createElement('div');
dropdown.style.background = 'yellow';
dropdown.style.position = 'absolute';
dropdown.style.height = '200px';
dropdown.style.width = '150px';
container.appendChild(button);
container.appendChild(dropdown);
container.appendChild(scroller);
jasmineWrapper.appendChild(container);
const scrollLeft = 50;
new Popper(button, dropdown, {
placement: 'bottom-end',
onCreate: () => {
expect(getRect(dropdown).right).toBeApprox(
getRect(container).right - 5
);
container.scrollLeft = scrollLeft;
},
onUpdate: data => {
expect(getRect(dropdown).right).toBeApprox(
getRect(container).right - scrollLeft
);
data.instance.destroy();
done();
},
});
});
it('init a bottom-start popper near the right side of its container and make sure it stays between boundaries', done => {
const container = document.createElement('div');
container.style.width = '800px';
container.style.height = '600px';
container.style.background = 'grey';
container.style.position = 'relative';
container.style.overflow = 'scroll';
const scroller = document.createElement('div');
scroller.style.width = '2000px';
scroller.style.height = '1px';
const button = document.createElement('div');
button.style.width = '20px';
button.style.height = '50px';
button.style.position = 'absolute';
button.style.top = 0;
button.style.right = 0;
button.style.background = 'green';
const dropdown = document.createElement('div');
dropdown.style.background = 'yellow';
dropdown.style.position = 'absolute';
dropdown.style.height = '200px';
dropdown.style.width = '150px';
container.appendChild(button);
container.appendChild(dropdown);
container.appendChild(scroller);
jasmineWrapper.appendChild(container);
const scrollLeft = 50;
new Popper(button, dropdown, {
placement: 'bottom-start',
modifiers: {
//preventOverflow: { enabled: false },
//flip: { enabled: false },
},
onCreate: () => {
expect(getRect(dropdown).right).toBeApprox(
getRect(container).right - 5
);
container.scrollLeft = scrollLeft;
},
onUpdate: data => {
expect(getRect(dropdown).right).toBeApprox(
getRect(container).right - 5
);
data.instance.destroy();
done();
},
});
});
it('init a popper near the right side of its container and make sure it stays between custom boundaries', done => {
const container = document.createElement('div');
container.style.width = '800px';
container.style.height = '600px';
container.style.background = 'grey';
container.style.position = 'relative';
container.style.overflow = 'scroll';
const scroller = document.createElement('div');
scroller.style.width = '2000px';
scroller.style.height = '1px';
const button = document.createElement('div');
button.style.width = '20px';
button.style.height = '50px';
button.style.position = 'absolute';
button.style.top = 0;
button.style.right = 0;
button.style.background = 'green';
const dropdown = document.createElement('div');
dropdown.style.background = 'yellow';
dropdown.style.position = 'absolute';
dropdown.style.height = '200px';
dropdown.style.width = '150px';
container.appendChild(button);
container.appendChild(dropdown);
container.appendChild(scroller);
jasmineWrapper.appendChild(container);
const scrollLeft = 50;
new Popper(button, dropdown, {
placement: 'bottom-end',
modifiers: {
preventOverflow: { boundariesElement: container },
},
onCreate: () => {
expect(getRect(dropdown).right).toBeApprox(
getRect(container).right - 5
);
container.scrollLeft = scrollLeft;
},
onUpdate: data => {
expect(getRect(dropdown).right).toBeApprox(
getRect(container).right - scrollLeft
);
data.instance.destroy();
done();
},
});
});
it('init a popper near the right side of a custom container and make sure it stays between boundaries', done => {
const container = document.createElement('div');
container.style.width = '800px';
container.style.height = '600px';
container.style.background = 'grey';
container.style.position = 'relative';
container.style.overflow = 'scroll';
const scroller = document.createElement('div');
scroller.style.width = '2000px';
scroller.style.height = '1px';
const button = document.createElement('div');
button.style.width = '20px';
button.style.height = '50px';
button.style.position = 'absolute';
button.style.top = 0;
button.style.right = 0;
button.style.background = 'green';
const dropdown = document.createElement('div');
dropdown.style.background = 'yellow';
dropdown.style.position = 'absolute';
dropdown.style.height = '200px';
dropdown.style.width = '150px';
container.appendChild(button);
container.appendChild(scroller);
jasmineWrapper.appendChild(container);
jasmineWrapper.appendChild(dropdown);
const scrollLeft = 50;
new Popper(button, dropdown, {
placement: 'bottom-end',
modifiers: {
preventOverflow: { boundariesElement: container },
},
onCreate: () => {
expect(getRect(dropdown).right).toBe(getRect(container).right - 5);
container.scrollLeft = scrollLeft;
},
onUpdate: data => {
expect(getRect(dropdown).right).toBe(
getRect(container).right - scrollLeft
);
data.instance.destroy();
done();
},
});
});
it('inits a popper near the left side of a custom absolute container contained in a relative parent', done => {
const parent = document.createElement('div');
parent.style.width = '600px';
parent.style.height = '300px';
parent.style.top = '50px';
parent.style.left = '80px';
parent.style.background = 'grey';
parent.style.position = 'relative';
parent.style.overflow = 'scroll';
const container = document.createElement('div');
container.style.top = 0;
container.style.right = 0;
container.style.bottom = 0;
container.style.left = 0;
container.style.position = 'absolute';
const button = document.createElement('div');
button.style.width = '20px';
button.style.height = '50px';
button.style.position = 'absolute';
button.style.top = 0;
button.style.left = 0;
button.style.background = 'green';
const dropdown = document.createElement('div');
dropdown.style.background = 'yellow';
dropdown.style.position = 'absolute';
dropdown.style.height = '200px';
dropdown.style.width = '150px';
container.appendChild(button);
parent.appendChild(container);
jasmineWrapper.appendChild(parent);
jasmineWrapper.appendChild(dropdown);
new Popper(button, dropdown, {
placement: 'bottom-end',
modifiers: {
preventOverflow: { boundariesElement: container },
},
onCreate: data => {
expect(getRect(dropdown).left).toBe(getRect(container).left + 5);
data.instance.destroy();
done();
},
});
});
it('inits a popper near a reference element, both inside an element with CSS translateX', done => {
const fixed = document.createElement('div');
fixed.style.position = 'fixed';
fixed.style.left = '50%';
fixed.style.top = '20px';
fixed.style.transform = 'translateX(0)';
fixed.style.background = 'green';
jasmineWrapper.appendChild(fixed);
const popper = appendNewPopper(2, 'popper', fixed);
const ref = appendNewRef(1, 'ref', fixed);
new Popper(ref, popper, {
placement: 'bottom-end',
onCreate: data => {
expect(getRect(popper).right).toBeApprox(getRect(ref).right);
data.instance.destroy();
done();
},
});
});
it('inits a popper near the reference element when it is a child of ref and a parent is relatively positioned', done => {
const relative = document.createElement('div');
relative.style.position = 'relative';
relative.style.left = '50%';
relative.style.top = '20px';
relative.style.background = 'green';
jasmineWrapper.appendChild(relative);
const ref = appendNewRef(1, 'ref', relative);
const popper = appendNewPopper(2, 'popper', ref);
new Popper(ref, popper, {
placement: 'bottom-end',
onCreate: data => {
expect(getRect(popper).right).toBeApprox(getRect(ref).right);
data.instance.destroy();
done();
},
});
});
it('inits a popper near the reference element when it is a child of ref and the ref is relatively positioned', done => {
const ref = appendNewRef(1, 'ref');
ref.style.position = 'relative';
ref.style.left = '300px';
ref.style.top = '20px';
ref.style.background = 'green';
const popper = appendNewPopper(2, 'popper', ref);
new Popper(ref, popper, {
placement: 'bottom-end',
onCreate: data => {
expect(getRect(popper).right).toBeApprox(getRect(ref).right);
data.instance.destroy();
done();
},
});
});
it('checks that all the scrollable parents have an event listener attached', done => {
jasmineWrapper.innerHTML = `
popper
`;
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
const s1 = document.getElementById('s1');
const s2 = document.getElementById('s2');
new Popper(reference, popper, {
onCreate() {
simulateScroll(s1, { scrollTop: 50 });
simulateScroll(s2, { scrollTop: 50 });
},
onUpdate(data) {
expect(getRect(reference).bottom).toBeApprox(getRect(popper).top);
data.instance.destroy();
done();
},
});
});
it('uses an object instead of the reference element to position its popper', done => {
// Skip IE10 here because the current implementation doesn't work with it and
// I don't want to add extra logic to support a "nice to have" feature on an
// ancient browser
if (isIE10) {
pending();
}
jasmineWrapper.innerHTML = `
popper
`;
const popper = document.getElementById('popper');
const reference = {
getBoundingClientRect() {
return {
top: 10,
left: 100,
right: 150,
bottom: 90,
width: 50,
height: 80,
};
},
clientWidth: 50,
clientHeight: 80,
};
new Popper(reference, popper, {
placement: 'bottom-start',
onCreate() {
expect(getRect(popper).top).toBe(
reference.getBoundingClientRect().bottom
);
expect(getRect(popper).left).toBe(
reference.getBoundingClientRect().left
);
done();
},
});
});
// test for #224
it('checks that only the needed parents scroll offsets are included', done => {
jasmineWrapper.innerHTML = `
spacer
popper
`;
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
const s1 = document.getElementById('s1');
new Popper(reference, popper, {
onCreate() {
simulateScroll(s1, { scrollTop: 20 });
simulateScroll(document.body, { scrollTop: 50 });
},
onUpdate(data) {
expect(getRect(reference).bottom).toBeApprox(getRect(popper).top);
data.instance.destroy();
done();
},
});
});
// test for #310
it('properly avoids overflow when parent is transformed', done => {
jasmineWrapper.innerHTML = `
`;
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
new Popper(reference, popper, {
placement: 'bottom',
onCreate(data) {
expect(getRect(reference).bottom).toBeApprox(getRect(popper).top);
expect(getRect(popper).left).toBeApprox(5);
data.instance.destroy();
done();
},
});
});
// test for #305
it('correct position if offset parent has borders', done => {
jasmineWrapper.innerHTML = `
`;
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
new Popper(reference, popper, {
placement: 'bottom',
onCreate(data) {
expect(getRect(reference).bottom).toBeApprox(getRect(popper).top);
expect(getRect(reference).left).toBeApprox(getRect(popper).left);
data.instance.destroy();
done();
},
});
});
// Test for #253
xit('sticky parent', done => {
// MS Browsers (IE and Edge) don't support Sticky position
if (isMSBrowser()) {
pending();
}
jasmineWrapper.innerHTML = `
`;
const s1 = document.getElementById('s1');
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
simulateScroll(s1, { scrollTop: 100 });
new Popper(reference, popper, {
onCreate(data) {
expect(getRect(reference).bottom).toBeApprox(getRect(popper).top);
data.instance.destroy();
done();
},
});
});
// test for #302
it(
'correct position on height:100% scrolled body with fixed popper parent',
done => {
jasmineWrapper.innerHTML = `
`;
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
new Popper(reference, popper, {
placement: 'top',
onCreate() {
simulateScroll(document.body, { scrollTop: 400, delay: 100 });
},
onUpdate(data) {
expect(getRect(reference).top).toBeApprox(getRect(popper).bottom);
data.instance.destroy();
done();
},
});
}
);
// test for #276
it('works inside tables', done => {
jasmineWrapper.innerHTML = `
`;
const reference = document.getElementById('reference');
const popper = document.getElementById('popper');
new Popper(reference, popper, {
placement: 'bottom',
onCreate(data) {
expect(getRect(reference).bottom).toBeApprox(getRect(popper).top);
expect(getRect(reference).left).toBeApprox(getRect(popper).left);
data.instance.destroy();
done();
},
});
});
});