diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 3db2cbc..8b3e015 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,32 +1,13 @@ -#------------------------------------------------------------------------------------------------------------- -# Copyright (c) Microsoft Corporation. All rights reserved. -# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. -#------------------------------------------------------------------------------------------------------------- -FROM node:22 +FROM node:22-alpine -# The node image includes a non-root user with sudo access. Use the -# "remoteUser" property in devcontainer.json to use it. On Linux, update -# these values to ensure the container user's UID/GID matches your local values. -# See https://aka.ms/vscode-remote/containers/non-root-user for details. ARG USERNAME=node ARG USER_UID=1000 ARG USER_GID=$USER_UID -RUN echo "deb http://archive.debian.org/debian stretch main" > /etc/apt/sources.list - # Configure apt and install packages -RUN apt-get update \ - && apt-get -y install --no-install-recommends dialog 2>&1 \ - # Verify git and needed tools are installed - && apt-get -y install git iproute2 procps \ - # Update npm to the latest version - && npm install -g npm@latest \ - # Clean up - && apt-get autoremove -y \ - && apt-get clean -y \ - && rm -rf /var/lib/apt/lists/* - -# set up a nicer prompt -RUN git clone https://github.com/magicmonty/bash-git-prompt.git ~/.bash-git-prompt --depth=1 - -RUN echo "source $HOME/.bash-git-prompt/gitprompt.sh" >> ~/.bashrc \ No newline at end of file +RUN apk update && \ + apk add --no-cache \ + ca-certificates \ + curl \ + git \ + openssh \ No newline at end of file diff --git a/README.md b/README.md index 843f1df..64bc5c3 100644 --- a/README.md +++ b/README.md @@ -65,10 +65,12 @@ const snapshotLocation = './snapshot/'; const snapshotAutoUpdateInterval = 3; const snapshotWatcher = true; const silentMode = '5m'; +const restrictRelay = true; const certPath = './certs/ca.pem'; Client.buildContext({ url, apiKey, domain, component, environment }, { - local, logger, snapshotLocation, snapshotAutoUpdateInterval, snapshotWatcher, silentMode, certPath + local, logger, snapshotLocation, snapshotAutoUpdateInterval, + snapshotWatcher, silentMode, restrictRelay, certPath }); const switcher = Client.getSwitcher(); @@ -76,14 +78,15 @@ const switcher = Client.getSwitcher(); - **local**: If activated, the client will only fetch the configuration inside your snapshot file. The default value is 'false' - **logger**: If activated, it is possible to retrieve the last results from a given Switcher key using Client.getLogger('KEY') -- **snapshotLocation**: Location of snapshot files. The default value is './snapshot/' -- **snapshotAutoUpdateInterval**: Enable Snapshot Auto Update given an interval in seconds (default: 0 disabled). -- **snapshotWatcher**: Enable Snapshot Watcher to monitor changes in the snapshot file (default: false). +- **snapshotLocation**: Location of snapshot files +- **snapshotAutoUpdateInterval**: Enable Snapshot Auto Update given an interval in seconds (default: 0 disabled) +- **snapshotWatcher**: Enable Snapshot Watcher to monitor changes in the snapshot file (default: false) - **silentMode**: Enable contigency given the time for the client to retry - e.g. 5s (s: seconds - m: minutes - h: hours) -- **regexSafe**: Enable REGEX Safe mode - Prevent agaist reDOS attack (default: true). +- **restrictRelay**: Enable Relay Restriction - Allow managing Relay restrictions when running in local mode (default: true) +- **regexSafe**: Enable REGEX Safe mode - Prevent agaist reDOS attack (default: true) - **regexMaxBlackList**: Number of entries cached when REGEX Strategy fails to perform (reDOS safe) - default: 50 - **regexMaxTimeLimit**: Time limit (ms) used by REGEX workers (reDOS safe) - default - 3000ms -- **certPath**: Path to the certificate file used to establish a secure connection with the API. +- **certPath**: Path to the certificate file used to establish a secure connection with the API (*) regexSafe is a feature that prevents your application from being exposed to a reDOS attack. It is recommended to keep this feature enabled.
diff --git a/package.json b/package.json index 6db7a86..5038a1e 100644 --- a/package.json +++ b/package.json @@ -18,11 +18,12 @@ ], "license": "MIT", "scripts": { - "lint": "eslint ./src/**/*.js ./test/**/*.js", - "test": "npm run coverage \"./test/**/*.test.js\"", - "test-local": "env-cmd npm run coverage \"./test/**/*.test.js\"", + "lint": "eslint ./src/**/*.js ./tests/**/*.js", + "test": "npm run coverage \"./tests/**/*.test.js\"", + "test-file": "env-cmd npm run coverage", + "test-local": "env-cmd npm run coverage \"./tests/**/*.test.js\"", "coverage": "c8 --include='src/**/*.js' mocha", - "play": "env-cmd node ./test/playground/index.js" + "play": "env-cmd node ./tests/playground/index.js" }, "files": [ "LICENSE", @@ -37,7 +38,7 @@ "chai": "^5.2.0", "env-cmd": "^10.1.0", "eslint": "^9.29.0", - "mocha": "^11.7.0", + "mocha": "^11.7.1", "mocha-sonarqube-reporter": "^1.0.2", "sinon": "^21.0.0" }, diff --git a/sonar-project.properties b/sonar-project.properties index c097316..d9249ca 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -8,7 +8,7 @@ sonar.javascript.lcov.reportPaths=coverage/lcov.info # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. sonar.sources=src -sonar.tests=test +sonar.tests=tests sonar.language=js sonar.exclusions=src/**/*.d.ts, src/lib/utils/timed-match/match-proc.js diff --git a/src/client.d.ts b/src/client.d.ts index 572ec11..2b41365 100644 --- a/src/client.d.ts +++ b/src/client.d.ts @@ -215,6 +215,11 @@ export type SwitcherOptions = { */ snapshotWatcher?: boolean; + /** + * Allow local snapshots to ignore or require Relay verification. + */ + restrictRelay?: boolean; + /** * When defined it will switch to local during the specified time before it switches back to remote * e.g. 5s (s: seconds - m: minutes - h: hours) diff --git a/src/client.js b/src/client.js index ded4077..a3551f5 100644 --- a/src/client.js +++ b/src/client.js @@ -55,6 +55,9 @@ export class Client { const optionsHandler = { [SWITCHER_OPTIONS.CERT_PATH]: (val) => val && remote.setCerts(val), [SWITCHER_OPTIONS.SILENT_MODE]: (val) => val && this.#initSilentMode(val), + [SWITCHER_OPTIONS.RESTRICT_RELAY]: (val) => { + GlobalOptions.updateOptions({ restrictRelay: val }); + }, [SWITCHER_OPTIONS.SNAPSHOT_AUTO_UPDATE_INTERVAL]: (val) => { GlobalOptions.updateOptions({ snapshotAutoUpdateInterval: val }); this.scheduleSnapshotAutoUpdate(); @@ -97,7 +100,8 @@ export class Client { } static getSwitcher(key) { - return new Switcher(util.get(key, '')); + return new Switcher(util.get(key, '')) + .restrictRelay(GlobalOptions.restrictRelay); } static async checkSnapshot() { diff --git a/src/lib/constants.js b/src/lib/constants.js index 6f3151f..29feafa 100644 --- a/src/lib/constants.js +++ b/src/lib/constants.js @@ -9,6 +9,7 @@ export const SWITCHER_OPTIONS = Object.freeze({ SNAPSHOT_LOCATION: 'snapshotLocation', SNAPSHOT_AUTO_UPDATE_INTERVAL: 'snapshotAutoUpdateInterval', SNAPSHOT_WATCHER: 'snapshotWatcher', + RESTRICT_RELAY: 'restrictRelay', SILENT_MODE: 'silentMode', REGEX_SAFE: 'regexSafe', REGEX_MAX_BLACK_LIST: 'regexMaxBlackList', diff --git a/src/lib/globals/globalOptions.js b/src/lib/globals/globalOptions.js index 01b7582..01b3057 100644 --- a/src/lib/globals/globalOptions.js +++ b/src/lib/globals/globalOptions.js @@ -33,4 +33,8 @@ export class GlobalOptions { static get silentMode() { return this.#options.silentMode; } + + static get restrictRelay() { + return this.#options.restrictRelay; + } } diff --git a/src/lib/remote.js b/src/lib/remote.js index 4f339eb..5428edd 100644 --- a/src/lib/remote.js +++ b/src/lib/remote.js @@ -151,6 +151,7 @@ export async function resolveSnapshot(domain, environment, component) { group { name activated config { key activated strategies { strategy activated operation values } + relay { type activated } components } } diff --git a/src/lib/resolver.js b/src/lib/resolver.js index cd07352..2613480 100644 --- a/src/lib/resolver.js +++ b/src/lib/resolver.js @@ -72,6 +72,10 @@ async function checkConfig(group, config, switcher) { throw new CriteriaFailed('Config disabled'); } + if (hasRelayEnabled(config) && switcher.isRelayRestricted) { + throw new CriteriaFailed(`Config '${config.key}' is restricted to relay`); + } + if (config.strategies) { return await checkStrategy(config, util.get(switcher.input, [])); } @@ -105,6 +109,10 @@ async function checkStrategyInput(entry, { strategy, operation, values }) { } } +function hasRelayEnabled(config) { + return config.relay?.activated; +} + export default async function checkCriteriaLocal(snapshot, switcher) { if (!snapshot) { throw new Error('Snapshot not loaded. Try to use \'Client.loadSnapshot()\''); diff --git a/src/switcher.d.ts b/src/switcher.d.ts index 6be1e33..196d20b 100644 --- a/src/switcher.d.ts +++ b/src/switcher.d.ts @@ -45,6 +45,11 @@ export class Switcher { * Define a default result when the client enters in panic mode */ defaultResult(defaultResult: boolean): Switcher; + + /** + * Allow local snapshots to ignore or require Relay verification. + */ + restrictRelay(restrict: boolean): Switcher; /** * Adds a strategy for validation diff --git a/src/switcherBuilder.js b/src/switcherBuilder.js index 640f304..d664798 100644 --- a/src/switcherBuilder.js +++ b/src/switcherBuilder.js @@ -9,6 +9,7 @@ export class SwitcherBuilder { _defaultResult; _forceRemote = false; _showDetail = false; + _restrictRelay = true; constructor(key) { this._key = key; @@ -42,6 +43,11 @@ export class SwitcherBuilder { this._defaultResult = defaultResult; return this; } + + restrictRelay(restrict = true) { + this._restrictRelay = restrict; + return this; + } check(startegyType, input) { if (!this._input) { diff --git a/src/switcherRequest.js b/src/switcherRequest.js index 75d89e2..16d0bfb 100644 --- a/src/switcherRequest.js +++ b/src/switcherRequest.js @@ -14,4 +14,11 @@ export class SwitcherRequest extends SwitcherBuilder { get input() { return this._input; } + + /** + * Return Relay restriction value + */ + get isRelayRestricted() { + return this._restrictRelay; + } } \ No newline at end of file diff --git a/test/helper/dummy-cert.pem b/tests/helper/dummy-cert.pem similarity index 100% rename from test/helper/dummy-cert.pem rename to tests/helper/dummy-cert.pem diff --git a/test/helper/utils.js b/tests/helper/utils.js similarity index 100% rename from test/helper/utils.js rename to tests/helper/utils.js diff --git a/test/playground/index.js b/tests/playground/index.js similarity index 96% rename from test/playground/index.js rename to tests/playground/index.js index 98ddfa2..7f901cb 100644 --- a/test/playground/index.js +++ b/tests/playground/index.js @@ -7,7 +7,7 @@ const domain = 'Switcher API'; const component = 'switcher-client-js'; const environment = 'default'; const url = 'https://api.switcherapi.com'; -const snapshotLocation = './test/playground/snapshot/'; +const snapshotLocation = './tests/playground/snapshot/'; /** * Playground environment for showcasing the API @@ -23,14 +23,14 @@ async function setupSwitcher(local) { * This code snippet is a minimal example of how to configure and use Switcher4Deno locally. * No remote API account is required. * - * Snapshot is loaded from file at test/playground/snapshot/local.json + * Snapshot is loaded from file at tests/playground/snapshot/local.json */ const _testLocal = async () => { Client.buildContext({ domain: 'Local Playground', environment: 'local' }, { - snapshotLocation: './test/playground/snapshot/', + snapshotLocation: './tests/playground/snapshot/', local: true }); diff --git a/test/playground/snapshot/default.json b/tests/playground/snapshot/default.json similarity index 100% rename from test/playground/snapshot/default.json rename to tests/playground/snapshot/default.json diff --git a/test/playground/snapshot/local.json b/tests/playground/snapshot/local.json similarity index 100% rename from test/playground/snapshot/local.json rename to tests/playground/snapshot/local.json diff --git a/test/snapshot/default.json b/tests/snapshot/default.json similarity index 83% rename from test/snapshot/default.json rename to tests/snapshot/default.json index 6cef193..a2d3174 100644 --- a/test/snapshot/default.json +++ b/tests/snapshot/default.json @@ -127,6 +127,33 @@ "components": [] } ] + }, + { + "name": "Relay test", + "description": "Relay group", + "activated": true, + "config": [ + { + "key": "USECASE103", + "description": "Relay enabled", + "activated": true, + "relay": { + "type": "VALIDATOR", + "activated": true + }, + "components": [] + }, + { + "key": "USECASE104", + "description": "Relay disabled", + "relay": { + "type": "VALIDATOR", + "activated": false + }, + "activated": true, + "components": [] + } + ] } ] } diff --git a/test/snapshot/dev.json b/tests/snapshot/dev.json similarity index 100% rename from test/snapshot/dev.json rename to tests/snapshot/dev.json diff --git a/test/snapshot/dev_v2.json b/tests/snapshot/dev_v2.json similarity index 100% rename from test/snapshot/dev_v2.json rename to tests/snapshot/dev_v2.json diff --git a/test/strategy-operations/date.test.js b/tests/strategy-operations/date.test.js similarity index 100% rename from test/strategy-operations/date.test.js rename to tests/strategy-operations/date.test.js diff --git a/test/strategy-operations/network.test.js b/tests/strategy-operations/network.test.js similarity index 100% rename from test/strategy-operations/network.test.js rename to tests/strategy-operations/network.test.js diff --git a/test/strategy-operations/numeric.test.js b/tests/strategy-operations/numeric.test.js similarity index 100% rename from test/strategy-operations/numeric.test.js rename to tests/strategy-operations/numeric.test.js diff --git a/test/strategy-operations/payload.test.js b/tests/strategy-operations/payload.test.js similarity index 100% rename from test/strategy-operations/payload.test.js rename to tests/strategy-operations/payload.test.js diff --git a/test/strategy-operations/regex.test.js b/tests/strategy-operations/regex.test.js similarity index 100% rename from test/strategy-operations/regex.test.js rename to tests/strategy-operations/regex.test.js diff --git a/test/strategy-operations/time.test.js b/tests/strategy-operations/time.test.js similarity index 100% rename from test/strategy-operations/time.test.js rename to tests/strategy-operations/time.test.js diff --git a/test/strategy-operations/value.test.js b/tests/strategy-operations/value.test.js similarity index 100% rename from test/strategy-operations/value.test.js rename to tests/strategy-operations/value.test.js diff --git a/test/switcher-client.test.js b/tests/switcher-client.test.js similarity index 83% rename from test/switcher-client.test.js rename to tests/switcher-client.test.js index 1890f3c..045d489 100644 --- a/test/switcher-client.test.js +++ b/tests/switcher-client.test.js @@ -16,29 +16,29 @@ const contextSettings = { }; const options = { - snapshotLocation: './test/snapshot/', - local: true, - logger: true, - regexMaxBlackList: 1, + snapshotLocation: './tests/snapshot/', + local: true, + logger: true, + regexMaxBlackList: 1, regexMaxTimeLimit: 500 }; describe('E2E test - Switcher local:', function () { - this.beforeAll(async function() { + this.beforeAll(async function () { Client.buildContext(contextSettings, options); await Client.loadSnapshot(); switcher = Client.getSwitcher(); }); - this.afterAll(function() { + this.afterAll(function () { Client.unloadSnapshot(); rmdir('//somewhere/', () => { return; }); }); - this.beforeEach(function() { + this.beforeEach(function () { Client.clearLogger(); switcher = Client.getSwitcher(); }); @@ -62,11 +62,11 @@ describe('E2E test - Switcher local:', function () { await switcher.isItOn('FF2FOR2020'); const log = Client.getExecution(switcher); - + assert.equal(log.key, 'FF2FOR2020'); assert.sameDeepMembers(log.input, [ - [ 'VALUE_VALIDATION', 'Japan' ], - [ 'NETWORK_VALIDATION', '10.0.0.3' ]]); + ['VALUE_VALIDATION', 'Japan'], + ['NETWORK_VALIDATION', '10.0.0.3']]); assert.equal(log.response.reason, 'Success'); assert.equal(log.response.result, true); }); @@ -151,40 +151,40 @@ describe('E2E test - Switcher local:', function () { const result = await switcher.isItOn(); assert.isFalse(result); - assert.equal(Client.getLogger('FF2FOR2023')[0].response.reason, + assert.equal(Client.getLogger('FF2FOR2023')[0].response.reason, `Strategy '${StrategiesType.PAYLOAD}' does not agree`); }); it('should be invalid - Input (IP) does not match', async function () { await switcher .checkValue('Japan') - .checkNetwork('192.168.0.2') + .checkNetwork('192.168.0.2') .prepare('FF2FOR2020'); const result = await switcher.isItOn(); assert.isFalse(result); - assert.equal(Client.getLogger('FF2FOR2020')[0].response.reason, + assert.equal(Client.getLogger('FF2FOR2020')[0].response.reason, `Strategy '${StrategiesType.NETWORK}' does not agree`); }); it('should be invalid - Input not provided', async function () { const result = await switcher.isItOn('FF2FOR2020'); assert.isFalse(result); - assert.equal(Client.getLogger('FF2FOR2020')[0].response.reason, + assert.equal(Client.getLogger('FF2FOR2020')[0].response.reason, `Strategy '${StrategiesType.NETWORK}' did not receive any input`); }); it('should be invalid - Switcher config disabled', async function () { const result = await switcher.isItOn('FF2FOR2031'); assert.isFalse(result); - assert.equal(Client.getLogger('FF2FOR2031')[0].response.reason, + assert.equal(Client.getLogger('FF2FOR2031')[0].response.reason, 'Config disabled'); }); it('should be invalid - Switcher group disabled', async function () { const result = await switcher.isItOn('FF2FOR2040'); assert.isFalse(result); - assert.equal(Client.getLogger('FF2FOR2040')[0].response.reason, + assert.equal(Client.getLogger('FF2FOR2040')[0].response.reason, 'Group disabled'); }); @@ -226,19 +226,19 @@ describe('E2E test - Switcher local:', function () { }); describe('E2E test - Client testing (assume) feature:', function () { - this.beforeAll(async function() { + this.beforeAll(async function () { Client.buildContext(contextSettings, options); await Client.loadSnapshot(); switcher = Client.getSwitcher(); }); - this.afterAll(function() { + this.afterAll(function () { Client.unloadSnapshot(); TimedMatch.terminateWorker(); }); - this.beforeEach(function() { + this.beforeEach(function () { Client.clearLogger(); Client.forget('FF2FOR2020'); switcher = Client.getSwitcher(); @@ -249,11 +249,11 @@ describe('E2E test - Client testing (assume) feature:', function () { .checkValue('Japan') .checkNetwork('10.0.0.3') .prepare('FF2FOR2020'); - + assert.isTrue(await switcher.isItOn()); Client.assume('FF2FOR2020').false(); assert.isFalse(await switcher.isItOn()); - + Client.forget('FF2FOR2020'); assert.isTrue(await switcher.isItOn()); }); @@ -278,9 +278,9 @@ describe('E2E test - Client testing (assume) feature:', function () { it('should be valid assuming unknown key to be true and throw error when forgetting', async function () { await switcher .checkValue('Japan') - .checkNetwork('10.0.0.3') + .checkNetwork('10.0.0.3') .prepare('UNKNOWN'); - + Client.assume('UNKNOWN').true(); assert.isTrue(await switcher.isItOn()); @@ -293,12 +293,12 @@ describe('E2E test - Client testing (assume) feature:', function () { .checkValue('Canada') // result to be false .checkNetwork('10.0.0.3') .prepare('FF2FOR2020'); - + assert.isFalse(await switcher.isItOn()); Client.assume('FF2FOR2020').true() .when(StrategiesType.VALUE, 'Canada') // manipulate the condition to result to true .and(StrategiesType.NETWORK, '10.0.0.3'); - + assert.isTrue(await switcher.isItOn()); }); @@ -307,20 +307,20 @@ describe('E2E test - Client testing (assume) feature:', function () { .checkValue('Japan') .checkNetwork('10.0.0.3') .prepare('FF2FOR2020'); - + assert.isTrue(await switcher.isItOn()); Client.assume('FF2FOR2020').true() .when(StrategiesType.VALUE, ['Brazil', 'Japan']) .and(StrategiesType.NETWORK, ['10.0.0.4', '192.168.0.1']); - + assert.isFalse(await switcher.isItOn()); }); }); describe('Type placeholders:', function () { - - this.afterAll(function() { + + this.afterAll(function () { deleteGeneratedSnapshot('./generated-snapshots'); }); @@ -337,4 +337,55 @@ describe('Type placeholders:', function () { assert.isNotNull(switcherContext); assert.isNotNull(switcherOptions); }); +}); + +describe('E2E test - Restrict Relay:', function () { + this.beforeAll(async function () { + Client.buildContext(contextSettings, options); + + await Client.loadSnapshot(); + }); + + this.afterAll(function () { + Client.unloadSnapshot(); + TimedMatch.terminateWorker(); + }); + + this.beforeEach(function () { + Client.clearLogger(); + }); + + it('should return false when Relay is enabled (restrict default: true)', async function () { + Client.buildContext(contextSettings, { + snapshotLocation: options.snapshotLocation, local: true + }); + + await Client.loadSnapshot(); + + switcher = Client.getSwitcher(); + assert.isFalse(await switcher.isItOn('USECASE103')); + }); + + it('should return true when Relay is enabled (restrict: false)', async function () { + Client.buildContext(contextSettings, { + snapshotLocation: options.snapshotLocation, local: true, restrictRelay: false + }); + + await Client.loadSnapshot(); + + switcher = Client.getSwitcher(); + assert.isTrue(await switcher.isItOn('USECASE103')); + }); + + it('should return true when Relay is disabled (restrict: true)', async function () { + Client.buildContext(contextSettings, { + snapshotLocation: options.snapshotLocation, local: true, restrictRelay: true + }); + + await Client.loadSnapshot(); + + switcher = Client.getSwitcher(); + assert.isTrue(await switcher.isItOn('USECASE104')); + }); + }); \ No newline at end of file diff --git a/test/switcher-functional.test.js b/tests/switcher-functional.test.js similarity index 98% rename from test/switcher-functional.test.js rename to tests/switcher-functional.test.js index 66bb9f4..bc6c59b 100644 --- a/test/switcher-functional.test.js +++ b/tests/switcher-functional.test.js @@ -12,7 +12,7 @@ describe('Integrated test - Switcher:', function () { let contextSettings; this.afterAll(function() { - unwatchFile('./test/snapshot/default.json'); + unwatchFile('./tests/snapshot/default.json'); }); this.beforeEach(function() { @@ -213,7 +213,7 @@ describe('Integrated test - Switcher:', function () { const forceRemoteOptions = { local: true, - snapshotLocation: './test/snapshot/', + snapshotLocation: './tests/snapshot/', regexSafe: false }; @@ -322,7 +322,7 @@ describe('Integrated test - Switcher:', function () { given(fetchStub, 0, { status: 429 }); //test - Client.buildContext(contextSettings, { silentMode: '5m', regexSafe: false, snapshotLocation: './test/snapshot/' }); + Client.buildContext(contextSettings, { silentMode: '5m', regexSafe: false, snapshotLocation: './tests/snapshot/' }); await Client.checkSwitchers(['FEATURE01', 'FEATURE02']).catch(e => { assert.equal(e.message, 'Something went wrong: [FEATURE01,FEATURE02] not found'); }); @@ -337,7 +337,7 @@ describe('Integrated test - Switcher:', function () { // test let asyncErrorMessage = null; - Client.buildContext(contextSettings, { silentMode: '5m', regexSafe: false, snapshotLocation: './test/snapshot/' }); + Client.buildContext(contextSettings, { silentMode: '5m', regexSafe: false, snapshotLocation: './tests/snapshot/' }); Client.subscribeNotifyError((error) => asyncErrorMessage = error.message); const switcher = Client.getSwitcher(); @@ -441,7 +441,7 @@ describe('Integrated test - Switcher:', function () { }); it('should NOT throw when certPath is valid', function() { - assert.doesNotThrow(() => Client.buildContext(contextSettings, { certPath: './test/helper/dummy-cert.pem' })); + assert.doesNotThrow(() => Client.buildContext(contextSettings, { certPath: './tests/helper/dummy-cert.pem' })); }); it('should renew the token after expiration', async function () { @@ -589,7 +589,7 @@ describe('Integrated test - Switcher:', function () { // setup context to read the snapshot in case the API does not respond Client.buildContext(contextSettings, { - snapshotLocation: './test/snapshot/', + snapshotLocation: './tests/snapshot/', regexSafe: false, silentMode: '2s' }); @@ -641,7 +641,7 @@ describe('Integrated test - Switcher:', function () { // test Client.buildContext(contextSettings, { - snapshotLocation: './test/snapshot/', + snapshotLocation: './tests/snapshot/', regexSafe: false, silentMode: '5m' }); diff --git a/test/switcher-integrated.test.js b/tests/switcher-integrated.test.js similarity index 100% rename from test/switcher-integrated.test.js rename to tests/switcher-integrated.test.js diff --git a/test/switcher-snapshot.test.js b/tests/switcher-snapshot.test.js similarity index 97% rename from test/switcher-snapshot.test.js rename to tests/switcher-snapshot.test.js index 6b059da..26f4d35 100644 --- a/test/switcher-snapshot.test.js +++ b/tests/switcher-snapshot.test.js @@ -19,7 +19,7 @@ describe('E2E test - Switcher local - Snapshot:', function () { const environment = 'dev'; const url = 'http://localhost:3000'; - const dataBuffer = readFileSync('./test/snapshot/dev.json'); + const dataBuffer = readFileSync('./tests/snapshot/dev.json'); const dataJSON = dataBuffer.toString(); let fetchStub; @@ -30,7 +30,7 @@ describe('E2E test - Switcher local - Snapshot:', function () { beforeEach(function() { Client.buildContext({ url, apiKey, domain, component, environment }, { - snapshotLocation: './test/snapshot/', + snapshotLocation: './tests/snapshot/', local: true, regexSafe: false }); @@ -196,7 +196,7 @@ describe('E2E test - Switcher local - Snapshot:', function () { unlinkSync(`generated-snapshots/${environment}.json`); }); - it('should not throw when switcher keys provided were configured properly', async function () { + it('should NOT throw when switcher keys provided were configured properly', async function () { await Client.loadSnapshot(); await assertResolve(assert, Client.checkSwitchers(['FF2FOR2030'])); }); @@ -274,10 +274,10 @@ describe('E2E test - Snapshot AutoUpdater:', function () { const environment = 'dev'; const url = 'http://localhost:3000'; - const dataBuffer = readFileSync('./test/snapshot/dev.json'); + const dataBuffer = readFileSync('./tests/snapshot/dev.json'); const dataJSON = dataBuffer.toString(); - const dataBufferV2 = readFileSync('./test/snapshot/dev_v2.json'); + const dataBufferV2 = readFileSync('./tests/snapshot/dev_v2.json'); const dataJSONV2 = dataBufferV2.toString(); let fetchStub; diff --git a/test/switcher-watch-snapshot.test.js b/tests/switcher-watch-snapshot.test.js similarity index 98% rename from test/switcher-watch-snapshot.test.js rename to tests/switcher-watch-snapshot.test.js index c96a4a7..7e4b50d 100644 --- a/test/switcher-watch-snapshot.test.js +++ b/tests/switcher-watch-snapshot.test.js @@ -23,7 +23,7 @@ const beforeAll = () => { mkdirSync('generated-watch-snapshots/', { recursive: true }); } - const dataBuffer = readFileSync('./test/snapshot/dev.json'); + const dataBuffer = readFileSync('./tests/snapshot/dev.json'); devJSON = JSON.parse(dataBuffer.toString()); devJSON.data.domain.group[0].config[0].activated = true; }; diff --git a/test/utils/datemoment.test.js b/tests/utils/datemoment.test.js similarity index 78% rename from test/utils/datemoment.test.js rename to tests/utils/datemoment.test.js index 63a09d2..8e0c4d7 100644 --- a/test/utils/datemoment.test.js +++ b/tests/utils/datemoment.test.js @@ -3,37 +3,37 @@ import DateMoment from '../../src/lib/utils/datemoment.js'; describe('Manipulate date and time', () => { - it('Should be true when the compared date is before', async () => { + it('should be true when the compared date is before', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.isTrue(todayMoment.isSameOrBefore(todayMoment.getDate(), '11:00')); }); - it('Should be false when the compared date is not before', async () => { + it('should be false when the compared date is not before', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.isFalse(todayMoment.isSameOrBefore(todayMoment.getDate(), '09:00')); }); - it('Should be true when the compared date is after', async () => { + it('should be true when the compared date is after', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.isTrue(todayMoment.isSameOrAfter(todayMoment.getDate(), '09:00')); }); - it('Should be false when the compared date is not after', async () => { + it('should be false when the compared date is not after', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.isFalse(todayMoment.isSameOrAfter(todayMoment.getDate(), '11:00')); }); - it('Should be true when the compared date is in between', async () => { + it('should be true when the compared date is in between', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.isTrue(todayMoment.isBetween(todayMoment.getDate(), todayMoment.getDate(), '09:00', '10:30')); }); - it('Should be false when the compared date is not in between', async () => { + it('should be false when the compared date is not in between', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.isFalse(todayMoment.isBetween(todayMoment.getDate(), todayMoment.getDate(), '10:01', '10:30')); }); - it('Should add 1 second to date', async () => { + it('should add 1 second to date', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); const beforeAdding = todayMoment.getDate().getSeconds(); const afterAdding = todayMoment.add(1, 's').getDate().getSeconds(); @@ -41,21 +41,21 @@ describe('Manipulate date and time', () => { assert.isTrue(diff == 1); }); - it('Should add 1 minute to date', async () => { + it('should add 1 minute to date', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); const beforeAdding = todayMoment.getDate().getMinutes(); const afterAdding = todayMoment.add(1, 'm').getDate().getMinutes(); assert.isTrue((afterAdding - beforeAdding) == 1); }); - it('Should add 1 hour to date', async () => { + it('should add 1 hour to date', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); const beforeAdding = todayMoment.getDate().getHours(); const afterAdding = todayMoment.add(1, 'h').getDate().getHours(); assert.isTrue((afterAdding - beforeAdding) == 1); }); - it('Should return error for using not compatible unit', async () => { + it('should return error for using not compatible unit', async () => { const todayMoment = new DateMoment(new Date(), '10:00'); assert.throws(() => todayMoment.add(1, 'x'), 'Unit x not compatible - try [s, m or h]'); }); diff --git a/test/utils/timed-match.test.js b/tests/utils/timed-match.test.js similarity index 100% rename from test/utils/timed-match.test.js rename to tests/utils/timed-match.test.js