From 50257c38b6da29efc852b54e733f60fc6f2ebaa6 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Mon, 9 Jan 2017 18:18:25 +0100 Subject: [PATCH 1/8] Add linting for "addon" and "app" folders --- addon/.eslintrc.js | 9 +++++++++ app/.eslintrc.js | 9 +++++++++ package.json | 2 +- 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 addon/.eslintrc.js create mode 100644 app/.eslintrc.js diff --git a/addon/.eslintrc.js b/addon/.eslintrc.js new file mode 100644 index 00000000..033f9d64 --- /dev/null +++ b/addon/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + }, + env: { + node: true + }, +}; diff --git a/app/.eslintrc.js b/app/.eslintrc.js new file mode 100644 index 00000000..033f9d64 --- /dev/null +++ b/app/.eslintrc.js @@ -0,0 +1,9 @@ +module.exports = { + parserOptions: { + ecmaVersion: 6, + sourceType: 'module', + }, + env: { + node: true + }, +}; diff --git a/package.json b/package.json index 7d596e5f..cfa67418 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,7 @@ "repository": "https://github.com/simplabs/ember-test-selectors", "scripts": { "build": "ember build", - "lint": "eslint config test-support tests *.js", + "lint": "eslint addon app config test-support tests *.js", "start": "ember server", "test": "npm run test:keep && npm run test:strip", "test:all": "ember try:each", From af385c6c346bbacb698ed0dc94d1097e78c488ff Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 10 Jan 2017 10:13:32 +0100 Subject: [PATCH 2/8] Adjust addon name to "ember-test-selectors" --- index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.js b/index.js index 5f78a186..0154706b 100644 --- a/index.js +++ b/index.js @@ -2,7 +2,7 @@ 'use strict'; module.exports = { - name: 'test-selectors', + name: 'ember-test-selectors', _assignOptions: function(app) { var ui = app.project.ui; From 0d31bc06e76204940c017e92f7393c4fad8ca40e Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 10 Jan 2017 10:25:06 +0100 Subject: [PATCH 3/8] Add "bind-data-test-attributes" utility function --- addon/utils/bind-data-test-attributes.js | 13 ++++ .../utils/bind-data-test-attributes-test.js | 77 +++++++++++++++++++ 2 files changed, 90 insertions(+) create mode 100644 addon/utils/bind-data-test-attributes.js create mode 100644 tests/unit/utils/bind-data-test-attributes-test.js diff --git a/addon/utils/bind-data-test-attributes.js b/addon/utils/bind-data-test-attributes.js new file mode 100644 index 00000000..89f8a72a --- /dev/null +++ b/addon/utils/bind-data-test-attributes.js @@ -0,0 +1,13 @@ +const TEST_SELECTOR_PREFIX = /data-test-.*/; + +export default function bindDataTestAttributes(component) { + let attributeBindings = component.getWithDefault('attributeBindings', []); + + for (let attr in component) { + if (TEST_SELECTOR_PREFIX.test(attr)) { + attributeBindings.push(attr); + } + } + + component.set('attributeBindings', attributeBindings); +} diff --git a/tests/unit/utils/bind-data-test-attributes-test.js b/tests/unit/utils/bind-data-test-attributes-test.js new file mode 100644 index 00000000..30b1981f --- /dev/null +++ b/tests/unit/utils/bind-data-test-attributes-test.js @@ -0,0 +1,77 @@ +import { module, test } from 'qunit'; +import Ember from 'ember'; + +import bindDataTestAttributes from 'ember-test-selectors/utils/bind-data-test-attributes'; + +module('Unit | Utility | bind data test attributes'); + +test('it adds missing attributeBindings array', function(assert) { + let Fixture = Ember.Object.extend({ + 'data-test-from-factory': 'foo', + }); + let instance = Fixture.create({ + 'data-test-from-invocation': 'bar', + }); + + assert.deepEqual(instance.get('attributeBindings'), undefined); + + bindDataTestAttributes(instance); + + assert.deepEqual(instance.get('attributeBindings'), + ['data-test-from-invocation', 'data-test-from-factory']); +}); + +test('it adds to existing attributeBindings array', function(assert) { + let Fixture = Ember.Object.extend({ + attributeBindings: ['foo', 'bar'], + + foo: 1, + bar: 2, + + 'data-test-from-factory': 'foo', + }); + let instance = Fixture.create({ + 'data-test-from-invocation': 'bar', + }); + + assert.deepEqual(instance.get('attributeBindings'), ['foo', 'bar']); + + bindDataTestAttributes(instance); + + assert.deepEqual(instance.get('attributeBindings'), + ['foo', 'bar', 'data-test-from-invocation', 'data-test-from-factory']); +}); + +test('it only adds data-test-* properties', function(assert) { + let Fixture = Ember.Object.extend({ + foo: 1, + bar: 2, + + 'data-test-from-factory': 'foo', + }); + let instance = Fixture.create({ + baz: 3, + + 'data-test-from-invocation': 'bar', + }); + + assert.deepEqual(instance.get('attributeBindings'), undefined); + + bindDataTestAttributes(instance); + + assert.deepEqual(instance.get('attributeBindings'), + ['data-test-from-invocation', 'data-test-from-factory']); +}); + +test('it does not add a data-test property', function(assert) { + let Fixture = Ember.Object.extend({ + 'data-test': 'foo', + }); + let instance = Fixture.create(); + + assert.deepEqual(instance.get('attributeBindings'), undefined); + + bindDataTestAttributes(instance); + + assert.deepEqual(instance.get('attributeBindings'), []); +}); From 3e69cc5ce29833c19701f2d9a84b85738db38f6b Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 10 Jan 2017 10:51:48 +0100 Subject: [PATCH 4/8] Add "ember-test-selectors" initializer ... that reopens the Component class and automatically binds all data-test-* attributes --- addon/initializers/ember-test-selectors.js | 16 ++++++ app/initializers/ember-test-selectors.js | 1 + ...data-test-attributes-in-components-test.js | 51 +++++++++++++++++++ tests/dummy/app/router.js | 1 + tests/dummy/app/templates/bind-test.hbs | 11 ++++ 5 files changed, 80 insertions(+) create mode 100644 addon/initializers/ember-test-selectors.js create mode 100644 app/initializers/ember-test-selectors.js create mode 100644 tests/acceptance/bind-data-test-attributes-in-components-test.js create mode 100644 tests/dummy/app/templates/bind-test.hbs diff --git a/addon/initializers/ember-test-selectors.js b/addon/initializers/ember-test-selectors.js new file mode 100644 index 00000000..80d05039 --- /dev/null +++ b/addon/initializers/ember-test-selectors.js @@ -0,0 +1,16 @@ +import Ember from 'ember'; +import bindDataTestAttributes from '../utils/bind-data-test-attributes'; + +function initialize(/* application */) { + Ember.Component.reopen({ + init() { + bindDataTestAttributes(this); + this._super(...arguments); + } + }); +} + +export default { + name: 'ember-test-selectors', + initialize +}; diff --git a/app/initializers/ember-test-selectors.js b/app/initializers/ember-test-selectors.js new file mode 100644 index 00000000..9487acb8 --- /dev/null +++ b/app/initializers/ember-test-selectors.js @@ -0,0 +1 @@ +export { default } from 'ember-test-selectors/initializers/ember-test-selectors'; diff --git a/tests/acceptance/bind-data-test-attributes-in-components-test.js b/tests/acceptance/bind-data-test-attributes-in-components-test.js new file mode 100644 index 00000000..3562f661 --- /dev/null +++ b/tests/acceptance/bind-data-test-attributes-in-components-test.js @@ -0,0 +1,51 @@ +import { test } from 'qunit'; +import moduleForAcceptance from '../../tests/helpers/module-for-acceptance'; + +import config from 'dummy/config/environment'; + +if (!config.stripTestSelectors) { + + /* + * We use an acceptance test here to test the "ember-test-selectors" initializer, + * because initializers are only applied in acceptance tests, but not in + * component integration tests. + */ + moduleForAcceptance('Acceptance | Initializer | ember-test-selectors', { + beforeEach() { + visit('/bind-test'); + }, + }); + + test('it binds data-test-* attributes on components', function (assert) { + assert.equal(find('.test1').find('div[data-test-first]').length, 1, 'data-test-first exists'); + assert.equal(find('.test1').find('div[data-test-first="foobar"]').length, 1, 'data-test-first has correct value'); + }); + + test('it binds data-test-* attributes on components in block form', function (assert) { + assert.equal(find('.test2').find('div[data-test-first]').length, 1, 'data-test-first exists'); + assert.equal(find('.test2').find('div[data-test-first="foobar"]').length, 1, 'data-test-first has correct value'); + }); + + test('it works with multiple data-test-* attributes on components', function (assert) { + assert.equal(find('.test3').find('div[data-test-first]').length, 1, 'data-test-first exists'); + assert.equal(find('.test3').find('div[data-test-first="foobar"]').length, 1, 'data-test-first has correct value'); + assert.equal(find('.test3').find('div[data-test-second]').length, 1, 'data-test-second exists'); + assert.equal(find('.test3').find('div[data-test-second="second"]').length, 1, 'data-test-second has correct value'); + }); + + test('it leaves other data attributes untouched, when a data-test-* attribute is present as well on components', function (assert) { + assert.equal(find('.test4').find('div[data-test-first]').length, 1, 'data-test-first exists'); + assert.equal(find('.test4').find('div[data-test-first="foobar"]').length, 1, 'data-test-first has correct value'); + assert.equal(find('.test4').find('div[data-non-test]').length, 0, 'data-non-test does not exists'); + }); + + test('it leaves data-test attributes untouched on components', function (assert) { + assert.equal(find('.test5').find('div[data-test]').length, 0, 'data-test does not exists'); + }); + + test('it leaves other data attributes untouched on components', function (assert) { + assert.equal(find('.test6').find('div[data-non-test]').length, 0, 'data-non-test does not exists'); + }); + +} + diff --git a/tests/dummy/app/router.js b/tests/dummy/app/router.js index cdc25787..3ae2f797 100644 --- a/tests/dummy/app/router.js +++ b/tests/dummy/app/router.js @@ -7,6 +7,7 @@ const Router = Ember.Router.extend({ }); Router.map(function() { + this.route('bind-test'); }); export default Router; diff --git a/tests/dummy/app/templates/bind-test.hbs b/tests/dummy/app/templates/bind-test.hbs new file mode 100644 index 00000000..98364b18 --- /dev/null +++ b/tests/dummy/app/templates/bind-test.hbs @@ -0,0 +1,11 @@ +
{{data-test-component data-test-first="foobar"}}
+ +
{{#data-test-component data-test-first="foobar"}}hello{{/data-test-component}}
+ +
{{data-test-component data-test-first="foobar" data-test-second="second"}}
+ +
{{data-test-component data-test-first="foobar" data-non-test="baz"}}
+ +
{{data-test-component data-test="foo"}}
+ +
{{data-test-component data-non-test="foo"}}
From 151aad032abb680be1bc320c8a6b1e4473903c4b Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 10 Jan 2017 11:18:17 +0100 Subject: [PATCH 5/8] Strip "app" and "addon" folders from the build --- index.js | 26 +++++++++++++++++++++++++- package.json | 1 + 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 0154706b..da4535ad 100644 --- a/index.js +++ b/index.js @@ -37,5 +37,29 @@ module.exports = { }); } } - } + }, + + treeForAddon: function() { + // remove our "addon" folder from the build if we're stripping test selectors + if (!this._stripTestSelectors) { + return this._super.treeForAddon.apply(this, arguments); + } + }, + + treeForApp: function() { + // remove our "app" folder from the build if we're stripping test selectors + if (!this._stripTestSelectors) { + return this._super.treeForApp.apply(this, arguments); + } + }, + + preprocessTree: function(type, tree) { + // remove the unit tests if we're testing ourself and are in strip mode. + // we do this because these tests depend on the "addon" and "app" folders being available, + // which is not the case if they are stripped out of the build. + if (type === 'test' && this._stripTestSelectors && this.project.name() === 'ember-test-selectors') { + tree = require('broccoli-stew').rm(tree, 'dummy/tests/unit/**/*.js'); + } + return tree; + }, }; diff --git a/package.json b/package.json index cfa67418..d9fb5506 100644 --- a/package.json +++ b/package.json @@ -26,6 +26,7 @@ }, "devDependencies": { "broccoli-asset-rev": "^2.4.5", + "broccoli-stew": "^1.4.0", "ember-ajax": "^2.4.1", "ember-cli": "2.10.0", "ember-cli-app-version": "^2.0.0", From b75c9f4fcd69fea6c092d93d1cdf88b5a3422228 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 10 Jan 2017 13:00:50 +0100 Subject: [PATCH 6/8] initializers/ember-test-selectors: Apply bindDataTestAttributes() after super() --- addon/initializers/ember-test-selectors.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addon/initializers/ember-test-selectors.js b/addon/initializers/ember-test-selectors.js index 80d05039..a6487301 100644 --- a/addon/initializers/ember-test-selectors.js +++ b/addon/initializers/ember-test-selectors.js @@ -4,8 +4,8 @@ import bindDataTestAttributes from '../utils/bind-data-test-attributes'; function initialize(/* application */) { Ember.Component.reopen({ init() { - bindDataTestAttributes(this); this._super(...arguments); + bindDataTestAttributes(this); } }); } From 7868eda2a8b3912172a4bca482b62eb1d962cbe5 Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Tue, 10 Jan 2017 13:26:55 +0100 Subject: [PATCH 7/8] utils/bind-data-test-attributes: Skip and print warning for computed property --- addon/utils/bind-data-test-attributes.js | 12 ++++++++++ .../utils/bind-data-test-attributes-test.js | 23 +++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/addon/utils/bind-data-test-attributes.js b/addon/utils/bind-data-test-attributes.js index 89f8a72a..3996702c 100644 --- a/addon/utils/bind-data-test-attributes.js +++ b/addon/utils/bind-data-test-attributes.js @@ -1,6 +1,18 @@ +import Ember from 'ember'; + const TEST_SELECTOR_PREFIX = /data-test-.*/; export default function bindDataTestAttributes(component) { + let computedBindings = component.attributeBindings && component.attributeBindings.isDescriptor; + if (computedBindings) { + let message = `ember-test-selectors could not bind data-test-* properties on ${component} ` + + `automatically because attributeBindings is a computed property.`; + + return Ember.warn(message, false, { + id: 'ember-test-selectors.computed-attribute-bindings', + }); + } + let attributeBindings = component.getWithDefault('attributeBindings', []); for (let attr in component) { diff --git a/tests/unit/utils/bind-data-test-attributes-test.js b/tests/unit/utils/bind-data-test-attributes-test.js index 30b1981f..b468934a 100644 --- a/tests/unit/utils/bind-data-test-attributes-test.js +++ b/tests/unit/utils/bind-data-test-attributes-test.js @@ -75,3 +75,26 @@ test('it does not add a data-test property', function(assert) { assert.deepEqual(instance.get('attributeBindings'), []); }); + +test('it skips if attributeBindings is a computed property', function(assert) { + let Fixture = Ember.Object.extend({ + attributeBindings: Ember.computed('prop', function() { + return [this.get('prop')]; + }).readOnly(), + + foo: 5, + + 'data-test-from-factory': 'foo', + }); + let instance = Fixture.create({ + prop: 'foo', + + 'data-test-from-invocation': 'bar', + }); + + assert.deepEqual(instance.get('attributeBindings'), ['foo']); + + bindDataTestAttributes(instance); + + assert.deepEqual(instance.get('attributeBindings'), ['foo']); +}); From f48e6ad216c3c60b6e983eb0a4b962226855b86c Mon Sep 17 00:00:00 2001 From: Tobias Bieniek Date: Wed, 11 Jan 2017 09:58:10 +0100 Subject: [PATCH 8/8] utils/bind-data-test-attributes: Convert string to array if necessary --- addon/utils/bind-data-test-attributes.js | 4 ++++ .../utils/bind-data-test-attributes-test.js | 20 +++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/addon/utils/bind-data-test-attributes.js b/addon/utils/bind-data-test-attributes.js index 3996702c..09f8cb9f 100644 --- a/addon/utils/bind-data-test-attributes.js +++ b/addon/utils/bind-data-test-attributes.js @@ -15,6 +15,10 @@ export default function bindDataTestAttributes(component) { let attributeBindings = component.getWithDefault('attributeBindings', []); + if (!Ember.isArray(attributeBindings)) { + attributeBindings = [attributeBindings]; + } + for (let attr in component) { if (TEST_SELECTOR_PREFIX.test(attr)) { attributeBindings.push(attr); diff --git a/tests/unit/utils/bind-data-test-attributes-test.js b/tests/unit/utils/bind-data-test-attributes-test.js index b468934a..284963ff 100644 --- a/tests/unit/utils/bind-data-test-attributes-test.js +++ b/tests/unit/utils/bind-data-test-attributes-test.js @@ -42,6 +42,26 @@ test('it adds to existing attributeBindings array', function(assert) { ['foo', 'bar', 'data-test-from-invocation', 'data-test-from-factory']); }); +test('it converts existing attributeBindings string to array', function(assert) { + let Fixture = Ember.Object.extend({ + attributeBindings: 'foo', + + foo: 1, + + 'data-test-from-factory': 'foo', + }); + let instance = Fixture.create({ + 'data-test-from-invocation': 'bar', + }); + + assert.deepEqual(instance.get('attributeBindings'), 'foo'); + + bindDataTestAttributes(instance); + + assert.deepEqual(instance.get('attributeBindings'), + ['foo', 'data-test-from-invocation', 'data-test-from-factory']); +}); + test('it only adds data-test-* properties', function(assert) { let Fixture = Ember.Object.extend({ foo: 1,