diff --git a/.github/workflows/integration_tests.yml b/.github/workflows/integration_tests.yml new file mode 100644 index 0000000..6ed6197 --- /dev/null +++ b/.github/workflows/integration_tests.yml @@ -0,0 +1,35 @@ +name: Planned integration tests + +on: + workflow_dispatch: + schedule: + - cron: '0 3 * * *' + +jobs: + tests: + runs-on: macos-latest + + steps: + - uses: actions/checkout@v2 + - name: Set Aegis url + run: | + fastlane setAegisUrl url:${{ secrets.AEGIS_URL }} + + - name: Use Node.js + uses: actions/setup-node@v1 + with: + node-version: '20.x' + + - name: Cache NPM # leverage npm cache on repeated workflow runs if package.json didn't change + uses: actions/cache@v1 + with: + path: ~/.npm + key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-node- + - name: Install Dependencies + run: yarn + + - name: Tests + run: | + yarn integrationTests diff --git a/.github/workflows/pr-checks.yml b/.github/workflows/pr-checks.yml index 9aecc96..37bc17c 100644 --- a/.github/workflows/pr-checks.yml +++ b/.github/workflows/pr-checks.yml @@ -17,7 +17,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '12.x' + node-version: '20.x' - name: Cache NPM # leverage npm cache on repeated workflow runs if package.json didn't change uses: actions/cache@v1 @@ -44,7 +44,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '12.x' + node-version: '20.x' - name: Cache NPM # leverage npm cache on repeated workflow runs if package.json didn't change uses: actions/cache@v1 @@ -71,7 +71,7 @@ jobs: - name: Use Node.js uses: actions/setup-node@v1 with: - node-version: '12.x' + node-version: '20.x' - name: Cache NPM uses: actions/cache@v1 @@ -84,4 +84,4 @@ jobs: run: yarn - name: Run tests - run: yarn test \ No newline at end of file + run: yarn test diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index ad4f8a5..618face 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -20,7 +20,7 @@ jobs: - name: Setup node for publishing uses: actions/setup-node@v3 with: - node-version: '16.x' + node-version: '20.x' registry-url: 'https://registry.npmjs.org' - name: Publish to npm diff --git a/fastlane/Fastfile b/fastlane/Fastfile index 27b42e7..19ecd28 100644 --- a/fastlane/Fastfile +++ b/fastlane/Fastfile @@ -23,6 +23,13 @@ def update_package_json(new_version) update_file(path, regex, result_value) end +def update_aegis_url_in_tests(url) + path = Dir['../**/__integrationTests__/constants.ts'].first + regex = /\/ + + update_file(path, regex, url) +end + def update_file(path, regex, result_value) file = File.read(path) new_content = file.gsub(regex, result_value) @@ -35,4 +42,10 @@ platform :mac do update_package_json(new_version) end -end \ No newline at end of file + + lane :setAegisUrl do |options| + path = options[:url] + + update_aegis_url_in_tests(path) + end +end diff --git a/fastlane/README.md b/fastlane/README.md index 1f14c3a..50acaae 100644 --- a/fastlane/README.md +++ b/fastlane/README.md @@ -23,6 +23,14 @@ For _fastlane_ installation instructions, see [Installing _fastlane_](https://do +### mac setAegisUrl + +```sh +[bundle exec] fastlane mac setAegisUrl +``` + + + ---- This README.md is auto-generated and will be re-generated every time [_fastlane_](https://fastlane.tools) is run. diff --git a/fastlane/report.xml b/fastlane/report.xml index 9661a52..0c291f4 100644 --- a/fastlane/report.xml +++ b/fastlane/report.xml @@ -5,7 +5,7 @@ - + diff --git a/package.json b/package.json index 17b9d80..0a1d466 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@qonversion/web-sdk", "title": "Qonversion Web SDK", - "version": "0.2.1", + "version": "0.2.2", "description": "Qonversion provides full in-app purchases infrastructure, so you do not need to build your own server for receipt validation. Implement in-app subscriptions, validate user receipts, check subscription status, and provide access to your app features and content using our Stripe wrapper, StoreKit wrapper and Google Play Billing wrapper.", "main": "sdk/build/index.js", "types": "sdk/build/index.d.ts", @@ -10,7 +10,8 @@ ], "scripts": { "build": "yarn tsc", - "test": "jest", + "test": "jest ./sdk/src/__tests__", + "integrationTests": "jest ./sdk/src/__integrationTests__", "lint": "eslint . --max-warnings=0" }, "repository": { @@ -38,13 +39,14 @@ "@babel/core": "^7.18.2", "@babel/preset-env": "^7.18.2", "@babel/preset-typescript": "^7.17.12", - "@types/jest": "^27.5.1", + "@types/jest": "^29.4.0", "@typescript-eslint/eslint-plugin": "^5.28.0", "@typescript-eslint/parser": "^5.28.0", "babel-jest": "^28.1.0", "eslint": "^8.17.0", "eslint-config-prettier": "^8.5.0", - "jest": "^28.1.0", + "jest": "^29.4.2", + "ts-jest": "^29.1.0", "typescript": "^4.7.3" }, "dependencies": { diff --git a/sdk/src/QonversionConfigBuilder.ts b/sdk/src/QonversionConfigBuilder.ts index b392835..d009102 100644 --- a/sdk/src/QonversionConfigBuilder.ts +++ b/sdk/src/QonversionConfigBuilder.ts @@ -3,6 +3,7 @@ import {QonversionErrorCode} from './exception/QonversionErrorCode'; import {Environment} from './dto/Environment'; import {LogLevel} from './dto/LogLevel'; import {LoggerConfig, NetworkConfig, PrimaryConfig, QonversionConfig} from './types'; +import {API_URL} from './internal/network'; // eslint-disable-next-line @typescript-eslint/no-var-requires const packageJson = require('../../package.json'); @@ -88,6 +89,7 @@ export class QonversionConfigBuilder { const networkConfig: NetworkConfig = { canSendRequests: true, + apiUrl: API_URL, }; return { @@ -95,5 +97,5 @@ export class QonversionConfigBuilder { loggerConfig, networkConfig, }; - } + }; } diff --git a/sdk/src/__integrationTests__/apiV3/EntitlementsService.test.ts b/sdk/src/__integrationTests__/apiV3/EntitlementsService.test.ts new file mode 100644 index 0000000..45192ab --- /dev/null +++ b/sdk/src/__integrationTests__/apiV3/EntitlementsService.test.ts @@ -0,0 +1,63 @@ +import {PRIVATE_TOKEN_FOR_TESTS} from '../constants'; +import {executeGrantEntitlementsRequest} from '../apiV3Utils'; +import {expectQonversionErrorAsync, getCurrentTs, getDependencyAssembly} from '../utils'; +import {QonversionErrorCode} from '../../exception/QonversionErrorCode'; +import {API_URL} from '../../internal/network'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('entitlements tests', function () { + const dependenciesAssembly = getDependencyAssembly(); + + const userService = dependenciesAssembly.userService(); + const entitlementsService = dependenciesAssembly.entitlementsService(); + + describe('GET entitlements', function () { + it('get entitlements for new user', async () => { + // given + const userId = 'testEntitlementUserId' + Date.now(); + await userService.createUser(userId); + + // when + const res = await entitlementsService.getEntitlements(userId); + + // then + expect(res).toEqual([]); + }); + + it('get entitlements for user with entitlements', async () => { + // given + const userId = 'testEntitlementUserId' + Date.now(); + await userService.createUser(userId); + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + const entitlementResponse = await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const entitlement = await entitlementResponse.json(); + + // when + const res = await entitlementsService.getEntitlements(userId); + + // then + expect(res).toEqual([entitlement]); + }); + + it('get entitlements for non-existent user', async () => { + // given + const userId = 'testNonExistentUserId' + Date.now(); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.UserNotFound, + 'Qonversion user not found. User id: ' + userId, + async () => { + await entitlementsService.getEntitlements(userId); + }, + ); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/apiV3/IdentityService.test.ts b/sdk/src/__integrationTests__/apiV3/IdentityService.test.ts new file mode 100644 index 0000000..d6f60f7 --- /dev/null +++ b/sdk/src/__integrationTests__/apiV3/IdentityService.test.ts @@ -0,0 +1,130 @@ +import {expectQonversionErrorAsync, getDependencyAssembly} from '../utils'; +import {QonversionErrorCode} from '../../exception/QonversionErrorCode'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('identities tests', function () { + const dependenciesAssembly = getDependencyAssembly(); + + const userService = dependenciesAssembly.userService(); + const identityService = dependenciesAssembly.identityService(); + + describe('POST identities', function () { + it('create correct identity', async () => { + // given + const identityId = 'testCorrectIdentity' + Date.now(); + const userId = 'testCorrectIdentityUid' + Date.now(); + await userService.createUser(userId); + + // when + const res = await identityService.createIdentity(userId, identityId); + + // then + expect(res).toEqual(userId); + }); + + it('create same identity above existing', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const userId = 'testCorrectIdentityUid' + Date.now(); + await userService.createUser(userId); + await identityService.createIdentity(userId, identityId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: user already has identity', + async () => { + await identityService.createIdentity(userId, identityId); + }, + ); + }); + + it('create different identity above existing', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const userId = 'testCorrectIdentityUid' + Date.now(); + await userService.createUser(userId); + await identityService.createIdentity(userId, identityId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: user already converted', + async () => { + await identityService.createIdentity(userId, identityId + 'another'); + }, + ); + }); + + it('create identity which was already used for another user', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const identifierUserId = 'testIdentifiedUid' + Date.now(); + await userService.createUser(identifierUserId); + await identityService.createIdentity(identifierUserId, identityId); + + const nonIdentifierUserId = 'testNonIdentifiedUid' + Date.now(); + await userService.createUser(nonIdentifierUserId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: identity already exists: it\'s linked to another user', + async () => { + await identityService.createIdentity(nonIdentifierUserId, identityId); + }, + ); + }); + + it('create identity for non-existent user', async () => { + // given + const identityId = 'testIdentityForNonExistentUser' + Date.now(); + const nonExistentUserId = 'testNonExistentUid' + Date.now(); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 400, message: user not found', + async () => { + await identityService.createIdentity(nonExistentUserId, identityId); + }, + ); + }); + }); + + describe('GET identities', function () { + it('get existing identity', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const userId = 'testExistingUid' + Date.now(); + await userService.createUser(userId); + await identityService.createIdentity(userId, identityId); + + // when + const res = await identityService.obtainIdentity(identityId); + + // then + expect(res).toEqual(userId); + }); + + it('get non-existent identity', async () => { + // given + const identityId = 'testNonExistentIdentity' + Date.now(); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.IdentityNotFound, + 'User with requested identity not found. Id: ' + identityId, + async () => { + await identityService.obtainIdentity(identityId); + }, + ); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/apiV3/PurchasesService.test.ts b/sdk/src/__integrationTests__/apiV3/PurchasesService.test.ts new file mode 100644 index 0000000..6631da8 --- /dev/null +++ b/sdk/src/__integrationTests__/apiV3/PurchasesService.test.ts @@ -0,0 +1,202 @@ +import {PurchaseCoreData, StripeStoreData, UserPurchase} from '../../dto/Purchase'; +import {expectQonversionErrorAsync, getCurrentTs, getDependencyAssembly} from '../utils'; +import {QonversionErrorCode} from '../../exception/QonversionErrorCode'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('purchases tests', function () { + const dependenciesAssembly = getDependencyAssembly(); + + const userService = dependenciesAssembly.userService(); + const purchasesService = dependenciesAssembly.purchasesService(); + + describe('POST purchases', () => { + it('create correct purchase', async () => { + // given + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchased = getCurrentTs(); + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + purchased, + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + stripeStoreData, + purchased: Math.floor(purchased / 1000) * 1000, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase without purchase time', async () => { + // given + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + stripeStoreData, + purchased: 0, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase for non-existing user', async () => { + const userId = 'testUidForPurchase' + Date.now(); + + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + purchased: getCurrentTs(), + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.UserNotFound, + 'Qonversion user not found. Id: ' + userId, + async () => { + await purchasesService.sendStripePurchase(userId, data); + }, + ); + }); + + it('create purchase with incorrect subscription id', async () => { + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + purchased: getCurrentTs(), + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'incorrect subscription id' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: Couldn\'t validate purchase with store request, potential fraud', + async () => { + await purchasesService.sendStripePurchase(userId, data); + }, + ); + }); + + it('create purchase with incorrect amount', async () => { + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21,49', + purchased: getCurrentTs(), + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 400, message: failed to parse price', + async () => { + await purchasesService.sendStripePurchase(userId, data); + }, + ); + }); + + it('create purchase with incorrect currency', async () => { + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchaseCoreData: PurchaseCoreData = { + currency: 'USDDD', + price: '21.49', + purchased: getCurrentTs(), + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 400, message: failed to recognize currency', + async () => { + await purchasesService.sendStripePurchase(userId, data); + }, + ); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/apiV3/UserService.test.ts b/sdk/src/__integrationTests__/apiV3/UserService.test.ts new file mode 100644 index 0000000..e4b02ea --- /dev/null +++ b/sdk/src/__integrationTests__/apiV3/UserService.test.ts @@ -0,0 +1,112 @@ +import {User} from '../../dto/User'; +import {Environment} from '../../dto/Environment'; +import {expectQonversionErrorAsync, getCurrentTs, getDependencyAssembly} from '../utils'; +import {QonversionErrorCode} from '../../exception/QonversionErrorCode'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('users tests', function () { + const dependenciesAssembly = getDependencyAssembly(); + + const userService = dependenciesAssembly.userService(); + + describe('POST users', function () { + it('create production user', async () => { + // given + const testsStartTs = getCurrentTs(); + const testUserId = 'testProd' + testsStartTs; + const expectedUser: User = { + created: 0, + environment: Environment.Production, + id: testUserId, + identityId: undefined, + }; + + // when + const res = await userService.createUser(testUserId); + const requestEndTs = getCurrentTs(); + + // then + expect(res.created).toBeGreaterThanOrEqual(testsStartTs); + expect(res.created).toBeLessThanOrEqual(requestEndTs); + expectedUser.created = res.created; + expect(res).toEqual(expectedUser); + }); + + it('create existing user', async () => { + // given + const testsStartTs = getCurrentTs(); + const testUserId = 'testExistingUser' + testsStartTs; + await userService.createUser(testUserId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: User with given uid already exists', + async () => { + await userService.createUser(testUserId); + }, + ); + }); + + it('create sandbox user', async () => { + // given + const dependenciesAssembly = getDependencyAssembly({environment: Environment.Sandbox}); + + const userService = dependenciesAssembly.userService(); + + const testsStartTs = getCurrentTs(); + + const testUserId = 'testSandbox' + testsStartTs; + const expectedUser: User = { + created: 0, + environment: Environment.Sandbox, + id: testUserId, + identityId: undefined, + }; + + // when + const res = await userService.createUser(testUserId); + const requestEndTs = getCurrentTs(); + + // then + expect(res.created).toBeGreaterThanOrEqual(testsStartTs); + expect(res.created).toBeLessThanOrEqual(requestEndTs); + expectedUser.created = res.created; + expect(res).toEqual(expectedUser); + }); + }); + + describe('GET users', function () { + it('get existing user', async () => { + // given + const testUserId = 'testGet' + Date.now(); + const expUser = await userService.createUser(testUserId); + + // when + const res = await userService.getUser(testUserId); + + // then + expect(res).toEqual(expUser); + }); + + it('get non-existent user', async () => { + // given + const nonExistentUserId = 'testNonExistent' + Date.now(); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.UserNotFound, + 'Qonversion user not found. Id: ' + nonExistentUserId, + async () => { + await userService.getUser(nonExistentUserId); + }, + ); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/apiV3/directApi.test.ts b/sdk/src/__integrationTests__/apiV3/directApi.test.ts new file mode 100644 index 0000000..0556557 --- /dev/null +++ b/sdk/src/__integrationTests__/apiV3/directApi.test.ts @@ -0,0 +1,269 @@ +import {PRIVATE_TOKEN_FOR_TESTS, PROJECT_KEY_FOR_TESTS} from '../constants'; +import {getCurrentTs, getDependencyAssembly} from '../utils'; +import {executeGrantEntitlementsRequest, executeRevokeEntitlementsRequest} from '../apiV3Utils'; +import {Entitlement, EntitlementSource} from '../../dto/Entitlement'; +import {API_URL} from '../../internal/network'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('Direct API tests', function () { + const dependenciesAssembly = getDependencyAssembly(); + const userService = dependenciesAssembly.userService(); + + describe('Grant entitlements', function () { + it('grant entitlement', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + + const expRes: Entitlement = { + active: true, + expires, + id: entitlementId, + source: EntitlementSource.Manual, + started: 0, + }; + const requestStartTs = getCurrentTs(); + + // when + const response = await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const requestEndTs = getCurrentTs(); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(200); + expect(responseBody.started).toBeGreaterThanOrEqual(requestStartTs); + expect(responseBody.started).toBeLessThanOrEqual(requestEndTs); + expRes.started = responseBody.started; + expect(responseBody).toEqual(expRes); + }); + + it('grant entitlement twice', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expiresOld = getCurrentTs() + 1000; + await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expiresOld); + + const expiresNew = getCurrentTs() + 10000; + const expRes: Entitlement = { + active: true, + expires: expiresOld, + id: entitlementId, + source: EntitlementSource.Manual, + started: 0, + }; + const requestStartTs = getCurrentTs(); + + // when + const response = await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expiresNew); + const requestEndTs = getCurrentTs(); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(200); + expect(responseBody.started).toBeGreaterThanOrEqual(requestStartTs); + expect(responseBody.started).toBeLessThanOrEqual(requestEndTs); + expRes.started = responseBody.started; + expect(responseBody).toEqual(expRes); + }); + + it('grant entitlement with wrong expires', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() - 10000; + + const expError = { + code: 'invalid_entitlement_data', + message: 'Invalid expires at value has been provided, should be in unix timestamp format in seconds in future', + type: 'request', + }; + + // when + const response = await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('grant entitlement with wrong token', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + + const expError = { + code: 'control_unauthorized', + message: 'Authorization error: project not found', + type: 'request', + }; + + // when + const response = await executeGrantEntitlementsRequest(API_URL, PROJECT_KEY_FOR_TESTS, userId, entitlementId, expires); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(401); + expect(responseBody.error).toEqual(expError); + }); + + it('grant entitlement with wrong id', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Non existent entitlement'; + const expires = getCurrentTs() + 10000; + + const expError = { + code: 'invalid_entitlement_data', + message: 'Invalid entitlement uid, no such entitlement found', + type: 'request', + }; + + // when + const response = await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('grant entitlement for non-existent user', async () => { + // given + const userId = 'testNonExistentUid' + Date.now(); + + const entitlementId = 'Non existent entitlement'; + const expires = getCurrentTs() + 10000; + + const expError = { + code: 'not_found', + message: 'User not found', + type: 'resource', + }; + + // when + const response = await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(404); + expect(responseBody.error).toEqual(expError); + }); + }); + + describe('Revoke entitlements', function () { + it('revoke existing entitlement', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + await executeGrantEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + + // when + const response = await executeRevokeEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + + // then + expect(response.status).toBe(200); + }); + + it('revoke non-existent entitlement', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + + // when + const response = await executeRevokeEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + + // then + expect(response.status).toBe(200); + }); + + it('revoke entitlement with non-existent id', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Non-existent entitlement id'; + + const expError = { + code: 'invalid_entitlement_data', + message: 'Invalid entitlement uid, no such entitlement found', + type: 'request', + }; + + // when + const response = await executeRevokeEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('revoke entitlement with wrong token', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + + const expError = { + code: 'control_unauthorized', + message: 'Authorization error: project not found', + type: 'request', + }; + + // when + const response = await executeRevokeEntitlementsRequest(API_URL, PROJECT_KEY_FOR_TESTS, userId, entitlementId); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(401); + expect(responseBody.error).toEqual(expError); + }); + + it('revoke entitlement for non-existent user', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + + const entitlementId = 'Test Permission'; + + const expError = { + code: 'not_found', + message: 'User not found', + type: 'resource', + }; + + // when + const response = await executeRevokeEntitlementsRequest(API_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(404); + expect(responseBody.error).toEqual(expError); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/apiV3Utils.ts b/sdk/src/__integrationTests__/apiV3Utils.ts new file mode 100644 index 0000000..13041e6 --- /dev/null +++ b/sdk/src/__integrationTests__/apiV3Utils.ts @@ -0,0 +1,38 @@ +import {ApiHeader} from '../internal/network'; + +export const executeGrantEntitlementsRequest = async ( + apiUrl: string, + accessToken: string, + userId: string, + entitlementId: string, + expires: number, +): Promise => { + return await fetch(encodeURI(`${apiUrl}/v3/users/${userId}/entitlements`), { + method: 'POST', + headers: { + [ApiHeader.Authorization]: 'Bearer ' + accessToken, + [ApiHeader.ContentType]: 'application/json', + [ApiHeader.Accept]: 'application/json', + }, + body: JSON.stringify({ + id: entitlementId, + expires, + }), + }); +}; + +export const executeRevokeEntitlementsRequest = async ( + apiUrl: string, + accessToken: string, + userId: string, + entitlementId: string, +): Promise => { + return await fetch(encodeURI(`${apiUrl}/v3/users/${userId}/entitlements/${entitlementId}`), { + method: 'DELETE', + headers: { + [ApiHeader.Authorization]: 'Bearer ' + accessToken, + [ApiHeader.ContentType]: 'application/json', + [ApiHeader.Accept]: 'application/json', + }, + }); +}; diff --git a/sdk/src/__integrationTests__/constants.ts b/sdk/src/__integrationTests__/constants.ts new file mode 100644 index 0000000..3195efc --- /dev/null +++ b/sdk/src/__integrationTests__/constants.ts @@ -0,0 +1,3 @@ +export const AEGIS_URL = ''; +export const PROJECT_KEY_FOR_TESTS = 'PV77YHL7qnGvsdmpTs7gimsxUvY-Znl2'; +export const PRIVATE_TOKEN_FOR_TESTS = 'sk_i_NNcYMRMkFxP_JIZ-igLUGi09U2itva'; diff --git a/sdk/src/__integrationTests__/eagis/EntitlementsService.test.ts b/sdk/src/__integrationTests__/eagis/EntitlementsService.test.ts new file mode 100644 index 0000000..0af48e9 --- /dev/null +++ b/sdk/src/__integrationTests__/eagis/EntitlementsService.test.ts @@ -0,0 +1,58 @@ +import {AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS} from '../constants'; +import {executeGrantEntitlementsRequest} from '../apiV3Utils'; +import {getCurrentTs, getDependencyAssembly} from '../utils'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('entitlements tests', function () { + const dependenciesAssembly = getDependencyAssembly({apiUrl: AEGIS_URL}); + + const userService = dependenciesAssembly.userService(); + const entitlementsService = dependenciesAssembly.entitlementsService(); + + describe('GET entitlements', function () { + it('get entitlements for new user', async () => { + // given + const userId = 'testEntitlementUserId' + Date.now(); + await userService.createUser(userId); + + // when + const res = await entitlementsService.getEntitlements(userId); + + // then + expect(res).toEqual([]); + }); + + it('get entitlements for user with entitlements', async () => { + // given + const userId = 'testEntitlementUserId' + Date.now(); + await userService.createUser(userId); + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + const entitlementResponse = await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const entitlement = await entitlementResponse.json(); + + // when + const res = await entitlementsService.getEntitlements(userId); + + // then + expect(res).toEqual([entitlement]); + }); + + it('get entitlements for non-existent user', async () => { + // given + const userId = 'testNonExistentUserId' + Date.now(); + + // when + const res = await entitlementsService.getEntitlements(userId); + + // then + expect(res).toEqual([]); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/eagis/IdentityService.test.ts b/sdk/src/__integrationTests__/eagis/IdentityService.test.ts new file mode 100644 index 0000000..75dac38 --- /dev/null +++ b/sdk/src/__integrationTests__/eagis/IdentityService.test.ts @@ -0,0 +1,128 @@ +import {expectQonversionErrorAsync, getDependencyAssembly} from '../utils'; +import {QonversionErrorCode} from '../../exception/QonversionErrorCode'; +import {AEGIS_URL} from '../constants'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('identities tests', function () { + const dependenciesAssembly = getDependencyAssembly({apiUrl: AEGIS_URL}); + + const userService = dependenciesAssembly.userService(); + const identityService = dependenciesAssembly.identityService(); + + describe('POST identities', function () { + it('create correct identity', async () => { + // given + const identityId = 'testCorrectIdentity' + Date.now(); + const userId = 'testCorrectIdentityUid' + Date.now(); + await userService.createUser(userId); + + // when + const res = await identityService.createIdentity(userId, identityId); + + // then + expect(res).toEqual(userId); + }); + + it('create same identity above existing', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const userId = 'testCorrectIdentityUid' + Date.now(); + await userService.createUser(userId); + await identityService.createIdentity(userId, identityId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: identity already exists: user already converted', + async () => { + await identityService.createIdentity(userId, identityId); + }, + ); + }); + + it('create different identity above existing', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const userId = 'testCorrectIdentityUid' + Date.now(); + await userService.createUser(userId); + await identityService.createIdentity(userId, identityId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: identity for provided user id already exists', + async () => { + await identityService.createIdentity(userId, identityId + 'another'); + }, + ); + }); + + it('create identity which was already used for another user', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const identifierUserId = 'testIdentifiedUid' + Date.now(); + await userService.createUser(identifierUserId); + await identityService.createIdentity(identifierUserId, identityId); + + const nonIdentifierUserId = 'testNonIdentifiedUid' + Date.now(); + await userService.createUser(nonIdentifierUserId); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.BackendError, + 'Qonversion API returned an error. Response code 422, message: identity already exists: it\'s linked to another user', + async () => { + await identityService.createIdentity(nonIdentifierUserId, identityId); + }, + ); + }); + + it('create identity for non-existent user', async () => { + // given + const identityId = 'testIdentityForNonExistentUser' + Date.now(); + const nonExistentUserId = 'testNonExistentUid' + Date.now(); + + // when + const res = await identityService.createIdentity(nonExistentUserId, identityId); + + // then + expect(res).toEqual(nonExistentUserId); + }); + }); + + describe('GET identities', function () { + it('get existing identity', async () => { + // given + const identityId = 'testExistingIdentity' + Date.now(); + const userId = 'testExistingUid' + Date.now(); + await userService.createUser(userId); + await identityService.createIdentity(userId, identityId); + + // when + const res = await identityService.obtainIdentity(identityId); + + // then + expect(res).toEqual(userId); + }); + + it('get non-existent identity', async () => { + // given + const identityId = 'testNonExistentIdentity' + Date.now(); + + // when and then + await expectQonversionErrorAsync( + QonversionErrorCode.IdentityNotFound, + 'User with requested identity not found. Id: ' + identityId, + async () => { + await identityService.obtainIdentity(identityId); + }, + ); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/eagis/PurchasesService.test.ts b/sdk/src/__integrationTests__/eagis/PurchasesService.test.ts new file mode 100644 index 0000000..083990c --- /dev/null +++ b/sdk/src/__integrationTests__/eagis/PurchasesService.test.ts @@ -0,0 +1,222 @@ +import {PurchaseCoreData, StripeStoreData, UserPurchase} from '../../dto/Purchase'; +import {getCurrentTs, getDependencyAssembly} from '../utils'; +import {AEGIS_URL} from '../constants'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('purchases tests', function () { + const dependenciesAssembly = getDependencyAssembly({apiUrl: AEGIS_URL}); + + const userService = dependenciesAssembly.userService(); + const purchasesService = dependenciesAssembly.purchasesService(); + + describe('POST purchases', () => { + it('create correct purchase', async () => { + // given + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchased = getCurrentTs(); + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + purchased, + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + purchased, + stripeStoreData, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase without purchase time', async () => { + // given + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + stripeStoreData, + purchased: 0, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase for non-existing user', async () => { + const userId = 'testUidForPurchase' + Date.now(); + + const purchased = getCurrentTs(); + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + purchased, + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + purchased, + stripeStoreData, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase with incorrect subscription id', async () => { + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchased = getCurrentTs(); + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21.49', + purchased, + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'incorrect subscription id' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + purchased, + stripeStoreData, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase with incorrect amount', async () => { + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchased = getCurrentTs(); + const purchaseCoreData: PurchaseCoreData = { + currency: 'USD', + price: '21,49', + purchased, + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + purchased, + stripeStoreData, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + + it('create purchase with incorrect currency', async () => { + const userId = 'testUidForPurchase' + Date.now(); + await userService.createUser(userId); + + const purchased = getCurrentTs(); + const purchaseCoreData: PurchaseCoreData = { + currency: 'USDDD', + price: '21.49', + purchased, + }; + const stripeStoreData: StripeStoreData = { + productId: 'prod_LkgDHk3f9Z9qb3', + subscriptionId: 'sub_1N6Z7sL9K6ILzohYE49VAPcq' + }; + + const data = { + ...purchaseCoreData, + ...stripeStoreData, + }; + + const expRes: UserPurchase = { + ...purchaseCoreData, + purchased, + stripeStoreData, + userId, + }; + + // when + const res = await purchasesService.sendStripePurchase(userId, data); + + // then + expect(res).toEqual(expRes); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/eagis/UserService.test.ts b/sdk/src/__integrationTests__/eagis/UserService.test.ts new file mode 100644 index 0000000..7bea14d --- /dev/null +++ b/sdk/src/__integrationTests__/eagis/UserService.test.ts @@ -0,0 +1,109 @@ +import {User} from '../../dto/User'; +import {Environment} from '../../dto/Environment'; +import {getDependencyAssembly} from '../utils'; +import {AEGIS_URL} from '../constants'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('users tests', function () { + const dependenciesAssembly = getDependencyAssembly({apiUrl: AEGIS_URL}); + + const userService = dependenciesAssembly.userService(); + + describe('POST users', function () { + it('create production user', async () => { + // given + const testUserId = 'testProd' + Date.now(); + const expectedUser: User = { + created: 0, + environment: Environment.Production, + id: testUserId, + identityId: undefined, + }; + + // when + const res = await userService.createUser(testUserId); + + // then + expect(res).toEqual(expectedUser); + }); + + it('create existing user', async () => { + // given + const testUserId = 'testExistingUser' + Date.now(); + await userService.createUser(testUserId); + const expectedUser: User = { + created: 0, + environment: Environment.Production, + id: testUserId, + identityId: undefined, + }; + + // when + const res = await userService.createUser(testUserId); + + // then + expect(res).toEqual(expectedUser); + }); + + it('create sandbox user', async () => { + // given + const dependenciesAssembly = getDependencyAssembly({ + environment: Environment.Sandbox, + apiUrl: AEGIS_URL, + }); + + const userService = dependenciesAssembly.userService(); + + const testUserId = 'testSandbox' + Date.now(); + const expectedUser: User = { + created: 0, + environment: Environment.Sandbox, + id: testUserId, + identityId: undefined, + }; + + // when + const res = await userService.createUser(testUserId); + + // then + expect(res).toEqual(expectedUser); + }); + }); + + describe('GET users', function () { + it('get existing user', async () => { + // given + const testUserId = 'testGet' + Date.now(); + const expUser = await userService.createUser(testUserId); + + // when + const res = await userService.getUser(testUserId); + + // then + expect(res).toEqual(expUser); + }); + + it('get non-existent user', async () => { + // given + const nonExistentUserId = 'testNonExistent' + Date.now(); + const expectedUser: User = { + created: 0, + environment: Environment.Production, + id: nonExistentUserId, + identityId: undefined, + }; + + // when + const res = await userService.getUser(nonExistentUserId); + + // then + expect(res).toEqual(expectedUser); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/eagis/directApi.test.ts b/sdk/src/__integrationTests__/eagis/directApi.test.ts new file mode 100644 index 0000000..e698d23 --- /dev/null +++ b/sdk/src/__integrationTests__/eagis/directApi.test.ts @@ -0,0 +1,238 @@ +import {AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, PROJECT_KEY_FOR_TESTS} from '../constants'; +import {getCurrentTs, getDependencyAssembly} from '../utils'; +import {executeGrantEntitlementsRequest, executeRevokeEntitlementsRequest} from '../apiV3Utils'; +import {Entitlement, EntitlementSource} from '../../dto/Entitlement'; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +// noinspection JSConstantReassignment +global.localStorage = { + getItem: jest.fn(), +}; + +describe('Direct API tests', function () { + const dependenciesAssembly = getDependencyAssembly({apiUrl: AEGIS_URL}); + const userService = dependenciesAssembly.userService(); + + describe('Grant entitlements', function () { + it('grant entitlement', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + + const expRes: Entitlement = { + active: true, + expires, + id: entitlementId, + source: EntitlementSource.Manual, + started: 0, + }; + const requestStartTs = getCurrentTs(); + + // when + const response = await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const requestEndTs = getCurrentTs(); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(200); + expect(responseBody.started).toBeGreaterThanOrEqual(requestStartTs); + expect(responseBody.started).toBeLessThanOrEqual(requestEndTs); + expRes.started = responseBody.started; + expect(responseBody).toEqual(expRes); + }); + + it('grant entitlement twice', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expiresOld = getCurrentTs() + 1000; + await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expiresOld); + + const expiresNew = getCurrentTs() + 10000; + const expRes: Entitlement = { + active: true, + expires: expiresNew, + id: entitlementId, + source: EntitlementSource.Manual, + started: 0, + }; + const requestStartTs = getCurrentTs(); + + // when + const response = await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expiresNew); + const requestEndTs = getCurrentTs(); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(200); + expect(responseBody.started).toBeGreaterThanOrEqual(requestStartTs); + expect(responseBody.started).toBeLessThanOrEqual(requestEndTs); + expRes.started = responseBody.started; + expect(responseBody).toEqual(expRes); + }); + + it('grant entitlement with wrong expires', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() - 10000; + + const expError = { + code: 'invalid_entitlement_data', + message: 'Invalid expires at value has been provided, should be in unix timestamp format in seconds in future', + type: 'request', + }; + + // when + const response = await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('grant entitlement with wrong token', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + + const expError = { + code: 'control_unauthorized', + message: 'Authorization error: project not found', + type: 'request', + }; + + // when + const response = await executeGrantEntitlementsRequest(AEGIS_URL, PROJECT_KEY_FOR_TESTS, userId, entitlementId, expires); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('grant entitlement for non-existent user', async () => { + // given + const userId = 'testNonExistentUid' + Date.now(); + + const entitlementId = 'Non existent entitlement'; + const expires = getCurrentTs() + 10000; + + const expRes: Entitlement = { + active: true, + expires, + id: entitlementId, + source: EntitlementSource.Manual, + started: 0, + }; + const requestStartTs = getCurrentTs(); + + // when + const response = await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + const requestEndTs = getCurrentTs(); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(200); + expect(responseBody.started).toBeGreaterThanOrEqual(requestStartTs); + expect(responseBody.started).toBeLessThanOrEqual(requestEndTs); + expRes.started = responseBody.started; + expect(responseBody).toEqual(expRes); + }); + }); + + describe('Revoke entitlements', function () { + it('revoke existing entitlement', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expires = getCurrentTs() + 10000; + await executeGrantEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId, expires); + + // when + const response = await executeRevokeEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + + // then + expect(response.status).toBe(200); + }); + + it('revoke non-existent entitlement', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + const expError = { + code: 'invalid_entitlement_data', + message: 'Invalid entitlement uid, no such entitlement found', + type: 'request', + }; + + // when + const response = await executeRevokeEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('revoke entitlement with non-existent id', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Non-existent entitlement id'; + + const expError = { + code: 'invalid_entitlement_data', + message: 'Invalid entitlement uid, no such entitlement found', + type: 'request', + }; + + // when + const response = await executeRevokeEntitlementsRequest(AEGIS_URL, PRIVATE_TOKEN_FOR_TESTS, userId, entitlementId); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + + it('revoke entitlement with wrong token', async () => { + // given + const userId = 'testGrantEntitlementUid' + Date.now(); + await userService.createUser(userId); + + const entitlementId = 'Test Permission'; + + const expError = { + code: 'control_unauthorized', + message: 'Authorization error: project not found', + type: 'request', + }; + + // when + const response = await executeRevokeEntitlementsRequest(AEGIS_URL, PROJECT_KEY_FOR_TESTS, userId, entitlementId); + const responseBody = await response.json(); + + // then + expect(response.status).toBe(400); + expect(responseBody.error).toEqual(expError); + }); + }); +}); diff --git a/sdk/src/__integrationTests__/utils.ts b/sdk/src/__integrationTests__/utils.ts new file mode 100644 index 0000000..824c25e --- /dev/null +++ b/sdk/src/__integrationTests__/utils.ts @@ -0,0 +1,43 @@ +import {QonversionErrorCode} from '../exception/QonversionErrorCode'; +import {QonversionError} from '../exception/QonversionError'; +import {DependenciesAssembly, DependenciesAssemblyBuilder} from '../internal/di/DependenciesAssembly'; +import {QonversionConfigBuilder} from '../QonversionConfigBuilder'; +import {PROJECT_KEY_FOR_TESTS} from './constants'; +import {InternalConfig} from '../internal'; +import {Environment} from '../dto/Environment'; + +export const getCurrentTs = (): number => Math.floor(Date.now() / 1000); + +export const getDependencyAssembly = (config: {apiUrl?: string, environment?: Environment} = {}): DependenciesAssembly => { + const qonversionConfig = new QonversionConfigBuilder(PROJECT_KEY_FOR_TESTS) + .setEnvironment(config.environment ?? Environment.Production) + .build(); + if (config.apiUrl) { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + // noinspection JSConstantReassignment + qonversionConfig.networkConfig.apiUrl = config.apiUrl; + } + const internalConfig = new InternalConfig(qonversionConfig); + return new DependenciesAssemblyBuilder(internalConfig).build(); +}; + +export const expectQonversionErrorAsync = async (code: QonversionErrorCode, message: string, method: () => Promise) => { + try { + await method(); + } catch (e) { + expect(e).toBeInstanceOf(QonversionError); + expect((e as QonversionError).code).toBe(code); + expect((e as QonversionError).message).toBe(message); + return; + } + fail("Exception expected but was not thrown"); +} + +const fail = (reason = "Fail was called in a test") => { + throw new Error(reason); +}; + +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +global.fail = fail; diff --git a/sdk/src/__tests__/QonversionConfigBuilder.test.ts b/sdk/src/__tests__/QonversionConfigBuilder.test.ts index b580881..310ecaa 100644 --- a/sdk/src/__tests__/QonversionConfigBuilder.test.ts +++ b/sdk/src/__tests__/QonversionConfigBuilder.test.ts @@ -7,6 +7,7 @@ import { } from '../index'; import {LoggerConfig, NetworkConfig, PrimaryConfig} from "../types"; import {expectQonversionError} from './utils'; +import {API_URL} from '../internal/network'; const packageJson = require('../../../package.json'); @@ -80,6 +81,7 @@ test('successful build with full list of arguments', () => { }; const expNetworkConfig: NetworkConfig = { canSendRequests: true, + apiUrl: API_URL, }; const expResult: QonversionConfig = { primaryConfig: expPrimaryConfig, @@ -115,6 +117,7 @@ test('successful build without full list of arguments', () => { }; const expNetworkConfig: NetworkConfig = { canSendRequests: defaultCanSendRequests, + apiUrl: API_URL, }; const expResult: QonversionConfig = { primaryConfig: expPrimaryConfig, diff --git a/sdk/src/__tests__/utils.ts b/sdk/src/__tests__/utils.ts index a4173be..1b622cd 100644 --- a/sdk/src/__tests__/utils.ts +++ b/sdk/src/__tests__/utils.ts @@ -6,8 +6,7 @@ export function expectQonversionError(code: QonversionErrorCode, method: () => u fail("Exception expected but was not thrown"); } catch (e) { expect(e).toBeInstanceOf(QonversionError); - // @ts-ignore - expect(e.code).toBe(code); + expect((e as QonversionError).code).toBe(code); } } diff --git a/sdk/src/dto/Purchase.ts b/sdk/src/dto/Purchase.ts index 35a16cb..7811bbf 100644 --- a/sdk/src/dto/Purchase.ts +++ b/sdk/src/dto/Purchase.ts @@ -1,7 +1,7 @@ export type PurchaseCoreData = { price: string; currency: string; // Currency code by ISO 4217 standard - purchased: number; // todo check date type + purchased?: number; }; export type StripeStoreData = { @@ -10,5 +10,7 @@ export type StripeStoreData = { }; export type UserPurchase = PurchaseCoreData & { + purchased: number; stripeStoreData: StripeStoreData; + userId: string; }; diff --git a/sdk/src/internal/di/NetworkAssembly.ts b/sdk/src/internal/di/NetworkAssembly.ts index bed7cc0..639c01d 100644 --- a/sdk/src/internal/di/NetworkAssembly.ts +++ b/sdk/src/internal/di/NetworkAssembly.ts @@ -1,6 +1,5 @@ import {MiscAssembly, NetworkAssembly, StorageAssembly} from './types'; import { - API_URL, ApiInteractorImpl, HeaderBuilderImpl, ApiInteractor, @@ -33,7 +32,7 @@ export class NetworkAssemblyImpl implements NetworkAssembly { requestConfigurator(): RequestConfigurator { return new RequestConfiguratorImpl( this.headerBuilder(), - API_URL, + this.internalConfig.networkConfig.apiUrl, this.internalConfig, this.storageAssembly.userDataProvider() ); diff --git a/sdk/src/internal/purchases/PurchaseService.ts b/sdk/src/internal/purchases/PurchaseService.ts index 50a365d..84bb852 100644 --- a/sdk/src/internal/purchases/PurchaseService.ts +++ b/sdk/src/internal/purchases/PurchaseService.ts @@ -4,6 +4,7 @@ import {ApiInteractor, RequestConfigurator} from '../network'; import {camelCaseKeys} from '../utils/objectUtils'; import {QonversionError} from '../../exception/QonversionError'; import {QonversionErrorCode} from '../../exception/QonversionErrorCode'; +import {HTTP_CODE_NOT_FOUND} from '../network/constants'; export class PurchaseServiceImpl implements PurchasesService { private readonly requestConfigurator: RequestConfigurator; @@ -22,6 +23,10 @@ export class PurchaseServiceImpl implements PurchasesService { return camelCaseKeys(response.data); } + if (response.code == HTTP_CODE_NOT_FOUND) { + throw new QonversionError(QonversionErrorCode.UserNotFound, `Id: ${userId}`); + } + const errorMessage = `Response code ${response.code}, message: ${response.message}`; throw new QonversionError(QonversionErrorCode.BackendError, errorMessage); } diff --git a/sdk/src/internal/utils/objectUtils.ts b/sdk/src/internal/utils/objectUtils.ts index a1176e0..66ebba9 100644 --- a/sdk/src/internal/utils/objectUtils.ts +++ b/sdk/src/internal/utils/objectUtils.ts @@ -2,9 +2,9 @@ type CamelCaseKeys = (value: any) => T; export const camelCaseKeys: CamelCaseKeys = value => { let convertedValue; - if (value instanceof Array) { + if (Array.isArray(value)) { convertedValue = value.map(arrayValue => camelCaseKeys(arrayValue)); - } else if (value instanceof Object) { + } else if (typeof value === 'object') { convertedValue = camelCaseObjectKeys(value); } else { convertedValue = value; @@ -31,4 +31,4 @@ export const snakeToCamelCase: SnakeToCamelCaseConverter = str => .toUpperCase() .replace('-', '') .replace('_', '') - ); \ No newline at end of file + ); diff --git a/sdk/src/types.ts b/sdk/src/types.ts index db42693..9a89056 100644 --- a/sdk/src/types.ts +++ b/sdk/src/types.ts @@ -136,6 +136,7 @@ export type LoggerConfig = { export type NetworkConfig = { canSendRequests: boolean; + readonly apiUrl: string; }; export type PrimaryConfig = { diff --git a/yarn.lock b/yarn.lock index 4250cdc..16ae55d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -177,6 +177,11 @@ resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.19.0.tgz#4796bb14961521f0f8715990bee2fb6e51ce21bf" integrity sha512-40Ryx7I8mT+0gaNxm8JGTZFUITNqdLAgdg0hXzeVZxVD6nFsdhQvip6v8dqkRHzsz1VFpFAaOCHNn0vKBL7Czw== +"@babel/helper-plugin-utils@^7.20.2": + version "7.21.5" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.21.5.tgz#345f2377d05a720a4e5ecfa39cbf4474a4daed56" + integrity sha512-0WDaIlXKOX/3KfBK/dwP1oQGiPh6rjMkT7HIRv7i5RR2VUMwrx5ZL0dwBkKx7+SW1zwNdgjHd34IMk5ZjTeHVg== + "@babel/helper-remap-async-to-generator@^7.18.6", "@babel/helper-remap-async-to-generator@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.18.9.tgz#997458a0e3357080e54e1d79ec347f8a8cd28519" @@ -475,6 +480,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.7.2": + version "7.21.4" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" + integrity sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ== + dependencies: + "@babel/helper-plugin-utils" "^7.20.2" + "@babel/plugin-syntax-logical-assignment-operators@^7.10.4", "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz#ca91ef46303530448b906652bac2e9fe9941f699" @@ -1002,110 +1014,110 @@ resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== -"@jest/console@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-28.1.3.tgz#2030606ec03a18c31803b8a36382762e447655df" - integrity sha512-QPAkP5EwKdK/bxIr6C1I4Vs0rm2nHiANzj/Z5X2JQkrZo6IqvC4ldZ9K95tF0HdidhA8Bo6egxSzUFPYKcEXLw== +"@jest/console@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.5.0.tgz#593a6c5c0d3f75689835f1b3b4688c4f8544cb57" + integrity sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ== dependencies: - "@jest/types" "^28.1.3" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" - jest-message-util "^28.1.3" - jest-util "^28.1.3" + jest-message-util "^29.5.0" + jest-util "^29.5.0" slash "^3.0.0" -"@jest/core@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-28.1.3.tgz#0ebf2bd39840f1233cd5f2d1e6fc8b71bd5a1ac7" - integrity sha512-CIKBrlaKOzA7YG19BEqCw3SLIsEwjZkeJzf5bdooVnW4bH5cktqe3JX+G2YV1aK5vP8N9na1IGWFzYaTp6k6NA== +"@jest/core@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.5.0.tgz#76674b96904484e8214614d17261cc491e5f1f03" + integrity sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ== dependencies: - "@jest/console" "^28.1.3" - "@jest/reporters" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/console" "^29.5.0" + "@jest/reporters" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" ci-info "^3.2.0" exit "^0.1.2" graceful-fs "^4.2.9" - jest-changed-files "^28.1.3" - jest-config "^28.1.3" - jest-haste-map "^28.1.3" - jest-message-util "^28.1.3" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.3" - jest-resolve-dependencies "^28.1.3" - jest-runner "^28.1.3" - jest-runtime "^28.1.3" - jest-snapshot "^28.1.3" - jest-util "^28.1.3" - jest-validate "^28.1.3" - jest-watcher "^28.1.3" + jest-changed-files "^29.5.0" + jest-config "^29.5.0" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-resolve-dependencies "^29.5.0" + jest-runner "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" + jest-watcher "^29.5.0" micromatch "^4.0.4" - pretty-format "^28.1.3" - rimraf "^3.0.0" + pretty-format "^29.5.0" slash "^3.0.0" strip-ansi "^6.0.0" -"@jest/environment@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-28.1.3.tgz#abed43a6b040a4c24fdcb69eab1f97589b2d663e" - integrity sha512-1bf40cMFTEkKyEf585R9Iz1WayDjHoHqvts0XFYEqyKM3cFWDpeMoqKKTAF9LSYQModPUlh8FKptoM2YcMWAXA== +"@jest/environment@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.5.0.tgz#9152d56317c1fdb1af389c46640ba74ef0bb4c65" + integrity sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ== dependencies: - "@jest/fake-timers" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" - jest-mock "^28.1.3" + jest-mock "^29.5.0" -"@jest/expect-utils@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-28.1.3.tgz#58561ce5db7cd253a7edddbc051fb39dda50f525" - integrity sha512-wvbi9LUrHJLn3NlDW6wF2hvIMtd4JUl2QNVrjq+IBSHirgfrR3o9RnVtxzdEGO2n9JyIWwHnLfby5KzqBGg2YA== +"@jest/expect-utils@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.5.0.tgz#f74fad6b6e20f924582dc8ecbf2cb800fe43a036" + integrity sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg== dependencies: - jest-get-type "^28.0.2" + jest-get-type "^29.4.3" -"@jest/expect@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-28.1.3.tgz#9ac57e1d4491baca550f6bdbd232487177ad6a72" - integrity sha512-lzc8CpUbSoE4dqT0U+g1qODQjBRHPpCPXissXD4mS9+sWQdmmpeJ9zSH1rS1HEkrsMN0fb7nKrJ9giAR1d3wBw== +"@jest/expect@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.5.0.tgz#80952f5316b23c483fbca4363ce822af79c38fba" + integrity sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g== dependencies: - expect "^28.1.3" - jest-snapshot "^28.1.3" + expect "^29.5.0" + jest-snapshot "^29.5.0" -"@jest/fake-timers@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-28.1.3.tgz#230255b3ad0a3d4978f1d06f70685baea91c640e" - integrity sha512-D/wOkL2POHv52h+ok5Oj/1gOG9HSywdoPtFsRCUmlCILXNn5eIWmcnd3DIiWlJnpGvQtmajqBP95Ei0EimxfLw== +"@jest/fake-timers@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-29.5.0.tgz#d4d09ec3286b3d90c60bdcd66ed28d35f1b4dc2c" + integrity sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg== dependencies: - "@jest/types" "^28.1.3" - "@sinonjs/fake-timers" "^9.1.2" + "@jest/types" "^29.5.0" + "@sinonjs/fake-timers" "^10.0.2" "@types/node" "*" - jest-message-util "^28.1.3" - jest-mock "^28.1.3" - jest-util "^28.1.3" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-util "^29.5.0" -"@jest/globals@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-28.1.3.tgz#a601d78ddc5fdef542728309894895b4a42dc333" - integrity sha512-XFU4P4phyryCXu1pbcqMO0GSQcYe1IsalYCDzRNyhetyeyxMcIxa11qPNDpVNLeretItNqEmYYQn1UYz/5x1NA== +"@jest/globals@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.5.0.tgz#6166c0bfc374c58268677539d0c181f9c1833298" + integrity sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ== dependencies: - "@jest/environment" "^28.1.3" - "@jest/expect" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/types" "^29.5.0" + jest-mock "^29.5.0" -"@jest/reporters@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-28.1.3.tgz#9adf6d265edafc5fc4a434cfb31e2df5a67a369a" - integrity sha512-JuAy7wkxQZVNU/V6g9xKzCGC5LVXx9FDcABKsSXp5MiKPEE2144a/vXTEDoyzjUpZKfVwp08Wqg5A4WfTMAzjg== +"@jest/reporters@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.5.0.tgz#985dfd91290cd78ddae4914ba7921bcbabe8ac9b" + integrity sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA== dependencies: "@bcoe/v8-coverage" "^0.2.3" - "@jest/console" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" - "@jridgewell/trace-mapping" "^0.3.13" + "@jest/console" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" "@types/node" "*" chalk "^4.0.0" collect-v8-coverage "^1.0.0" @@ -1117,13 +1129,12 @@ istanbul-lib-report "^3.0.0" istanbul-lib-source-maps "^4.0.0" istanbul-reports "^3.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" - jest-worker "^28.1.3" + jest-message-util "^29.5.0" + jest-util "^29.5.0" + jest-worker "^29.5.0" slash "^3.0.0" string-length "^4.0.1" strip-ansi "^6.0.0" - terminal-link "^2.0.0" v8-to-istanbul "^9.0.1" "@jest/schemas@^28.1.3": @@ -1133,33 +1144,40 @@ dependencies: "@sinclair/typebox" "^0.24.1" -"@jest/source-map@^28.1.2": - version "28.1.2" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-28.1.2.tgz#7fe832b172b497d6663cdff6c13b0a920e139e24" - integrity sha512-cV8Lx3BeStJb8ipPHnqVw/IM2VCMWO3crWZzYodSIkxXnRcXJipCdx1JCK0K5MsJJouZQTH73mzf4vgxRaH9ww== +"@jest/schemas@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/schemas/-/schemas-29.4.3.tgz#39cf1b8469afc40b6f5a2baaa146e332c4151788" + integrity sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg== dependencies: - "@jridgewell/trace-mapping" "^0.3.13" + "@sinclair/typebox" "^0.25.16" + +"@jest/source-map@^29.4.3": + version "29.4.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.4.3.tgz#ff8d05cbfff875d4a791ab679b4333df47951d20" + integrity sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w== + dependencies: + "@jridgewell/trace-mapping" "^0.3.15" callsites "^3.0.0" graceful-fs "^4.2.9" -"@jest/test-result@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-28.1.3.tgz#5eae945fd9f4b8fcfce74d239e6f725b6bf076c5" - integrity sha512-kZAkxnSE+FqE8YjW8gNuoVkkC9I7S1qmenl8sGcDOLropASP+BkcGKwhXoyqQuGOGeYY0y/ixjrd/iERpEXHNg== +"@jest/test-result@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.5.0.tgz#7c856a6ca84f45cc36926a4e9c6b57f1973f1408" + integrity sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ== dependencies: - "@jest/console" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/console" "^29.5.0" + "@jest/types" "^29.5.0" "@types/istanbul-lib-coverage" "^2.0.0" collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^28.1.3": - version "28.1.3" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-28.1.3.tgz#9d0c283d906ac599c74bde464bc0d7e6a82886c3" - integrity sha512-NIMPEqqa59MWnDi1kvXXpYbqsfQmSJsIbnd85mdVGkiDfQ9WQQTXOLsvISUfonmnBT+w85WEgneCigEEdHDFxw== +"@jest/test-sequencer@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz#34d7d82d3081abd523dbddc038a3ddcb9f6d3cc4" + integrity sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ== dependencies: - "@jest/test-result" "^28.1.3" + "@jest/test-result" "^29.5.0" graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" + jest-haste-map "^29.5.0" slash "^3.0.0" "@jest/transform@^28.1.3": @@ -1183,6 +1201,27 @@ slash "^3.0.0" write-file-atomic "^4.0.1" +"@jest/transform@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.5.0.tgz#cf9c872d0965f0cbd32f1458aa44a2b1988b00f9" + integrity sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw== + dependencies: + "@babel/core" "^7.11.6" + "@jest/types" "^29.5.0" + "@jridgewell/trace-mapping" "^0.3.15" + babel-plugin-istanbul "^6.1.1" + chalk "^4.0.0" + convert-source-map "^2.0.0" + fast-json-stable-stringify "^2.1.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.5.0" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" + "@jest/types@^28.1.3": version "28.1.3" resolved "https://registry.yarnpkg.com/@jest/types/-/types-28.1.3.tgz#b05de80996ff12512bc5ceb1d208285a7d11748b" @@ -1195,6 +1234,18 @@ "@types/yargs" "^17.0.8" chalk "^4.0.0" +"@jest/types@^29.5.0": + version "29.5.0" + resolved "https://registry.yarnpkg.com/@jest/types/-/types-29.5.0.tgz#f59ef9b031ced83047c67032700d8c807d6e1593" + integrity sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog== + dependencies: + "@jest/schemas" "^29.4.3" + "@types/istanbul-lib-coverage" "^2.0.0" + "@types/istanbul-reports" "^3.0.0" + "@types/node" "*" + "@types/yargs" "^17.0.8" + chalk "^4.0.0" + "@jridgewell/gen-mapping@^0.1.0": version "0.1.1" resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996" @@ -1212,7 +1263,7 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" -"@jridgewell/resolve-uri@^3.0.3": +"@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== @@ -1222,7 +1273,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw== -"@jridgewell/sourcemap-codec@^1.4.10": +"@jridgewell/sourcemap-codec@1.4.14", "@jridgewell/sourcemap-codec@^1.4.10": version "1.4.14" resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24" integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw== @@ -1235,6 +1286,14 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@jridgewell/trace-mapping@^0.3.15": + version "0.3.18" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" + integrity sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA== + dependencies: + "@jridgewell/resolve-uri" "3.1.0" + "@jridgewell/sourcemap-codec" "1.4.14" + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" @@ -1261,19 +1320,24 @@ resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.24.44.tgz#0a0aa3bf4a155a678418527342a3ee84bd8caa5c" integrity sha512-ka0W0KN5i6LfrSocduwliMMpqVgohtPFidKdMEOUjoOFCHcOOYkKsPRxfs5f15oPNHTm6ERAm0GV/+/LTKeiWg== -"@sinonjs/commons@^1.7.0": - version "1.8.3" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.3.tgz#3802ddd21a50a949b6721ddd72da36e67e7f1b2d" - integrity sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ== +"@sinclair/typebox@^0.25.16": + version "0.25.24" + resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" + integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== + +"@sinonjs/commons@^2.0.0": + version "2.0.0" + resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" + integrity sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg== dependencies: type-detect "4.0.8" -"@sinonjs/fake-timers@^9.1.2": - version "9.1.2" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-9.1.2.tgz#4eaab737fab77332ab132d396a3c0d364bd0ea8c" - integrity sha512-BPS4ynJW/o92PUR4wgriz2Ud5gpST5vz6GQfMixEDK0Z8ZCUv2M7SkBLykH56T++Xs+8ln9zTGbOvNGIe02/jw== +"@sinonjs/fake-timers@^10.0.2": + version "10.0.2" + resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz#d10549ed1f423d80639c528b6c7f5a1017747d0c" + integrity sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw== dependencies: - "@sinonjs/commons" "^1.7.0" + "@sinonjs/commons" "^2.0.0" "@types/babel__core@^7.1.14": version "7.1.19" @@ -1334,13 +1398,13 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^27.5.1": - version "27.5.2" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-27.5.2.tgz#ec49d29d926500ffb9fd22b84262e862049c026c" - integrity sha512-mpT8LJJ4CMeeahobofYWIjFo0xonRS/HfxnVEPMPFSQdGUt1uHCnoPT7Zhb+sjDU2wz0oKV0OLUR0WzrHNgfeA== +"@types/jest@^29.4.0": + version "29.5.1" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.1.tgz#83c818aa9a87da27d6da85d3378e5a34d2f31a47" + integrity sha512-tEuVcHrpaixS36w7hpsfLBLpjtMRJUE09/MHXn923LOVojDwyC14cWcfc0rDs0VEfUyYmt/+iX1kxxp+gZMcaQ== dependencies: - jest-matcher-utils "^27.0.0" - pretty-format "^27.0.0" + expect "^29.0.0" + pretty-format "^29.0.0" "@types/json-schema@^7.0.9": version "7.0.11" @@ -1535,7 +1599,7 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -babel-jest@^28.1.0, babel-jest@^28.1.3: +babel-jest@^28.1.0: version "28.1.3" resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-28.1.3.tgz#c1187258197c099072156a0a121c11ee1e3917d5" integrity sha512-epUaPOEWMk3cWX0M/sPvCHHCe9fMFAa/9hXEgKP8nFfNl/jlGkE9ucq9NqkZGXLDduCJYS0UvSlPUwC0S+rH6Q== @@ -1548,6 +1612,19 @@ babel-jest@^28.1.0, babel-jest@^28.1.3: graceful-fs "^4.2.9" slash "^3.0.0" +babel-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.5.0.tgz#3fe3ddb109198e78b1c88f9ebdecd5e4fc2f50a5" + integrity sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q== + dependencies: + "@jest/transform" "^29.5.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.5.0" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" + babel-plugin-dynamic-import-node@^2.3.3: version "2.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz#84fda19c976ec5c6defef57f9427b3def66e17a3" @@ -1576,6 +1653,16 @@ babel-plugin-jest-hoist@^28.1.3: "@types/babel__core" "^7.1.14" "@types/babel__traverse" "^7.0.6" +babel-plugin-jest-hoist@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz#a97db437936f441ec196990c9738d4b88538618a" + integrity sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w== + dependencies: + "@babel/template" "^7.3.3" + "@babel/types" "^7.3.3" + "@types/babel__core" "^7.1.14" + "@types/babel__traverse" "^7.0.6" + babel-plugin-polyfill-corejs2@^0.3.3: version "0.3.3" resolved "https://registry.yarnpkg.com/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.3.tgz#5d1bd3836d0a19e1b84bbf2d9640ccb6f951c122" @@ -1626,6 +1713,14 @@ babel-preset-jest@^28.1.3: babel-plugin-jest-hoist "^28.1.3" babel-preset-current-node-syntax "^1.0.0" +babel-preset-jest@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz#57bc8cc88097af7ff6a5ab59d1cd29d52a5916e2" + integrity sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg== + dependencies: + babel-plugin-jest-hoist "^29.5.0" + babel-preset-current-node-syntax "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" @@ -1656,6 +1751,13 @@ browserslist@^4.21.3, browserslist@^4.21.4: node-releases "^2.0.6" update-browserslist-db "^1.0.9" +bs-logger@0.x: + version "0.2.6" + resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== + dependencies: + fast-json-stable-stringify "2.x" + bser@2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" @@ -1783,6 +1885,11 @@ convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: dependencies: safe-buffer "~5.1.1" +convert-source-map@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-2.0.0.tgz#4b560f649fc4e918dd0ab75cf4961e8bc882d82a" + integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== + core-js-compat@^3.25.1: version "3.25.3" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.25.3.tgz#d6a442a03f4eade4555d4e640e6a06151dd95d38" @@ -1834,15 +1941,10 @@ detect-newline@^3.0.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== -diff-sequences@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-27.5.1.tgz#eaecc0d327fd68c8d9672a1e64ab8dccb2ef5327" - integrity sha512-k1gCAXAsNgLwEL+Y8Wvl+M6oEFj5bgazfZULpS5CneoPPXRaCCW7dm+q21Ky2VEE5X+VeRDBVg1Pcvvsr4TtNQ== - -diff-sequences@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-28.1.1.tgz#9989dc731266dc2903457a70e996f3a041913ac6" - integrity sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw== +diff-sequences@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" + integrity sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA== dir-glob@^3.0.1: version "3.0.1" @@ -1863,10 +1965,10 @@ electron-to-chromium@^1.4.251: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.268.tgz#5a902075f0209a628837e508a66d40ace04d54ab" integrity sha512-PO90Bv++vEzdln+eA9qLg1IRnh0rKETus6QkTzcFm5P3Wg3EQBZud5dcnzkpYXuIKWBjKe5CO8zjz02cicvn1g== -emittery@^0.10.2: - version "0.10.2" - resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.10.2.tgz#902eec8aedb8c41938c46e9385e9db7e03182933" - integrity sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw== +emittery@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" + integrity sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ== emoji-regex@^8.0.0: version "8.0.0" @@ -2046,16 +2148,16 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expect@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/expect/-/expect-28.1.3.tgz#90a7c1a124f1824133dd4533cce2d2bdcb6603ec" - integrity sha512-eEh0xn8HlsuOBxFgIss+2mX85VAS4Qy3OSkjV7rlBWljtA4oWH37glVGyOZSZvErDT/yBywZdPGwCXuTvSG85g== +expect@^29.0.0, expect@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.5.0.tgz#68c0509156cb2a0adb8865d413b137eeaae682f7" + integrity sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg== dependencies: - "@jest/expect-utils" "^28.1.3" - jest-get-type "^28.0.2" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" + "@jest/expect-utils" "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: version "3.1.3" @@ -2073,7 +2175,7 @@ fast-glob@^3.2.9: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@^2.0.0: +fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== @@ -2413,144 +2515,130 @@ istanbul-reports@^3.1.3: html-escaper "^2.0.0" istanbul-lib-report "^3.0.0" -jest-changed-files@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-28.1.3.tgz#d9aeee6792be3686c47cb988a8eaf82ff4238831" - integrity sha512-esaOfUWJXk2nfZt9SPyC8gA1kNfdKLkQWyzsMlqq8msYSlNKfmZxfRgZn4Cd4MGVUF+7v6dBs0d5TOAKa7iIiA== +jest-changed-files@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.5.0.tgz#e88786dca8bf2aa899ec4af7644e16d9dcf9b23e" + integrity sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag== dependencies: execa "^5.0.0" p-limit "^3.1.0" -jest-circus@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-28.1.3.tgz#d14bd11cf8ee1a03d69902dc47b6bd4634ee00e4" - integrity sha512-cZ+eS5zc79MBwt+IhQhiEp0OeBddpc1n8MBo1nMB8A7oPMKEO+Sre+wHaLJexQUj9Ya/8NOBY0RESUgYjB6fow== +jest-circus@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.5.0.tgz#b5926989449e75bff0d59944bae083c9d7fb7317" + integrity sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA== dependencies: - "@jest/environment" "^28.1.3" - "@jest/expect" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/environment" "^29.5.0" + "@jest/expect" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" co "^4.6.0" dedent "^0.7.0" is-generator-fn "^2.0.0" - jest-each "^28.1.3" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-runtime "^28.1.3" - jest-snapshot "^28.1.3" - jest-util "^28.1.3" + jest-each "^29.5.0" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-runtime "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" p-limit "^3.1.0" - pretty-format "^28.1.3" + pretty-format "^29.5.0" + pure-rand "^6.0.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-cli@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-28.1.3.tgz#558b33c577d06de55087b8448d373b9f654e46b2" - integrity sha512-roY3kvrv57Azn1yPgdTebPAXvdR2xfezaKKYzVxZ6It/5NCxzJym6tUI5P1zkdWhfUYkxEI9uZWcQdaFLo8mJQ== +jest-cli@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.5.0.tgz#b34c20a6d35968f3ee47a7437ff8e53e086b4a67" + integrity sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw== dependencies: - "@jest/core" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/core" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" chalk "^4.0.0" exit "^0.1.2" graceful-fs "^4.2.9" import-local "^3.0.2" - jest-config "^28.1.3" - jest-util "^28.1.3" - jest-validate "^28.1.3" + jest-config "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" prompts "^2.0.1" yargs "^17.3.1" -jest-config@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-28.1.3.tgz#e315e1f73df3cac31447eed8b8740a477392ec60" - integrity sha512-MG3INjByJ0J4AsNBm7T3hsuxKQqFIiRo/AUqb1q9LRKI5UU6Aar9JHbr9Ivn1TVwfUD9KirRoM/T6u8XlcQPHQ== +jest-config@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.5.0.tgz#3cc972faec8c8aaea9ae158c694541b79f3748da" + integrity sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA== dependencies: "@babel/core" "^7.11.6" - "@jest/test-sequencer" "^28.1.3" - "@jest/types" "^28.1.3" - babel-jest "^28.1.3" + "@jest/test-sequencer" "^29.5.0" + "@jest/types" "^29.5.0" + babel-jest "^29.5.0" chalk "^4.0.0" ci-info "^3.2.0" deepmerge "^4.2.2" glob "^7.1.3" graceful-fs "^4.2.9" - jest-circus "^28.1.3" - jest-environment-node "^28.1.3" - jest-get-type "^28.0.2" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.3" - jest-runner "^28.1.3" - jest-util "^28.1.3" - jest-validate "^28.1.3" + jest-circus "^29.5.0" + jest-environment-node "^29.5.0" + jest-get-type "^29.4.3" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-runner "^29.5.0" + jest-util "^29.5.0" + jest-validate "^29.5.0" micromatch "^4.0.4" parse-json "^5.2.0" - pretty-format "^28.1.3" + pretty-format "^29.5.0" slash "^3.0.0" strip-json-comments "^3.1.1" -jest-diff@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-27.5.1.tgz#a07f5011ac9e6643cf8a95a462b7b1ecf6680def" - integrity sha512-m0NvkX55LDt9T4mctTEgnZk3fmEg3NRYutvMPWM/0iPnkFj2wIeF45O1718cMSOFO1vINkqmxqD8vE37uTEbqw== - dependencies: - chalk "^4.0.0" - diff-sequences "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" - -jest-diff@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-28.1.3.tgz#948a192d86f4e7a64c5264ad4da4877133d8792f" - integrity sha512-8RqP1B/OXzjjTWkqMX67iqgwBVJRgCyKD3L9nq+6ZqJMdvjE8RgHktqZ6jNrkdMT+dJuYNI3rhQpxaz7drJHfw== +jest-diff@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.5.0.tgz#e0d83a58eb5451dcc1fa61b1c3ee4e8f5a290d63" + integrity sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw== dependencies: chalk "^4.0.0" - diff-sequences "^28.1.1" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" + diff-sequences "^29.4.3" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" -jest-docblock@^28.1.1: - version "28.1.1" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-28.1.1.tgz#6f515c3bf841516d82ecd57a62eed9204c2f42a8" - integrity sha512-3wayBVNiOYx0cwAbl9rwm5kKFP8yHH3d/fkEaL02NPTkDojPtheGB7HZSFY4wzX+DxyrvhXz0KSCVksmCknCuA== +jest-docblock@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.4.3.tgz#90505aa89514a1c7dceeac1123df79e414636ea8" + integrity sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg== dependencies: detect-newline "^3.0.0" -jest-each@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-28.1.3.tgz#bdd1516edbe2b1f3569cfdad9acd543040028f81" - integrity sha512-arT1z4sg2yABU5uogObVPvSlSMQlDA48owx07BDPAiasW0yYpYHYOo4HHLz9q0BVzDVU4hILFjzJw0So9aCL/g== +jest-each@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.5.0.tgz#fc6e7014f83eac68e22b7195598de8554c2e5c06" + integrity sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA== dependencies: - "@jest/types" "^28.1.3" + "@jest/types" "^29.5.0" chalk "^4.0.0" - jest-get-type "^28.0.2" - jest-util "^28.1.3" - pretty-format "^28.1.3" - -jest-environment-node@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-28.1.3.tgz#7e74fe40eb645b9d56c0c4b70ca4357faa349be5" - integrity sha512-ugP6XOhEpjAEhGYvp5Xj989ns5cB1K6ZdjBYuS30umT4CQEETaxSiPcZ/E1kFktX4GkrcM4qu07IIlDYX1gp+A== - dependencies: - "@jest/environment" "^28.1.3" - "@jest/fake-timers" "^28.1.3" - "@jest/types" "^28.1.3" + jest-get-type "^29.4.3" + jest-util "^29.5.0" + pretty-format "^29.5.0" + +jest-environment-node@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.5.0.tgz#f17219d0f0cc0e68e0727c58b792c040e332c967" + integrity sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" - jest-mock "^28.1.3" - jest-util "^28.1.3" - -jest-get-type@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-27.5.1.tgz#3cd613c507b0f7ace013df407a1c1cd578bcb4f1" - integrity sha512-2KY95ksYSaK7DMBWQn6dQz3kqAf3BB64y2udeG+hv4KfSOb9qwcYQstTJc1KCbsix+wLZWZYN8t7nwX3GOBLRw== + jest-mock "^29.5.0" + jest-util "^29.5.0" -jest-get-type@^28.0.2: - version "28.0.2" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-28.0.2.tgz#34622e628e4fdcd793d46db8a242227901fcf203" - integrity sha512-ioj2w9/DxSYHfOm5lJKCdcAmPJzQXmbM/Url3rhlghrPvT3tt+7a/+oXc9azkKmLvoiXjtV83bEWqi+vs5nlPA== +jest-get-type@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.4.3.tgz#1ab7a5207c995161100b5187159ca82dd48b3dd5" + integrity sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg== jest-haste-map@^28.1.3: version "28.1.3" @@ -2571,56 +2659,66 @@ jest-haste-map@^28.1.3: optionalDependencies: fsevents "^2.3.2" -jest-leak-detector@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-28.1.3.tgz#a6685d9b074be99e3adee816ce84fd30795e654d" - integrity sha512-WFVJhnQsiKtDEo5lG2mM0v40QWnBM+zMdHHyJs8AWZ7J0QZJS59MsyKeJHWhpBZBH32S48FOVvGyOFT1h0DlqA== +jest-haste-map@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.5.0.tgz#69bd67dc9012d6e2723f20a945099e972b2e94de" + integrity sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA== dependencies: - jest-get-type "^28.0.2" - pretty-format "^28.1.3" + "@jest/types" "^29.5.0" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" + fb-watchman "^2.0.0" + graceful-fs "^4.2.9" + jest-regex-util "^29.4.3" + jest-util "^29.5.0" + jest-worker "^29.5.0" + micromatch "^4.0.4" + walker "^1.0.8" + optionalDependencies: + fsevents "^2.3.2" -jest-matcher-utils@^27.0.0: - version "27.5.1" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-27.5.1.tgz#9c0cdbda8245bc22d2331729d1091308b40cf8ab" - integrity sha512-z2uTx/T6LBaCoNWNFWwChLBKYxTMcGBRjAt+2SbP929/Fflb9aa5LGma654Rz8z9HLxsrUaYzxE9T/EFIL/PAw== +jest-leak-detector@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz#cf4bdea9615c72bac4a3a7ba7e7930f9c0610c8c" + integrity sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow== dependencies: - chalk "^4.0.0" - jest-diff "^27.5.1" - jest-get-type "^27.5.1" - pretty-format "^27.5.1" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" -jest-matcher-utils@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-28.1.3.tgz#5a77f1c129dd5ba3b4d7fc20728806c78893146e" - integrity sha512-kQeJ7qHemKfbzKoGjHHrRKH6atgxMk8Enkk2iPQ3XwO6oE/KYD8lMYOziCkeSB9G4adPM4nR1DE8Tf5JeWH6Bw== +jest-matcher-utils@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz#d957af7f8c0692c5453666705621ad4abc2c59c5" + integrity sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw== dependencies: chalk "^4.0.0" - jest-diff "^28.1.3" - jest-get-type "^28.0.2" - pretty-format "^28.1.3" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + pretty-format "^29.5.0" -jest-message-util@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-28.1.3.tgz#232def7f2e333f1eecc90649b5b94b0055e7c43d" - integrity sha512-PFdn9Iewbt575zKPf1286Ht9EPoJmYT7P0kY+RibeYZ2XtOr53pDLEFoTWXbd1h4JiGiWpTBC84fc8xMXQMb7g== +jest-message-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-29.5.0.tgz#1f776cac3aca332ab8dd2e3b41625435085c900e" + integrity sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA== dependencies: "@babel/code-frame" "^7.12.13" - "@jest/types" "^28.1.3" + "@jest/types" "^29.5.0" "@types/stack-utils" "^2.0.0" chalk "^4.0.0" graceful-fs "^4.2.9" micromatch "^4.0.4" - pretty-format "^28.1.3" + pretty-format "^29.5.0" slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-28.1.3.tgz#d4e9b1fc838bea595c77ab73672ebf513ab249da" - integrity sha512-o3J2jr6dMMWYVH4Lh/NKmDXdosrsJgi4AviS8oXLujcjpCMBb1FMsblDnOXKZKfSiHLxYub1eS0IHuRXsio9eA== +jest-mock@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.5.0.tgz#26e2172bcc71d8b0195081ff1f146ac7e1518aed" + integrity sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw== dependencies: - "@jest/types" "^28.1.3" + "@jest/types" "^29.5.0" "@types/node" "*" + jest-util "^29.5.0" jest-pnp-resolver@^1.2.2: version "1.2.2" @@ -2632,111 +2730,116 @@ jest-regex-util@^28.0.2: resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-28.0.2.tgz#afdc377a3b25fb6e80825adcf76c854e5bf47ead" integrity sha512-4s0IgyNIy0y9FK+cjoVYoxamT7Zeo7MhzqRGx7YDYmaQn1wucY9rotiGkBzzcMXTtjrCAP/f7f+E0F7+fxPNdw== -jest-resolve-dependencies@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-28.1.3.tgz#8c65d7583460df7275c6ea2791901fa975c1fe66" - integrity sha512-qa0QO2Q0XzQoNPouMbCc7Bvtsem8eQgVPNkwn9LnS+R2n8DaVDPL/U1gngC0LTl1RYXJU0uJa2BMC2DbTfFrHA== +jest-regex-util@^29.4.3: + version "29.4.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.4.3.tgz#a42616141e0cae052cfa32c169945d00c0aa0bb8" + integrity sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg== + +jest-resolve-dependencies@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz#f0ea29955996f49788bf70996052aa98e7befee4" + integrity sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg== dependencies: - jest-regex-util "^28.0.2" - jest-snapshot "^28.1.3" + jest-regex-util "^29.4.3" + jest-snapshot "^29.5.0" -jest-resolve@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-28.1.3.tgz#cfb36100341ddbb061ec781426b3c31eb51aa0a8" - integrity sha512-Z1W3tTjE6QaNI90qo/BJpfnvpxtaFTFw5CDgwpyE/Kz8U/06N1Hjf4ia9quUhCh39qIGWF1ZuxFiBiJQwSEYKQ== +jest-resolve@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.5.0.tgz#b053cc95ad1d5f6327f0ac8aae9f98795475ecdc" + integrity sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w== dependencies: chalk "^4.0.0" graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" + jest-haste-map "^29.5.0" jest-pnp-resolver "^1.2.2" - jest-util "^28.1.3" - jest-validate "^28.1.3" + jest-util "^29.5.0" + jest-validate "^29.5.0" resolve "^1.20.0" - resolve.exports "^1.1.0" + resolve.exports "^2.0.0" slash "^3.0.0" -jest-runner@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-28.1.3.tgz#5eee25febd730b4713a2cdfd76bdd5557840f9a1" - integrity sha512-GkMw4D/0USd62OVO0oEgjn23TM+YJa2U2Wu5zz9xsQB1MxWKDOlrnykPxnMsN0tnJllfLPinHTka61u0QhaxBA== +jest-runner@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.5.0.tgz#6a57c282eb0ef749778d444c1d758c6a7693b6f8" + integrity sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ== dependencies: - "@jest/console" "^28.1.3" - "@jest/environment" "^28.1.3" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/console" "^29.5.0" + "@jest/environment" "^29.5.0" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" chalk "^4.0.0" - emittery "^0.10.2" + emittery "^0.13.1" graceful-fs "^4.2.9" - jest-docblock "^28.1.1" - jest-environment-node "^28.1.3" - jest-haste-map "^28.1.3" - jest-leak-detector "^28.1.3" - jest-message-util "^28.1.3" - jest-resolve "^28.1.3" - jest-runtime "^28.1.3" - jest-util "^28.1.3" - jest-watcher "^28.1.3" - jest-worker "^28.1.3" + jest-docblock "^29.4.3" + jest-environment-node "^29.5.0" + jest-haste-map "^29.5.0" + jest-leak-detector "^29.5.0" + jest-message-util "^29.5.0" + jest-resolve "^29.5.0" + jest-runtime "^29.5.0" + jest-util "^29.5.0" + jest-watcher "^29.5.0" + jest-worker "^29.5.0" p-limit "^3.1.0" source-map-support "0.5.13" -jest-runtime@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-28.1.3.tgz#a57643458235aa53e8ec7821949e728960d0605f" - integrity sha512-NU+881ScBQQLc1JHG5eJGU7Ui3kLKrmwCPPtYsJtBykixrM2OhVQlpMmFWJjMyDfdkGgBMNjXCGB/ebzsgNGQw== - dependencies: - "@jest/environment" "^28.1.3" - "@jest/fake-timers" "^28.1.3" - "@jest/globals" "^28.1.3" - "@jest/source-map" "^28.1.2" - "@jest/test-result" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" +jest-runtime@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.5.0.tgz#c83f943ee0c1da7eb91fa181b0811ebd59b03420" + integrity sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw== + dependencies: + "@jest/environment" "^29.5.0" + "@jest/fake-timers" "^29.5.0" + "@jest/globals" "^29.5.0" + "@jest/source-map" "^29.4.3" + "@jest/test-result" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" + "@types/node" "*" chalk "^4.0.0" cjs-module-lexer "^1.0.0" collect-v8-coverage "^1.0.0" - execa "^5.0.0" glob "^7.1.3" graceful-fs "^4.2.9" - jest-haste-map "^28.1.3" - jest-message-util "^28.1.3" - jest-mock "^28.1.3" - jest-regex-util "^28.0.2" - jest-resolve "^28.1.3" - jest-snapshot "^28.1.3" - jest-util "^28.1.3" + jest-haste-map "^29.5.0" + jest-message-util "^29.5.0" + jest-mock "^29.5.0" + jest-regex-util "^29.4.3" + jest-resolve "^29.5.0" + jest-snapshot "^29.5.0" + jest-util "^29.5.0" slash "^3.0.0" strip-bom "^4.0.0" -jest-snapshot@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-28.1.3.tgz#17467b3ab8ddb81e2f605db05583d69388fc0668" - integrity sha512-4lzMgtiNlc3DU/8lZfmqxN3AYD6GGLbl+72rdBpXvcV+whX7mDrREzkPdp2RnmfIiWBg1YbuFSkXduF2JcafJg== +jest-snapshot@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.5.0.tgz#c9c1ce0331e5b63cd444e2f95a55a73b84b1e8ce" + integrity sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g== dependencies: "@babel/core" "^7.11.6" "@babel/generator" "^7.7.2" + "@babel/plugin-syntax-jsx" "^7.7.2" "@babel/plugin-syntax-typescript" "^7.7.2" "@babel/traverse" "^7.7.2" "@babel/types" "^7.3.3" - "@jest/expect-utils" "^28.1.3" - "@jest/transform" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/expect-utils" "^29.5.0" + "@jest/transform" "^29.5.0" + "@jest/types" "^29.5.0" "@types/babel__traverse" "^7.0.6" "@types/prettier" "^2.1.5" babel-preset-current-node-syntax "^1.0.0" chalk "^4.0.0" - expect "^28.1.3" + expect "^29.5.0" graceful-fs "^4.2.9" - jest-diff "^28.1.3" - jest-get-type "^28.0.2" - jest-haste-map "^28.1.3" - jest-matcher-utils "^28.1.3" - jest-message-util "^28.1.3" - jest-util "^28.1.3" + jest-diff "^29.5.0" + jest-get-type "^29.4.3" + jest-matcher-utils "^29.5.0" + jest-message-util "^29.5.0" + jest-util "^29.5.0" natural-compare "^1.4.0" - pretty-format "^28.1.3" + pretty-format "^29.5.0" semver "^7.3.5" jest-util@^28.1.3: @@ -2751,30 +2854,42 @@ jest-util@^28.1.3: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-28.1.3.tgz#e322267fd5e7c64cea4629612c357bbda96229df" - integrity sha512-SZbOGBWEsaTxBGCOpsRWlXlvNkvTkY0XxRfh7zYmvd8uL5Qzyg0CHAXiXKROflh801quA6+/DsT4ODDthOC/OA== +jest-util@^29.0.0, jest-util@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.5.0.tgz#24a4d3d92fc39ce90425311b23c27a6e0ef16b8f" + integrity sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ== dependencies: - "@jest/types" "^28.1.3" + "@jest/types" "^29.5.0" + "@types/node" "*" + chalk "^4.0.0" + ci-info "^3.2.0" + graceful-fs "^4.2.9" + picomatch "^2.2.3" + +jest-validate@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.5.0.tgz#8e5a8f36178d40e47138dc00866a5f3bd9916ffc" + integrity sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ== + dependencies: + "@jest/types" "^29.5.0" camelcase "^6.2.0" chalk "^4.0.0" - jest-get-type "^28.0.2" + jest-get-type "^29.4.3" leven "^3.1.0" - pretty-format "^28.1.3" + pretty-format "^29.5.0" -jest-watcher@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-28.1.3.tgz#c6023a59ba2255e3b4c57179fc94164b3e73abd4" - integrity sha512-t4qcqj9hze+jviFPUN3YAtAEeFnr/azITXQEMARf5cMwKY2SMBRnCQTXLixTl20OR6mLh9KLMrgVJgJISym+1g== +jest-watcher@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.5.0.tgz#cf7f0f949828ba65ddbbb45c743a382a4d911363" + integrity sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA== dependencies: - "@jest/test-result" "^28.1.3" - "@jest/types" "^28.1.3" + "@jest/test-result" "^29.5.0" + "@jest/types" "^29.5.0" "@types/node" "*" ansi-escapes "^4.2.1" chalk "^4.0.0" - emittery "^0.10.2" - jest-util "^28.1.3" + emittery "^0.13.1" + jest-util "^29.5.0" string-length "^4.0.1" jest-worker@^28.1.3: @@ -2786,15 +2901,25 @@ jest-worker@^28.1.3: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^28.1.0: - version "28.1.3" - resolved "https://registry.yarnpkg.com/jest/-/jest-28.1.3.tgz#e9c6a7eecdebe3548ca2b18894a50f45b36dfc6b" - integrity sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA== +jest-worker@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.5.0.tgz#bdaefb06811bd3384d93f009755014d8acb4615d" + integrity sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA== dependencies: - "@jest/core" "^28.1.3" - "@jest/types" "^28.1.3" + "@types/node" "*" + jest-util "^29.5.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.4.2: + version "29.5.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.5.0.tgz#f75157622f5ce7ad53028f2f8888ab53e1f1f24e" + integrity sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ== + dependencies: + "@jest/core" "^29.5.0" + "@jest/types" "^29.5.0" import-local "^3.0.2" - jest-cli "^28.1.3" + jest-cli "^29.5.0" js-sdsl@^4.1.4: version "4.1.4" @@ -2851,6 +2976,11 @@ json5@^2.2.1: resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c" integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA== +json5@^2.2.3: + version "2.2.3" + resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" + integrity sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg== + kleur@^3.0.3: version "3.0.3" resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" @@ -2893,6 +3023,11 @@ lodash.debounce@^4.0.8: resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow== +lodash.memoize@4.x: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== + lodash.merge@^4.6.2: version "4.6.2" resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" @@ -2912,6 +3047,11 @@ make-dir@^3.0.0: dependencies: semver "^6.0.0" +make-error@1.x: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + makeerror@1.0.12: version "1.0.12" resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.12.tgz#3e5dd2079a82e812e983cc6610c4a2cb0eaa801a" @@ -3124,22 +3264,12 @@ prelude-ls@^1.2.1: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== -pretty-format@^27.0.0, pretty-format@^27.5.1: - version "27.5.1" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-27.5.1.tgz#2181879fdea51a7a5851fb39d920faa63f01d88e" - integrity sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ== +pretty-format@^29.0.0, pretty-format@^29.5.0: + version "29.5.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.5.0.tgz#283134e74f70e2e3e7229336de0e4fce94ccde5a" + integrity sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw== dependencies: - ansi-regex "^5.0.1" - ansi-styles "^5.0.0" - react-is "^17.0.1" - -pretty-format@^28.1.3: - version "28.1.3" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-28.1.3.tgz#c9fba8cedf99ce50963a11b27d982a9ae90970d5" - integrity sha512-8gFb/To0OmxHR9+ZTb14Df2vNxdGCX8g1xWGUTqUw5TiZvcQf5sHKObd5UcPyLLyowNwDAMTF3XWOG1B6mxl1Q== - dependencies: - "@jest/schemas" "^28.1.3" - ansi-regex "^5.0.1" + "@jest/schemas" "^29.4.3" ansi-styles "^5.0.0" react-is "^18.0.0" @@ -3156,16 +3286,16 @@ punycode@^2.1.0: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== +pure-rand@^6.0.0: + version "6.0.2" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.2.tgz#a9c2ddcae9b68d736a8163036f088a2781c8b306" + integrity sha512-6Yg0ekpKICSjPswYOuC5sku/TSWaRYlA0qsXqJgM/d/4pLPHPuTxK7Nbf7jFKzAeedUhR8C7K9Uv63FBsSo8xQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== -react-is@^17.0.1: - version "17.0.2" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" - integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== - react-is@^18.0.0: version "18.2.0" resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" @@ -3246,10 +3376,10 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== -resolve.exports@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" - integrity sha512-J1l+Zxxp4XK3LUDZ9m60LRJF/mAe4z6a4xyabPHk7pvK5t35dACV32iIjJDFeWZFfZlO29w6SZ67knR0tHzJtQ== +resolve.exports@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-2.0.2.tgz#f8c934b8e6a13f539e38b7098e2e36134f01e800" + integrity sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg== resolve@^1.14.2, resolve@^1.20.0: version "1.22.1" @@ -3265,7 +3395,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.0, rimraf@^3.0.2: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -3284,6 +3414,13 @@ safe-buffer@~5.1.1: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +semver@7.x: + version "7.5.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.0.tgz#ed8c5dc8efb6c629c88b23d41dc9bf40c1d96cd0" + integrity sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA== + dependencies: + lru-cache "^6.0.0" + semver@^6.0.0, semver@^6.1.1, semver@^6.1.2, semver@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" @@ -3394,7 +3531,7 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^7.0.0, supports-color@^7.1.0: +supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== @@ -3408,27 +3545,11 @@ supports-color@^8.0.0: dependencies: has-flag "^4.0.0" -supports-hyperlinks@^2.0.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz#3943544347c1ff90b15effb03fc14ae45ec10624" - integrity sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA== - dependencies: - has-flag "^4.0.0" - supports-color "^7.0.0" - supports-preserve-symlinks-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== -terminal-link@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" - integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== - dependencies: - ansi-escapes "^4.2.1" - supports-hyperlinks "^2.0.0" - test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" @@ -3460,6 +3581,20 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" +ts-jest@^29.1.0: + version "29.1.0" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" + integrity sha512-ZhNr7Z4PcYa+JjMl62ir+zPiNJfXJN6E8hSLnaUKhOgqcn8vb3e537cpkd0FuAfRK3sR1LSqM1MOhliXNgOFPA== + dependencies: + bs-logger "0.x" + fast-json-stable-stringify "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" + lodash.memoize "4.x" + make-error "1.x" + semver "7.x" + yargs-parser "^21.0.1" + tslib@^1.8.1: version "1.14.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" @@ -3584,7 +3719,7 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@^4.0.1: +write-file-atomic@^4.0.1, write-file-atomic@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-4.0.2.tgz#a9df01ae5b77858a027fd2e80768ee433555fcfd" integrity sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg== @@ -3602,7 +3737,7 @@ yallist@^4.0.0: resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== -yargs-parser@^21.0.0: +yargs-parser@^21.0.0, yargs-parser@^21.0.1: version "21.1.1" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-21.1.1.tgz#9096bceebf990d21bb31fa9516e0ede294a77d35" integrity sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==