diff --git a/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml
index c94916b..470b1d5 100644
--- a/.github/workflows/ci-cd.yml
+++ b/.github/workflows/ci-cd.yml
@@ -19,8 +19,7 @@ permissions:
jobs:
build:
name: Build
- # @TODO rollback to ubuntu-latest eventually. ATM, `npm run test-browser` fails when using ubuntu-latest (ubuntu-22.04) with "ERROR [launcher]: Cannot start ChromeHeadless"
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
@@ -56,7 +55,7 @@ jobs:
upload-stage:
name: Upload assets
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
needs: build
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/development' }}
strategy:
@@ -99,7 +98,7 @@ jobs:
upload-prod:
name: Upload assets
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
needs: build
if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
strategy:
diff --git a/.github/workflows/sonar-scan.yml b/.github/workflows/sonar-scan.yml
index c114c56..f10bda2 100644
--- a/.github/workflows/sonar-scan.yml
+++ b/.github/workflows/sonar-scan.yml
@@ -12,7 +12,7 @@ on:
jobs:
build:
name: Build
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
diff --git a/.github/workflows/update-license-year.yml b/.github/workflows/update-license-year.yml
index 199a0ef..7e0a945 100644
--- a/.github/workflows/update-license-year.yml
+++ b/.github/workflows/update-license-year.yml
@@ -10,7 +10,7 @@ permissions:
jobs:
test:
- runs-on: ubuntu-20.04
+ runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
diff --git a/CHANGES.txt b/CHANGES.txt
index f267b97..c0c9895 100644
--- a/CHANGES.txt
+++ b/CHANGES.txt
@@ -1,3 +1,11 @@
+1.2.0 (March 31, 2025)
+ - Added a new optional argument to the client `getTreatment` methods to allow passing additional evaluation options, such as a map of properties to append to the generated impressions sent to Split backend. Read more in our docs.
+ - Added two new configuration options for the SDK's `InLocalStorage` module to control the behavior of the persisted rollout plan cache in the browser:
+ - `expirationDays` to specify the validity period of the rollout plan cache in days.
+ - `clearOnInit` to clear the rollout plan cache on SDK initialization.
+ - Updated SDK_READY_FROM_CACHE event when using `InLocalStorage` module to be emitted alongside the SDK_READY event if it has not already been emitted.
+ - Updated @splitsoftware/splitio-commons package to version 2.2.0.
+
1.1.0 (January 17, 2025)
- Added support for the new impressions tracking toggle available on feature flags, both respecting the setting and including the new field being returned on `SplitView` type objects. Read more in our docs.
- Bugfixing - Updated @splitsoftware/splitio-commons package to version 2.1.0, which properly handles rejected promises when using targeting rules with segment matchers in consumer modes (e.g., Redis and Pluggable storages).
diff --git a/README.md b/README.md
index 2c68837..9f4babf 100644
--- a/README.md
+++ b/README.md
@@ -64,6 +64,7 @@ Split has built and maintains SDKs for:
* .NET [Github](https://github.com/splitio/dotnet-client) [Docs](https://help.split.io/hc/en-us/articles/360020240172--NET-SDK)
* Android [Github](https://github.com/splitio/android-client) [Docs](https://help.split.io/hc/en-us/articles/360020343291-Android-SDK)
* Angular [Github](https://github.com/splitio/angular-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/6495326064397-Angular-utilities)
+* Elixir thin-client [Github](https://github.com/splitio/elixir-thin-client) [Docs](https://help.split.io/hc/en-us/articles/26988707417869-Elixir-Thin-Client-SDK)
* Flutter [Github](https://github.com/splitio/flutter-sdk-plugin) [Docs](https://help.split.io/hc/en-us/articles/8096158017165-Flutter-plugin)
* GO [Github](https://github.com/splitio/go-client) [Docs](https://help.split.io/hc/en-us/articles/360020093652-Go-SDK)
* iOS [Github](https://github.com/splitio/ios-client) [Docs](https://help.split.io/hc/en-us/articles/360020401491-iOS-SDK)
@@ -83,4 +84,4 @@ For a comprehensive list of open source projects visit our [Github page](https:/
**Learn more about Split:**
-Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](http://help.split.io) for more detailed information.
+Visit [split.io/product](https://www.split.io/product) for an overview of Split, or visit our documentation at [help.split.io](https://help.split.io) for more detailed information.
diff --git a/karma/config.js b/karma/config.js
index 40cbe1c..83b3539 100644
--- a/karma/config.js
+++ b/karma/config.js
@@ -24,10 +24,15 @@ module.exports = {
'tap'
],
- // Run on Chrome Headless. Use 'Chrome' instead to run on full browser for debugging
- browsers: [
- 'ChromeHeadless'
- ],
+ // Run on Chrome Headless
+ customLaunchers: {
+ ChromeHeadlessNoSandbox: {
+ base: 'ChromeHeadless',
+ // Flags required to run in ubuntu-22.04 or above (https://chromium.googlesource.com/chromium/src/+/master/docs/linux/suid_sandbox_development.md)
+ flags: ['--no-sandbox', '--disable-setuid-sandbox']
+ }
+ },
+ browsers: ['ChromeHeadlessNoSandbox'],
// Continuous Integration mode
// if true, it capture browsers, run tests and exit. Set false for debugging
diff --git a/package-lock.json b/package-lock.json
index 9b030df..feb5856 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,15 +1,15 @@
{
"name": "@splitsoftware/splitio-browserjs",
- "version": "1.1.0",
+ "version": "1.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@splitsoftware/splitio-browserjs",
- "version": "1.1.0",
+ "version": "1.2.0",
"license": "Apache-2.0",
"dependencies": {
- "@splitsoftware/splitio-commons": "2.1.0",
+ "@splitsoftware/splitio-commons": "2.2.0",
"tslib": "^2.3.1",
"unfetch": "^4.2.0"
},
@@ -70,89 +70,20 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.22.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
- "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+ "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/highlight": "^7.22.13",
- "chalk": "^2.4.2"
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
- "node_modules/@babel/code-frame/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@babel/code-frame/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@babel/code-frame/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@babel/compat-data": {
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.2.tgz",
@@ -340,19 +271,21 @@
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=6.9.0"
}
@@ -367,109 +300,28 @@
}
},
"node_modules/@babel/helpers": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
- "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
+ "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/template": "^7.22.15",
- "@babel/traverse": "^7.23.2",
- "@babel/types": "^7.23.0"
+ "@babel/template": "^7.27.0",
+ "@babel/types": "^7.27.0"
},
"engines": {
"node": ">=6.9.0"
}
},
- "node_modules/@babel/highlight": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
- "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
- "dev": true,
- "dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@babel/highlight/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "node_modules/@babel/highlight/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@babel/highlight/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/highlight/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "node_modules/@babel/parser": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
+ "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "has-flag": "^3.0.0"
+ "@babel/types": "^7.27.0"
},
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/parser": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
- "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
- "dev": true,
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -640,10 +492,11 @@
}
},
"node_modules/@babel/runtime": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
- "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
+ "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
"dev": true,
+ "license": "MIT",
"optional": true,
"peer": true,
"dependencies": {
@@ -654,14 +507,15 @@
}
},
"node_modules/@babel/template": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
- "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
+ "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/code-frame": "^7.22.13",
- "@babel/parser": "^7.22.15",
- "@babel/types": "^7.22.15"
+ "@babel/code-frame": "^7.26.2",
+ "@babel/parser": "^7.27.0",
+ "@babel/types": "^7.27.0"
},
"engines": {
"node": ">=6.9.0"
@@ -698,14 +552,14 @@
}
},
"node_modules/@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
+ "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
"dev": true,
+ "license": "MIT",
"dependencies": {
- "@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
},
"engines": {
"node": ">=6.9.0"
@@ -1542,9 +1396,10 @@
"dev": true
},
"node_modules/@splitsoftware/splitio-commons": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.1.0.tgz",
- "integrity": "sha512-7SJRBia0Pi72s76drH8kG2cVnCqkjMHMJQWJSFnG+rE/UOx9AROmuviOkY6tv6qYPJFqFQQGHGX6lXjxZhYzkw==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.2.0.tgz",
+ "integrity": "sha512-ywWDh2fM4/EqJ1AByjXM13gAal+z/WSGiBQ5OZmjpL/iqFLENy3yo/GwsxR/ataOi27XbRQTeQbE/eD7HVnWiA==",
+ "license": "Apache-2.0",
"dependencies": {
"@types/ioredis": "^4.28.0",
"tslib": "^2.3.1"
@@ -6074,7 +5929,8 @@
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
- "dev": true
+ "dev": true,
+ "license": "MIT"
},
"node_modules/js-yaml": {
"version": "4.1.0",
@@ -8146,9 +8002,9 @@
"dev": true
},
"node_modules/serialize-javascript": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
- "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"dependencies": {
"randombytes": "^2.1.0"
@@ -8683,10 +8539,11 @@
}
},
"node_modules/tar-fs": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
- "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
+ "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
"dev": true,
+ "license": "MIT",
"dependencies": {
"chownr": "^1.1.1",
"mkdirp-classic": "^0.5.2",
@@ -8814,15 +8671,6 @@
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
"dev": true
},
- "node_modules/to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@@ -9562,71 +9410,14 @@
}
},
"@babel/code-frame": {
- "version": "7.22.13",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
- "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
+ "version": "7.26.2",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz",
+ "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==",
"dev": true,
"requires": {
- "@babel/highlight": "^7.22.13",
- "chalk": "^2.4.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
+ "@babel/helper-validator-identifier": "^7.25.9",
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
}
},
"@babel/compat-data": {
@@ -9771,15 +9562,15 @@
}
},
"@babel/helper-string-parser": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
- "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz",
+ "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==",
"dev": true
},
"@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.25.9",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz",
+ "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==",
"dev": true
},
"@babel/helper-validator-option": {
@@ -9789,91 +9580,24 @@
"dev": true
},
"@babel/helpers": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.2.tgz",
- "integrity": "sha512-lzchcp8SjTSVe/fPmLwtWVBFC7+Tbn8LGHDVfDp9JGxpAY5opSaEFgt8UQvrnECWOTdji2mOWMz1rOhkHscmGQ==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
+ "integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
"dev": true,
"requires": {
- "@babel/template": "^7.22.15",
- "@babel/traverse": "^7.23.2",
- "@babel/types": "^7.23.0"
+ "@babel/template": "^7.27.0",
+ "@babel/types": "^7.27.0"
}
},
- "@babel/highlight": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
- "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
+ "@babel/parser": {
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
+ "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
"dev": true,
"requires": {
- "@babel/helper-validator-identifier": "^7.22.20",
- "chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dev": true,
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dev": true,
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dev": true,
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
- "dev": true
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "dev": true
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dev": true,
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
+ "@babel/types": "^7.27.0"
}
},
- "@babel/parser": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
- "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
- "dev": true
- },
"@babel/plugin-syntax-async-generators": {
"version": "7.8.4",
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz",
@@ -9992,9 +9716,9 @@
}
},
"@babel/runtime": {
- "version": "7.23.2",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.2.tgz",
- "integrity": "sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
+ "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
"dev": true,
"optional": true,
"peer": true,
@@ -10003,14 +9727,14 @@
}
},
"@babel/template": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
- "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
+ "integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
"dev": true,
"requires": {
- "@babel/code-frame": "^7.22.13",
- "@babel/parser": "^7.22.15",
- "@babel/types": "^7.22.15"
+ "@babel/code-frame": "^7.26.2",
+ "@babel/parser": "^7.27.0",
+ "@babel/types": "^7.27.0"
}
},
"@babel/traverse": {
@@ -10040,14 +9764,13 @@
}
},
"@babel/types": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
- "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
+ "version": "7.27.0",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
+ "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
"dev": true,
"requires": {
- "@babel/helper-string-parser": "^7.22.5",
- "@babel/helper-validator-identifier": "^7.22.20",
- "to-fast-properties": "^2.0.0"
+ "@babel/helper-string-parser": "^7.25.9",
+ "@babel/helper-validator-identifier": "^7.25.9"
}
},
"@bcoe/v8-coverage": {
@@ -10688,9 +10411,9 @@
"dev": true
},
"@splitsoftware/splitio-commons": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.1.0.tgz",
- "integrity": "sha512-7SJRBia0Pi72s76drH8kG2cVnCqkjMHMJQWJSFnG+rE/UOx9AROmuviOkY6tv6qYPJFqFQQGHGX6lXjxZhYzkw==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/@splitsoftware/splitio-commons/-/splitio-commons-2.2.0.tgz",
+ "integrity": "sha512-ywWDh2fM4/EqJ1AByjXM13gAal+z/WSGiBQ5OZmjpL/iqFLENy3yo/GwsxR/ataOi27XbRQTeQbE/eD7HVnWiA==",
"requires": {
"@types/ioredis": "^4.28.0",
"tslib": "^2.3.1"
@@ -15617,9 +15340,9 @@
}
},
"serialize-javascript": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz",
- "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==",
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.2.tgz",
+ "integrity": "sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==",
"dev": true,
"requires": {
"randombytes": "^2.1.0"
@@ -16032,9 +15755,9 @@
}
},
"tar-fs": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz",
- "integrity": "sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==",
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.2.tgz",
+ "integrity": "sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==",
"dev": true,
"requires": {
"chownr": "^1.1.1",
@@ -16138,12 +15861,6 @@
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
"dev": true
},
- "to-fast-properties": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
- "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==",
- "dev": true
- },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
diff --git a/package.json b/package.json
index 6213ced..a9a01de 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@splitsoftware/splitio-browserjs",
- "version": "1.1.0",
+ "version": "1.2.0",
"description": "Split SDK for JavaScript on Browser",
"main": "cjs/index.js",
"module": "esm/index.js",
@@ -59,7 +59,7 @@
"bugs": "https://github.com/splitio/javascript-browser-client/issues",
"homepage": "https://github.com/splitio/javascript-browser-client#readme",
"dependencies": {
- "@splitsoftware/splitio-commons": "2.1.0",
+ "@splitsoftware/splitio-commons": "2.2.0",
"tslib": "^2.3.1",
"unfetch": "^4.2.0"
},
diff --git a/src/__tests__/browserSuites/impressions-listener.spec.js b/src/__tests__/browserSuites/impressions-listener.spec.js
index ca47995..9907eab 100644
--- a/src/__tests__/browserSuites/impressions-listener.spec.js
+++ b/src/__tests__/browserSuites/impressions-listener.spec.js
@@ -46,7 +46,7 @@ export default function (assert) {
const testAttrs = { is_test: true };
// Impression listener is shared across all client instances and does not get affected by configurations.
- client.getTreatment('hierarchical_splits_test');
+ client.getTreatment('hierarchical_splits_test', undefined, { properties: { prop1: 'prop-value' } });
client2.getTreatment('qc_team');
client2.getTreatmentWithConfig('qc_team'); // Validate that the impression is the same.
client3.getTreatment('qc_team', testAttrs);
@@ -58,7 +58,8 @@ export default function (assert) {
treatment: 'no',
bucketingKey: 'impr_bucketing_2',
label: 'default rule',
- pt: undefined
+ pt: undefined,
+ properties: undefined
};
assert.equal(listener.logImpression.callCount, 4, 'Impression listener logImpression method should be called after we call client.getTreatment, once per each impression generated.');
@@ -71,7 +72,7 @@ export default function (assert) {
bucketingKey: undefined,
label: 'expected label',
changeNumber: 2828282828,
- pt: undefined
+ properties: '{"prop1":"prop-value"}'
},
attributes: undefined,
...metaData
diff --git a/src/__tests__/browserSuites/impressions.debug.spec.js b/src/__tests__/browserSuites/impressions.debug.spec.js
index 5f90b70..ce40a0f 100644
--- a/src/__tests__/browserSuites/impressions.debug.spec.js
+++ b/src/__tests__/browserSuites/impressions.debug.spec.js
@@ -75,7 +75,7 @@ export default function (fetchMock, assert) {
fetchMock.postOnce(url(settings, '/testImpressions/count'), (url, opts) => {
assert.deepEqual(JSON.parse(opts.body), {
- pf: [{ f: 'always_on_track_impressions_false', m: truncatedTimeFrame, rc: 1 }]
+ pf: [{ f: 'always_on_impressions_disabled_true', m: truncatedTimeFrame, rc: 1 }]
}, 'We should generate impression count for the feature with track impressions disabled.');
return 200;
@@ -83,7 +83,7 @@ export default function (fetchMock, assert) {
fetchMock.postOnce(url(settings, '/v1/keys/cs'), (url, opts) => {
assert.deepEqual(JSON.parse(opts.body), {
- keys: [{ fs: ['always_on_track_impressions_false'], k: 'facundo@split.io' }]
+ keys: [{ fs: ['always_on_impressions_disabled_true'], k: 'facundo@split.io' }]
}, 'We should track unique keys for the feature with track impressions disabled.');
return 200;
@@ -95,6 +95,6 @@ export default function (fetchMock, assert) {
client.getTreatment('split_with_config');
client.getTreatment('split_with_config');
client.getTreatment('split_with_config');
- assert.equal(client.getTreatment('always_on_track_impressions_false'), 'on');
+ assert.equal(client.getTreatment('always_on_impressions_disabled_true'), 'on');
});
}
diff --git a/src/__tests__/browserSuites/impressions.spec.js b/src/__tests__/browserSuites/impressions.spec.js
index 33e6010..d271beb 100644
--- a/src/__tests__/browserSuites/impressions.spec.js
+++ b/src/__tests__/browserSuites/impressions.spec.js
@@ -53,7 +53,7 @@ export default function (fetchMock, assert) {
const dependencyChildImpr = resp.filter(e => e.f === 'hierarchical_splits_test')[0];
const splitWithConfigImpr = resp.filter(e => e.f === 'split_with_config')[0];
- const alwaysOnWithTrackImpressionsFalse = resp.filter(e => e.f === 'always_on_track_impressions_false');
+ const alwaysOnWithImpressionsDisabledTrue = resp.filter(e => e.f === 'always_on_impressions_disabled_true');
assert.true(dependencyChildImpr, 'Split we wanted to evaluate should be present on the impressions.');
assert.false(resp.some(e => e.f === 'hierarchical_dep_always_on'), 'Parent split evaluations should not result in impressions.');
@@ -61,7 +61,7 @@ export default function (fetchMock, assert) {
assert.true(splitWithConfigImpr, 'Split evaluated with config should have generated an impression too.');
assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'configuration'), 'Impressions do not change with configuration evaluations.');
assert.false(Object.prototype.hasOwnProperty.call(splitWithConfigImpr.i[0], 'config'), 'Impressions do not change with configuration evaluations.');
- assert.equal(alwaysOnWithTrackImpressionsFalse.length, 0);
+ assert.equal(alwaysOnWithImpressionsDisabledTrue.length, 0);
const {
k,
@@ -100,21 +100,21 @@ export default function (fetchMock, assert) {
// finding these validate the feature names collection too
const splitWithConfigImpr = data.pf.filter(e => e.f === 'split_with_config')[0];
- const alwaysOnWithTrackImpressionsFalse = data.pf.filter(e => e.f === 'always_on_track_impressions_false')[0];
+ const alwaysOnWithImpressionsDisabledTrue = data.pf.filter(e => e.f === 'always_on_impressions_disabled_true')[0];
assert.equal(splitWithConfigImpr.rc, 2);
assert.equal(typeof splitWithConfigImpr.m, 'number');
assert.equal(splitWithConfigImpr.m, truncatedTimeFrame);
- assert.equal(alwaysOnWithTrackImpressionsFalse.rc, 1);
- assert.equal(typeof alwaysOnWithTrackImpressionsFalse.m, 'number');
- assert.equal(alwaysOnWithTrackImpressionsFalse.m, truncatedTimeFrame);
+ assert.equal(alwaysOnWithImpressionsDisabledTrue.rc, 1);
+ assert.equal(typeof alwaysOnWithImpressionsDisabledTrue.m, 'number');
+ assert.equal(alwaysOnWithImpressionsDisabledTrue.m, truncatedTimeFrame);
return 200;
});
fetchMock.postOnce(url(settings, '/v1/keys/cs'), (url, opts) => {
assert.deepEqual(JSON.parse(opts.body), {
- keys: [{ fs: [ 'always_on_track_impressions_false' ], k: 'facundo@split.io' }]
+ keys: [{ fs: [ 'always_on_impressions_disabled_true' ], k: 'facundo@split.io' }]
}, 'We should only track unique keys for features flags with track impressions disabled.');
return 200;
@@ -132,6 +132,6 @@ export default function (fetchMock, assert) {
client.getTreatmentWithConfig('split_with_config');
// Impression should not be tracked
- assert.equal(client.getTreatment('always_on_track_impressions_false'), 'on');
+ assert.equal(client.getTreatment('always_on_impressions_disabled_true'), 'on');
});
}
diff --git a/src/__tests__/browserSuites/ready-from-cache.spec.js b/src/__tests__/browserSuites/ready-from-cache.spec.js
index b41220f..2afb8cf 100644
--- a/src/__tests__/browserSuites/ready-from-cache.spec.js
+++ b/src/__tests__/browserSuites/ready-from-cache.spec.js
@@ -1,3 +1,5 @@
+import sinon from 'sinon';
+import { nearlyEqual } from '../testUtils';
import { getStorageHash } from '@splitsoftware/splitio-commons/src/storages/KeyBuilder';
import { SplitFactory, InLocalStorage } from '../../';
@@ -5,8 +7,6 @@ import splitChangesMock1 from '../mocks/splitchanges.since.-1.json';
import splitChangesMock2 from '../mocks/splitchanges.since.1457552620999.json';
import membershipsNicolas from '../mocks/memberships.nicolas@split.io.json';
-import { nearlyEqual } from '../testUtils';
-
const DEFAULT_CACHE_EXPIRATION_IN_MILLIS = 864000000; // 10 days
const alwaysOnSplitInverted = JSON.stringify({
@@ -94,7 +94,7 @@ export default function (fetchMock, assert) {
events: 'https://events.baseurl/readyFromCacheEmpty'
};
localStorage.clear();
- t.plan(3);
+ t.plan(4);
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=-1', { status: 200, body: splitChangesMock1 });
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
@@ -122,18 +122,17 @@ export default function (fetchMock, assert) {
t.end();
});
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE if there is no cache.');
- t.end();
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.on(client.Event.SDK_READY, () => {
- t.pass('It should emit SDK_READY alone, since there was no cache.');
+ t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache');
});
client2.on(client.Event.SDK_READY, () => {
- t.pass('It should emit SDK_READY alone, since there was no cache.');
+ t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache');
});
client3.on(client.Event.SDK_READY, () => {
- t.pass('It should emit SDK_READY alone, since there was no cache.');
+ t.true(client.__getStatus().isReadyFromCache, 'Client should emit SDK_READY and it should be ready from cache');
});
});
@@ -146,17 +145,17 @@ export default function (fetchMock, assert) {
localStorage.clear();
t.plan(12 * 2 + 3);
- fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', function () {
+ fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: { ...splitChangesMock1, since: 25 }, headers: {} }), 200); }); // 400ms is how long it'll take to reply with Splits, no SDK_READY should be emitted before that.
});
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
- fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', function () {
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), 400); }); // First client gets segments before splits. No segment cache loading (yet)
});
- fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', function () {
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 700); }); // Second client gets segments after 700ms
});
- fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', function () {
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 1000); }); // Third client memberships will come after 1s
});
fetchMock.postOnce(testUrls.events + '/testImpressions/bulk', 200);
@@ -177,7 +176,6 @@ export default function (fetchMock, assert) {
readyTimeout: 0.85
},
urls: testUrls,
- debug: true
});
const client = splitio.client();
const client2 = splitio.client('nicolas2@split.io');
@@ -245,7 +243,7 @@ export default function (fetchMock, assert) {
});
});
- assert.test(t => { // Testing when we start with cached data and not expired (lastUpdate item higher than expirationTimestamp)
+ assert.test(t => { // Testing when we start with cached data and not expired (lastUpdate timestamp higher than default (10) expirationDays ago)
const testUrls = {
sdk: 'https://sdk.baseurl/readyFromCacheWithData3',
events: 'https://events.baseurl/readyFromCacheWithData3'
@@ -253,18 +251,18 @@ export default function (fetchMock, assert) {
localStorage.clear();
t.plan(12 * 2 + 5);
- fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', function () {
+ fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=25', () => {
t.equal(localStorage.getItem('readyFromCache_3.SPLITIO.split.always_on'), alwaysOnSplitInverted, 'feature flags must not be cleaned from cache');
return new Promise(res => { setTimeout(() => res({ status: 200, body: { ...splitChangesMock1, since: 25 }, headers: {} }), 200); }); // 400ms is how long it'll take to reply with Splits, no SDK_READY should be emitted before that.
});
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
- fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', function () {
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), 400); }); // First client gets segments before splits. No segment cache loading (yet)
});
- fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', function () {
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 700); }); // Second client gets segments after 700ms
});
- fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', function () {
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', () => {
return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 1000); }); // Third client memberships will come after 1s
});
fetchMock.get(testUrls.sdk + '/memberships/nicolas4%40split.io', { 'ms': {} });
@@ -287,7 +285,6 @@ export default function (fetchMock, assert) {
readyTimeout: 0.85
},
urls: testUrls,
- debug: true
});
const client = splitio.client();
const client2 = splitio.client('nicolas2@split.io');
@@ -362,35 +359,38 @@ export default function (fetchMock, assert) {
});
});
- assert.test(t => { // Testing when we start with cached data but expired (lastUpdate item lower than expirationTimestamp)
+ assert.test(t => { // Testing when we start with cached data but expired (lastUpdate timestamp lower than custom (1) expirationDays ago)
+ const CLIENT_READY_MS = 400, CLIENT2_READY_MS = 700, CLIENT3_READY_MS = 1000;
+
const testUrls = {
sdk: 'https://sdk.baseurl/readyFromCacheWithData4',
events: 'https://events.baseurl/readyFromCacheWithData4'
};
localStorage.clear();
- fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=-1', function () {
+ fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=-1', () => {
t.equal(localStorage.getItem('some_user_item'), 'user_item', 'user items at localStorage must not be changed');
t.equal(localStorage.getItem('readyFromCache_4.SPLITIO.hash'), expectedHashNullFilter, 'storage hash must not be changed');
- t.equal(localStorage.length, 2, 'feature flags cache data must be cleaned from localStorage');
+ t.true(nearlyEqual(parseInt(localStorage.getItem('readyFromCache_4.SPLITIO.lastClear'), 10), Date.now()), 'storage lastClear timestamp must be updated');
+ t.equal(localStorage.length, 3, 'feature flags cache data must be cleaned from localStorage');
return { status: 200, body: splitChangesMock1 };
});
fetchMock.get(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
- fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', function () {
- return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), 400); }); // First client gets segments before splits. No segment cache loading (yet)
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', () => {
+ return new Promise(res => { setTimeout(() => res({ status: 200, body: membershipsNicolas, headers: {} }), CLIENT_READY_MS); }); // First client gets segments before splits. No segment cache loading (yet)
});
- fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', function () {
- return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 700); }); // Second client gets segments after 700ms
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas2%40split.io', () => {
+ return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), CLIENT2_READY_MS); }); // Second client gets segments after 700ms
});
- fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', function () {
- return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), 1000); }); // Third client memberships will come after 1s
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas3%40split.io', () => {
+ return new Promise(res => { setTimeout(() => res({ status: 200, body: { 'ms': {} }, headers: {} }), CLIENT3_READY_MS); }); // Third client memberships will come after 1s
});
fetchMock.postOnce(testUrls.events + '/testImpressions/bulk', 200);
fetchMock.postOnce(testUrls.events + '/testImpressions/count', 200);
localStorage.setItem('some_user_item', 'user_item');
localStorage.setItem('readyFromCache_4.SPLITIO.splits.till', 25);
- localStorage.setItem('readyFromCache_4.SPLITIO.splits.lastUpdated', Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS - 1); // -1 to ensure having an expired lastUpdated item
+ localStorage.setItem('readyFromCache_4.SPLITIO.splits.lastUpdated', Date.now() - DEFAULT_CACHE_EXPIRATION_IN_MILLIS / 10 - 1); // -1 to ensure having an expired lastUpdated item
localStorage.setItem('readyFromCache_4.SPLITIO.split.always_on', alwaysOnSplitInverted);
localStorage.setItem('readyFromCache_4.SPLITIO.hash', expectedHashNullFilter);
@@ -398,13 +398,13 @@ export default function (fetchMock, assert) {
const splitio = SplitFactory({
...baseConfig,
storage: InLocalStorage({
- prefix: 'readyFromCache_4'
+ prefix: 'readyFromCache_4',
+ expirationDays: 1
}),
startup: {
readyTimeout: 0.85
},
urls: testUrls,
- debug: true
});
const client = splitio.client();
const client2 = splitio.client('nicolas2@split.io');
@@ -419,37 +419,34 @@ export default function (fetchMock, assert) {
});
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE if there is expired cache.');
- t.end();
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT_READY_MS), 'It should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client2.once(client2.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE if there is expired cache.');
- t.end();
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT2_READY_MS), 'It should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client3.once(client3.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE if there is expired cache.');
- t.end();
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT3_READY_MS), 'It should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.on(client.Event.SDK_READY, () => {
- t.true(Date.now() - startTime >= 400, 'It should emit SDK_READY after syncing with the cloud.');
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT_READY_MS), 'It should emit SDK_READY after syncing with the cloud.');
t.equal(client.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
});
client.ready().then(() => {
- t.true(Date.now() - startTime >= 400, 'It should resolve ready promise after syncing with the cloud.');
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT_READY_MS), 'It should resolve ready promise after syncing with the cloud.');
t.equal(client.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
});
client2.on(client2.Event.SDK_READY, () => {
- t.true(Date.now() - startTime >= 700, 'It should emit SDK_READY after syncing with the cloud.');
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT2_READY_MS), 'It should emit SDK_READY after syncing with the cloud.');
t.equal(client2.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
});
client2.ready().then(() => {
- t.true(Date.now() - startTime >= 700, 'It should resolve ready promise after syncing with the cloud.');
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT2_READY_MS), 'It should resolve ready promise after syncing with the cloud.');
t.equal(client2.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
});
client3.on(client3.Event.SDK_READY, () => {
client3.ready().then(() => {
- t.true(Date.now() - startTime >= 1000, 'It should resolve ready promise after syncing with the cloud.');
+ t.true(nearlyEqual(Date.now() - startTime, CLIENT3_READY_MS), 'It should resolve ready promise after syncing with the cloud.');
t.equal(client3.getTreatment('always_on'), 'on', 'It should evaluate treatments with updated data after syncing with the cloud.');
// Last cb: destroy clients and check that localstorage has the expected items
@@ -482,7 +479,7 @@ export default function (fetchMock, assert) {
events: 'https://events.baseurl/readyFromCache_5'
};
localStorage.clear();
- t.plan(7);
+ t.plan(8);
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&names=p1__split,p2__split', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -502,14 +499,12 @@ export default function (fetchMock, assert) {
sync: {
splitFilters: [{ type: 'byName', values: ['p2__split', 'p1__split'] }, { type: 'byName', values: ['p2__split', null] }]
},
- debug: true
});
const client = splitio.client();
const manager = splitio.manager();
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE because localStorage is cleaned and there isn\'t cached feature flags');
- t.end();
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.once(client.Event.SDK_READY, () => {
@@ -533,7 +528,7 @@ export default function (fetchMock, assert) {
events: 'https://events.baseurl/readyFromCache_5B'
};
localStorage.clear();
- t.plan(5);
+ t.plan(6);
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&names=p1__split,p2__split', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -547,14 +542,12 @@ export default function (fetchMock, assert) {
sync: {
splitFilters: [{ type: 'byName', values: ['p2__split', 'p1__split'] }, { type: 'byName', values: ['p2__split', null] }]
},
- debug: true
});
const client = splitio.client();
const manager = splitio.manager();
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE if cache is empty.');
- t.end();
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.once(client.Event.SDK_READY, () => {
@@ -597,7 +590,6 @@ export default function (fetchMock, assert) {
sync: {
splitFilters: [{ type: 'byName', values: [undefined, true, 'p2__split'] }, { type: 'byPrefix', values: ['p1'] }, { type: 'byName', values: ['p2__split'] }]
},
- debug: true
});
const client = splitio.client();
const manager = splitio.manager();
@@ -626,7 +618,7 @@ export default function (fetchMock, assert) {
events: 'https://events.baseurl/readyFromCache_7'
};
localStorage.clear();
- t.plan(6);
+ t.plan(7);
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&prefixes=p1,p2', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -642,20 +634,19 @@ export default function (fetchMock, assert) {
const splitio = SplitFactory({
...baseConfig,
storage: InLocalStorage({
- prefix: 'readyFromCache_7'
+ prefix: 'readyFromCache_7',
+ expirationDays: 0, // invalid value, will use default (10)
}),
urls: testUrls,
sync: {
splitFilters: [{ type: 'byPrefix', values: ['p2'] }, { type: 'byPrefix', values: ['p1', ''] }, { type: '', values: [] }, {}, { type: 'byPrefix' }]
},
- debug: true
});
const client = splitio.client();
const manager = splitio.manager();
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE if cache has expired.');
- t.end();
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.once(client.Event.SDK_READY, () => {
@@ -691,7 +682,7 @@ export default function (fetchMock, assert) {
events: 'https://events.baseurl/readyFromCache_8'
};
localStorage.clear();
- t.plan(7);
+ t.plan(8);
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1', { status: 200, body: { splits: [splitDeclarations.p1__split, splitDeclarations.p2__split, splitDeclarations.p3__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -710,14 +701,12 @@ export default function (fetchMock, assert) {
}),
urls: testUrls,
sync: syncParam,
- debug: true
});
const client = splitio.client();
const manager = splitio.manager();
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE because all feature flags were removed from cache since the filter query changed.');
- t.end();
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.once(client.Event.SDK_READY, () => {
@@ -744,7 +733,7 @@ export default function (fetchMock, assert) {
events: 'https://events.baseurl/readyFromCache_9'
};
localStorage.clear();
- t.plan(6);
+ t.plan(7);
fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1&names=no%20exist%20trim,no_exist,p3__split&prefixes=no%20exist%20trim,p2', { status: 200, body: { splits: [splitDeclarations.p2__split, splitDeclarations.p3__split], since: -1, till: 1457552620999 } }, { delay: 10 }); // short delay to let emit SDK_READY_FROM_CACHE
fetchMock.getOnce(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
@@ -764,14 +753,12 @@ export default function (fetchMock, assert) {
sync: {
splitFilters: [{ type: 'byName', values: ['p3__split'] }, { type: 'byPrefix', values: [' p2', ' p2', ' p2', ' p2', 'no exist trim '] }, { type: 'byName', values: ['no_exist', ' no exist trim '] }]
},
- debug: true
});
const client = splitio.client();
const manager = splitio.manager();
client.once(client.Event.SDK_READY_FROM_CACHE, () => {
- t.fail('It should not emit SDK_READY_FROM_CACHE because all feature flags were removed from cache since the filter query changed.');
- t.end();
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY');
});
client.once(client.Event.SDK_READY, () => {
@@ -788,4 +775,91 @@ export default function (fetchMock, assert) {
});
});
+ assert.test(async t => { // Testing clearOnInit config true
+ sinon.spy(console, 'log');
+
+ const testUrls = {
+ sdk: 'https://sdk.baseurl/readyFromCache_10',
+ events: 'https://events.baseurl/readyFromCache_10'
+ };
+ const clearOnInitConfig = {
+ ...baseConfig,
+ storage: InLocalStorage({
+ type: 'LOCALSTORAGE',
+ prefix: 'readyFromCache_10',
+ clearOnInit: true
+ }),
+ urls: testUrls,
+ debug: true
+ };
+
+ // Start with cached data but without lastClear item (JS SDK below 11.1.0) -> cache cleanup
+ localStorage.clear();
+ localStorage.setItem('readyFromCache_10.SPLITIO.splits.till', 25);
+ localStorage.setItem('readyFromCache_10.SPLITIO.split.p1__split', JSON.stringify(splitDeclarations.p1__split));
+ localStorage.setItem('readyFromCache_10.SPLITIO.split.p2__split', JSON.stringify(splitDeclarations.p2__split));
+ localStorage.setItem('readyFromCache_10.SPLITIO.hash', expectedHashNullFilter);
+
+ fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1', { status: 200, body: splitChangesMock1 });
+ fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
+ fetchMock.get(testUrls.sdk + '/memberships/nicolas%40split.io', { status: 200, body: { ms: {} } });
+
+ let splitio = SplitFactory(clearOnInitConfig);
+ let client = splitio.client();
+ let manager = splitio.manager();
+
+ t.true(console.log.calledWithMatch('clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache'), 'It should log a message about cleaning up cache');
+
+ client.once(client.Event.SDK_READY_FROM_CACHE, () => {
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true');
+ });
+
+ await client.ready();
+ t.equal(manager.names().sort().length, 33, 'active splits should be present for evaluation');
+
+ await splitio.destroy();
+ t.equal(localStorage.getItem('readyFromCache_10.SPLITIO.splits.till'), '1457552620999', 'splits.till must correspond to the till of the last successfully fetched Splits');
+ t.equal(localStorage.getItem('readyFromCache_10.SPLITIO.hash'), expectedHashNullFilter, 'Storage hash must not be changed');
+ t.true(nearlyEqual(parseInt(localStorage.getItem('readyFromCache_10.SPLITIO.lastClear')), Date.now()), 'lastClear timestamp must be set');
+
+ // Start again with cached data and lastClear item within the last 24 hours -> no cache cleanup
+ console.log.resetHistory();
+ fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
+
+ splitio = SplitFactory(clearOnInitConfig);
+ client = splitio.client();
+ manager = splitio.manager();
+
+ await new Promise(res => client.once(client.Event.SDK_READY_FROM_CACHE, res));
+
+ t.equal(manager.names().sort().length, 33, 'active splits should be present for evaluation');
+ t.false(console.log.calledWithMatch('clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache'), 'It should log a message about cleaning up cache');
+
+ await splitio.destroy();
+
+ // Start again with cached data and lastClear item older than 24 hours -> cache cleanup
+ console.log.resetHistory();
+ localStorage.setItem('readyFromCache_10.SPLITIO.lastClear', Date.now() - 25 * 60 * 60 * 1000); // 25 hours ago
+ fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=-1', { status: 200, body: splitChangesMock1 });
+ fetchMock.getOnce(testUrls.sdk + '/splitChanges?s=1.2&since=1457552620999', { status: 200, body: splitChangesMock2 });
+
+ splitio = SplitFactory(clearOnInitConfig);
+ client = splitio.client();
+ manager = splitio.manager();
+
+ client.once(client.Event.SDK_READY_FROM_CACHE, () => {
+ t.true(client.__getStatus().isReady, 'Client should emit SDK_READY_FROM_CACHE alongside SDK_READY, because clearOnInit is true');
+ });
+
+ await new Promise(res => client.once(client.Event.SDK_READY, res));
+
+ t.equal(manager.names().sort().length, 33, 'active splits should be present for evaluation');
+ t.true(console.log.calledWithMatch('clearOnInit was set and cache was not cleared in the last 24 hours. Cleaning up cache'), 'It should log a message about cleaning up cache');
+
+ await splitio.destroy();
+
+ console.log.restore();
+ t.end();
+ });
+
}
diff --git a/src/__tests__/mocks/splitchanges.since.-1.json b/src/__tests__/mocks/splitchanges.since.-1.json
index 372b030..c479eae 100644
--- a/src/__tests__/mocks/splitchanges.since.-1.json
+++ b/src/__tests__/mocks/splitchanges.since.-1.json
@@ -1387,7 +1387,7 @@
"environment": null,
"trafficTypeId": null,
"trafficTypeName": null,
- "name": "always_on_track_impressions_false",
+ "name": "always_on_impressions_disabled_true",
"impressionsDisabled": true,
"seed": -790401604,
"status": "ACTIVE",
diff --git a/src/__tests__/testUtils/index.js b/src/__tests__/testUtils/index.js
index 5994a3c..35c601f 100644
--- a/src/__tests__/testUtils/index.js
+++ b/src/__tests__/testUtils/index.js
@@ -18,8 +18,8 @@ export function nearlyEqual(actual, expected, epsilon = DEFAULT_ERROR_MARGIN) {
* - when `?since=-1`, it returns the given segment `keys` in `added` list.
* - otherwise, it returns empty `added` and `removed` lists, and the same since and till values.
*
- * @param {Object} fetchMock see http://www.wheresrhys.co.uk/fetch-mock
- * @param {string|RegExp|...} matcher see http://www.wheresrhys.co.uk/fetch-mock/#api-mockingmock_matcher
+ * @param {Object} fetchMock see https://www.wheresrhys.co.uk/fetch-mock
+ * @param {string|RegExp|...} matcher see https://www.wheresrhys.co.uk/fetch-mock/#api-mockingmock_matcher
* @param {string[]} keys array of segment keys to fetch
* @param {number} changeNumber optional changeNumber
*/
diff --git a/src/settings/defaults.ts b/src/settings/defaults.ts
index be04ade..6d9393b 100644
--- a/src/settings/defaults.ts
+++ b/src/settings/defaults.ts
@@ -2,7 +2,7 @@ import type SplitIO from '@splitsoftware/splitio-commons/types/splitio';
import { LogLevels, isLogLevelString } from '@splitsoftware/splitio-commons/src/logger/index';
import { CONSENT_GRANTED } from '@splitsoftware/splitio-commons/src/utils/constants';
-const packageVersion = '1.1.0';
+const packageVersion = '1.2.0';
/**
* In browser, the default debug level, can be set via the `localStorage.splitio_debug` item.
diff --git a/ts-tests/index.ts b/ts-tests/index.ts
index 8c6dbb6..c66a7b5 100644
--- a/ts-tests/index.ts
+++ b/ts-tests/index.ts
@@ -89,6 +89,14 @@ const attributes: SplitIO.Attributes = {
attr6: [1, 2],
attr7: true
};
+const evaluationOptions: SplitIO.EvaluationOptions = {
+ properties: {
+ prop1: 1,
+ prop2: '2',
+ prop3: true,
+ prop4: null
+ }
+};
// const splitKeyObj: SplitIO.SplitKeyObject = {
// matchingKey: 'matchingKey',
// bucketingKey: 'bucketingKey'
@@ -110,7 +118,9 @@ let impressionData: SplitIO.ImpressionData;
let syncStorage: SplitIO.StorageSync;
let syncStorageFactory: SplitIO.StorageSyncFactory = InLocalStorage();
let localStorageOptions: SplitIO.InLocalStorageOptions = {
- prefix: 'PREFIX'
+ prefix: 'PREFIX',
+ expirationDays: 1,
+ clearOnInit: true
};
syncStorageFactory = InLocalStorage(localStorageOptions);
@@ -265,58 +275,66 @@ promise = SDK.destroy();
// We can call getTreatment without a key.
// treatment = client.getTreatment(splitKey, 'mySplit');
treatment = client.getTreatment('mySplit');
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatment = client.getTreatment(splitKey, 'mySplit', attributes);
treatment = client.getTreatment('mySplit', attributes);
+treatment = client.getTreatment('mySplit', undefined, evaluationOptions);
// We can call getTreatments without a key.
// treatments = client.getTreatments(splitKey, ['mySplit']);
treatments = client.getTreatments(['mySplit']);
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatments = client.getTreatments(splitKey, ['mySplit'], attributes);
treatments = client.getTreatments(['mySplit'], attributes);
+treatments = client.getTreatments(['mySplit'], undefined, evaluationOptions);
// We can call getTreatmentWithConfig without a key.
// treatmentWithConfig = client.getTreatmentWithConfig(splitKey, 'mySplit');
treatmentWithConfig = client.getTreatmentWithConfig('mySplit');
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatmentWithConfig = client.getTreatmentWithConfig(splitKey, 'mySplit', attributes);
treatmentWithConfig = client.getTreatmentWithConfig('mySplit', attributes);
+treatmentWithConfig = client.getTreatmentWithConfig('mySplit', undefined, evaluationOptions);
// We can call getTreatmentsWithConfig without a key.
// treatmentsWithConfig = client.getTreatmentsWithConfig(splitKey, ['mySplit']);
treatmentsWithConfig = client.getTreatmentsWithConfig(['mySplit']);
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatmentsWithConfig = client.getTreatmentsWithConfig(splitKey, ['mySplit'], attributes);
treatmentsWithConfig = client.getTreatmentsWithConfig(['mySplit'], attributes);
+treatmentsWithConfig = client.getTreatmentsWithConfig(['mySplit'], undefined, evaluationOptions);
// We can call getTreatmentsByFlagSet without a key.
// treatments = client.getTreatmentsByFlagSet(splitKey, 'set_a');
treatments = client.getTreatmentsByFlagSet('set_a');
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatments = client.getTreatmentsByFlagSet(splitKey, 'set_a', attributes);
treatments = client.getTreatmentsByFlagSet('set_a', attributes);
+treatments = client.getTreatmentsByFlagSet('set_a', undefined, evaluationOptions);
// We can call getTreatmentsByFlagSets without a key.
// treatments = client.getTreatmentsByFlagSets(splitKey, ['set_a']);
treatments = client.getTreatmentsByFlagSets(['set_a']);
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatments = client.getTreatmentsByFlagSets(splitKey, ['set_a'], attributes);
treatments = client.getTreatmentsByFlagSets(['set_a'], attributes);
+treatments = client.getTreatmentsByFlagSets(['set_a'], undefined, evaluationOptions);
// We can call getTreatmentsWithConfigByFlagSet without a key.
// treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSet(splitKey, 'set_a');
treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSet('set_a');
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSet(splitKey, 'set_a', attributes);
treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSet('set_a', attributes);
+treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSet('set_a', undefined, evaluationOptions);
// We can call getTreatmentsWithConfigByFlagSets without a key.
// treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSets(splitKey, ['set_a']);
treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSets(['set_a']);
-// Attributes parameter is optional.
+// Attributes and EvaluationOptions parameters are optional.
// treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSets(splitKey, ['set_a'], attributes);
treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSets(['set_a'], attributes);
+treatmentsWithConfig = client.getTreatmentsWithConfigByFlagSets(['set_a'], undefined, evaluationOptions);
// We can call track without a key. Traffic type can also be binded to the client.
// tracked = client.track(splitKey, 'myTrafficType', 'myEventType'); // all params
@@ -355,57 +373,65 @@ promise = AsyncSDK.destroy();
// We can call getTreatment
asyncTreatment = asyncClient.getTreatment('mySplit');
// asyncTreatment = asyncClient.getTreatment(splitKey, 'mySplit');
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatment = asyncClient.getTreatment('mySplit', attributes);
+asyncTreatment = asyncClient.getTreatment('mySplit', undefined, evaluationOptions);
// asyncTreatment = asyncClient.getTreatment(splitKey, 'mySplit', attributes);
// We can call getTreatments
asyncTreatments = asyncClient.getTreatments(['mySplit']);
// asyncTreatments = asyncClient.getTreatments(splitKey, ['mySplit']);
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatments = asyncClient.getTreatments(['mySplit'], attributes);
+asyncTreatments = asyncClient.getTreatments(['mySplit'], undefined, evaluationOptions);
// asyncTreatments = asyncClient.getTreatments(splitKey, ['mySplit'], attributes);
// We can call getTreatmentWithConfig
asyncTreatmentWithConfig = asyncClient.getTreatmentWithConfig('mySplit');
// asyncTreatmentWithConfig = asyncClient.getTreatmentWithConfig(splitKey, 'mySplit');
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatmentWithConfig = asyncClient.getTreatmentWithConfig('mySplit', attributes);
+asyncTreatmentWithConfig = asyncClient.getTreatmentWithConfig('mySplit', undefined, evaluationOptions);
// asyncTreatmentWithConfig = asyncClient.getTreatmentWithConfig(splitKey, 'mySplit', attributes);
// We can call getTreatments but always with a key.
asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfig(['mySplit']);
// asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfig(splitKey, ['mySplit']);
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfig(['mySplit'], attributes);
+asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfig(['mySplit'], undefined, evaluationOptions);
// asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfig(splitKey, ['mySplit'], attributes);
// We can call getTreatmentsByFlagSet
asyncTreatments = asyncClient.getTreatmentsByFlagSet('set_a');
// asyncTreatments = asyncClient.getTreatmentsByFlagSet(splitKey, 'set_a');
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatments = asyncClient.getTreatmentsByFlagSet('set_a', attributes);
+asyncTreatments = asyncClient.getTreatmentsByFlagSet('set_a', undefined, evaluationOptions);
// asyncTreatments = asyncClient.getTreatmentsByFlagSet(splitKey, 'set_a', attributes);
// We can call getTreatmentsByFlagSets
asyncTreatments = asyncClient.getTreatmentsByFlagSets(['set_a']);
// asyncTreatments = asyncClient.getTreatmentsByFlagSets(splitKey, ['set_a']);
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatments = asyncClient.getTreatmentsByFlagSets(['set_a'], attributes);
+asyncTreatments = asyncClient.getTreatmentsByFlagSets(['set_a'], undefined, evaluationOptions);
// asyncTreatments = asyncClient.getTreatmentsByFlagSets(splitKey, ['set_a'], attributes);
// We can call getTreatmentsWithConfigByFlagSet
asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSet('set_a');
// asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSet(splitKey, 'set_a');
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSet('set_a', attributes);
+asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSet('set_a', undefined, evaluationOptions);
// asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSet(splitKey, 'set_a', attributes);
// We can call getTreatmentsByFlagSets but always with a key.
asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSets(['set_a']);
// asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSets(splitKey, ['set_a']);
-// Attributes parameter is optional
+// Attributes and EvaluationOptions parameters are optional.
asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSets(['set_a'], attributes);
+asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSets(['set_a'], undefined, evaluationOptions);
// asyncTreatmentsWithConfig = asyncClient.getTreatmentsWithConfigByFlagSets(splitKey, ['set_a'], attributes);
// We can call track.
diff --git a/types/full/index.d.ts b/types/full/index.d.ts
index 7ce5b8b..e765b7f 100644
--- a/types/full/index.d.ts
+++ b/types/full/index.d.ts
@@ -1,5 +1,5 @@
// Declaration file for JavaScript Browser Split Software SDK
-// Project: http://www.split.io/
+// Project: https://www.split.io/
// Definitions by: Nico Zelaya
///
diff --git a/types/index.d.ts b/types/index.d.ts
index 040dfaa..c33e845 100644
--- a/types/index.d.ts
+++ b/types/index.d.ts
@@ -1,5 +1,5 @@
// Declaration file for JavaScript Browser Split Software SDK
-// Project: http://www.split.io/
+// Project: https://www.split.io/
// Definitions by: Nico Zelaya
///