diff options
| author | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
|---|---|---|
| committer | stephanchrst <stephanchrst@gmail.com> | 2022-05-10 21:51:50 +0700 |
| commit | 3751379f1e9a4c215fb6eb898b4ccc67659b9ace (patch) | |
| tree | a44932296ef4a9b71d5f010906253d8c53727726 /addons/web/static/tests/helpers/qunit_asserts.js | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/web/static/tests/helpers/qunit_asserts.js')
| -rw-r--r-- | addons/web/static/tests/helpers/qunit_asserts.js | 244 |
1 files changed, 244 insertions, 0 deletions
diff --git a/addons/web/static/tests/helpers/qunit_asserts.js b/addons/web/static/tests/helpers/qunit_asserts.js new file mode 100644 index 00000000..69cf2807 --- /dev/null +++ b/addons/web/static/tests/helpers/qunit_asserts.js @@ -0,0 +1,244 @@ +odoo.define('web.qunit_asserts', function (require) { + "use strict"; + + /** + * In this file, we extend QUnit by adding some specialized assertions. The goal + * of these new assertions is twofold: + * - ease of use: they should allow us to simplify some common complex assertions + * - safer: these assertions will fail when some preconditions are not met. + * + * For example, the assert.isVisible assertion will also check that the target + * matches exactly one element. + */ + + const Widget = require('web.Widget'); + + /** @todo use testUtilsDom.getNode to extract the element from the 'w' argument */ + + //------------------------------------------------------------------------- + // Private functions + //------------------------------------------------------------------------- + + /** + * Helper function, to check if a given element + * - is unique (if it is a jquery node set) + * - has (or has not) a css class + * + * @private + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} className + * @param {boolean} shouldHaveClass + * @param {string} [msg] + */ + function _checkClass(w, className, shouldHaveClass, msg) { + if (w instanceof jQuery && w.length !== 1) { + const assertion = shouldHaveClass ? 'hasClass' : 'doesNotHaveClass'; + QUnit.assert.ok(false, `Assertion '${assertion} ${className}' targets ${w.length} elements instead of 1`); + } + + const el = w instanceof Widget || w instanceof owl.Component ? w.el : + w instanceof jQuery ? w[0] : w; + + msg = msg || `target should ${shouldHaveClass ? 'have' : 'not have'} class ${className}`; + const isFalse = className.split(" ").some(cls => { + const hasClass = el.classList.contains(cls); + return shouldHaveClass ? !hasClass : hasClass; + }); + QUnit.assert.ok(!isFalse, msg); + } + + /** + * Helper function, to check if a given element + * - is unique (if it is a jquery node set) + * - is (or not) visible + * + * @private + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {boolean} shouldBeVisible + * @param {string} [msg] + */ + function _checkVisible(w, shouldBeVisible, msg) { + if (w instanceof jQuery && w.length !== 1) { + const assertion = shouldBeVisible ? 'isVisible' : 'isNotVisible'; + QUnit.assert.ok(false, `Assertion '${assertion}' targets ${w.length} elements instead of 1`); + } + + const el = w instanceof Widget || w instanceof owl.Component ? w.el : + w instanceof jQuery ? w[0] : w; + + msg = msg || `target should ${shouldBeVisible ? '' : 'not'} be visible`; + let isVisible = el && + el.offsetWidth && + el.offsetHeight; + if (isVisible) { + // This computation is a little more heavy and we only want to perform it + // if the above assertion has failed. + const rect = el.getBoundingClientRect(); + isVisible = rect.width + rect.height; + } + const condition = shouldBeVisible ? isVisible : !isVisible; + QUnit.assert.ok(condition, msg); + } + + //------------------------------------------------------------------------- + // Public functions + //------------------------------------------------------------------------- + + /** + * Checks that the target element (described by widget/jquery or html element) + * contains exactly n matches for the selector. + * + * Example: assert.containsN(document.body, '.modal', 0) + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} selector + * @param {number} n + * @param {string} [msg] + */ + function containsN(w, selector, n, msg) { + if (typeof n !== 'number') { + throw new Error("containsN assert should be called with a number as third argument"); + } + let matches = []; + if (w instanceof owl.Component) { + if (!w.el) { + throw new Error(`containsN assert with selector '${selector}' called on an unmounted component`); + } + matches = w.el.querySelectorAll(selector); + } else { + const $el = w instanceof Widget ? w.$el : + w instanceof HTMLElement ? $(w) : + w; // jquery element + matches = $el.find(selector); + } + if (!msg) { + msg = `Selector '${selector}' should have exactly ${n} matches (inside the target)`; + } + QUnit.assert.strictEqual(matches.length, n, msg); + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * contains exactly 0 match for the selector. + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} selector + * @param {string} [msg] + */ + function containsNone(w, selector, msg) { + containsN(w, selector, 0, msg); + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * contains exactly 1 match for the selector. + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} selector + * @param {string} [msg] + */ + function containsOnce(w, selector, msg) { + containsN(w, selector, 1, msg); + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is unique + * - has the given class (specified by className) + * + * Note that it uses the hasClass jQuery method, so it can be used to check the + * presence of more than one class ('some-class other-class'), but it is a + * little brittle, because it depends on the order of these classes: + * + * div.a.b.c: has class 'a b c', but does not have class 'a c b' + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} className + * @param {string} [msg] + */ + function hasClass(w, className, msg) { + _checkClass(w, className, true, msg); + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is unique + * - does not have the given class (specified by className) + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} className + * @param {string} [msg] + */ + function doesNotHaveClass(w, className, msg) { + _checkClass(w, className, false, msg); + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is unique + * - has the given attribute with the proper value + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} attr + * @param {string} value + * @param {string} [msg] + */ + function hasAttrValue(w, attr, value, msg) { + const $el = w instanceof Widget ? w.$el : + w instanceof HTMLElement ? $(w) : + w; // jquery element + + if ($el.length !== 1) { + const descr = `hasAttrValue (${attr}: ${value})`; + QUnit.assert.ok(false, + `Assertion '${descr}' targets ${$el.length} elements instead of 1` + ); + } else { + msg = msg || `attribute '${attr}' of target should be '${value}'`; + QUnit.assert.strictEqual($el.attr(attr), value, msg); + } + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is visible (as far as jQuery can tell: not in display none, ...) + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} [msg] + */ + function isVisible(w, msg) { + _checkVisible(w, true, msg); + } + + /** + * Checks that the target element (described by widget/jquery or html element) + * - exists + * - is not visible (as far as jQuery can tell: display none, ...) + * + * @param {Widget|jQuery|HTMLElement|owl.Component} w + * @param {string} [msg] + */ + function isNotVisible(w, msg) { + _checkVisible(w, false, msg); + } + + //------------------------------------------------------------------------- + // Exposed API + //------------------------------------------------------------------------- + + QUnit.assert.containsN = containsN; + QUnit.assert.containsNone = containsNone; + QUnit.assert.containsOnce = containsOnce; + + QUnit.assert.hasClass = hasClass; + QUnit.assert.doesNotHaveClass = doesNotHaveClass; + + QUnit.assert.hasAttrValue = hasAttrValue; + + QUnit.assert.isVisible = isVisible; + QUnit.assert.isNotVisible = isNotVisible; +}); |
