Ember CLI addon for feature flags
JavaScript HTML CSS
Clone or download
kategengler Update README.md
Further clarification
Latest commit 87f0b7b Apr 18, 2018
Permalink
Failed to load latest commit information.
addon-test-support Fix New Style testing helpers usage to support integration tests Feb 27, 2018
addon Add public `flags` computed property Jan 31, 2018
app Introduce feature-flag template helper Jan 28, 2018
config Remove redundant default scenario Feb 2, 2018
tests Fix New Style testing helpers usage to support integration tests Feb 27, 2018
vendor Initial Commit from Ember CLI v0.1.2 Nov 16, 2014
.editorconfig
.ember-cli
.eslintrc.js Support RFC 268 testing style Feb 2, 2018
.gitignore Upgrade Ember CLI to version 2.18 and align with default blueprint Jan 24, 2018
.npmignore Merge pull request #52 from akatov/update-npmignore Feb 27, 2018
.travis.yml Fix typo in .travis.yml Feb 2, 2018
.watchmanconfig Upgrade ember-cli & test against additonal ember versions Jan 26, 2016
CHANGELOG.md Update CHANGELOG for v5.0.0 Feb 27, 2018
LICENSE.md Upgrade ember-cli & test against additonal ember versions Jan 26, 2016
README.md Update README.md Apr 18, 2018
RELEASE.md Have travis release on tags, add lerna-changelog Feb 2, 2018
ember-cli-build.js Upgrade Ember CLI to version 2.18 and align with default blueprint Jan 24, 2018
index.js Upgrade Ember CLI to version 2.18 and align with default blueprint Jan 24, 2018
package.json 5.0.0 Feb 27, 2018
testem.js Align with default blueprint and fix readme Jan 24, 2018
yarn.lock Update yarn.lock Feb 2, 2018

README.md

ember-feature-flags Build Status Ember Observer Score

An ember-cli addon to provide feature flags.

Note to users of ember.js >= 3.1

Referencing the features service must be done using get as it is a proxy.

Installation

ember install ember-feature-flags

Usage

This addon provides a service named features available for injection into your routes, controllers, components, etc.

For example you may check if a feature is enabled:

import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
export default Controller.extend({
  features: service(), 
  plans() {
    if (this.get('features').isEnabled('new-billing-plans')) {
      // Return new plans
    } else {
      // Return old plans
    }
  }
});

Features are also available as properties of features. They are camelized.

import Controller from '@ember/controller';
import { inject as service } from '@ember/service';
import { computed } from '@ember/object';
export default Controller.extend({
  features: service(), 
  plans: computed('features.newBillingPlans', function(){
    if (this.get('features.newBillingPlans')) {
      // Return new plans
    } else {
      // Return old plans
    }
  })
});

Check whether a feature is enabled in a template (be sure to inject the features service into the template's backing JavaScript):

// templates/components/homepage-link.hbs
{{#if features.newHomepage}}
  {{link-to "new.homepage"}}
{{else}}
  {{link-to "old.homepage"}}
{{/if}}

NOTE: features service must be injected into the respective component:

// components/homepage-link.js
export default Component.extend({
  features: service()
});

Alternatively you can use a template helper named feature-flag:

// templates/components/homepage-link.hbs
{{#if (feature-flag 'newHomepage')}}
  {{link-to "new.homepage"}}
{{else}}
  {{link-to "old.homepage"}}
{{/if}}

Features can be toggled at runtime, and are bound:

this.get('features').enable('newHomepage');
this.get('features').disable('newHomepage');

Features can be set in bulk:

this.get('features').setup({
  "new-billing-plans": true,
  "new-homepage": false
});

NOTE: setup methods reset previously setup flags and their state.

You can get list of known feature flags via flags computed property:

this.get('features').setup({
  "new-billing-plans": true,
  "new-homepage": false
});

this.get('features.flags') // ['newBillingPlans', 'newHomepage']

Configuration

config.featureFlags

You can configure a set of initial feature flags in your app's config/environment.js file. This is an easy way to change settings for a given environment. For example:

// config/environment.js
module.exports = function(environment) {
  var ENV = {
    featureFlags: {
      'show-spinners': true,
      'download-cats': false
    }
  };

  if (environment === 'production') {
    ENV.featureFlags['download-cats'] = true;
  }

  return ENV;
};

ENV.LOG_FEATURE_FLAG_MISS

Will log when a feature flag is queried and found to be off, useful to prevent cursing at the app, wondering why your feature is not working.

Test Helpers

enableFeature

Turns on a feature for the test in which it is called. Requires ember-cli-qunit >= 4.1.0 and the newer style of tests that use setupTest, setupRenderingTest, setupApplicationTest.

Example:

import { enableFeature } from 'ember-feature-flags/test-support';

module('Acceptance | Awesome page', function(hooks) {
  setupApplicationTest(hooks);

  test('links go to the new homepage', async function (assert) {
    enableFeature('new-homepage');
  
    await visit('/');
    await click('a.home');

    assert.equal(currentRoute(), 'new.homepage', 'Should be on the new homepage');
  });
});

withFeature

"Old"-style acceptance tests can utilize withFeature test helper to turn on a feature for the test. To use, import into your test-helper.js: import 'ember-feature-flags/test-support/helpers/with-feature' and add to your test .jshintrc, it will now be available in all of your tests.

Example:

import 'ember-feature-flags/test-support/helpers/with-feature';

test( "links go to the new homepage", function () {
  withFeature( 'new-homepage' );

  visit('/');
  click('a.home');
  andThen(function(){
    equal(currentRoute(), 'new.homepage', 'Should be on the new homepage');
  });
});

Integration Tests

If you use this.features.isEnabled() in components under integration test, you will need to inject a stub service in your tests. Using ember-qunit 0.4.16 or later, here's how to do this:

let featuresService = Service.extend({
  isEnabled() {
    return false;
  }
});

moduleForComponent('my-component', 'Integration | Component | my component', {
  integration: true,
  beforeEach() {
    this.register('service:features', featuresService);
    getOwner(this).inject('component', 'features', 'service:features');
  }
});

Note: for Ember before 2.3.0, you'll need to use ember-getowner-polyfill.

Development

Installation

  • git clone this repository
  • cd ember-feature-flags`
  • yarn install

Running

Running Tests

  • ember try:each (Test against multiple ember versions)
  • ember test
  • ember test --server

Deploying

  • See RELEASE.md