From 4c5b52d5e7396d9a1d4c0359f5d93f03fda2257d Mon Sep 17 00:00:00 2001 From: Krzysztof Miksa Date: Mon, 16 Jan 2017 14:08:48 +0000 Subject: [PATCH 1/3] FIX: featureFlags.set() does not update cached featureFlags #42 --- bower.json | 2 +- dist/featureFlags.js | 5 +++-- dist/featureFlags.min.js | 4 ++-- package.json | 2 +- src/featureFlags.provider.js | 1 + 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/bower.json b/bower.json index 28dda94..a3c9e5c 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-feature-flags", - "version": "1.4.0", + "version": "1.4.1", "authors": [ { "name": "Michael Taranto", diff --git a/dist/featureFlags.js b/dist/featureFlags.js index 4ef6eb7..bfc2dd0 100644 --- a/dist/featureFlags.js +++ b/dist/featureFlags.js @@ -1,7 +1,7 @@ /*! - * Angular Feature Flags v1.4.0 + * Angular Feature Flags v1.4.1 * - * © 2016, Michael Taranto + * © 2017, Michael Taranto */ (function(){ @@ -168,6 +168,7 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) { updateFlagsAndGetAll = function(newFlags) { newFlags.forEach(function(flag) { serverFlagCache[flag.key] = flag.active; + featureFlagOverrides.set(flag.key, flag.active); flag.active = isOn(flag.key); }); angular.copy(newFlags, flags); diff --git a/dist/featureFlags.min.js b/dist/featureFlags.min.js index 4815efa..f8732af 100644 --- a/dist/featureFlags.min.js +++ b/dist/featureFlags.min.js @@ -1,2 +1,2 @@ -/*! Angular Feature Flags v1.4.0 © 2016 Michael Taranto */ -!function(){function e(e,a,t){var r={},n=[],i=function(a){var t=e.defer();return t.resolve(a),t.promise},l=function(e){return a.isPresent(e)},f=function(e){return l(e)?"true"===a.get(e):r[e]},u=function(e){return r[e]},s=function(e){return e.forEach(function(e){r[e.key]=e.active,e.active=f(e.key)}),angular.copy(e,n),n},c=function(e){return e.then(function(e){return s(e.data||e)})},g=function(){return n},o=function(e){return angular.isArray(e)?i(s(e)):c(e)},d=function(e){e.active=!0,a.set(e.key,!0)},v=function(e){e.active=!1,a.set(e.key,!1)},y=function(e){e.active=r[e.key],a.remove(e.key)},m=function(){t&&o(t)};return m(),{set:o,get:g,enable:d,disable:v,reset:y,isOn:f,isOnByDefault:u,isOverridden:l}}angular.module("feature-flags",[]),angular.module("feature-flags").directive("featureFlag",["featureFlags","$interpolate",function(e,a){return{transclude:"element",priority:599,terminal:!0,restrict:"A",$$tlb:!0,compile:function(t,r){var n="featureFlagHide"in r;return t[0].textContent=" featureFlag: "+r.featureFlag+" is "+(n?"on":"off")+" ",function(t,r,i,l,f){var u,s;t.$watch(function(){var r=a(i.featureFlag)(t);return e.isOn(r)},function(e){var a=n?!e:e;a?(s=t.$new(),f(s,function(e){u=e,r.after(u).remove()})):(s&&(s.$destroy(),s=null),u&&(u.after(r).remove(),u=null))})}}}}]),angular.module("feature-flags").directive("featureFlagOverrides",["featureFlags",function(e){return{restrict:"A",link:function(a){a.flags=e.get(),a.isOn=e.isOn,a.isOverridden=e.isOverridden,a.enable=e.enable,a.disable=e.disable,a.reset=e.reset,a.isOnByDefault=e.isOnByDefault},template:'

Feature Flags

{{flag.name || flag.key}}
ON
OFF
DEFAULT ({{isOnByDefault(flag.key) ? \'ON\' : \'OFF\'}})
{{flag.description}}
',replace:!0}}]),angular.module("feature-flags").service("featureFlagOverrides",["$rootElement",function(e){var a=e.attr("ng-app"),t="featureFlags."+a+".",r=function(){try{return localStorage.setItem("featureFlags.availableTest","test"),localStorage.removeItem("featureFlags.availableTest"),!0}catch(e){return!1}}(),n=function(e){return t+e},i=function(e){return 0===e.indexOf(t)},l=function(e,a){r&&localStorage.setItem(n(a),e)},f=function(e){return r?localStorage.getItem(n(e)):void 0},u=function(e){r&&localStorage.removeItem(n(e))};return{isPresent:function(e){var a=f(e);return"undefined"!=typeof a&&null!==a},get:f,set:function(e,a){angular.isObject(e)?angular.forEach(e,l):l(a,e)},remove:u,reset:function(){var e;if(r)for(e in localStorage)i(e)&&localStorage.removeItem(e)}}}]),angular.module("feature-flags").provider("featureFlags",function(){var a=[];this.setInitialFlags=function(e){a=e},this.$get=["$q","featureFlagOverrides",function(t,r){return new e(t,r,a)}]})}(); \ No newline at end of file +/*! Angular Feature Flags v1.4.1 © 2017 Michael Taranto */ +!function(){function e(e,a,t){var r={},n=[],i=function(a){var t=e.defer();return t.resolve(a),t.promise},l=function(e){return a.isPresent(e)},f=function(e){return l(e)?"true"===a.get(e):r[e]},u=function(e){return r[e]},s=function(e){return e.forEach(function(e){r[e.key]=e.active,a.set(e.key,e.active),e.active=f(e.key)}),angular.copy(e,n),n},c=function(e){return e.then(function(e){return s(e.data||e)})},g=function(){return n},o=function(e){return angular.isArray(e)?i(s(e)):c(e)},d=function(e){e.active=!0,a.set(e.key,!0)},v=function(e){e.active=!1,a.set(e.key,!1)},y=function(e){e.active=r[e.key],a.remove(e.key)},m=function(){t&&o(t)};return m(),{set:o,get:g,enable:d,disable:v,reset:y,isOn:f,isOnByDefault:u,isOverridden:l}}angular.module("feature-flags",[]),angular.module("feature-flags").directive("featureFlag",["featureFlags","$interpolate",function(e,a){return{transclude:"element",priority:599,terminal:!0,restrict:"A",$$tlb:!0,compile:function(t,r){var n="featureFlagHide"in r;return t[0].textContent=" featureFlag: "+r.featureFlag+" is "+(n?"on":"off")+" ",function(t,r,i,l,f){var u,s;t.$watch(function(){var r=a(i.featureFlag)(t);return e.isOn(r)},function(e){var a=n?!e:e;a?(s=t.$new(),f(s,function(e){u=e,r.after(u).remove()})):(s&&(s.$destroy(),s=null),u&&(u.after(r).remove(),u=null))})}}}}]),angular.module("feature-flags").directive("featureFlagOverrides",["featureFlags",function(e){return{restrict:"A",link:function(a){a.flags=e.get(),a.isOn=e.isOn,a.isOverridden=e.isOverridden,a.enable=e.enable,a.disable=e.disable,a.reset=e.reset,a.isOnByDefault=e.isOnByDefault},template:'

Feature Flags

{{flag.name || flag.key}}
ON
OFF
DEFAULT ({{isOnByDefault(flag.key) ? \'ON\' : \'OFF\'}})
{{flag.description}}
',replace:!0}}]),angular.module("feature-flags").service("featureFlagOverrides",["$rootElement",function(e){var a=e.attr("ng-app"),t="featureFlags."+a+".",r=function(){try{return localStorage.setItem("featureFlags.availableTest","test"),localStorage.removeItem("featureFlags.availableTest"),!0}catch(e){return!1}}(),n=function(e){return t+e},i=function(e){return 0===e.indexOf(t)},l=function(e,a){r&&localStorage.setItem(n(a),e)},f=function(e){return r?localStorage.getItem(n(e)):void 0},u=function(e){r&&localStorage.removeItem(n(e))};return{isPresent:function(e){var a=f(e);return"undefined"!=typeof a&&null!==a},get:f,set:function(e,a){angular.isObject(e)?angular.forEach(e,l):l(a,e)},remove:u,reset:function(){var e;if(r)for(e in localStorage)i(e)&&localStorage.removeItem(e)}}}]),angular.module("feature-flags").provider("featureFlags",function(){var a=[];this.setInitialFlags=function(e){a=e},this.$get=["$q","featureFlagOverrides",function(t,r){return new e(t,r,a)}]})}(); \ No newline at end of file diff --git a/package.json b/package.json index a8bac47..1bee84a 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-feature-flags", "title": "Angular Feature Flags", - "version": "1.4.0", + "version": "1.4.1", "description": "Feature Flag module for Angular JS apps", "main": "dist/featureFlags.js", "keywords": [ diff --git a/src/featureFlags.provider.js b/src/featureFlags.provider.js index db7ac99..3e2e4b8 100644 --- a/src/featureFlags.provider.js +++ b/src/featureFlags.provider.js @@ -23,6 +23,7 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) { updateFlagsAndGetAll = function(newFlags) { newFlags.forEach(function(flag) { serverFlagCache[flag.key] = flag.active; + featureFlagOverrides.set(flag.key, flag.active); flag.active = isOn(flag.key); }); angular.copy(newFlags, flags); From 816367fba3ad507e7f943f405f5d17e39b819d30 Mon Sep 17 00:00:00 2001 From: Krzysztof Miksa Date: Thu, 19 Jan 2017 10:22:09 +0000 Subject: [PATCH 2/3] Revert bump version --- bower.json | 2 +- dist/featureFlags.js | 5 ++--- dist/featureFlags.min.js | 4 ++-- package.json | 2 +- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/bower.json b/bower.json index a3c9e5c..28dda94 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "angular-feature-flags", - "version": "1.4.1", + "version": "1.4.0", "authors": [ { "name": "Michael Taranto", diff --git a/dist/featureFlags.js b/dist/featureFlags.js index bfc2dd0..4ef6eb7 100644 --- a/dist/featureFlags.js +++ b/dist/featureFlags.js @@ -1,7 +1,7 @@ /*! - * Angular Feature Flags v1.4.1 + * Angular Feature Flags v1.4.0 * - * © 2017, Michael Taranto + * © 2016, Michael Taranto */ (function(){ @@ -168,7 +168,6 @@ function FeatureFlags($q, featureFlagOverrides, initialFlags) { updateFlagsAndGetAll = function(newFlags) { newFlags.forEach(function(flag) { serverFlagCache[flag.key] = flag.active; - featureFlagOverrides.set(flag.key, flag.active); flag.active = isOn(flag.key); }); angular.copy(newFlags, flags); diff --git a/dist/featureFlags.min.js b/dist/featureFlags.min.js index f8732af..4815efa 100644 --- a/dist/featureFlags.min.js +++ b/dist/featureFlags.min.js @@ -1,2 +1,2 @@ -/*! Angular Feature Flags v1.4.1 © 2017 Michael Taranto */ -!function(){function e(e,a,t){var r={},n=[],i=function(a){var t=e.defer();return t.resolve(a),t.promise},l=function(e){return a.isPresent(e)},f=function(e){return l(e)?"true"===a.get(e):r[e]},u=function(e){return r[e]},s=function(e){return e.forEach(function(e){r[e.key]=e.active,a.set(e.key,e.active),e.active=f(e.key)}),angular.copy(e,n),n},c=function(e){return e.then(function(e){return s(e.data||e)})},g=function(){return n},o=function(e){return angular.isArray(e)?i(s(e)):c(e)},d=function(e){e.active=!0,a.set(e.key,!0)},v=function(e){e.active=!1,a.set(e.key,!1)},y=function(e){e.active=r[e.key],a.remove(e.key)},m=function(){t&&o(t)};return m(),{set:o,get:g,enable:d,disable:v,reset:y,isOn:f,isOnByDefault:u,isOverridden:l}}angular.module("feature-flags",[]),angular.module("feature-flags").directive("featureFlag",["featureFlags","$interpolate",function(e,a){return{transclude:"element",priority:599,terminal:!0,restrict:"A",$$tlb:!0,compile:function(t,r){var n="featureFlagHide"in r;return t[0].textContent=" featureFlag: "+r.featureFlag+" is "+(n?"on":"off")+" ",function(t,r,i,l,f){var u,s;t.$watch(function(){var r=a(i.featureFlag)(t);return e.isOn(r)},function(e){var a=n?!e:e;a?(s=t.$new(),f(s,function(e){u=e,r.after(u).remove()})):(s&&(s.$destroy(),s=null),u&&(u.after(r).remove(),u=null))})}}}}]),angular.module("feature-flags").directive("featureFlagOverrides",["featureFlags",function(e){return{restrict:"A",link:function(a){a.flags=e.get(),a.isOn=e.isOn,a.isOverridden=e.isOverridden,a.enable=e.enable,a.disable=e.disable,a.reset=e.reset,a.isOnByDefault=e.isOnByDefault},template:'

Feature Flags

{{flag.name || flag.key}}
ON
OFF
DEFAULT ({{isOnByDefault(flag.key) ? \'ON\' : \'OFF\'}})
{{flag.description}}
',replace:!0}}]),angular.module("feature-flags").service("featureFlagOverrides",["$rootElement",function(e){var a=e.attr("ng-app"),t="featureFlags."+a+".",r=function(){try{return localStorage.setItem("featureFlags.availableTest","test"),localStorage.removeItem("featureFlags.availableTest"),!0}catch(e){return!1}}(),n=function(e){return t+e},i=function(e){return 0===e.indexOf(t)},l=function(e,a){r&&localStorage.setItem(n(a),e)},f=function(e){return r?localStorage.getItem(n(e)):void 0},u=function(e){r&&localStorage.removeItem(n(e))};return{isPresent:function(e){var a=f(e);return"undefined"!=typeof a&&null!==a},get:f,set:function(e,a){angular.isObject(e)?angular.forEach(e,l):l(a,e)},remove:u,reset:function(){var e;if(r)for(e in localStorage)i(e)&&localStorage.removeItem(e)}}}]),angular.module("feature-flags").provider("featureFlags",function(){var a=[];this.setInitialFlags=function(e){a=e},this.$get=["$q","featureFlagOverrides",function(t,r){return new e(t,r,a)}]})}(); \ No newline at end of file +/*! Angular Feature Flags v1.4.0 © 2016 Michael Taranto */ +!function(){function e(e,a,t){var r={},n=[],i=function(a){var t=e.defer();return t.resolve(a),t.promise},l=function(e){return a.isPresent(e)},f=function(e){return l(e)?"true"===a.get(e):r[e]},u=function(e){return r[e]},s=function(e){return e.forEach(function(e){r[e.key]=e.active,e.active=f(e.key)}),angular.copy(e,n),n},c=function(e){return e.then(function(e){return s(e.data||e)})},g=function(){return n},o=function(e){return angular.isArray(e)?i(s(e)):c(e)},d=function(e){e.active=!0,a.set(e.key,!0)},v=function(e){e.active=!1,a.set(e.key,!1)},y=function(e){e.active=r[e.key],a.remove(e.key)},m=function(){t&&o(t)};return m(),{set:o,get:g,enable:d,disable:v,reset:y,isOn:f,isOnByDefault:u,isOverridden:l}}angular.module("feature-flags",[]),angular.module("feature-flags").directive("featureFlag",["featureFlags","$interpolate",function(e,a){return{transclude:"element",priority:599,terminal:!0,restrict:"A",$$tlb:!0,compile:function(t,r){var n="featureFlagHide"in r;return t[0].textContent=" featureFlag: "+r.featureFlag+" is "+(n?"on":"off")+" ",function(t,r,i,l,f){var u,s;t.$watch(function(){var r=a(i.featureFlag)(t);return e.isOn(r)},function(e){var a=n?!e:e;a?(s=t.$new(),f(s,function(e){u=e,r.after(u).remove()})):(s&&(s.$destroy(),s=null),u&&(u.after(r).remove(),u=null))})}}}}]),angular.module("feature-flags").directive("featureFlagOverrides",["featureFlags",function(e){return{restrict:"A",link:function(a){a.flags=e.get(),a.isOn=e.isOn,a.isOverridden=e.isOverridden,a.enable=e.enable,a.disable=e.disable,a.reset=e.reset,a.isOnByDefault=e.isOnByDefault},template:'

Feature Flags

{{flag.name || flag.key}}
ON
OFF
DEFAULT ({{isOnByDefault(flag.key) ? \'ON\' : \'OFF\'}})
{{flag.description}}
',replace:!0}}]),angular.module("feature-flags").service("featureFlagOverrides",["$rootElement",function(e){var a=e.attr("ng-app"),t="featureFlags."+a+".",r=function(){try{return localStorage.setItem("featureFlags.availableTest","test"),localStorage.removeItem("featureFlags.availableTest"),!0}catch(e){return!1}}(),n=function(e){return t+e},i=function(e){return 0===e.indexOf(t)},l=function(e,a){r&&localStorage.setItem(n(a),e)},f=function(e){return r?localStorage.getItem(n(e)):void 0},u=function(e){r&&localStorage.removeItem(n(e))};return{isPresent:function(e){var a=f(e);return"undefined"!=typeof a&&null!==a},get:f,set:function(e,a){angular.isObject(e)?angular.forEach(e,l):l(a,e)},remove:u,reset:function(){var e;if(r)for(e in localStorage)i(e)&&localStorage.removeItem(e)}}}]),angular.module("feature-flags").provider("featureFlags",function(){var a=[];this.setInitialFlags=function(e){a=e},this.$get=["$q","featureFlagOverrides",function(t,r){return new e(t,r,a)}]})}(); \ No newline at end of file diff --git a/package.json b/package.json index 1bee84a..a8bac47 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "angular-feature-flags", "title": "Angular Feature Flags", - "version": "1.4.1", + "version": "1.4.0", "description": "Feature Flag module for Angular JS apps", "main": "dist/featureFlags.js", "keywords": [ From 8d4602e9a9a14ceb222984914a062c3fbb1de3fd Mon Sep 17 00:00:00 2001 From: Krzysztof Miksa Date: Thu, 19 Jan 2017 11:29:59 +0000 Subject: [PATCH 3/3] Implement test to capture fix --- test/featureFlags.provider.spec.js | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/test/featureFlags.provider.spec.js b/test/featureFlags.provider.spec.js index 99df006..05398bf 100644 --- a/test/featureFlags.provider.spec.js +++ b/test/featureFlags.provider.spec.js @@ -352,6 +352,28 @@ }); }); }); + + describe('when I enable a flag and then set the list of flags with the same flag', function() { + var flagKey = 'FLAG_KEY'; + var onFlag = { + active: true, + key: flagKey + }; + var offFlag = { + active: false, + key: flagKey + }; + + beforeEach(function() { + featureFlags.enable(onFlag); + + featureFlags.set([offFlag]); + }); + + it('should override previous flag value', function() { + expect(featureFlags.isOn(flagKey)).toBe(false); + }); + }); }); describe('Provider: featureFlags', function() {