diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a32435fe..c6d66a6e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -65,6 +65,7 @@ jobs: - ember-canary - ember-default-with-jquery - ember-classic + - embroider-safe steps: - uses: actions/checkout@v2 diff --git a/addon/services/metrics.js b/addon/services/metrics.js index 9582461c..07761b72 100644 --- a/addon/services/metrics.js +++ b/addon/services/metrics.js @@ -39,6 +39,14 @@ export default class Metrics extends Service { */ enabled = true; + /** + * Information about the active adapters from environment.js + * + * I think this could have been isolated to the init method only, but since + * was public before, would have been a breaking change + */ + options; + /** * When the Service is created, activate adapters that were specified in the * configuration. This config is injected into the Service as @@ -49,8 +57,13 @@ export default class Metrics extends Service { * @return {Void} */ init() { - const adapters = this.options.metricsAdapters || emberArray(); const owner = getOwner(this); + const config = owner.factoryFor('config:environment').class; + const {metricsAdapters = []} = config; + const {environment = 'development'} = config; + this.options = {metricsAdapters, environment} + + const adapters = this.options.metricsAdapters || emberArray(); owner.registerOptionsForType('ember-metrics@metrics-adapter', { instantiate: false }); owner.registerOptionsForType('metrics-adapter', { instantiate: false }); diff --git a/app/initializers/metrics.js b/app/initializers/metrics.js deleted file mode 100644 index 7e30cdcf..00000000 --- a/app/initializers/metrics.js +++ /dev/null @@ -1,16 +0,0 @@ -import config from '../config/environment'; - -export function initialize() { - const application = arguments[1] || arguments[0]; - const { metricsAdapters = [] } = config; - const { environment = 'development' } = config; - const options = { metricsAdapters, environment }; - - application.register('config:metrics', options, { instantiate: false }); - application.inject('service:metrics', 'options', 'config:metrics'); -} - -export default { - name: 'metrics', - initialize -}; diff --git a/config/ember-try.js b/config/ember-try.js index d0c69bbb..231b10a6 100644 --- a/config/ember-try.js +++ b/config/ember-try.js @@ -1,6 +1,7 @@ "use strict"; const getChannelURL = require("ember-source-channel-url"); +const { embroiderSafe } = require('@embroider/test-setup'); module.exports = async function () { return { @@ -74,6 +75,13 @@ module.exports = async function () { }, }, }, + embroiderSafe({ + npm: { + devDependencies: { + "webpack": '^5.0.0', + }, + }, + }), ], }; }; diff --git a/ember-cli-build.js b/ember-cli-build.js index dc5a39e1..d721fe09 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -14,5 +14,6 @@ module.exports = function(defaults) { behave. You most likely want to be modifying `./index.js` or app's build file */ - return app.toTree(); + const { maybeEmbroider } = require('@embroider/test-setup'); + return maybeEmbroider(app); }; diff --git a/package.json b/package.json index 69ef0063..f28c74a0 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ ], "devDependencies": { "@ember/optional-features": "^2.0.0", + "@embroider/test-setup": "^0.40.0", "babel-eslint": "^10.1.0", "broccoli-asset-rev": "^3.0.0", "ember-cli": "~3.21.2", diff --git a/tests/unit/services/metrics-test.js b/tests/unit/services/metrics-test.js index 85cb2816..d399952c 100644 --- a/tests/unit/services/metrics-test.js +++ b/tests/unit/services/metrics-test.js @@ -1,10 +1,9 @@ -import { set, get } from '@ember/object'; +import { set } from '@ember/object'; import { module, test } from 'qunit'; import { setupTest } from 'ember-qunit'; import sinon from 'sinon'; -const environment = 'test'; -let sandbox, metricsAdapters, options; +let sandbox, service; module('Unit | Service | metrics', function(hooks) { setupTest(hooks); @@ -12,7 +11,8 @@ module('Unit | Service | metrics', function(hooks) { hooks.beforeEach(function() { sandbox = sinon.createSandbox(); - metricsAdapters = [ + service = this.owner.factoryFor('service:metrics').create(); + service.activateAdapters([ { name: 'GoogleAnalytics', environments: ['all'], @@ -34,12 +34,7 @@ module('Unit | Service | metrics', function(hooks) { foo: 'bar' } } - ]; - - options = { - metricsAdapters, - environment - }; + ]); }); hooks.afterEach(function() { @@ -48,31 +43,17 @@ module('Unit | Service | metrics', function(hooks) { delete window.mixpanel; }); - test('it creates adapters with owners (for container/injection purposes)', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); - - get(service, '_adapters.LocalDummyAdapter'); - let owner = this.owner; - - assert.ok(owner); - }); - test('it activates local adapters', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); - - assert.ok(get(service, '_adapters.LocalDummyAdapter'), 'it activated the LocalDummyAdapter'); - assert.equal(get(service, '_adapters.LocalDummyAdapter.config.foo'), 'bar', 'it passes config options to the LocalDummyAdapter'); + assert.ok(service._adapters.LocalDummyAdapter, 'it activated the LocalDummyAdapter'); + assert.equal(service._adapters.LocalDummyAdapter.config.foo, 'bar', 'it passes config options to the LocalDummyAdapter'); }); test('#activateAdapters activates an array of adapters', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); - - assert.ok(get(service, '_adapters.GoogleAnalytics'), 'it activated the GoogleAnalytics adapter'); - assert.equal(get(service, '_adapters.GoogleAnalytics.config.id'), 'UA-XXXX-Y', 'it passes config options to the GoogleAnalytics adapter'); + assert.ok(service._adapters.GoogleAnalytics, 'it activated the GoogleAnalytics adapter'); + assert.equal(service._adapters.GoogleAnalytics.config.id, 'UA-XXXX-Y', 'it passes config options to the GoogleAnalytics adapter'); }); test('#activateAdapters is idempotent', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); service.activateAdapters([ { name: 'GoogleAnalytics', @@ -96,17 +77,16 @@ module('Unit | Service | metrics', function(hooks) { } } ]); - assert.equal(get(service, '_adapters.GoogleAnalytics.config.id'), 'UA-XXXX-Y', 'it does not override the GoogleAnalytics adapter'); - assert.equal(get(service, '_adapters.Mixpanel.config.token'), '0f76c037-4d76-4fce-8a0f-a9a8f89d1453', 'it does not override the Mixpanel adapter'); - assert.equal(get(service, '_adapters.LocalDummyAdapter.config.foo'), 'bar', 'it does not override the LocalDummyAdapter'); + assert.equal(service._adapters.GoogleAnalytics.config.id, 'UA-XXXX-Y', 'it does not override the GoogleAnalytics adapter'); + assert.equal(service._adapters.Mixpanel.config.token, '0f76c037-4d76-4fce-8a0f-a9a8f89d1453', 'it does not override the Mixpanel adapter'); + assert.equal(service._adapters.LocalDummyAdapter.config.foo, 'bar', 'it does not override the LocalDummyAdapter'); }); test('#invoke invokes the named method on activated adapters', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); const MixpanelStub = sandbox.stub(window.mixpanel, 'identify'); const GoogleAnalyticsStub = sandbox.stub(window, 'ga'); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'identify'); - const MixpanelSpy = sandbox.spy(get(service, '_adapters.Mixpanel'), 'identify'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'identify'); + const MixpanelSpy = sandbox.spy(service._adapters.Mixpanel, 'identify'); const opts = { userId: '1e810c197e', name: 'Bill Limbergh', @@ -123,10 +103,9 @@ module('Unit | Service | metrics', function(hooks) { }); test('#invoke invokes the named method on a single activated adapter', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); const GoogleAnalyticsStub = sandbox.stub(window, 'ga'); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'trackEvent'); - const MixpanelSpy = sandbox.spy(get(service, '_adapters.Mixpanel'), 'trackEvent'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'trackEvent'); + const MixpanelSpy = sandbox.spy(service._adapters.Mixpanel, 'trackEvent'); const opts = { userId: '1e810c197e', name: 'Bill Limbergh', @@ -141,12 +120,11 @@ module('Unit | Service | metrics', function(hooks) { }); test('#invoke invokes the named methods on a whitelist of activated adapters', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); const MixpanelStub = sandbox.stub(window.mixpanel, 'identify'); const GoogleAnalyticsStub = sandbox.stub(window, 'ga'); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'identify'); - const MixpanelSpy = sandbox.spy(get(service, '_adapters.Mixpanel'), 'identify'); - const LocalDummyAdapterSpy = sandbox.spy(get(service, '_adapters.LocalDummyAdapter'), 'trackEvent'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'identify'); + const MixpanelSpy = sandbox.spy(service._adapters.Mixpanel, 'identify'); + const LocalDummyAdapterSpy = sandbox.spy(service._adapters.LocalDummyAdapter, 'trackEvent'); const opts = { userId: '1e810c197e', name: 'Bill Limbergh', @@ -164,15 +142,13 @@ module('Unit | Service | metrics', function(hooks) { }); test("#invoke doesn't error when asked to use a single deactivated adapter", function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); service.invoke('trackEvent', 'Trackmaster2000', {}); assert.ok(true, 'No exception was thrown'); }); test('#invoke invokes the named method on a single activated adapter with no arguments', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); const GoogleAnalyticsStub = sandbox.stub(window, 'ga'); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'trackPage'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'trackPage'); service.invoke('trackPage', 'GoogleAnalytics'); assert.ok(GoogleAnalyticsSpy.calledOnce, 'it invokes the track method on the adapter'); @@ -180,8 +156,7 @@ module('Unit | Service | metrics', function(hooks) { }); test('#invoke includes `context` properties', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'trackPage'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'trackPage'); set(service, 'context.userName', 'Jimbo'); service.invoke('trackPage', 'GoogleAnalytics', { page: 'page/1', title: 'page one' }); @@ -190,8 +165,7 @@ module('Unit | Service | metrics', function(hooks) { }); test('#invoke does not leak options between calls', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'trackPage'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'trackPage'); set(service, 'context.userName', 'Jimbo'); service.invoke('trackPage', 'GoogleAnalytics', { page: 'page/1', title: 'page one', callOne: true }); @@ -201,8 +175,7 @@ module('Unit | Service | metrics', function(hooks) { }); test('it can be disabled', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); - const GoogleAnalyticsSpy = sandbox.spy(get(service, '_adapters.GoogleAnalytics'), 'trackPage'); + const GoogleAnalyticsSpy = sandbox.spy(service._adapters.GoogleAnalytics, 'trackPage'); set(service, 'enabled', false); service.invoke('trackPage', 'GoogleAnalytics', { page: 'page/1', title: 'page one' }); @@ -211,7 +184,6 @@ module('Unit | Service | metrics', function(hooks) { }); test('it implements standard contracts', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ options }); delete window.mixpanel.toString; sandbox.stub(window.mixpanel); sandbox.stub(window, 'ga'); @@ -228,54 +200,44 @@ module('Unit | Service | metrics', function(hooks) { }); test('it does not activate adapters that are not in the current app environment', function(assert) { - const service = this.owner.factoryFor('service:metrics').create({ - options: { - metricsAdapters: [ - { - name: 'GoogleAnalytics', - config: { - id: 'UA-XXXX-Y' - } - }, - { - name: 'LocalDummyAdapter', - environments: ['production'], - config: { - foo: 'bar' - } - } - ] + service.activateAdapters([ + { + name: 'GoogleAnalytics', + config: { + id: 'UA-XXXX-Y' + } }, - environment - }); + { + name: 'LocalDummyAdapter', + environments: ['production'], + config: { + foo: 'bar' + } + } + ]); - assert.ok(get(service, '_adapters.GoogleAnalytics'), 'it activated the GoogleAnalytics adapter'); - assert.notOk(get(service, '_adapters.LocalDummyAdapter'), 'it did not activate the LocalDummyAdapter'); + assert.ok(service._adapters.GoogleAnalytics, 'it activated the GoogleAnalytics adapter'); + assert.notOk(service._adapters.LocalDummyAdapter, 'it did not activate the LocalDummyAdapter'); }); test('when in FastBoot env, it does not activate adapters that are not FastBoot-enabled', function(assert) { window.FastBoot = true; - const service = this.owner.factoryFor('service:metrics').create({ - options: { - metricsAdapters: [ - { - name: 'GoogleAnalytics', - config: { - id: 'UA-XXXX-Y' - } - }, - { - name: 'LocalDummyAdapter', - config: { - foo: 'bar' - } - } - ] + service.activateAdapters([ + { + name: 'GoogleAnalytics', + config: { + id: 'UA-XXXX-Y' + } }, - environment - }); + { + name: 'LocalDummyAdapter', + config: { + foo: 'bar' + } + } + ]); - assert.notOk(get(service, '_adapters.GoogleAnalytics'), 'it did not activate the GoogleAnalytics adapter'); - assert.ok(get(service, '_adapters.LocalDummyAdapter'), 'it activated the LocalDummyAdapter'); + assert.notOk(service._adapters.GoogleAnalytics, 'it did not activate the GoogleAnalytics adapter'); + assert.ok(service._adapters.LocalDummyAdapter, 'it activated the LocalDummyAdapter'); }); }); diff --git a/yarn.lock b/yarn.lock index cc822d66..8bd7e535 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2383,6 +2383,14 @@ ember-cli-htmlbars-inline-precompile "^2.1.0" ember-test-waiters "^1.1.1" +"@embroider/test-setup@^0.40.0": + version "0.40.0" + resolved "https://registry.yarnpkg.com/@embroider/test-setup/-/test-setup-0.40.0.tgz#bff8e7d780c1ba1a349f9e51605c9668a8f2c65d" + integrity sha512-Ukk7KDviBd7Ro181WPGp+Sk/fZpD7Os0tJ5msf/2TsCUL631cAQKkUqGjQsva+jJYQnqbB3pxF1fR5fnY3x3ug== + dependencies: + lodash "^4.17.20" + resolve "^1.17.0" + "@eslint/eslintrc@^0.1.3": version "0.1.3" resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.1.3.tgz#7d1a2b2358552cc04834c0979bd4275362e37085" @@ -7819,6 +7827,11 @@ lodash@^4.17.19: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== +lodash@^4.17.20: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + log-symbols@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-2.2.0.tgz#5740e1c5d6f0dfda4ad9323b5332107ef6b4c40a"