Skip to content

Commit

Permalink
Implement stop-propagation helper. Closes #2.
Browse files Browse the repository at this point in the history
  • Loading branch information
Garrett Murphey committed Apr 26, 2019
1 parent 8e68e8a commit f3efba4
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 0 deletions.
22 changes: 22 additions & 0 deletions addon/helpers/stop-propagation.js
Original file line number Diff line number Diff line change
@@ -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);
4 changes: 4 additions & 0 deletions app/helpers/stop-propagation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export {
default,
stopPropagation
} from 'ember-event-helpers/helpers/stop-propagation';
112 changes: 112 additions & 0 deletions tests/integration/helpers/stop-propagation-test.js
Original file line number Diff line number Diff line change
@@ -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`
<div {{on "click" this.onAncestorClick}}>
<button>Click me</button>
</div>
`);

await click('button');
});

test('{{on "click" (stop-propagation)}}', async function(assert) {
assert.expect(0);

await render(hbs`
<div {{on "click" this.onAncestorClick}}>
<button {{on "click" (stop-propagation)}}>Click me</button>
</div>
`);

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`
<div {{on "click" (stop-propagation this.outerListener) capture=true}}>
<button {{on "click" this.innerListener}}>inner</button>
</div>
`);

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`
<div {{on "click" this.onAncestorClick}}>
<button
{{on "click" this.onClick}}
{{on "click" (stop-propagation)}}
>
Click me
</button>
</div>
`);

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`
<div {{on "click" this.onAncestorClick}}>
<button
{{on "click" (stop-propagation)}}
{{on "click" this.onClick}}
>
Click me
</button>
</div>
`);

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`
<div {{on "click" this.onAncestorClick}}>
<button {{on "click" (stop-propagation this.onClick)}}>
Click me
</button>
</div>
`);

await click('button');
});
});
49 changes: 49 additions & 0 deletions tests/unit/helpers/stop-propagation-test.js
Original file line number Diff line number Diff line change
@@ -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'
);
});
});

0 comments on commit f3efba4

Please sign in to comment.