Skip to content

Commit

Permalink
Merge pull request #16 from jkusa/test-support
Browse files Browse the repository at this point in the history
Test support helpers
  • Loading branch information
jkusa authored Jan 20, 2017
2 parents c6d3fd7 + b1a18ba commit e4a0824
Show file tree
Hide file tree
Showing 6 changed files with 289 additions and 5 deletions.
105 changes: 105 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,111 @@ The following clipboard.js custom events are sent as actions

More information about the clipboard.js events can be found [here](https://github.com/zenorocha/clipboard.js/#events)

### Test Helpers

Some browsers do not allow simulated clicks to fire `execCommand('copy')`. This makes testing difficult. To assist with integration testing, the following test helpers are available to test the wiring of the `success` and `error` action handlers.

#### Integration Test Helpers

* `triggerSuccess(context, selector='.copy-btn')`
* `triggerError(context, selector='.copy-btn')`

Example:

```js
// tests/integration/components/my-test.js

...

import {
triggerError,
triggerSuccess
} from '../../helpers/ember-cli-clipboard';

...

test('copy-button integration', function(assert) {
assert.expect(2);

this.set('success', () => {
assert.ok(true, '`success` action handler correctly fired');
});

this.set('error', () => {
assert.ok(true, '`error` action handler correctly fired');
});

this.render(hbs`
{{#copy-button
classNames='my-copy-btn'
clipboardText='text to copy'
success=(action success)
error=(action error)
}}
Click To Copy
{{/copy-button}}
`);

triggerError(this, '.my-copy-btn');
triggerSuccess(this, '.my-copy-btn');
});

```

#### Acceptance Test Helpers

* `triggerCopySuccess(selector='.copy-btn')`
* `triggerCopyError(selector='.copy-btn')`

To use the helpers in acceptance tests you need to register them in the `/tests/helpers/start-app.js` file.

```js
// tests/helpers/start-app.js

...

import registerClipboardHelpers from '../helpers/ember-cli-clipboard';

registerClipboardHelpers();

export default function startApp(attrs) {

...

```
Example:
```js
// tests/acceptance/my-test.js

...

test('copy button message', function(assert) {
assert.expect(3);

visit('/');
andThen(() => {
assert.notOk(!!find('.alert').length,
'no alert message is initially present');
});

triggerCopySuccess();

andThen(() => {
assert.ok(!!find('.alert.alert-success').length,
'a success message is displayed when a copy is successful');
});

triggerCopyError();

andThen(() => {
assert.ok(!!find('.alert.alert-info').length,
'an error message is displayed when a copy is unsuccessful');
});
});
```
### Browser Support
For browser support information, checkout the [clipboard.js](http://zenorocha.github.io/clipboard.js/) documentation:
Expand Down
104 changes: 104 additions & 0 deletions test-support/helpers/ember-cli-clipboard.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import Test from 'ember-test';
import Ember from 'ember';

const { run } = Ember;

/* === Integration Test Helpers === */

/**
* Fires `success` action for an instance of a copy-button component
* @function triggerSuccess
* @param {Object} context - integration test’s this context
* @param {String|Element} selector - selector of the copy-button instance
* @returns {Void}
*/
export function triggerSuccess(context, selector) {
fireComponentAction(context, selector, 'success');
}

/**
* Fires `error` action for an instance of a copy-button component
* @function triggerError
* @param {Object} context - integration test’s this context
* @param {String|Element} selector - selector of the copy-button instance
* @returns {Void}
*/
export function triggerError(context, selector) {
fireComponentAction(context, selector, 'error');
}

/* === Acceptance Test Helpers === */

/**
* Default export is a function that registers acceptance test helpers
*/
export default function() {
Test.registerAsyncHelper('triggerCopySuccess', function(app, selector='.copy-btn') {
fireComponentActionFromApp(app, selector, 'success');
});

Test.registerAsyncHelper('triggerCopyError', function(app, selector='.copy-btn') {
fireComponentActionFromApp(app, selector, 'error');
});
}

/* === Private Functions === */

/**
* Fires named action for an instance of a copy-button component in an app
* @function fireComponentActionFromApp
* @param {Object} app - Ember application
* @param {String|Element} selector - selector of the copy-button instance
* @param {String} actionName - name of action
* @returns {Void}
*/
function fireComponentActionFromApp(app, selector, actionName) {
fireComponentAction({
container: app.__container__,
$: app.$
}, selector, actionName);
}

/**
* Fires named action for an instance of a copy-button component
* @function fireComponentAction
* @param {Object} context - test context
* @param {String|Element} selector - selector of the copy-button instance
* @param {String} actionName - name of action
* @returns {Void}
*/
function fireComponentAction(context, selector, actionName) {
let component = getComponentBySelector(context, selector);
fireActionByName(component, actionName);
}

/**
* Fetches component reference for a given context and selector
* @function getComponentBySelector
* @param {Object} context - test context
* @param {String|Element} selector - selector of the copy-button instance
* @returns {Object} component object
*/
function getComponentBySelector(context, selector='.copy-btn') {
let emberId = context.$(selector).attr('id');
return context.container.lookup('-view-registry:main')[emberId];
}

/**
* Fires a component's action given an action name
* @function fireActionByName
* @param {Ember.Component} component - component to fire action from
* @param {String} actionName - name of action
* @returns {Void}
*/
function fireActionByName(component, actionName) {
let action = component[actionName];

run(() => {
if (typeof action === 'string') {
component.sendAction(action);
} else {
action();
}
});
}
4 changes: 3 additions & 1 deletion tests/.jshintrc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
"currentURL",
"currentPath",
"currentRouteName",
"hljs"
"hljs",
"triggerCopySuccess",
"triggerCopyError"
],
"node": false,
"browser": false,
Expand Down
28 changes: 28 additions & 0 deletions tests/acceptance/test-helpers-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { test } from 'qunit';
import moduleForAcceptance from '../../tests/helpers/module-for-acceptance';

moduleForAcceptance('Acceptance | test helpers');

test('test-helpers', function(assert) {
assert.expect(3);

visit('/');
andThen(() => {
assert.notOk(!!find('.alert').length,
'no alert message is initially present');
});

triggerCopySuccess();

andThen(() => {
assert.ok(!!find('.alert.alert-success').length,
'a success message is displayed when a copy is successful');
});

triggerCopyError();

andThen(() => {
assert.ok(!!find('.alert.alert-info').length,
'an error message is displayed when a copy is unsuccessful');
});
});
9 changes: 7 additions & 2 deletions tests/helpers/start-app.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import Ember from 'ember';
import Application from '../../app';
import config from '../../config/environment';
import registerTestHelpers from '../helpers/ember-cli-clipboard';

registerTestHelpers();

const merge = Ember.assign || Ember.merge;

export default function startApp(attrs) {
let application;

// use defaults, but you can override
let attributes = Ember.assign({}, config.APP, attrs);
let attributes = merge({}, config.APP);
attributes = merge(attributes, attrs); // use defaults, but you can override

Ember.run(() => {
application = Application.create(attributes);
Expand Down
44 changes: 42 additions & 2 deletions tests/integration/components/copy-button-test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
import { moduleForComponent, test } from 'ember-qunit';
import hbs from 'htmlbars-inline-precompile';

import {
triggerError,
triggerSuccess
} from '../../helpers/ember-cli-clipboard';

moduleForComponent('copy-button', 'Integration | Component | copy button', {
integration: true
});
Expand Down Expand Up @@ -63,12 +68,47 @@ test('error action fires', function(assert) {
`);

/*
* Can only test error case here b/c browsers do not allow simulated
* clicks for `execCommand('copy')`
* Can only directly test error case here b/c browsers do not allow simulated
* clicks for `execCommand('copy')`. See test-helpers to test action integration.
*/
this.$('button').click();
});

test('test-helpers fire correct actions', function(assert) {
assert.expect(2);

this.on('success', () => {
assert.notOk(true, 'success action incorrectly fired');
});

this.set('error', () => {
assert.ok(true, 'triggerError correctly fired `error` action for selector');
});

this.render(hbs`
{{#copy-button
classNames='my-copy-btn'
clipboardText='text'
success='success'
error=(action error)
}}
Click To Copy
{{/copy-button}}
`);

triggerError(this, '.my-copy-btn');

this.set('error', () => {
assert.notOk(true, 'error action incorrectly fired');
});

this.on('success', () => {
assert.ok(true, 'triggerSuccess correctly fired `success` action for selector');
});

triggerSuccess(this);
});

test('button is not disabled by default', function(assert) {
assert.expect(1);

Expand Down

0 comments on commit e4a0824

Please sign in to comment.