2016-08-03 21:27:03 +02:00
/* eslint-env qunit */
2015-05-04 01:12:38 +02:00
import document from 'global/document' ;
2017-01-19 22:30:47 +02:00
import sinon from 'sinon' ;
2015-05-04 01:12:38 +02:00
import * as Dom from '../../../src/js/utils/dom.js' ;
2019-07-29 23:45:40 +02:00
import TestHelpers from '../test-helpers.js' ;
2015-05-04 01:12:38 +02:00
2022-05-23 22:23:13 +02:00
QUnit . module ( 'utils/dom' ) ;
2015-08-03 21:19:36 +02:00
2016-08-12 19:51:31 +02:00
QUnit . test ( 'should create an element' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const div = Dom . createEl ( ) ;
const span = Dom . createEl ( 'span' , {
2015-09-15 19:57:55 +02:00
innerHTML : 'fdsa'
} , {
'data-test' : 'asdf'
} ) ;
2016-11-04 19:45:51 +02:00
assert . strictEqual ( div . nodeName , 'DIV' ) ;
assert . strictEqual ( span . nodeName , 'SPAN' ) ;
assert . strictEqual ( span . getAttribute ( 'data-test' ) , 'asdf' ) ;
assert . strictEqual ( span . innerHTML , 'fdsa' ) ;
} ) ;
QUnit . test ( 'should create an element, supporting textContent' , function ( assert ) {
const span = Dom . createEl ( 'span' , { textContent : 'howdy' } ) ;
if ( span . textContent ) {
assert . strictEqual ( span . textContent , 'howdy' , 'works in browsers that support textContent' ) ;
} else {
assert . strictEqual ( span . innerText , 'howdy' , 'works in browsers that DO NOT support textContent' ) ;
}
} ) ;
2022-07-28 22:44:53 +02:00
QUnit . test ( 'should create an element with tabIndex prop' , function ( assert ) {
const span = Dom . createEl ( 'span' , { tabIndex : '5' } ) ;
assert . strictEqual ( span . tabIndex , 5 ) ;
} ) ;
2016-11-04 19:45:51 +02:00
QUnit . test ( 'should create an element with content' , function ( assert ) {
const span = Dom . createEl ( 'span' ) ;
const div = Dom . createEl ( 'div' , undefined , undefined , span ) ;
assert . strictEqual ( div . firstChild , span ) ;
2015-05-04 01:12:38 +02:00
} ) ;
2022-07-28 22:44:53 +02:00
QUnit . test ( 'should be able to set standard props as attributes, and vice versa, on a created element' , function ( assert ) {
const span = Dom . createEl ( 'span' , { className : 'bar' } , { id : 'foo' } ) ;
assert . strictEqual ( span . getAttribute ( 'class' ) , 'bar' ) ;
assert . strictEqual ( span . id , 'foo' ) ;
} ) ;
2016-08-12 19:51:31 +02:00
QUnit . test ( 'should insert an element first in another' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const el1 = document . createElement ( 'div' ) ;
const el2 = document . createElement ( 'div' ) ;
const parent = document . createElement ( 'div' ) ;
2015-05-04 01:12:38 +02:00
2017-01-19 23:01:56 +02:00
Dom . prependTo ( el1 , parent ) ;
2016-11-04 19:45:51 +02:00
assert . strictEqual ( parent . firstChild , el1 , 'inserts first into empty parent' ) ;
2015-05-04 01:12:38 +02:00
2017-01-19 23:01:56 +02:00
Dom . prependTo ( el2 , parent ) ;
2016-11-04 19:45:51 +02:00
assert . strictEqual ( parent . firstChild , el2 , 'inserts first into parent with child' ) ;
2015-05-04 01:12:38 +02:00
} ) ;
2017-01-19 23:01:56 +02:00
QUnit . test ( 'addClass()' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const el = document . createElement ( 'div' ) ;
2015-11-10 00:43:17 +02:00
2022-08-08 17:14:06 +02:00
assert . expect ( 6 ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . addClass ( el , 'test-class' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'test-class' , 'adds a single class' ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . addClass ( el , 'test-class' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'test-class' , 'does not duplicate classes' ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . addClass ( el , 'test2_className' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'test-class test2_className' , 'adds second class' ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . addClass ( el , 'FOO' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'test-class test2_className FOO' , 'adds third class' ) ;
2022-08-08 17:14:06 +02:00
Dom . addClass ( el , 'left-class' , 'right-class' ) ;
assert . strictEqual ( el . className , 'test-class test2_className FOO left-class right-class' , 'adds two classes' ) ;
Dom . addClass ( el , 'l-class r-class' ) ;
assert . strictEqual (
el . className ,
'test-class test2_className FOO left-class right-class l-class r-class' ,
'adds two classes via one string'
) ;
2015-11-10 00:43:17 +02:00
} ) ;
2017-01-19 23:01:56 +02:00
QUnit . test ( 'removeClass()' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const el = document . createElement ( 'div' ) ;
2015-11-10 00:43:17 +02:00
2016-11-09 23:06:38 +02:00
el . className = 'test-class test2_className FOO bar' ;
2015-11-10 00:43:17 +02:00
2022-08-08 17:14:06 +02:00
assert . expect ( 5 ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . removeClass ( el , 'test-class' ) ;
2016-11-09 23:06:38 +02:00
assert . strictEqual ( el . className , 'test2_className FOO bar' , 'removes one class' ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . removeClass ( el , 'test2_className' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'FOO bar' , 'removes another class' ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . removeClass ( el , 'FOO' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'bar' , 'removes another class' ) ;
2022-08-08 17:14:06 +02:00
el . className = 'bar left-class right-class' ;
Dom . removeClass ( el , 'left-class' , 'right-class' ) ;
assert . strictEqual ( el . className , 'bar' , 'removes two classes' ) ;
el . className = 'bar l-class r-class' ;
Dom . removeClass ( el , 'l-class r-class' ) ;
assert . strictEqual ( el . className , 'bar' , 'removes two classes via one string' ) ;
2015-05-04 01:12:38 +02:00
} ) ;
2017-01-19 23:01:56 +02:00
QUnit . test ( 'hasClass()' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const el = document . createElement ( 'div' ) ;
2015-11-10 00:43:17 +02:00
el . className = 'test-class foo foo test2_className FOO bar' ;
2017-01-19 23:01:56 +02:00
assert . strictEqual ( Dom . hasClass ( el , 'test-class' ) , true , 'class detected' ) ;
assert . strictEqual ( Dom . hasClass ( el , 'foo' ) , true , 'class detected' ) ;
assert . strictEqual ( Dom . hasClass ( el , 'test2_className' ) , true , 'class detected' ) ;
assert . strictEqual ( Dom . hasClass ( el , 'FOO' ) , true , 'class detected' ) ;
assert . strictEqual ( Dom . hasClass ( el , 'bar' ) , true , 'class detected' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
Dom . hasClass ( el , 'test2' ) ,
false ,
'valid substring - but not a class - correctly not detected'
) ;
assert . strictEqual (
Dom . hasClass ( el , 'className' ) ,
false ,
'valid substring - but not a class - correctly not detected'
) ;
2016-08-03 21:27:03 +02:00
2016-08-12 19:51:31 +02:00
assert . throws ( function ( ) {
2017-01-19 23:01:56 +02:00
Dom . hasClass ( el , 'FOO bar' ) ;
2015-11-10 00:43:17 +02:00
} , 'throws when attempting to detect a class with whitespace' ) ;
} ) ;
2017-01-19 23:01:56 +02:00
QUnit . test ( 'toggleClass()' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const el = Dom . createEl ( 'div' , { className : 'foo bar' } ) ;
2015-11-10 00:43:17 +02:00
2016-08-03 21:27:03 +02:00
const predicateToggles = [
2015-11-10 00:43:17 +02:00
{
toggle : 'foo' ,
predicate : true ,
className : 'foo bar' ,
message : 'if predicate `true` matches state of the element, do nothing'
} ,
{
toggle : 'baz' ,
predicate : false ,
className : 'foo bar' ,
message : 'if predicate `false` matches state of the element, do nothing'
} ,
{
toggle : 'baz' ,
predicate : true ,
className : 'foo bar baz' ,
message : 'if predicate `true` differs from state of the element, add the class'
} ,
{
toggle : 'foo' ,
predicate : false ,
className : 'bar baz' ,
message : 'if predicate `false` differs from state of the element, remove the class'
} ,
{
toggle : 'bar' ,
predicate : ( ) => true ,
className : 'bar baz' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns `true`, ' +
'matching the state of the element, do nothing'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'foo' ,
predicate : ( ) => false ,
className : 'bar baz' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns `false`, matching ' +
'the state of the element, do nothing'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'foo' ,
predicate : ( ) => true ,
className : 'bar baz foo' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns `true`, ' +
'differing from state of the element, add the class'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'foo' ,
predicate : ( ) => false ,
className : 'bar baz' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns `false`, differing ' +
'from state of the element, remove the class'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'foo' ,
predicate : Function . prototype ,
className : 'bar baz foo' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns `undefined` and ' +
'the element does not have the class, add the class'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'bar' ,
predicate : Function . prototype ,
className : 'baz foo' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns `undefined` and the ' +
'element has the class, remove the class'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'bar' ,
predicate : ( ) => [ ] ,
className : 'baz foo bar' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns a defined non-boolean ' +
'value and the element does not have the class, add the class'
2015-11-10 00:43:17 +02:00
} ,
{
toggle : 'baz' ,
predicate : ( ) => 'this is incorrect' ,
className : 'foo bar' ,
2016-08-03 21:27:03 +02:00
message : 'if a predicate function returns a defined non-boolean value ' +
'and the element has the class, remove the class'
}
2015-11-10 00:43:17 +02:00
] ;
2022-08-08 17:14:06 +02:00
assert . expect ( 4 + predicateToggles . length ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . toggleClass ( el , 'bar' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'foo' , 'toggles a class off, if present' ) ;
2015-11-10 00:43:17 +02:00
2017-01-19 23:01:56 +02:00
Dom . toggleClass ( el , 'bar' ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , 'foo bar' , 'toggles a class on, if absent' ) ;
2015-11-10 00:43:17 +02:00
2022-08-08 17:14:06 +02:00
Dom . toggleClass ( el , 'bla ok' ) ;
assert . strictEqual ( el . className , 'foo bar bla ok' , 'toggles a classes on, if absent' ) ;
Dom . toggleClass ( el , 'bla ok' ) ;
assert . strictEqual ( el . className , 'foo bar' , 'toggles a classes off, if present' ) ;
2015-11-10 00:43:17 +02:00
predicateToggles . forEach ( x => {
2017-01-19 23:01:56 +02:00
Dom . toggleClass ( el , x . toggle , x . predicate ) ;
2016-08-12 19:51:31 +02:00
assert . strictEqual ( el . className , x . className , x . message ) ;
2015-11-10 00:43:17 +02:00
} ) ;
2015-05-04 01:12:38 +02:00
} ) ;
2016-08-12 19:51:31 +02:00
QUnit . test ( 'should set element attributes from object' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const el = document . createElement ( 'div' ) ;
2015-05-04 01:12:38 +02:00
el . id = 'el1' ;
2017-01-19 23:01:56 +02:00
Dom . setAttributes ( el , { 'controls' : true , 'data-test' : 'asdf' } ) ;
2015-05-04 01:12:38 +02:00
2016-08-12 19:51:31 +02:00
assert . equal ( el . getAttribute ( 'id' ) , 'el1' ) ;
assert . equal ( el . getAttribute ( 'controls' ) , '' ) ;
assert . equal ( el . getAttribute ( 'data-test' ) , 'asdf' ) ;
2015-05-04 01:12:38 +02:00
} ) ;
2016-08-12 19:51:31 +02:00
QUnit . test ( 'should read tag attributes from elements, including HTML5 in all browsers' , function ( assert ) {
2015-08-25 02:46:54 +02:00
// Creating the source/track tags outside of the video tag prevents log errors
2016-08-03 21:27:03 +02:00
const tags = `
2015-09-01 02:17:26 +02:00
< video id = "vid1" controls autoplay loop muted preload = "none" src = "http://google.com" poster = "http://www2.videojs.com/img/video-js-html5-video-player.png" data - test = "asdf" data - empty - string = "" >
< source id = "source" src = "http://google.com" type = "video/mp4" media = "fdsa" title = "test" >
< / v i d e o >
2015-08-25 02:46:54 +02:00
< track id = "track" default src = "http://google.com" kind = "captions" srclang = "en" label = "testlabel" title = "test" >
` ;
2015-05-04 01:12:38 +02:00
2016-08-03 21:27:03 +02:00
const fixture = document . getElementById ( 'qunit-fixture' ) ;
2015-08-25 02:46:54 +02:00
// Have to use innerHTML to append for IE8. AppendChild doesn't work.
// Also it must be added to the page body, not just in memory.
fixture . innerHTML += tags ;
2017-01-19 23:01:56 +02:00
const vid1Vals = Dom . getAttributes ( fixture . getElementsByTagName ( 'video' ) [ 0 ] ) ;
const sourceVals = Dom . getAttributes ( fixture . getElementsByTagName ( 'source' ) [ 0 ] ) ;
const trackVals = Dom . getAttributes ( fixture . getElementsByTagName ( 'track' ) [ 0 ] ) ;
2015-05-04 01:12:38 +02:00
// vid1
2015-08-25 02:46:54 +02:00
// was using deepEqual, but ie8 would send all properties as attributes
2016-08-12 19:51:31 +02:00
assert . equal ( vid1Vals . autoplay , true ) ;
assert . equal ( vid1Vals . controls , true ) ;
assert . equal ( vid1Vals [ 'data-test' ] , 'asdf' ) ;
assert . equal ( vid1Vals [ 'data-empty-string' ] , '' ) ;
assert . equal ( vid1Vals . id , 'vid1' ) ;
assert . equal ( vid1Vals . loop , true ) ;
assert . equal ( vid1Vals . muted , true ) ;
assert . equal ( vid1Vals . poster , 'http://www2.videojs.com/img/video-js-html5-video-player.png' ) ;
assert . equal ( vid1Vals . preload , 'none' ) ;
assert . equal ( vid1Vals . src , 'http://google.com' ) ;
2015-05-04 01:12:38 +02:00
// sourceVals
2016-08-12 19:51:31 +02:00
assert . equal ( sourceVals . title , 'test' ) ;
assert . equal ( sourceVals . media , 'fdsa' ) ;
assert . equal ( sourceVals . type , 'video/mp4' ) ;
assert . equal ( sourceVals . src , 'http://google.com' ) ;
assert . equal ( sourceVals . id , 'source' ) ;
2015-05-04 01:12:38 +02:00
// trackVals
2016-08-12 19:51:31 +02:00
assert . equal ( trackVals . default , true ) ;
assert . equal ( trackVals . id , 'track' ) ;
assert . equal ( trackVals . kind , 'captions' ) ;
assert . equal ( trackVals . label , 'testlabel' ) ;
assert . equal ( trackVals . src , 'http://google.com' ) ;
assert . equal ( trackVals . srclang , 'en' ) ;
assert . equal ( trackVals . title , 'test' ) ;
2015-05-04 01:12:38 +02:00
} ) ;
2017-01-19 23:01:56 +02:00
QUnit . test ( 'Dom.findPosition should find top and left position' , function ( assert ) {
2015-05-04 01:12:38 +02:00
const d = document . createElement ( 'div' ) ;
2017-01-19 23:01:56 +02:00
let position = Dom . findPosition ( d ) ;
2016-08-03 21:27:03 +02:00
2020-08-31 18:29:25 +02:00
d . style . width = '100px' ;
d . style . height = '50px' ;
2015-05-04 01:12:38 +02:00
d . style . top = '10px' ;
d . style . left = '20px' ;
d . style . position = 'absolute' ;
2018-09-28 20:58:15 +02:00
assert . deepEqual (
position ,
2020-08-31 18:29:25 +02:00
{ left : 0 , top : 0 , width : 0 , height : 0 } ,
2018-09-28 20:58:15 +02:00
'If element isn\'t in the DOM, we should get zeros'
) ;
2015-05-04 01:12:38 +02:00
document . body . appendChild ( d ) ;
2017-01-19 23:01:56 +02:00
position = Dom . findPosition ( d ) ;
2020-08-31 18:29:25 +02:00
assert . deepEqual ( position . left , 20 , 'The position left was not correct' ) ;
assert . deepEqual ( position . top , 10 , 'The position top was not correct' ) ;
assert . deepEqual ( position . width , 100 , 'The dimension width was not correct' ) ;
assert . deepEqual ( position . height , 50 , 'The dimension height was not correct' ) ;
2015-05-04 01:12:38 +02:00
2020-08-31 18:29:25 +02:00
d . style . display = 'none' ;
2017-01-19 23:01:56 +02:00
position = Dom . findPosition ( d ) ;
2018-09-28 20:58:15 +02:00
assert . deepEqual (
position ,
2020-08-31 18:29:25 +02:00
{ left : 0 , top : 0 , width : 0 , height : 0 } ,
'If there is no offsetParent, we should get zeros'
2018-09-28 20:58:15 +02:00
) ;
2015-05-04 01:12:38 +02:00
} ) ;
2015-10-28 19:28:15 +02:00
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.isEl' , function ( assert ) {
2015-10-28 19:28:15 +02:00
assert . expect ( 7 ) ;
assert . notOk ( Dom . isEl ( ) , 'undefined is not an element' ) ;
assert . notOk ( Dom . isEl ( true ) , 'booleans are not elements' ) ;
assert . notOk ( Dom . isEl ( { } ) , 'objects are not elements' ) ;
assert . notOk ( Dom . isEl ( [ ] ) , 'arrays are not elements' ) ;
assert . notOk ( Dom . isEl ( '<h1></h1>' ) , 'strings are not elements' ) ;
assert . ok ( Dom . isEl ( document . createElement ( 'div' ) ) , 'elements are elements' ) ;
assert . ok ( Dom . isEl ( { nodeType : 1 } ) , 'duck typing is imperfect' ) ;
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.isTextNode' , function ( assert ) {
2015-10-28 19:28:15 +02:00
assert . expect ( 7 ) ;
assert . notOk ( Dom . isTextNode ( ) , 'undefined is not a text node' ) ;
assert . notOk ( Dom . isTextNode ( true ) , 'booleans are not text nodes' ) ;
assert . notOk ( Dom . isTextNode ( { } ) , 'objects are not text nodes' ) ;
assert . notOk ( Dom . isTextNode ( [ ] ) , 'arrays are not text nodes' ) ;
assert . notOk ( Dom . isTextNode ( 'hola mundo' ) , 'strings are not text nodes' ) ;
2018-09-28 20:58:15 +02:00
assert . ok (
Dom . isTextNode ( document . createTextNode ( 'hello, world!' ) ) ,
'text nodes are text nodes'
) ;
2015-10-28 19:28:15 +02:00
assert . ok ( Dom . isTextNode ( { nodeType : 3 } ) , 'duck typing is imperfect' ) ;
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.emptyEl' , function ( assert ) {
const el = Dom . createEl ( ) ;
2015-10-28 19:28:15 +02:00
el . appendChild ( Dom . createEl ( 'span' ) ) ;
el . appendChild ( Dom . createEl ( 'span' ) ) ;
el . appendChild ( document . createTextNode ( 'hola mundo' ) ) ;
el . appendChild ( Dom . createEl ( 'span' ) ) ;
Dom . emptyEl ( el ) ;
assert . expect ( 1 ) ;
assert . notOk ( el . firstChild , 'the element was emptied' ) ;
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.normalizeContent: strings and elements/nodes' , function ( assert ) {
2015-10-28 19:28:15 +02:00
assert . expect ( 8 ) ;
2016-08-03 21:27:03 +02:00
const str = Dom . normalizeContent ( 'hello' ) ;
2015-10-28 19:28:15 +02:00
assert . strictEqual ( str [ 0 ] . data , 'hello' , 'single string becomes a text node' ) ;
2016-08-03 21:27:03 +02:00
const elem = Dom . normalizeContent ( Dom . createEl ( ) ) ;
2015-10-28 19:28:15 +02:00
assert . ok ( Dom . isEl ( elem [ 0 ] ) , 'an element is passed through' ) ;
2016-08-03 21:27:03 +02:00
const node = Dom . normalizeContent ( document . createTextNode ( 'goodbye' ) ) ;
2015-10-28 19:28:15 +02:00
assert . strictEqual ( node [ 0 ] . data , 'goodbye' , 'a text node is passed through' ) ;
assert . strictEqual ( Dom . normalizeContent ( null ) . length , 0 , 'falsy values are ignored' ) ;
assert . strictEqual ( Dom . normalizeContent ( false ) . length , 0 , 'falsy values are ignored' ) ;
assert . strictEqual ( Dom . normalizeContent ( ) . length , 0 , 'falsy values are ignored' ) ;
assert . strictEqual ( Dom . normalizeContent ( 123 ) . length , 0 , 'numbers are ignored' ) ;
assert . strictEqual ( Dom . normalizeContent ( { } ) . length , 0 , 'objects are ignored' ) ;
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.normalizeContent: functions returning strings and elements/nodes' , function ( assert ) {
2015-10-28 19:28:15 +02:00
assert . expect ( 9 ) ;
2016-08-03 21:27:03 +02:00
const str = Dom . normalizeContent ( ( ) => 'hello' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
str [ 0 ] . data ,
'hello' ,
'a function can return a string, which becomes a text node'
) ;
2016-08-03 21:27:03 +02:00
const elem = Dom . normalizeContent ( ( ) => Dom . createEl ( ) ) ;
2015-10-28 19:28:15 +02:00
assert . ok ( Dom . isEl ( elem [ 0 ] ) , 'a function can return an element' ) ;
2016-08-03 21:27:03 +02:00
const node = Dom . normalizeContent ( ( ) => document . createTextNode ( 'goodbye' ) ) ;
2015-10-28 19:28:15 +02:00
assert . strictEqual ( node [ 0 ] . data , 'goodbye' , 'a function can return a text node' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
Dom . normalizeContent ( ( ) => null ) . length ,
0 ,
'a function CANNOT return falsy values'
) ;
assert . strictEqual (
Dom . normalizeContent ( ( ) => false ) . length ,
0 ,
'a function CANNOT return falsy values'
) ;
assert . strictEqual (
Dom . normalizeContent ( ( ) => undefined ) . length ,
0 ,
'a function CANNOT return falsy values'
) ;
assert . strictEqual (
Dom . normalizeContent ( ( ) => 123 ) . length ,
0 ,
'a function CANNOT return numbers'
) ;
assert . strictEqual (
Dom . normalizeContent ( ( ) => { } ) . length ,
0 ,
'a function CANNOT return objects'
) ;
assert . strictEqual (
Dom . normalizeContent ( ( ) => ( ( ) => null ) ) . length ,
0 ,
'a function CANNOT return a function'
) ;
2015-10-28 19:28:15 +02:00
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.normalizeContent: arrays of strings and objects' , function ( assert ) {
2015-10-28 19:28:15 +02:00
assert . expect ( 7 ) ;
2016-08-03 21:27:03 +02:00
const source = [
2015-10-28 19:28:15 +02:00
'hello' ,
{ } ,
Dom . createEl ( ) ,
[ 'oops' ] ,
null ,
document . createTextNode ( 'goodbye' ) ,
( ) => 'it works'
] ;
2016-08-03 21:27:03 +02:00
const result = Dom . normalizeContent ( source ) ;
2015-10-28 19:28:15 +02:00
2018-09-28 20:58:15 +02:00
assert . strictEqual (
result [ 0 ] . data ,
'hello' ,
'an array can include a string normalized to a text node'
) ;
2015-10-28 19:28:15 +02:00
assert . ok ( Dom . isEl ( result [ 1 ] ) , 'an array can include an element' ) ;
assert . strictEqual ( result [ 2 ] . data , 'goodbye' , 'an array can include a text node' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
result [ 3 ] . data ,
'it works' ,
'an array can include a function, which is invoked'
) ;
2015-10-28 19:28:15 +02:00
assert . strictEqual ( result . indexOf ( source [ 1 ] ) , - 1 , 'an array CANNOT include an object' ) ;
assert . strictEqual ( result . indexOf ( source [ 3 ] ) , - 1 , 'an array CANNOT include an array' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
result . indexOf ( source [ 4 ] ) ,
- 1 ,
'an array CANNOT include falsy values'
) ;
2015-10-28 19:28:15 +02:00
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.normalizeContent: functions returning arrays' , function ( assert ) {
2015-10-28 19:28:15 +02:00
assert . expect ( 3 ) ;
2016-08-03 21:27:03 +02:00
const arr = [ ] ;
const result = Dom . normalizeContent ( ( ) => [ 'hello' , Function . prototype , arr ] ) ;
2015-10-28 19:28:15 +02:00
assert . strictEqual ( result [ 0 ] . data , 'hello' , 'a function can return an array' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
result . indexOf ( Function . prototype ) ,
- 1 ,
'a function can return an array, but it CANNOT include a function'
) ;
assert . strictEqual (
result . indexOf ( arr ) ,
- 1 ,
'a function can return an array, but it CANNOT include an array'
) ;
2015-10-28 19:28:15 +02:00
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.insertContent' , function ( assert ) {
const p = Dom . createEl ( 'p' ) ;
const text = document . createTextNode ( 'hello' ) ;
const el = Dom . insertContent ( Dom . createEl ( ) , [ p , text ] ) ;
2015-10-28 19:28:15 +02:00
assert . expect ( 2 ) ;
assert . strictEqual ( el . firstChild , p , 'the paragraph was inserted first' ) ;
assert . strictEqual ( el . firstChild . nextSibling , text , 'the text node was inserted last' ) ;
} ) ;
2016-08-03 21:27:03 +02:00
QUnit . test ( 'Dom.appendContent' , function ( assert ) {
const p1 = Dom . createEl ( 'p' ) ;
const p2 = Dom . createEl ( 'p' ) ;
const el = Dom . insertContent ( Dom . createEl ( ) , [ p1 ] ) ;
2015-10-28 19:28:15 +02:00
Dom . appendContent ( el , p2 ) ;
assert . expect ( 2 ) ;
assert . strictEqual ( el . firstChild , p1 , 'the first paragraph is the first child' ) ;
assert . strictEqual ( el . firstChild . nextSibling , p2 , 'the second paragraph was appended' ) ;
} ) ;
2016-08-12 19:51:31 +02:00
QUnit . test ( '$() and $$()' , function ( assert ) {
2016-08-03 21:27:03 +02:00
const fixture = document . getElementById ( 'qunit-fixture' ) ;
const container = document . createElement ( 'div' ) ;
const children = [
2015-11-10 00:43:17 +02:00
document . createElement ( 'div' ) ,
document . createElement ( 'div' ) ,
2016-08-03 21:27:03 +02:00
document . createElement ( 'div' )
2015-11-10 00:43:17 +02:00
] ;
2015-10-28 19:28:15 +02:00
2015-11-10 00:43:17 +02:00
children . forEach ( child => container . appendChild ( child ) ) ;
fixture . appendChild ( container ) ;
2016-08-03 21:27:03 +02:00
const totalDivCount = document . getElementsByTagName ( 'div' ) . length ;
2016-08-12 19:51:31 +02:00
assert . expect ( 12 ) ;
2016-08-03 21:27:03 +02:00
2018-09-28 20:58:15 +02:00
assert . strictEqual (
Dom . $ ( '#qunit-fixture' ) ,
fixture ,
'can find an element in the document context'
) ;
assert . strictEqual (
Dom . $$ ( 'div' ) . length ,
totalDivCount ,
'finds elements in the document context'
) ;
assert . strictEqual (
Dom . $ ( 'div' , container ) ,
children [ 0 ] ,
'can find an element in a DOM element context'
) ;
assert . strictEqual (
Dom . $$ ( 'div' , container ) . length ,
children . length ,
'finds elements in a DOM element context'
) ;
assert . strictEqual (
Dom . $ ( '#qunit-fixture' , document . querySelector ( 'unknown' ) ) ,
fixture ,
'falls back to document given a bad context element'
) ;
assert . strictEqual (
Dom . $$ ( 'div' , document . querySelector ( 'unknown' ) ) . length ,
totalDivCount ,
'falls back to document given a bad context element'
) ;
assert . strictEqual (
Dom . $ ( '#qunit-fixture' , 'body' ) ,
fixture ,
'can find an element in a selector context'
) ;
assert . strictEqual (
Dom . $$ ( 'div' , '#qunit-fixture' ) . length ,
1 + children . length ,
'finds elements in a selector context'
) ;
assert . strictEqual (
Dom . $ ( '#qunit-fixture' , 'unknown' ) ,
fixture ,
'falls back to document given a bad context selector'
) ;
assert . strictEqual (
Dom . $$ ( 'div' , 'unknown' ) . length ,
totalDivCount ,
'falls back to document given a bad context selector'
) ;
2016-08-03 21:27:03 +02:00
2016-08-12 19:51:31 +02:00
assert . strictEqual ( Dom . $ ( 'div' , children [ 0 ] ) , null , 'returns null for missing elements' ) ;
2018-09-28 20:58:15 +02:00
assert . strictEqual (
Dom . $$ ( 'div' , children [ 0 ] ) . length ,
0 ,
'returns 0 for missing elements'
) ;
2015-11-10 00:43:17 +02:00
} ) ;
2017-01-19 22:30:47 +02:00
QUnit . test ( 'getBoundingClientRect() returns an object for elements that support it' , function ( assert ) {
const mockEl = {
getBoundingClientRect : sinon . spy ( ( ) => {
return {
bottom : 3 ,
height : 10 ,
left : 4 ,
right : 2 ,
top : 1 ,
width : 20
} ;
} ) ,
parentNode : true
} ;
const actual = Dom . getBoundingClientRect ( mockEl ) ;
// The expected result is what is returned by the mock element.
const expected = mockEl . getBoundingClientRect . firstCall . returnValue ;
assert . notStrictEqual ( actual , expected , 'the object returned by the mock element was cloned and not returned directly' ) ;
Object . keys ( expected ) . forEach ( k => {
assert . strictEqual ( actual [ k ] , expected [ k ] , ` the " ${ k } " returned by the Dom util matches what was returned by the mock element ` ) ;
} ) ;
} ) ;
2019-07-29 23:45:40 +02:00
QUnit . test ( 'isSingleLeftClick() returns false for mousemove event' , function ( assert ) {
const mouseEvent = TestHelpers . createEvent ( 'mousemove' ) ;
mouseEvent . button = 0 ;
mouseEvent . buttons = 0 ;
assert . notOk ( Dom . isSingleLeftClick ( mouseEvent ) , 'a mousemove event is not a single left click' ) ;
} ) ;
QUnit . test ( 'isSingleLeftClick() returns true for mouseup event' , function ( assert ) {
const mouseEvent = TestHelpers . createEvent ( 'mouseup' ) ;
mouseEvent . button = 0 ;
mouseEvent . buttons = 0 ;
assert . ok ( Dom . isSingleLeftClick ( mouseEvent ) , 'a mouseup event is a single left click' ) ;
} ) ;
QUnit . test ( 'isSingleLeftClick() checks return values for mousedown event' , function ( assert ) {
const mouseEvent = TestHelpers . createEvent ( 'mousedown' ) ;
// Left mouse click
mouseEvent . button = 0 ;
mouseEvent . buttons = 0 ;
assert . notOk ( Dom . isSingleLeftClick ( mouseEvent ) , 'a left mouse click on an older browser (Safari) is a single left click' ) ;
// Left mouse click
mouseEvent . button = 0 ;
mouseEvent . buttons = 1 ;
assert . ok ( Dom . isSingleLeftClick ( mouseEvent ) , 'a left mouse click on browsers that supporting buttons property is a single left click' ) ;
// Right mouse click
mouseEvent . button = 2 ;
mouseEvent . buttons = 2 ;
assert . notOk ( Dom . isSingleLeftClick ( mouseEvent ) , 'a right mouse click is not a single left click' ) ;
// Touch event on some mobiles
mouseEvent . button = 0 ;
mouseEvent . buttons = undefined ;
assert . ok ( Dom . isSingleLeftClick ( mouseEvent ) , 'a touch event on mobiles is a single left click' ) ;
// Chrome simulates mobile devices
mouseEvent . button = undefined ;
mouseEvent . buttons = undefined ;
assert . ok ( Dom . isSingleLeftClick ( mouseEvent ) , 'a touch event on simulated mobiles is a single left click' ) ;
} ) ;
2023-07-07 15:56:54 +02:00
2023-07-21 19:12:48 +02:00
QUnit . test ( 'Dom.copyStyleSheetsToWindow() copies all style sheets to a window' , function ( assert ) {
/ * *
* This test is checking that styles are copied by comparing strings in original stylesheets to those in
* documents . styleSheets in the new ( fake ) window . This can be problematic on older Safari as documents . styleSheets
* does not always return the original style - a shorthand property like ` background: white ` may be returned as
* ` background-color: white ` .
* /
2023-07-19 09:10:07 +02:00
2023-07-07 15:56:54 +02:00
const fakeWindow = document . createElement ( 'div' ) ;
const done = assert . async ( ) ;
assert . expect ( 7 ) ;
fakeWindow . document = {
head : document . createElement ( 'div' )
} ;
const style1 = document . createElement ( 'style' ) ;
2023-07-21 19:12:48 +02:00
style1 . textContent = 'body { background-color: white; }' ;
2023-07-07 15:56:54 +02:00
document . head . appendChild ( style1 ) ;
const style2 = document . createElement ( 'style' ) ;
style2 . textContent = 'body { margin: 0px; }' ;
document . head . appendChild ( style2 ) ;
const link = document . createElement ( 'link' ) ;
link . rel = 'stylesheet' ;
link . type = 'text/css' ;
link . media = 'print' ;
link . href = 'http://asdf.com/styles.css' ;
const containsRulesFromStyle = ( el ) => {
return Boolean ( [ ... fakeWindow . document . head . querySelectorAll ( 'style' ) ] . find ( s => {
return s . textContent . includes ( el . textContent ) ;
} ) ) ;
} ;
link . onload = link . onerror = ( ) => {
Dom . copyStyleSheetsToWindow ( fakeWindow ) ;
assert . strictEqual ( fakeWindow . document . head . querySelectorAll ( 'style, link' ) . length , document . styleSheets . length , 'the fake window has as many <style> or <link> elements as document.styleSheets' ) ;
assert . true ( containsRulesFromStyle ( style1 ) , 'a <style> in the fake window contains content from first <style> element' ) ;
assert . true ( containsRulesFromStyle ( style2 ) , 'a <style> in the fake window contains content from second <style> element' ) ;
assert . strictEqual ( fakeWindow . document . head . querySelectorAll ( 'link[rel=stylesheet]' ) . length , 1 , 'the fake window has one <link> stylesheet element' ) ;
const fakeWindowLink = fakeWindow . document . head . querySelectorAll ( 'link[rel=stylesheet]' ) [ 0 ] ;
assert . strictEqual ( fakeWindowLink . type , link . type , 'the <style> type attribute in the fake window is the one from <link> element' ) ;
assert . strictEqual ( fakeWindowLink . href , link . href , 'the <style> href attribute in the fake window is the one from <link> element' ) ;
assert . strictEqual ( fakeWindowLink . media , link . media , 'the <style> media attribute in the fake window is the one from <link> element' ) ;
done ( ) ;
} ;
document . head . appendChild ( link ) ;
} ) ;