summaryrefslogtreecommitdiff
path: root/addons/web/static/tests/component_extension_tests.js
diff options
context:
space:
mode:
authorLucas Perais (lpe) <lpe@odoo.com>2020-01-22 12:38:10 +0000
committeraab-odoo <aab@odoo.com>2020-02-03 09:15:02 +0000
commit6bdcf054fdeef1b02cbb20bdb00fcba648725f36 (patch)
tree1e61b50fd1fdd57662139b4ec00931f0c0afc8b2 /addons/web/static/tests/component_extension_tests.js
parenta3e24efc19e68dc838f645413cd392a64a9e3d8b (diff)
[IMP] web: custom_hooks: dynamic inheritable event handling
This commit's intention is to bring class inheritance of event handlers to components. Use case: A component class may want to set generic event handlers for all classes inheriting from it, in order to set shared event behavior from the start It is the case in many parts of Odoo, in particular in the cases of fields which need at least to react on some keyboard event for navigation The way to implement such a behavior is to make use of the `useListener` OWL hook, by passing as arguments event name and the handler function
Diffstat (limited to 'addons/web/static/tests/component_extension_tests.js')
-rw-r--r--addons/web/static/tests/component_extension_tests.js138
1 files changed, 138 insertions, 0 deletions
diff --git a/addons/web/static/tests/component_extension_tests.js b/addons/web/static/tests/component_extension_tests.js
index c9fd5906a9f..f0b33db655c 100644
--- a/addons/web/static/tests/component_extension_tests.js
+++ b/addons/web/static/tests/component_extension_tests.js
@@ -6,6 +6,7 @@ odoo.define('web.component_extension_tests', function (require) {
const { Component, tags } = owl;
const { xml } = tags;
+ const { useListener } = require('web.custom_hooks');
QUnit.module("web", function () {
QUnit.module("Component Extension");
@@ -43,5 +44,142 @@ odoo.define('web.component_extension_tests', function (require) {
assert.ok(true, "Promise should still be pending");
});
+
+ QUnit.module("Custom Hooks");
+
+ QUnit.test("useListener handler type", async function (assert) {
+ assert.expect(1);
+
+ class Parent extends Component {
+ constructor() {
+ super();
+ useListener('custom1', '_onCustom1');
+ }
+ }
+ Parent.env = makeTestEnvironment({}, () => Promise.reject());
+ Parent.template = xml`<div/>`;
+
+ assert.throws(() => new Parent(null), 'The handler must be a function');
+ });
+
+ QUnit.test("useListener in inheritance setting", async function (assert) {
+ assert.expect(12);
+ const fixture = document.body.querySelector('#qunit-fixture');
+
+ class Parent extends Component {
+ constructor() {
+ super();
+ useListener('custom1', this._onCustom1);
+ useListener('custom2', this._onCustom2);
+ }
+ _onCustom1() {
+ assert.step(`${this.constructor.name} custom1`);
+ }
+ _onCustom2() {
+ assert.step('parent custom2');
+ }
+ }
+ Parent.env = makeTestEnvironment({}, () => Promise.reject());
+ Parent.template = xml`<div/>`;
+
+ class Child extends Parent {
+ constructor() {
+ super();
+ useListener('custom2', this._onCustom2);
+ useListener('custom3', this._onCustom3);
+ }
+ _onCustom2() {
+ assert.step('overriden custom2');
+ }
+ _onCustom3() {
+ assert.step('child custom3');
+ }
+ }
+
+ const parent = new Parent(null);
+ const child = new Child(null);
+ await parent.mount(fixture);
+ await child.mount(fixture);
+
+ parent.trigger('custom1');
+ assert.verifySteps(['Parent custom1']);
+ parent.trigger('custom2');
+ assert.verifySteps(['parent custom2']);
+ parent.trigger('custom3');
+ assert.verifySteps([]);
+
+ child.trigger('custom1');
+ assert.verifySteps(['Child custom1']);
+ // There are two handlers for that one (Parent and Child)
+ // Although the handler is overriden in Child
+ child.trigger('custom2');
+ assert.verifySteps(['overriden custom2', 'overriden custom2']);
+ child.trigger('custom3');
+ assert.verifySteps(['child custom3']);
+ parent.destroy();
+ child.destroy();
+ });
+
+ QUnit.test("useListener with native JS selector", async function (assert) {
+ assert.expect(3);
+ const fixture = document.body.querySelector('#qunit-fixture');
+
+ class Parent extends Component {
+ constructor() {
+ super();
+ useListener('custom1', 'div .custom-class', this._onCustom1);
+ }
+ _onCustom1() {
+ assert.step(`custom1`);
+ }
+ }
+ Parent.env = makeTestEnvironment({}, () => Promise.reject());
+ Parent.template = xml`
+ <div>
+ <p>no trigger</p>
+ <h1 class="custom-class">triggers</h1>
+ </div>`;
+
+ const parent = new Parent(null);
+ await parent.mount(fixture);
+
+ parent.el.querySelector('p').dispatchEvent(new Event('custom1', {bubbles: true}));
+ assert.verifySteps([]);
+ parent.el.querySelector('h1').dispatchEvent(new Event('custom1', {bubbles: true}));
+ assert.verifySteps(['custom1']);
+ parent.destroy();
+ });
+
+ QUnit.test("useListener with native JS selector delegation", async function (assert) {
+ assert.expect(3);
+ const fixture = document.body.querySelector('#qunit-fixture');
+
+ class Parent extends Component {
+ constructor() {
+ super();
+ useListener('custom1', '.custom-class', this._onCustom1);
+ }
+ _onCustom1() {
+ assert.step(`custom1`);
+ }
+ }
+ Parent.env = makeTestEnvironment({}, () => Promise.reject());
+ Parent.template = xml`
+ <div>
+ <p>no trigger</p>
+ <h1 class="custom-class"><h2>triggers</h2></h1>
+ </div>`;
+
+ fixture.classList.add('custom-class');
+ const parent = new Parent(null);
+ await parent.mount(fixture);
+
+ parent.el.querySelector('p').dispatchEvent(new Event('custom1', {bubbles: true}));
+ assert.verifySteps([]);
+ parent.el.querySelector('h2').dispatchEvent(new Event('custom1', {bubbles: true}));
+ assert.verifySteps(['custom1']);
+ parent.destroy();
+ fixture.classList.remove('custom-class');
+ });
});
});