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/component_extension_tests.js | |
| parent | 0a15094050bfde69a06d6eff798e9a8ddf2b8c21 (diff) | |
initial commit 2
Diffstat (limited to 'addons/web/static/tests/component_extension_tests.js')
| -rw-r--r-- | addons/web/static/tests/component_extension_tests.js | 252 |
1 files changed, 252 insertions, 0 deletions
diff --git a/addons/web/static/tests/component_extension_tests.js b/addons/web/static/tests/component_extension_tests.js new file mode 100644 index 00000000..08f5071e --- /dev/null +++ b/addons/web/static/tests/component_extension_tests.js @@ -0,0 +1,252 @@ +odoo.define('web.component_extension_tests', function (require) { + "use strict"; + + const makeTestEnvironment = require("web.test_env"); + const testUtils = require("web.test_utils"); + + const { Component, tags } = owl; + const { xml } = tags; + const { useListener } = require('web.custom_hooks'); + + QUnit.module("web", function () { + QUnit.module("Component Extension"); + + QUnit.test("Component destroyed while performing successful RPC", async function (assert) { + assert.expect(1); + + class Parent extends Component {} + Parent.env = makeTestEnvironment({}, () => Promise.resolve()); + Parent.template = xml`<div/>`; + + const parent = new Parent(); + + parent.rpc({}).then(() => { throw new Error(); }); + parent.destroy(); + + await testUtils.nextTick(); + + assert.ok(true, "Promise should still be pending"); + }); + + QUnit.test("Component destroyed while performing failed RPC", async function (assert) { + assert.expect(1); + + class Parent extends Component {} + Parent.env = makeTestEnvironment({}, () => Promise.reject()); + Parent.template = xml`<div/>`; + + const parent = new Parent(); + + parent.rpc({}).catch(() => { throw new Error(); }); + parent.destroy(); + + await testUtils.nextTick(); + + 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'); + }); + + QUnit.test("useListener with capture option", async function (assert) { + assert.expect(7); + const fixture = document.body.querySelector('#qunit-fixture'); + + class Leaf extends Component { + constructor() { + super(); + useListener('custom1', this._onCustom1); + } + _onCustom1() { + assert.step(`${this.constructor.name} custom1`); + } + } + Leaf.template = xml`<div class="leaf"/>`; + + class Root extends Component { + constructor() { + super(); + useListener('custom1', this._onCustom1, { capture: true }); + } + _onCustom1(event) { + assert.step(`${this.constructor.name} custom1`); + const detail = event.detail; + if (detail && detail.stopMe) { + event.stopPropagation(); + } + } + } + Root.template = xml`<div class="root"><Leaf/></div>`; + Root.components = { Leaf }; + + const root = new Root(null); + await root.mount(fixture); + + const rootNode = document.body.querySelector('.root'); + const leafNode = document.body.querySelector('.leaf'); + rootNode.dispatchEvent(new CustomEvent('custom1', { + bubbles: true, + cancelable: true + })); + assert.verifySteps(['Root custom1']); + + // Dispatch custom1 on the leaf element. + // Since we listen in the capture phase, Root is first triggered. + // The event is stopped there. + leafNode.dispatchEvent(new CustomEvent('custom1', { + bubbles: true, + cancelable: true, + detail: { + stopMe: true + }, + })); + assert.verifySteps(['Root custom1']); + + // Same as before, except this time we don't stop the event + leafNode.dispatchEvent(new CustomEvent('custom1', { + bubbles: true, + cancelable: true, + detail: { + stopMe: false + } + })); + assert.verifySteps(['Root custom1', 'Leaf custom1']); + + root.destroy(); + }); + }); +}); |
