mirror of
https://github.com/Unleash/unleash.git
synced 2025-07-07 01:16:28 +02:00
task: migrate tests to vitest
Vitest Pros: * Automated failing test comments on github PRs * A nice local UI with incremental testing when changing files (`yarn test:ui`) * Also nicely supported in all major IDEs, click to run test works (so we won't miss what we had with jest). * Works well with ESM Vitest Cons: * The ESBuild transformer vitest uses takes a little longer to transform than our current SWC/jest setup, however, it is possible to setup SWC as the transformer for vitest as well (though it only does one transform, so we're paying ~7-10 seconds instead of ~ 2-3 seconds in transform phase). * Exposes how slow our tests are (tongue in cheek here)
This commit is contained in:
parent
4d1b44818f
commit
b681702b77
13
.github/workflows/build.yaml
vendored
13
.github/workflows/build.yaml
vendored
@ -16,7 +16,10 @@ jobs:
|
|||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
name: build
|
name: build
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
# Needed for the github-reporter from vite to make comments on PRs
|
||||||
|
pull-requests: write
|
||||||
services:
|
services:
|
||||||
# Label used to access the service container
|
# Label used to access the service container
|
||||||
postgres:
|
postgres:
|
||||||
@ -47,14 +50,8 @@ jobs:
|
|||||||
YARN_ENABLE_SCRIPTS: false
|
YARN_ENABLE_SCRIPTS: false
|
||||||
- run: yarn lint
|
- run: yarn lint
|
||||||
- run: yarn build:backend
|
- run: yarn build:backend
|
||||||
- run: yarn run test:report # This adds test results as github check to the workflow
|
- run: yarn run test
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
||||||
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
||||||
- name: Upload test report to build # Done this way since external PRs would not be able to write the check. See https://github.com/marketplace/actions/test-reporter#recommended-setup-for-public-repositories
|
|
||||||
uses: actions/upload-artifact@v4
|
|
||||||
if: (success() || failure()) && github.ref == 'refs/heads/main'
|
|
||||||
with:
|
|
||||||
name: test-results
|
|
||||||
path: ./reports/jest-junit.xml
|
|
||||||
|
27
.github/workflows/build_prs_jest_report.yaml
vendored
27
.github/workflows/build_prs_jest_report.yaml
vendored
@ -12,6 +12,9 @@ on:
|
|||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull_requests: write
|
||||||
name: build # temporary solution to trick branch protection rules
|
name: build # temporary solution to trick branch protection rules
|
||||||
|
|
||||||
services:
|
services:
|
||||||
@ -32,31 +35,25 @@ jobs:
|
|||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Use Node.js 20.x
|
- name: Use Node.js 22.x
|
||||||
uses: actions/setup-node@v4
|
uses: actions/setup-node@v4
|
||||||
with:
|
with:
|
||||||
node-version: 22.x
|
node-version: 22.x
|
||||||
cache: 'yarn'
|
cache: 'yarn'
|
||||||
- name: Enable corepack
|
- name: Enable corepack
|
||||||
run: corepack enable
|
run: corepack enable
|
||||||
- run: yarn build:backend
|
- name: Install deps
|
||||||
- name: Tests on 20.x
|
run: yarn install
|
||||||
|
- name: Build backend
|
||||||
|
run: yarn backend
|
||||||
|
- name: Tests on 22.x
|
||||||
id: coverage
|
id: coverage
|
||||||
uses: ArtiomTr/jest-coverage-report-action@v2
|
run: yarn test:coverage
|
||||||
with:
|
|
||||||
annotations: none
|
|
||||||
package-manager: yarn
|
|
||||||
test-script: yarn run test:coverage:jest
|
|
||||||
base-coverage-file: ./coverage/report.json
|
|
||||||
output: report-markdown
|
|
||||||
env:
|
env:
|
||||||
CI: true
|
CI: true
|
||||||
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
TEST_DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
||||||
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
DATABASE_URL: postgres://postgres:postgres@localhost:5432/postgres
|
||||||
NODE_ENV: test
|
NODE_ENV: test
|
||||||
PORT: 4243
|
PORT: 4243
|
||||||
# - name: Report coverage on ${{ matrix.node-version }}
|
- name: Report coverage
|
||||||
# uses: marocchino/sticky-pull-request-comment@v2
|
uses: davelosert/vitest-coverage-report-action@v2
|
||||||
# with:
|
|
||||||
# # pass output from the previous step by id.
|
|
||||||
# message: ${{ steps.coverage.outputs.report }}
|
|
||||||
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -107,3 +107,4 @@ website/.yarn/*
|
|||||||
!website/.yarn/sdks
|
!website/.yarn/sdks
|
||||||
!website/.yarn/versions
|
!website/.yarn/versions
|
||||||
|
|
||||||
|
coverage/.tmp
|
||||||
|
1728
coverage/clover.xml
1728
coverage/clover.xml
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
3781
coverage/lcov.info
3781
coverage/lcov.info
File diff suppressed because it is too large
Load Diff
67141
coverage/report.json
67141
coverage/report.json
File diff suppressed because it is too large
Load Diff
82
package.json
82
package.json
@ -53,15 +53,15 @@
|
|||||||
"local:package": "del-cli --force build && mkdir build && cp -r dist docs CHANGELOG.md LICENSE README.md package.json build",
|
"local:package": "del-cli --force build && mkdir build && cp -r dist docs CHANGELOG.md LICENSE README.md package.json build",
|
||||||
"build:watch": "tsc -w",
|
"build:watch": "tsc -w",
|
||||||
"prepare": "husky && yarn --cwd ./frontend install && if [ ! -d ./dist ]; then yarn build; fi",
|
"prepare": "husky && yarn --cwd ./frontend install && if [ ! -d ./dist ]; then yarn build; fi",
|
||||||
"test": "NODE_ENV=test PORT=4243 node --experimental-vm-modules node_modules/.bin/jest",
|
"test": "NODE_ENV=test PORT=4243 vitest run",
|
||||||
"test:unit": "NODE_ENV=test PORT=4243 node --experimental-vm-modules node_modules/.bin/jest --testPathIgnorePatterns=src/test/e2e",
|
"test:unit": "NODE_ENV=test PORT=4243 vitest --exclude src/test/e2e",
|
||||||
"test:docker": "./scripts/docker-postgres.sh",
|
"test:docker": "./scripts/docker-postgres.sh",
|
||||||
"test:report": "NODE_OPTIONS=--experimental-vm-modules NODE_ENV=test PORT=4243 node node_modules/.bin/jest --reporters=\"default\" --reporters=\"jest-junit\"",
|
"test:report": "NODE_ENV=test PORT=4243 vitest --reporter=junit",
|
||||||
"test:docker:cleanup": "docker rm -f unleash-postgres",
|
"test:docker:cleanup": "docker rm -f unleash-postgres",
|
||||||
"test:watch": "yarn test --watch",
|
"test:watch": "vitest",
|
||||||
"test:coverage": "NODE_ENV=test PORT=4243 node --experimental-vm-modules node_modules/.bin/jest --coverage --testLocationInResults --outputFile=\"coverage/report.json\" --forceExit",
|
"test:coverage": "NODE_ENV=test PORT=4243 vitest run --coverage --outputFile=\"coverage/report.json\"",
|
||||||
"test:coverage:jest": "NODE_ENV=test PORT=4243 node --experimental-vm-modules node_modules/.bin/jest --silent --ci --json --coverage --testLocationInResults --outputFile=\"report.json\" --forceExit",
|
"test:updateSnapshot": "NODE_ENV=test PORT=4243 vitest run -u",
|
||||||
"test:updateSnapshot": "NODE_ENV=test PORT=4243 node --experimental-vm-modules node_modules/.bin/jest --updateSnapshot",
|
"test:ui": "vitest --ui",
|
||||||
"seed:setup": "ts-node src/test/e2e/seed/segment.seed.ts",
|
"seed:setup": "ts-node src/test/e2e/seed/segment.seed.ts",
|
||||||
"seed:serve": "UNLEASH_DATABASE_NAME=unleash_test UNLEASH_DATABASE_SCHEMA=seed yarn run start:dev",
|
"seed:serve": "UNLEASH_DATABASE_NAME=unleash_test UNLEASH_DATABASE_SCHEMA=seed yarn run start:dev",
|
||||||
"clean": "del-cli --force dist",
|
"clean": "del-cli --force dist",
|
||||||
@ -69,66 +69,6 @@
|
|||||||
"prepack": "./scripts/prepack.sh",
|
"prepack": "./scripts/prepack.sh",
|
||||||
"schema:update": "node ./.husky/update-openapi-spec-list.js"
|
"schema:update": "node ./.husky/update-openapi-spec-list.js"
|
||||||
},
|
},
|
||||||
"jest-junit": {
|
|
||||||
"suiteName": "Unleash Unit Tests",
|
|
||||||
"outputDirectory": "./reports",
|
|
||||||
"outputName": "jest-junit.xml",
|
|
||||||
"uniqueOutputName": "false",
|
|
||||||
"classNameTemplate": "{classname}-{title}",
|
|
||||||
"titleTemplate": "{classname}-{title}",
|
|
||||||
"ancestorSeparator": " › ",
|
|
||||||
"usePathForSuiteName": "true"
|
|
||||||
},
|
|
||||||
"jest": {
|
|
||||||
"automock": false,
|
|
||||||
"maxWorkers": 4,
|
|
||||||
"testTimeout": 20000,
|
|
||||||
"globalSetup": "./src/jest-setup.ts",
|
|
||||||
"transform": {
|
|
||||||
"^.+\\.tsx?$": [
|
|
||||||
"@swc/jest",
|
|
||||||
{
|
|
||||||
"jsc": {
|
|
||||||
"target": "ESNext",
|
|
||||||
"parser": {
|
|
||||||
"syntax": "typescript"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"isModule": true
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"testRegex": "(/__tests__/.*|(\\.|/)(test|spec))\\.(jsx?|tsx?)$",
|
|
||||||
"testPathIgnorePatterns": [
|
|
||||||
"/dist/",
|
|
||||||
"/node_modules/",
|
|
||||||
"/frontend/",
|
|
||||||
"/website/"
|
|
||||||
],
|
|
||||||
"moduleFileExtensions": [
|
|
||||||
"ts",
|
|
||||||
"tsx",
|
|
||||||
"js",
|
|
||||||
"jsx",
|
|
||||||
"json"
|
|
||||||
],
|
|
||||||
"coveragePathIgnorePatterns": [
|
|
||||||
"/node_modules/",
|
|
||||||
"/dist/",
|
|
||||||
"/src/migrations",
|
|
||||||
"/src/test"
|
|
||||||
],
|
|
||||||
"extensionsToTreatAsEsm": [
|
|
||||||
".ts",
|
|
||||||
".tsx"
|
|
||||||
],
|
|
||||||
"moduleNameMapper": {
|
|
||||||
"^(\\.{1,2}/.*)\\.js$": "$1"
|
|
||||||
},
|
|
||||||
"transformIgnorePatterns": [
|
|
||||||
"node_modules"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@slack/web-api": "^7.9.1",
|
"@slack/web-api": "^7.9.1",
|
||||||
"@wesleytodd/openapi": "^1.1.0",
|
"@wesleytodd/openapi": "^1.1.0",
|
||||||
@ -199,15 +139,14 @@
|
|||||||
"@babel/core": "7.26.10",
|
"@babel/core": "7.26.10",
|
||||||
"@biomejs/biome": "^1.9.4",
|
"@biomejs/biome": "^1.9.4",
|
||||||
"@cyclonedx/yarn-plugin-cyclonedx": "^2.0.0",
|
"@cyclonedx/yarn-plugin-cyclonedx": "^2.0.0",
|
||||||
|
"@fast-check/vitest": "^0.2.1",
|
||||||
"@swc/core": "1.11.24",
|
"@swc/core": "1.11.24",
|
||||||
"@swc/jest": "0.2.38",
|
|
||||||
"@types/bcryptjs": "2.4.6",
|
"@types/bcryptjs": "2.4.6",
|
||||||
"@types/cors": "2.8.17",
|
"@types/cors": "2.8.17",
|
||||||
"@types/express": "4.17.21",
|
"@types/express": "4.17.21",
|
||||||
"@types/express-session": "1.18.1",
|
"@types/express-session": "1.18.1",
|
||||||
"@types/faker": "5.5.9",
|
"@types/faker": "5.5.9",
|
||||||
"@types/hash-sum": "^1.0.0",
|
"@types/hash-sum": "^1.0.0",
|
||||||
"@types/jest": "29.5.14",
|
|
||||||
"@types/js-yaml": "4.0.9",
|
"@types/js-yaml": "4.0.9",
|
||||||
"@types/lodash.groupby": "4.6.9",
|
"@types/lodash.groupby": "4.6.9",
|
||||||
"@types/lodash.isequal": "^4.5.8",
|
"@types/lodash.isequal": "^4.5.8",
|
||||||
@ -226,6 +165,8 @@
|
|||||||
"@types/supertest": "6.0.2",
|
"@types/supertest": "6.0.2",
|
||||||
"@types/type-is": "1.6.7",
|
"@types/type-is": "1.6.7",
|
||||||
"@types/uuid": "9.0.8",
|
"@types/uuid": "9.0.8",
|
||||||
|
"@vitest/coverage-v8": "^3.1.3",
|
||||||
|
"@vitest/ui": "^3.1.3",
|
||||||
"concurrently": "^9.0.0",
|
"concurrently": "^9.0.0",
|
||||||
"copyfiles": "2.4.1",
|
"copyfiles": "2.4.1",
|
||||||
"coveralls": "^3.1.1",
|
"coveralls": "^3.1.1",
|
||||||
@ -234,8 +175,6 @@
|
|||||||
"fast-check": "3.23.2",
|
"fast-check": "3.23.2",
|
||||||
"fetch-mock": "^12.0.0",
|
"fetch-mock": "^12.0.0",
|
||||||
"husky": "^9.0.11",
|
"husky": "^9.0.11",
|
||||||
"jest": "29.7.0",
|
|
||||||
"jest-junit": "^16.0.0",
|
|
||||||
"lint-staged": "15.4.3",
|
"lint-staged": "15.4.3",
|
||||||
"nock": "13.5.6",
|
"nock": "13.5.6",
|
||||||
"openapi-enforcer": "1.23.0",
|
"openapi-enforcer": "1.23.0",
|
||||||
@ -247,6 +186,7 @@
|
|||||||
"tsc-watch": "6.2.1",
|
"tsc-watch": "6.2.1",
|
||||||
"typescript": "5.8.3",
|
"typescript": "5.8.3",
|
||||||
"vite-node": "^3.1.3",
|
"vite-node": "^3.1.3",
|
||||||
|
"vitest": "^3.1.3",
|
||||||
"wait-on": "^8.0.0"
|
"wait-on": "^8.0.0"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`should create default config 1`] = `
|
exports[`should create default config 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Datadog integration Should call datadog webhook for archived toggle 1`] = `"{"text":"%%% \\n *some@user.com* archived *some-toggle* in project ** \\n %%% ","title":"Unleash notification update"}"`;
|
exports[`Datadog integration > Should call datadog webhook for archived toggle 1`] = `"{"text":"%%% \\n *some@user.com* archived *some-toggle* in project ** \\n %%% ","title":"Unleash notification update"}"`;
|
||||||
|
|
||||||
exports[`Datadog integration Should call datadog webhook for archived toggle with project info 1`] = `"{"text":"%%% \\n *some@user.com* archived *some-toggle* in project *[some-project](http://some-url.com/projects/some-project)* \\n %%% ","title":"Unleash notification update"}"`;
|
exports[`Datadog integration > Should call datadog webhook for archived toggle with project info 1`] = `"{"text":"%%% \\n *some@user.com* archived *some-toggle* in project *[some-project](http://some-url.com/projects/some-project)* \\n %%% ","title":"Unleash notification update"}"`;
|
||||||
|
|
||||||
exports[`Datadog integration Should call datadog webhook 1`] = `"{"text":"%%% \\n *some@user.com* created *[some-toggle](http://some-url.com/projects//features/some-toggle)* in project ** \\n %%% ","title":"Unleash notification update"}"`;
|
exports[`Datadog integration > Should call datadog webhook 1`] = `"{"text":"%%% \\n *some@user.com* created *[some-toggle](http://some-url.com/projects//features/some-toggle)* in project ** \\n %%% ","title":"Unleash notification update"}"`;
|
||||||
|
|
||||||
exports[`Datadog integration Should call datadog webhook for toggled environment 1`] = `"{"text":"%%% \\n *some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)* \\n %%% ","title":"Unleash notification update"}"`;
|
exports[`Datadog integration > Should call datadog webhook for toggled environment 1`] = `"{"text":"%%% \\n *some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)* \\n %%% ","title":"Unleash notification update"}"`;
|
||||||
|
|
||||||
exports[`Datadog integration Should call datadog webhook with JSON when template set 1`] = `"{"text":"{\\n \\"event\\": \\"feature-created\\",\\n \\"createdBy\\": \\"some@user.com\\"\\n}","title":"Unleash notification update"}"`;
|
exports[`Datadog integration > Should call datadog webhook with JSON when template set 1`] = `"{"text":"{\\n \\"event\\": \\"feature-created\\",\\n \\"createdBy\\": \\"some@user.com\\"\\n}","title":"Unleash notification update"}"`;
|
||||||
|
|
||||||
exports[`Datadog integration Should include customHeaders in headers when calling service 1`] = `"{"text":"%%% \\n *some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)* \\n %%% ","title":"Unleash notification update"}"`;
|
exports[`Datadog integration > Should include customHeaders in headers when calling service 1`] = `"{"text":"%%% \\n *some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)* \\n %%% ","title":"Unleash notification update"}"`;
|
||||||
|
|
||||||
exports[`Datadog integration Should not include source_type_name when included in the config 1`] = `"{"text":"%%% \\n *some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)* \\n %%% ","title":"Unleash notification update","source_type_name":"my-custom-source-type"}"`;
|
exports[`Datadog integration > Should not include source_type_name when included in the config 1`] = `"{"text":"%%% \\n *some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)* \\n %%% ","title":"Unleash notification update","source_type_name":"my-custom-source-type"}"`;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Should format specialised text for events when IPs changed 1`] = `
|
exports[`Should format specialised text for events when IPs changed 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Slack integration Should call slack webhook 1`] = `
|
exports[`Slack integration > Should call slack webhook 1`] = `
|
||||||
{
|
{
|
||||||
"attachments": [
|
"attachments": [
|
||||||
{
|
{
|
||||||
@ -23,10 +23,10 @@ exports[`Slack integration Should call slack webhook 1`] = `
|
|||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`Slack integration Should call slack webhook for archived toggle 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* archived *some-toggle* in project **","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects//archive"}]}]}"`;
|
exports[`Slack integration > Should call slack webhook for archived toggle 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* archived *some-toggle* in project **","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects//archive"}]}]}"`;
|
||||||
|
|
||||||
exports[`Slack integration Should call slack webhook for archived toggle with project info 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* archived *some-toggle* in project *<http://some-url.com/projects/some-project|some-project>*","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects/some-project/archive"}]}]}"`;
|
exports[`Slack integration > Should call slack webhook for archived toggle with project info 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* archived *some-toggle* in project *<http://some-url.com/projects/some-project|some-project>*","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects/some-project/archive"}]}]}"`;
|
||||||
|
|
||||||
exports[`Slack integration Should call webhook for toggled environment 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* disabled *<http://some-url.com/projects/default/features/some-toggle|some-toggle>* for the *development* environment in project *<http://some-url.com/projects/default|default>*","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
exports[`Slack integration > Should call webhook for toggled environment 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* disabled *<http://some-url.com/projects/default/features/some-toggle|some-toggle>* for the *development* environment in project *<http://some-url.com/projects/default|default>*","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
||||||
|
|
||||||
exports[`Slack integration Should include custom headers from parameters in call to service 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* disabled *<http://some-url.com/projects/default/features/some-toggle|some-toggle>* for the *development* environment in project *<http://some-url.com/projects/default|default>*","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
exports[`Slack integration > Should include custom headers from parameters in call to service 1`] = `"{"username":"Unleash","icon_emoji":":unleash:","text":"*some@user.com* disabled *<http://some-url.com/projects/default/features/some-toggle|some-toggle>* for the *development* environment in project *<http://some-url.com/projects/default|default>*","channel":"#general","attachments":[{"actions":[{"name":"featureToggle","text":"Open in Unleash","type":"button","value":"featureToggle","style":"primary","url":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Teams integration Should call teams webhook 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* created *[some-toggle](http://some-url.com/projects//features/some-toggle)* in project **","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-created"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects//features/some-toggle"}]}]}"`;
|
exports[`Teams integration > Should call teams webhook 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* created *[some-toggle](http://some-url.com/projects//features/some-toggle)* in project **","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-created"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects//features/some-toggle"}]}]}"`;
|
||||||
|
|
||||||
exports[`Teams integration Should call teams webhook for archived toggle 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* archived *some-toggle* in project **","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-archived"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects//archive"}]}]}"`;
|
exports[`Teams integration > Should call teams webhook for archived toggle 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* archived *some-toggle* in project **","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-archived"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects//archive"}]}]}"`;
|
||||||
|
|
||||||
exports[`Teams integration Should call teams webhook for archived toggle with project info 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* archived *some-toggle* in project *[some-project](http://some-url.com/projects/some-project)*","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-archived"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects/some-project/archive"}]}]}"`;
|
exports[`Teams integration > Should call teams webhook for archived toggle with project info 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* archived *some-toggle* in project *[some-project](http://some-url.com/projects/some-project)*","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-archived"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects/some-project/archive"}]}]}"`;
|
||||||
|
|
||||||
exports[`Teams integration Should call teams webhook for toggled environment 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)*","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-environment-disabled"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
exports[`Teams integration > Should call teams webhook for toggled environment 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)*","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-environment-disabled"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
||||||
|
|
||||||
exports[`Teams integration Should include custom headers in call to teams 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)*","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-environment-disabled"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
exports[`Teams integration > Should include custom headers in call to teams 1`] = `"{"themeColor":"0076D7","summary":"Message","sections":[{"activityTitle":"*some@user.com* disabled *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* for the *development* environment in project *[default](http://some-url.com/projects/default)*","activitySubtitle":"Unleash notification update","facts":[{"name":"User","value":"some@user.com"},{"name":"Action","value":"feature-environment-disabled"}]}],"potentialAction":[{"@type":"OpenUri","name":"Go to feature","targets":[{"os":"default","uri":"http://some-url.com/projects/default/features/some-toggle"}]}]}"`;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`Webhook integration should allow for eventJson and eventMarkdown in bodyTemplate 1`] = `
|
exports[`Webhook integration > should allow for eventJson and eventMarkdown in bodyTemplate 1`] = `
|
||||||
"{
|
"{
|
||||||
"json": "{\\"id\\":1,\\"createdAt\\":\\"2024-07-24T00:00:00.000Z\\",\\"createdByUserId\\":-1337,\\"type\\":\\"feature-created\\",\\"createdBy\\":\\"some@user.com\\",\\"featureName\\":\\"some-toggle\\",\\"project\\":\\"default\\",\\"data\\":{\\"name\\":\\"some-toggle\\",\\"enabled\\":false,\\"strategies\\":[{\\"name\\":\\"default\\"}]}}",
|
"json": "{\\"id\\":1,\\"createdAt\\":\\"2024-07-24T00:00:00.000Z\\",\\"createdByUserId\\":-1337,\\"type\\":\\"feature-created\\",\\"createdBy\\":\\"some@user.com\\",\\"featureName\\":\\"some-toggle\\",\\"project\\":\\"default\\",\\"data\\":{\\"name\\":\\"some-toggle\\",\\"enabled\\":false,\\"strategies\\":[{\\"name\\":\\"default\\"}]}}",
|
||||||
"markdown": "*some@user.com* created *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* in project *[default](http://some-url.com/projects/default)*"
|
"markdown": "*some@user.com* created *[some-toggle](http://some-url.com/projects/default/features/some-toggle)* in project *[default](http://some-url.com/projects/default)*"
|
||||||
|
@ -16,17 +16,17 @@ import {
|
|||||||
} from '../types/index.js';
|
} from '../types/index.js';
|
||||||
import type { IntegrationEventsService } from '../services/index.js';
|
import type { IntegrationEventsService } from '../services/index.js';
|
||||||
import nock from 'nock';
|
import nock from 'nock';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
const INTEGRATION_ID = 1337;
|
const INTEGRATION_ID = 1337;
|
||||||
const ARGS: IAddonConfig = {
|
const ARGS: IAddonConfig = {
|
||||||
getLogger: noLogger,
|
getLogger: noLogger,
|
||||||
unleashUrl: 'http://some-url.com',
|
unleashUrl: 'http://some-url.com',
|
||||||
integrationEventsService: {
|
integrationEventsService: {
|
||||||
registerEvent: jest.fn(),
|
registerEvent: vi.fn(),
|
||||||
} as unknown as IntegrationEventsService,
|
} as unknown as IntegrationEventsService,
|
||||||
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
||||||
eventBus: <any>{ emit: jest.fn() },
|
eventBus: <any>{ emit: vi.fn() },
|
||||||
};
|
};
|
||||||
|
|
||||||
describe('Datadog integration', () => {
|
describe('Datadog integration', () => {
|
||||||
@ -317,7 +317,7 @@ describe('Datadog integration', () => {
|
|||||||
|
|
||||||
test('Should call registerEvent', async () => {
|
test('Should call registerEvent', async () => {
|
||||||
const addon = new DatadogAddon(ARGS);
|
const addon = new DatadogAddon(ARGS);
|
||||||
const registerEventSpy = jest.spyOn(addon, 'registerEvent');
|
const registerEventSpy = vi.spyOn(addon, 'registerEvent');
|
||||||
const event: IEvent = {
|
const event: IEvent = {
|
||||||
id: 1,
|
id: 1,
|
||||||
createdAt: new Date(),
|
createdAt: new Date(),
|
||||||
|
@ -17,12 +17,12 @@ import {
|
|||||||
FEATURE_ARCHIVED,
|
FEATURE_ARCHIVED,
|
||||||
FEATURE_ENVIRONMENT_DISABLED,
|
FEATURE_ENVIRONMENT_DISABLED,
|
||||||
} from '../events/index.js';
|
} from '../events/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
import nock from 'nock';
|
import nock from 'nock';
|
||||||
|
|
||||||
const asyncGunzip = promisify(gunzip);
|
const asyncGunzip = promisify(gunzip);
|
||||||
|
|
||||||
const registerEventMock = jest.fn();
|
const registerEventMock = vi.fn();
|
||||||
|
|
||||||
const INTEGRATION_ID = 1337;
|
const INTEGRATION_ID = 1337;
|
||||||
const ARGS: IAddonConfig = {
|
const ARGS: IAddonConfig = {
|
||||||
@ -33,7 +33,7 @@ const ARGS: IAddonConfig = {
|
|||||||
} as unknown as IntegrationEventsService,
|
} as unknown as IntegrationEventsService,
|
||||||
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
||||||
eventBus: {
|
eventBus: {
|
||||||
emit: jest.fn(),
|
emit: vi.fn(),
|
||||||
} as any,
|
} as any,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -14,18 +14,18 @@ import {
|
|||||||
} from '../types/index.js';
|
} from '../types/index.js';
|
||||||
import type { IntegrationEventsService } from '../services/index.js';
|
import type { IntegrationEventsService } from '../services/index.js';
|
||||||
const slackApiCalls: ChatPostMessageArguments[] = [];
|
const slackApiCalls: ChatPostMessageArguments[] = [];
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
const loggerMock = {
|
const loggerMock = {
|
||||||
debug: jest.fn(),
|
debug: vi.fn(),
|
||||||
info: jest.fn(),
|
info: vi.fn(),
|
||||||
warn: jest.fn(),
|
warn: vi.fn(),
|
||||||
error: jest.fn(),
|
error: vi.fn(),
|
||||||
fatal: jest.fn(),
|
fatal: vi.fn(),
|
||||||
};
|
};
|
||||||
const getLogger = jest.fn(() => loggerMock);
|
const getLogger = vi.fn(() => loggerMock);
|
||||||
|
|
||||||
const registerEventMock = jest.fn();
|
const registerEventMock = vi.fn();
|
||||||
|
|
||||||
const INTEGRATION_ID = 1337;
|
const INTEGRATION_ID = 1337;
|
||||||
const ARGS: IAddonConfig = {
|
const ARGS: IAddonConfig = {
|
||||||
@ -36,11 +36,11 @@ const ARGS: IAddonConfig = {
|
|||||||
} as unknown as IntegrationEventsService,
|
} as unknown as IntegrationEventsService,
|
||||||
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
||||||
eventBus: {
|
eventBus: {
|
||||||
emit: jest.fn(),
|
emit: vi.fn(),
|
||||||
} as any,
|
} as any,
|
||||||
};
|
};
|
||||||
|
|
||||||
let postMessage = jest.fn().mockImplementation((options: any) => {
|
let postMessage = vi.fn().mockImplementation((options: any) => {
|
||||||
slackApiCalls.push(options);
|
slackApiCalls.push(options);
|
||||||
return Promise.resolve();
|
return Promise.resolve();
|
||||||
});
|
});
|
||||||
@ -73,7 +73,7 @@ describe('SlackAppAddon', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
slackApiCalls.length = 0;
|
slackApiCalls.length = 0;
|
||||||
postMessage.mockClear();
|
postMessage.mockClear();
|
||||||
registerEventMock.mockClear();
|
registerEventMock.mockClear();
|
||||||
@ -82,13 +82,13 @@ describe('SlackAppAddon', () => {
|
|||||||
chat: {
|
chat: {
|
||||||
postMessage,
|
postMessage,
|
||||||
},
|
},
|
||||||
on: jest.fn(),
|
on: vi.fn(),
|
||||||
} as unknown as Methods;
|
} as unknown as Methods;
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should post message when feature is toggled', async () => {
|
it('should post message when feature is toggled', async () => {
|
||||||
@ -182,7 +182,7 @@ describe('SlackAppAddon', () => {
|
|||||||
|
|
||||||
it('should log error when an API call fails', async () => {
|
it('should log error when an API call fails', async () => {
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
postMessage = jest.fn().mockRejectedValue(mockError);
|
postMessage = vi.fn().mockRejectedValue(mockError);
|
||||||
|
|
||||||
await addon.handleEvent(
|
await addon.handleEvent(
|
||||||
event,
|
event,
|
||||||
@ -208,13 +208,10 @@ describe('SlackAppAddon', () => {
|
|||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|
||||||
postMessage = jest
|
postMessage = vi
|
||||||
.fn()
|
.fn()
|
||||||
// @ts-ignore
|
|
||||||
.mockResolvedValueOnce({ ok: true })
|
.mockResolvedValueOnce({ ok: true })
|
||||||
// @ts-ignore
|
|
||||||
.mockResolvedValueOnce({ ok: true })
|
.mockResolvedValueOnce({ ok: true })
|
||||||
// @ts-ignore
|
|
||||||
.mockRejectedValueOnce(mockError);
|
.mockRejectedValueOnce(mockError);
|
||||||
|
|
||||||
await addon.handleEvent(
|
await addon.handleEvent(
|
||||||
|
@ -17,10 +17,10 @@ import {
|
|||||||
} from '../types/index.js';
|
} from '../types/index.js';
|
||||||
import type { IntegrationEventsService } from '../services/index.js';
|
import type { IntegrationEventsService } from '../services/index.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
import nock from 'nock';
|
import nock from 'nock';
|
||||||
|
|
||||||
const registerEventMock = jest.fn();
|
const registerEventMock = vi.fn();
|
||||||
|
|
||||||
const INTEGRATION_ID = 1337;
|
const INTEGRATION_ID = 1337;
|
||||||
const ARGS: IAddonConfig = {
|
const ARGS: IAddonConfig = {
|
||||||
@ -31,7 +31,7 @@ const ARGS: IAddonConfig = {
|
|||||||
} as unknown as IntegrationEventsService,
|
} as unknown as IntegrationEventsService,
|
||||||
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
||||||
eventBus: {
|
eventBus: {
|
||||||
emit: jest.fn(),
|
emit: vi.fn(),
|
||||||
} as any,
|
} as any,
|
||||||
};
|
};
|
||||||
describe('Slack integration', () => {
|
describe('Slack integration', () => {
|
||||||
|
@ -17,10 +17,10 @@ import {
|
|||||||
} from '../types/index.js';
|
} from '../types/index.js';
|
||||||
import type { IntegrationEventsService } from '../services/index.js';
|
import type { IntegrationEventsService } from '../services/index.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
import nock from 'nock';
|
import nock from 'nock';
|
||||||
|
|
||||||
const registerEventMock = jest.fn();
|
const registerEventMock = vi.fn();
|
||||||
|
|
||||||
const INTEGRATION_ID = 1337;
|
const INTEGRATION_ID = 1337;
|
||||||
const ARGS: IAddonConfig = {
|
const ARGS: IAddonConfig = {
|
||||||
@ -31,7 +31,7 @@ const ARGS: IAddonConfig = {
|
|||||||
} as unknown as IntegrationEventsService,
|
} as unknown as IntegrationEventsService,
|
||||||
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
flagResolver: { isEnabled: (expName: IFlagKey) => false } as IFlagResolver,
|
||||||
eventBus: {
|
eventBus: {
|
||||||
emit: jest.fn(),
|
emit: vi.fn(),
|
||||||
} as any,
|
} as any,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
} from '../types/index.js';
|
} from '../types/index.js';
|
||||||
import type { IntegrationEventsService } from '../services/index.js';
|
import type { IntegrationEventsService } from '../services/index.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
import EventEmitter from 'node:events';
|
import EventEmitter from 'node:events';
|
||||||
import nock from 'nock';
|
import nock from 'nock';
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ afterEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const setup = () => {
|
const setup = () => {
|
||||||
const registerEventMock = jest.fn();
|
const registerEventMock = vi.fn();
|
||||||
const addonConfig: IAddonConfig = {
|
const addonConfig: IAddonConfig = {
|
||||||
getLogger: noLogger,
|
getLogger: noLogger,
|
||||||
unleashUrl: 'http://some-url.com',
|
unleashUrl: 'http://some-url.com',
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { createTestConfig } from '../test/config/test-config.js';
|
import { createTestConfig } from '../test/config/test-config.js';
|
||||||
import { jest } from '@jest/globals';
|
import { type Mock, vi } from 'vitest';
|
||||||
|
|
||||||
// This mock setup MUST be at the top-level, before any other code that might trigger imports.
|
// This mock setup MUST be at the top-level, before any other code that might trigger imports.
|
||||||
jest.unstable_mockModule('compression', () => ({
|
vi.mock('compression', () => ({
|
||||||
default: jest.fn().mockImplementation(() => {
|
default: vi.fn().mockImplementation(() => {
|
||||||
// This is the actual middleware function Express would use
|
// This is the actual middleware function Express would use
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
next();
|
next();
|
||||||
@ -15,8 +15,8 @@ let compression: any;
|
|||||||
|
|
||||||
const openApiService = {
|
const openApiService = {
|
||||||
// returns a middleware
|
// returns a middleware
|
||||||
validPath: jest.fn().mockReturnValue(() => {}),
|
validPath: vi.fn().mockReturnValue(() => {}),
|
||||||
useDocs: jest.fn(),
|
useDocs: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
const appModule = await import('./app.js');
|
const appModule = await import('./app.js');
|
||||||
@ -52,10 +52,10 @@ test('should call preRouterHook', async () => {
|
|||||||
|
|
||||||
describe('compression middleware', () => {
|
describe('compression middleware', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
jest.resetModules(); // Crucial: Clears the module cache.
|
vi.resetModules(); // Crucial: Clears the module cache.
|
||||||
// Import 'compression' AFTER resetModules. This ensures we get the mock.
|
// Import 'compression' AFTER resetModules. This ensures we get the mock.
|
||||||
const compressionModule = await import('compression');
|
const compressionModule = await import('compression');
|
||||||
compression = compressionModule.default; // `compression` is now our jest.fn()
|
compression = compressionModule.default; // `compression` is now our vi.fn()
|
||||||
|
|
||||||
// Import 'app.js' AFTER resetModules and AFTER 'compression' is set to the mock.
|
// Import 'app.js' AFTER resetModules and AFTER 'compression' is set to the mock.
|
||||||
// This ensures app.js uses the mocked version of compression.
|
// This ensures app.js uses the mocked version of compression.
|
||||||
@ -67,9 +67,9 @@ describe('compression middleware', () => {
|
|||||||
// Clear call history for the mock before each test in this describe block
|
// Clear call history for the mock before each test in this describe block
|
||||||
if (
|
if (
|
||||||
compression &&
|
compression &&
|
||||||
typeof (compression as jest.Mock).mockClear === 'function'
|
typeof (compression as Mock).mockClear === 'function'
|
||||||
) {
|
) {
|
||||||
(compression as jest.Mock).mockClear();
|
(compression as Mock).mockClear();
|
||||||
} else {
|
} else {
|
||||||
// This case might happen if beforeAll failed or types are unexpected
|
// This case might happen if beforeAll failed or types are unexpected
|
||||||
console.warn(
|
console.warn(
|
||||||
|
@ -5,6 +5,7 @@ import type { AccessStore } from './access-store.js';
|
|||||||
import { BadDataError } from '../error/index.js';
|
import { BadDataError } from '../error/index.js';
|
||||||
|
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
|
import { afterAll, beforeAll, describe, expect, test } from 'vitest';
|
||||||
|
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
db = await dbInit('access_store_serial', getLogger);
|
db = await dbInit('access_store_serial', getLogger);
|
||||||
|
@ -5,10 +5,10 @@ import {
|
|||||||
throwExceedsLimitError,
|
throwExceedsLimitError,
|
||||||
} from './exceeds-limit-error.js';
|
} from './exceeds-limit-error.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi, it, expect } from 'vitest';
|
||||||
|
|
||||||
it('emits events event when created through the external function', () => {
|
it('emits events event when created through the external function', () => {
|
||||||
const emitEvent = jest.fn();
|
const emitEvent = vi.fn();
|
||||||
const resource = 'some-resource';
|
const resource = 'some-resource';
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ it('emits events event when created through the external function', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('emits uses the resourceNameOverride for the event when provided, but uses the resource for the error', () => {
|
it('emits uses the resourceNameOverride for the event when provided, but uses the resource for the error', () => {
|
||||||
const emitEvent = jest.fn();
|
const emitEvent = vi.fn();
|
||||||
const resource = 'not this';
|
const resource = 'not this';
|
||||||
const resourceNameOverride = 'but this!';
|
const resourceNameOverride = 'but this!';
|
||||||
const limit = 10;
|
const limit = 10;
|
||||||
@ -47,7 +47,9 @@ it('emits uses the resourceNameOverride for the event when provided, but uses th
|
|||||||
limit,
|
limit,
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
).toThrow(new ExceedsLimitError(resource, limit));
|
).toThrowError(
|
||||||
|
expect.errorWithMessage(new ExceedsLimitError(resource, limit)),
|
||||||
|
);
|
||||||
|
|
||||||
expect(emitEvent).toHaveBeenCalledWith(EXCEEDS_LIMIT, {
|
expect(emitEvent).toHaveBeenCalledWith(EXCEEDS_LIMIT, {
|
||||||
resource: resourceNameOverride,
|
resource: resourceNameOverride,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`should match snapshot from /api/client/features 1`] = `
|
exports[`should match snapshot from /api/client/features 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -11,7 +11,7 @@ import type { Application } from 'express';
|
|||||||
import type { IFlagResolver } from '../../../types/index.js';
|
import type { IFlagResolver } from '../../../types/index.js';
|
||||||
import type TestAgent from 'supertest/lib/agent.d.ts';
|
import type TestAgent from 'supertest/lib/agent.d.ts';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let app: Application;
|
let app: Application;
|
||||||
|
|
||||||
@ -78,10 +78,10 @@ test('should get empty getFeatures via client', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('if caching is enabled should memoize', async () => {
|
test('if caching is enabled should memoize', async () => {
|
||||||
const getClientFeatures = jest.fn().mockReturnValue([]);
|
const getClientFeatures = vi.fn().mockReturnValue([]);
|
||||||
const getActiveSegmentsForClient = jest.fn().mockReturnValue([]);
|
const getActiveSegmentsForClient = vi.fn().mockReturnValue([]);
|
||||||
const respondWithValidation = jest.fn().mockReturnValue({});
|
const respondWithValidation = vi.fn().mockReturnValue({});
|
||||||
const validPath = jest.fn().mockReturnValue(jest.fn());
|
const validPath = vi.fn().mockReturnValue(vi.fn());
|
||||||
const clientSpecService = new ClientSpecService({ getLogger });
|
const clientSpecService = new ClientSpecService({ getLogger });
|
||||||
const openApiService = { respondWithValidation, validPath };
|
const openApiService = { respondWithValidation, validPath };
|
||||||
const clientFeatureToggleService = {
|
const clientFeatureToggleService = {
|
||||||
@ -119,10 +119,10 @@ test('if caching is enabled should memoize', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('if caching is not enabled all calls goes to service', async () => {
|
test('if caching is not enabled all calls goes to service', async () => {
|
||||||
const getClientFeatures = jest.fn().mockReturnValue([]);
|
const getClientFeatures = vi.fn().mockReturnValue([]);
|
||||||
const getActiveSegmentsForClient = jest.fn().mockReturnValue([]);
|
const getActiveSegmentsForClient = vi.fn().mockReturnValue([]);
|
||||||
const respondWithValidation = jest.fn().mockReturnValue({});
|
const respondWithValidation = vi.fn().mockReturnValue({});
|
||||||
const validPath = jest.fn().mockReturnValue(jest.fn());
|
const validPath = vi.fn().mockReturnValue(vi.fn());
|
||||||
const clientSpecService = new ClientSpecService({ getLogger });
|
const clientSpecService = new ClientSpecService({ getLogger });
|
||||||
const clientFeatureToggleService = {
|
const clientFeatureToggleService = {
|
||||||
getClientFeatures,
|
getClientFeatures,
|
||||||
|
@ -11,7 +11,7 @@ import type { ProjectAccess } from '../private-project/privateProjectStore.js';
|
|||||||
import EventService, { filterAccessibleProjects } from './event-service.js';
|
import EventService, { filterAccessibleProjects } from './event-service.js';
|
||||||
import { type IBaseEvent, USER_UPDATED } from '../../events/index.js';
|
import { type IBaseEvent, USER_UPDATED } from '../../events/index.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
describe('filterPrivateProjectsFromParams', () => {
|
describe('filterPrivateProjectsFromParams', () => {
|
||||||
it('should return IS_ANY_OF with allowed projects when projectParam is undefined and mode is limited', () => {
|
it('should return IS_ANY_OF with allowed projects when projectParam is undefined and mode is limited', () => {
|
||||||
@ -124,13 +124,13 @@ describe('storeEvents', () => {
|
|||||||
'should store the event %s',
|
'should store the event %s',
|
||||||
async (preDataAndData: Pick<IBaseEvent, 'preData' | 'data'>) => {
|
async (preDataAndData: Pick<IBaseEvent, 'preData' | 'data'>) => {
|
||||||
const eventStore = {
|
const eventStore = {
|
||||||
batchStore: jest.fn(),
|
batchStore: vi.fn(),
|
||||||
} as unknown as IEventStore;
|
} as unknown as IEventStore;
|
||||||
const eventService = new EventService(
|
const eventService = new EventService(
|
||||||
{
|
{
|
||||||
eventStore,
|
eventStore,
|
||||||
featureTagStore: {
|
featureTagStore: {
|
||||||
getAllByFeatures: jest.fn().mockReturnValue([]),
|
getAllByFeatures: vi.fn().mockReturnValue([]),
|
||||||
} as unknown as IFeatureTagStore,
|
} as unknown as IFeatureTagStore,
|
||||||
},
|
},
|
||||||
{ getLogger, eventBus: undefined } as unknown as IUnleashConfig,
|
{ getLogger, eventBus: undefined } as unknown as IUnleashConfig,
|
||||||
@ -152,13 +152,13 @@ describe('storeEvents', () => {
|
|||||||
);
|
);
|
||||||
test('should not store the event when predata and data are the same', async () => {
|
test('should not store the event when predata and data are the same', async () => {
|
||||||
const eventStore = {
|
const eventStore = {
|
||||||
batchStore: jest.fn(),
|
batchStore: vi.fn(),
|
||||||
} as unknown as IEventStore;
|
} as unknown as IEventStore;
|
||||||
const eventService = new EventService(
|
const eventService = new EventService(
|
||||||
{
|
{
|
||||||
eventStore,
|
eventStore,
|
||||||
featureTagStore: {
|
featureTagStore: {
|
||||||
getAllByFeatures: jest.fn().mockReturnValue([]),
|
getAllByFeatures: vi.fn().mockReturnValue([]),
|
||||||
} as unknown as IFeatureTagStore,
|
} as unknown as IFeatureTagStore,
|
||||||
},
|
},
|
||||||
{ getLogger, eventBus: undefined } as unknown as IUnleashConfig,
|
{ getLogger, eventBus: undefined } as unknown as IUnleashConfig,
|
||||||
|
@ -99,7 +99,7 @@ describe('validate incoming feature naming data', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result.state === 'valid') {
|
if (result.state === 'valid') {
|
||||||
fail('Expected invalid result');
|
expect.fail('Expected invalid result');
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(result.reasons.length).toBe(1);
|
expect(result.reasons.length).toBe(1);
|
||||||
|
@ -32,7 +32,14 @@ import {
|
|||||||
import { insertLastSeenAt } from '../../../../test/e2e/helpers/test-helper.js';
|
import { insertLastSeenAt } from '../../../../test/e2e/helpers/test-helper.js';
|
||||||
import type { EventService } from '../../../services/index.js';
|
import type { EventService } from '../../../services/index.js';
|
||||||
import type FeatureLinkService from '../../feature-links/feature-link-service.js';
|
import type FeatureLinkService from '../../feature-links/feature-link-service.js';
|
||||||
|
import {
|
||||||
|
beforeAll,
|
||||||
|
afterAll,
|
||||||
|
beforeEach,
|
||||||
|
test,
|
||||||
|
expect,
|
||||||
|
describe,
|
||||||
|
} from 'vitest';
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let service: FeatureToggleService;
|
let service: FeatureToggleService;
|
||||||
@ -385,7 +392,7 @@ test('cloning a feature flag not allowed for change requests enabled', async ()
|
|||||||
SYSTEM_USER_AUDIT,
|
SYSTEM_USER_AUDIT,
|
||||||
true,
|
true,
|
||||||
),
|
),
|
||||||
).rejects.toEqual(
|
).rejects.errorWithMessage(
|
||||||
new ForbiddenError(
|
new ForbiddenError(
|
||||||
`Cloning not allowed. Project default has change requests enabled.`,
|
`Cloning not allowed. Project default has change requests enabled.`,
|
||||||
),
|
),
|
||||||
@ -399,7 +406,7 @@ test('changing to a project with change requests enabled should not be allowed',
|
|||||||
});
|
});
|
||||||
await expect(
|
await expect(
|
||||||
service.changeProject('newFlagName', 'default', TEST_AUDIT_USER),
|
service.changeProject('newFlagName', 'default', TEST_AUDIT_USER),
|
||||||
).rejects.toEqual(
|
).rejects.errorWithMessage(
|
||||||
new ForbiddenError(
|
new ForbiddenError(
|
||||||
`Changing project not allowed. Project default has change requests enabled.`,
|
`Changing project not allowed. Project default has change requests enabled.`,
|
||||||
),
|
),
|
||||||
@ -531,7 +538,9 @@ test('If change requests are enabled, cannot change variants without going via C
|
|||||||
TEST_AUDIT_USER,
|
TEST_AUDIT_USER,
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
).rejects.toThrowError(new PermissionError(SKIP_CHANGE_REQUEST));
|
).rejects.toThrowError(
|
||||||
|
expect.errorWithMessage(new PermissionError(SKIP_CHANGE_REQUEST)),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('If CRs are protected for any environment in the project stops bulk update of variants', async () => {
|
test('If CRs are protected for any environment in the project stops bulk update of variants', async () => {
|
||||||
@ -620,7 +629,9 @@ test('If CRs are protected for any environment in the project stops bulk update
|
|||||||
},
|
},
|
||||||
TEST_AUDIT_USER,
|
TEST_AUDIT_USER,
|
||||||
),
|
),
|
||||||
).rejects.toThrowError(new PermissionError(SKIP_CHANGE_REQUEST));
|
).rejects.toThrowError(
|
||||||
|
expect.errorWithMessage(new PermissionError(SKIP_CHANGE_REQUEST)),
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('getPlaygroundFeatures should return ids and titles (if they exist) on client strategies', async () => {
|
test('getPlaygroundFeatures should return ids and titles (if they exist) on client strategies', async () => {
|
||||||
@ -799,7 +810,7 @@ test('Should not allow to add flags to archived projects', async () => {
|
|||||||
},
|
},
|
||||||
TEST_AUDIT_USER,
|
TEST_AUDIT_USER,
|
||||||
),
|
),
|
||||||
).rejects.toEqual(
|
).rejects.errorWithMessage(
|
||||||
new NotFoundError(
|
new NotFoundError(
|
||||||
`Active project with id archivedProject does not exist`,
|
`Active project with id archivedProject does not exist`,
|
||||||
),
|
),
|
||||||
@ -828,7 +839,7 @@ test('Should not allow to revive flags to archived projects', async () => {
|
|||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
service.reviveFeature(flag.name, TEST_AUDIT_USER),
|
service.reviveFeature(flag.name, TEST_AUDIT_USER),
|
||||||
).rejects.toEqual(
|
).rejects.errorWithMessage(
|
||||||
new NotFoundError(
|
new NotFoundError(
|
||||||
`Active project with id archivedProjectWithFlag does not exist`,
|
`Active project with id archivedProjectWithFlag does not exist`,
|
||||||
),
|
),
|
||||||
@ -836,7 +847,7 @@ test('Should not allow to revive flags to archived projects', async () => {
|
|||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
service.reviveFeatures([flag.name], project.id, TEST_AUDIT_USER),
|
service.reviveFeatures([flag.name], project.id, TEST_AUDIT_USER),
|
||||||
).rejects.toEqual(
|
).rejects.errorWithMessage(
|
||||||
new NotFoundError(
|
new NotFoundError(
|
||||||
`Active project with id archivedProjectWithFlag does not exist`,
|
`Active project with id archivedProjectWithFlag does not exist`,
|
||||||
),
|
),
|
||||||
|
@ -9,7 +9,7 @@ import type {
|
|||||||
} from '../../../types/index.js';
|
} from '../../../types/index.js';
|
||||||
import getLogger from '../../../../test/fixtures/no-logger.js';
|
import getLogger from '../../../../test/fixtures/no-logger.js';
|
||||||
import { ExceedsLimitError } from '../../../error/exceeds-limit-error.js';
|
import { ExceedsLimitError } from '../../../error/exceeds-limit-error.js';
|
||||||
|
import { describe, test, expect } from 'vitest';
|
||||||
const alwaysOnFlagResolver = {
|
const alwaysOnFlagResolver = {
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
return true;
|
return true;
|
||||||
@ -43,7 +43,7 @@ describe('Strategy limits', () => {
|
|||||||
await addStrategy();
|
await addStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
await expect(addStrategy()).rejects.toThrow(
|
await expect(addStrategy()).rejects.toThrowError(
|
||||||
"Failed to create strategy. You can't create more than the established limit of 3",
|
"Failed to create strategy. You can't create more than the established limit of 3",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -87,7 +87,7 @@ describe('Strategy limits', () => {
|
|||||||
contextName: 'accountId',
|
contextName: 'accountId',
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
).rejects.toThrow(
|
).rejects.toThrowError(
|
||||||
"Failed to create constraints. You can't create more than the established limit of 1",
|
"Failed to create constraints. You can't create more than the established limit of 1",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -159,7 +159,7 @@ describe('Strategy limits', () => {
|
|||||||
// check that you can't save more constraints
|
// check that you can't save more constraints
|
||||||
await expect(async () =>
|
await expect(async () =>
|
||||||
updateStrategy([...constraints, ...constraints]),
|
updateStrategy([...constraints, ...constraints]),
|
||||||
).rejects.toThrow(new ExceedsLimitError('constraints', LIMIT));
|
).rejects.errorWithMessage(new ExceedsLimitError('constraints', LIMIT));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should not allow to exceed constraint values limit', async () => {
|
test('Should not allow to exceed constraint values limit', async () => {
|
||||||
@ -195,7 +195,7 @@ describe('Strategy limits', () => {
|
|||||||
values: ['1', '2', '3', '4'],
|
values: ['1', '2', '3', '4'],
|
||||||
},
|
},
|
||||||
]),
|
]),
|
||||||
).rejects.toThrow(
|
).rejects.toThrowError(
|
||||||
"Failed to create constraint values for userId. You can't create more than the established limit of 3",
|
"Failed to create constraint values for userId. You can't create more than the established limit of 3",
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -266,7 +266,7 @@ describe('Strategy limits', () => {
|
|||||||
// check that you can't save more constraint values
|
// check that you can't save more constraint values
|
||||||
await expect(async () =>
|
await expect(async () =>
|
||||||
updateStrategy(initialConstraintValueCount + 1),
|
updateStrategy(initialConstraintValueCount + 1),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new ExceedsLimitError('constraint values for appName', LIMIT),
|
new ExceedsLimitError('constraint values for appName', LIMIT),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -33,7 +33,7 @@ import type {
|
|||||||
SetStrategySortOrderSchema,
|
SetStrategySortOrderSchema,
|
||||||
} from '../../../openapi/index.js';
|
} from '../../../openapi/index.js';
|
||||||
import { ForbiddenError } from '../../../error/index.js';
|
import { ForbiddenError } from '../../../error/index.js';
|
||||||
|
import { beforeAll, afterEach, afterAll, test, describe, expect } from 'vitest';
|
||||||
let app: IUnleashTest;
|
let app: IUnleashTest;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let defaultToken: IApiToken;
|
let defaultToken: IApiToken;
|
||||||
@ -282,7 +282,7 @@ test('should not allow to change project with dependencies', async () => {
|
|||||||
'default',
|
'default',
|
||||||
TEST_AUDIT_USER,
|
TEST_AUDIT_USER,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new ForbiddenError(
|
new ForbiddenError(
|
||||||
'Changing project not allowed. Feature has dependencies.',
|
'Changing project not allowed. Feature has dependencies.',
|
||||||
),
|
),
|
||||||
@ -2329,7 +2329,7 @@ test('Should not allow changing project to target project without the same enabl
|
|||||||
'default',
|
'default',
|
||||||
TEST_AUDIT_USER,
|
TEST_AUDIT_USER,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(new IncompatibleProjectError(targetProject));
|
).rejects.errorWithMessage(new IncompatibleProjectError(targetProject));
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should allow changing project to target project with the same enabled environments', async () => {
|
test('Should allow changing project to target project with the same enabled environments', async () => {
|
||||||
@ -2401,7 +2401,7 @@ test('Should allow changing project to target project with the same enabled envi
|
|||||||
environment: '*',
|
environment: '*',
|
||||||
secret: 'a',
|
secret: 'a',
|
||||||
});
|
});
|
||||||
await expect(async () =>
|
await expect(
|
||||||
app.services.projectService.changeProject(
|
app.services.projectService.changeProject(
|
||||||
targetProject,
|
targetProject,
|
||||||
featureName,
|
featureName,
|
||||||
|
@ -9,7 +9,7 @@ import getLogger from '../../../test/fixtures/no-logger.js';
|
|||||||
import { randomId } from '../../util/index.js';
|
import { randomId } from '../../util/index.js';
|
||||||
import { ApiTokenType } from '../../types/model.js';
|
import { ApiTokenType } from '../../types/model.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let app: IUnleashNoSupertest;
|
let app: IUnleashNoSupertest;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -37,7 +37,7 @@ beforeAll(async () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
app.services.frontendApiService.stopAll();
|
app.services.frontendApiService.stopAll();
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
|
@ -21,7 +21,7 @@ import {
|
|||||||
} from '../../types/index.js';
|
} from '../../types/index.js';
|
||||||
import type { FrontendApiService } from './frontend-api-service.js';
|
import type { FrontendApiService } from './frontend-api-service.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let app: IUnleashTest;
|
let app: IUnleashTest;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
@ -42,7 +42,7 @@ beforeAll(async () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
app.services.frontendApiService.stopAll();
|
app.services.frontendApiService.stopAll();
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(async () => {
|
afterAll(async () => {
|
||||||
@ -362,7 +362,7 @@ test('should store frontend api client metrics', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// @ts-expect-error - cachedFeatureNames is a private property in ClientMetricsServiceV2
|
// @ts-expect-error - cachedFeatureNames is a private property in ClientMetricsServiceV2
|
||||||
app.services.clientMetricsServiceV2.cachedFeatureNames = jest
|
app.services.clientMetricsServiceV2.cachedFeatureNames = vi
|
||||||
.fn<() => Promise<string[]>>()
|
.fn<() => Promise<string[]>>()
|
||||||
.mockResolvedValue([featureName]);
|
.mockResolvedValue([featureName]);
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ import type {
|
|||||||
} from '../../types/index.js';
|
} from '../../types/index.js';
|
||||||
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service.js';
|
import { UPDATE_REVISION } from '../feature-toggle/configuration-revision-service.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
const state = async (
|
const state = async (
|
||||||
cache: GlobalFrontendApiCache,
|
cache: GlobalFrontendApiCache,
|
||||||
@ -53,7 +53,7 @@ const createCache = (
|
|||||||
const config = {
|
const config = {
|
||||||
getLogger: noLogger,
|
getLogger: noLogger,
|
||||||
flagResolver: alwaysOnFlagResolver,
|
flagResolver: alwaysOnFlagResolver,
|
||||||
eventBus: <any>{ emit: jest.fn() },
|
eventBus: <any>{ emit: vi.fn() },
|
||||||
};
|
};
|
||||||
const segmentReadModel = new FakeSegmentReadModel([segment as ISegment]);
|
const segmentReadModel = new FakeSegmentReadModel([segment as ISegment]);
|
||||||
const clientFeatureToggleReadModel = new FakeClientFeatureToggleReadModel(
|
const clientFeatureToggleReadModel = new FakeClientFeatureToggleReadModel(
|
||||||
|
@ -12,7 +12,7 @@ import type {
|
|||||||
IUnleashStores,
|
IUnleashStores,
|
||||||
} from '../../types/index.js';
|
} from '../../types/index.js';
|
||||||
import { createFakeGetLicensedUsers } from './getLicensedUsers.js';
|
import { createFakeGetLicensedUsers } from './getLicensedUsers.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let instanceStatsService: InstanceStatsService;
|
let instanceStatsService: InstanceStatsService;
|
||||||
let versionService: VersionService;
|
let versionService: VersionService;
|
||||||
@ -22,7 +22,7 @@ let flagResolver: IFlagResolver;
|
|||||||
|
|
||||||
let updateMetrics: () => Promise<void>;
|
let updateMetrics: () => Promise<void>;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
register.clear();
|
register.clear();
|
||||||
|
|
||||||
@ -49,8 +49,8 @@ beforeEach(() => {
|
|||||||
);
|
);
|
||||||
updateMetrics = collectAggDbMetrics;
|
updateMetrics = collectAggDbMetrics;
|
||||||
|
|
||||||
jest.spyOn(clientInstanceStore, 'getDistinctApplicationsCount');
|
vi.spyOn(clientInstanceStore, 'getDistinctApplicationsCount');
|
||||||
jest.spyOn(instanceStatsService, 'getStats');
|
vi.spyOn(instanceStatsService, 'getStats');
|
||||||
|
|
||||||
expect(instanceStatsService.getStats).toHaveBeenCalledTimes(0);
|
expect(instanceStatsService.getStats).toHaveBeenCalledTimes(0);
|
||||||
});
|
});
|
||||||
@ -84,7 +84,7 @@ describe.each([true, false])(
|
|||||||
'When feature enabled is %s',
|
'When feature enabled is %s',
|
||||||
(featureEnabled: boolean) => {
|
(featureEnabled: boolean) => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.spyOn(flagResolver, 'getVariant').mockReturnValue({
|
vi.spyOn(flagResolver, 'getVariant').mockReturnValue({
|
||||||
name: 'memorizeStats',
|
name: 'memorizeStats',
|
||||||
enabled: featureEnabled,
|
enabled: featureEnabled,
|
||||||
feature_enabled: featureEnabled,
|
feature_enabled: featureEnabled,
|
||||||
@ -93,9 +93,7 @@ describe.each([true, false])(
|
|||||||
|
|
||||||
test(`should${featureEnabled ? ' ' : ' not '}memoize query results`, async () => {
|
test(`should${featureEnabled ? ' ' : ' not '}memoize query results`, async () => {
|
||||||
const segmentStore = stores.segmentStore;
|
const segmentStore = stores.segmentStore;
|
||||||
jest.spyOn(segmentStore, 'count').mockReturnValue(
|
vi.spyOn(segmentStore, 'count').mockReturnValue(Promise.resolve(5));
|
||||||
Promise.resolve(5),
|
|
||||||
);
|
|
||||||
expect(segmentStore.count).toHaveBeenCalledTimes(0);
|
expect(segmentStore.count).toHaveBeenCalledTimes(0);
|
||||||
expect(await instanceStatsService.segmentCount()).toBe(5);
|
expect(await instanceStatsService.segmentCount()).toBe(5);
|
||||||
expect(segmentStore.count).toHaveBeenCalledTimes(1);
|
expect(segmentStore.count).toHaveBeenCalledTimes(1);
|
||||||
@ -107,7 +105,7 @@ describe.each([true, false])(
|
|||||||
|
|
||||||
test(`should${featureEnabled ? ' ' : ' not '}memoize async query results`, async () => {
|
test(`should${featureEnabled ? ' ' : ' not '}memoize async query results`, async () => {
|
||||||
const trafficDataUsageStore = stores.trafficDataUsageStore;
|
const trafficDataUsageStore = stores.trafficDataUsageStore;
|
||||||
jest.spyOn(
|
vi.spyOn(
|
||||||
trafficDataUsageStore,
|
trafficDataUsageStore,
|
||||||
'getTrafficDataUsageForPeriod',
|
'getTrafficDataUsageForPeriod',
|
||||||
).mockReturnValue(
|
).mockReturnValue(
|
||||||
@ -142,7 +140,7 @@ describe.each([true, false])(
|
|||||||
test(`getStats should${featureEnabled ? ' ' : ' not '}be memorized`, async () => {
|
test(`getStats should${featureEnabled ? ' ' : ' not '}be memorized`, async () => {
|
||||||
const featureStrategiesReadModel =
|
const featureStrategiesReadModel =
|
||||||
stores.featureStrategiesReadModel;
|
stores.featureStrategiesReadModel;
|
||||||
jest.spyOn(
|
vi.spyOn(
|
||||||
featureStrategiesReadModel,
|
featureStrategiesReadModel,
|
||||||
'getMaxFeatureEnvironmentStrategies',
|
'getMaxFeatureEnvironmentStrategies',
|
||||||
).mockReturnValue(
|
).mockReturnValue(
|
||||||
|
@ -5,7 +5,7 @@ import { createTestConfig } from '../../../test/config/test-config.js';
|
|||||||
import FakeSettingStore from '../../../test/fixtures/fake-setting-store.js';
|
import FakeSettingStore from '../../../test/fixtures/fake-setting-store.js';
|
||||||
import type EventService from '../events/event-service.js';
|
import type EventService from '../events/event-service.js';
|
||||||
import { TEST_AUDIT_USER } from '../../types/index.js';
|
import { TEST_AUDIT_USER } from '../../types/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
test('Scheduler should run scheduled functions if maintenance mode is off', async () => {
|
test('Scheduler should run scheduled functions if maintenance mode is off', async () => {
|
||||||
const config = createTestConfig();
|
const config = createTestConfig();
|
||||||
@ -20,7 +20,7 @@ test('Scheduler should run scheduled functions if maintenance mode is off', asyn
|
|||||||
config.eventBus,
|
config.eventBus,
|
||||||
);
|
);
|
||||||
|
|
||||||
const job = jest.fn();
|
const job = vi.fn();
|
||||||
|
|
||||||
await schedulerService.schedule(
|
await schedulerService.schedule(
|
||||||
async () => {
|
async () => {
|
||||||
@ -52,7 +52,7 @@ test('Scheduler should not run scheduled functions if maintenance mode is on', a
|
|||||||
TEST_AUDIT_USER,
|
TEST_AUDIT_USER,
|
||||||
);
|
);
|
||||||
|
|
||||||
const job = jest.fn();
|
const job = vi.fn();
|
||||||
|
|
||||||
await schedulerService.schedule(
|
await schedulerService.schedule(
|
||||||
async () => {
|
async () => {
|
||||||
|
@ -13,13 +13,13 @@ import { endOfDay, startOfHour, subDays, subHours } from 'date-fns';
|
|||||||
import type { IClientMetricsEnv } from './client-metrics-store-v2-type.js';
|
import type { IClientMetricsEnv } from './client-metrics-store-v2-type.js';
|
||||||
import { UnknownFlagsService } from '../unknown-flags/unknown-flags-service.js';
|
import { UnknownFlagsService } from '../unknown-flags/unknown-flags-service.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
function initClientMetrics() {
|
function initClientMetrics() {
|
||||||
const stores = createStores();
|
const stores = createStores();
|
||||||
|
|
||||||
const eventBus = new EventEmitter();
|
const eventBus = new EventEmitter();
|
||||||
eventBus.emit = jest.fn(() => true);
|
eventBus.emit = vi.fn(() => true);
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
eventBus,
|
eventBus,
|
||||||
@ -35,7 +35,7 @@ function initClientMetrics() {
|
|||||||
},
|
},
|
||||||
config,
|
config,
|
||||||
);
|
);
|
||||||
lastSeenService.updateLastSeen = jest.fn();
|
lastSeenService.updateLastSeen = vi.fn();
|
||||||
const unknownFlagsService = new UnknownFlagsService(
|
const unknownFlagsService = new UnknownFlagsService(
|
||||||
{
|
{
|
||||||
unknownFlagsStore: stores.unknownFlagsStore,
|
unknownFlagsStore: stores.unknownFlagsStore,
|
||||||
@ -56,7 +56,7 @@ test('process metrics properly', async () => {
|
|||||||
const { clientMetricsService, eventBus, lastSeenService, stores } =
|
const { clientMetricsService, eventBus, lastSeenService, stores } =
|
||||||
initClientMetrics();
|
initClientMetrics();
|
||||||
|
|
||||||
stores.clientMetricsStoreV2.getFeatureFlagNames = jest
|
stores.clientMetricsStoreV2.getFeatureFlagNames = vi
|
||||||
.fn<() => Promise<string[]>>()
|
.fn<() => Promise<string[]>>()
|
||||||
.mockResolvedValue(['myCoolToggle', 'myOtherToggle']);
|
.mockResolvedValue(['myCoolToggle', 'myOtherToggle']);
|
||||||
|
|
||||||
|
@ -12,15 +12,15 @@ import FakeStrategiesStore from '../../../../test/fixtures/fake-strategies-store
|
|||||||
import FakeFeatureToggleStore from '../../feature-toggle/fakes/fake-feature-toggle-store.js';
|
import FakeFeatureToggleStore from '../../feature-toggle/fakes/fake-feature-toggle-store.js';
|
||||||
import type { IApplicationOverview } from './models.js';
|
import type { IApplicationOverview } from './models.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
config = createTestConfig({});
|
config = createTestConfig({});
|
||||||
});
|
});
|
||||||
test('Multiple registrations of same appname and instanceid within same time period should only cause one registration', async () => {
|
test('Multiple registrations of same appname and instanceid within same time period should only cause one registration', async () => {
|
||||||
const appStoreSpy = jest.fn();
|
const appStoreSpy = vi.fn();
|
||||||
const bulkSpy = jest.fn();
|
const bulkSpy = vi.fn();
|
||||||
const clientApplicationsStore: any = {
|
const clientApplicationsStore: any = {
|
||||||
bulkUpsert: appStoreSpy,
|
bulkUpsert: appStoreSpy,
|
||||||
};
|
};
|
||||||
@ -65,12 +65,12 @@ test('Multiple registrations of same appname and instanceid within same time per
|
|||||||
expect(registrations[0].started).toBe(client1.started);
|
expect(registrations[0].started).toBe(client1.started);
|
||||||
expect(registrations[0].interval).toBe(client1.interval);
|
expect(registrations[0].interval).toBe(client1.interval);
|
||||||
|
|
||||||
jest.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Multiple unique clients causes multiple registrations', async () => {
|
test('Multiple unique clients causes multiple registrations', async () => {
|
||||||
const appStoreSpy = jest.fn();
|
const appStoreSpy = vi.fn();
|
||||||
const bulkSpy = jest.fn();
|
const bulkSpy = vi.fn();
|
||||||
const clientApplicationsStore: any = {
|
const clientApplicationsStore: any = {
|
||||||
bulkUpsert: appStoreSpy,
|
bulkUpsert: appStoreSpy,
|
||||||
};
|
};
|
||||||
@ -119,8 +119,8 @@ test('Multiple unique clients causes multiple registrations', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Same client registered outside of dedup interval will be registered twice', async () => {
|
test('Same client registered outside of dedup interval will be registered twice', async () => {
|
||||||
const appStoreSpy = jest.fn();
|
const appStoreSpy = vi.fn();
|
||||||
const bulkSpy = jest.fn();
|
const bulkSpy = vi.fn();
|
||||||
const clientApplicationsStore: any = {
|
const clientApplicationsStore: any = {
|
||||||
bulkUpsert: appStoreSpy,
|
bulkUpsert: appStoreSpy,
|
||||||
};
|
};
|
||||||
@ -162,9 +162,7 @@ test('Same client registered outside of dedup interval will be registered twice'
|
|||||||
expect(appStoreSpy).toHaveBeenCalledTimes(2);
|
expect(appStoreSpy).toHaveBeenCalledTimes(2);
|
||||||
expect(bulkSpy).toHaveBeenCalledTimes(2);
|
expect(bulkSpy).toHaveBeenCalledTimes(2);
|
||||||
|
|
||||||
// @ts-expect-error unknown type
|
|
||||||
const firstRegistrations = appStoreSpy.mock.calls[0][0][0];
|
const firstRegistrations = appStoreSpy.mock.calls[0][0][0];
|
||||||
// @ts-expect-error unknown type
|
|
||||||
const secondRegistrations = appStoreSpy.mock.calls[1][0][0];
|
const secondRegistrations = appStoreSpy.mock.calls[1][0][0];
|
||||||
|
|
||||||
expect(firstRegistrations.appName).toBe(secondRegistrations.appName);
|
expect(firstRegistrations.appName).toBe(secondRegistrations.appName);
|
||||||
@ -172,8 +170,8 @@ test('Same client registered outside of dedup interval will be registered twice'
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('No registrations during a time period will not call stores', async () => {
|
test('No registrations during a time period will not call stores', async () => {
|
||||||
const appStoreSpy = jest.fn();
|
const appStoreSpy = vi.fn();
|
||||||
const bulkSpy = jest.fn();
|
const bulkSpy = vi.fn();
|
||||||
const clientApplicationsStore: any = {
|
const clientApplicationsStore: any = {
|
||||||
bulkUpsert: appStoreSpy,
|
bulkUpsert: appStoreSpy,
|
||||||
};
|
};
|
||||||
|
@ -3,13 +3,13 @@ import EventEmitter from 'events';
|
|||||||
import getLogger from '../../../../../test/fixtures/no-logger.js';
|
import getLogger from '../../../../../test/fixtures/no-logger.js';
|
||||||
import type { IUnleashConfig } from '../../../../types/index.js';
|
import type { IUnleashConfig } from '../../../../types/index.js';
|
||||||
import { type LastSeenInput, LastSeenService } from '../last-seen-service.js';
|
import { type LastSeenInput, LastSeenService } from '../last-seen-service.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
function initLastSeenService(flagEnabled = true) {
|
function initLastSeenService(flagEnabled = true) {
|
||||||
const stores = createStores();
|
const stores = createStores();
|
||||||
|
|
||||||
const eventBus = new EventEmitter();
|
const eventBus = new EventEmitter();
|
||||||
eventBus.emit = jest.fn() as () => boolean;
|
eventBus.emit = vi.fn() as () => boolean;
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
eventBus,
|
eventBus,
|
||||||
@ -38,7 +38,7 @@ function initLastSeenService(flagEnabled = true) {
|
|||||||
test('should not add duplicates per feature/environment', async () => {
|
test('should not add duplicates per feature/environment', async () => {
|
||||||
const { lastSeenService, featureToggleStore, lastSeenStore } =
|
const { lastSeenService, featureToggleStore, lastSeenStore } =
|
||||||
initLastSeenService(false);
|
initLastSeenService(false);
|
||||||
const lastSeenSpy = jest.spyOn(lastSeenStore, 'setLastSeen');
|
const lastSeenSpy = vi.spyOn(lastSeenStore, 'setLastSeen');
|
||||||
|
|
||||||
lastSeenService.updateLastSeen([
|
lastSeenService.updateLastSeen([
|
||||||
{
|
{
|
||||||
@ -95,7 +95,7 @@ test('should call last seen at store with correct data', async () => {
|
|||||||
timestamp: new Date(),
|
timestamp: new Date(),
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
lastSeenStore.setLastSeen = jest.fn() as (
|
lastSeenStore.setLastSeen = vi.fn() as (
|
||||||
data: LastSeenInput[],
|
data: LastSeenInput[],
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
await lastSeenService.store();
|
await lastSeenService.store();
|
||||||
|
@ -12,7 +12,7 @@ import { createTestConfig } from '../../../test/config/test-config.js';
|
|||||||
import { createOnboardingService } from './createOnboardingService.js';
|
import { createOnboardingService } from './createOnboardingService.js';
|
||||||
import type EventEmitter from 'events';
|
import type EventEmitter from 'events';
|
||||||
import { STAGE_ENTERED, USER_LOGIN } from '../../metric-events.js';
|
import { STAGE_ENTERED, USER_LOGIN } from '../../metric-events.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
@ -41,25 +41,25 @@ beforeEach(async () => {
|
|||||||
await stores.projectStore.deleteAll();
|
await stores.projectStore.deleteAll();
|
||||||
await stores.onboardingStore.deleteAll();
|
await stores.onboardingStore.deleteAll();
|
||||||
await stores.userStore.deleteAll();
|
await stores.userStore.deleteAll();
|
||||||
jest.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Default project should take first user created instead of project created as start time', async () => {
|
test('Default project should take first user created instead of project created as start time', async () => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
jest.setSystemTime(new Date());
|
vi.setSystemTime(new Date());
|
||||||
const { userStore, featureToggleStore, projectStore } = stores;
|
const { userStore, featureToggleStore, projectStore } = stores;
|
||||||
|
|
||||||
// default projects are created in advance and should be ignored
|
// default projects are created in advance and should be ignored
|
||||||
await projectStore.create({ id: 'default', name: 'irrelevant' });
|
await projectStore.create({ id: 'default', name: 'irrelevant' });
|
||||||
|
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
const user = await userStore.insert({});
|
const user = await userStore.insert({});
|
||||||
await featureToggleStore.create('default', {
|
await featureToggleStore.create('default', {
|
||||||
name: 'test-default',
|
name: 'test-default',
|
||||||
createdByUserId: user.id,
|
createdByUserId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({
|
await onboardingService.insert({
|
||||||
type: 'flag-created',
|
type: 'flag-created',
|
||||||
flag: 'test-default',
|
flag: 'test-default',
|
||||||
@ -82,12 +82,12 @@ test('Default project should take first user created instead of project created
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Ignore events for existing customers', async () => {
|
test('Ignore events for existing customers', async () => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
jest.setSystemTime(new Date(2024, 8, 2)); // day before we added metrics
|
vi.setSystemTime(new Date(2024, 8, 2)); // day before we added metrics
|
||||||
const { userStore } = stores;
|
const { userStore } = stores;
|
||||||
await userStore.insert({});
|
await userStore.insert({});
|
||||||
|
|
||||||
jest.setSystemTime(new Date());
|
vi.setSystemTime(new Date());
|
||||||
await onboardingService.insert({ type: 'first-user-login' });
|
await onboardingService.insert({ type: 'first-user-login' });
|
||||||
|
|
||||||
const { rows: instanceEvents } = await db.rawDatabase.raw(
|
const { rows: instanceEvents } = await db.rawDatabase.raw(
|
||||||
@ -109,8 +109,8 @@ test('Ignore system user in onboarding events', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Storing onboarding events', async () => {
|
test('Storing onboarding events', async () => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
jest.setSystemTime(new Date());
|
vi.setSystemTime(new Date());
|
||||||
const { userStore, featureToggleStore, projectStore } = stores;
|
const { userStore, featureToggleStore, projectStore } = stores;
|
||||||
const user = await userStore.insert({});
|
const user = await userStore.insert({});
|
||||||
await projectStore.create({ id: 'test_project', name: 'irrelevant' });
|
await projectStore.create({ id: 'test_project', name: 'irrelevant' });
|
||||||
@ -119,23 +119,23 @@ test('Storing onboarding events', async () => {
|
|||||||
createdByUserId: user.id,
|
createdByUserId: user.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'first-user-login' });
|
await onboardingService.insert({ type: 'first-user-login' });
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'second-user-login' });
|
await onboardingService.insert({ type: 'second-user-login' });
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'flag-created', flag: 'test' });
|
await onboardingService.insert({ type: 'flag-created', flag: 'test' });
|
||||||
await onboardingService.insert({ type: 'flag-created', flag: 'test' });
|
await onboardingService.insert({ type: 'flag-created', flag: 'test' });
|
||||||
await onboardingService.insert({ type: 'flag-created', flag: 'invalid' });
|
await onboardingService.insert({ type: 'flag-created', flag: 'invalid' });
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'pre-live', flag: 'test' });
|
await onboardingService.insert({ type: 'pre-live', flag: 'test' });
|
||||||
await onboardingService.insert({ type: 'pre-live', flag: 'test' });
|
await onboardingService.insert({ type: 'pre-live', flag: 'test' });
|
||||||
await onboardingService.insert({ type: 'pre-live', flag: 'invalid' });
|
await onboardingService.insert({ type: 'pre-live', flag: 'invalid' });
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'live', flag: 'test' });
|
await onboardingService.insert({ type: 'live', flag: 'test' });
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'live', flag: 'test' });
|
await onboardingService.insert({ type: 'live', flag: 'test' });
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
await onboardingService.insert({ type: 'live', flag: 'invalid' });
|
await onboardingService.insert({ type: 'live', flag: 'invalid' });
|
||||||
|
|
||||||
const { rows: instanceEvents } = await db.rawDatabase.raw(
|
const { rows: instanceEvents } = await db.rawDatabase.raw(
|
||||||
@ -174,8 +174,8 @@ const reachedOnboardingEvents = (count: number) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
test('Reacting to events', async () => {
|
test('Reacting to events', async () => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
jest.setSystemTime(new Date());
|
vi.setSystemTime(new Date());
|
||||||
const { userStore, featureToggleStore, projectStore } = stores;
|
const { userStore, featureToggleStore, projectStore } = stores;
|
||||||
const user = await userStore.insert({});
|
const user = await userStore.insert({});
|
||||||
await projectStore.create({ id: 'test_project', name: 'irrelevant' });
|
await projectStore.create({ id: 'test_project', name: 'irrelevant' });
|
||||||
@ -183,7 +183,7 @@ test('Reacting to events', async () => {
|
|||||||
name: 'test',
|
name: 'test',
|
||||||
createdByUserId: user.id,
|
createdByUserId: user.id,
|
||||||
});
|
});
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(1));
|
vi.advanceTimersByTime(minutesToMilliseconds(1));
|
||||||
|
|
||||||
eventBus.emit(USER_LOGIN, { loginOrder: 0 });
|
eventBus.emit(USER_LOGIN, { loginOrder: 0 });
|
||||||
eventBus.emit(USER_LOGIN, { loginOrder: 1 });
|
eventBus.emit(USER_LOGIN, { loginOrder: 1 });
|
||||||
|
@ -3,7 +3,8 @@ import fc from 'fast-check';
|
|||||||
import supertest from 'supertest';
|
import supertest from 'supertest';
|
||||||
import { createServices } from '../../services/index.js';
|
import { createServices } from '../../services/index.js';
|
||||||
import { createTestConfig } from '../../../test/config/test-config.js';
|
import { createTestConfig } from '../../../test/config/test-config.js';
|
||||||
|
import { it } from '@fast-check/vitest';
|
||||||
|
import { describe } from 'vitest';
|
||||||
import createStores from '../../../test/fixtures/store.js';
|
import createStores from '../../../test/fixtures/store.js';
|
||||||
|
|
||||||
import getApp from '../../app.js';
|
import getApp from '../../app.js';
|
||||||
@ -80,7 +81,7 @@ describe('the playground API', () => {
|
|||||||
.send(payload)
|
.send(payload)
|
||||||
.expect('Content-Type', /json/);
|
.expect('Content-Type', /json/);
|
||||||
|
|
||||||
return status === 400;
|
expect(status).toBe(400);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
testParams,
|
testParams,
|
||||||
|
@ -12,7 +12,7 @@ import {
|
|||||||
import NameExistsError from '../../error/name-exists-error.js';
|
import NameExistsError from '../../error/name-exists-error.js';
|
||||||
import type { EventService } from '../../services/index.js';
|
import type { EventService } from '../../services/index.js';
|
||||||
import { createEventsService } from '../events/createEventsService.js';
|
import { createEventsService } from '../events/createEventsService.js';
|
||||||
|
import { test, beforeAll, afterAll, expect } from 'vitest';
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let service: EnvironmentService;
|
let service: EnvironmentService;
|
||||||
@ -219,25 +219,26 @@ test('Adding same environment twice should throw a NameExistsError', async () =>
|
|||||||
'default',
|
'default',
|
||||||
SYSTEM_USER_AUDIT,
|
SYSTEM_USER_AUDIT,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new NameExistsError(
|
new NameExistsError(
|
||||||
'default already has the environment uniqueness-test enabled',
|
'default already has the environment uniqueness-test enabled',
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Removing environment not connected to project should be a noop', async () =>
|
test('Removing environment not connected to project should be a noop', async () => {
|
||||||
expect(async () =>
|
await expect(
|
||||||
service.removeEnvironmentFromProject(
|
service.removeEnvironmentFromProject(
|
||||||
'some-non-existing-environment',
|
'some-non-existing-environment',
|
||||||
'default',
|
'default',
|
||||||
SYSTEM_USER_AUDIT,
|
SYSTEM_USER_AUDIT,
|
||||||
),
|
),
|
||||||
).resolves);
|
).resolves;
|
||||||
|
});
|
||||||
|
|
||||||
test('Trying to get an environment that does not exist throws NotFoundError', async () => {
|
test('Trying to get an environment that does not exist throws NotFoundError', async () => {
|
||||||
const envName = 'this-should-not-exist';
|
const envName = 'this-should-not-exist';
|
||||||
await expect(async () => service.get(envName)).rejects.toThrow(
|
await expect(async () => service.get(envName)).rejects.errorWithMessage(
|
||||||
new NotFoundError(`Could not find environment with name: ${envName}`),
|
new NotFoundError(`Could not find environment with name: ${envName}`),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -34,7 +34,14 @@ import { DEFAULT_ENV, extractAuditInfoFromUser } from '../../util/index.js';
|
|||||||
import { ApiTokenType } from '../../types/model.js';
|
import { ApiTokenType } from '../../types/model.js';
|
||||||
import { createApiTokenService } from '../api-tokens/createApiTokenService.js';
|
import { createApiTokenService } from '../api-tokens/createApiTokenService.js';
|
||||||
import type User from '../../types/user.js';
|
import type User from '../../types/user.js';
|
||||||
|
import {
|
||||||
|
beforeAll,
|
||||||
|
expect,
|
||||||
|
test,
|
||||||
|
beforeEach,
|
||||||
|
afterEach,
|
||||||
|
afterAll,
|
||||||
|
} from 'vitest';
|
||||||
let stores: IUnleashStores;
|
let stores: IUnleashStores;
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
|
|
||||||
@ -672,7 +679,7 @@ describe('Managing Project access', () => {
|
|||||||
[secondUser.id],
|
[secondUser.id],
|
||||||
projectAuditUser,
|
projectAuditUser,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new InvalidOperationError(
|
new InvalidOperationError(
|
||||||
'User tried to grant role they did not have access to',
|
'User tried to grant role they did not have access to',
|
||||||
),
|
),
|
||||||
@ -746,7 +753,7 @@ describe('Managing Project access', () => {
|
|||||||
[secondUser.id],
|
[secondUser.id],
|
||||||
projectAuditUser,
|
projectAuditUser,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new InvalidOperationError(
|
new InvalidOperationError(
|
||||||
'User tried to grant role they did not have access to',
|
'User tried to grant role they did not have access to',
|
||||||
),
|
),
|
||||||
@ -868,7 +875,7 @@ describe('Managing Project access', () => {
|
|||||||
[customRoleUpdateEnvironments.id],
|
[customRoleUpdateEnvironments.id],
|
||||||
auditProjectUser,
|
auditProjectUser,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new InvalidOperationError(
|
new InvalidOperationError(
|
||||||
'User tried to assign a role they did not have access to',
|
'User tried to assign a role they did not have access to',
|
||||||
),
|
),
|
||||||
@ -885,7 +892,7 @@ describe('Managing Project access', () => {
|
|||||||
[customRoleUpdateEnvironments.id],
|
[customRoleUpdateEnvironments.id],
|
||||||
auditProjectUser,
|
auditProjectUser,
|
||||||
),
|
),
|
||||||
).rejects.toThrow(
|
).rejects.errorWithMessage(
|
||||||
new InvalidOperationError(
|
new InvalidOperationError(
|
||||||
'User tried to assign a role they did not have access to',
|
'User tried to assign a role they did not have access to',
|
||||||
),
|
),
|
||||||
@ -2641,12 +2648,12 @@ describe('create project with environments', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test("envs that don't exist cause errors", async () => {
|
test("envs that don't exist cause errors", async () => {
|
||||||
await expect(createProjectWithEnvs(['fake-project'])).rejects.toThrow(
|
await expect(
|
||||||
BadDataError,
|
createProjectWithEnvs(['fake-project']),
|
||||||
);
|
).rejects.toThrowError(BadDataError);
|
||||||
await expect(createProjectWithEnvs(['fake-project'])).rejects.toThrow(
|
await expect(
|
||||||
/'fake-project'/,
|
createProjectWithEnvs(['fake-project']),
|
||||||
);
|
).rejects.toThrowError(/'fake-project'/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ import {
|
|||||||
} from '../../types/index.js';
|
} from '../../types/index.js';
|
||||||
import { createFakeProjectService } from './createProjectService.js';
|
import { createFakeProjectService } from './createProjectService.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
describe('enterprise extension: enable change requests', () => {
|
describe('enterprise extension: enable change requests', () => {
|
||||||
const createService = (mode: 'oss' | 'enterprise' = 'enterprise') => {
|
const createService = (mode: 'oss' | 'enterprise' = 'enterprise') => {
|
||||||
@ -75,7 +75,7 @@ describe('enterprise extension: enable change requests', () => {
|
|||||||
test("it does not call the change request enablement function if we're not enterprise", async () => {
|
test("it does not call the change request enablement function if we're not enterprise", async () => {
|
||||||
const { service } = createService('oss');
|
const { service } = createService('oss');
|
||||||
|
|
||||||
const fn = jest.fn() as () => Promise<
|
const fn = vi.fn() as () => Promise<
|
||||||
{ name: string; requiredApprovals: number }[] | undefined
|
{ name: string; requiredApprovals: number }[] | undefined
|
||||||
>;
|
>;
|
||||||
|
|
||||||
@ -334,7 +334,7 @@ describe('enterprise extension: enable change requests', () => {
|
|||||||
const { service } = createService();
|
const { service } = createService();
|
||||||
|
|
||||||
const projectId = 'fake-project-id';
|
const projectId = 'fake-project-id';
|
||||||
expect(
|
await expect(
|
||||||
service.createProject(
|
service.createProject(
|
||||||
{
|
{
|
||||||
id: projectId,
|
id: projectId,
|
||||||
@ -357,7 +357,7 @@ describe('enterprise extension: enable change requests', () => {
|
|||||||
const { service } = createService('oss');
|
const { service } = createService('oss');
|
||||||
|
|
||||||
const projectId = 'fake-project-id';
|
const projectId = 'fake-project-id';
|
||||||
expect(
|
await expect(
|
||||||
service.createProject(
|
service.createProject(
|
||||||
{
|
{
|
||||||
id: projectId,
|
id: projectId,
|
||||||
|
@ -8,7 +8,7 @@ import type EventService from '../events/event-service.js';
|
|||||||
import { SCHEDULER_JOB_TIME } from '../../metric-events.js';
|
import { SCHEDULER_JOB_TIME } from '../../metric-events.js';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
import { TEST_AUDIT_USER } from '../../types/index.js';
|
import { TEST_AUDIT_USER } from '../../types/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
function ms(timeMs) {
|
function ms(timeMs) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, timeMs));
|
return new Promise((resolve) => setTimeout(resolve, timeMs));
|
||||||
@ -72,7 +72,7 @@ test('Schedules job immediately', async () => {
|
|||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
const NO_JITTER = 0;
|
const NO_JITTER = 0;
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 10, 'test-id', NO_JITTER);
|
await schedulerService.schedule(job, 10, 'test-id', NO_JITTER);
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ test('Does not schedule job immediately when paused', async () => {
|
|||||||
const { schedulerService, maintenanceService } =
|
const { schedulerService, maintenanceService } =
|
||||||
createSchedulerTestService();
|
createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await toggleMaintenanceMode(maintenanceService, true);
|
await toggleMaintenanceMode(maintenanceService, true);
|
||||||
await schedulerService.schedule(job, 10, 'test-id-2');
|
await schedulerService.schedule(job, 10, 'test-id-2');
|
||||||
@ -96,7 +96,7 @@ test('Does not schedule job immediately when paused', async () => {
|
|||||||
test('Can schedule a single regular job', async () => {
|
test('Can schedule a single regular job', async () => {
|
||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 50, 'test-id-3');
|
await schedulerService.schedule(job, 50, 'test-id-3');
|
||||||
await ms(75);
|
await ms(75);
|
||||||
@ -109,7 +109,7 @@ test('Scheduled job ignored in a paused mode', async () => {
|
|||||||
const { schedulerService, maintenanceService } =
|
const { schedulerService, maintenanceService } =
|
||||||
createSchedulerTestService();
|
createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await toggleMaintenanceMode(maintenanceService, true);
|
await toggleMaintenanceMode(maintenanceService, true);
|
||||||
await schedulerService.schedule(job, 50, 'test-id-4');
|
await schedulerService.schedule(job, 50, 'test-id-4');
|
||||||
@ -123,7 +123,7 @@ test('Can resume paused job', async () => {
|
|||||||
const { schedulerService, maintenanceService } =
|
const { schedulerService, maintenanceService } =
|
||||||
createSchedulerTestService();
|
createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await toggleMaintenanceMode(maintenanceService, true);
|
await toggleMaintenanceMode(maintenanceService, true);
|
||||||
await schedulerService.schedule(job, 50, 'test-id-5');
|
await schedulerService.schedule(job, 50, 'test-id-5');
|
||||||
@ -137,8 +137,8 @@ test('Can resume paused job', async () => {
|
|||||||
test('Can schedule multiple jobs at the same interval', async () => {
|
test('Can schedule multiple jobs at the same interval', async () => {
|
||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
const anotherJob = jest.fn() as () => Promise<void>;
|
const anotherJob = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 50, 'test-id-6');
|
await schedulerService.schedule(job, 50, 'test-id-6');
|
||||||
await schedulerService.schedule(anotherJob, 50, 'test-id-7');
|
await schedulerService.schedule(anotherJob, 50, 'test-id-7');
|
||||||
@ -152,8 +152,8 @@ test('Can schedule multiple jobs at the same interval', async () => {
|
|||||||
test('Can schedule multiple jobs at the different intervals', async () => {
|
test('Can schedule multiple jobs at the different intervals', async () => {
|
||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
const anotherJob = jest.fn() as () => Promise<void>;
|
const anotherJob = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 100, 'test-id-8');
|
await schedulerService.schedule(job, 100, 'test-id-8');
|
||||||
await schedulerService.schedule(anotherJob, 200, 'test-id-9');
|
await schedulerService.schedule(anotherJob, 200, 'test-id-9');
|
||||||
@ -242,7 +242,7 @@ it('should emit scheduler job time event when scheduled function is run', async
|
|||||||
test('Delays initial job execution by jitter duration', async () => {
|
test('Delays initial job execution by jitter duration', async () => {
|
||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
const jitterMs = 10;
|
const jitterMs = 10;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 10000, 'test-id', jitterMs);
|
await schedulerService.schedule(job, 10000, 'test-id', jitterMs);
|
||||||
@ -256,7 +256,7 @@ test('Delays initial job execution by jitter duration', async () => {
|
|||||||
test('Does not apply jitter if schedule interval is smaller than max jitter', async () => {
|
test('Does not apply jitter if schedule interval is smaller than max jitter', async () => {
|
||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
// default jitter 2s-30s
|
// default jitter 2s-30s
|
||||||
await schedulerService.schedule(job, 1000, 'test-id');
|
await schedulerService.schedule(job, 1000, 'test-id');
|
||||||
@ -269,7 +269,7 @@ test('Does not allow to run scheduled job when it is already pending', async ()
|
|||||||
const { schedulerService } = createSchedulerTestService();
|
const { schedulerService } = createSchedulerTestService();
|
||||||
const NO_JITTER = 0;
|
const NO_JITTER = 0;
|
||||||
|
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
const slowJob = async () => {
|
const slowJob = async () => {
|
||||||
job();
|
job();
|
||||||
await ms(25);
|
await ms(25);
|
||||||
|
@ -28,7 +28,7 @@ import type {
|
|||||||
} from '../../openapi/index.js';
|
} from '../../openapi/index.js';
|
||||||
import { DEFAULT_ENV, extractAuditInfoFromUser } from '../../util/index.js';
|
import { DEFAULT_ENV, extractAuditInfoFromUser } from '../../util/index.js';
|
||||||
import { DEFAULT_PROJECT, TEST_AUDIT_USER } from '../../types/index.js';
|
import { DEFAULT_PROJECT, TEST_AUDIT_USER } from '../../types/index.js';
|
||||||
|
import { beforeAll, afterAll, afterEach, test, describe, expect } from 'vitest';
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
let app: IUnleashTest;
|
let app: IUnleashTest;
|
||||||
|
|
||||||
@ -55,11 +55,9 @@ const fetchFeatureStrategies = (featureName: string) =>
|
|||||||
.expect(200)
|
.expect(200)
|
||||||
.then((res) => res.body);
|
.then((res) => res.body);
|
||||||
|
|
||||||
const fetchClientFeatures = (): Promise<IFeatureToggleClient[]> => {
|
const fetchClientFeatures = async (): Promise<IFeatureToggleClient[]> => {
|
||||||
return app.request
|
const res = await app.request.get(FEATURES_CLIENT_BASE_PATH).expect(200);
|
||||||
.get(FEATURES_CLIENT_BASE_PATH)
|
return res.body.features;
|
||||||
.expect(200)
|
|
||||||
.then((res) => res.body.features);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const createSegment = (postData: UpsertSegmentSchema): Promise<ISegment> => {
|
const createSegment = (postData: UpsertSegmentSchema): Promise<ISegment> => {
|
||||||
@ -235,7 +233,7 @@ test('should validate segment constraint values limit', async () => {
|
|||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
createSegment({ name: randomId(), constraints }),
|
createSegment({ name: randomId(), constraints }),
|
||||||
).rejects.toThrow(
|
).rejects.toThrowError(
|
||||||
`Segments may not have more than ${DEFAULT_SEGMENT_VALUES_LIMIT} values`,
|
`Segments may not have more than ${DEFAULT_SEGMENT_VALUES_LIMIT} values`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -256,7 +254,7 @@ test('should validate segment constraint values limit with multiple constraints'
|
|||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
createSegment({ name: randomId(), constraints }),
|
createSegment({ name: randomId(), constraints }),
|
||||||
).rejects.toThrow(
|
).rejects.toThrowError(
|
||||||
`Segments may not have more than ${DEFAULT_SEGMENT_VALUES_LIMIT} values`,
|
`Segments may not have more than ${DEFAULT_SEGMENT_VALUES_LIMIT} values`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -514,7 +512,7 @@ describe('project-specific segments', () => {
|
|||||||
...segment,
|
...segment,
|
||||||
project: project2,
|
project: project2,
|
||||||
}),
|
}),
|
||||||
).rejects.toThrow(
|
).rejects.toThrowError(
|
||||||
`Invalid project. Segment is being used by strategies in other projects: ${project1}`,
|
`Invalid project. Segment is being used by strategies in other projects: ${project1}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
@ -543,12 +541,12 @@ describe('project-specific segments', () => {
|
|||||||
[strategy],
|
[strategy],
|
||||||
project1,
|
project1,
|
||||||
);
|
);
|
||||||
await expect(() =>
|
await expect(
|
||||||
updateSegment(segment.id, {
|
updateSegment(segment.id, {
|
||||||
...segment,
|
...segment,
|
||||||
project: '',
|
project: '',
|
||||||
}),
|
}),
|
||||||
).resolves;
|
).resolves.toBeUndefined();
|
||||||
});
|
});
|
||||||
|
|
||||||
test(`can't set a specific segment project when being used by multiple projects (global)`, async () => {
|
test(`can't set a specific segment project when being used by multiple projects (global)`, async () => {
|
||||||
@ -589,12 +587,12 @@ describe('project-specific segments', () => {
|
|||||||
[strategy2],
|
[strategy2],
|
||||||
project2,
|
project2,
|
||||||
);
|
);
|
||||||
await expect(() =>
|
await expect(
|
||||||
updateSegment(segment.id, {
|
updateSegment(segment.id, {
|
||||||
...segment,
|
...segment,
|
||||||
project: project1,
|
project: project1,
|
||||||
}),
|
}),
|
||||||
).rejects.toThrow(
|
).rejects.toThrowError(
|
||||||
`Invalid project. Segment is being used by strategies in other projects: ${project1}, ${project2}`,
|
`Invalid project. Segment is being used by strategies in other projects: ${project1}, ${project2}`,
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
@ -9,7 +9,7 @@ import apiTokenMiddleware, {
|
|||||||
} from './api-token-middleware.js';
|
} from './api-token-middleware.js';
|
||||||
import type { ApiTokenService } from '../services/index.js';
|
import type { ApiTokenService } from '../services/index.js';
|
||||||
import type { IUnleashConfig } from '../types/index.js';
|
import type { IUnleashConfig } from '../types/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
|
|
||||||
@ -24,15 +24,15 @@ beforeEach(() => {
|
|||||||
|
|
||||||
test('should not do anything if request does not contain a authorization', async () => {
|
test('should not do anything if request does not contain a authorization', async () => {
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn(),
|
getUserForToken: vi.fn(),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn(),
|
header: vi.fn(),
|
||||||
};
|
};
|
||||||
|
|
||||||
await func(req, undefined, cb);
|
await func(req, undefined, cb);
|
||||||
@ -43,15 +43,15 @@ test('should not do anything if request does not contain a authorization', async
|
|||||||
|
|
||||||
test('should not add user if unknown token', async () => {
|
test('should not add user if unknown token', async () => {
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn(),
|
getUserForToken: vi.fn(),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-token'),
|
header: vi.fn().mockReturnValue('some-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -64,15 +64,15 @@ test('should not add user if unknown token', async () => {
|
|||||||
|
|
||||||
test('should not make database query when provided PAT format', async () => {
|
test('should not make database query when provided PAT format', async () => {
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn(),
|
getUserForToken: vi.fn(),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('user:asdkjsdhg3'),
|
header: vi.fn().mockReturnValue('user:asdkjsdhg3'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -94,15 +94,15 @@ test('should add user if known token', async () => {
|
|||||||
secret: 'a',
|
secret: 'a',
|
||||||
});
|
});
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
getUserForToken: vi.fn().mockReturnValue(apiUser),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-known-token'),
|
header: vi.fn().mockReturnValue('some-known-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
path: '/api/client',
|
path: '/api/client',
|
||||||
};
|
};
|
||||||
@ -127,11 +127,11 @@ test('should not add user if not /api/client', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
getUserForToken: vi.fn().mockReturnValue(apiUser),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const res = {
|
const res = {
|
||||||
status: (code: unknown) => ({
|
status: (code: unknown) => ({
|
||||||
@ -143,7 +143,7 @@ test('should not add user if not /api/client', async () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-known-token'),
|
header: vi.fn().mockReturnValue('some-known-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
path: '/api/admin',
|
path: '/api/admin',
|
||||||
};
|
};
|
||||||
@ -165,7 +165,7 @@ test('should not add user if disabled', async () => {
|
|||||||
secret: 'a',
|
secret: 'a',
|
||||||
});
|
});
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
getUserForToken: vi.fn().mockReturnValue(apiUser),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const disabledConfig = createTestConfig({
|
const disabledConfig = createTestConfig({
|
||||||
@ -178,14 +178,14 @@ test('should not add user if disabled', async () => {
|
|||||||
|
|
||||||
const func = apiTokenMiddleware(disabledConfig, { apiTokenService });
|
const func = apiTokenMiddleware(disabledConfig, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-known-token'),
|
header: vi.fn().mockReturnValue('some-known-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
const send = jest.fn();
|
const send = vi.fn();
|
||||||
const res = {
|
const res = {
|
||||||
status: () => {
|
status: () => {
|
||||||
return {
|
return {
|
||||||
@ -211,10 +211,10 @@ test('should call next if apiTokenService throws', async () => {
|
|||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-token'),
|
header: vi.fn().mockReturnValue('some-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -225,7 +225,7 @@ test('should call next if apiTokenService throws', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should call next if apiTokenService throws x2', async () => {
|
test('should call next if apiTokenService throws x2', async () => {
|
||||||
jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
|
vi.spyOn(global.console, 'error').mockImplementation(() => vi.fn());
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: () => {
|
getUserForToken: () => {
|
||||||
throw new Error('hi there, i am stupid');
|
throw new Error('hi there, i am stupid');
|
||||||
@ -234,10 +234,10 @@ test('should call next if apiTokenService throws x2', async () => {
|
|||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-token'),
|
header: vi.fn().mockReturnValue('some-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -256,15 +256,15 @@ test('should add user if client token and /edge/metrics', async () => {
|
|||||||
secret: 'a',
|
secret: 'a',
|
||||||
});
|
});
|
||||||
const apiTokenService = {
|
const apiTokenService = {
|
||||||
getUserForToken: jest.fn().mockReturnValue(apiUser),
|
getUserForToken: vi.fn().mockReturnValue(apiUser),
|
||||||
} as unknown as ApiTokenService;
|
} as unknown as ApiTokenService;
|
||||||
|
|
||||||
const func = apiTokenMiddleware(config, { apiTokenService });
|
const func = apiTokenMiddleware(config, { apiTokenService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('some-known-token'),
|
header: vi.fn().mockReturnValue('some-known-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
path: '/edge/metrics',
|
path: '/edge/metrics',
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
@ -3,14 +3,14 @@ import type { IUnleashConfig } from '../types/index.js';
|
|||||||
import { createTestConfig } from '../../test/config/test-config.js';
|
import { createTestConfig } from '../../test/config/test-config.js';
|
||||||
import getLogger from '../../test/fixtures/no-logger.js';
|
import getLogger from '../../test/fixtures/no-logger.js';
|
||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
const exampleSignalToken = 'signal_tokensecret';
|
const exampleSignalToken = 'signal_tokensecret';
|
||||||
|
|
||||||
describe('bearerTokenMiddleware', () => {
|
describe('bearerTokenMiddleware', () => {
|
||||||
const req = { headers: {}, path: '' } as Request;
|
const req = { headers: {}, path: '' } as Request;
|
||||||
const res = {} as Response;
|
const res = {} as Response;
|
||||||
const next = jest.fn();
|
const next = vi.fn();
|
||||||
|
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import requireContentType from './content_type_checker.js';
|
import requireContentType from './content_type_checker.js';
|
||||||
import { jest } from '@jest/globals';
|
import { type Mock, vi } from 'vitest';
|
||||||
|
|
||||||
const mockRequest: (contentType: string) => Request = (contentType) => ({
|
const mockRequest: (contentType: string) => Request = (contentType) => ({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -12,7 +12,7 @@ const mockRequest: (contentType: string) => Request = (contentType) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const returns415: (t: jest.Mock) => Response = (t) => ({
|
const returns415: (t: Mock) => Response = (t) => ({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
status: (code) => {
|
status: (code) => {
|
||||||
expect(415).toBe(code);
|
expect(415).toBe(code);
|
||||||
@ -25,7 +25,7 @@ const returns415: (t: jest.Mock) => Response = (t) => ({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const expectNoCall: (t: jest.Mock) => Response = (t) => ({
|
const expectNoCall: (t: Mock) => Response = (t) => ({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
status: () => ({
|
status: () => ({
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@ -38,8 +38,8 @@ const expectNoCall: (t: jest.Mock) => Response = (t) => ({
|
|||||||
|
|
||||||
test('Content-type middleware should by default only support application/json', () => {
|
test('Content-type middleware should by default only support application/json', () => {
|
||||||
const middleware = requireContentType();
|
const middleware = requireContentType();
|
||||||
const t = jest.fn();
|
const t = vi.fn();
|
||||||
const fail = jest.fn();
|
const fail = vi.fn();
|
||||||
middleware(mockRequest('application/json'), expectNoCall(fail), t);
|
middleware(mockRequest('application/json'), expectNoCall(fail), t);
|
||||||
middleware(mockRequest('text/plain'), returns415(t), fail);
|
middleware(mockRequest('text/plain'), returns415(t), fail);
|
||||||
expect(t).toHaveBeenCalledTimes(2);
|
expect(t).toHaveBeenCalledTimes(2);
|
||||||
@ -48,8 +48,8 @@ test('Content-type middleware should by default only support application/json',
|
|||||||
|
|
||||||
test('Content-type middleware should by default only support application/json with charset', () => {
|
test('Content-type middleware should by default only support application/json with charset', () => {
|
||||||
const middleware = requireContentType();
|
const middleware = requireContentType();
|
||||||
const t = jest.fn();
|
const t = vi.fn();
|
||||||
const fail = jest.fn();
|
const fail = vi.fn();
|
||||||
middleware(
|
middleware(
|
||||||
mockRequest('application/json; charset=UTF-8'),
|
mockRequest('application/json; charset=UTF-8'),
|
||||||
expectNoCall(fail),
|
expectNoCall(fail),
|
||||||
@ -62,8 +62,8 @@ test('Content-type middleware should by default only support application/json wi
|
|||||||
|
|
||||||
test('Content-type middleware should allow adding custom supported types', () => {
|
test('Content-type middleware should allow adding custom supported types', () => {
|
||||||
const middleware = requireContentType('application/yaml');
|
const middleware = requireContentType('application/yaml');
|
||||||
const t = jest.fn();
|
const t = vi.fn();
|
||||||
const fail = jest.fn();
|
const fail = vi.fn();
|
||||||
middleware(mockRequest('application/yaml'), expectNoCall(fail), t);
|
middleware(mockRequest('application/yaml'), expectNoCall(fail), t);
|
||||||
middleware(mockRequest('text/html'), returns415(t), fail);
|
middleware(mockRequest('text/html'), returns415(t), fail);
|
||||||
middleware(mockRequest('text/plain'), returns415(t), fail);
|
middleware(mockRequest('text/plain'), returns415(t), fail);
|
||||||
@ -73,8 +73,8 @@ test('Content-type middleware should allow adding custom supported types', () =>
|
|||||||
|
|
||||||
test('adding custom supported types no longer supports default type', () => {
|
test('adding custom supported types no longer supports default type', () => {
|
||||||
const middleware = requireContentType('application/yaml');
|
const middleware = requireContentType('application/yaml');
|
||||||
const t = jest.fn();
|
const t = vi.fn();
|
||||||
const fail = jest.fn();
|
const fail = vi.fn();
|
||||||
middleware(mockRequest('application/json'), returns415(t), fail);
|
middleware(mockRequest('application/json'), returns415(t), fail);
|
||||||
expect(t).toHaveBeenCalledTimes(1);
|
expect(t).toHaveBeenCalledTimes(1);
|
||||||
expect(fail).toHaveBeenCalledTimes(0);
|
expect(fail).toHaveBeenCalledTimes(0);
|
||||||
@ -86,8 +86,8 @@ test('Should be able to add multiple content-types supported', () => {
|
|||||||
'application/yaml',
|
'application/yaml',
|
||||||
'form/multipart',
|
'form/multipart',
|
||||||
);
|
);
|
||||||
const fail = jest.fn();
|
const fail = vi.fn();
|
||||||
const succeed = jest.fn();
|
const succeed = vi.fn();
|
||||||
middleware(mockRequest('application/json'), expectNoCall(fail), succeed);
|
middleware(mockRequest('application/json'), expectNoCall(fail), succeed);
|
||||||
middleware(mockRequest('application/yaml'), expectNoCall(fail), succeed);
|
middleware(mockRequest('application/yaml'), expectNoCall(fail), succeed);
|
||||||
middleware(mockRequest('form/multipart'), expectNoCall(fail), succeed);
|
middleware(mockRequest('form/multipart'), expectNoCall(fail), succeed);
|
||||||
|
@ -4,7 +4,7 @@ import { createTestConfig } from '../../test/config/test-config.js';
|
|||||||
import type { Request, Response } from 'express';
|
import type { Request, Response } from 'express';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { REQUEST_ORIGIN } from '../metric-events.js';
|
import { REQUEST_ORIGIN } from '../metric-events.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
const TEST_UNLEASH_TOKEN = 'TEST_UNLEASH_TOKEN';
|
const TEST_UNLEASH_TOKEN = 'TEST_UNLEASH_TOKEN';
|
||||||
const TEST_USER_AGENT = 'TEST_USER_AGENT';
|
const TEST_USER_AGENT = 'TEST_USER_AGENT';
|
||||||
@ -12,17 +12,17 @@ const TEST_USER_AGENT = 'TEST_USER_AGENT';
|
|||||||
describe('originMiddleware', () => {
|
describe('originMiddleware', () => {
|
||||||
const req = { headers: {}, path: '' } as Request;
|
const req = { headers: {}, path: '' } as Request;
|
||||||
const res = {} as Response;
|
const res = {} as Response;
|
||||||
const next = jest.fn();
|
const next = vi.fn();
|
||||||
const loggerMock = {
|
const loggerMock = {
|
||||||
debug: jest.fn(),
|
debug: vi.fn(),
|
||||||
info: jest.fn(),
|
info: vi.fn(),
|
||||||
warn: jest.fn(),
|
warn: vi.fn(),
|
||||||
error: jest.fn(),
|
error: vi.fn(),
|
||||||
fatal: jest.fn(),
|
fatal: vi.fn(),
|
||||||
};
|
};
|
||||||
const getLogger = jest.fn(() => loggerMock);
|
const getLogger = vi.fn(() => loggerMock);
|
||||||
const eventBus = new EventEmitter();
|
const eventBus = new EventEmitter();
|
||||||
eventBus.emit = jest.fn() as () => boolean;
|
eventBus.emit = vi.fn() as () => boolean;
|
||||||
|
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
|
|
||||||
|
@ -4,7 +4,7 @@ import User from '../types/user.js';
|
|||||||
import NotFoundError from '../error/notfound-error.js';
|
import NotFoundError from '../error/notfound-error.js';
|
||||||
import type { AccountService } from '../services/account-service.js';
|
import type { AccountService } from '../services/account-service.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let config: any;
|
let config: any;
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ beforeEach(() => {
|
|||||||
config = {
|
config = {
|
||||||
getLogger,
|
getLogger,
|
||||||
flagResolver: {
|
flagResolver: {
|
||||||
isEnabled: jest.fn().mockReturnValue(true),
|
isEnabled: vi.fn().mockReturnValue(true),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -20,16 +20,16 @@ beforeEach(() => {
|
|||||||
test('should not set user if unknown token', async () => {
|
test('should not set user if unknown token', async () => {
|
||||||
// @ts-expect-error wrong type
|
// @ts-expect-error wrong type
|
||||||
const accountService = {
|
const accountService = {
|
||||||
getAccountByPersonalAccessToken: jest.fn(),
|
getAccountByPersonalAccessToken: vi.fn(),
|
||||||
addPATSeen: jest.fn(),
|
addPATSeen: vi.fn(),
|
||||||
} as AccountService;
|
} as AccountService;
|
||||||
|
|
||||||
const func = patMiddleware(config, { accountService });
|
const func = patMiddleware(config, { accountService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('user:some-token'),
|
header: vi.fn().mockReturnValue('user:some-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -43,15 +43,15 @@ test('should not set user if unknown token', async () => {
|
|||||||
test('should not set user if token wrong format', async () => {
|
test('should not set user if token wrong format', async () => {
|
||||||
// @ts-expect-error wrong type
|
// @ts-expect-error wrong type
|
||||||
const accountService = {
|
const accountService = {
|
||||||
getAccountByPersonalAccessToken: jest.fn(),
|
getAccountByPersonalAccessToken: vi.fn(),
|
||||||
} as AccountService;
|
} as AccountService;
|
||||||
|
|
||||||
const func = patMiddleware(config, { accountService });
|
const func = patMiddleware(config, { accountService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('token-not-starting-with-user'),
|
header: vi.fn().mockReturnValue('token-not-starting-with-user'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -72,16 +72,16 @@ test('should add user if known token', async () => {
|
|||||||
});
|
});
|
||||||
// @ts-expect-error wrong type
|
// @ts-expect-error wrong type
|
||||||
const accountService = {
|
const accountService = {
|
||||||
getAccountByPersonalAccessToken: jest.fn().mockReturnValue(apiUser),
|
getAccountByPersonalAccessToken: vi.fn().mockReturnValue(apiUser),
|
||||||
addPATSeen: jest.fn(),
|
addPATSeen: vi.fn(),
|
||||||
} as AccountService;
|
} as AccountService;
|
||||||
|
|
||||||
const func = patMiddleware(config, { accountService });
|
const func = patMiddleware(config, { accountService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('user:some-known-token'),
|
header: vi.fn().mockReturnValue('user:some-known-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
path: '/api/client',
|
path: '/api/client',
|
||||||
};
|
};
|
||||||
@ -104,10 +104,10 @@ test('should call next if accountService throws exception', async () => {
|
|||||||
|
|
||||||
const func = patMiddleware(config, { accountService });
|
const func = patMiddleware(config, { accountService });
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('user:some-token'),
|
header: vi.fn().mockReturnValue('user:some-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,8 +121,8 @@ test('Should not log at error level if user not found', async () => {
|
|||||||
const fakeLogger = {
|
const fakeLogger = {
|
||||||
debug: () => {},
|
debug: () => {},
|
||||||
info: () => {},
|
info: () => {},
|
||||||
warn: jest.fn(),
|
warn: vi.fn(),
|
||||||
error: jest.fn(),
|
error: vi.fn(),
|
||||||
fatal: console.error,
|
fatal: console.error,
|
||||||
};
|
};
|
||||||
const conf = {
|
const conf = {
|
||||||
@ -130,20 +130,20 @@ test('Should not log at error level if user not found', async () => {
|
|||||||
return fakeLogger;
|
return fakeLogger;
|
||||||
},
|
},
|
||||||
flagResolver: {
|
flagResolver: {
|
||||||
isEnabled: jest.fn().mockReturnValue(true),
|
isEnabled: vi.fn().mockReturnValue(true),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
// @ts-expect-error wrong type
|
// @ts-expect-error wrong type
|
||||||
const accountService = {
|
const accountService = {
|
||||||
getAccountByPersonalAccessToken: jest.fn().mockImplementation(() => {
|
getAccountByPersonalAccessToken: vi.fn().mockImplementation(() => {
|
||||||
throw new NotFoundError('Could not find pat');
|
throw new NotFoundError('Could not find pat');
|
||||||
}),
|
}),
|
||||||
} as AccountService;
|
} as AccountService;
|
||||||
const mw = patMiddleware(conf, { accountService });
|
const mw = patMiddleware(conf, { accountService });
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = {
|
const req = {
|
||||||
header: jest.fn().mockReturnValue('user:some-token'),
|
header: vi.fn().mockReturnValue('user:some-token'),
|
||||||
user: undefined,
|
user: undefined,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ import { ApiTokenType } from '../types/model.js';
|
|||||||
import { type ISegmentStore, SYSTEM_USER_ID } from '../types/index.js';
|
import { type ISegmentStore, SYSTEM_USER_ID } from '../types/index.js';
|
||||||
import FakeSegmentStore from '../../test/fixtures/fake-segment-store.js';
|
import FakeSegmentStore from '../../test/fixtures/fake-segment-store.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
let featureToggleStore: IFeatureToggleStore;
|
let featureToggleStore: IFeatureToggleStore;
|
||||||
@ -24,7 +24,7 @@ beforeEach(() => {
|
|||||||
|
|
||||||
test('should add checkRbac to request', () => {
|
test('should add checkRbac to request', () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -33,9 +33,9 @@ test('should add checkRbac to request', () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
|
|
||||||
const req = jest.fn();
|
const req = vi.fn();
|
||||||
|
|
||||||
func(req, undefined, cb);
|
func(req, undefined, cb);
|
||||||
|
|
||||||
@ -47,7 +47,7 @@ test('should add checkRbac to request', () => {
|
|||||||
|
|
||||||
test('should give api-user ADMIN permission', async () => {
|
test('should give api-user ADMIN permission', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -56,7 +56,7 @@ test('should give api-user ADMIN permission', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new ApiUser({
|
user: new ApiUser({
|
||||||
tokenName: 'api',
|
tokenName: 'api',
|
||||||
@ -79,7 +79,7 @@ describe('ADMIN tokens should have user id -1337 when only passed through rbac-m
|
|||||||
/// Will be -42 (ADMIN_USER.id) when we have the api-token-middleware run first
|
/// Will be -42 (ADMIN_USER.id) when we have the api-token-middleware run first
|
||||||
test('Should give ADMIN api-user userid -1337 (SYSTEM_USER_ID)', async () => {
|
test('Should give ADMIN api-user userid -1337 (SYSTEM_USER_ID)', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -88,7 +88,7 @@ describe('ADMIN tokens should have user id -1337 when only passed through rbac-m
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new ApiUser({
|
user: new ApiUser({
|
||||||
tokenName: 'api',
|
tokenName: 'api',
|
||||||
@ -107,7 +107,7 @@ describe('ADMIN tokens should have user id -1337 when only passed through rbac-m
|
|||||||
/// Will be -42 (ADMIN_USER.id) when we have the api-token-middleware run first
|
/// Will be -42 (ADMIN_USER.id) when we have the api-token-middleware run first
|
||||||
test('Also when checking against permission NONE, userid should still be -1337', async () => {
|
test('Also when checking against permission NONE, userid should still be -1337', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -116,7 +116,7 @@ describe('ADMIN tokens should have user id -1337 when only passed through rbac-m
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new ApiUser({
|
user: new ApiUser({
|
||||||
tokenName: 'api',
|
tokenName: 'api',
|
||||||
@ -136,7 +136,7 @@ describe('ADMIN tokens should have user id -1337 when only passed through rbac-m
|
|||||||
|
|
||||||
test('should not give api-user ADMIN permission', async () => {
|
test('should not give api-user ADMIN permission', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -145,7 +145,7 @@ test('should not give api-user ADMIN permission', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new ApiUser({
|
user: new ApiUser({
|
||||||
tokenName: 'api',
|
tokenName: 'api',
|
||||||
@ -166,9 +166,9 @@ test('should not give api-user ADMIN permission', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should not allow user to miss userId', async () => {
|
test('should not allow user to miss userId', async () => {
|
||||||
jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
|
vi.spyOn(global.console, 'error').mockImplementation(() => vi.fn());
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -177,7 +177,7 @@ test('should not allow user to miss userId', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: {
|
user: {
|
||||||
username: 'user',
|
username: 'user',
|
||||||
@ -192,9 +192,9 @@ test('should not allow user to miss userId', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should return false for missing user', async () => {
|
test('should return false for missing user', async () => {
|
||||||
jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
|
vi.spyOn(global.console, 'error').mockImplementation(() => vi.fn());
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -203,7 +203,7 @@ test('should return false for missing user', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {};
|
const req: any = {};
|
||||||
|
|
||||||
func(req, undefined, cb);
|
func(req, undefined, cb);
|
||||||
@ -216,7 +216,7 @@ test('should return false for missing user', async () => {
|
|||||||
|
|
||||||
test('should verify permission for root resource', async () => {
|
test('should verify permission for root resource', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -225,7 +225,7 @@ test('should verify permission for root resource', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({
|
user: new User({
|
||||||
username: 'user',
|
username: 'user',
|
||||||
@ -249,7 +249,7 @@ test('should verify permission for root resource', async () => {
|
|||||||
|
|
||||||
test('should lookup projectId from params', async () => {
|
test('should lookup projectId from params', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -258,7 +258,7 @@ test('should lookup projectId from params', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({
|
user: new User({
|
||||||
username: 'user',
|
username: 'user',
|
||||||
@ -286,11 +286,10 @@ test('should lookup projectId from feature flag', async () => {
|
|||||||
const featureName = 'some-feature-flag';
|
const featureName = 'some-feature-flag';
|
||||||
|
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
// @ts-expect-error unknown fn type
|
featureToggleStore.getProjectId = vi.fn().mockReturnValue(projectId);
|
||||||
featureToggleStore.getProjectId = jest.fn().mockReturnValue(projectId);
|
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
config,
|
config,
|
||||||
@ -298,7 +297,7 @@ test('should lookup projectId from feature flag', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({
|
user: new User({
|
||||||
username: 'user',
|
username: 'user',
|
||||||
@ -326,7 +325,7 @@ test('should lookup projectId from data', async () => {
|
|||||||
const featureName = 'some-feature-flag';
|
const featureName = 'some-feature-flag';
|
||||||
|
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -335,7 +334,7 @@ test('should lookup projectId from data', async () => {
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({
|
user: new User({
|
||||||
username: 'user',
|
username: 'user',
|
||||||
@ -364,17 +363,16 @@ test('Does not double check permission if not changing project when updating fla
|
|||||||
const oldProjectId = 'some-project-34';
|
const oldProjectId = 'some-project-34';
|
||||||
const featureName = 'some-feature-flag';
|
const featureName = 'some-feature-flag';
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn().mockReturnValue(true),
|
hasPermission: vi.fn().mockReturnValue(true),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
// @ts-expect-error unknown fn type
|
featureToggleStore.getProjectId = vi.fn().mockReturnValue(oldProjectId);
|
||||||
featureToggleStore.getProjectId = jest.fn().mockReturnValue(oldProjectId);
|
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
config,
|
config,
|
||||||
{ featureToggleStore, segmentStore },
|
{ featureToggleStore, segmentStore },
|
||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({ username: 'user', id: 1 }),
|
user: new User({ username: 'user', id: 1 }),
|
||||||
params: { featureName },
|
params: { featureName },
|
||||||
@ -394,7 +392,7 @@ test('Does not double check permission if not changing project when updating fla
|
|||||||
|
|
||||||
test('CREATE_TAG_TYPE does not need projectId', async () => {
|
test('CREATE_TAG_TYPE does not need projectId', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn().mockReturnValue(true),
|
hasPermission: vi.fn().mockReturnValue(true),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -402,7 +400,7 @@ test('CREATE_TAG_TYPE does not need projectId', async () => {
|
|||||||
{ featureToggleStore, segmentStore },
|
{ featureToggleStore, segmentStore },
|
||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({ username: 'user', id: 1 }),
|
user: new User({ username: 'user', id: 1 }),
|
||||||
params: {},
|
params: {},
|
||||||
@ -422,7 +420,7 @@ test('CREATE_TAG_TYPE does not need projectId', async () => {
|
|||||||
|
|
||||||
test('UPDATE_TAG_TYPE does not need projectId', async () => {
|
test('UPDATE_TAG_TYPE does not need projectId', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn().mockReturnValue(true),
|
hasPermission: vi.fn().mockReturnValue(true),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -430,7 +428,7 @@ test('UPDATE_TAG_TYPE does not need projectId', async () => {
|
|||||||
{ featureToggleStore, segmentStore },
|
{ featureToggleStore, segmentStore },
|
||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({ username: 'user', id: 1 }),
|
user: new User({ username: 'user', id: 1 }),
|
||||||
params: {},
|
params: {},
|
||||||
@ -450,7 +448,7 @@ test('UPDATE_TAG_TYPE does not need projectId', async () => {
|
|||||||
|
|
||||||
test('DELETE_TAG_TYPE does not need projectId', async () => {
|
test('DELETE_TAG_TYPE does not need projectId', async () => {
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn().mockReturnValue(true),
|
hasPermission: vi.fn().mockReturnValue(true),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -458,7 +456,7 @@ test('DELETE_TAG_TYPE does not need projectId', async () => {
|
|||||||
{ featureToggleStore, segmentStore },
|
{ featureToggleStore, segmentStore },
|
||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({ username: 'user', id: 1 }),
|
user: new User({ username: 'user', id: 1 }),
|
||||||
params: {},
|
params: {},
|
||||||
@ -480,7 +478,7 @@ test('should not expect featureName for UPDATE_FEATURE when projectId specified'
|
|||||||
const projectId = 'some-project-33';
|
const projectId = 'some-project-33';
|
||||||
|
|
||||||
const accessService = {
|
const accessService = {
|
||||||
hasPermission: jest.fn(),
|
hasPermission: vi.fn(),
|
||||||
} as PermissionChecker;
|
} as PermissionChecker;
|
||||||
|
|
||||||
const func = rbacMiddleware(
|
const func = rbacMiddleware(
|
||||||
@ -489,7 +487,7 @@ test('should not expect featureName for UPDATE_FEATURE when projectId specified'
|
|||||||
accessService,
|
accessService,
|
||||||
);
|
);
|
||||||
|
|
||||||
const cb = jest.fn();
|
const cb = vi.fn();
|
||||||
const req: any = {
|
const req: any = {
|
||||||
user: new User({
|
user: new User({
|
||||||
username: 'user',
|
username: 'user',
|
||||||
|
@ -3,7 +3,7 @@ import {
|
|||||||
storeRequestedRoute,
|
storeRequestedRoute,
|
||||||
} from './response-time-metrics.js';
|
} from './response-time-metrics.js';
|
||||||
import { REQUEST_TIME } from '../metric-events.js';
|
import { REQUEST_TIME } from '../metric-events.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
import type { IFlagResolver } from '../server-impl.js';
|
import type { IFlagResolver } from '../server-impl.js';
|
||||||
import EventEmitter from 'events';
|
import EventEmitter from 'events';
|
||||||
|
|
||||||
@ -20,10 +20,10 @@ const isDefined = async (timeInfo: any, limit = 10) => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const flagResolver = {
|
const flagResolver = {
|
||||||
isEnabled: jest.fn(),
|
isEnabled: vi.fn(),
|
||||||
getAll: jest.fn(),
|
getAll: vi.fn(),
|
||||||
getVariant: jest.fn(),
|
getVariant: vi.fn(),
|
||||||
getStaticContext: jest.fn(),
|
getStaticContext: vi.fn(),
|
||||||
} as IFlagResolver;
|
} as IFlagResolver;
|
||||||
|
|
||||||
// Make sure it's always cleaned up
|
// Make sure it's always cleaned up
|
||||||
@ -32,7 +32,7 @@ beforeEach(() => {
|
|||||||
res = {
|
res = {
|
||||||
statusCode: 200,
|
statusCode: 200,
|
||||||
locals: {}, // res will always have locals (according to express RequestHandler type)
|
locals: {}, // res will always have locals (according to express RequestHandler type)
|
||||||
once: jest.fn((event: string, callback: () => void) => {
|
once: vi.fn((event: string, callback: () => void) => {
|
||||||
if (event === 'finish') {
|
if (event === 'finish') {
|
||||||
callback();
|
callback();
|
||||||
}
|
}
|
||||||
@ -42,7 +42,7 @@ beforeEach(() => {
|
|||||||
|
|
||||||
describe('responseTimeMetrics new behavior', () => {
|
describe('responseTimeMetrics new behavior', () => {
|
||||||
const instanceStatsService = {
|
const instanceStatsService = {
|
||||||
getAppCountSnapshot: jest.fn() as () => number | undefined,
|
getAppCountSnapshot: vi.fn() as () => number | undefined,
|
||||||
};
|
};
|
||||||
const eventBus = new EventEmitter();
|
const eventBus = new EventEmitter();
|
||||||
|
|
||||||
|
@ -134,6 +134,11 @@ describe.each(metaRules)('OpenAPI schemas $name', (rule) => {
|
|||||||
expect(validateMetaSchema.errors).toBeNull();
|
expect(validateMetaSchema.errors).toBeNull();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
} else {
|
||||||
|
// Added, because vitest requires tests for all exceptions.
|
||||||
|
it(`${schemaName}`, () => {
|
||||||
|
expect(true).toBe(true);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`updateEnvironmentSchema 1`] = `
|
exports[`updateEnvironmentSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`apiTokenSchema empty 1`] = `
|
exports[`apiTokenSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`changePasswordSchema empty 1`] = `
|
exports[`changePasswordSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`clientApplicationSchema no fields 1`] = `
|
exports[`clientApplicationSchema no fields 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`clientFeaturesSchema no fields 1`] = `
|
exports[`clientFeaturesSchema no fields 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`clientMetricsSchema should fail when required field is missing 1`] = `
|
exports[`clientMetricsSchema should fail when required field is missing 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`constraintSchema invalid operator name 1`] = `
|
exports[`constraintSchema invalid operator name 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`contextFieldSchema empty 1`] = `
|
exports[`contextFieldSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`deprecatedProjectOverviewSchema 1`] = `
|
exports[`deprecatedProjectOverviewSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`emailSchema 1`] = `
|
exports[`emailSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`featureEnvironmentSchema empty 1`] = `
|
exports[`featureEnvironmentSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`featureSchema constraints 1`] = `
|
exports[`featureSchema constraints 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`featureTypeCountSchema 1`] = `
|
exports[`featureTypeCountSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`featureTypeSchema empty 1`] = `
|
exports[`featureTypeSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`meSchema empty 1`] = `
|
exports[`meSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`projectOverviewSchema 1`] = `
|
exports[`projectOverviewSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`roleSchema 1`] = `
|
exports[`roleSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`segmentStrategiesSchema 1`] = `
|
exports[`segmentStrategiesSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`updateEnvironmentSchema 1`] = `undefined`;
|
exports[`updateEnvironmentSchema 1`] = `undefined`;
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`setStrategySortOrderSchema missing id 1`] = `
|
exports[`setStrategySortOrderSchema missing id 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`sortOrderSchema invalid value type 1`] = `
|
exports[`sortOrderSchema invalid value type 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`strategySchema 1`] = `
|
exports[`strategySchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`tokenUserSchema 1`] = `
|
exports[`tokenUserSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`updateFeatureStrategySegmentsSchema schema 1`] = `
|
exports[`updateFeatureStrategySegmentsSchema schema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`upsertSegmentSchema 1`] = `
|
exports[`upsertSegmentSchema 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||||
|
|
||||||
exports[`validatePasswordSchema empty 1`] = `
|
exports[`validatePasswordSchema empty 1`] = `
|
||||||
{
|
{
|
||||||
|
@ -6,6 +6,7 @@ import {
|
|||||||
} from '../../../lib/openapi/spec/playground-request-schema.js';
|
} from '../../../lib/openapi/spec/playground-request-schema.js';
|
||||||
import { validateSchema } from '../validate.js';
|
import { validateSchema } from '../validate.js';
|
||||||
import { generate as generateContext } from './sdk-context-schema.test.js';
|
import { generate as generateContext } from './sdk-context-schema.test.js';
|
||||||
|
import { test } from '@fast-check/vitest';
|
||||||
|
|
||||||
export const generate = (): Arbitrary<PlaygroundRequestSchema> =>
|
export const generate = (): Arbitrary<PlaygroundRequestSchema> =>
|
||||||
fc.record({
|
fc.record({
|
||||||
|
@ -6,7 +6,7 @@ import {
|
|||||||
import { validateSchema } from '../validate.js';
|
import { validateSchema } from '../validate.js';
|
||||||
import { generate as generateInput } from './playground-request-schema.test.js';
|
import { generate as generateInput } from './playground-request-schema.test.js';
|
||||||
import { generate as generateFeature } from './playground-feature-schema.test.js';
|
import { generate as generateFeature } from './playground-feature-schema.test.js';
|
||||||
|
import { test } from '@fast-check/vitest';
|
||||||
const generate = (): Arbitrary<PlaygroundResponseSchema> =>
|
const generate = (): Arbitrary<PlaygroundResponseSchema> =>
|
||||||
fc.record({
|
fc.record({
|
||||||
input: generateInput(),
|
input: generateInput(),
|
||||||
@ -15,7 +15,9 @@ const generate = (): Arbitrary<PlaygroundResponseSchema> =>
|
|||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
|
|
||||||
test('playgroundResponseSchema', () =>
|
test(
|
||||||
|
'playgroundResponseSchema',
|
||||||
|
() =>
|
||||||
fc.assert(
|
fc.assert(
|
||||||
fc.property(
|
fc.property(
|
||||||
generate(),
|
generate(),
|
||||||
@ -23,4 +25,6 @@ test('playgroundResponseSchema', () =>
|
|||||||
validateSchema(playgroundResponseSchema.$id, data) ===
|
validateSchema(playgroundResponseSchema.$id, data) ===
|
||||||
undefined,
|
undefined,
|
||||||
),
|
),
|
||||||
));
|
),
|
||||||
|
{ timeout: 60000 },
|
||||||
|
);
|
||||||
|
@ -5,7 +5,7 @@ import {
|
|||||||
sdkContextSchema,
|
sdkContextSchema,
|
||||||
} from './sdk-context-schema.js';
|
} from './sdk-context-schema.js';
|
||||||
import { commonISOTimestamp } from '../../../test/arbitraries.test.js';
|
import { commonISOTimestamp } from '../../../test/arbitraries.test.js';
|
||||||
|
import { test } from '@fast-check/vitest';
|
||||||
export const generate = (): Arbitrary<SdkContextSchema> =>
|
export const generate = (): Arbitrary<SdkContextSchema> =>
|
||||||
fc.record(
|
fc.record(
|
||||||
{
|
{
|
||||||
|
@ -7,7 +7,7 @@ import permissions from '../../../test/fixtures/permissions.js';
|
|||||||
import { RoleName, RoleType } from '../../types/model.js';
|
import { RoleName, RoleType } from '../../types/model.js';
|
||||||
import type { IUnleashStores } from '../../types/index.js';
|
import type { IUnleashStores } from '../../types/index.js';
|
||||||
import type TestAgent from 'supertest/lib/agent.d.ts';
|
import type TestAgent from 'supertest/lib/agent.d.ts';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
describe('Public Signup API', () => {
|
describe('Public Signup API', () => {
|
||||||
async function getSetup() {
|
async function getSetup() {
|
||||||
@ -19,8 +19,8 @@ describe('Public Signup API', () => {
|
|||||||
|
|
||||||
stores.accessStore = {
|
stores.accessStore = {
|
||||||
...stores.accessStore,
|
...stores.accessStore,
|
||||||
addUserToRole: jest.fn() as () => Promise<void>,
|
addUserToRole: vi.fn() as () => Promise<void>,
|
||||||
removeRolesOfTypeForUser: jest.fn() as () => Promise<void>,
|
removeRolesOfTypeForUser: vi.fn() as () => Promise<void>,
|
||||||
};
|
};
|
||||||
|
|
||||||
const services = createServices(stores, config);
|
const services = createServices(stores, config);
|
||||||
|
@ -4,7 +4,7 @@ import createStores from '../../../test/fixtures/store.js';
|
|||||||
import permissions from '../../../test/fixtures/permissions.js';
|
import permissions from '../../../test/fixtures/permissions.js';
|
||||||
import getApp from '../../app.js';
|
import getApp from '../../app.js';
|
||||||
import { createServices } from '../../services/index.js';
|
import { createServices } from '../../services/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
async function getSetup() {
|
async function getSetup() {
|
||||||
const randomBase = `/random${Math.round(Math.random() * 1000)}`;
|
const randomBase = `/random${Math.round(Math.random() * 1000)}`;
|
||||||
@ -113,14 +113,14 @@ test('validate format when updating strategy', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('editable=false will stop delete request', async () => {
|
test('editable=false will stop delete request', async () => {
|
||||||
jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
|
vi.spyOn(global.console, 'error').mockImplementation(() => vi.fn());
|
||||||
const { request, base } = await getSetup();
|
const { request, base } = await getSetup();
|
||||||
const name = 'default';
|
const name = 'default';
|
||||||
return request.delete(`${base}/api/admin/strategies/${name}`).expect(500);
|
return request.delete(`${base}/api/admin/strategies/${name}`).expect(500);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('editable=false will stop edit request', async () => {
|
test('editable=false will stop edit request', async () => {
|
||||||
jest.spyOn(global.console, 'error').mockImplementation(() => jest.fn());
|
vi.spyOn(global.console, 'error').mockImplementation(() => vi.fn());
|
||||||
const { request, base } = await getSetup();
|
const { request, base } = await getSetup();
|
||||||
const name = 'default';
|
const name = 'default';
|
||||||
return request
|
return request
|
||||||
|
@ -8,7 +8,7 @@ import SessionService from '../services/session-service.js';
|
|||||||
import FakeSessionStore from '../../test/fixtures/fake-session-store.js';
|
import FakeSessionStore from '../../test/fixtures/fake-session-store.js';
|
||||||
import noLogger from '../../test/fixtures/no-logger.js';
|
import noLogger from '../../test/fixtures/no-logger.js';
|
||||||
import { addDays } from 'date-fns';
|
import { addDays } from 'date-fns';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
test('should redirect to "/" after logout', async () => {
|
test('should redirect to "/" after logout', async () => {
|
||||||
const baseUriPath = '';
|
const baseUriPath = '';
|
||||||
@ -146,7 +146,7 @@ test('should clear "unleash-session" cookie even when disabled clear site data',
|
|||||||
test('should call destroy on session', async () => {
|
test('should call destroy on session', async () => {
|
||||||
const baseUriPath = '';
|
const baseUriPath = '';
|
||||||
const fakeSession = {
|
const fakeSession = {
|
||||||
destroy: jest.fn(),
|
destroy: vi.fn(),
|
||||||
};
|
};
|
||||||
const app = express();
|
const app = express();
|
||||||
const config = createTestConfig({ server: { baseUriPath } });
|
const config = createTestConfig({ server: { baseUriPath } });
|
||||||
@ -171,7 +171,7 @@ test('should call destroy on session', async () => {
|
|||||||
test('should handle req.logout with callback function', async () => {
|
test('should handle req.logout with callback function', async () => {
|
||||||
// passport >=0.6.0
|
// passport >=0.6.0
|
||||||
const baseUriPath = '';
|
const baseUriPath = '';
|
||||||
const logoutFunction = jest.fn((cb: (err?: any) => void) => cb());
|
const logoutFunction = vi.fn((cb: (err?: any) => void) => cb());
|
||||||
const app = express();
|
const app = express();
|
||||||
const config = createTestConfig({ server: { baseUriPath } });
|
const config = createTestConfig({ server: { baseUriPath } });
|
||||||
app.use((req: IAuthRequest, res, next) => {
|
app.use((req: IAuthRequest, res, next) => {
|
||||||
@ -196,7 +196,7 @@ test('should handle req.logout with callback function', async () => {
|
|||||||
test('should handle req.logout without callback function', async () => {
|
test('should handle req.logout without callback function', async () => {
|
||||||
// passport <0.6.0
|
// passport <0.6.0
|
||||||
const baseUriPath = '';
|
const baseUriPath = '';
|
||||||
const logoutFunction = jest.fn();
|
const logoutFunction = vi.fn();
|
||||||
const app = express();
|
const app = express();
|
||||||
const config = createTestConfig({ server: { baseUriPath } });
|
const config = createTestConfig({ server: { baseUriPath } });
|
||||||
app.use((req: IAuthRequest, res, next) => {
|
app.use((req: IAuthRequest, res, next) => {
|
||||||
@ -220,7 +220,7 @@ test('should handle req.logout without callback function', async () => {
|
|||||||
|
|
||||||
test('should redirect to alternative logoutUrl', async () => {
|
test('should redirect to alternative logoutUrl', async () => {
|
||||||
const fakeSession = {
|
const fakeSession = {
|
||||||
destroy: jest.fn(),
|
destroy: vi.fn(),
|
||||||
logoutUrl: '/some-other-path',
|
logoutUrl: '/some-other-path',
|
||||||
};
|
};
|
||||||
const app = express();
|
const app = express();
|
||||||
@ -248,7 +248,7 @@ test('Should destroy sessions for user', async () => {
|
|||||||
const app = express();
|
const app = express();
|
||||||
const config = createTestConfig();
|
const config = createTestConfig();
|
||||||
const fakeSession = {
|
const fakeSession = {
|
||||||
destroy: jest.fn(),
|
destroy: vi.fn(),
|
||||||
user: {
|
user: {
|
||||||
id: 1,
|
id: 1,
|
||||||
},
|
},
|
||||||
|
@ -7,7 +7,7 @@ import permissions from '../../test/fixtures/permissions.js';
|
|||||||
import { RoleName, RoleType } from '../types/model.js';
|
import { RoleName, RoleType } from '../types/model.js';
|
||||||
import type { IUnleashStores } from '../types/index.js';
|
import type { IUnleashStores } from '../types/index.js';
|
||||||
import type TestAgent from 'supertest/lib/agent.d.ts';
|
import type TestAgent from 'supertest/lib/agent.d.ts';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
describe('Public Signup API', () => {
|
describe('Public Signup API', () => {
|
||||||
async function getSetup() {
|
async function getSetup() {
|
||||||
@ -19,8 +19,8 @@ describe('Public Signup API', () => {
|
|||||||
|
|
||||||
stores.accessStore = {
|
stores.accessStore = {
|
||||||
...stores.accessStore,
|
...stores.accessStore,
|
||||||
addUserToRole: jest.fn() as () => Promise<void>,
|
addUserToRole: vi.fn() as () => Promise<void>,
|
||||||
removeRolesOfTypeForUser: jest.fn() as () => Promise<void>,
|
removeRolesOfTypeForUser: vi.fn() as () => Promise<void>,
|
||||||
getRolesForUserId: () => Promise.resolve([]),
|
getRolesForUserId: () => Promise.resolve([]),
|
||||||
getRootRoleForUser: () =>
|
getRootRoleForUser: () =>
|
||||||
Promise.resolve({
|
Promise.resolve({
|
||||||
|
@ -10,25 +10,25 @@ import {
|
|||||||
start,
|
start,
|
||||||
type UnleashFactoryMethods,
|
type UnleashFactoryMethods,
|
||||||
} from './server-impl.js';
|
} from './server-impl.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
import type MetricsMonitor from './metrics.js';
|
import type MetricsMonitor from './metrics.js';
|
||||||
|
|
||||||
const mockFactories: () => UnleashFactoryMethods = () => ({
|
const mockFactories: () => UnleashFactoryMethods = () => ({
|
||||||
createDb: jest.fn<(config: IUnleashConfig) => Db>().mockReturnValue({
|
createDb: vi.fn<(config: IUnleashConfig) => Db>().mockReturnValue({
|
||||||
destroy: jest.fn(),
|
destroy: vi.fn(),
|
||||||
} as unknown as Db),
|
} as unknown as Db),
|
||||||
createStores: jest
|
createStores: vi
|
||||||
.fn<(config: IUnleashConfig, db: Db) => IUnleashStores>()
|
.fn<(config: IUnleashConfig, db: Db) => IUnleashStores>()
|
||||||
.mockReturnValue({
|
.mockReturnValue({
|
||||||
settingStore: {
|
settingStore: {
|
||||||
get: jest.fn(),
|
get: vi.fn(),
|
||||||
postgresVersion: jest.fn(),
|
postgresVersion: vi.fn(),
|
||||||
},
|
},
|
||||||
eventStore: {
|
eventStore: {
|
||||||
on: jest.fn(),
|
on: vi.fn(),
|
||||||
},
|
},
|
||||||
} as unknown as IUnleashStores),
|
} as unknown as IUnleashStores),
|
||||||
createServices: jest
|
createServices: vi
|
||||||
.fn<
|
.fn<
|
||||||
(
|
(
|
||||||
stores: IUnleashStores,
|
stores: IUnleashStores,
|
||||||
@ -38,24 +38,24 @@ const mockFactories: () => UnleashFactoryMethods = () => ({
|
|||||||
>()
|
>()
|
||||||
.mockReturnValue({
|
.mockReturnValue({
|
||||||
userService: {
|
userService: {
|
||||||
initAdminUser: jest.fn(),
|
initAdminUser: vi.fn(),
|
||||||
},
|
},
|
||||||
schedulerService: {
|
schedulerService: {
|
||||||
schedule: jest.fn(),
|
schedule: vi.fn(),
|
||||||
stop: jest.fn(),
|
stop: vi.fn(),
|
||||||
},
|
},
|
||||||
addonService: {
|
addonService: {
|
||||||
destroy: jest.fn(),
|
destroy: vi.fn(),
|
||||||
},
|
},
|
||||||
openApiService: {
|
openApiService: {
|
||||||
// returns a middleware
|
// returns a middleware
|
||||||
validPath: jest.fn().mockReturnValue(() => {}),
|
validPath: vi.fn().mockReturnValue(() => {}),
|
||||||
},
|
},
|
||||||
} as unknown as IUnleashServices),
|
} as unknown as IUnleashServices),
|
||||||
createSessionDb:
|
createSessionDb:
|
||||||
jest.fn<(config: IUnleashConfig, db: Db) => RequestHandler>(),
|
vi.fn<(config: IUnleashConfig, db: Db) => RequestHandler>(),
|
||||||
createMetricsMonitor: jest.fn<() => MetricsMonitor>().mockReturnValue({
|
createMetricsMonitor: vi.fn<() => MetricsMonitor>().mockReturnValue({
|
||||||
startMonitoring: jest.fn(),
|
startMonitoring: vi.fn(),
|
||||||
} as unknown as MetricsMonitor),
|
} as unknown as MetricsMonitor),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,6 +27,7 @@ import BadDataError from '../../lib/error/bad-data-error.js';
|
|||||||
import { createFakeEventsService } from '../../lib/features/events/createEventsService.js';
|
import { createFakeEventsService } from '../../lib/features/events/createEventsService.js';
|
||||||
import { createFakeAccessReadModel } from '../features/access/createAccessReadModel.js';
|
import { createFakeAccessReadModel } from '../features/access/createAccessReadModel.js';
|
||||||
import { ROLE_CREATED } from '../events/index.js';
|
import { ROLE_CREATED } from '../events/index.js';
|
||||||
|
import { expect } from 'vitest';
|
||||||
|
|
||||||
function getSetup() {
|
function getSetup() {
|
||||||
const config = createTestConfig({
|
const config = createTestConfig({
|
||||||
@ -56,10 +57,14 @@ test('should fail when name exists', async () => {
|
|||||||
SYSTEM_USER_AUDIT,
|
SYSTEM_USER_AUDIT,
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(accessService.validateRole(existingRole)).rejects.toThrow(
|
await expect(() =>
|
||||||
|
accessService.validateRole(existingRole),
|
||||||
|
).rejects.toThrowError(
|
||||||
|
expect.errorWithMessage(
|
||||||
new NameExistsError(
|
new NameExistsError(
|
||||||
`There already exists a role with the name ${existingRole.name}`,
|
`There already exists a role with the name ${existingRole.name}`,
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -110,7 +115,7 @@ test('should not accept empty names', async () => {
|
|||||||
|
|
||||||
await expect(
|
await expect(
|
||||||
accessService.validateRole(withWhitespaceName),
|
accessService.validateRole(withWhitespaceName),
|
||||||
).rejects.toThrow('"name" is not allowed to be empty');
|
).rejects.toThrowError('"name" is not allowed to be empty');
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should trim leading and trailing whitespace from names', async () => {
|
test('should trim leading and trailing whitespace from names', async () => {
|
||||||
|
@ -14,7 +14,7 @@ import {
|
|||||||
API_TOKEN_DELETED,
|
API_TOKEN_DELETED,
|
||||||
API_TOKEN_UPDATED,
|
API_TOKEN_UPDATED,
|
||||||
} from '../events/index.js';
|
} from '../events/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
test('Should init api token', async () => {
|
test('Should init api token', async () => {
|
||||||
const token = {
|
const token = {
|
||||||
@ -170,7 +170,7 @@ describe('API token getTokenWithCache', () => {
|
|||||||
|
|
||||||
test('should return the token and perform only one db query', async () => {
|
test('should return the token and perform only one db query', async () => {
|
||||||
const { apiTokenService, apiTokenStore } = setup();
|
const { apiTokenService, apiTokenStore } = setup();
|
||||||
const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get');
|
const apiTokenStoreGet = vi.spyOn(apiTokenStore, 'get');
|
||||||
|
|
||||||
// valid token not present in cache (could be inserted by another instance)
|
// valid token not present in cache (could be inserted by another instance)
|
||||||
apiTokenStore.insert(token);
|
apiTokenStore.insert(token);
|
||||||
@ -185,9 +185,9 @@ describe('API token getTokenWithCache', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should query the db only once for invalid tokens', async () => {
|
test('should query the db only once for invalid tokens', async () => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
const { apiTokenService, apiTokenStore } = setup();
|
const { apiTokenService, apiTokenStore } = setup();
|
||||||
const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get');
|
const apiTokenStoreGet = vi.spyOn(apiTokenStore, 'get');
|
||||||
|
|
||||||
const invalidToken = 'invalid-token';
|
const invalidToken = 'invalid-token';
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
@ -198,7 +198,7 @@ describe('API token getTokenWithCache', () => {
|
|||||||
expect(apiTokenStoreGet).toHaveBeenCalledTimes(1);
|
expect(apiTokenStoreGet).toHaveBeenCalledTimes(1);
|
||||||
|
|
||||||
// after more than 5 minutes we should be able to query again
|
// after more than 5 minutes we should be able to query again
|
||||||
jest.advanceTimersByTime(minutesToMilliseconds(6));
|
vi.advanceTimersByTime(minutesToMilliseconds(6));
|
||||||
for (let i = 0; i < 5; i++) {
|
for (let i = 0; i < 5; i++) {
|
||||||
expect(
|
expect(
|
||||||
await apiTokenService.getTokenWithCache(invalidToken),
|
await apiTokenService.getTokenWithCache(invalidToken),
|
||||||
@ -209,7 +209,7 @@ describe('API token getTokenWithCache', () => {
|
|||||||
|
|
||||||
test('should not return the token if it has expired and shoud perform only one db query', async () => {
|
test('should not return the token if it has expired and shoud perform only one db query', async () => {
|
||||||
const { apiTokenService, apiTokenStore } = setup();
|
const { apiTokenService, apiTokenStore } = setup();
|
||||||
const apiTokenStoreGet = jest.spyOn(apiTokenStore, 'get');
|
const apiTokenStoreGet = vi.spyOn(apiTokenStore, 'get');
|
||||||
|
|
||||||
// valid token not present in cache but expired
|
// valid token not present in cache but expired
|
||||||
apiTokenStore.insert({ ...token, expiresAt: subDays(new Date(), 1) });
|
apiTokenStore.insert({ ...token, expiresAt: subDays(new Date(), 1) });
|
||||||
@ -234,7 +234,7 @@ test('normalizes api token type casing to lowercase', async () => {
|
|||||||
sortOrder: 1,
|
sortOrder: 1,
|
||||||
});
|
});
|
||||||
|
|
||||||
const apiTokenStoreInsert = jest.spyOn(apiTokenStore, 'insert');
|
const apiTokenStoreInsert = vi.spyOn(apiTokenStore, 'insert');
|
||||||
|
|
||||||
await apiTokenService.createApiTokenWithProjects(
|
await apiTokenService.createApiTokenWithProjects(
|
||||||
{
|
{
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { EmailService, type TransportProvider } from './email-service.js';
|
import { EmailService, type TransportProvider } from './email-service.js';
|
||||||
import noLoggerProvider from '../../test/fixtures/no-logger.js';
|
import noLoggerProvider from '../../test/fixtures/no-logger.js';
|
||||||
import type { IUnleashConfig } from '../types/index.js';
|
import type { IUnleashConfig } from '../types/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
test('Can send reset email', async () => {
|
test('Can send reset email', async () => {
|
||||||
const emailService = new EmailService({
|
const emailService = new EmailService({
|
||||||
@ -54,7 +54,7 @@ test('Can send welcome mail', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Can supply additional SMTP transport options', async () => {
|
test('Can supply additional SMTP transport options', async () => {
|
||||||
const transport = jest.fn() as unknown as TransportProvider;
|
const transport = vi.fn() as unknown as TransportProvider;
|
||||||
|
|
||||||
new EmailService(
|
new EmailService(
|
||||||
{
|
{
|
||||||
|
@ -6,7 +6,7 @@ import SettingService from './setting-service.js';
|
|||||||
import type EventService from '../features/events/event-service.js';
|
import type EventService from '../features/events/event-service.js';
|
||||||
import MaintenanceService from '../features/maintenance/maintenance-service.js';
|
import MaintenanceService from '../features/maintenance/maintenance-service.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
function ms(timeMs: number) {
|
function ms(timeMs: number) {
|
||||||
return new Promise((resolve) => setTimeout(resolve, timeMs));
|
return new Promise((resolve) => setTimeout(resolve, timeMs));
|
||||||
@ -51,7 +51,7 @@ beforeEach(() => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Schedules job immediately', async () => {
|
test('Schedules job immediately', async () => {
|
||||||
const job = jest.fn() as () => Promise<void> as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void> as () => Promise<void>;
|
||||||
await schedulerService.schedule(job, 10, 'test-id');
|
await schedulerService.schedule(job, 10, 'test-id');
|
||||||
|
|
||||||
expect(job).toHaveBeenCalledTimes(1);
|
expect(job).toHaveBeenCalledTimes(1);
|
||||||
@ -59,7 +59,7 @@ test('Schedules job immediately', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Can schedule a single regular job', async () => {
|
test('Can schedule a single regular job', async () => {
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
await schedulerService.schedule(job, 50, 'test-id-3');
|
await schedulerService.schedule(job, 50, 'test-id-3');
|
||||||
await ms(75);
|
await ms(75);
|
||||||
|
|
||||||
@ -68,8 +68,8 @@ test('Can schedule a single regular job', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Can schedule multiple jobs at the same interval', async () => {
|
test('Can schedule multiple jobs at the same interval', async () => {
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
const anotherJob = jest.fn() as () => Promise<void>;
|
const anotherJob = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 50, 'test-id-6');
|
await schedulerService.schedule(job, 50, 'test-id-6');
|
||||||
await schedulerService.schedule(anotherJob, 50, 'test-id-7');
|
await schedulerService.schedule(anotherJob, 50, 'test-id-7');
|
||||||
@ -81,8 +81,8 @@ test('Can schedule multiple jobs at the same interval', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Can schedule multiple jobs at the different intervals', async () => {
|
test('Can schedule multiple jobs at the different intervals', async () => {
|
||||||
const job = jest.fn() as () => Promise<void>;
|
const job = vi.fn() as () => Promise<void>;
|
||||||
const anotherJob = jest.fn() as () => Promise<void>;
|
const anotherJob = vi.fn() as () => Promise<void>;
|
||||||
|
|
||||||
await schedulerService.schedule(job, 100, 'test-id-8');
|
await schedulerService.schedule(job, 100, 'test-id-8');
|
||||||
await schedulerService.schedule(anotherJob, 200, 'test-id-9');
|
await schedulerService.schedule(anotherJob, 200, 'test-id-9');
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { tagSchema } from './tag-schema.js';
|
import { tagSchema } from './tag-schema.js';
|
||||||
|
import { test, expect } from 'vitest';
|
||||||
|
|
||||||
test('should require url friendly type if defined', () => {
|
test('should require url friendly type if defined', () => {
|
||||||
const tag = {
|
const tag = {
|
||||||
@ -8,7 +9,7 @@ test('should require url friendly type if defined', () => {
|
|||||||
|
|
||||||
const { error } = tagSchema.validate(tag);
|
const { error } = tagSchema.validate(tag);
|
||||||
if (error === undefined) {
|
if (error === undefined) {
|
||||||
fail('Did not receive an expected error');
|
expect.fail('Did not receive an expected error');
|
||||||
}
|
}
|
||||||
expect(error.details[0].message).toEqual('"type" must be URL friendly');
|
expect(error.details[0].message).toEqual('"type" must be URL friendly');
|
||||||
});
|
});
|
||||||
|
@ -15,8 +15,7 @@ import SettingService from './setting-service.js';
|
|||||||
import FakeSettingStore from '../../test/fixtures/fake-setting-store.js';
|
import FakeSettingStore from '../../test/fixtures/fake-setting-store.js';
|
||||||
import { extractAuditInfoFromUser } from '../util/index.js';
|
import { extractAuditInfoFromUser } from '../util/index.js';
|
||||||
import { createFakeEventsService } from '../features/index.js';
|
import { createFakeEventsService } from '../features/index.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi, expect, test, describe, beforeEach } from 'vitest';
|
||||||
|
|
||||||
const config: IUnleashConfig = createTestConfig();
|
const config: IUnleashConfig = createTestConfig();
|
||||||
|
|
||||||
const systemUser = new User({ id: -1, username: 'system' });
|
const systemUser = new User({ id: -1, username: 'system' });
|
||||||
@ -76,11 +75,10 @@ describe('Default admin initialization', () => {
|
|||||||
const CUSTOM_ADMIN_PASSWORD = 'custom-password';
|
const CUSTOM_ADMIN_PASSWORD = 'custom-password';
|
||||||
|
|
||||||
let userService: UserService;
|
let userService: UserService;
|
||||||
const sendGettingStartedMailMock =
|
const sendGettingStartedMailMock = vi.fn() as () => Promise<IEmailEnvelope>;
|
||||||
jest.fn() as () => Promise<IEmailEnvelope>;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
|
|
||||||
const userStore = new UserStoreMock();
|
const userStore = new UserStoreMock();
|
||||||
const accessService = new AccessServiceMock();
|
const accessService = new AccessServiceMock();
|
||||||
@ -91,7 +89,7 @@ describe('Default admin initialization', () => {
|
|||||||
);
|
);
|
||||||
const emailService = new EmailService(config);
|
const emailService = new EmailService(config);
|
||||||
|
|
||||||
emailService.configured = jest.fn(() => true);
|
emailService.configured = vi.fn(() => true);
|
||||||
emailService.sendGettingStartedMail = sendGettingStartedMailMock;
|
emailService.sendGettingStartedMail = sendGettingStartedMailMock;
|
||||||
|
|
||||||
const sessionStore = new FakeSessionStore();
|
const sessionStore = new FakeSessionStore();
|
||||||
@ -187,7 +185,7 @@ describe('Default admin initialization', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('Should use the correct environment variables when initializing the default admin account', async () => {
|
test('Should use the correct environment variables when initializing the default admin account', async () => {
|
||||||
jest.resetModules();
|
vi.resetModules();
|
||||||
|
|
||||||
process.env.UNLEASH_DEFAULT_ADMIN_USERNAME = CUSTOM_ADMIN_USERNAME;
|
process.env.UNLEASH_DEFAULT_ADMIN_USERNAME = CUSTOM_ADMIN_USERNAME;
|
||||||
process.env.UNLEASH_DEFAULT_ADMIN_PASSWORD = CUSTOM_ADMIN_PASSWORD;
|
process.env.UNLEASH_DEFAULT_ADMIN_PASSWORD = CUSTOM_ADMIN_PASSWORD;
|
||||||
@ -465,7 +463,7 @@ test('Should send password reset email if user exists', async () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const knownUser = service.createResetPasswordEmail('known@example.com');
|
const knownUser = service.createResetPasswordEmail('known@example.com');
|
||||||
expect(knownUser).resolves.toBeInstanceOf(URL);
|
await expect(knownUser).resolves.toBeInstanceOf(URL);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('Should throttle password reset email', async () => {
|
test('Should throttle password reset email', async () => {
|
||||||
@ -511,17 +509,17 @@ test('Should throttle password reset email', async () => {
|
|||||||
generateImageUrl: () => '',
|
generateImageUrl: () => '',
|
||||||
});
|
});
|
||||||
|
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
|
||||||
const attempt1 = service.createResetPasswordEmail('known@example.com');
|
const attempt1 = service.createResetPasswordEmail('known@example.com');
|
||||||
await expect(attempt1).resolves.toBeInstanceOf(URL);
|
await expect(attempt1).resolves.toBeInstanceOf(URL);
|
||||||
|
|
||||||
const attempt2 = service.createResetPasswordEmail('known@example.com');
|
const attempt2 = service.createResetPasswordEmail('known@example.com');
|
||||||
await expect(attempt2).rejects.toThrow(
|
await expect(attempt2).rejects.toThrowError(
|
||||||
'You can only send one new reset password email per minute, per user. Please try again later.',
|
'You can only send one new reset password email per minute, per user. Please try again later.',
|
||||||
);
|
);
|
||||||
|
|
||||||
jest.runAllTimers();
|
vi.runAllTimers();
|
||||||
|
|
||||||
const attempt3 = service.createResetPasswordEmail('known@example.com');
|
const attempt3 = service.createResetPasswordEmail('known@example.com');
|
||||||
await expect(attempt3).resolves.toBeInstanceOf(URL);
|
await expect(attempt3).resolves.toBeInstanceOf(URL);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import dbInit, { type ITestDb } from '../../test/e2e/helpers/database-init.js';
|
import dbInit, { type ITestDb } from '../../test/e2e/helpers/database-init.js';
|
||||||
import { SYSTEM_USER } from './core.js';
|
import { SYSTEM_USER } from './core.js';
|
||||||
import getLogger from '../../test/fixtures/no-logger.js';
|
import getLogger from '../../test/fixtures/no-logger.js';
|
||||||
import { jest } from '@jest/globals';
|
|
||||||
|
|
||||||
describe('System user definitions in code and db', () => {
|
describe('System user definitions in code and db', () => {
|
||||||
let dbDefinition: {
|
let dbDefinition: {
|
||||||
@ -13,7 +12,6 @@ describe('System user definitions in code and db', () => {
|
|||||||
};
|
};
|
||||||
let db: ITestDb;
|
let db: ITestDb;
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
jest.setTimeout(15000);
|
|
||||||
db = await dbInit('system_user_alignment_test', getLogger);
|
db = await dbInit('system_user_alignment_test', getLogger);
|
||||||
|
|
||||||
const query = await db.rawDatabase.raw(
|
const query = await db.rawDatabase.raw(
|
||||||
|
16
src/lib/types/openapi.d.ts
vendored
16
src/lib/types/openapi.d.ts
vendored
@ -1,16 +0,0 @@
|
|||||||
// Partial types for "@unleash/express-openapi".
|
|
||||||
declare module '@unleash/express-openapi' {
|
|
||||||
import type { RequestHandler } from 'express';
|
|
||||||
|
|
||||||
export interface IExpressOpenApi extends RequestHandler {
|
|
||||||
validPath: (operation: OpenAPIV3.OperationObject) => RequestHandler;
|
|
||||||
schema: (name: string, schema: OpenAPIV3.SchemaObject) => void;
|
|
||||||
swaggerui: RequestHandler;
|
|
||||||
}
|
|
||||||
|
|
||||||
export default function openapi(
|
|
||||||
docsPath: string,
|
|
||||||
document: Omit<OpenAPIV3.Document, 'paths'>,
|
|
||||||
options?: { coerce: boolean; extendRefs: boolean },
|
|
||||||
): IExpressOpenApi;
|
|
||||||
}
|
|
@ -1,18 +1,18 @@
|
|||||||
import { jest } from '@jest/globals';
|
import { type Mock, vi } from 'vitest';
|
||||||
import { batchExecute } from './batchExecute.js';
|
import { batchExecute } from './batchExecute.js';
|
||||||
|
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
|
|
||||||
describe('batchExecute', () => {
|
describe('batchExecute', () => {
|
||||||
let mockExecuteFn: jest.Mock;
|
let mockExecuteFn: Mock;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
mockExecuteFn = jest.fn();
|
mockExecuteFn = vi.fn();
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
jest.clearAllTimers();
|
vi.clearAllTimers();
|
||||||
jest.clearAllMocks();
|
vi.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should process each item in batches of the specified size', async () => {
|
it('should process each item in batches of the specified size', async () => {
|
||||||
@ -23,7 +23,7 @@ describe('batchExecute', () => {
|
|||||||
batchExecute(items, batchSize, delayMs, mockExecuteFn);
|
batchExecute(items, batchSize, delayMs, mockExecuteFn);
|
||||||
|
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
jest.advanceTimersByTime(delayMs);
|
vi.advanceTimersByTime(delayMs);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,11 +42,11 @@ describe('batchExecute', () => {
|
|||||||
|
|
||||||
expect(mockExecuteFn).toHaveBeenCalledTimes(5);
|
expect(mockExecuteFn).toHaveBeenCalledTimes(5);
|
||||||
|
|
||||||
jest.advanceTimersByTime(delayMs);
|
vi.advanceTimersByTime(delayMs);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
expect(mockExecuteFn).toHaveBeenCalledTimes(10);
|
expect(mockExecuteFn).toHaveBeenCalledTimes(10);
|
||||||
|
|
||||||
jest.advanceTimersByTime(delayMs);
|
vi.advanceTimersByTime(delayMs);
|
||||||
await Promise.resolve();
|
await Promise.resolve();
|
||||||
expect(mockExecuteFn).toHaveBeenCalledTimes(15);
|
expect(mockExecuteFn).toHaveBeenCalledTimes(15);
|
||||||
});
|
});
|
||||||
|
@ -9,6 +9,7 @@ function registerGracefulShutdown(unleash: IUnleash, logger: Logger): void {
|
|||||||
logger.info('Unleash has been successfully stopped.');
|
logger.info('Unleash has been successfully stopped.');
|
||||||
process.exit(0);
|
process.exit(0);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
console.log('Exiting with code 1');
|
||||||
logger.error('Unable to shutdown Unleash. Hard exit!');
|
logger.error('Unable to shutdown Unleash. Hard exit!');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
@ -3,7 +3,7 @@ import { createTestConfig } from '../../test/config/test-config.js';
|
|||||||
import { compareAndLogPostgresVersion } from './postgres-version-checker.js';
|
import { compareAndLogPostgresVersion } from './postgres-version-checker.js';
|
||||||
import FakeSettingStore from '../../test/fixtures/fake-setting-store.js';
|
import FakeSettingStore from '../../test/fixtures/fake-setting-store.js';
|
||||||
|
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
let config: IUnleashConfig;
|
let config: IUnleashConfig;
|
||||||
let settingStore: ISettingStore;
|
let settingStore: ISettingStore;
|
||||||
@ -12,7 +12,7 @@ let errorMessages: string[];
|
|||||||
|
|
||||||
const fakeSettingStore = (postgresVersion: string): ISettingStore => {
|
const fakeSettingStore = (postgresVersion: string): ISettingStore => {
|
||||||
const temp = new FakeSettingStore();
|
const temp = new FakeSettingStore();
|
||||||
jest.spyOn(temp, 'postgresVersion').mockResolvedValue(postgresVersion);
|
vi.spyOn(temp, 'postgresVersion').mockResolvedValue(postgresVersion);
|
||||||
return temp;
|
return temp;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import timer from './timer.js';
|
import timer from './timer.js';
|
||||||
import { jest } from '@jest/globals';
|
import { vi } from 'vitest';
|
||||||
|
|
||||||
function timeout(fn, ms): Promise<void> {
|
function timeout(fn, ms): Promise<void> {
|
||||||
return new Promise((resolve) =>
|
return new Promise((resolve) =>
|
||||||
@ -18,14 +18,14 @@ test('should calculate the correct time in seconds', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('timer should track the time', async () => {
|
test('timer should track the time', async () => {
|
||||||
jest.useFakeTimers();
|
vi.useFakeTimers();
|
||||||
const tt = timer.new();
|
const tt = timer.new();
|
||||||
let diff: number | undefined;
|
let diff: number | undefined;
|
||||||
timeout(() => {
|
timeout(() => {
|
||||||
diff = tt();
|
diff = tt();
|
||||||
}, 20);
|
}, 20);
|
||||||
jest.advanceTimersByTime(20);
|
vi.advanceTimersByTime(20);
|
||||||
expect(diff).toBeGreaterThan(0.0019);
|
expect(diff).toBeGreaterThan(0.0019);
|
||||||
expect(diff).toBeLessThan(0.05);
|
expect(diff).toBeLessThan(0.05);
|
||||||
jest.useRealTimers();
|
vi.useRealTimers();
|
||||||
});
|
});
|
||||||
|
@ -28,7 +28,6 @@ const initializeTemplateDb = (db: IUnleashConfig['db']): Promise<void> => {
|
|||||||
);
|
);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
result.rows.map((row) => {
|
result.rows.map((row) => {
|
||||||
console.log(`Dropping test database ${row.datname}`);
|
|
||||||
return client.query(`DROP DATABASE ${row.datname}`);
|
return client.query(`DROP DATABASE ${row.datname}`);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user