From f3efba4d949c97c996b0ddfdf01ef1a8ee234827 Mon Sep 17 00:00:00 2001 From: Garrett Murphey Date: Fri, 26 Apr 2019 10:34:33 -0400 Subject: [PATCH] Implement stop-propagation helper. Closes #2. --- addon/helpers/stop-propagation.js | 22 ++++ app/helpers/stop-propagation.js | 4 + .../helpers/stop-propagation-test.js | 112 ++++++++++++++++++ tests/unit/helpers/stop-propagation-test.js | 49 ++++++++ 4 files changed, 187 insertions(+) create mode 100644 addon/helpers/stop-propagation.js create mode 100644 app/helpers/stop-propagation.js create mode 100644 tests/integration/helpers/stop-propagation-test.js create mode 100644 tests/unit/helpers/stop-propagation-test.js diff --git a/addon/helpers/stop-propagation.js b/addon/helpers/stop-propagation.js new file mode 100644 index 0000000..e00c088 --- /dev/null +++ b/addon/helpers/stop-propagation.js @@ -0,0 +1,22 @@ +import { helper } from '@ember/component/helper'; +import { assert } from '@ember/debug'; + +export function stopPropagation([handler]) { + assert( + `Expected '${handler}' to be a function, if present.`, + !handler || typeof handler === 'function' + ); + + return function(event) { + assert( + `Expected '${event}' to be an Event and have a 'stopPropagation' method.`, + event && typeof event.stopPropagation === 'function' + ); + + event.stopPropagation(); + + if (handler) handler(event); + }; +} + +export default helper(stopPropagation); diff --git a/app/helpers/stop-propagation.js b/app/helpers/stop-propagation.js new file mode 100644 index 0000000..4bb5637 --- /dev/null +++ b/app/helpers/stop-propagation.js @@ -0,0 +1,4 @@ +export { + default, + stopPropagation +} from 'ember-event-helpers/helpers/stop-propagation'; diff --git a/tests/integration/helpers/stop-propagation-test.js b/tests/integration/helpers/stop-propagation-test.js new file mode 100644 index 0000000..6875a9e --- /dev/null +++ b/tests/integration/helpers/stop-propagation-test.js @@ -0,0 +1,112 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'ember-qunit'; +import { render, click } from '@ember/test-helpers'; +import hbs from 'htmlbars-inline-precompile'; + +module('Integration | Helper | stop-propagation', function(hooks) { + setupRenderingTest(hooks); + + hooks.beforeEach(function() { + this.onAncestorClick = () => { + throw new Error(`Uncaught 'click' event.`); + }; + }); + + // The rest of this test suite relies on this. + test('a click event propagates up the DOM by default', async function(assert) { + assert.expect(1); + + this.onAncestorClick = () => { + assert.ok(true); + }; + + await render(hbs` +
+ +
+ `); + + await click('button'); + }); + + test('{{on "click" (stop-propagation)}}', async function(assert) { + assert.expect(0); + + await render(hbs` +
+ +
+ `); + + await click('button'); + }); + + test('{{on "click" (stop-propagation) capture=true}}', async function(assert) { + this.outerListener = () => assert.step('outer'); + this.innerListener = () => assert.step('inner'); + + await render(hbs` +
+ +
+ `); + + await click('button'); + + assert.verifySteps(['outer'], 'it only runs the outer listener'); + }); + + test('{{on "click" this.onClick}} {{on "click" (stop-propagation)}}', async function(assert) { + assert.expect(1); + + this.onClick = event => assert.ok(event instanceof Event); + + await render(hbs` +
+ +
+ `); + + await click('button'); + }); + + test('{{on "click" (stop-propagation)}} {{on "click" this.onClick}}', async function(assert) { + assert.expect(1); + + this.onClick = event => assert.ok(event instanceof Event); + + await render(hbs` +
+ +
+ `); + + await click('button'); + }); + + test('{{on "click" (stop-propagation this.onClick)}}', async function(assert) { + assert.expect(1); + + this.onClick = event => assert.ok(event instanceof Event); + + await render(hbs` +
+ +
+ `); + + await click('button'); + }); +}); diff --git a/tests/unit/helpers/stop-propagation-test.js b/tests/unit/helpers/stop-propagation-test.js new file mode 100644 index 0000000..192f02c --- /dev/null +++ b/tests/unit/helpers/stop-propagation-test.js @@ -0,0 +1,49 @@ +import { stopPropagation } from 'ember-event-helpers/helpers/stop-propagation'; +import { module, test } from 'qunit'; + +module('Unit | Helper | stop-propagation', function() { + test('it throws an assertion, when used incorrectly', function(assert) { + assert.expectAssertion(() => { + stopPropagation(['not a function']); + }, `Expected 'not a function' to be a function, if present.`); + + assert.expectAssertion(() => { + stopPropagation([])('not an event'); + }, `Expected 'not an event' to be an Event and have a 'stopPropagation' method.`); + + assert.expectAssertion(() => { + stopPropagation([])({ stopPropagation: 'not a method' }); + }, `Expected '[object Object]' to be an Event and have a 'stopPropagation' method.`); + }); + + test('it works without a handler', function(assert) { + assert.expect(1); + stopPropagation([])({ + stopPropagation: () => assert.ok(true, `it has called 'stopPropagation'`) + }); + }); + + test('it works with a handler', function(assert) { + assert.expect(2); + stopPropagation([() => assert.ok(true, 'it has called the handler')])({ + stopPropagation: () => assert.ok(true, `it has called 'stopPropagation'`) + }); + }); + + test(`it calls 'stopPropagation', even if the handler throws`, function(assert) { + assert.expect(2); + assert.throws( + () => + stopPropagation([ + () => { + throw new Error('foobar'); + } + ])({ + stopPropagation: () => + assert.ok(true, `it has called 'stopPropagation'`) + }), + /foobar/, + 'The error has bubbled up' + ); + }); +});