From 3751379f1e9a4c215fb6eb898b4ccc67659b9ace Mon Sep 17 00:00:00 2001 From: stephanchrst Date: Tue, 10 May 2022 21:51:50 +0700 Subject: initial commit 2 --- addons/web/static/tests/core/ajax_tests.js | 35 + addons/web/static/tests/core/class_tests.js | 168 +++ addons/web/static/tests/core/concurrency_tests.js | 576 ++++++++ .../tests/core/data_comparison_utils_tests.js | 75 ++ addons/web/static/tests/core/dialog_tests.js | 173 +++ addons/web/static/tests/core/dom_tests.js | 133 ++ addons/web/static/tests/core/domain_tests.js | 186 +++ addons/web/static/tests/core/math_utils_tests.js | 56 + addons/web/static/tests/core/mixins_tests.js | 36 + addons/web/static/tests/core/owl_dialog_tests.js | 332 +++++ addons/web/static/tests/core/patch_mixin_tests.js | 994 ++++++++++++++ addons/web/static/tests/core/popover_tests.js | 280 ++++ addons/web/static/tests/core/py_utils_tests.js | 1376 ++++++++++++++++++++ addons/web/static/tests/core/registry_tests.js | 90 ++ addons/web/static/tests/core/rpc_tests.js | 316 +++++ addons/web/static/tests/core/time_tests.js | 165 +++ addons/web/static/tests/core/util_tests.js | 339 +++++ addons/web/static/tests/core/widget_tests.js | 530 ++++++++ 18 files changed, 5860 insertions(+) create mode 100644 addons/web/static/tests/core/ajax_tests.js create mode 100644 addons/web/static/tests/core/class_tests.js create mode 100644 addons/web/static/tests/core/concurrency_tests.js create mode 100644 addons/web/static/tests/core/data_comparison_utils_tests.js create mode 100644 addons/web/static/tests/core/dialog_tests.js create mode 100644 addons/web/static/tests/core/dom_tests.js create mode 100644 addons/web/static/tests/core/domain_tests.js create mode 100644 addons/web/static/tests/core/math_utils_tests.js create mode 100644 addons/web/static/tests/core/mixins_tests.js create mode 100644 addons/web/static/tests/core/owl_dialog_tests.js create mode 100644 addons/web/static/tests/core/patch_mixin_tests.js create mode 100644 addons/web/static/tests/core/popover_tests.js create mode 100644 addons/web/static/tests/core/py_utils_tests.js create mode 100644 addons/web/static/tests/core/registry_tests.js create mode 100644 addons/web/static/tests/core/rpc_tests.js create mode 100644 addons/web/static/tests/core/time_tests.js create mode 100644 addons/web/static/tests/core/util_tests.js create mode 100644 addons/web/static/tests/core/widget_tests.js (limited to 'addons/web/static/tests/core') diff --git a/addons/web/static/tests/core/ajax_tests.js b/addons/web/static/tests/core/ajax_tests.js new file mode 100644 index 00000000..f58d7368 --- /dev/null +++ b/addons/web/static/tests/core/ajax_tests.js @@ -0,0 +1,35 @@ +odoo.define('web.ajax_tests', function (require) { +"use strict"; + +var ajax = require('web.ajax'); + +QUnit.module('core', function () { + + var test_css_url = '/test_assetsbundle/static/src/css/test_cssfile1.css'; + var test_link_selector = 'link[href="' + test_css_url + '"]'; + + QUnit.module('ajax', { + beforeEach: function () { + $(test_link_selector).remove(); + }, + afterEach: function () { + $(test_link_selector).remove(); + } + }); + + QUnit.test('loadCSS', function (assert) { + var done = assert.async(); + assert.expect(2); + ajax.loadCSS(test_css_url).then(function () { + var $links = $(test_link_selector); + assert.strictEqual($links.length, 1, "The css should be added to the dom."); + ajax.loadCSS(test_css_url).then(function () { + var $links = $(test_link_selector); + assert.strictEqual($links.length, 1, "The css should have been added only once."); + done(); + }); + }); + }); +}); + +}); diff --git a/addons/web/static/tests/core/class_tests.js b/addons/web/static/tests/core/class_tests.js new file mode 100644 index 00000000..438b137e --- /dev/null +++ b/addons/web/static/tests/core/class_tests.js @@ -0,0 +1,168 @@ +odoo.define('web.class_tests', function (require) { +"use strict"; + +var Class = require('web.Class'); + +QUnit.module('core', {}, function () { + + QUnit.module('Class'); + + + QUnit.test('Basic class creation', function (assert) { + assert.expect(2); + + var C = Class.extend({ + foo: function () { + return this.somevar; + } + }); + var i = new C(); + i.somevar = 3; + + assert.ok(i instanceof C); + assert.strictEqual(i.foo(), 3); + }); + + QUnit.test('Class initialization', function (assert) { + assert.expect(2); + + var C1 = Class.extend({ + init: function () { + this.foo = 3; + } + }); + var C2 = Class.extend({ + init: function (arg) { + this.foo = arg; + } + }); + + var i1 = new C1(), + i2 = new C2(42); + + assert.strictEqual(i1.foo, 3); + assert.strictEqual(i2.foo, 42); + }); + + QUnit.test('Inheritance', function (assert) { + assert.expect(3); + + var C0 = Class.extend({ + foo: function () { + return 1; + } + }); + var C1 = C0.extend({ + foo: function () { + return 1 + this._super(); + } + }); + var C2 = C1.extend({ + foo: function () { + return 1 + this._super(); + } + }); + + assert.strictEqual(new C0().foo(), 1); + assert.strictEqual(new C1().foo(), 2); + assert.strictEqual(new C2().foo(), 3); + }); + + QUnit.test('In-place extension', function (assert) { + assert.expect(4); + + var C0 = Class.extend({ + foo: function () { + return 3; + }, + qux: function () { + return 3; + }, + bar: 3 + }); + + C0.include({ + foo: function () { + return 5; + }, + qux: function () { + return 2 + this._super(); + }, + bar: 5, + baz: 5 + }); + + assert.strictEqual(new C0().bar, 5); + assert.strictEqual(new C0().baz, 5); + assert.strictEqual(new C0().foo(), 5); + assert.strictEqual(new C0().qux(), 5); + }); + + QUnit.test('In-place extension and inheritance', function (assert) { + assert.expect(4); + + var C0 = Class.extend({ + foo: function () { return 1; }, + bar: function () { return 1; } + }); + var C1 = C0.extend({ + foo: function () { return 1 + this._super(); } + }); + assert.strictEqual(new C1().foo(), 2); + assert.strictEqual(new C1().bar(), 1); + + C1.include({ + foo: function () { return 2 + this._super(); }, + bar: function () { return 1 + this._super(); } + }); + assert.strictEqual(new C1().foo(), 4); + assert.strictEqual(new C1().bar(), 2); + }); + + QUnit.test('In-place extensions alter existing instances', function (assert) { + assert.expect(4); + + var C0 = Class.extend({ + foo: function () { return 1; }, + bar: function () { return 1; } + }); + var i = new C0(); + assert.strictEqual(i.foo(), 1); + assert.strictEqual(i.bar(), 1); + + C0.include({ + foo: function () { return 2; }, + bar: function () { return 2 + this._super(); } + }); + assert.strictEqual(i.foo(), 2); + assert.strictEqual(i.bar(), 3); + }); + + QUnit.test('In-place extension of subclassed types', function (assert) { + assert.expect(3); + + var C0 = Class.extend({ + foo: function () { return 1; }, + bar: function () { return 1; } + }); + var C1 = C0.extend({ + foo: function () { return 1 + this._super(); }, + bar: function () { return 1 + this._super(); } + }); + var i = new C1(); + + assert.strictEqual(i.foo(), 2); + + C0.include({ + foo: function () { return 2; }, + bar: function () { return 2 + this._super(); } + }); + + assert.strictEqual(i.foo(), 3); + assert.strictEqual(i.bar(), 4); + }); + + +}); + +}); diff --git a/addons/web/static/tests/core/concurrency_tests.js b/addons/web/static/tests/core/concurrency_tests.js new file mode 100644 index 00000000..1e195fde --- /dev/null +++ b/addons/web/static/tests/core/concurrency_tests.js @@ -0,0 +1,576 @@ +odoo.define('web.concurrency_tests', function (require) { +"use strict"; + +var concurrency = require('web.concurrency'); +var testUtils = require('web.test_utils'); + +var makeTestPromise = testUtils.makeTestPromise; +var makeTestPromiseWithAssert = testUtils.makeTestPromiseWithAssert; + +QUnit.module('core', {}, function () { + + QUnit.module('concurrency'); + + QUnit.test('mutex: simple scheduling', async function (assert) { + assert.expect(5); + var mutex = new concurrency.Mutex(); + + var prom1 = makeTestPromiseWithAssert(assert, 'prom1'); + var prom2 = makeTestPromiseWithAssert(assert, 'prom2'); + + mutex.exec(function () { return prom1; }); + mutex.exec(function () { return prom2; }); + + assert.verifySteps([]); + + await prom1.resolve(); + + assert.verifySteps(['ok prom1']); + + await prom2.resolve(); + + assert.verifySteps(['ok prom2']); + }); + + QUnit.test('mutex: simpleScheduling2', async function (assert) { + assert.expect(5); + var mutex = new concurrency.Mutex(); + + var prom1 = makeTestPromiseWithAssert(assert, 'prom1'); + var prom2 = makeTestPromiseWithAssert(assert, 'prom2'); + + mutex.exec(function () { return prom1; }); + mutex.exec(function () { return prom2; }); + + assert.verifySteps([]); + + await prom2.resolve(); + + assert.verifySteps(['ok prom2']); + + await prom1.resolve(); + + assert.verifySteps(['ok prom1']); + }); + + QUnit.test('mutex: reject', async function (assert) { + assert.expect(7); + var mutex = new concurrency.Mutex(); + + var prom1 = makeTestPromiseWithAssert(assert, 'prom1'); + var prom2 = makeTestPromiseWithAssert(assert, 'prom2'); + var prom3 = makeTestPromiseWithAssert(assert, 'prom3'); + + mutex.exec(function () { return prom1; }).catch(function () {}); + mutex.exec(function () { return prom2; }).catch(function () {}); + mutex.exec(function () { return prom3; }).catch(function () {}); + + assert.verifySteps([]); + + prom1.resolve(); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok prom1']); + + prom2.catch(function () { + assert.verifySteps(['ko prom2']); + }); + prom2.reject({name: "sdkjfmqsjdfmsjkdfkljsdq"}); + await testUtils.nextMicrotaskTick(); + + prom3.resolve(); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok prom3']); + }); + + QUnit.test('mutex: getUnlockedDef checks', async function (assert) { + assert.expect(9); + + var mutex = new concurrency.Mutex(); + + var prom1 = makeTestPromiseWithAssert(assert, 'prom1'); + var prom2 = makeTestPromiseWithAssert(assert, 'prom2'); + + mutex.getUnlockedDef().then(function () { + assert.step('mutex unlocked (1)'); + }); + + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['mutex unlocked (1)']); + + mutex.exec(function () { return prom1; }); + await testUtils.nextMicrotaskTick(); + + mutex.getUnlockedDef().then(function () { + assert.step('mutex unlocked (2)'); + }); + + assert.verifySteps([]); + + mutex.exec(function () { return prom2; }); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps([]); + + await prom1.resolve(); + + assert.verifySteps(['ok prom1']); + + prom2.resolve(); + await testUtils.nextTick(); + + assert.verifySteps(['ok prom2', 'mutex unlocked (2)']); + }); + + QUnit.test('DropPrevious: basic usecase', async function (assert) { + assert.expect(4); + + var dp = new concurrency.DropPrevious(); + + var prom1 = makeTestPromise(assert, 'prom1'); + var prom2 = makeTestPromise(assert, 'prom2'); + + dp.add(prom1).then(() => assert.step('should not go here')) + .catch(()=> assert.step("rejected dp1")); + dp.add(prom2).then(() => assert.step("ok dp2")); + + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['rejected dp1']); + + prom2.resolve(); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok dp2']); + }); + + QUnit.test('DropPrevious: resolve first before last', async function (assert) { + assert.expect(4); + + var dp = new concurrency.DropPrevious(); + + var prom1 = makeTestPromise(assert, 'prom1'); + var prom2 = makeTestPromise(assert, 'prom2'); + + dp.add(prom1).then(() => assert.step('should not go here')) + .catch(()=> assert.step("rejected dp1")); + dp.add(prom2).then(() => assert.step("ok dp2")); + + + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['rejected dp1']); + + prom1.resolve(); + prom2.resolve(); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok dp2']); + }); + + QUnit.test('DropMisordered: resolve all correctly ordered, sync', async function (assert) { + assert.expect(1); + + var dm = new concurrency.DropMisordered(), + flag = false; + + var d1 = makeTestPromise(); + var d2 = makeTestPromise(); + + var r1 = dm.add(d1), + r2 = dm.add(d2); + + Promise.all([r1, r2]).then(function () { + flag = true; + }); + + d1.resolve(); + d2.resolve(); + await testUtils.nextTick(); + + assert.ok(flag); + }); + + QUnit.test("DropMisordered: don't resolve mis-ordered, sync", async function (assert) { + assert.expect(4); + + var dm = new concurrency.DropMisordered(), + done1 = false, + done2 = false, + fail1 = false, + fail2 = false; + + var d1 = makeTestPromise(); + var d2 = makeTestPromise(); + + dm.add(d1).then(function () { done1 = true; }) + .catch(function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }) + .catch(function () { fail2 = true; }); + + d2.resolve(); + d1.resolve(); + await testUtils.nextMicrotaskTick(); + + // d1 is in limbo + assert.ok(!done1); + assert.ok(!fail1); + + // d2 is fulfilled + assert.ok(done2); + assert.ok(!fail2); + }); + + QUnit.test('DropMisordered: fail mis-ordered flag, sync', async function (assert) { + assert.expect(4); + + var dm = new concurrency.DropMisordered(true/* failMisordered */), + done1 = false, + done2 = false, + fail1 = false, + fail2 = false; + + var d1 = makeTestPromise(); + var d2 = makeTestPromise(); + + dm.add(d1).then(function () { done1 = true; }) + .catch(function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }) + .catch(function () { fail2 = true; }); + + d2.resolve(); + d1.resolve(); + await testUtils.nextMicrotaskTick(); + + // d1 is in limbo + assert.ok(!done1); + assert.ok(fail1); + + // d2 is resolved + assert.ok(done2); + assert.ok(!fail2); + }); + + QUnit.test('DropMisordered: resolve all correctly ordered, async', function (assert) { + var done = assert.async(); + assert.expect(1); + + var dm = new concurrency.DropMisordered(); + + var d1 = makeTestPromise(); + var d2 = makeTestPromise(); + + var r1 = dm.add(d1), + r2 = dm.add(d2); + + setTimeout(function () { d1.resolve(); }, 10); + setTimeout(function () { d2.resolve(); }, 20); + + Promise.all([r1, r2]).then(function () { + assert.ok(true); + done(); + }); + }); + + QUnit.test("DropMisordered: don't resolve mis-ordered, async", function (assert) { + var done = assert.async(); + assert.expect(4); + + var dm = new concurrency.DropMisordered(), + done1 = false, done2 = false, + fail1 = false, fail2 = false; + + var d1 = makeTestPromise(); + var d2 = makeTestPromise(); + + dm.add(d1).then(function () { done1 = true; }) + .catch(function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }) + .catch(function () { fail2 = true; }); + + setTimeout(function () { d1.resolve(); }, 20); + setTimeout(function () { d2.resolve(); }, 10); + + setTimeout(function () { + // d1 is in limbo + assert.ok(!done1); + assert.ok(!fail1); + + // d2 is resolved + assert.ok(done2); + assert.ok(!fail2); + done(); + }, 30); + }); + + QUnit.test('DropMisordered: fail mis-ordered flag, async', function (assert) { + var done = assert.async(); + assert.expect(4); + + var dm = new concurrency.DropMisordered(true), + done1 = false, done2 = false, + fail1 = false, fail2 = false; + + var d1 = makeTestPromise(); + var d2 = makeTestPromise(); + + dm.add(d1).then(function () { done1 = true; }) + .catch(function () { fail1 = true; }); + dm.add(d2).then(function () { done2 = true; }) + .catch(function () { fail2 = true; }); + + setTimeout(function () { d1.resolve(); }, 20); + setTimeout(function () { d2.resolve(); }, 10); + + setTimeout(function () { + // d1 is failed + assert.ok(!done1); + assert.ok(fail1); + + // d2 is resolved + assert.ok(done2); + assert.ok(!fail2); + done(); + }, 30); + }); + + QUnit.test('MutexedDropPrevious: simple', async function (assert) { + assert.expect(5); + + var m = new concurrency.MutexedDropPrevious(); + var d1 = makeTestPromise(); + + d1.then(function () { + assert.step("d1 resolved"); + }); + m.exec(function () { return d1; }).then(function (result) { + assert.step("p1 done"); + assert.strictEqual(result, 'd1'); + }); + + assert.verifySteps([]); + d1.resolve('d1'); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(["d1 resolved","p1 done"]); + }); + + QUnit.test('MutexedDropPrevious: d2 arrives after d1 resolution', async function (assert) { + assert.expect(8); + + var m = new concurrency.MutexedDropPrevious(); + var d1 = makeTestPromiseWithAssert(assert, 'd1'); + + m.exec(function () { return d1; }).then(function () { + assert.step("p1 resolved"); + }); + + assert.verifySteps([]); + d1.resolve('d1'); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok d1','p1 resolved']); + + var d2 = makeTestPromiseWithAssert(assert, 'd2'); + m.exec(function () { return d2; }).then(function () { + assert.step("p2 resolved"); + }); + + assert.verifySteps([]); + d2.resolve('d2'); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok d2','p2 resolved']); + }); + + QUnit.test('MutexedDropPrevious: p1 does not return a deferred', async function (assert) { + assert.expect(7); + + var m = new concurrency.MutexedDropPrevious(); + + m.exec(function () { return 42; }).then(function () { + assert.step("p1 resolved"); + }); + + assert.verifySteps([]); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['p1 resolved']); + + var d2 = makeTestPromiseWithAssert(assert, 'd2'); + m.exec(function () { return d2; }).then(function () { + assert.step("p2 resolved"); + }); + + assert.verifySteps([]); + d2.resolve('d2'); + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['ok d2','p2 resolved']); + }); + + QUnit.test('MutexedDropPrevious: p2 arrives before p1 resolution', async function (assert) { + assert.expect(8); + + var m = new concurrency.MutexedDropPrevious(); + var d1 = makeTestPromiseWithAssert(assert, 'd1'); + + m.exec(function () { return d1; }).catch(function () { + assert.step("p1 rejected"); + }); + assert.verifySteps([]); + + var d2 = makeTestPromiseWithAssert(assert, 'd2'); + m.exec(function () { return d2; }).then(function () { + assert.step("p2 resolved"); + }); + + assert.verifySteps([]); + d1.resolve('d1'); + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['p1 rejected', 'ok d1']); + + d2.resolve('d2'); + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['ok d2', 'p2 resolved']); + }); + + QUnit.test('MutexedDropPrevious: 3 arrives before 2 initialization', async function (assert) { + assert.expect(10); + var m = new concurrency.MutexedDropPrevious(); + + var d1 = makeTestPromiseWithAssert(assert, 'd1'); + var d3 = makeTestPromiseWithAssert(assert, 'd3'); + + m.exec(function () { return d1; }).catch(function () { + assert.step('p1 rejected'); + }); + + m.exec(function () { + assert.ok(false, "should not execute this function"); + }).catch(function () { + assert.step('p2 rejected'); + }); + + m.exec(function () { return d3; }).then(function (result) { + assert.strictEqual(result, 'd3'); + assert.step('p3 resolved'); + }); + + assert.verifySteps([]); + + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['p1 rejected', 'p2 rejected']); + + d1.resolve('d1'); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok d1']); + + d3.resolve('d3'); + await testUtils.nextTick(); + + + assert.verifySteps(['ok d3','p3 resolved']); + }); + + QUnit.test('MutexedDropPrevious: 3 arrives after 2 initialization', async function (assert) { + assert.expect(15); + var m = new concurrency.MutexedDropPrevious(); + + var d1 = makeTestPromiseWithAssert(assert, 'd1'); + var d2 = makeTestPromiseWithAssert(assert, 'd2'); + var d3 = makeTestPromiseWithAssert(assert, 'd3'); + + m.exec(function () { + assert.step('execute d1'); + return d1; + }).catch(function () { + assert.step('p1 rejected'); + }); + + m.exec(function () { + assert.step('execute d2'); + return d2; + }).catch(function () { + assert.step('p2 rejected'); + }); + + assert.verifySteps(['execute d1']); + + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['p1 rejected']); + + d1.resolve('d1'); + await testUtils.nextMicrotaskTick(); + + assert.verifySteps(['ok d1', 'execute d2']); + + m.exec(function () { + assert.step('execute d3'); + return d3; + }).then(function () { + assert.step('p3 resolved'); + }); + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['p2 rejected']); + + d2.resolve(); + await testUtils.nextMicrotaskTick(); + assert.verifySteps(['ok d2', 'execute d3']); + + d3.resolve(); + await testUtils.nextTick(); + assert.verifySteps(['ok d3', 'p3 resolved']); + + }); + + QUnit.test('MutexedDropPrevious: 2 in then of 1 with 3', async function (assert) { + assert.expect(9); + + var m = new concurrency.MutexedDropPrevious(); + + var d1 = makeTestPromiseWithAssert(assert, 'd1'); + var d2 = makeTestPromiseWithAssert(assert, 'd2'); + var d3 = makeTestPromiseWithAssert(assert, 'd3'); + var p3; + + m.exec(function () { return d1; }) + .catch(function () { + assert.step('p1 rejected'); + p3 = m.exec(function () { + return d3; + }).then(function () { + assert.step('p3 resolved'); + }); + return p3; + }); + + await testUtils.nextTick(); + assert.verifySteps([]); + + m.exec(function () { + assert.ok(false, 'should not execute this function'); + return d2; + }).catch(function () { + assert.step('p2 rejected'); + }); + + await testUtils.nextTick(); + assert.verifySteps(['p1 rejected', 'p2 rejected']); + + d1.resolve('d1'); + await testUtils.nextTick(); + + assert.verifySteps(['ok d1']); + + d3.resolve('d3'); + await testUtils.nextTick(); + + assert.verifySteps(['ok d3', 'p3 resolved']); + }); + +}); + +}); diff --git a/addons/web/static/tests/core/data_comparison_utils_tests.js b/addons/web/static/tests/core/data_comparison_utils_tests.js new file mode 100644 index 00000000..f5058714 --- /dev/null +++ b/addons/web/static/tests/core/data_comparison_utils_tests.js @@ -0,0 +1,75 @@ +odoo.define('web.data_comparison_utils_tests', function(require) { +"use strict"; + +var dataComparisonUtils = require('web.dataComparisonUtils'); +var DateClasses = dataComparisonUtils.DateClasses; + +QUnit.module('dataComparisonUtils', function () { + + QUnit.module('DateClasses'); + + + QUnit.test('main parameters are correctly computed', function(assert) { + assert.expect(30); + + var dateClasses; + + dateClasses = new DateClasses([['2019']]); + assert.strictEqual(dateClasses.referenceIndex, 0); + assert.strictEqual(dateClasses.dateClass(0, '2019'), 0); + assert.deepEqual(dateClasses.dateClassMembers(0), ['2019']); + + dateClasses = new DateClasses([['2018', '2019']]); + assert.strictEqual(dateClasses.referenceIndex, 0); + assert.strictEqual(dateClasses.dateClass(0, '2018'), 0); + assert.strictEqual(dateClasses.dateClass(0, '2019'), 1); + assert.deepEqual(dateClasses.dateClassMembers(0), ['2018']); + assert.deepEqual(dateClasses.dateClassMembers(1), ['2019']); + + dateClasses = new DateClasses([['2019'], []]); + assert.strictEqual(dateClasses.referenceIndex, 0); + assert.strictEqual(dateClasses.dateClass(0, '2019'), 0); + assert.deepEqual(dateClasses.dateClassMembers(0), ['2019']); + + dateClasses = new DateClasses([[], ['2019']]); + assert.strictEqual(dateClasses.referenceIndex, 1); + assert.strictEqual(dateClasses.dateClass(1, '2019'), 0); + assert.deepEqual(dateClasses.dateClassMembers(0), ['2019']); + + dateClasses = new DateClasses([['2019'],['2018', '2019']]); + assert.strictEqual(dateClasses.referenceIndex, 0); + assert.strictEqual(dateClasses.dateClass(0, '2019'), 0); + assert.strictEqual(dateClasses.dateClass(1, '2018'), 0); + assert.strictEqual(dateClasses.dateClass(1, '2019'), 1); + assert.deepEqual(dateClasses.dateClassMembers(0), ['2019', '2018']); + assert.deepEqual(dateClasses.dateClassMembers(1), ['2019']); + + + dateClasses = new DateClasses([['2019'], ['2017', '2018', '2020'], ['2017', '2019']]); + assert.strictEqual(dateClasses.referenceIndex, 0); + assert.strictEqual(dateClasses.dateClass(0, '2019'), 0); + assert.strictEqual(dateClasses.dateClass(1, '2017'), 0); + assert.strictEqual(dateClasses.dateClass(1, '2018'), 1); + assert.strictEqual(dateClasses.dateClass(1, '2020'), 2); + assert.strictEqual(dateClasses.dateClass(2, '2017'), 0); + assert.strictEqual(dateClasses.dateClass(2, '2019'), 1); + assert.deepEqual(dateClasses.dateClassMembers(0), ['2019', '2017']); + assert.deepEqual(dateClasses.dateClassMembers(1), ['2018', '2019']); + assert.deepEqual(dateClasses.dateClassMembers(2), ['2020']); + + + }); + + QUnit.test('two overlapping datesets and classes representatives', function(assert) { + assert.expect(4); + + var dateClasses = new DateClasses([['March 2017'], ['February 2017', 'March 2017']]); + + assert.strictEqual(dateClasses.representative(0, 0), 'March 2017'); + assert.strictEqual(dateClasses.representative(0, 1), 'February 2017'); + + assert.strictEqual(dateClasses.representative(1, 0), undefined); + assert.strictEqual(dateClasses.representative(1, 1), 'March 2017'); + }); +}); +}); diff --git a/addons/web/static/tests/core/dialog_tests.js b/addons/web/static/tests/core/dialog_tests.js new file mode 100644 index 00000000..3c83b2ba --- /dev/null +++ b/addons/web/static/tests/core/dialog_tests.js @@ -0,0 +1,173 @@ +odoo.define('web.dialog_tests', function (require) { +"use strict"; + +var Dialog = require('web.Dialog'); +var testUtils = require('web.test_utils'); +var Widget = require('web.Widget'); + +var ESCAPE_KEY = $.Event("keyup", { which: 27 }); + +async function createEmptyParent(debug) { + var widget = new Widget(); + + await testUtils.mock.addMockEnvironment(widget, { + debug: debug || false, + }); + return widget; +} + +QUnit.module('core', {}, function () { + + QUnit.module('Dialog'); + + QUnit.test("Closing custom dialog using buttons calls standard callback", async function (assert) { + assert.expect(3); + + var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'custom callback'); + var parent = await createEmptyParent(); + new Dialog(parent, { + buttons: [ + { + text: "Close", + classes: 'btn-primary', + close: true, + click: testPromise.resolve, + }, + ], + $content: $('
'), + onForceClose: testPromise.reject, + }).open(); + + assert.verifySteps([]); + + await testUtils.nextTick(); + await testUtils.dom.click($('.modal[role="dialog"] .btn-primary')); + + testPromise.then(() => { + assert.verifySteps(['ok custom callback']); + }); + + parent.destroy(); + }); + + QUnit.test("Closing custom dialog without using buttons calls force close callback", async function (assert) { + assert.expect(3); + + var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'custom callback'); + var parent = await createEmptyParent(); + new Dialog(parent, { + buttons: [ + { + text: "Close", + classes: 'btn-primary', + close: true, + click: testPromise.reject, + }, + ], + $content: $('
'), + onForceClose: testPromise.resolve, + }).open(); + + assert.verifySteps([]); + + await testUtils.nextTick(); + await testUtils.dom.triggerEvents($('.modal[role="dialog"]'), [ESCAPE_KEY]); + + testPromise.then(() => { + assert.verifySteps(['ok custom callback']); + }); + + parent.destroy(); + }); + + QUnit.test("Closing confirm dialog without using buttons calls cancel callback", async function (assert) { + assert.expect(3); + + var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'confirm callback'); + var parent = await createEmptyParent(); + var options = { + confirm_callback: testPromise.reject, + cancel_callback: testPromise.resolve, + }; + Dialog.confirm(parent, "", options); + + assert.verifySteps([]); + + await testUtils.nextTick(); + await testUtils.dom.triggerEvents($('.modal[role="dialog"]'), [ESCAPE_KEY]); + + testPromise.then(() => { + assert.verifySteps(['ok confirm callback']); + }); + + parent.destroy(); + }); + + QUnit.test("Closing alert dialog without using buttons calls confirm callback", async function (assert) { + assert.expect(3); + + var testPromise = testUtils.makeTestPromiseWithAssert(assert, 'alert callback'); + var parent = await createEmptyParent(); + var options = { + confirm_callback: testPromise.resolve, + }; + Dialog.alert(parent, "", options); + + assert.verifySteps([]); + + await testUtils.nextTick(); + await testUtils.dom.triggerEvents($('.modal[role="dialog"]'), [ESCAPE_KEY]); + + testPromise.then(() => { + assert.verifySteps(['ok alert callback']); + }); + + parent.destroy(); + }); + + QUnit.test("Ensure on_attach_callback and on_detach_callback are properly called", async function (assert) { + assert.expect(4); + + const TestDialog = Dialog.extend({ + on_attach_callback() { + assert.step('on_attach_callback'); + }, + on_detach_callback() { + assert.step('on_detach_callback'); + }, + }); + + const parent = await createEmptyParent(); + const dialog = new TestDialog(parent, { + buttons: [ + { + text: "Close", + classes: 'btn-primary', + close: true, + }, + ], + $content: $('
'), + }).open(); + + await dialog.opened(); + + assert.verifySteps(['on_attach_callback']); + + await testUtils.dom.click($('.modal[role="dialog"] .btn-primary')); + assert.verifySteps(['on_detach_callback']); + + parent.destroy(); + }); + + QUnit.test("Should not be displayed if parent is destroyed while dialog is being opened", async function (assert) { + assert.expect(1); + const parent = await createEmptyParent(); + const dialog = new Dialog(parent); + dialog.open(); + parent.destroy(); + await testUtils.nextTick(); + assert.containsNone(document.body, ".modal[role='dialog']"); + }); +}); + +}); diff --git a/addons/web/static/tests/core/dom_tests.js b/addons/web/static/tests/core/dom_tests.js new file mode 100644 index 00000000..c57ced52 --- /dev/null +++ b/addons/web/static/tests/core/dom_tests.js @@ -0,0 +1,133 @@ +odoo.define('web.dom_tests', function (require) { +"use strict"; + +var dom = require('web.dom'); +var testUtils = require('web.test_utils'); + +/** + * Create an autoresize text area with 'border-box' as box sizing rule. + * The minimum height of this autoresize text are is 1px. + * + * @param {Object} [options={}] + * @param {integer} [options.borderBottomWidth=0] + * @param {integer} [options.borderTopWidth=0] + * @param {integer} [options.padding=0] + */ +function prepareAutoresizeTextArea(options) { + options = options || {}; + var $textarea = $('