mirror of
https://github.com/twbs/bootstrap.git
synced 2025-08-18 03:11:19 +02:00
Switch from QUnit to Jasmine.
This commit is contained in:
@@ -1,20 +1,16 @@
|
||||
## How does Bootstrap's test suite work?
|
||||
|
||||
Bootstrap uses [QUnit](https://qunitjs.com/) and [Sinon](https://sinonjs.org/). Each plugin has a file dedicated to its tests in `unit/<plugin-name>.js`.
|
||||
Bootstrap uses [Jasmine](https://jasmine.github.io/). Each plugin has a file dedicated to its tests in `src/<plugin-name>/<plugin-name>.spec.js`.
|
||||
|
||||
* `unit/` contains the unit test files for each Bootstrap plugin.
|
||||
* `vendor/` contains third-party testing-related code (QUnit, jQuery and Sinon).
|
||||
* `visual/` contains "visual" tests which are run interactively in real browsers and require manual verification by humans.
|
||||
|
||||
To run the unit test suite via [Karma](https://karma-runner.github.io/), run `npm run js-test`.
|
||||
|
||||
To run the unit test suite via a real web browser, open `index.html` in the browser.
|
||||
|
||||
To run the unit test suite via [Karma](https://karma-runner.github.io/) and debug, run `npm run js-debug`.
|
||||
|
||||
## How do I add a new unit test?
|
||||
|
||||
1. Locate and open the file dedicated to the plugin which you need to add tests to (`unit/<plugin-name>.js`).
|
||||
2. Review the [QUnit API Documentation](https://api.qunitjs.com/) and use the existing tests as references for how to structure your new tests.
|
||||
1. Locate and open the file dedicated to the plugin which you need to add tests to (`src/<plugin-name>/<plugin-name>.spec.js`).
|
||||
2. Review the [Jasmine API Documentation](https://jasmine.github.io/pages/docs_home.html) and use the existing tests as references for how to structure your new tests.
|
||||
3. Write the necessary unit test(s) for the new or revised functionality.
|
||||
4. Run `npm run js-test` to see the results of your newly-added test(s).
|
||||
|
||||
@@ -23,47 +19,53 @@ To run the unit test suite via a real web browser, open `index.html` in the brow
|
||||
## What should a unit test look like?
|
||||
|
||||
* Each test should have a unique name clearly stating what unit is being tested.
|
||||
* Each test should be in the corresponding `describe`.
|
||||
* Each test should test only one unit per test, although one test can include several assertions. Create multiple tests for multiple units of functionality.
|
||||
* Each test should begin with [`assert.expect`](https://api.qunitjs.com/assert/expect/) to ensure that the expected assertions are run.
|
||||
* Each test should use [`expect`](https://jasmine.github.io/api/edge/matchers.html) to ensure something is expected.
|
||||
* Each test should follow the project's [JavaScript Code Guidelines](https://github.com/twbs/bootstrap/blob/master/CONTRIBUTING.md#js)
|
||||
|
||||
## Code coverage
|
||||
|
||||
Currently we're aiming for at least 80% test coverage for our code. To ensure your changes meet or exceed this limit, run `npm run js-compile && npm run js-test` and open the file in `js/coverage/lcov-report/index.html` to see the code coverage for each plugin. See more details when you select a plugin and ensure your change is fully covered by unit tests.
|
||||
Currently we're aiming for at least 90% test coverage for our code. To ensure your changes meet or exceed this limit, run `npm run js-compile && npm run js-test` and open the file in `js/coverage/lcov-report/index.html` to see the code coverage for each plugin. See more details when you select a plugin and ensure your change is fully covered by unit tests.
|
||||
|
||||
### Example tests
|
||||
|
||||
```js
|
||||
// Synchronous test
|
||||
QUnit.test('should describe the unit being tested', function (assert) {
|
||||
assert.expect(1)
|
||||
var templateHTML = '<div class="alert alert-danger fade show">' +
|
||||
'<a class="close" href="#" data-dismiss="alert">×</a>' +
|
||||
'<p><strong>Template necessary for the test.</p>' +
|
||||
'</div>'
|
||||
var $alert = $(templateHTML).appendTo('#qunit-fixture').bootstrapAlert()
|
||||
describe('_getInstance', () => {
|
||||
it('should return null if there is no instance', () => {
|
||||
// Make assertion
|
||||
expect(Tab._getInstance(fixtureEl)).toEqual(null)
|
||||
})
|
||||
|
||||
$alert.find('.close').trigger('click')
|
||||
it('should return this instance', () => {
|
||||
fixtureEl.innerHTML = '<div></div>'
|
||||
|
||||
// Make assertion
|
||||
assert.strictEqual($alert.hasClass('show'), false, 'remove .show class on .close click')
|
||||
const divEl = fixtureEl.querySelector('div')
|
||||
const tab = new Tab(divEl)
|
||||
|
||||
// Make assertion
|
||||
expect(Tab._getInstance(divEl)).toEqual(tab)
|
||||
})
|
||||
})
|
||||
|
||||
// Asynchronous test
|
||||
QUnit.test('should describe the unit being tested', function (assert) {
|
||||
assert.expect(2)
|
||||
var done = assert.async()
|
||||
it('should show a tooltip without the animation', done => {
|
||||
fixtureEl.innerHTML = '<a href="#" rel="tooltip" title="Another tooltip"/>'
|
||||
|
||||
var $tooltip = $('<div title="tooltip title"></div>').bootstrapTooltip()
|
||||
var tooltipInstance = $tooltip.data('bs.tooltip')
|
||||
var spyShow = sinon.spy(tooltipInstance, 'show')
|
||||
const tooltipEl = fixtureEl.querySelector('a')
|
||||
const tooltip = new Tooltip(tooltipEl, {
|
||||
animation: false
|
||||
})
|
||||
|
||||
$tooltip.appendTo('#qunit-fixture')
|
||||
.on('shown.bs.tooltip', function () {
|
||||
assert.ok(true, '"shown" event was fired after calling "show"')
|
||||
assert.ok(spyShow.called, 'show called')
|
||||
done()
|
||||
})
|
||||
.bootstrapTooltip('show')
|
||||
tooltipEl.addEventListener('shown.bs.tooltip', () => {
|
||||
const tip = document.querySelector('.tooltip')
|
||||
|
||||
expect(tip).toBeDefined()
|
||||
expect(tip.classList.contains('fade')).toEqual(false)
|
||||
done()
|
||||
})
|
||||
|
||||
tooltip.show()
|
||||
})
|
||||
```
|
||||
|
20
js/tests/helpers/fixture.js
Normal file
20
js/tests/helpers/fixture.js
Normal file
@@ -0,0 +1,20 @@
|
||||
const fixtureId = 'fixture'
|
||||
|
||||
export const getFixture = () => {
|
||||
let fixtureEl = document.getElementById(fixtureId)
|
||||
|
||||
if (!fixtureEl) {
|
||||
fixtureEl = document.createElement('div')
|
||||
fixtureEl.setAttribute('id', fixtureId)
|
||||
fixtureEl.style.display = 'none'
|
||||
document.body.appendChild(fixtureEl)
|
||||
}
|
||||
|
||||
return fixtureEl
|
||||
}
|
||||
|
||||
export const clearFixture = () => {
|
||||
const fixtureEl = getFixture()
|
||||
|
||||
fixtureEl.innerHTML = ''
|
||||
}
|
@@ -7,22 +7,19 @@ const {
|
||||
browsers,
|
||||
browsersKeys
|
||||
} = require('./browsers')
|
||||
const babel = require('rollup-plugin-babel')
|
||||
const istanbul = require('rollup-plugin-istanbul')
|
||||
|
||||
const { env } = process
|
||||
const bundle = env.BUNDLE === 'true'
|
||||
const browserStack = env.BROWSER === 'true'
|
||||
const debug = env.DEBUG === 'true'
|
||||
|
||||
const jqueryFile = 'node_modules/jquery/dist/jquery.slim.min.js'
|
||||
|
||||
const frameworks = [
|
||||
'qunit',
|
||||
'sinon'
|
||||
'jasmine'
|
||||
]
|
||||
|
||||
const plugins = [
|
||||
'karma-qunit',
|
||||
'karma-sinon'
|
||||
'karma-jasmine',
|
||||
'karma-rollup-preprocessor'
|
||||
]
|
||||
|
||||
const reporters = ['dots']
|
||||
@@ -49,10 +46,35 @@ const customLaunchers = {
|
||||
}
|
||||
}
|
||||
|
||||
let files = [
|
||||
'node_modules/popper.js/dist/umd/popper.min.js',
|
||||
'node_modules/hammer-simulator/index.js'
|
||||
]
|
||||
const rollupPreprocessor = {
|
||||
plugins: [
|
||||
istanbul({
|
||||
exclude: ['js/src/**/*.spec.js']
|
||||
}),
|
||||
babel({
|
||||
// Only transpile our source code
|
||||
exclude: 'node_modules/**',
|
||||
// Include only required helpers
|
||||
externalHelpersWhitelist: [
|
||||
'defineProperties',
|
||||
'createClass',
|
||||
'inheritsLoose',
|
||||
'defineProperty',
|
||||
'objectSpread2'
|
||||
],
|
||||
plugins: [
|
||||
'@babel/plugin-proposal-object-rest-spread'
|
||||
]
|
||||
})
|
||||
],
|
||||
output: {
|
||||
format: 'iife',
|
||||
name: 'bootstrapTest',
|
||||
sourcemap: 'inline'
|
||||
}
|
||||
}
|
||||
|
||||
let files = []
|
||||
|
||||
const conf = {
|
||||
basePath: '../..',
|
||||
@@ -62,28 +84,11 @@ const conf = {
|
||||
singleRun: true,
|
||||
concurrency: Infinity,
|
||||
client: {
|
||||
qunit: {
|
||||
showUI: true
|
||||
}
|
||||
clearContext: false
|
||||
}
|
||||
}
|
||||
|
||||
if (bundle) {
|
||||
frameworks.push('detectBrowsers')
|
||||
plugins.push(
|
||||
'karma-chrome-launcher',
|
||||
'karma-firefox-launcher',
|
||||
'karma-detect-browsers'
|
||||
)
|
||||
conf.customLaunchers = customLaunchers
|
||||
conf.detectBrowsers = detectBrowsers
|
||||
files = files.concat([
|
||||
jqueryFile,
|
||||
'js/tests/unit/tests-polyfills.js',
|
||||
'dist/js/bootstrap.js',
|
||||
'js/tests/unit/!(tests-polyfills).js'
|
||||
])
|
||||
} else if (browserStack) {
|
||||
if (browserStack) {
|
||||
conf.hostname = ip.address()
|
||||
conf.browserStack = {
|
||||
username: env.BROWSER_STACK_USERNAME,
|
||||
@@ -92,27 +97,17 @@ if (bundle) {
|
||||
project: 'Bootstrap',
|
||||
retryLimit: 2
|
||||
}
|
||||
plugins.push('karma-browserstack-launcher')
|
||||
plugins.push('karma-browserstack-launcher', 'karma-jasmine-html-reporter')
|
||||
conf.customLaunchers = browsers
|
||||
conf.browsers = browsersKeys
|
||||
reporters.push('BrowserStack')
|
||||
reporters.push('BrowserStack', 'kjhtml')
|
||||
files = files.concat([
|
||||
jqueryFile,
|
||||
'js/tests/unit/tests-polyfills.js',
|
||||
'js/coverage/dist/util/index.js',
|
||||
'js/coverage/dist/util/sanitizer.js',
|
||||
'js/coverage/dist/dom/polyfill.js',
|
||||
'js/coverage/dist/dom/event-handler.js',
|
||||
'js/coverage/dist/dom/selector-engine.js',
|
||||
'js/coverage/dist/dom/data.js',
|
||||
'js/coverage/dist/dom/manipulator.js',
|
||||
'js/coverage/dist/dom/!(polyfill).js',
|
||||
'js/coverage/dist/tooltip.js',
|
||||
'js/coverage/dist/!(util|index|tooltip).js', // include all of our js/dist files except util.js, index.js and tooltip.js
|
||||
'js/tests/unit/!(tests-polyfills).js',
|
||||
'js/tests/unit/dom/*.js',
|
||||
'js/tests/unit/util/*.js'
|
||||
{ pattern: 'js/src/**/*.spec.js', watched: false }
|
||||
])
|
||||
conf.preprocessors = {
|
||||
'js/src/**/*.spec.js': ['rollup']
|
||||
}
|
||||
conf.rollupPreprocessor = rollupPreprocessor
|
||||
} else {
|
||||
frameworks.push('detectBrowsers')
|
||||
plugins.push(
|
||||
@@ -122,23 +117,13 @@ if (bundle) {
|
||||
'karma-coverage-istanbul-reporter'
|
||||
)
|
||||
files = files.concat([
|
||||
jqueryFile,
|
||||
'js/tests/unit/tests-polyfills.js',
|
||||
'js/coverage/dist/util/index.js',
|
||||
'js/coverage/dist/util/sanitizer.js',
|
||||
'js/coverage/dist/dom/polyfill.js',
|
||||
'js/coverage/dist/dom/event-handler.js',
|
||||
'js/coverage/dist/dom/selector-engine.js',
|
||||
'js/coverage/dist/dom/data.js',
|
||||
'js/coverage/dist/dom/manipulator.js',
|
||||
'js/coverage/dist/dom/!(polyfill).js',
|
||||
'js/coverage/dist/tooltip.js',
|
||||
'js/coverage/dist/!(util|index|tooltip).js', // include all of our js/dist files except util.js, index.js and tooltip.js
|
||||
'js/tests/unit/!(tests-polyfills).js',
|
||||
'js/tests/unit/dom/*.js',
|
||||
'js/tests/unit/util/*.js'
|
||||
{ pattern: 'js/src/**/*.spec.js', watched: true }
|
||||
])
|
||||
reporters.push('coverage-istanbul')
|
||||
conf.preprocessors = {
|
||||
'js/src/**/*.spec.js': ['rollup']
|
||||
}
|
||||
conf.rollupPreprocessor = rollupPreprocessor
|
||||
conf.customLaunchers = customLaunchers
|
||||
conf.detectBrowsers = detectBrowsers
|
||||
conf.coverageIstanbulReporter = {
|
||||
@@ -148,8 +133,8 @@ if (bundle) {
|
||||
emitWarning: false,
|
||||
global: {
|
||||
statements: 90,
|
||||
branches: 86,
|
||||
functions: 89,
|
||||
branches: 90,
|
||||
functions: 90,
|
||||
lines: 90
|
||||
},
|
||||
each: {
|
||||
@@ -166,6 +151,9 @@ if (bundle) {
|
||||
}
|
||||
|
||||
if (debug) {
|
||||
conf.hostname = ip.address()
|
||||
plugins.push('karma-jasmine-html-reporter')
|
||||
reporters.push('kjhtml')
|
||||
conf.singleRun = false
|
||||
conf.autoWatch = true
|
||||
}
|
||||
|
@@ -1,123 +0,0 @@
|
||||
$(function () {
|
||||
'use strict'
|
||||
|
||||
var Alert = typeof window.bootstrap === 'undefined' ? window.Alert : window.bootstrap.Alert
|
||||
|
||||
QUnit.module('alert plugin')
|
||||
|
||||
QUnit.test('should be defined on jquery object', function (assert) {
|
||||
assert.expect(1)
|
||||
assert.ok($(document.body).alert, 'alert method is defined')
|
||||
})
|
||||
|
||||
QUnit.module('alert', {
|
||||
beforeEach: function () {
|
||||
// Run all tests in noConflict mode -- it's the only way to ensure that the plugin works in noConflict mode
|
||||
$.fn.bootstrapAlert = $.fn.alert.noConflict()
|
||||
},
|
||||
afterEach: function () {
|
||||
$.fn.alert = $.fn.bootstrapAlert
|
||||
delete $.fn.bootstrapAlert
|
||||
$('#qunit-fixture').html('')
|
||||
}
|
||||
})
|
||||
|
||||
QUnit.test('should provide no conflict', function (assert) {
|
||||
assert.expect(1)
|
||||
assert.strictEqual(typeof $.fn.alert, 'undefined', 'alert was set back to undefined (org value)')
|
||||
})
|
||||
|
||||
QUnit.test('should return jquery collection containing the element', function (assert) {
|
||||
assert.expect(2)
|
||||
var $el = $('<div/>')
|
||||
var $alert = $el.bootstrapAlert()
|
||||
assert.ok($alert instanceof $, 'returns jquery collection')
|
||||
assert.strictEqual($alert[0], $el[0], 'collection contains element')
|
||||
})
|
||||
|
||||
QUnit.test('should fade element out on clicking .close', function (assert) {
|
||||
assert.expect(1)
|
||||
var alertHTML = '<div class="alert alert-danger fade show">' +
|
||||
'<a class="close" href="#" data-dismiss="alert">×</a>' +
|
||||
'<p><strong>Holy guacamole!</strong> Best check yo self, you\'re not looking too good.</p>' +
|
||||
'</div>'
|
||||
|
||||
var $alert = $(alertHTML).bootstrapAlert().appendTo($('#qunit-fixture'))
|
||||
|
||||
var closeBtn = $alert.find('.close')[0]
|
||||
closeBtn.dispatchEvent(new Event('click'))
|
||||
assert.strictEqual($alert.hasClass('show'), false, 'remove .show class on .close click')
|
||||
})
|
||||
|
||||
QUnit.test('should remove element when clicking .close', function (assert) {
|
||||
assert.expect(2)
|
||||
var done = assert.async()
|
||||
var alertHTML = '<div class="alert alert-danger fade show">' +
|
||||
'<a class="close" href="#" data-dismiss="alert">×</a>' +
|
||||
'<p><strong>Holy guacamole!</strong> Best check yo self, you\'re not looking too good.</p>' +
|
||||
'</div>'
|
||||
var $alert = $(alertHTML).appendTo('#qunit-fixture').bootstrapAlert()
|
||||
|
||||
assert.notEqual($('#qunit-fixture').find('.alert').length, 0, 'element added to dom')
|
||||
|
||||
$alert[0].addEventListener('closed.bs.alert', function () {
|
||||
assert.strictEqual($('#qunit-fixture').find('.alert').length, 0, 'element removed from dom')
|
||||
done()
|
||||
})
|
||||
|
||||
var closeBtn = $alert.find('.close')[0]
|
||||
closeBtn.dispatchEvent(new Event('click'))
|
||||
})
|
||||
|
||||
QUnit.test('should not fire closed when close is prevented', function (assert) {
|
||||
assert.expect(1)
|
||||
var done = assert.async()
|
||||
var $alert = $('<div class="alert"/>')
|
||||
$alert.appendTo('#qunit-fixture')
|
||||
|
||||
$alert[0].addEventListener('close.bs.alert', function (e) {
|
||||
e.preventDefault()
|
||||
assert.ok(true, 'close event fired')
|
||||
done()
|
||||
})
|
||||
$alert[0].addEventListener('closed.bs.alert', function () {
|
||||
assert.ok(false, 'closed event fired')
|
||||
})
|
||||
|
||||
$alert.bootstrapAlert('close')
|
||||
})
|
||||
|
||||
QUnit.test('close should use internal _element if no element provided', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var done = assert.async()
|
||||
var $el = $('<div/>')
|
||||
var $alert = $el.bootstrapAlert()
|
||||
var alertInstance = Alert._getInstance($alert[0])
|
||||
|
||||
$alert[0].addEventListener('closed.bs.alert', function () {
|
||||
assert.ok('alert closed')
|
||||
done()
|
||||
})
|
||||
|
||||
alertInstance.close()
|
||||
})
|
||||
|
||||
QUnit.test('dispose should remove data and the element', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var $el = $('<div/>')
|
||||
var $alert = $el.bootstrapAlert()
|
||||
|
||||
assert.ok(typeof Alert._getInstance($alert[0]) !== 'undefined')
|
||||
|
||||
Alert._getInstance($alert[0]).dispose()
|
||||
|
||||
assert.ok(Alert._getInstance($alert[0]) === null)
|
||||
})
|
||||
|
||||
QUnit.test('should return the version', function (assert) {
|
||||
assert.expect(1)
|
||||
assert.strictEqual(typeof Alert.VERSION, 'string')
|
||||
})
|
||||
})
|
@@ -1,83 +0,0 @@
|
||||
$(function () {
|
||||
'use strict'
|
||||
|
||||
QUnit.module('data')
|
||||
|
||||
QUnit.test('should be defined', function (assert) {
|
||||
assert.expect(1)
|
||||
assert.ok(Data, 'Data is defined')
|
||||
})
|
||||
|
||||
QUnit.test('should set data in a element', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $div = $('<div />').appendTo('#qunit-fixture')
|
||||
var data = {
|
||||
test: 'bsData'
|
||||
}
|
||||
Data.setData($div[0], 'test', data)
|
||||
|
||||
assert.ok($div[0].key, 'element have a data key')
|
||||
})
|
||||
|
||||
QUnit.test('should get data from an element', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $div = $('<div />').appendTo('#qunit-fixture')
|
||||
var data = {
|
||||
test: 'bsData'
|
||||
}
|
||||
Data.setData($div[0], 'test', data)
|
||||
|
||||
assert.strictEqual(Data.getData($div[0], 'test'), data)
|
||||
})
|
||||
|
||||
QUnit.test('should return null if nothing is stored', function (assert) {
|
||||
assert.expect(1)
|
||||
assert.ok(Data.getData(document.body, 'test') === null)
|
||||
})
|
||||
|
||||
QUnit.test('should return null if nothing is stored with an existing key', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $div = $('<div />').appendTo('#qunit-fixture')
|
||||
$div[0].key = {
|
||||
key: 'test2',
|
||||
data: 'woot woot'
|
||||
}
|
||||
|
||||
assert.ok(Data.getData($div[0], 'test') === null)
|
||||
})
|
||||
|
||||
QUnit.test('should delete data', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var $div = $('<div />').appendTo('#qunit-fixture')
|
||||
var data = {
|
||||
test: 'bsData'
|
||||
}
|
||||
Data.setData($div[0], 'test', data)
|
||||
assert.ok(Data.getData($div[0], 'test') !== null)
|
||||
|
||||
Data.removeData($div[0], 'test')
|
||||
assert.ok(Data.getData($div[0], 'test') === null)
|
||||
})
|
||||
|
||||
QUnit.test('should delete nothing if there are nothing', function (assert) {
|
||||
assert.expect(0)
|
||||
|
||||
Data.removeData(document.body, 'test')
|
||||
})
|
||||
|
||||
QUnit.test('should delete nothing if not the good key', function (assert) {
|
||||
assert.expect(0)
|
||||
|
||||
var $div = $('<div />').appendTo('#qunit-fixture')
|
||||
$div[0].key = {
|
||||
key: 'test2',
|
||||
data: 'woot woot'
|
||||
}
|
||||
|
||||
Data.removeData($div[0], 'test')
|
||||
})
|
||||
})
|
@@ -1,340 +0,0 @@
|
||||
$(function () {
|
||||
'use strict'
|
||||
|
||||
QUnit.module('eventHandler')
|
||||
|
||||
QUnit.test('should be defined', function (assert) {
|
||||
assert.expect(1)
|
||||
assert.ok(EventHandler, 'EventHandler is defined')
|
||||
})
|
||||
|
||||
QUnit.test('should trigger event correctly', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
element.addEventListener('foobar', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('should trigger event through jQuery event system', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
$(element).on('foobar', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('should trigger namespaced event through jQuery event system', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
$(element).on('foobar.namespace', function () {
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
element.addEventListener('foobar.namespace', function () {
|
||||
assert.ok(true, 'second listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
})
|
||||
|
||||
QUnit.test('should mirror preventDefault', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
$(element).on('foobar.namespace', function (event) {
|
||||
event.preventDefault()
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
element.addEventListener('foobar.namespace', function (event) {
|
||||
assert.ok(event.defaultPrevented, 'defaultPrevented is true in second listener')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
})
|
||||
|
||||
QUnit.test('should mirror preventDefault for native events', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
document.body.appendChild(element)
|
||||
|
||||
$(element).on('click', function (event) {
|
||||
event.preventDefault()
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
element.addEventListener('click', function (event) {
|
||||
assert.ok(event.defaultPrevented, 'defaultPrevented is true in second listener')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'click')
|
||||
document.body.removeChild(element)
|
||||
})
|
||||
|
||||
QUnit.test('on should add event listener', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
EventHandler.on(element, 'foobar', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('on should add namespaced event listener', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
EventHandler.on(element, 'foobar.namespace', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
})
|
||||
|
||||
QUnit.test('on should add native namespaced event listener', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
document.body.appendChild(element)
|
||||
EventHandler.on(element, 'click.namespace', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'click')
|
||||
document.body.removeChild(element)
|
||||
})
|
||||
|
||||
QUnit.test('on should add delegated event listener', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
var subelement = document.createElement('span')
|
||||
element.appendChild(subelement)
|
||||
|
||||
var anchor = document.createElement('a')
|
||||
element.appendChild(anchor)
|
||||
|
||||
EventHandler.on(element, 'click.namespace', 'a', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.on(element, 'click', 'span', function () {
|
||||
assert.notOk(true, 'listener should not be called')
|
||||
})
|
||||
|
||||
document.body.appendChild(element)
|
||||
EventHandler.trigger(anchor, 'click')
|
||||
document.body.removeChild(element)
|
||||
})
|
||||
|
||||
QUnit.test('on should add delegated event listener if delegated selector differs', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
var subelement = document.createElement('span')
|
||||
element.appendChild(subelement)
|
||||
|
||||
var anchor = document.createElement('a')
|
||||
element.appendChild(anchor)
|
||||
|
||||
var i = 0
|
||||
var handler = function () {
|
||||
i++
|
||||
}
|
||||
|
||||
EventHandler.on(element, 'click', 'a', handler)
|
||||
EventHandler.on(element, 'click', 'span', handler)
|
||||
|
||||
document.body.appendChild(element)
|
||||
EventHandler.trigger(anchor, 'click')
|
||||
EventHandler.trigger(subelement, 'click')
|
||||
document.body.removeChild(element)
|
||||
|
||||
assert.ok(i === 2, 'listeners called')
|
||||
})
|
||||
|
||||
QUnit.test('one should remove the listener after the event', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
EventHandler.one(element, 'foobar', function () {
|
||||
assert.ok(true, 'listener called')
|
||||
})
|
||||
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('off should remove a listener', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var element = document.createElement('div')
|
||||
var handler = function () {
|
||||
assert.ok(true, 'listener called')
|
||||
}
|
||||
|
||||
EventHandler.on(element, 'foobar', handler)
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
|
||||
EventHandler.off(element, 'foobar', handler)
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('off should remove all the listeners', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
|
||||
EventHandler.on(element, 'foobar', function () {
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
EventHandler.on(element, 'foobar', function () {
|
||||
assert.ok(true, 'second listener called')
|
||||
})
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
|
||||
EventHandler.off(element, 'foobar')
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('off should remove all the namespaced listeners if namespace is passed', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
|
||||
EventHandler.on(element, 'foobar.namespace', function () {
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
EventHandler.on(element, 'foofoo.namespace', function () {
|
||||
assert.ok(true, 'second listener called')
|
||||
})
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
EventHandler.trigger(element, 'foofoo.namespace')
|
||||
|
||||
EventHandler.off(element, '.namespace')
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
EventHandler.trigger(element, 'foofoo.namespace')
|
||||
})
|
||||
|
||||
QUnit.test('off should remove the namespaced listeners', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
|
||||
EventHandler.on(element, 'foobar.namespace', function () {
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
EventHandler.on(element, 'foofoo.namespace', function () {
|
||||
assert.ok(true, 'second listener called')
|
||||
})
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
|
||||
EventHandler.off(element, 'foobar.namespace')
|
||||
EventHandler.trigger(element, 'foobar.namespace')
|
||||
|
||||
EventHandler.trigger(element, 'foofoo.namespace')
|
||||
})
|
||||
|
||||
QUnit.test('off should remove the all the namespaced listeners for native events', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var element = document.createElement('div')
|
||||
document.body.appendChild(element)
|
||||
|
||||
EventHandler.on(element, 'click.namespace', function () {
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
EventHandler.on(element, 'click.namespace2', function () {
|
||||
assert.ok(true, 'second listener called')
|
||||
})
|
||||
EventHandler.trigger(element, 'click')
|
||||
|
||||
EventHandler.off(element, 'click')
|
||||
EventHandler.trigger(element, 'click')
|
||||
document.body.removeChild(element)
|
||||
})
|
||||
|
||||
QUnit.test('off should remove the specified namespaced listeners for native events', function (assert) {
|
||||
assert.expect(3)
|
||||
|
||||
var element = document.createElement('div')
|
||||
document.body.appendChild(element)
|
||||
|
||||
EventHandler.on(element, 'click.namespace', function () {
|
||||
assert.ok(true, 'first listener called')
|
||||
})
|
||||
EventHandler.on(element, 'click.namespace2', function () {
|
||||
assert.ok(true, 'second listener called')
|
||||
})
|
||||
EventHandler.trigger(element, 'click')
|
||||
|
||||
EventHandler.off(element, 'click.namespace')
|
||||
EventHandler.trigger(element, 'click')
|
||||
document.body.removeChild(element)
|
||||
})
|
||||
|
||||
QUnit.test('off should remove a listener registered by .one', function (assert) {
|
||||
assert.expect(0)
|
||||
|
||||
var element = document.createElement('div')
|
||||
var handler = function () {
|
||||
assert.notOk(true, 'listener called')
|
||||
}
|
||||
|
||||
EventHandler.one(element, 'foobar', handler)
|
||||
EventHandler.off(element, 'foobar', handler)
|
||||
|
||||
EventHandler.trigger(element, 'foobar')
|
||||
})
|
||||
|
||||
QUnit.test('off should remove the correct delegated event listener', function (assert) {
|
||||
assert.expect(5)
|
||||
|
||||
var element = document.createElement('div')
|
||||
var subelement = document.createElement('span')
|
||||
element.appendChild(subelement)
|
||||
|
||||
var anchor = document.createElement('a')
|
||||
element.appendChild(anchor)
|
||||
|
||||
var i = 0
|
||||
var handler = function () {
|
||||
i++
|
||||
}
|
||||
|
||||
EventHandler.on(element, 'click', 'a', handler)
|
||||
EventHandler.on(element, 'click', 'span', handler)
|
||||
|
||||
document.body.appendChild(element)
|
||||
|
||||
EventHandler.trigger(anchor, 'click')
|
||||
EventHandler.trigger(subelement, 'click')
|
||||
assert.ok(i === 2, 'first listeners called')
|
||||
|
||||
EventHandler.off(element, 'click', 'span', handler)
|
||||
EventHandler.trigger(subelement, 'click')
|
||||
assert.ok(i === 2, 'removed listener not called')
|
||||
|
||||
EventHandler.trigger(anchor, 'click')
|
||||
assert.ok(i === 3, 'not removed listener called')
|
||||
|
||||
EventHandler.on(element, 'click', 'span', handler)
|
||||
EventHandler.trigger(anchor, 'click')
|
||||
EventHandler.trigger(subelement, 'click')
|
||||
assert.ok(i === 5, 'listener re-registered')
|
||||
|
||||
EventHandler.off(element, 'click', 'span')
|
||||
EventHandler.trigger(subelement, 'click')
|
||||
assert.ok(i === 5, 'listener removed again')
|
||||
|
||||
document.body.removeChild(element)
|
||||
})
|
||||
})
|
@@ -1,191 +0,0 @@
|
||||
$(function () {
|
||||
'use strict'
|
||||
|
||||
QUnit.module('util', {
|
||||
afterEach: function () {
|
||||
$('#qunit-fixture').html('')
|
||||
}
|
||||
})
|
||||
|
||||
QUnit.test('Util.getSelectorFromElement should return the correct element', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var $el = $('<div data-target="body"></div>').appendTo($('#qunit-fixture'))
|
||||
assert.strictEqual(Util.getSelectorFromElement($el[0]), 'body')
|
||||
|
||||
// Not found element
|
||||
var $el2 = $('<div data-target="#fakeDiv"></div>').appendTo($('#qunit-fixture'))
|
||||
assert.strictEqual(Util.getSelectorFromElement($el2[0]), null)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getSelectorFromElement should return null when there is a bad selector', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var $el = $('<div data-target="#1"></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.getSelectorFromElement($el[0]), null)
|
||||
|
||||
var $el2 = $('<a href="/posts"></a>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.getSelectorFromElement($el2[0]), null)
|
||||
})
|
||||
|
||||
QUnit.test('Util.typeCheckConfig should thrown an error when a bad config is passed', function (assert) {
|
||||
assert.expect(1)
|
||||
var namePlugin = 'collapse'
|
||||
var defaultType = {
|
||||
toggle: 'boolean',
|
||||
parent: '(string|element)'
|
||||
}
|
||||
var config = {
|
||||
toggle: true,
|
||||
parent: 777
|
||||
}
|
||||
|
||||
try {
|
||||
Util.typeCheckConfig(namePlugin, config, defaultType)
|
||||
} catch (error) {
|
||||
assert.strictEqual(error.message, 'COLLAPSE: Option "parent" provided type "number" but expected type "(string|element)".')
|
||||
}
|
||||
})
|
||||
|
||||
QUnit.test('Util.isElement should check if we passed an element or not', function (assert) {
|
||||
assert.expect(3)
|
||||
var $div = $('<div id="test"></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.isElement($div), 1)
|
||||
assert.strictEqual(Util.isElement($div[0]), 1)
|
||||
assert.strictEqual(typeof Util.isElement({}) === 'undefined', true)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getTransitionDurationFromElement should accept transition durations in milliseconds', function (assert) {
|
||||
assert.expect(1)
|
||||
var $div = $('<div style="transition: all 300ms ease-out;"></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div[0]), 300)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getTransitionDurationFromElement should accept transition durations in seconds', function (assert) {
|
||||
assert.expect(1)
|
||||
var $div = $('<div style="transition: all .4s ease-out;"></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div[0]), 400)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getTransitionDurationFromElement should return the addition of transition-delay and transition-duration', function (assert) {
|
||||
assert.expect(2)
|
||||
var $fixture = $('#qunit-fixture')
|
||||
var $div = $('<div style="transition: all 0s 150ms ease-out;"></div>').appendTo($fixture)
|
||||
var $div2 = $('<div style="transition: all .25s 30ms ease-out;"></div>').appendTo($fixture)
|
||||
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div[0]), 150)
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div2[0]), 280)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getTransitionDurationFromElement should get the first transition duration if multiple transition durations are defined', function (assert) {
|
||||
assert.expect(1)
|
||||
var $div = $('<div style="transition: transform .3s ease-out, opacity .2s;"></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div[0]), 300)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getTransitionDurationFromElement should return 0 if transition duration is not defined', function (assert) {
|
||||
assert.expect(1)
|
||||
var $div = $('<div></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div[0]), 0)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getTransitionDurationFromElement should return 0 if element is not found in DOM', function (assert) {
|
||||
assert.expect(1)
|
||||
var $div = $('#fake-id')
|
||||
|
||||
assert.strictEqual(Util.getTransitionDurationFromElement($div[0]), 0)
|
||||
})
|
||||
|
||||
QUnit.test('Util.getUID should generate a new id uniq', function (assert) {
|
||||
assert.expect(2)
|
||||
var id = Util.getUID('test')
|
||||
var id2 = Util.getUID('test')
|
||||
|
||||
assert.ok(id !== id2, id + ' !== ' + id2)
|
||||
|
||||
id = Util.getUID('test')
|
||||
$('<div id="' + id + '"></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
id2 = Util.getUID('test')
|
||||
assert.ok(id !== id2, id + ' !== ' + id2)
|
||||
})
|
||||
|
||||
QUnit.test('Util.findShadowRoot should find the shadow DOM root', function (assert) {
|
||||
// Only for newer browsers
|
||||
if (!document.documentElement.attachShadow) {
|
||||
assert.expect(0)
|
||||
return
|
||||
}
|
||||
|
||||
assert.expect(2)
|
||||
var $div = $('<div id="test"></div>').appendTo($('#qunit-fixture'))
|
||||
var shadowRoot = $div[0].attachShadow({
|
||||
mode: 'open'
|
||||
})
|
||||
|
||||
assert.equal(shadowRoot, Util.findShadowRoot(shadowRoot))
|
||||
shadowRoot.innerHTML = '<button>Shadow Button</button>'
|
||||
assert.equal(shadowRoot, Util.findShadowRoot(shadowRoot.firstChild))
|
||||
})
|
||||
|
||||
QUnit.test('Util.findShadowRoot should return null when attachShadow is not available', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var $div = $('<div id="test"></div>').appendTo($('#qunit-fixture'))
|
||||
if (document.documentElement.attachShadow) {
|
||||
var sandbox = sinon.createSandbox()
|
||||
|
||||
sandbox.replace(document.documentElement, 'attachShadow', function () {
|
||||
// to avoid empty function
|
||||
return $div
|
||||
})
|
||||
|
||||
assert.equal(null, Util.findShadowRoot($div[0]))
|
||||
sandbox.restore()
|
||||
} else {
|
||||
assert.equal(null, Util.findShadowRoot($div[0]))
|
||||
}
|
||||
})
|
||||
|
||||
QUnit.test('noop should return an empty function', function (assert) {
|
||||
assert.expect(1)
|
||||
Util.noop().call()
|
||||
assert.ok(typeof Util.noop() === 'function')
|
||||
})
|
||||
|
||||
QUnit.test('should return jQuery if present', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
assert.equal(Util.jQuery, $)
|
||||
|
||||
$.noConflict()
|
||||
|
||||
assert.equal(Util.jQuery, jQuery)
|
||||
|
||||
window.$ = jQuery
|
||||
})
|
||||
|
||||
QUnit.test('Util.emulateTransitionEnd should emulate transition end', function (assert) {
|
||||
assert.expect(1)
|
||||
var $div = $('<div></div>').appendTo($('#qunit-fixture'))
|
||||
|
||||
var spy = sinon.spy($div[0], 'removeEventListener')
|
||||
|
||||
Util.emulateTransitionEnd($div[0], 7)
|
||||
|
||||
assert.ok(spy.notCalled)
|
||||
})
|
||||
|
||||
QUnit.test('Util.makeArray should return empty array on null', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
assert.ok(Util.makeArray(null).length === 0)
|
||||
})
|
||||
})
|
@@ -1,51 +0,0 @@
|
||||
$(function () {
|
||||
'use strict'
|
||||
|
||||
QUnit.module('sanitizer', {
|
||||
afterEach: function () {
|
||||
$('#qunit-fixture').html('')
|
||||
}
|
||||
})
|
||||
|
||||
QUnit.test('should export a default white list', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
assert.ok(Sanitizer.DefaultWhitelist)
|
||||
})
|
||||
|
||||
QUnit.test('should sanitize template by removing tags with XSS', function (assert) {
|
||||
assert.expect(1)
|
||||
|
||||
var template = [
|
||||
'<div>',
|
||||
' <a href="javascript:alert(7)">Click me</a>',
|
||||
' <span>Some content</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
|
||||
var result = Sanitizer.sanitizeHtml(template, Sanitizer.DefaultWhitelist, null)
|
||||
|
||||
assert.strictEqual(result.indexOf('script'), -1)
|
||||
})
|
||||
|
||||
QUnit.test('should not use native api to sanitize if a custom function passed', function (assert) {
|
||||
assert.expect(2)
|
||||
|
||||
var template = [
|
||||
'<div>',
|
||||
' <span>Some content</span>',
|
||||
'</div>'
|
||||
].join('')
|
||||
|
||||
function mySanitize(htmlUnsafe) {
|
||||
return htmlUnsafe
|
||||
}
|
||||
|
||||
var spy = sinon.spy(DOMParser.prototype, 'parseFromString')
|
||||
var result = Sanitizer.sanitizeHtml(template, Sanitizer.DefaultWhitelist, mySanitize)
|
||||
|
||||
assert.strictEqual(result, template)
|
||||
assert.strictEqual(spy.called, false)
|
||||
spy.restore()
|
||||
})
|
||||
})
|
Reference in New Issue
Block a user