creature-features
Advanced tools
Comparing version 3.1.0 to 3.1.2
@@ -7,4 +7,10 @@ { | ||
}, | ||
"extends": ["eslint:recommended", "plugin:node/recommended", "prettier"], | ||
"plugins": ["prettier"], | ||
"extends": [ | ||
"eslint:recommended", | ||
"plugin:node/recommended", | ||
"prettier" | ||
], | ||
"plugins": [ | ||
"prettier" | ||
], | ||
"parserOptions": { | ||
@@ -17,3 +23,2 @@ "ecmaVersion": 2018, | ||
}, | ||
"rules": { | ||
@@ -27,7 +32,21 @@ "indent": [ | ||
], | ||
"linebreak-style": ["error", "unix"], | ||
"quotes": ["error", "single"], | ||
"semi": ["error", "always"], | ||
"no-console": [0], | ||
"node/exports-style": ["error", "module.exports"], | ||
"linebreak-style": [ | ||
"error", | ||
"unix" | ||
], | ||
"quotes": [ | ||
"error", | ||
"single" | ||
], | ||
"semi": [ | ||
"error", | ||
"never" | ||
], | ||
"no-console": [ | ||
0 | ||
], | ||
"node/exports-style": [ | ||
"error", | ||
"module.exports" | ||
], | ||
"prettier/prettier": [ | ||
@@ -39,2 +58,3 @@ "error", | ||
"jsxBracketSameLine": true, | ||
"semi": false, | ||
"parser": "flow" | ||
@@ -41,0 +61,0 @@ } |
92
index.js
@@ -1,24 +0,24 @@ | ||
const path = require('path'); | ||
const fs = require('fs'); | ||
const debug = require('debug')('Creature-Features'); | ||
const endWith = require('end-with'); | ||
const random = require('random-weighted'); | ||
const exists = fs.existsSync; | ||
const path = require('path') | ||
const fs = require('fs') | ||
const debug = require('debug')('Creature-Features') | ||
const endWith = require('end-with') | ||
const random = require('random-weighted') | ||
const exists = fs.existsSync | ||
module.exports = function(config) { | ||
let env; | ||
let featuresFile; | ||
let baseFeatures; | ||
let env | ||
let featuresFile | ||
let baseFeatures | ||
let defaults = { | ||
location: './features/' | ||
}; | ||
} | ||
const settings = Object.assign({}, defaults, config); | ||
const settings = Object.assign({}, defaults, config) | ||
if (arguments.length === 0) { | ||
env = process.env.NODE_ENV || 'development'; | ||
env = process.env.NODE_ENV || 'development' | ||
} else { | ||
if (typeof config === 'string') { | ||
env = config; | ||
env = config | ||
} else { | ||
env = config.env ? config.env : process.env.NODE_ENV; | ||
env = config.env ? config.env : process.env.NODE_ENV | ||
} | ||
@@ -31,3 +31,3 @@ } | ||
: settings.location + '/' | ||
}${env}.json`; | ||
}${env}.json` | ||
baseFeatures = `${ | ||
@@ -37,8 +37,8 @@ endWith(settings.location, '/') | ||
: settings.location + '/' | ||
}default.json`; | ||
}default.json` | ||
var featuresFiles = []; | ||
featuresFiles.push(baseFeatures); | ||
var featuresFiles = [] | ||
featuresFiles.push(baseFeatures) | ||
if (typeof featuresFile === 'string' && exists(featuresFile)) { | ||
featuresFiles.push(featuresFile); | ||
featuresFiles.push(featuresFile) | ||
} | ||
@@ -48,3 +48,3 @@ | ||
// look for a "named" development file | ||
const files = fs.readdirSync(path.join(process.cwd(), './features')); | ||
const files = fs.readdirSync(path.join(process.cwd(), './features')) | ||
for (let i = 0; i < files.length; i++) { | ||
@@ -55,3 +55,3 @@ if ( | ||
) { | ||
featuresFiles.push('./features/' + files[i]); | ||
featuresFiles.push('./features/' + files[i]) | ||
} | ||
@@ -64,18 +64,18 @@ } | ||
.map(function(file) { | ||
return require(file); | ||
}); | ||
return require(file) | ||
}) | ||
const feats = requiredFeatures.reduce((prev, current) => { | ||
return { ...prev, ...current }; | ||
}, {}); | ||
return { ...prev, ...current } | ||
}, {}) | ||
const featureProxy = new Proxy(feats, { | ||
get: (obj, prop) => { | ||
if (obj[prop] === undefined) { | ||
if (typeof prop === 'symbol') return false; | ||
debug(`${prop} feature is undefined`); | ||
return false; | ||
if (typeof prop === 'symbol') return false | ||
debug(`${prop} feature is undefined`) | ||
return false | ||
} | ||
if (obj[prop] === true || obj[prop] === false) { | ||
return obj[prop]; | ||
return obj[prop] | ||
} | ||
@@ -87,8 +87,8 @@ if (obj[prop].range !== undefined) { | ||
0 | ||
); | ||
) | ||
if (total !== 100) { | ||
throw new Error('Range values must total 100'); | ||
throw new Error('Range values must total 100') | ||
} | ||
const range = obj[prop].range.map(v => v / 100); | ||
return random(range) === 0; | ||
const range = obj[prop].range.map(v => v / 100) | ||
return random(range) === 0 | ||
} | ||
@@ -103,8 +103,8 @@ | ||
const ${obj[prop].parameters} = '${args[1]}' | ||
return ${obj[prop].check}`; | ||
return ${obj[prop].check}` | ||
const funced = new Function(check); | ||
const result = funced(); | ||
const funced = new Function(check) | ||
const result = funced() | ||
return result; | ||
return result | ||
} | ||
@@ -114,18 +114,18 @@ const check = ` | ||
const { ${obj[prop].parameters} } = ${JSON.stringify(args[1])} | ||
return ${obj[prop].check}`; | ||
const funced = new Function(check); | ||
const result = funced(); | ||
return ${obj[prop].check}` | ||
const funced = new Function(check) | ||
const result = funced() | ||
return result; | ||
return result | ||
}, | ||
featureProxy, | ||
[prop, ...args] | ||
); | ||
) | ||
}, | ||
set: () => { | ||
throw new Error('Not allowed to set a value'); | ||
throw new Error('Not allowed to set a value') | ||
} | ||
}); | ||
}) | ||
return featureProxy; | ||
}; | ||
return featureProxy | ||
} |
{ | ||
"name": "creature-features", | ||
"version": "3.1.0", | ||
"version": "3.1.2", | ||
"description": "Feature flags for node.js", | ||
@@ -11,4 +11,6 @@ "main": "index.js", | ||
"lint": "eslint ./index.js ./test/*.test.js", | ||
"test": "cross-env DEBUG=* jest test/*.test.js", | ||
"cov": "jest test/*.test.js --coverage" | ||
"test": "cross-env jest test/*.test.js", | ||
"cov": "jest test/*.test.js --coverage", | ||
"predocs": " jest test/*.test.js --coverage --coverageDirectory=dist/coverage ", | ||
"docs": "publisher" | ||
}, | ||
@@ -33,4 +35,5 @@ "repository": { | ||
}, | ||
"homepage": "https://github.com/Kevnz/creature-features#readme", | ||
"homepage": "https://kevinisom.info/creature-features/", | ||
"devDependencies": { | ||
"@kev_nz/publisher": "^1.0.1", | ||
"cross-env": "^5.2.0", | ||
@@ -50,3 +53,10 @@ "eslint": "^5.6.0", | ||
"weighted": "^0.3.0" | ||
}, | ||
"jest": { | ||
"coverageReporters": [ | ||
"json", | ||
"text", | ||
"html" | ||
] | ||
} | ||
} | ||
} |
# Creature Features | ||
## Dead simple feature flags for node.js | ||
[![npm version](https://badge.fury.io/js/fuxor.svg)](https://badge.fury.io/js/fuxor) [![Build Status](https://travis-ci.org/Kevnz/creature-features.svg?branch=master)](https://travis-ci.org/Kevnz/creature-features) [![Coverage](https://img.shields.io/badge/endpoint.svg?color=brightgreen&label=Coverage&logoColor=brightgreen&url=https%3A%2F%2Fkevinisom.info%2Fcreature-features%2Fbadge.json)](https://kevinisom.info/creature-features/coverage/) | ||
## Dead simple feature flags | ||
Creature-Features allows feature flags based on json configuration files and supports true/false, custom rules, and weighted checks. | ||
### Install | ||
```bash | ||
npm install creature-features --save | ||
``` | ||
### Configure | ||
#### directory and files | ||
``` | ||
- features | ||
@@ -19,4 +30,7 @@ -- default.json (default settings) | ||
``` | ||
#### Example File | ||
```json | ||
{ | ||
@@ -30,3 +44,5 @@ "FeatureOne": true, | ||
### Usage | ||
```javascript | ||
const features = require('creature-features')(); | ||
@@ -42,2 +58,3 @@ // Default behavior | ||
```json | ||
{ | ||
@@ -56,3 +73,5 @@ "FeatureOne": true, | ||
``` | ||
```javascript | ||
const features = require('creature-features')(); | ||
@@ -73,3 +92,5 @@ // Default behavior | ||
#### Weight Based | ||
```json | ||
{ | ||
@@ -88,2 +109,3 @@ "FeatureOne": true, | ||
```javascript | ||
const features = require('creature-features')(); | ||
@@ -98,6 +120,9 @@ // Roughly 50% of the the time this will be true | ||
} | ||
``` | ||
### In Webpack | ||
```javascript | ||
const features = require('creature-features')(); | ||
@@ -115,9 +140,13 @@ const webpack = require('webpack'); | ||
// in a ui file | ||
if (FEATURES.FeatureOne) | ||
if (FEATURES.FeatureOne) { } | ||
``` | ||
### Why? | ||
* [They are useful](http://code.flickr.net/2009/12/02/flipping-out/) | ||
* [What are they?](https://martinfowler.com/articles/feature-toggles.html) | ||
* [How are they useful](http://code.flickr.net/2009/12/02/flipping-out/) | ||
* [More info](http://featureflags.io/) | ||
### Advanced Usage | ||
```javascript | ||
@@ -124,0 +153,0 @@ const creature = require('creature-features'); |
describe('The Default Behavior of the Module', () => { | ||
beforeAll(() => { | ||
process.env.NODE_ENV = null; | ||
delete process.env.NODE_ENV; | ||
}); | ||
process.env.NODE_ENV = null | ||
delete process.env.NODE_ENV | ||
}) | ||
it('Load default features', () => { | ||
const creature = require('../index'); | ||
const features = creature(); | ||
expect(features.FirstFeature).toBe(true); | ||
expect(features.DefaultOverride).toBe(false); | ||
expect(features.IsTest).toBe(false); | ||
}); | ||
const creature = require('../index') | ||
const features = creature() | ||
expect(features.FirstFeature).toBe(true) | ||
expect(features.DefaultOverride).toBe(false) | ||
expect(features.IsTest).toBe(false) | ||
}) | ||
it('should load named development features', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
const namedFeatures = creature('development'); | ||
expect(namedFeatures.IsNamed).toBe(true); | ||
}); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const namedFeatures = creature('development') | ||
expect(namedFeatures.IsNamed).toBe(true) | ||
}) | ||
it('should load features with a custom environment passed', () => { | ||
process.env.NODE_ENV = 'test'; | ||
const creature = require('../index'); | ||
const envFeatures = creature('development'); | ||
expect(envFeatures.FirstFeature).toBe(true); | ||
expect(envFeatures.IsDevelopment).toBe(true); | ||
expect(envFeatures.IsTest).toBe(false); | ||
}); | ||
process.env.NODE_ENV = 'test' | ||
const creature = require('../index') | ||
const envFeatures = creature('development') | ||
expect(envFeatures.FirstFeature).toBe(true) | ||
expect(envFeatures.IsDevelopment).toBe(true) | ||
expect(envFeatures.IsTest).toBe(false) | ||
}) | ||
it('should load features with a custom env that does not have a feature file', () => { | ||
process.env.NODE_ENV = 'stable'; | ||
const creature = require('../index'); | ||
const envFeatures = creature(); | ||
process.env.NODE_ENV = 'stable' | ||
const creature = require('../index') | ||
const envFeatures = creature() | ||
expect(envFeatures.FirstFeature).toBe(true); | ||
expect(envFeatures.DefaultOverride).toBe(false); | ||
}); | ||
expect(envFeatures.FirstFeature).toBe(true) | ||
expect(envFeatures.DefaultOverride).toBe(false) | ||
}) | ||
it('should load features from a custom location and the NODE_ENV has been set', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/' | ||
}); | ||
expect(locationFeatures.Location).toBe(true); | ||
expect(locationFeatures.LocationIsTest).toBe(true); | ||
expect(locationFeatures.DefaultLocation).toBe(false); | ||
}); | ||
}) | ||
expect(locationFeatures.Location).toBe(true) | ||
expect(locationFeatures.LocationIsTest).toBe(true) | ||
expect(locationFeatures.DefaultLocation).toBe(false) | ||
}) | ||
it('should load features from a custom location no slash and the NODE_ENV has been set', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features' | ||
}); | ||
expect(locationFeatures.Location).toBe(true); | ||
expect(locationFeatures.LocationIsTest).toBe(true); | ||
expect(locationFeatures.DefaultLocation).toBe(false); | ||
}); | ||
}) | ||
expect(locationFeatures.Location).toBe(true) | ||
expect(locationFeatures.LocationIsTest).toBe(true) | ||
expect(locationFeatures.DefaultLocation).toBe(false) | ||
}) | ||
it('should when given a symbol return false and not error', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features' | ||
}); | ||
expect(locationFeatures[Symbol('tester')]).toBe(false); | ||
}); | ||
}) | ||
expect(locationFeatures[Symbol('tester')]).toBe(false) | ||
}) | ||
it('should load features from a custom location and a custom environment config object', () => { | ||
process.env.NODE_ENV = 'test'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'test' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/', | ||
env: 'development' | ||
}); | ||
}) | ||
expect(locationFeatures.Location).toBe(true); | ||
expect(locationFeatures.DevelopmentFeature).toBe(true); | ||
}); | ||
expect(locationFeatures.Location).toBe(true) | ||
expect(locationFeatures.DevelopmentFeature).toBe(true) | ||
}) | ||
it('should load features from a config object with custom location without trailing slash', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features' | ||
}); | ||
expect(locationFeatures.Location).toBe(true); | ||
expect(locationFeatures.LocationIsTest).toBe(true); | ||
expect(locationFeatures.DefaultLocation).toBe(false); | ||
}); | ||
}) | ||
expect(locationFeatures.Location).toBe(true) | ||
expect(locationFeatures.LocationIsTest).toBe(true) | ||
expect(locationFeatures.DefaultLocation).toBe(false) | ||
}) | ||
it('should load features from a custom location with a trailing slash', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/' | ||
}); | ||
expect(locationFeatures.Location).toBe(true); | ||
expect(locationFeatures.LocationIsTest).toBe(true); | ||
expect(locationFeatures.DefaultLocation).toBe(false); | ||
}); | ||
}) | ||
expect(locationFeatures.Location).toBe(true) | ||
expect(locationFeatures.LocationIsTest).toBe(true) | ||
expect(locationFeatures.DefaultLocation).toBe(false) | ||
}) | ||
it('should throw an error when trying to set a feature', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
const locationFeatures = creature(); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const locationFeatures = creature() | ||
expect(() => { | ||
locationFeatures.FirstFeature = true; | ||
}).toThrow(); | ||
}); | ||
}); | ||
locationFeatures.FirstFeature = true | ||
}).toThrow() | ||
}) | ||
}) |
describe('The Default Behavior of the Module', () => { | ||
beforeAll(() => { | ||
process.env.NODE_ENV = null; | ||
delete process.env.NODE_ENV; | ||
}); | ||
process.env.NODE_ENV = null | ||
delete process.env.NODE_ENV | ||
}) | ||
it('should load named the development features when the NODE_ENV is set to "development"', () => { | ||
process.env.NODE_ENV = 'development'; | ||
const creature = require('../index'); | ||
const namedFeatures = creature(); | ||
expect(namedFeatures.IsNamed).toBe(true); | ||
expect(namedFeatures.IsDevelopmentFromDefault).toBe(true); | ||
expect(namedFeatures.IsDevelopment).toBe(true); | ||
}); | ||
process.env.NODE_ENV = 'development' | ||
const creature = require('../index') | ||
const namedFeatures = creature() | ||
expect(namedFeatures.IsNamed).toBe(true) | ||
expect(namedFeatures.IsDevelopmentFromDefault).toBe(true) | ||
expect(namedFeatures.IsDevelopment).toBe(true) | ||
}) | ||
it('should load features with a custom env when a different NODE_ENV is already set', () => { | ||
process.env.NODE_ENV = 'test'; | ||
const creature = require('../index'); | ||
const envFeatures = creature('development'); | ||
expect(envFeatures.FirstFeature).toBe(true); | ||
expect(envFeatures.IsDevelopment).toBe(true); | ||
expect(envFeatures.IsDevelopmentFromDefault).toBe(true); | ||
expect(envFeatures.IsTest).toBe(false); | ||
}); | ||
process.env.NODE_ENV = 'test' | ||
const creature = require('../index') | ||
const envFeatures = creature('development') | ||
expect(envFeatures.FirstFeature).toBe(true) | ||
expect(envFeatures.IsDevelopment).toBe(true) | ||
expect(envFeatures.IsDevelopmentFromDefault).toBe(true) | ||
expect(envFeatures.IsTest).toBe(false) | ||
}) | ||
it('should load features with a production env that does have a feature file', () => { | ||
process.env.NODE_ENV = 'production'; | ||
const creature = require('../index'); | ||
const envFeatures = creature(); | ||
process.env.NODE_ENV = 'production' | ||
const creature = require('../index') | ||
const envFeatures = creature() | ||
expect(envFeatures.IsTest).toBe(false); | ||
expect(envFeatures.IsProduction).toBe(true); | ||
expect(envFeatures.IsCustomLocation).toBe(false); | ||
}); | ||
expect(envFeatures.IsTest).toBe(false) | ||
expect(envFeatures.IsProduction).toBe(true) | ||
expect(envFeatures.IsCustomLocation).toBe(false) | ||
}) | ||
it('should load features from a custom location and a custom environment based on NODE_ENV setting', () => { | ||
process.env.NODE_ENV = 'production'; | ||
const creature = require('../index'); | ||
process.env.NODE_ENV = 'production' | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/' | ||
}); | ||
}) | ||
expect(locationFeatures.Location).toBe(true); | ||
expect(locationFeatures.IsTest).toBe(false); | ||
expect(locationFeatures.IsCustomLocation).toBe(true); | ||
}); | ||
}); | ||
expect(locationFeatures.Location).toBe(true) | ||
expect(locationFeatures.IsTest).toBe(false) | ||
expect(locationFeatures.IsCustomLocation).toBe(true) | ||
}) | ||
}) |
describe('Feature based on rules', () => { | ||
it('should when passed a parameter evaluate the rule and return true or false', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/rules' | ||
}); | ||
}) | ||
expect(locationFeatures.EmailBasedFeature('test@example.com')).toBe(true); | ||
expect(locationFeatures.EmailBasedFeature('nope@example.com')).toBe(false); | ||
}); | ||
expect(locationFeatures.EmailBasedFeature('test@example.com')).toBe(true) | ||
expect(locationFeatures.EmailBasedFeature('nope@example.com')).toBe(false) | ||
}) | ||
it('should when passed an object evaluate the rule and return true or false', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/rules' | ||
}); | ||
}) | ||
@@ -23,3 +23,3 @@ expect( | ||
}) | ||
).toBe(true); | ||
).toBe(true) | ||
expect( | ||
@@ -30,10 +30,10 @@ locationFeatures.ObjectPassedFeature({ | ||
}) | ||
).toBe(false); | ||
}); | ||
).toBe(false) | ||
}) | ||
it('should when passed an object evaluate the rule and return false if missing parameters', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const locationFeatures = creature({ | ||
location: './test/features/rules' | ||
}); | ||
}) | ||
@@ -45,3 +45,3 @@ expect( | ||
}) | ||
).toBe(true); | ||
).toBe(true) | ||
@@ -53,4 +53,4 @@ expect( | ||
}) | ||
).toBe(false); | ||
}); | ||
}); | ||
).toBe(false) | ||
}) | ||
}) |
describe('Feature based on percents', () => { | ||
it('should take an object with a range of 50 50 and return a % of true results', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const features = creature({ | ||
location: './test/features/rules' | ||
}); | ||
let trueTotal = 0; | ||
}) | ||
let trueTotal = 0 | ||
for (let index = 0; index < 1000; index++) { | ||
if (features.PercentBasedFiftyFifty) { | ||
trueTotal++; | ||
trueTotal++ | ||
} | ||
} | ||
expect(trueTotal > 450).toBe(true); | ||
expect(trueTotal < 550).toBe(true); | ||
}); | ||
expect(trueTotal > 450).toBe(true) | ||
expect(trueTotal < 550).toBe(true) | ||
}) | ||
it('should take an object with a range of 33 67 and return a % of true results', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const features = creature({ | ||
location: './test/features/rules' | ||
}); | ||
let trueTotal = 0; | ||
}) | ||
let trueTotal = 0 | ||
for (let index = 0; index < 1000; index++) { | ||
if (features.PercentBasedRuleOneThird) { | ||
trueTotal++; | ||
trueTotal++ | ||
} | ||
} | ||
expect(trueTotal > 300).toBe(true); | ||
expect(trueTotal < 375).toBe(true); | ||
}); | ||
expect(trueTotal > 300).toBe(true) | ||
expect(trueTotal < 375).toBe(true) | ||
}) | ||
it('should when given a range that totals above or below 100 throw an error', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const features = creature({ | ||
location: './test/features/rules' | ||
}); | ||
}) | ||
expect(() => features.InvalidUnderPercentRule).toThrow(); | ||
expect(() => features.InvalidOverPercentRule).toThrow(); | ||
}); | ||
expect(() => features.InvalidUnderPercentRule).toThrow() | ||
expect(() => features.InvalidOverPercentRule).toThrow() | ||
}) | ||
it('should take an object with a range of 33 67 and return a % of true results for 10000 calls', () => { | ||
const creature = require('../index'); | ||
const creature = require('../index') | ||
const features = creature({ | ||
location: './test/features/rules' | ||
}); | ||
let trueTotal = 0; | ||
}) | ||
let trueTotal = 0 | ||
for (let index = 0; index < 10000; index++) { | ||
if (features.PercentBasedRuleOneThird) { | ||
trueTotal++; | ||
trueTotal++ | ||
} | ||
} | ||
expect(trueTotal > 3000).toBe(true); | ||
expect(trueTotal < 3750).toBe(true); | ||
}); | ||
}); | ||
expect(trueTotal > 3000).toBe(true) | ||
expect(trueTotal < 3750).toBe(true) | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
24342
23
585
151
8
3