From f33cd0aadc5d2dcb836b716dd5b0b8e5c440ffaf Mon Sep 17 00:00:00 2001 From: israx <70438514+israx@users.noreply.github.com> Date: Mon, 27 Nov 2023 13:16:46 -0500 Subject: [PATCH 01/15] fix(auth): correct unknownError typo (#12634) chore: fix unknown error typo --- packages/auth/src/errors/utils/assertServiceError.ts | 2 +- .../src/inAppMessaging/errors/assertServiceError.ts | 2 +- .../src/providers/s3/utils/client/utils/serializeHelpers.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/auth/src/errors/utils/assertServiceError.ts b/packages/auth/src/errors/utils/assertServiceError.ts index 2185383cc80..8036b4cd755 100644 --- a/packages/auth/src/errors/utils/assertServiceError.ts +++ b/packages/auth/src/errors/utils/assertServiceError.ts @@ -17,7 +17,7 @@ export function assertServiceError( ) { throw new AuthError({ name: AmplifyErrorCode.Unknown, - message: 'An unknown error has ocurred.', + message: 'An unknown error has occurred.', underlyingError: error, }); } diff --git a/packages/notifications/src/inAppMessaging/errors/assertServiceError.ts b/packages/notifications/src/inAppMessaging/errors/assertServiceError.ts index cfdf676397e..9665304dd01 100644 --- a/packages/notifications/src/inAppMessaging/errors/assertServiceError.ts +++ b/packages/notifications/src/inAppMessaging/errors/assertServiceError.ts @@ -17,7 +17,7 @@ export function assertServiceError( ) { throw new InAppMessagingError({ name: AmplifyErrorCode.Unknown, - message: 'An unknown error has ocurred.', + message: 'An unknown error has occurred.', underlyingError: error, }); } diff --git a/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts b/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts index 29f5b4943e4..1fd41bc916e 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/serializeHelpers.ts @@ -82,7 +82,7 @@ export function validateS3RequiredParameter( if (!assertion) { throw new StorageError({ name: AmplifyErrorCode.Unknown, - message: 'An unknown error has ocurred.', + message: 'An unknown error has occurred.', underlyingError: new TypeError( `Expected a non-null value for S3 parameter ${paramName}` ), From f2b7a8d78058af2e1c04f7d507525641def667c3 Mon Sep 17 00:00:00 2001 From: Jim Blanchard Date: Mon, 27 Nov 2023 12:26:17 -0600 Subject: [PATCH 02/15] chore: Revert "Revert "chore: Upgrade Prettier (#12582)" (#12600)" (#12612) Revert "Revert "chore: Upgrade Prettier (#12582)" (#12600)" This reverts commit cd937f56bef5f90a4b42638776656faf746c48aa. Co-authored-by: Chris F <5827964+cshfang@users.noreply.github.com> --- .../workflows/callable-canary-e2e-runner.yml | 2 +- package.json | 2 +- ...torageAdapterFromNextServerContext.test.ts | 6 +- .../src/api/generateServerClient.ts | 4 +- packages/analytics/src/types/inputs.ts | 2 +- packages/analytics/src/utils/groupBy.ts | 11 +- packages/analytics/tsconfig.json | 14 +- .../src/internals/server/generateClient.ts | 2 +- packages/api-graphql/src/internals/v6.ts | 2 +- packages/api-graphql/src/types/index.ts | 53 +- packages/api/src/internals/InternalAPI.ts | 10 +- .../providers/cognito/signInWithSRP.test.ts | 5 +- .../providers/cognito/testUtils/data.ts | 1 - .../__tests__/utils/openAuthSession.test.ts | 2 +- packages/auth/jest.setup.js | 6 +- .../apis/internal/fetchUserAttributes.ts | 6 +- .../src/providers/cognito/types/models.ts | 2 +- .../providers/cognito/utils/signInHelpers.ts | 2 +- .../cognito/utils/signInWithRedirectStore.ts | 5 +- packages/auth/src/types/inputs.ts | 27 +- packages/auth/src/types/models.ts | 20 +- packages/auth/src/types/options.ts | 2 +- packages/auth/src/types/outputs.ts | 10 +- packages/core/__mocks__/SessionStorage.js | 2 +- .../pinpoint/utils/EventBuffer.test.ts | 6 +- .../pinpoint/utils/getEventBuffer.test.ts | 17 +- packages/core/src/Cache/types/index.ts | 8 +- packages/core/src/Hub/index.ts | 8 +- packages/core/src/Hub/types/HubTypes.ts | 6 +- .../src/clients/internal/composeServiceApi.ts | 2 +- .../internal/composeTransferHandler.ts | 30 +- .../signing/signer/signatureV4/signRequest.ts | 5 +- packages/core/src/clients/types/core.ts | 4 +- packages/core/src/global.d.ts | 2 +- packages/datastore-storage-adapter/.npmignore | 1 - .../datastore-storage-adapter/jest.setup.js | 4 +- .../src/common/CommonSQLiteAdapter.ts | 4 +- packages/datastore/.npmignore | 1 - packages/datastore/__tests__/AsyncStorage.ts | 2 +- packages/datastore/__tests__/DataStore.ts | 5 +- packages/datastore/__tests__/Predicate.ts | 540 +++++++----------- .../__tests__/connectivityHandling.test.ts | 5 +- packages/datastore/jest.setup.js | 4 +- packages/datastore/src/datastore/datastore.ts | 6 +- .../storage/adapter/AsyncStorageDatabase.ts | 5 +- packages/datastore/src/sync/index.ts | 5 +- .../src/sync/processors/subscription.ts | 2 +- packages/datastore/src/sync/utils.ts | 2 +- packages/datastore/src/types.ts | 96 ++-- .../AmazonLocationServiceProvider.test.ts | 5 +- .../utils/processInAppMessages.test.ts | 2 +- .../providers/pinpoint/utils/helpers.ts | 4 +- .../utils/messageProcessingHelpers.ts | 10 +- .../src/inAppMessaging/types/inputs.ts | 3 +- .../src/pushNotifications/types/inputs.ts | 3 +- .../AmazonAIIdentifyPredictionsProvider.ts | 7 +- packages/pubsub/src/vendor/paho-mqtt.js | 8 +- .../s3/utils/client/testUtils/types.ts | 4 +- .../s3/utils/client/utils/parsePayload.ts | 4 +- packages/storage/src/types/inputs.ts | 4 +- .prettierrc.js => prettier.config.js | 1 + yarn.lock | 8 +- 62 files changed, 458 insertions(+), 573 deletions(-) rename .prettierrc.js => prettier.config.js (71%) diff --git a/.github/workflows/callable-canary-e2e-runner.yml b/.github/workflows/callable-canary-e2e-runner.yml index ecde3811698..073192758e2 100644 --- a/.github/workflows/callable-canary-e2e-runner.yml +++ b/.github/workflows/callable-canary-e2e-runner.yml @@ -37,4 +37,4 @@ jobs: sample_name: ${{ toJSON(matrix.canary-config.sample_name) || '[""]' }} browser: ${{ toJSON(matrix.canary-config.browser) || '[""]' }} timeout_minutes: ${{ matrix.canary-config.timeout_minutes || 35 }} - retry_count: ${{ matrix.canary-config.retry_count || 3 }} \ No newline at end of file + retry_count: ${{ matrix.canary-config.retry_count || 3 }} diff --git a/package.json b/package.json index 1c5e52a5091..a427664243c 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "json-loader": "^0.5.7", "lerna": "^7.4.2", "license-check-and-add": "^4.0.5", - "prettier": "^2.4.1", + "prettier": "^3.1.0", "rimraf": "^2.6.2", "rollup": "^0.67.4", "rollup-plugin-commonjs": "^9.2.0", diff --git a/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts b/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts index b1ae7366d1c..3094472548f 100644 --- a/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts +++ b/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts @@ -49,7 +49,7 @@ describe('createCookieStorageAdapterFromNextServerContext', () => { ({ get: mockGetFunc, getAll: mockGetAllFunc, - } as any) + }) as any ); jest.spyOn(response, 'cookies', 'get').mockImplementation(() => ({ @@ -124,13 +124,13 @@ describe('createCookieStorageAdapterFromNextServerContext', () => { ({ get: mockGetFunc, getAll: mockGetAllFunc, - } as any) + }) as any ); jest.spyOn(response, 'headers', 'get').mockImplementation( () => ({ append: mockAppend, - } as any) + }) as any ); const mockContext = { diff --git a/packages/adapter-nextjs/src/api/generateServerClient.ts b/packages/adapter-nextjs/src/api/generateServerClient.ts index 22490a5e2ab..841e4c4ee9e 100644 --- a/packages/adapter-nextjs/src/api/generateServerClient.ts +++ b/packages/adapter-nextjs/src/api/generateServerClient.ts @@ -44,7 +44,7 @@ type ReqClientParams = { * const result = await client.graphql({ query: listPosts }); */ export function generateServerClientUsingCookies< - T extends Record = never + T extends Record = never, >({ config, cookies, @@ -99,7 +99,7 @@ export function generateServerClientUsingCookies< * }); */ export function generateServerClientUsingReqRes< - T extends Record = never + T extends Record = never, >({ config, authMode, authToken }: ReqClientParams): V6ClientSSRRequest { const amplifyConfig = getAmplifyConfig(config); // passing `null` instance because each (future model) method must retrieve a valid instance diff --git a/packages/analytics/src/types/inputs.ts b/packages/analytics/src/types/inputs.ts index 7eedad05a6c..2d7f2a8fcde 100644 --- a/packages/analytics/src/types/inputs.ts +++ b/packages/analytics/src/types/inputs.ts @@ -13,7 +13,7 @@ import { * Input type for `identifyUser`. */ export type AnalyticsIdentifyUserInput< - ServiceOptions extends AnalyticsServiceOptions = AnalyticsServiceOptions + ServiceOptions extends AnalyticsServiceOptions = AnalyticsServiceOptions, > = { /** * A User ID associated to the current device. diff --git a/packages/analytics/src/utils/groupBy.ts b/packages/analytics/src/utils/groupBy.ts index 014483a195f..c11dd6f225d 100644 --- a/packages/analytics/src/utils/groupBy.ts +++ b/packages/analytics/src/utils/groupBy.ts @@ -5,8 +5,11 @@ export const groupBy = ( getGroupId: (x: T) => string, list: T[] ): Record => { - return list.reduce((result, current) => { - const groupId = getGroupId(current); - return { ...result, [groupId]: [...(result[groupId] ?? []), current] }; - }, {} as Record); + return list.reduce( + (result, current) => { + const groupId = getGroupId(current); + return { ...result, [groupId]: [...(result[groupId] ?? []), current] }; + }, + {} as Record + ); }; diff --git a/packages/analytics/tsconfig.json b/packages/analytics/tsconfig.json index 5f6d8cbfa41..f907c964821 100644 --- a/packages/analytics/tsconfig.json +++ b/packages/analytics/tsconfig.json @@ -1,9 +1,9 @@ { - "extends": "../tsconfig.base.json", - "compilerOptions": { - "importHelpers": true, - "strict": true, - "noImplicitAny": true - }, - "include": ["./src"], + "extends": "../tsconfig.base.json", + "compilerOptions": { + "importHelpers": true, + "strict": true, + "noImplicitAny": true + }, + "include": ["./src"] } diff --git a/packages/api-graphql/src/internals/server/generateClient.ts b/packages/api-graphql/src/internals/server/generateClient.ts index c1860c703be..9ea530b8f75 100644 --- a/packages/api-graphql/src/internals/server/generateClient.ts +++ b/packages/api-graphql/src/internals/server/generateClient.ts @@ -26,7 +26,7 @@ export function generateClient< T extends Record = never, ClientType extends | V6ClientSSRRequest - | V6ClientSSRCookies = V6ClientSSRCookies + | V6ClientSSRCookies = V6ClientSSRCookies, >( params: ServerClientGenerationParams & CommonPublicClientOptions ): ClientType { diff --git a/packages/api-graphql/src/internals/v6.ts b/packages/api-graphql/src/internals/v6.ts index 67393e0ef48..337758e4451 100644 --- a/packages/api-graphql/src/internals/v6.ts +++ b/packages/api-graphql/src/internals/v6.ts @@ -97,7 +97,7 @@ import { CustomHeaders } from '@aws-amplify/data-schema-types'; */ export function graphql< FALLBACK_TYPES = unknown, - TYPED_GQL_STRING extends string = string + TYPED_GQL_STRING extends string = string, >( this: V6Client, options: GraphQLOptionsV6, diff --git a/packages/api-graphql/src/types/index.ts b/packages/api-graphql/src/types/index.ts index e15ad853fd6..ff4c1a98b95 100644 --- a/packages/api-graphql/src/types/index.ts +++ b/packages/api-graphql/src/types/index.ts @@ -96,10 +96,10 @@ type PagedList = { type WithListsFixed = T extends PagedList ? PagedList, NAME> : T extends {} - ? { - [K in keyof T]: WithListsFixed; - } - : T; + ? { + [K in keyof T]: WithListsFixed; + } + : T; /** * Returns an updated response type to always return a value. @@ -205,7 +205,7 @@ export type GraphQLOperation = Source | string; */ export interface GraphQLOptionsV6< FALLBACK_TYPES = unknown, - TYPED_GQL_STRING extends string = string + TYPED_GQL_STRING extends string = string, > { query: TYPED_GQL_STRING | DocumentNode; variables?: GraphQLVariablesV6; @@ -234,16 +234,16 @@ export type UnknownGraphQLResponse = */ export type GraphQLVariablesV6< FALLBACK_TYPES = unknown, - TYPED_GQL_STRING extends string = string + TYPED_GQL_STRING extends string = string, > = TYPED_GQL_STRING extends GeneratedQuery ? IN : TYPED_GQL_STRING extends GeneratedMutation - ? IN - : TYPED_GQL_STRING extends GeneratedSubscription - ? IN - : FALLBACK_TYPES extends GraphQLOperationType - ? IN - : any; + ? IN + : TYPED_GQL_STRING extends GeneratedSubscription + ? IN + : FALLBACK_TYPES extends GraphQLOperationType + ? IN + : any; /** * The expected return type with respect to the given `FALLBACK_TYPE` @@ -251,20 +251,23 @@ export type GraphQLVariablesV6< */ export type GraphQLResponseV6< FALLBACK_TYPE = unknown, - TYPED_GQL_STRING extends string = string + TYPED_GQL_STRING extends string = string, > = TYPED_GQL_STRING extends GeneratedQuery ? Promise>> : TYPED_GQL_STRING extends GeneratedMutation - ? Promise>> - : TYPED_GQL_STRING extends GeneratedSubscription - ? GraphqlSubscriptionResult> - : FALLBACK_TYPE extends GraphQLQuery - ? Promise> - : FALLBACK_TYPE extends GraphQLSubscription - ? GraphqlSubscriptionResult - : FALLBACK_TYPE extends GraphQLOperationType - ? CUSTOM_OUT - : UnknownGraphQLResponse; + ? Promise>> + : TYPED_GQL_STRING extends GeneratedSubscription + ? GraphqlSubscriptionResult> + : FALLBACK_TYPE extends GraphQLQuery + ? Promise> + : FALLBACK_TYPE extends GraphQLSubscription + ? GraphqlSubscriptionResult + : FALLBACK_TYPE extends GraphQLOperationType< + infer IN, + infer CUSTOM_OUT + > + ? CUSTOM_OUT + : UnknownGraphQLResponse; /** * The shape customers can use to provide `T` to `graphql()` to specify both @@ -407,7 +410,7 @@ export type V6ClientSSRCookies = never> = export type GraphQLMethod = < FALLBACK_TYPES = unknown, - TYPED_GQL_STRING extends string = string + TYPED_GQL_STRING extends string = string, >( options: GraphQLOptionsV6, additionalHeaders?: CustomHeaders | undefined @@ -415,7 +418,7 @@ export type GraphQLMethod = < export type GraphQLMethodSSR = < FALLBACK_TYPES = unknown, - TYPED_GQL_STRING extends string = string + TYPED_GQL_STRING extends string = string, >( contextSpec: AmplifyServer.ContextSpec, options: GraphQLOptionsV6, diff --git a/packages/api/src/internals/InternalAPI.ts b/packages/api/src/internals/InternalAPI.ts index 5e5662a5fc0..d9d7aa56281 100644 --- a/packages/api/src/internals/InternalAPI.ts +++ b/packages/api/src/internals/InternalAPI.ts @@ -72,11 +72,11 @@ export class InternalAPIClass { ): T extends GraphQLQuery ? Promise> : T extends GraphQLSubscription - ? Observable<{ - provider: AWSAppSyncRealTimeProvider; - value: GraphQLResult; - }> - : Promise> | Observable; + ? Observable<{ + provider: AWSAppSyncRealTimeProvider; + value: GraphQLResult; + }> + : Promise> | Observable; graphql( options: GraphQLOptions, additionalHeaders?: CustomHeaders, diff --git a/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts b/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts index 200f1659164..11d1a30812e 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts @@ -73,9 +73,8 @@ describe('signIn API happy path cases', () => { .spyOn(initiateAuthHelpers, 'handleUserPasswordAuthFlow') .mockImplementation( async (): Promise => { - const deviceKeys = await tokenOrchestrator.getDeviceMetadata( - lastAuthUser - ); + const deviceKeys = + await tokenOrchestrator.getDeviceMetadata(lastAuthUser); if (deviceKeys) { throw new AuthError({ name: 'ResourceNotFoundException', diff --git a/packages/auth/__tests__/providers/cognito/testUtils/data.ts b/packages/auth/__tests__/providers/cognito/testUtils/data.ts index 1df7d043c1f..9a7dfb0a0ed 100644 --- a/packages/auth/__tests__/providers/cognito/testUtils/data.ts +++ b/packages/auth/__tests__/providers/cognito/testUtils/data.ts @@ -78,4 +78,3 @@ export function buildMockErrorResponse(errorName: string): { }, }; } - diff --git a/packages/auth/__tests__/utils/openAuthSession.test.ts b/packages/auth/__tests__/utils/openAuthSession.test.ts index b0dd69c3a7a..6dc046d1312 100644 --- a/packages/auth/__tests__/utils/openAuthSession.test.ts +++ b/packages/auth/__tests__/utils/openAuthSession.test.ts @@ -12,7 +12,7 @@ describe('openAuthSession', () => { // create mocks beforeAll(() => { - windowSpy.mockImplementation(() => ({ location } as any)); + windowSpy.mockImplementation(() => ({ location }) as any); }); beforeEach(() => { diff --git a/packages/auth/jest.setup.js b/packages/auth/jest.setup.js index 82b8d276385..961fd1f6625 100644 --- a/packages/auth/jest.setup.js +++ b/packages/auth/jest.setup.js @@ -10,7 +10,7 @@ if ( const crypto = require('crypto'); Object.defineProperty(globalThis, 'crypto', { - value: { - getRandomValues: arr => crypto.randomBytes(arr.length) - } + value: { + getRandomValues: arr => crypto.randomBytes(arr.length), + }, }); diff --git a/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts b/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts index b19dcc1ecf1..718e8ca6ca0 100644 --- a/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts +++ b/packages/auth/src/providers/cognito/apis/internal/fetchUserAttributes.ts @@ -25,9 +25,9 @@ export const fetchUserAttributes = async ( assertAuthTokens(tokens); const { UserAttributes } = await getUser( - { - region: getRegion(authConfig.userPoolId), - userAgentValue: getAuthUserAgentValue(AuthAction.FetchUserAttributes) + { + region: getRegion(authConfig.userPoolId), + userAgentValue: getAuthUserAgentValue(AuthAction.FetchUserAttributes), }, { AccessToken: tokens.accessToken.toString(), diff --git a/packages/auth/src/providers/cognito/types/models.ts b/packages/auth/src/providers/cognito/types/models.ts index f763b494a0c..ae9dbc90acd 100644 --- a/packages/auth/src/providers/cognito/types/models.ts +++ b/packages/auth/src/providers/cognito/types/models.ts @@ -107,5 +107,5 @@ export interface AuthUser extends AWSAuthUser { * Holds data describing the dispatch of a confirmation code. */ export type CodeDeliveryDetails< - CognitoUserAttributeKey extends UserAttributeKey = UserAttributeKey + CognitoUserAttributeKey extends UserAttributeKey = UserAttributeKey, > = AuthCodeDeliveryDetails; diff --git a/packages/auth/src/providers/cognito/utils/signInHelpers.ts b/packages/auth/src/providers/cognito/utils/signInHelpers.ts index d12ec03682c..372ed25e700 100644 --- a/packages/auth/src/providers/cognito/utils/signInHelpers.ts +++ b/packages/auth/src/providers/cognito/utils/signInHelpers.ts @@ -1082,7 +1082,7 @@ export async function getNewDeviceMetatada( * */ export async function retryOnResourceNotFoundException< - F extends (...args: any[]) => any + F extends (...args: any[]) => any, >( func: F, args: Parameters, diff --git a/packages/auth/src/providers/cognito/utils/signInWithRedirectStore.ts b/packages/auth/src/providers/cognito/utils/signInWithRedirectStore.ts index c31892a562d..79b5df9acf7 100644 --- a/packages/auth/src/providers/cognito/utils/signInWithRedirectStore.ts +++ b/packages/auth/src/providers/cognito/utils/signInWithRedirectStore.ts @@ -123,9 +123,8 @@ export class DefaultOAuthStore implements OAuthStore { this.cognitoConfig.userPoolClientId ); - const isLegacyHostedUISignIn = await this.keyValueStorage.getItem( - V5_HOSTED_UI_KEY - ); + const isLegacyHostedUISignIn = + await this.keyValueStorage.getItem(V5_HOSTED_UI_KEY); const [isOAuthSignIn, preferPrivateSession] = (await this.keyValueStorage.getItem(authKeys.oauthSignIn))?.split(',') ?? diff --git a/packages/auth/src/types/inputs.ts b/packages/auth/src/types/inputs.ts index 1f8aa0ddb3e..2e326686ef4 100644 --- a/packages/auth/src/types/inputs.ts +++ b/packages/auth/src/types/inputs.ts @@ -10,7 +10,7 @@ import { import { AuthServiceOptions, AuthSignUpOptions } from './options'; export type AuthConfirmResetPasswordInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { username: string; newPassword: string; @@ -25,21 +25,21 @@ export type AuthConfirmResetPasswordInput< * @param options - optional parameters for the Sign Up process such as the plugin options */ export type AuthResendSignUpCodeInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { username: string; options?: ServiceOptions; }; export type AuthResetPasswordInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { username: string; options?: ServiceOptions; }; export type AuthSignInInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { username: string; password?: string; @@ -76,7 +76,8 @@ export type AuthSignInWithRedirectInput = { * @param options - optional parameters for the Sign Up process, including user attributes */ export type AuthSignUpInput< - ServiceOptions extends AuthSignUpOptions = AuthSignUpOptions + ServiceOptions extends + AuthSignUpOptions = AuthSignUpOptions, > = { username: string; password: string; @@ -91,7 +92,7 @@ export type AuthSignUpInput< * @param options - optional parameters for the Sign Up process, including user attributes */ export type AuthConfirmSignUpInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { username: string; confirmationCode: string; @@ -105,7 +106,7 @@ export type AuthConfirmSignUpInput< * @param options - optional parameters for the Confirm Sign In process such as the service options */ export type AuthConfirmSignInInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { challengeResponse: string; options?: ServiceOptions; @@ -118,7 +119,7 @@ export type AuthConfirmSignInInput< * @param options - optional parameters for the Verify TOTP Setup process such as the service options. */ export type AuthVerifyTOTPSetupInput< - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { code: string; options?: ServiceOptions; @@ -143,7 +144,7 @@ export type AuthUpdatePasswordInput = { */ export type AuthUpdateUserAttributesInput< UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { userAttributes: AuthUserAttributes; options?: ServiceOptions; @@ -156,7 +157,7 @@ export type AuthUpdateUserAttributesInput< */ export type AuthUpdateUserAttributeInput< UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { userAttribute: AuthUserAttribute; options?: ServiceOptions; @@ -170,7 +171,7 @@ export type AuthUpdateUserAttributeInput< * */ export type AuthConfirmUserAttributeInput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { userAttributeKey: UserAttributeKey; confirmationCode: string }; /** @@ -181,7 +182,7 @@ export type AuthConfirmUserAttributeInput< */ export type AuthSendUserAttributeVerificationCodeInput< UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, - ServiceOptions extends AuthServiceOptions = AuthServiceOptions + ServiceOptions extends AuthServiceOptions = AuthServiceOptions, > = { userAttributeKey: UserAttributeKey; options?: ServiceOptions; @@ -193,7 +194,7 @@ export type AuthSendUserAttributeVerificationCodeInput< * @param userAttributeKeys - the user attribute keys to be deleted */ export type AuthDeleteUserAttributesInput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { userAttributeKeys: [UserAttributeKey, ...UserAttributeKey[]] }; /** diff --git a/packages/auth/src/types/models.ts b/packages/auth/src/types/models.ts index 10259c042e3..08ff0c4f016 100644 --- a/packages/auth/src/types/models.ts +++ b/packages/auth/src/types/models.ts @@ -20,7 +20,7 @@ export type AuthDeliveryMedium = 'EMAIL' | 'SMS' | 'PHONE' | 'UNKNOWN'; * Data describing the dispatch of a confirmation code. */ export type AuthCodeDeliveryDetails< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { destination?: string; deliveryMedium?: AuthDeliveryMedium; @@ -31,7 +31,7 @@ export type AuthCodeDeliveryDetails< */ export type AuthResetPasswordStep = 'CONFIRM_RESET_PASSWORD_WITH_CODE' | 'DONE'; export type AuthNextResetPasswordStep< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { resetPasswordStep: AuthResetPasswordStep; additionalInfo?: AuthAdditionalInfo; @@ -106,7 +106,7 @@ export type ConfirmSignInWithCustomChallenge = { }; export type ConfirmSignInWithNewPasswordRequired< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { /** * Auth step requires user to change their password with any required attributes. @@ -173,7 +173,7 @@ export type DoneSignInStep = { }; export type AuthNextSignInStep< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = | ConfirmSignInWithCustomChallenge | ContinueSignInWithMFASelection @@ -189,7 +189,7 @@ export type AuthNextSignInStep< * Key/value pairs describing a user attributes. */ export type AuthUserAttributes< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { [Attribute in UserAttributeKey]?: string; }; @@ -198,7 +198,7 @@ export type AuthUserAttributes< * The interface of a user attribute. */ export type AuthUserAttribute< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { attributeKey: UserAttributeKey; value: string; @@ -226,7 +226,7 @@ export type AuthUpdateAttributeStep = * Data encapsulating the next step in the Sign Up process */ export type AuthNextSignUpStep< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = | ConfirmSignUpSignUpStep | AutoSignInSignUpStep @@ -238,21 +238,21 @@ export type DoneSignUpStep = { }; export type ConfirmSignUpSignUpStep< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { signUpStep: 'CONFIRM_SIGN_UP'; codeDeliveryDetails: AuthCodeDeliveryDetails; }; export type AutoSignInSignUpStep< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { signUpStep: 'COMPLETE_AUTO_SIGN_IN'; codeDeliveryDetails?: AuthCodeDeliveryDetails; }; export type AuthNextUpdateAttributeStep< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { updateAttributeStep: AuthUpdateAttributeStep; codeDeliveryDetails?: AuthCodeDeliveryDetails; diff --git a/packages/auth/src/types/options.ts b/packages/auth/src/types/options.ts index fcf13f839c3..d026ef3bfb6 100644 --- a/packages/auth/src/types/options.ts +++ b/packages/auth/src/types/options.ts @@ -15,7 +15,7 @@ export type AuthServiceOptions = Record; * Particular services may require some of these parameters. */ export type AuthSignUpOptions< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { userAttributes: AuthUserAttributes; }; diff --git a/packages/auth/src/types/outputs.ts b/packages/auth/src/types/outputs.ts index aa6a49c7546..5e1d65cd3be 100644 --- a/packages/auth/src/types/outputs.ts +++ b/packages/auth/src/types/outputs.ts @@ -10,14 +10,14 @@ import { } from './models'; export type AuthSignInOutput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { isSignedIn: boolean; nextStep: AuthNextSignInStep; }; export type AuthSignUpOutput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { isSignUpComplete: boolean; userId?: string; @@ -25,21 +25,21 @@ export type AuthSignUpOutput< }; export type AuthResetPasswordOutput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { isPasswordReset: boolean; nextStep: AuthNextResetPasswordStep; }; export type AuthUpdateUserAttributeOutput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { isUpdated: boolean; nextStep: AuthNextUpdateAttributeStep; }; export type AuthUpdateUserAttributesOutput< - UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey + UserAttributeKey extends AuthUserAttributeKey = AuthUserAttributeKey, > = { [authKey in UserAttributeKey]: AuthUpdateUserAttributeOutput; }; diff --git a/packages/core/__mocks__/SessionStorage.js b/packages/core/__mocks__/SessionStorage.js index 356f1f19433..54a0f228dd7 100644 --- a/packages/core/__mocks__/SessionStorage.js +++ b/packages/core/__mocks__/SessionStorage.js @@ -75,6 +75,6 @@ class SessionStorageMock { } } -if (typeof window !== 'undefined') { +if (typeof window !== 'undefined') { window.sessionStorage = new SessionStorageMock(); } diff --git a/packages/core/__tests__/providers/pinpoint/utils/EventBuffer.test.ts b/packages/core/__tests__/providers/pinpoint/utils/EventBuffer.test.ts index d2c1349e62b..52cc67ff816 100644 --- a/packages/core/__tests__/providers/pinpoint/utils/EventBuffer.test.ts +++ b/packages/core/__tests__/providers/pinpoint/utils/EventBuffer.test.ts @@ -6,14 +6,14 @@ const DEFAULT_CONFIG = { appId: 'app-id', credentials: { accessKeyId: 'access-key-id', - secretAccessKey: 'secret-access-key' + secretAccessKey: 'secret-access-key', }, identityId: 'identity-id', bufferSize: 1000, flushSize: 100, flushInterval: 5 * 1000, // 5s resendLimit: 5, - region: 'region' + region: 'region', }; const EVENT_OBJECT = { @@ -34,7 +34,7 @@ const EVENT_OBJECT = { credentials: {}, session: { Id: 'session-id', - StartTimestamp: 'start-timestamp' + StartTimestamp: 'start-timestamp', }, resendLimit: 5, }; diff --git a/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts b/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts index 7192da1964e..fe2347a0259 100644 --- a/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts +++ b/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts @@ -1,12 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { - appId, - credentials, - identityId, - region, -} from '../testUtils/data'; +import { appId, credentials, identityId, region } from '../testUtils/data'; import { getEventBuffer } from '../../../../src/providers/pinpoint/utils/getEventBuffer'; import { PinpointEventBuffer } from '../../../../src/providers/pinpoint/utils/PinpointEventBuffer'; @@ -21,8 +16,8 @@ const mockConfig = { flushSize: 50, identityId, region, - resendLimit: 5 -} + resendLimit: 5, +}; describe('Pinpoint Provider Util: bufferManager', () => { const mockPinpointEventBuffer = PinpointEventBuffer as jest.Mock; @@ -35,11 +30,11 @@ describe('Pinpoint Provider Util: bufferManager', () => { mockPinpointEventBuffer.mockReset(); mockPinpointEventBuffer.mockImplementation(() => ({ identityHasChanged: mockIdentityHasChanged, - flush: mockFlush - })) + flush: mockFlush, + })); }); - it('creates a buffer if one doesn\'t exist', async () => { + it("creates a buffer if one doesn't exist", async () => { const testBuffer = getEventBuffer(mockConfig); expect(mockPinpointEventBuffer).toBeCalledWith(mockConfig); diff --git a/packages/core/src/Cache/types/index.ts b/packages/core/src/Cache/types/index.ts index 5ca15b25bd6..c2c1db22a6f 100644 --- a/packages/core/src/Cache/types/index.ts +++ b/packages/core/src/Cache/types/index.ts @@ -1,4 +1,4 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 - -export * from './cache'; +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export * from './cache'; diff --git a/packages/core/src/Hub/index.ts b/packages/core/src/Hub/index.ts index e1808a345d9..e80b42ab0fb 100644 --- a/packages/core/src/Hub/index.ts +++ b/packages/core/src/Hub/index.ts @@ -51,7 +51,7 @@ export class HubClass { */ private _remove< Channel extends AmplifyChannel | string = string, - EventData extends EventDataMap = EventDataMap + EventData extends EventDataMap = EventDataMap, >(channel: Channel, listener: HubCallback) { const holder = this.listeners.get(channel); if (!holder) { @@ -89,7 +89,7 @@ export class HubClass { dispatch< Channel extends AmplifyChannel | string, - EventData extends EventDataMap = EventDataMap + EventData extends EventDataMap = EventDataMap, >( channel: Channel | string, payload: HubPayload, @@ -134,7 +134,7 @@ export class HubClass { */ listen< Channel extends AmplifyChannel, - EventData extends EventDataMap = EventDataMap + EventData extends EventDataMap = EventDataMap, >( channel: Channel, callback: HubCallback, @@ -149,7 +149,7 @@ export class HubClass { listen< Channel extends AmplifyChannel | string = string, - EventData extends EventDataMap = EventDataMap + EventData extends EventDataMap = EventDataMap, >( channel: Channel, callback: HubCallback, diff --git a/packages/core/src/Hub/types/HubTypes.ts b/packages/core/src/Hub/types/HubTypes.ts index 88b90bd5d59..2f4d59a589b 100644 --- a/packages/core/src/Hub/types/HubTypes.ts +++ b/packages/core/src/Hub/types/HubTypes.ts @@ -5,7 +5,7 @@ import { AuthHubEventData } from './AuthTypes'; export type IListener< Channel extends string = AmplifyChannel | string, - EventData extends EventDataMap = EventDataMap + EventData extends EventDataMap = EventDataMap, > = { name: string; callback: HubCallback; @@ -23,7 +23,7 @@ export type StopListenerCallback = () => void; export type HubCapsule< Channel extends string, - EventData extends EventDataMap + EventData extends EventDataMap, > = { channel: Channel; payload: HubPayload; @@ -33,7 +33,7 @@ export type HubCapsule< export type HubCallback< Channel extends string = string, - EventData extends EventDataMap = EventDataMap + EventData extends EventDataMap = EventDataMap, > = (capsule: HubCapsule) => void; export type HubPayload = diff --git a/packages/core/src/clients/internal/composeServiceApi.ts b/packages/core/src/clients/internal/composeServiceApi.ts index b7f861a5bc3..650c59fb1e5 100644 --- a/packages/core/src/clients/internal/composeServiceApi.ts +++ b/packages/core/src/clients/internal/composeServiceApi.ts @@ -9,7 +9,7 @@ export const composeServiceApi = < TransferHandlerOptions, Input, Output, - DefaultConfig + DefaultConfig, >( transferHandler: TransferHandler< HttpRequest, diff --git a/packages/core/src/clients/internal/composeTransferHandler.ts b/packages/core/src/clients/internal/composeTransferHandler.ts index fd9deeddbd4..edb0137c1bd 100644 --- a/packages/core/src/clients/internal/composeTransferHandler.ts +++ b/packages/core/src/clients/internal/composeTransferHandler.ts @@ -26,7 +26,7 @@ export const composeTransferHandler = Request, Response, any - > = TransferHandler + > = TransferHandler, >( coreHandler: CoreHandler, middleware: OptionToMiddleware @@ -56,34 +56,34 @@ export const composeTransferHandler = type OptionToMiddleware< Request extends RequestBase, Response extends ResponseBase, - Options extends any[] + Options extends any[], > = Options extends [] ? [] : Options extends [infer LastOption] - ? [Middleware] - : Options extends [infer FirstOption, ...infer RestOptions] - ? [ - Middleware, - ...OptionToMiddleware - ] - : never; + ? [Middleware] + : Options extends [infer FirstOption, ...infer RestOptions] + ? [ + Middleware, + ...OptionToMiddleware, + ] + : never; /** * Type to intersect multiple types if they have no conflict keys. */ type MergeNoConflictKeys = Options extends [ - infer OnlyOption + infer OnlyOption, ] ? OnlyOption : Options extends [infer FirstOption, infer SecondOption] - ? FirstOption & SecondOption - : Options extends [infer FirstOption, ...infer RestOptions] - ? FirstOption & MergeNoConflictKeys - : never; + ? FirstOption & SecondOption + : Options extends [infer FirstOption, ...infer RestOptions] + ? FirstOption & MergeNoConflictKeys + : never; /** * Type to infer the option type of a transfer handler type. */ type InferOptionTypeFromTransferHandler< - T extends TransferHandler + T extends TransferHandler, > = Parameters[1]; diff --git a/packages/core/src/clients/middleware/signing/signer/signatureV4/signRequest.ts b/packages/core/src/clients/middleware/signing/signer/signatureV4/signRequest.ts index 132236fe4b4..4e19be6b431 100644 --- a/packages/core/src/clients/middleware/signing/signer/signatureV4/signRequest.ts +++ b/packages/core/src/clients/middleware/signing/signer/signatureV4/signRequest.ts @@ -43,9 +43,8 @@ export const signRequest = ( const credentialEntry = `Credential=${accessKeyId}/${credentialScope}`; const signedHeadersEntry = `SignedHeaders=${getSignedHeaders(headers)}`; const signatureEntry = `Signature=${signature}`; - headers[ - AUTH_HEADER - ] = `${SHA256_ALGORITHM_IDENTIFIER} ${credentialEntry}, ${signedHeadersEntry}, ${signatureEntry}`; + headers[AUTH_HEADER] = + `${SHA256_ALGORITHM_IDENTIFIER} ${credentialEntry}, ${signedHeadersEntry}, ${signatureEntry}`; return requestToSign; }; diff --git a/packages/core/src/clients/types/core.ts b/packages/core/src/clients/types/core.ts index d369312cd40..c510b2eed73 100644 --- a/packages/core/src/clients/types/core.ts +++ b/packages/core/src/clients/types/core.ts @@ -16,7 +16,7 @@ export interface Response { export interface TransferHandler< Input extends Request, Output extends Response, - TransferOptions + TransferOptions, > { (request: Input, options: TransferOptions): Promise; } @@ -49,7 +49,7 @@ type ConfiguredMiddleware = ( export type Middleware< Input extends Request, Output extends Response, - MiddlewareOptions + MiddlewareOptions, > = (options: MiddlewareOptions) => ConfiguredMiddleware; export interface Endpoint { diff --git a/packages/core/src/global.d.ts b/packages/core/src/global.d.ts index d2e571148d5..2f78bef6184 100644 --- a/packages/core/src/global.d.ts +++ b/packages/core/src/global.d.ts @@ -4,7 +4,7 @@ declare global { interface Window { FB: any; - gapi: any; + gapi: any; } } diff --git a/packages/datastore-storage-adapter/.npmignore b/packages/datastore-storage-adapter/.npmignore index 329f5cdc2dd..92866a5d2e7 100644 --- a/packages/datastore-storage-adapter/.npmignore +++ b/packages/datastore-storage-adapter/.npmignore @@ -6,7 +6,6 @@ node_modules/** .vscode/** .DS_Store *.log -prettier.config.json tsconfig.json tsfmt.json tslint.json diff --git a/packages/datastore-storage-adapter/jest.setup.js b/packages/datastore-storage-adapter/jest.setup.js index c8e9543debe..a0f3d5370fa 100644 --- a/packages/datastore-storage-adapter/jest.setup.js +++ b/packages/datastore-storage-adapter/jest.setup.js @@ -2,6 +2,6 @@ const crypto = require('crypto'); Object.defineProperty(globalThis, 'crypto', { value: { - getRandomValues: arr => crypto.randomBytes(arr.length) - } + getRandomValues: arr => crypto.randomBytes(arr.length), + }, }); diff --git a/packages/datastore-storage-adapter/src/common/CommonSQLiteAdapter.ts b/packages/datastore-storage-adapter/src/common/CommonSQLiteAdapter.ts index 395c34ca2e1..a6ccf3a97c2 100644 --- a/packages/datastore-storage-adapter/src/common/CommonSQLiteAdapter.ts +++ b/packages/datastore-storage-adapter/src/common/CommonSQLiteAdapter.ts @@ -85,8 +85,8 @@ export class CommonSQLiteAdapter implements StorageAdapter { const usesCPKCodegen = Object.values( this.schema.namespaces.user.models ).some(model => - Object.values(model.fields).some(field => - field.association?.hasOwnProperty('targetNames') + Object.values(model.fields).some( + field => field.association?.hasOwnProperty('targetNames') ) ); if (usesCPKCodegen) { diff --git a/packages/datastore/.npmignore b/packages/datastore/.npmignore index 329f5cdc2dd..92866a5d2e7 100644 --- a/packages/datastore/.npmignore +++ b/packages/datastore/.npmignore @@ -6,7 +6,6 @@ node_modules/** .vscode/** .DS_Store *.log -prettier.config.json tsconfig.json tsfmt.json tslint.json diff --git a/packages/datastore/__tests__/AsyncStorage.ts b/packages/datastore/__tests__/AsyncStorage.ts index b73378542f4..3887ff7fe9d 100644 --- a/packages/datastore/__tests__/AsyncStorage.ts +++ b/packages/datastore/__tests__/AsyncStorage.ts @@ -593,7 +593,7 @@ describe('AsyncStorage tests', () => { const oldData: [ string, - string[] + string[], ] = require('./AsyncStorage.migration.data.json'); inmemoryMap.clear(); diff --git a/packages/datastore/__tests__/DataStore.ts b/packages/datastore/__tests__/DataStore.ts index 636972153a3..e90ae98bb9d 100644 --- a/packages/datastore/__tests__/DataStore.ts +++ b/packages/datastore/__tests__/DataStore.ts @@ -4729,9 +4729,8 @@ describe('DataStore tests', () => { describe('Query with generic type', () => { test('all', async () => { - const allPostCustomPKs = await DataStore.query( - PostCustomPK - ); + const allPostCustomPKs = + await DataStore.query(PostCustomPK); expectType(allPostCustomPKs); diff --git a/packages/datastore/__tests__/Predicate.ts b/packages/datastore/__tests__/Predicate.ts index d8167452dba..6c24e9950da 100644 --- a/packages/datastore/__tests__/Predicate.ts +++ b/packages/datastore/__tests__/Predicate.ts @@ -221,9 +221,8 @@ describe('Predicates', () => { test('match on eq', async () => { const query = recursivePredicateFor(AuthorMeta).name.eq('Adam West'); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -238,9 +237,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.eq('Adam West') ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -254,9 +252,8 @@ describe('Predicates', () => { test('match on ne', async () => { const query = recursivePredicateFor(AuthorMeta).name.ne('Adam West'); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -271,9 +268,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.ne('Adam West') ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -287,9 +283,8 @@ describe('Predicates', () => { test('match on gt', async () => { const query = recursivePredicateFor(AuthorMeta).name.gt('Clarice Starling'); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -304,9 +299,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.gt('Clarice Starling') ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -320,9 +314,8 @@ describe('Predicates', () => { test('match on ge', async () => { const query = recursivePredicateFor(AuthorMeta).name.ge('Clarice Starling'); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -337,9 +330,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.ge('Clarice Starling') ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -353,9 +345,8 @@ describe('Predicates', () => { test('match on lt', async () => { const query = recursivePredicateFor(AuthorMeta).name.lt('Clarice Starling'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -370,9 +361,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.lt('Clarice Starling') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -386,9 +376,8 @@ describe('Predicates', () => { test('match on le', async () => { const query = recursivePredicateFor(AuthorMeta).name.le('Clarice Starling'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -403,9 +392,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.le('Clarice Starling') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -419,9 +407,8 @@ describe('Predicates', () => { test('match beginsWith', async () => { const query = recursivePredicateFor(AuthorMeta).name.beginsWith('Debbie'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -436,9 +423,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.beginsWith('Debbie') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -456,9 +442,8 @@ describe('Predicates', () => { '0', '{' ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(m => m.name)).toEqual([ 'Adam West', @@ -475,9 +460,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.between('0', '{') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(0); }); @@ -487,9 +471,8 @@ describe('Predicates', () => { 'Bob Jones', 'Debbie Donut' ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -504,9 +487,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.between('Bob Jones', 'Debbie Donut') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -522,9 +504,8 @@ describe('Predicates', () => { 'Az', 'E' ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -539,9 +520,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.between('Az', 'E') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -557,9 +537,8 @@ describe('Predicates', () => { '{', '}' ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(0); }); @@ -568,9 +547,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.between('{', '}') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(5); }); @@ -578,9 +556,8 @@ describe('Predicates', () => { test('match contains', async () => { const query = recursivePredicateFor(AuthorMeta).name.contains('Jones'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -595,9 +572,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.contains('Jones') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -611,9 +587,8 @@ describe('Predicates', () => { test('match notContains', async () => { const query = recursivePredicateFor(AuthorMeta).name.notContains('Jones'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -628,9 +603,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.notContains('Jones') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -645,9 +619,8 @@ describe('Predicates', () => { describe('on boolean fields', () => { test('match on eq', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.eq(true); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -662,9 +635,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.eq(true) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -677,9 +649,8 @@ describe('Predicates', () => { test('match on ne', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.ne(true); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -694,9 +665,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.ne(true) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -709,9 +679,8 @@ describe('Predicates', () => { test('match on gt true', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.gt(true); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(0); }); @@ -720,18 +689,16 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.gt(true) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(5); }); test('match on gt false', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.gt(false); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -746,9 +713,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.gt(false) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -763,9 +729,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.ge(true) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -778,9 +743,8 @@ describe('Predicates', () => { test('match on ge false', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.ge(false); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(5); }); @@ -789,18 +753,16 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.ge(false) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(0); }); test('match on lt true', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.lt(true); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -815,9 +777,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.lt(true) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -830,9 +791,8 @@ describe('Predicates', () => { test('match on lt false', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.lt(false); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(0); }); @@ -841,18 +801,16 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.lt(false) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(5); }); test('match on le true', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.le(true); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(5); }); @@ -861,18 +819,16 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.le(true) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.length).toBe(0); }); test('match on le false', async () => { const query = recursivePredicateFor(AuthorMeta).isActive.le(false); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -887,9 +843,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.isActive.le(false) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -904,9 +859,8 @@ describe('Predicates', () => { describe('on int fields', () => { test('match on eq', async () => { const query = recursivePredicateFor(AuthorMeta).karma.eq(3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -921,9 +875,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.eq(3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -936,9 +889,8 @@ describe('Predicates', () => { test('match on ne', async () => { const query = recursivePredicateFor(AuthorMeta).karma.ne(3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -953,9 +905,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.ne(3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -968,9 +919,8 @@ describe('Predicates', () => { test('match on gt', async () => { const query = recursivePredicateFor(AuthorMeta).karma.gt(3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -985,9 +935,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.gt(3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1000,9 +949,8 @@ describe('Predicates', () => { test('match on ge', async () => { const query = recursivePredicateFor(AuthorMeta).karma.ge(3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1017,9 +965,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.ge(3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1032,9 +979,8 @@ describe('Predicates', () => { test('match on lt', async () => { const query = recursivePredicateFor(AuthorMeta).karma.lt(3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1049,9 +995,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.lt(3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1064,9 +1009,8 @@ describe('Predicates', () => { test('match on le', async () => { const query = recursivePredicateFor(AuthorMeta).karma.le(3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1081,9 +1025,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.le(3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1096,9 +1039,8 @@ describe('Predicates', () => { test('match on between', async () => { const query = recursivePredicateFor(AuthorMeta).karma.between(1, 3); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1113,9 +1055,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.karma.between(1, 3) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1130,9 +1071,8 @@ describe('Predicates', () => { describe('on float fields', () => { test('match on eq', async () => { const query = recursivePredicateFor(AuthorMeta).rating.eq(0.75); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1147,9 +1087,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.eq(0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1162,9 +1101,8 @@ describe('Predicates', () => { test('match on ne', async () => { const query = recursivePredicateFor(AuthorMeta).rating.ne(0.75); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1179,9 +1117,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.ne(0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1194,9 +1131,8 @@ describe('Predicates', () => { test('match on gt', async () => { const query = recursivePredicateFor(AuthorMeta).rating.gt(0.75); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1211,9 +1147,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.gt(0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1226,9 +1161,8 @@ describe('Predicates', () => { test('match on ge', async () => { const query = recursivePredicateFor(AuthorMeta).rating.ge(0.75); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1243,9 +1177,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.ge(0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1258,9 +1191,8 @@ describe('Predicates', () => { test('match on lt', async () => { const query = recursivePredicateFor(AuthorMeta).rating.lt(0.75); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1275,9 +1207,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.lt(0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1290,9 +1221,8 @@ describe('Predicates', () => { test('match on le', async () => { const query = recursivePredicateFor(AuthorMeta).rating.le(0.75); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1307,9 +1237,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.le(0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1325,9 +1254,8 @@ describe('Predicates', () => { 0.25, 0.75 ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ // 'Adam West', @@ -1342,9 +1270,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.rating.between(0.25, 0.75) ); - const matches = await mechanism.execute< - ModelOf> - >(query); + const matches = + await mechanism.execute>>(query); expect(matches.map(n => n.name)).toEqual([ 'Adam West', @@ -1426,9 +1353,8 @@ describe('Predicates', () => { a.name.contains('Bob'), a.name.contains('Jones'), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches[0].name).toBe('Bob Jones'); @@ -1441,9 +1367,8 @@ describe('Predicates', () => { a.name.contains('Jones'), ]) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(n => n.name)).not.toContain('Bob Jones'); @@ -1454,9 +1379,8 @@ describe('Predicates', () => { a.name.contains('Adam'), a.name.contains('Donut'), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(0); }); @@ -1468,9 +1392,8 @@ describe('Predicates', () => { a.name.contains('Donut'), ]) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(5); }); @@ -1480,9 +1403,8 @@ describe('Predicates', () => { a.name.contains('Bob'), a.name.contains('Donut'), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(m => m.name)).toEqual([ @@ -1498,9 +1420,8 @@ describe('Predicates', () => { a.name.contains('Donut'), ]) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(3); expect(matches.map(m => m.name)).not.toContain('Bob Jones'); @@ -1512,9 +1433,8 @@ describe('Predicates', () => { a.name.contains('Bob'), a.name.contains('Jones'), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches[0].name).toEqual('Bob Jones'); @@ -1527,9 +1447,8 @@ describe('Predicates', () => { a.name.contains('Jones'), ]) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(n => n.name)).not.toContain('Bob Jones'); @@ -1540,9 +1459,8 @@ describe('Predicates', () => { a.name.contains('Bob'), a.name.contains('Thanos'), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches[0].name).toEqual('Bob Jones'); @@ -1553,9 +1471,8 @@ describe('Predicates', () => { a.name.contains('Thanos'), a.name.contains('Thor (God of Thunder, as it just so happens)'), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(0); }); @@ -1571,9 +1488,8 @@ describe('Predicates', () => { a.name.contains('from the Legend of Zelda'), ]), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(m => m.name)).toEqual(['Bob Jones']); @@ -1590,9 +1506,8 @@ describe('Predicates', () => { a.name.contains('from the Legend of Zelda'), ]), ]); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(m => m.name)).toEqual(['Debbie Donut']); @@ -1611,9 +1526,8 @@ describe('Predicates', () => { ]), ]) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(m => m.name)).not.toContain('Debbie Donut'); @@ -1623,9 +1537,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.eq('Bob Jones') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(m => m.name)).toEqual([ @@ -1640,9 +1553,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a => a.name.gt('0') ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(0); }); @@ -1655,9 +1567,8 @@ describe('Predicates', () => { a.name.between('C', 'D'), ]) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(m => m.name)).toEqual([ @@ -1670,9 +1581,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a1 => a1.not(a2 => a2.name.eq('Bob Jones')) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(m => m.name)).toEqual(['Bob Jones']); @@ -1682,9 +1592,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a1 => a1.not(a2 => a2.not(a3 => a3.name.eq('Bob Jones'))) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(m => m.name)).toEqual([ @@ -1699,9 +1608,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(AuthorMeta).not(a1 => a1.not(a2 => a2.not(a3 => a3.not(a4 => a4.name.eq('Bob Jones')))) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(m => m.name)).toEqual(['Bob Jones']); @@ -1719,9 +1627,8 @@ describe('Predicates', () => { const query = (V1Predicates.ALL as any)( recursivePredicateFor(AuthorMeta) ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(5); expect(matches.map(m => m.name)).toEqual([ @@ -1772,9 +1679,8 @@ describe('Predicates', () => { test('can select non-null values by their defined values', async () => { const query = recursivePredicateFor(PersonMeta).username.eq('defined 01'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(n => n.username)).toEqual(['defined 01']); @@ -1784,9 +1690,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(PersonMeta).username.ne( null as any ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(n => n.username)).toEqual([ @@ -1798,9 +1703,8 @@ describe('Predicates', () => { test('can select non-null values by searching for != undefined', async () => { const query = recursivePredicateFor(PersonMeta).username.ne(undefined); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(n => n.username)).toEqual([ @@ -1813,9 +1717,8 @@ describe('Predicates', () => { const query = recursivePredicateFor(PersonMeta).username.eq( null as any ); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(3); expect(matches.map(n => n.username)).toEqual([null, null, null]); @@ -1824,9 +1727,8 @@ describe('Predicates', () => { test('can select null values by searching for == undefined', async () => { const query = recursivePredicateFor(PersonMeta).username.eq(undefined); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(3); expect(matches.map(n => n.username)).toEqual([null, null, null]); @@ -1837,9 +1739,8 @@ describe('Predicates', () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).username.eq('defined 01'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(n => n.username)).toEqual(['defined 01']); }); @@ -1848,9 +1749,8 @@ describe('Predicates', () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).username.ne('defined 01'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(n => n.username)).toEqual([ null, @@ -1863,9 +1763,8 @@ describe('Predicates', () => { test('gt', async () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).age.gt(1); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(1); expect(matches.map(n => n.username)).toEqual(['defined 02']); }); @@ -1873,9 +1772,8 @@ describe('Predicates', () => { test('ge', async () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).age.ge(1); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(n => n.username)).toEqual([ 'defined 01', @@ -1886,9 +1784,8 @@ describe('Predicates', () => { test('lt', async () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).age.lt(2); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(4); expect(matches.map(n => n.username)).toEqual([ null, @@ -1901,9 +1798,8 @@ describe('Predicates', () => { test('le', async () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).age.le(2); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(5); expect(matches.map(n => n.username)).toEqual([ null, @@ -1918,9 +1814,8 @@ describe('Predicates', () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).username.contains('defined'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(n => n.username)).toEqual([ 'defined 01', @@ -1932,9 +1827,8 @@ describe('Predicates', () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).username.notContains('defined'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(3); expect(matches.map(n => n.username)).toEqual([null, null, null]); }); @@ -1943,9 +1837,8 @@ describe('Predicates', () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).username.beginsWith('defined'); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(n => n.username)).toEqual([ 'defined 01', @@ -1956,9 +1849,8 @@ describe('Predicates', () => { test('between', async () => { expect.assertions(2); const query = recursivePredicateFor(PersonMeta).age.between(1, 2); - const matches = await mechanism.execute>( - query - ); + const matches = + await mechanism.execute>(query); expect(matches.length).toBe(2); expect(matches.map(n => n.username)).toEqual([ 'defined 01', diff --git a/packages/datastore/__tests__/connectivityHandling.test.ts b/packages/datastore/__tests__/connectivityHandling.test.ts index 0a8cd7b7406..de2281b996f 100644 --- a/packages/datastore/__tests__/connectivityHandling.test.ts +++ b/packages/datastore/__tests__/connectivityHandling.test.ts @@ -2187,8 +2187,9 @@ describe('DataStore sync engine', () => { }; await resyncWith([ - syncExpression(LegacyJSONPost, p => - p?.title.eq("whatever, it doesn't matter.") + syncExpression( + LegacyJSONPost, + p => p?.title.eq("whatever, it doesn't matter.") ), ]); diff --git a/packages/datastore/jest.setup.js b/packages/datastore/jest.setup.js index c8e9543debe..a0f3d5370fa 100644 --- a/packages/datastore/jest.setup.js +++ b/packages/datastore/jest.setup.js @@ -2,6 +2,6 @@ const crypto = require('crypto'); Object.defineProperty(globalThis, 'crypto', { value: { - getRandomValues: arr => crypto.randomBytes(arr.length) - } + getRandomValues: arr => crypto.randomBytes(arr.length), + }, }); diff --git a/packages/datastore/src/datastore/datastore.ts b/packages/datastore/src/datastore/datastore.ts index 8ccbac67bad..ebd29d1c73c 100644 --- a/packages/datastore/src/datastore/datastore.ts +++ b/packages/datastore/src/datastore/datastore.ts @@ -835,8 +835,8 @@ const createModelClass = ( const id = isInternalModel ? _id : modelDefinition.syncable - ? amplifyUuid() - : ulid(); + ? amplifyUuid() + : ulid(); ((draft)).id = id; } else if (isIdOptionallyManaged(modelDefinition)) { @@ -1740,7 +1740,7 @@ class DataStore { const initPatchesTuple = initPatches.has(model) ? ([initPatches.get(model)!, {}] as [ Patch[], - Readonly> + Readonly>, ]) : undefined; diff --git a/packages/datastore/src/storage/adapter/AsyncStorageDatabase.ts b/packages/datastore/src/storage/adapter/AsyncStorageDatabase.ts index 2a50e232b83..99fc190c4e1 100644 --- a/packages/datastore/src/storage/adapter/AsyncStorageDatabase.ts +++ b/packages/datastore/src/storage/adapter/AsyncStorageDatabase.ts @@ -170,9 +170,8 @@ class AsyncStorageDatabase { } } - const existingRecordsMap: [string, string][] = await this.storage.multiGet( - allItemsKeys - ); + const existingRecordsMap: [string, string][] = + await this.storage.multiGet(allItemsKeys); const existingRecordsKeys = existingRecordsMap .filter(([, v]) => !!v) .reduce((set, [k]) => set.add(k), new Set()); diff --git a/packages/datastore/src/sync/index.ts b/packages/datastore/src/sync/index.ts index a8274dcbae3..e3b72b8cc1d 100644 --- a/packages/datastore/src/sync/index.ts +++ b/packages/datastore/src/sync/index.ts @@ -598,9 +598,8 @@ export class SyncEngine { * merged individually. Otherwise, we can merge them in batches. */ await this.storage.runExclusive(async storage => { - const idsInOutbox = await this.outbox.getModelIds( - storage - ); + const idsInOutbox = + await this.outbox.getModelIds(storage); const oneByOne: ModelInstanceMetadata[] = []; const page = items.filter(item => { diff --git a/packages/datastore/src/sync/processors/subscription.ts b/packages/datastore/src/sync/processors/subscription.ts index 025d5abf1d4..36ddaeb8513 100644 --- a/packages/datastore/src/sync/processors/subscription.ts +++ b/packages/datastore/src/sync/processors/subscription.ts @@ -247,7 +247,7 @@ class SubscriptionProcessor { start(): [ Observable, - Observable<[TransformerMutationType, SchemaModel, PersistentModel]> + Observable<[TransformerMutationType, SchemaModel, PersistentModel]>, ] { this.runningProcesses = this.runningProcesses || new BackgroundProcessManager(); diff --git a/packages/datastore/src/sync/utils.ts b/packages/datastore/src/sync/utils.ts index 0904151230d..bc1c42f99ea 100644 --- a/packages/datastore/src/sync/utils.ts +++ b/packages/datastore/src/sync/utils.ts @@ -411,7 +411,7 @@ export function buildGraphQLOperation( } export function createMutationInstanceFromModelOperation< - T extends PersistentModel + T extends PersistentModel, >( relationships: RelationshipType, modelDefinition: SchemaModel, diff --git a/packages/datastore/src/types.ts b/packages/datastore/src/types.ts index 9d8ceb1d899..a39c83864de 100644 --- a/packages/datastore/src/types.ts +++ b/packages/datastore/src/types.ts @@ -454,34 +454,34 @@ export type Identifier = export type IdentifierFields< T extends PersistentModel, - M extends PersistentModelMetaData = never + M extends PersistentModelMetaData = never, > = (MetadataOrDefault['identifier'] extends | ManagedIdentifier | OptionallyManagedIdentifier ? MetadataOrDefault['identifier']['field'] : MetadataOrDefault['identifier'] extends CompositeIdentifier< - T, - infer B - > - ? B[number] // B[number] - : MetadataOrDefault['identifier']['field']) & + T, + infer B + > + ? B[number] // B[number] + : MetadataOrDefault['identifier']['field']) & string; export type IdentifierFieldsForInit< T extends PersistentModel, - M extends PersistentModelMetaData + M extends PersistentModelMetaData, > = MetadataOrDefault['identifier'] extends | DefaultPersistentModelMetaData | ManagedIdentifier ? never : MetadataOrDefault['identifier'] extends OptionallyManagedIdentifier< - T, - any - > - ? IdentifierFields - : MetadataOrDefault['identifier'] extends CompositeIdentifier - ? IdentifierFields - : never; + T, + any + > + ? IdentifierFields + : MetadataOrDefault['identifier'] extends CompositeIdentifier + ? IdentifierFields + : never; // Instance of model export declare const __modelMeta__: unique symbol; @@ -500,18 +500,18 @@ export type SettableFieldType = T extends Promise ? InnerPromiseType | null : InnerPromiseType : T extends AsyncCollection - ? InnerCollectionType[] | undefined - : undefined extends T - ? T | null - : T; + ? InnerCollectionType[] | undefined + : undefined extends T + ? T | null + : T; export type PredicateFieldType = NonNullable< Scalar< T extends Promise ? InnerPromiseType : T extends AsyncCollection - ? InnerCollectionType - : T + ? InnerCollectionType + : T > >; @@ -545,7 +545,7 @@ export type DefaultPersistentModelMetaData = { export type MetadataOrDefault< T extends PersistentModel, - _ extends PersistentModelMetaData = never + _ extends PersistentModelMetaData = never, > = T extends { [__modelMeta__]: PersistentModelMetaData; } @@ -556,7 +556,7 @@ export type PersistentModel = Readonly>; export type MetadataReadOnlyFields< T extends PersistentModel, - M extends PersistentModelMetaData + M extends PersistentModelMetaData, > = Extract< MetadataOrDefault['readOnlyFields'] | M['readOnlyFields'], keyof T @@ -569,7 +569,7 @@ export type MetadataReadOnlyFields< // This type makes optional some identifiers in the constructor init object (e.g. OptionallyManagedIdentifier) export type ModelInitBase< T extends PersistentModel, - M extends PersistentModelMetaData = {} + M extends PersistentModelMetaData = {}, > = Omit< T, typeof __modelMeta__ | IdentifierFields | MetadataReadOnlyFields @@ -583,7 +583,7 @@ export type ModelInitBase< export type ModelInit< T extends PersistentModel, - M extends PersistentModelMetaData = {} + M extends PersistentModelMetaData = {}, > = { [P in keyof OmitOptionalRelatives>]: SettableFieldType< ModelInitBase[P] @@ -598,17 +598,17 @@ type DeepWritable = { -readonly [P in keyof T]: T[P] extends TypeName ? T[P] : T[P] extends Promise - ? undefined extends InnerPromiseType - ? InnerPromiseType | null - : InnerPromiseType - : T[P] extends AsyncCollection - ? InnerCollectionType[] | undefined | null - : DeepWritable; + ? undefined extends InnerPromiseType + ? InnerPromiseType | null + : InnerPromiseType + : T[P] extends AsyncCollection + ? InnerCollectionType[] | undefined | null + : DeepWritable; }; export type MutableModel< T extends PersistentModel, - M extends PersistentModelMetaData = {} + M extends PersistentModelMetaData = {}, // This provides Intellisense with ALL of the properties, regardless of read-only // but will throw a linting error if trying to overwrite a read-only property > = DeepWritable< @@ -624,7 +624,7 @@ export type ModelInstanceMetadata = { export type IdentifierFieldValue< T extends PersistentModel, - M extends PersistentModelMetaData + M extends PersistentModelMetaData, > = MetadataOrDefault['identifier'] extends CompositeIdentifier ? MetadataOrDefault['identifier']['fields'] extends [any] ? T[MetadataOrDefault['identifier']['fields'][0]] @@ -633,7 +633,7 @@ export type IdentifierFieldValue< export type IdentifierFieldOrIdentifierObject< T extends PersistentModel, - M extends PersistentModelMetaData + M extends PersistentModelMetaData, > = Pick> | IdentifierFieldValue; export function isIdentifierObject( @@ -678,7 +678,7 @@ export type DataStoreSnapshot = { export type PredicateExpression< M extends PersistentModel, - FT + FT, > = TypeName extends keyof MapTypeToOperands ? ( operator: keyof MapTypeToOperands[TypeName], @@ -726,16 +726,16 @@ type MapTypeToOperands = { type TypeName = T extends string ? 'string' : T extends number - ? 'number' - : T extends boolean - ? 'boolean' - : T extends string[] - ? 'string[]' - : T extends number[] - ? 'number[]' - : T extends boolean[] - ? 'boolean[]' - : never; + ? 'number' + : T extends boolean + ? 'boolean' + : T extends string[] + ? 'string[]' + : T extends number[] + ? 'number[]' + : T extends boolean[] + ? 'boolean[]' + : never; export type PredicateGroups = { and: ( @@ -843,7 +843,7 @@ export type SortPredicate = { export type SortPredicateExpression< M extends PersistentModel, - FT + FT, > = TypeName extends keyof MapTypeToOperands ? (sortDirection: keyof typeof SortDirection) => SortPredicate : never; @@ -1028,7 +1028,7 @@ type ConditionProducer> = ( export async function syncExpression< T extends PersistentModel, - A extends Option + A extends Option, >( modelConstructor: PersistentModelConstructor, conditionProducer: ConditionProducer @@ -1149,7 +1149,7 @@ export type RecursiveModelPredicateExtender = ( ) => PredicateInternalsKey; export type RecursiveModelPredicateAggregateExtender< - RT extends PersistentModel + RT extends PersistentModel, > = (lambda: RecursiveModelPredicate) => PredicateInternalsKey[]; export type RecursiveModelPredicateOperator = ( @@ -1201,7 +1201,7 @@ export type ModelPredicateAggregateExtender = ( export type ValuePredicate< RT extends PersistentModel, - MT extends MatchableTypes + MT extends MatchableTypes, > = { [K in AllFieldOperators]: K extends 'between' ? ( diff --git a/packages/geo/__tests__/Providers/AmazonLocationServiceProvider.test.ts b/packages/geo/__tests__/Providers/AmazonLocationServiceProvider.test.ts index 49bc2093ee4..c44e391b21a 100644 --- a/packages/geo/__tests__/Providers/AmazonLocationServiceProvider.test.ts +++ b/packages/geo/__tests__/Providers/AmazonLocationServiceProvider.test.ts @@ -601,9 +601,8 @@ describe('AmazonLocationServiceProvider', () => { awsConfigGeoV4 ); - const results = await locationProvider.searchByCoordinates( - testCoordinates - ); + const results = + await locationProvider.searchByCoordinates(testCoordinates); expect(results).toEqual(testPlaceCamelCase); const spyon = jest.spyOn(LocationClient.prototype, 'send'); diff --git a/packages/notifications/__tests__/inAppMessaging/utils/processInAppMessages.test.ts b/packages/notifications/__tests__/inAppMessaging/utils/processInAppMessages.test.ts index de8c6112467..ef764ec2d77 100644 --- a/packages/notifications/__tests__/inAppMessaging/utils/processInAppMessages.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/utils/processInAppMessages.test.ts @@ -3,7 +3,7 @@ import { pinpointInAppMessage, - simpleInAppMessagingEvent + simpleInAppMessagingEvent, } from '../../testUtils/data'; import { incrementMessageCounts, diff --git a/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/helpers.ts b/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/helpers.ts index 8b596b43a1d..be0a1bb5b24 100644 --- a/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/helpers.ts +++ b/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/helpers.ts @@ -98,8 +98,8 @@ export const matchesAttributes = ( if (!eventAttributesMemo.hasOwnProperty(memoKey)) { eventAttributesMemo[memoKey] = !Attributes || - Object.entries(Attributes).every(([key, { Values }]) => - Values?.includes(attributes[key]) + Object.entries(Attributes).every( + ([key, { Values }]) => Values?.includes(attributes[key]) ); } return eventAttributesMemo[memoKey]; diff --git a/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/messageProcessingHelpers.ts b/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/messageProcessingHelpers.ts index 960ae44828c..fe22b139b87 100644 --- a/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/messageProcessingHelpers.ts +++ b/packages/notifications/src/inAppMessaging/providers/pinpoint/utils/messageProcessingHelpers.ts @@ -76,9 +76,8 @@ export function sessionStateChangeHandler(state: SessionState): void { } export async function incrementMessageCounts(messageId: string): Promise { - const { sessionCount, dailyCount, totalCount } = await getMessageCounts( - messageId - ); + const { sessionCount, dailyCount, totalCount } = + await getMessageCounts(messageId); setSessionCount(messageId, sessionCount + 1); setDailyCount(dailyCount + 1); await setTotalCount(messageId, totalCount + 1); @@ -106,9 +105,8 @@ async function isBelowCap({ DailyCap, TotalCap, }: PinpointInAppMessage): Promise { - const { sessionCount, dailyCount, totalCount } = await getMessageCounts( - CampaignId - ); + const { sessionCount, dailyCount, totalCount } = + await getMessageCounts(CampaignId); return ( (!SessionCap || sessionCount < SessionCap) && diff --git a/packages/notifications/src/inAppMessaging/types/inputs.ts b/packages/notifications/src/inAppMessaging/types/inputs.ts index ee0666eff16..75e653cdb9f 100644 --- a/packages/notifications/src/inAppMessaging/types/inputs.ts +++ b/packages/notifications/src/inAppMessaging/types/inputs.ts @@ -8,7 +8,8 @@ import { InAppMessagingServiceOptions } from '.'; * Input type for `identifyUser`. */ export type InAppMessagingIdentifyUserInput< - ServiceOptions extends InAppMessagingServiceOptions = InAppMessagingServiceOptions + ServiceOptions extends + InAppMessagingServiceOptions = InAppMessagingServiceOptions, > = { /** * A User ID associated to the current device. diff --git a/packages/notifications/src/pushNotifications/types/inputs.ts b/packages/notifications/src/pushNotifications/types/inputs.ts index 0c0c0d8019c..994c345e658 100644 --- a/packages/notifications/src/pushNotifications/types/inputs.ts +++ b/packages/notifications/src/pushNotifications/types/inputs.ts @@ -10,7 +10,8 @@ import { } from './pushNotifications'; export type PushNotificationIdentifyUserInput< - ServiceOptions extends PushNotificationServiceOptions = PushNotificationServiceOptions + ServiceOptions extends + PushNotificationServiceOptions = PushNotificationServiceOptions, > = { /** * A User ID associated to the current device. diff --git a/packages/predictions/src/providers/AmazonAIIdentifyPredictionsProvider.ts b/packages/predictions/src/providers/AmazonAIIdentifyPredictionsProvider.ts index 006f68a1d7a..5c749eb465d 100644 --- a/packages/predictions/src/providers/AmazonAIIdentifyPredictionsProvider.ts +++ b/packages/predictions/src/providers/AmazonAIIdentifyPredictionsProvider.ts @@ -203,9 +203,8 @@ export class AmazonAIIdentifyPredictionsProvider { }; const detectTextCommand = new DetectTextCommand(rekognitionParam); - const rekognitionData = await this.rekognitionClient.send( - detectTextCommand - ); + const rekognitionData = + await this.rekognitionClient.send(detectTextCommand); const rekognitionResponse = categorizeRekognitionBlocks( rekognitionData.TextDetections as TextDetectionList @@ -400,7 +399,7 @@ export class AmazonAIIdentifyPredictionsProvider { ...makeCamelCase(celebrity, ['Id', 'Name', 'Urls']), pose: makeCamelCase(celebrity.Face?.Pose), }, - } as IdentifyEntity) + }) as IdentifyEntity ) ?? []; return { entities: faces }; } else if ( diff --git a/packages/pubsub/src/vendor/paho-mqtt.js b/packages/pubsub/src/vendor/paho-mqtt.js index dd467e5f623..d5899c55c01 100644 --- a/packages/pubsub/src/vendor/paho-mqtt.js +++ b/packages/pubsub/src/vendor/paho-mqtt.js @@ -2819,10 +2819,10 @@ function onMessageArrived(message) { typeof global !== 'undefined' ? global : typeof self !== 'undefined' - ? self - : typeof window !== 'undefined' - ? window - : {} + ? self + : typeof window !== 'undefined' + ? window + : {} ); return PahoMQTT; }); diff --git a/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts b/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts index 88e89ec4071..237508ee9af 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/testUtils/types.ts @@ -20,7 +20,7 @@ type ApiFunctionalTestHappyCase any> = [ Parameters[1], // input HttpRequest, // expected request MockFetchResponse, // response - Awaited> // expected output + Awaited>, // expected output ]; type ApiFunctionalTestErrorCase any> = [ @@ -31,7 +31,7 @@ type ApiFunctionalTestErrorCase any> = [ Parameters[1], // input HttpRequest, // expected request MockFetchResponse, // response - {} // error + {}, // error ]; /** diff --git a/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts b/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts index 4dd5e2f8178..7ac7029a8d1 100644 --- a/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts +++ b/packages/storage/src/providers/s3/utils/client/utils/parsePayload.ts @@ -18,8 +18,8 @@ export const parseXmlError: ErrorParser = async (response?: HttpResponse) => { const code = body?.['Code'] ? (body.Code as string) : statusCode === 404 - ? 'NotFound' - : statusCode.toString(); + ? 'NotFound' + : statusCode.toString(); const message = body?.['message'] ?? body?.['Message'] ?? code; const error = new Error(message); return Object.assign(error, { diff --git a/packages/storage/src/types/inputs.ts b/packages/storage/src/types/inputs.ts index a8602bf5bfd..0a8e709137d 100644 --- a/packages/storage/src/types/inputs.ts +++ b/packages/storage/src/types/inputs.ts @@ -21,7 +21,7 @@ export type StorageRemoveInput = { }; export type StorageListInput< - Options extends StorageListAllOptions | StorageListPaginateOptions + Options extends StorageListAllOptions | StorageListPaginateOptions, > = { prefix?: string; options?: Options; @@ -40,7 +40,7 @@ export type StorageUploadDataInput = export type StorageCopyInput< SourceOptions extends StorageOptions, - DestinationOptions extends StorageOptions + DestinationOptions extends StorageOptions, > = { source: SourceOptions; destination: DestinationOptions; diff --git a/.prettierrc.js b/prettier.config.js similarity index 71% rename from .prettierrc.js rename to prettier.config.js index 1ddacd85aeb..e2b1a6a467c 100644 --- a/.prettierrc.js +++ b/prettier.config.js @@ -1,3 +1,4 @@ +/** @type {import('prettier').Config} */ module.exports = { trailingComma: 'es5', singleQuote: true, diff --git a/yarn.lock b/yarn.lock index c0bc1ce293f..51bc5fc63d9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -12757,10 +12757,10 @@ prelude-ls@~1.1.2: resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== -prettier@^2.4.1: - version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +prettier@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" + integrity sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw== pretty-format@29.4.3: version "29.4.3" From a353e0d777a1ca5e57aa4b2cda48d147ee1d4803 Mon Sep 17 00:00:00 2001 From: Chris F <5827964+cshfang@users.noreply.github.com> Date: Mon, 27 Nov 2023 22:38:18 -0800 Subject: [PATCH 03/15] fix: refactor to avoid importing from current index (#12636) --- .../src/providers/pinpoint/types/inputs.ts | 2 +- packages/analytics/src/types/inputs.ts | 2 +- .../CognitoUserPoolsTokenProvider.ts | 44 ++++++++++++++ .../cognito/tokenProvider/cacheTokens.ts | 4 +- .../providers/cognito/tokenProvider/index.ts | 59 +++---------------- .../cognito/tokenProvider/tokenProvider.ts | 10 ++++ .../providers/pinpoint/types/inputs.ts | 4 +- .../src/inAppMessaging/types/inputs.ts | 2 +- 8 files changed, 68 insertions(+), 59 deletions(-) create mode 100644 packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts create mode 100644 packages/auth/src/providers/cognito/tokenProvider/tokenProvider.ts diff --git a/packages/analytics/src/providers/pinpoint/types/inputs.ts b/packages/analytics/src/providers/pinpoint/types/inputs.ts index 5dbd0880d50..acb28b68c4a 100644 --- a/packages/analytics/src/providers/pinpoint/types/inputs.ts +++ b/packages/analytics/src/providers/pinpoint/types/inputs.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { PinpointAnalyticsEvent } from '@aws-amplify/core/internals/providers/pinpoint'; -import { IdentifyUserOptions } from '.'; +import { IdentifyUserOptions } from './options'; import { AnalyticsConfigureAutoTrackInput, AnalyticsIdentifyUserInput, diff --git a/packages/analytics/src/types/inputs.ts b/packages/analytics/src/types/inputs.ts index 2d7f2a8fcde..6f3911ad52b 100644 --- a/packages/analytics/src/types/inputs.ts +++ b/packages/analytics/src/types/inputs.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { UserProfile } from '@aws-amplify/core'; -import { AnalyticsServiceOptions } from '.'; +import { AnalyticsServiceOptions } from './options'; import { SessionTrackingOptions, PageViewTrackingOptions, diff --git a/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts b/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts new file mode 100644 index 00000000000..cae8a50fa36 --- /dev/null +++ b/packages/auth/src/providers/cognito/tokenProvider/CognitoUserPoolsTokenProvider.ts @@ -0,0 +1,44 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { + AuthConfig, + AuthTokens, + FetchAuthSessionOptions, + KeyValueStorageInterface, + defaultStorage, +} from '@aws-amplify/core'; +import { refreshAuthTokens } from '../utils/refreshAuthTokens'; +import { DefaultTokenStore } from './TokenStore'; +import { TokenOrchestrator } from './TokenOrchestrator'; +import { CognitoUserPoolTokenProviderType } from './types'; + +export class CognitoUserPoolsTokenProvider + implements CognitoUserPoolTokenProviderType +{ + authTokenStore: DefaultTokenStore; + tokenOrchestrator: TokenOrchestrator; + constructor() { + this.authTokenStore = new DefaultTokenStore(); + this.authTokenStore.setKeyValueStorage(defaultStorage); + this.tokenOrchestrator = new TokenOrchestrator(); + this.tokenOrchestrator.setAuthTokenStore(this.authTokenStore); + this.tokenOrchestrator.setTokenRefresher(refreshAuthTokens); + } + getTokens( + { forceRefresh }: FetchAuthSessionOptions = { forceRefresh: false } + ): Promise { + return this.tokenOrchestrator.getTokens({ forceRefresh }); + } + + setKeyValueStorage(keyValueStorage: KeyValueStorageInterface): void { + this.authTokenStore.setKeyValueStorage(keyValueStorage); + } + setWaitForInflightOAuth(waitForInflightOAuth: () => Promise): void { + this.tokenOrchestrator.setWaitForInflightOAuth(waitForInflightOAuth); + } + setAuthConfig(authConfig: AuthConfig) { + this.authTokenStore.setAuthConfig(authConfig); + this.tokenOrchestrator.setAuthConfig(authConfig); + } +} diff --git a/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts b/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts index 6aa385dd9a4..acd5ee07f47 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/cacheTokens.ts @@ -1,10 +1,10 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { AmplifyError, decodeJWT } from '@aws-amplify/core/internals/utils'; -import { tokenOrchestrator } from '.'; +import { CognitoAuthSignInDetails } from '../types'; import { AuthenticationResultType } from '../utils/clients/CognitoIdentityProvider/types'; +import { tokenOrchestrator } from './tokenProvider'; import { CognitoAuthTokens, DeviceMetadata } from './types'; -import { CognitoAuthSignInDetails } from '../types'; export async function cacheCognitoTokens( AuthenticationResult: AuthenticationResultType & { diff --git a/packages/auth/src/providers/cognito/tokenProvider/index.ts b/packages/auth/src/providers/cognito/tokenProvider/index.ts index bc2ac570b53..c44dc5e8325 100644 --- a/packages/auth/src/providers/cognito/tokenProvider/index.ts +++ b/packages/auth/src/providers/cognito/tokenProvider/index.ts @@ -1,56 +1,11 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { - AuthConfig, - AuthTokens, - FetchAuthSessionOptions, - KeyValueStorageInterface, - defaultStorage, -} from '@aws-amplify/core'; -import { refreshAuthTokens } from '../utils/refreshAuthTokens'; -import { DefaultTokenStore } from './TokenStore'; -import { TokenOrchestrator } from './TokenOrchestrator'; -import { CognitoUserPoolTokenProviderType } from './types'; - -class CognitoUserPoolsTokenProviderClass - implements CognitoUserPoolTokenProviderType -{ - authTokenStore: DefaultTokenStore; - tokenOrchestrator: TokenOrchestrator; - constructor() { - this.authTokenStore = new DefaultTokenStore(); - this.authTokenStore.setKeyValueStorage(defaultStorage); - this.tokenOrchestrator = new TokenOrchestrator(); - this.tokenOrchestrator.setAuthTokenStore(this.authTokenStore); - this.tokenOrchestrator.setTokenRefresher(refreshAuthTokens); - } - getTokens( - { forceRefresh }: FetchAuthSessionOptions = { forceRefresh: false } - ): Promise { - return this.tokenOrchestrator.getTokens({ forceRefresh }); - } - - setKeyValueStorage(keyValueStorage: KeyValueStorageInterface): void { - this.authTokenStore.setKeyValueStorage(keyValueStorage); - } - setWaitForInflightOAuth(waitForInflightOAuth: () => Promise): void { - this.tokenOrchestrator.setWaitForInflightOAuth(waitForInflightOAuth); - } - setAuthConfig(authConfig: AuthConfig) { - this.authTokenStore.setAuthConfig(authConfig); - this.tokenOrchestrator.setAuthConfig(authConfig); - } -} - -export const cognitoUserPoolsTokenProvider = - new CognitoUserPoolsTokenProviderClass(); - -export const tokenOrchestrator = - cognitoUserPoolsTokenProvider.tokenOrchestrator; +export { refreshAuthTokens } from '../utils/refreshAuthTokens'; +export { DefaultTokenStore } from './TokenStore'; +export { TokenOrchestrator } from './TokenOrchestrator'; +export { CognitoUserPoolTokenProviderType } from './types'; export { - CognitoUserPoolTokenProviderType, - DefaultTokenStore, - TokenOrchestrator, - refreshAuthTokens, -}; + cognitoUserPoolsTokenProvider, + tokenOrchestrator, +} from './tokenProvider'; diff --git a/packages/auth/src/providers/cognito/tokenProvider/tokenProvider.ts b/packages/auth/src/providers/cognito/tokenProvider/tokenProvider.ts new file mode 100644 index 00000000000..7e5135395f4 --- /dev/null +++ b/packages/auth/src/providers/cognito/tokenProvider/tokenProvider.ts @@ -0,0 +1,10 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { CognitoUserPoolsTokenProvider } from './CognitoUserPoolsTokenProvider'; + +export const cognitoUserPoolsTokenProvider = + new CognitoUserPoolsTokenProvider(); + +export const tokenOrchestrator = + cognitoUserPoolsTokenProvider.tokenOrchestrator; diff --git a/packages/notifications/src/inAppMessaging/providers/pinpoint/types/inputs.ts b/packages/notifications/src/inAppMessaging/providers/pinpoint/types/inputs.ts index d98ac12d22b..092bdd88b91 100644 --- a/packages/notifications/src/inAppMessaging/providers/pinpoint/types/inputs.ts +++ b/packages/notifications/src/inAppMessaging/providers/pinpoint/types/inputs.ts @@ -1,11 +1,11 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { IdentifyUserOptions } from './options'; import { - IdentifyUserOptions, InAppMessageConflictHandler, OnMessageInteractionEventHandler, -} from '.'; +} from './types'; import { InAppMessage, InAppMessageInteractionEvent, diff --git a/packages/notifications/src/inAppMessaging/types/inputs.ts b/packages/notifications/src/inAppMessaging/types/inputs.ts index 75e653cdb9f..0df082ea000 100644 --- a/packages/notifications/src/inAppMessaging/types/inputs.ts +++ b/packages/notifications/src/inAppMessaging/types/inputs.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { UserProfile } from '@aws-amplify/core'; -import { InAppMessagingServiceOptions } from '.'; +import { InAppMessagingServiceOptions } from './options'; /** * Input type for `identifyUser`. From e2c5b5738e3747676a17c20a18d7d0d400a08fd1 Mon Sep 17 00:00:00 2001 From: erinleigh90 <106691284+erinleigh90@users.noreply.github.com> Date: Tue, 28 Nov 2023 11:19:02 -0700 Subject: [PATCH 04/15] fix: determine timeoutid type based on return type of setTimeout (#12641) --- packages/core/src/clients/middleware/retry/middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/core/src/clients/middleware/retry/middleware.ts b/packages/core/src/clients/middleware/retry/middleware.ts index f3323375c7e..9a00dd270c7 100644 --- a/packages/core/src/clients/middleware/retry/middleware.ts +++ b/packages/core/src/clients/middleware/retry/middleware.ts @@ -109,7 +109,7 @@ const cancellableSleep = (timeoutMs: number, abortSignal?: AbortSignal) => { if (abortSignal?.aborted) { return Promise.resolve(); } - let timeoutId: number; + let timeoutId: ReturnType; let sleepPromiseResolveFn: Function; const sleepPromise = new Promise(resolve => { sleepPromiseResolveFn = resolve; From cf3a619c323bbf91baf4d192142dfca2d13a7ddd Mon Sep 17 00:00:00 2001 From: Venkata Ramyasri Kota <34170013+kvramyasri7@users.noreply.github.com> Date: Tue, 28 Nov 2023 10:57:48 -0800 Subject: [PATCH 05/15] chore: comment and remove failing and not need canaries (#12642) * chore: comment and remove failing and not need canaries --- .github/canary-config/canary-all.yml | 55 ++++++++++++++-------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/.github/canary-config/canary-all.yml b/.github/canary-config/canary-all.yml index 9584146d552..47241d613d7 100644 --- a/.github/canary-config/canary-all.yml +++ b/.github/canary-config/canary-all.yml @@ -161,13 +161,13 @@ tests: browser: [chrome] # INTERACTIONS - - test_name: integ_react_interactions_react_interactions - desc: 'React Interactions' - framework: react - category: interactions - sample_name: [chatbot-component] - spec: chatbot-component - browser: *minimal_browser_list + # - test_name: integ_react_interactions_react_interactions + # desc: 'React Interactions' + # framework: react + # category: interactions + # sample_name: [chatbot-component] + # spec: chatbot-component + # browser: *minimal_browser_list - test_name: integ_react_interactions_chatbot_v1 desc: 'Chatbot V1' framework: react @@ -175,22 +175,28 @@ tests: sample_name: [lex-test-component] spec: chatbot-v1 browser: *minimal_browser_list - - test_name: integ_angular_interactions - desc: 'Angular Interactions' - framework: angular + - test_name: integ_react_interactions_chatbot_v2 + desc: 'Chatbot V2' + framework: react category: interactions - sample_name: [chatbot-component] - spec: chatbot-component + sample_name: [lex-test-component] + spec: chatbot-v2 browser: *minimal_browser_list - - test_name: integ_vue_interactions_vue_2_interactions - desc: 'Vue 2 Interactions' - framework: vue - category: interactions - sample_name: [chatbot-component] - spec: chatbot-component - browser: [chrome] - - # PREDICTIONS + # - test_name: integ_angular_interactions + # desc: 'Angular Interactions' + # framework: angular + # category: interactions + # sample_name: [chatbot-component] + # spec: chatbot-component + # browser: *minimal_browser_list + # - test_name: integ_vue_interactions_vue_2_interactions + # desc: 'Vue 2 Interactions' + # framework: vue + # category: interactions + # sample_name: [chatbot-component] + # spec: chatbot-component + # browser: [chrome] + # PREDICTIONS - test_name: integ_react_predictions desc: 'React Predictions' framework: react @@ -250,13 +256,6 @@ tests: browser: *minimal_browser_list # AUTH - - test_name: integ_react_auth_1_react_authenticator - desc: 'React Authenticator' - framework: react - category: auth - sample_name: [amplify-authenticator] - spec: new-ui-authenticator - browser: *minimal_browser_list - test_name: integ_react_auth_2_react_credentials_different_region desc: 'React Credentials Different Region' framework: react From 8ca7c15fe7f425b2a43821ea46778328d9860188 Mon Sep 17 00:00:00 2001 From: Chris F <5827964+cshfang@users.noreply.github.com> Date: Tue, 28 Nov 2023 13:05:19 -0800 Subject: [PATCH 06/15] chore: Upgrade Jest (#12607) * chore: Upgrade Jest * Address feedback * Address feedback * Fix issue with required uuid-validate module --------- Co-authored-by: Aaron S <94858815+stocaaro@users.noreply.github.com> --- jest.config.js | 24 + jest.setup.js | 13 + package.json | 19 +- .../api/generateServerClient.test.ts | 2 +- ...torageAdapterFromNextServerContext.test.ts | 2 +- packages/adapter-nextjs/jest.config.js | 11 + packages/adapter-nextjs/package.json | 49 - .../analytics/__tests__/apis/disable.test.ts | 2 +- .../analytics/__tests__/apis/enable.test.ts | 2 +- .../kinesis-firehose/apis/flushEvents.test.ts | 7 +- .../kinesis-firehose/apis/record.test.ts | 15 +- .../utils/getEventBuffer.test.ts | 8 +- .../utils/resolveConfig.test.ts | 4 +- .../kinesis/apis/flushEvents.test.ts | 7 +- .../providers/kinesis/apis/record.test.ts | 15 +- .../kinesis/utils/getEventBuffer.test.ts | 8 +- .../kinesis/utils/resolveConfig.test.ts | 2 +- .../personalize/apis/flushEvents.test.ts | 7 +- .../providers/personalize/apis/record.test.ts | 29 +- .../personalize/utils/cachedSession.test.ts | 8 +- .../personalize/utils/getEventBuffer.test.ts | 8 +- .../personalize/utils/resolveConfig.test.ts | 4 +- .../pinpoint/apis/configureAutoTrack.test.ts | 12 +- .../pinpoint/apis/flushEvents.test.ts | 13 +- .../pinpoint/apis/identifyUser.test.ts | 4 +- .../providers/pinpoint/apis/record.test.ts | 21 +- ...mockConstants.test.ts => mockConstants.ts} | 0 .../utils/eventBuffer/EventBuffer.test.ts | 4 +- packages/analytics/jest.config.js | 14 + packages/analytics/package.json | 42 - packages/analytics/src/setupTests.ts | 8 - .../AWSAppSyncRealTimeProvider.test.ts | 45 +- .../api-graphql/__tests__/GraphQLAPI.test.ts | 14 +- .../__tests__/generateClient.test.ts | 30 +- packages/api-graphql/__tests__/helpers.ts | 40 +- .../__tests__/server/generateClient.test.ts | 4 +- packages/api-graphql/jest.config.js | 11 + packages/api-graphql/package.json | 52 +- .../apis/common/internalPost.test.ts | 24 +- .../__tests__/apis/common/publicApis.test.ts | 36 +- packages/api-rest/jest.config.js | 11 + packages/api-rest/package.json | 44 +- .../src/utils/createCancellableOperation.ts | 14 +- packages/api/__tests__/API.test.ts | 2 +- packages/api/jest.config.js | 11 + packages/api/package.json | 50 - .../cognito/assertServiceError.test.ts | 12 +- .../providers/cognito/autoSignIn.test.ts | 20 +- .../cognito/confirmResetPassword.test.ts | 103 +- .../cognito/confirmSignInErrorCases.test.ts | 90 +- .../cognito/confirmSignInHappyCases.test.ts | 14 +- .../providers/cognito/confirmSignUp.test.ts | 122 +- .../cognito/confirmUserAttribute.test.ts | 112 +- .../cognito/credentialsProvider.test.ts | 24 +- .../providers/cognito/deleteUser.test.ts | 118 +- .../cognito/deleteUserAttributes.test.ts | 104 +- .../cognito/fetchAuthSession.test.ts | 4 +- .../providers/cognito/fetchDevices.test.ts | 135 +- .../cognito/fetchMFAPreference.test.ts | 108 +- .../cognito/fetchUserAttributes.test.ts | 98 +- .../providers/cognito/forgetDevice.test.ts | 186 +- .../providers/cognito/getCurrentUser.test.ts | 57 +- .../cognito/identityIdProvider.test.ts | 13 +- .../providers/cognito/identityIdStore.test.ts | 8 +- .../providers/cognito/refreshToken.test.ts | 156 +- .../providers/cognito/rememberDevice.test.ts | 117 +- .../cognito/resendSignUpCode.test.ts | 112 +- .../providers/cognito/resetPassword.test.ts | 102 +- .../sendUserAttributeVerificationCode.test.ts | 106 +- .../providers/cognito/setUpTOTP.test.ts | 105 +- .../cognito/signInErrorCases.test.ts | 88 +- .../cognito/signInStateManagement.test.ts | 4 +- .../cognito/signInWithCustomAuth.test.ts | 8 +- .../cognito/signInWithCustomSRPAuth.test.ts | 8 +- .../cognito/signInWithRedirect.test.ts | 6 +- .../providers/cognito/signInWithSRP.test.ts | 10 +- .../cognito/signInWithUserPassword.test.ts | 6 +- .../providers/cognito/signOut.test.ts | 54 +- .../providers/cognito/signUp.test.ts | 78 +- .../cognito/testUtils/authApiTestParams.ts | 4 +- .../providers/cognito/testUtils/data.ts | 12 +- .../cognito/testUtils/setUpGetConfig.ts | 14 + .../cognito/updateMFAPreference.test.ts | 106 +- .../providers/cognito/updatePassword.test.ts | 110 +- .../cognito/updateUserAttribute.test.ts | 65 +- .../cognito/updateUserAttributes.test.ts | 179 +- .../utils/oauth/completeOAuthSignOut.test.ts | 8 +- .../oauth/handleOAuthSignOut.native.test.ts | 29 +- .../utils/oauth/handleOAuthSignOut.test.ts | 8 +- .../utils/oauth/oAuthSignOutRedirect.test.ts | 6 +- .../utils/srp/AuthenticationHelper.test.ts | 10 +- .../utils/srp/calculate/calculateA.test.ts | 2 +- .../utils/srp/calculate/calculateS.test.ts | 2 +- .../utils/srp/calculate/calculateU.test.ts | 6 +- .../providers/cognito/verifyTOTPSetup.test.ts | 104 +- .../utils/getAuthUserAgentValue.test.ts | 2 +- packages/auth/jest.config.js | 11 + packages/auth/package.json | 54 +- ...WSCredentialsAndIdentityIdProvider.test.ts | 8 +- ...KeyValueStorageFromCookieStorageAdapter.ts | 8 +- .../__tests__/initSingleton.test.ts | 30 +- packages/aws-amplify/jest.config.js | 14 + packages/aws-amplify/package.json | 42 +- .../BackgroundProcessManager.test.ts | 18 +- .../core/__tests__/Cache/StorageCache.test.ts | 6 +- .../Cache/StorageCacheCommon.test.ts | 133 +- packages/core/__tests__/ConsoleLogger.test.ts | 7 +- packages/core/__tests__/DateUtils.test.ts | 8 +- packages/core/__tests__/HubClass.test.ts | 2 +- packages/core/__tests__/I18n.test.ts | 4 +- .../core/__tests__/JS-browser-runtime.test.ts | 4 - packages/core/__tests__/Mutex.test.ts | 2 +- packages/core/__tests__/ServiceWorker.test.ts | 8 +- packages/core/__tests__/Signer.test.ts | 8 +- packages/core/__tests__/StringUtils.test.ts | 4 +- .../adapterCore/serverContext.test.ts | 6 +- .../getCredentialsForIdentity.test.ts | 6 +- .../awsClients/cognitoIdentity/getId.test.ts | 6 +- .../pinpoint/getInAppMessages.test.ts | 2 +- .../awsClients/pinpoint/putEvents.test.ts | 2 +- .../pinpoint/updateEndpoint.test.ts | 2 +- .../clients/composeApiHandler.test.ts | 19 +- .../clients/composeTransferHandler.test.ts | 6 +- packages/core/__tests__/clients/fetch.test.ts | 16 +- .../middleware/retry/middleware.test.ts | 38 +- .../middleware/signing/middleware.test.ts | 17 +- .../pinpoint/apis/flushEvents.test.ts | 4 +- .../providers/pinpoint/apis/record.test.ts | 10 +- .../pinpoint/apis/updateEndpoint.test.ts | 12 +- .../pinpoint/utils/cacheEndpointId.test.ts | 4 +- .../pinpoint/utils/getEndpointId.test.ts | 4 +- .../pinpoint/utils/getEventBuffer.test.ts | 2 +- .../pinpoint/utils/resolveEndpointId.test.ts | 2 +- .../__tests__/singleton/Singleton.test.ts | 10 +- .../__tests__/storage/CookieStorage.test.ts | 19 +- .../storage-mechanisms-node-runtime.test.ts | 4 +- packages/core/__tests__/utils.test.ts | 8 +- .../utils/cryptoSecureRandomInt.test.ts | 2 +- .../globalHelpers.native.test.ts | 6 +- .../SessionListener.native.test.ts | 12 +- .../sessionListener/SessionListener.test.ts | 10 +- packages/core/jest.config.js | 11 + packages/core/package.json | 40 - packages/core/src/Cache/StorageCacheCommon.ts | 2 +- .../__tests__/SQLiteAdapter.test.ts | 4 +- .../__tests__/SQLiteCPKDisabled.test.ts | 5 +- .../__tests__/SQLiteCPKEnabled.test.ts | 5 +- .../datastore-storage-adapter/jest.config.js | 11 + .../datastore-storage-adapter/jest.setup.js | 7 - .../datastore-storage-adapter/package.json | 53 - .../src/common/SQLiteUtils.ts | 2 +- .../datastore-storage-adapter/tsconfig.json | 3 +- .../{AsyncStorage.ts => AsyncStorage.test.ts} | 0 .../DataStore.test.ts} | 2148 +---------- .../__tests__/DataStore/modelBehavior.test.ts | 329 ++ .../__tests__/DataStore/observe.test.ts | 327 ++ .../__tests__/DataStore/observeQuery.test.ts | 643 ++++ .../__tests__/DataStore/sanityCheck.test.ts | 703 ++++ .../__tests__/IndexedDBAdapter.test.ts | 2 - .../{Predicate.ts => Predicate.test.ts} | 12 +- ...rage.ts.snap => AsyncStorage.test.ts.snap} | 2 +- .../__snapshots__/indexeddb.test.ts.snap | 312 +- .../indexeddb.upgrade.test.ts.snap | 104 +- .../__tests__/__snapshots__/sync.test.ts.snap | 46 +- .../datastore/__tests__/commonAdapterTests.ts | 4 +- .../__tests__/connectivityHandling.test.ts | 36 +- .../composite-identifier.test.tsx | 34 +- .../custom-identifier.test.tsx | 24 +- .../legacy-backwards-compatibility.test.tsx | 40 +- .../managed-identifier.test.tsx | 24 +- .../optionally-managed-identifier.test.tsx | 20 +- .../__tests__/{graphql.ts => graphql.test.ts} | 0 .../datastore/__tests__/indexeddb.test.ts | 16 +- .../__tests__/indexeddb.upgrade.test.ts | 4 +- packages/datastore/__tests__/mutation.test.ts | 42 +- packages/datastore/__tests__/utils.test.ts | 20 +- packages/datastore/jest.config.js | 15 + packages/datastore/jest.setup.js | 7 - packages/datastore/package.json | 61 +- packages/geo/__tests__/util.test.ts | 56 +- packages/geo/jest.config.js | 14 + packages/geo/package.json | 54 +- .../__tests__/lex-v1/AWSLexProvider.test.ts | 6 +- .../__tests__/lex-v1/apis/onComplete.test.ts | 6 +- .../__tests__/lex-v1/apis/send.test.ts | 6 +- .../lex-v1/utils/resolveBotConfig.test.ts | 2 +- .../__tests__/lex-v2/AWSLexV2Provider.test.ts | 6 +- .../__tests__/lex-v2/apis/onComplete.test.ts | 6 +- .../__tests__/lex-v2/apis/send.test.ts | 6 +- .../lex-v2/utils/resolveBotConfig.test.ts | 2 +- ...tion.test.ts => randomConfigGeneration.ts} | 0 packages/interactions/jest.config.js | 14 + packages/interactions/package.json | 41 +- .../eventListeners/eventListeners.test.ts | 16 +- .../pinpoint/apis/clearMessages.test.ts | 4 +- .../pinpoint/apis/dispatchEvent.test.ts | 13 +- .../pinpoint/apis/identifyUser.test.ts | 4 +- .../pinpoint/apis/interactionEvents.test.ts | 25 +- .../pinpoint/apis/setConflictHandler.test.ts | 2 +- .../pinpoint/apis/syncMessages.test.ts | 8 +- .../pinpoint/apis/identifyUser.native.test.ts | 4 +- ...initializePushNotifications.native.test.ts | 42 +- .../apis/onNotificationOpened.native.test.ts | 2 +- ...icationReceivedInBackground.native.test.ts | 2 +- ...icationReceivedInForeground.native.test.ts | 2 +- .../apis/onTokenReceived.native.test.ts | 5 +- .../apis/setBadgeCount.native.test.ts | 2 +- .../utils/createMessageEventRecorder.test.ts | 4 +- ...getPushNotificationUserAgentString.test.ts | 2 +- packages/notifications/jest.config.js | 11 + packages/notifications/package.json | 40 - .../AWSAIConvertPredictionsProvider.test.ts | 2 +- .../AWSAIIdentifyPredictionsProvider.test.ts | 2 +- packages/predictions/jest.config.js | 14 + packages/predictions/package.json | 49 +- packages/pubsub/__tests__/PubSub.test.ts | 47 +- packages/pubsub/__tests__/helpers.ts | 42 +- packages/pubsub/jest.config.js | 14 + packages/pubsub/package.json | 44 +- packages/react-native/jest.config.js | 11 + .../apis/addMessageEventListener.test.ts | 9 +- .../apis/addTokenEventListener.test.ts | 4 +- .../apis/completeNotification.test.ts | 4 +- .../__tests__/apis/getBadgeCount.test.ts | 2 +- .../__tests__/apis/getConstants.test.ts | 2 +- .../apis/getLaunchNotification.test.ts | 8 +- .../apis/getPermissionStatus.test.ts | 4 +- .../apis/registerHeadlessTask.test.ts | 6 +- .../__tests__/apis/requestPermissions.test.ts | 4 +- .../__tests__/apis/setBadgeCount.test.ts | 2 +- packages/rtn-push-notification/jest.config.js | 11 + packages/rtn-push-notification/package.json | 41 +- packages/rtn-web-browser/jest.config.js | 11 + .../__tests__/providers/s3/apis/copy.test.ts | 6 +- .../providers/s3/apis/downloadData.test.ts | 4 +- .../providers/s3/apis/getProperties.test.ts | 8 +- .../providers/s3/apis/getUrl.test.ts | 18 +- .../__tests__/providers/s3/apis/list.test.ts | 8 +- .../providers/s3/apis/remove.test.ts | 6 +- .../s3/apis/uploadData/index.test.ts | 18 +- .../apis/uploadData/multipartHandlers.test.ts | 72 +- .../s3/apis/uploadData/putObjectJob.test.ts | 4 +- .../utils/resolveS3ConfigAndInput.test.ts | 18 +- .../s3/utils/client/S3/cases/getObject.ts | 5 - .../s3/utils/client/S3/cases/listObjectsV2.ts | 2 - .../s3/utils/client/S3/cases/shared.ts | 9 - .../utils/client/S3/functional-apis.test.ts | 19 +- .../S3/getPresignedGetObjectUrl.test.ts | 2 +- .../client/xhrTransferHandler-util.test.ts | 22 +- packages/storage/jest.config.js | 11 + packages/storage/package.json | 53 - yarn.lock | 3237 +++++------------ 252 files changed, 5604 insertions(+), 8083 deletions(-) create mode 100644 jest.config.js create mode 100644 jest.setup.js create mode 100644 packages/adapter-nextjs/jest.config.js rename packages/analytics/__tests__/testUtils/{mockConstants.test.ts => mockConstants.ts} (100%) create mode 100644 packages/analytics/jest.config.js delete mode 100644 packages/analytics/src/setupTests.ts create mode 100644 packages/api-graphql/jest.config.js create mode 100644 packages/api-rest/jest.config.js create mode 100644 packages/api/jest.config.js create mode 100644 packages/auth/__tests__/providers/cognito/testUtils/setUpGetConfig.ts create mode 100644 packages/auth/jest.config.js create mode 100644 packages/aws-amplify/jest.config.js create mode 100644 packages/core/jest.config.js create mode 100644 packages/datastore-storage-adapter/jest.config.js delete mode 100644 packages/datastore-storage-adapter/jest.setup.js rename packages/datastore/__tests__/{AsyncStorage.ts => AsyncStorage.test.ts} (100%) rename packages/datastore/__tests__/{DataStore.ts => DataStore/DataStore.test.ts} (55%) create mode 100644 packages/datastore/__tests__/DataStore/modelBehavior.test.ts create mode 100644 packages/datastore/__tests__/DataStore/observe.test.ts create mode 100644 packages/datastore/__tests__/DataStore/observeQuery.test.ts create mode 100644 packages/datastore/__tests__/DataStore/sanityCheck.test.ts rename packages/datastore/__tests__/{Predicate.ts => Predicate.test.ts} (99%) rename packages/datastore/__tests__/__snapshots__/{AsyncStorage.ts.snap => AsyncStorage.test.ts.snap} (99%) rename packages/datastore/__tests__/{graphql.ts => graphql.test.ts} (100%) create mode 100644 packages/datastore/jest.config.js delete mode 100644 packages/datastore/jest.setup.js create mode 100644 packages/geo/jest.config.js rename packages/interactions/__tests__/testUtils/{randomConfigGeneration.test.ts => randomConfigGeneration.ts} (100%) create mode 100644 packages/interactions/jest.config.js create mode 100644 packages/notifications/jest.config.js create mode 100644 packages/predictions/jest.config.js create mode 100644 packages/pubsub/jest.config.js create mode 100644 packages/react-native/jest.config.js create mode 100644 packages/rtn-push-notification/jest.config.js create mode 100644 packages/rtn-web-browser/jest.config.js create mode 100644 packages/storage/jest.config.js diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 00000000000..7f0c776869e --- /dev/null +++ b/jest.config.js @@ -0,0 +1,24 @@ +/** @type {import('jest').Config} */ +module.exports = { + coveragePathIgnorePatterns: [ + '/node_modules/', + 'dist', + '__tests__', + ], + setupFiles: ['../../jest.setup.js'], + testEnvironment: 'jsdom', + testRegex: '/__tests__/.*\\.(test|spec)\\.[jt]sx?$', + transform: { + '^.+\\.(js|jsx|ts|tsx)$': [ + 'ts-jest', + { + tsconfig: { + allowJs: true, + lib: ['dom', 'es2020'], + noImplicitAny: false, + types: ['jest', 'jsdom'], + }, + }, + ], + }, +}; diff --git a/jest.setup.js b/jest.setup.js new file mode 100644 index 00000000000..05fbee97db1 --- /dev/null +++ b/jest.setup.js @@ -0,0 +1,13 @@ +// Suppress console messages printing during unit tests. +// Comment out log level as necessary (e.g. while debugging tests) +global.console = { + ...console, + log: jest.fn(), + debug: jest.fn(), + info: jest.fn(), + warn: jest.fn(), + error: jest.fn(), +}; + +// React Native global +global['__DEV__'] = true; diff --git a/package.json b/package.json index a427664243c..2539a8f069c 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,9 @@ "setup-dev": "yarn && yarn bootstrap && yarn link-all && yarn build", "setup-dev:react-native": "node ./scripts/setup-dev-rn", "bootstrap": "lerna bootstrap", - "test": "lerna run test --stream && yarn test:license && yarn test:github-actions && yarn test:tsc-compliance", + "test": "yarn test:no-datastore && yarn test:datastore && yarn test:license && yarn test:github-actions && yarn test:tsc-compliance", + "test:no-datastore": "lerna run test --stream --ignore @aws-amplify/datastore", + "test:datastore": "lerna run test --stream --scope @aws-amplify/datastore", "test:size": "lerna run test:size --no-bail", "test:duplicates": "./scripts/duplicates-yarn.sh", "test:license": "license-check-and-add check -f license_config.json", @@ -84,16 +86,15 @@ "@size-limit/file": "^8.1.0", "@size-limit/webpack": "^8.1.0", "@size-limit/webpack-why": "^8.1.0", - "@types/jest": "^24.0.18", + "@types/jest": "^29.5.8", "@types/lodash": "4.14.182", "@types/node": "^8.9.5", "@types/puppeteer": "1.3.0", - "babel-jest": "^24.9.0", "babel-loader": "^8.3.0", "codecov": "^3.6.5", "glob": "^10.3.10", - "jest": "^24.x.x", - "jest-config": "24.8.0", + "jest": "^29.7.0", + "jest-environment-jsdom": "^29.7.0", "json-loader": "^0.5.7", "lerna": "^7.4.2", "license-check-and-add": "^4.0.5", @@ -107,12 +108,12 @@ "rollup-plugin-typescript": "^1.0.0", "size-limit": "^8.1.0", "terser-webpack-plugin": "^5.3.6", - "ts-jest": "^24.x.x", + "ts-jest": "^29.1.1", "ts-loader": "^9.4.3", "tslint": "^5.7.0", "tslint-config-airbnb": "^5.8.0", "typedoc": "^0.17.0", - "typescript": "~3.8.3", + "typescript": "^4.3.5", "typescript-coverage-report": "^0.6.4", "uuid-validate": "^0.0.3", "webpack": "^5.75.0", @@ -127,9 +128,5 @@ "**/glob/minipass": "6.0.2", "nx": "16.7.0", "next": "13.5.6" - }, - "jest": { - "resetMocks": true, - "verbose": true } } diff --git a/packages/adapter-nextjs/__tests__/api/generateServerClient.test.ts b/packages/adapter-nextjs/__tests__/api/generateServerClient.test.ts index 09400588077..dfc038de44a 100644 --- a/packages/adapter-nextjs/__tests__/api/generateServerClient.test.ts +++ b/packages/adapter-nextjs/__tests__/api/generateServerClient.test.ts @@ -55,7 +55,7 @@ describe('generateServerClientUsingCookies', () => { request: mockedReq, response: mockedRes, }); - }).toThrowError(); + }).toThrow(); }); it('should call createRunWithAmplifyServerContext to create runWithAmplifyServerContext function', async () => { diff --git a/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts b/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts index 3094472548f..7d26d45e12b 100644 --- a/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts +++ b/packages/adapter-nextjs/__tests__/utils/createCookieStorageAdapterFromNextServerContext.test.ts @@ -397,6 +397,6 @@ describe('createCookieStorageAdapterFromNextServerContext', () => { request: undefined, response: new ServerResponse({} as any), } as any) - ).toThrowError(); + ).toThrow(); }); }); diff --git a/packages/adapter-nextjs/jest.config.js b/packages/adapter-nextjs/jest.config.js new file mode 100644 index 00000000000..c6406b36105 --- /dev/null +++ b/packages/adapter-nextjs/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 88, + functions: 90, + lines: 92, + statements: 93, + }, + }, +}; diff --git a/packages/adapter-nextjs/package.json b/packages/adapter-nextjs/package.json index bb1a1e19051..ce8b55daf8d 100644 --- a/packages/adapter-nextjs/package.json +++ b/packages/adapter-nextjs/package.json @@ -71,54 +71,5 @@ "lint": "tslint 'src/**/*.ts' && npm run ts-coverage", "test": "npm run lint && jest -w 1 --coverage", "ts-coverage": "typescript-coverage-report -p ./tsconfig.build.json -t 90.31" - }, - "jest": { - "coveragePathIgnorePatterns": [ - "/node_modules/", - "dist", - "lib", - "lib-esm", - "__tests__/mocks" - ], - "coverageThreshold": { - "global": { - "branches": 88, - "functions": 90, - "lines": 92, - "statements": 93 - } - }, - "globals": { - "ts-jest": { - "diagnostics": { - "pathRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$" - }, - "tsConfig": { - "allowJs": true, - "types": [ - "@types/jest" - ] - } - } - }, - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "node", - "testPathIgnorePatterns": [ - "xmlParser-fixture.ts", - "testUtils", - "cases", - "mocks" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testURL": "http://localhost/", - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - } } } diff --git a/packages/analytics/__tests__/apis/disable.test.ts b/packages/analytics/__tests__/apis/disable.test.ts index 94578d75875..faeb38987be 100644 --- a/packages/analytics/__tests__/apis/disable.test.ts +++ b/packages/analytics/__tests__/apis/disable.test.ts @@ -16,6 +16,6 @@ describe('Pinpoint APIs: disable', () => { it('should disable Analytics', () => { disable(); - expect(mockDisableAnalytics).toBeCalledTimes(1); + expect(mockDisableAnalytics).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/analytics/__tests__/apis/enable.test.ts b/packages/analytics/__tests__/apis/enable.test.ts index db523ec43b5..93dc764368c 100644 --- a/packages/analytics/__tests__/apis/enable.test.ts +++ b/packages/analytics/__tests__/apis/enable.test.ts @@ -16,6 +16,6 @@ describe('Pinpoint APIs: enable', () => { it('should enable Analytics', () => { enable(); - expect(mockEnableAnalytics).toBeCalledTimes(1); + expect(mockEnableAnalytics).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis-firehose/apis/flushEvents.test.ts b/packages/analytics/__tests__/providers/kinesis-firehose/apis/flushEvents.test.ts index 14c5849c0a3..44ad877cc34 100644 --- a/packages/analytics/__tests__/providers/kinesis-firehose/apis/flushEvents.test.ts +++ b/packages/analytics/__tests__/providers/kinesis-firehose/apis/flushEvents.test.ts @@ -9,7 +9,7 @@ import { resolveCredentials } from '../../../../src/utils'; import { mockKinesisConfig, mockCredentialConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { flushEvents } from '../../../../src/providers/kinesis-firehose/apis'; import { ConsoleLogger } from '@aws-amplify/core'; @@ -60,6 +60,9 @@ describe('Analytics Kinesis Firehose API: flushEvents', () => { flushEvents(); await new Promise(process.nextTick); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis-firehose/apis/record.test.ts b/packages/analytics/__tests__/providers/kinesis-firehose/apis/record.test.ts index c7e5e8cca5a..9910831f6a1 100644 --- a/packages/analytics/__tests__/providers/kinesis-firehose/apis/record.test.ts +++ b/packages/analytics/__tests__/providers/kinesis-firehose/apis/record.test.ts @@ -9,7 +9,7 @@ import { isAnalyticsEnabled, resolveCredentials } from '../../../../src/utils'; import { mockKinesisConfig, mockCredentialConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { record } from '../../../../src/providers/kinesis-firehose'; import { ConsoleLogger } from '@aws-amplify/core'; import { RecordInput as KinesisFirehoseRecordInput } from '../../../../src/providers/kinesis-firehose/types'; @@ -54,7 +54,7 @@ describe('Analytics KinesisFirehose API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockAppend).toBeCalledWith( + expect(mockAppend).toHaveBeenCalledWith( expect.objectContaining({ region: mockKinesisConfig.region, streamName: mockRecordInput.streamName, @@ -70,15 +70,18 @@ describe('Analytics KinesisFirehose API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); it('logs and skip the event recoding if Analytics plugin is not enabled', async () => { mockIsAnalyticsEnabled.mockReturnValue(false); record(mockRecordInput); await new Promise(process.nextTick); - expect(loggerDebugSpy).toBeCalledWith(expect.any(String)); - expect(mockGetEventBuffer).not.toBeCalled(); - expect(mockAppend).not.toBeCalled(); + expect(loggerDebugSpy).toHaveBeenCalledWith(expect.any(String)); + expect(mockGetEventBuffer).not.toHaveBeenCalled(); + expect(mockAppend).not.toHaveBeenCalled(); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis-firehose/utils/getEventBuffer.test.ts b/packages/analytics/__tests__/providers/kinesis-firehose/utils/getEventBuffer.test.ts index da44719ecc7..ea12c7c8665 100644 --- a/packages/analytics/__tests__/providers/kinesis-firehose/utils/getEventBuffer.test.ts +++ b/packages/analytics/__tests__/providers/kinesis-firehose/utils/getEventBuffer.test.ts @@ -7,7 +7,7 @@ import { mockBufferConfig, mockCredentialConfig, mockKinesisConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; jest.mock('../../../../src/utils'); @@ -24,7 +24,7 @@ describe('KinesisFirehose Provider Util: getEventBuffer', () => { ...mockCredentialConfig, }); - expect(mockEventBuffer).toBeCalledWith( + expect(mockEventBuffer).toHaveBeenCalledWith( mockBufferConfig, expect.any(Function) ); @@ -59,8 +59,8 @@ describe('KinesisFirehose Provider Util: getEventBuffer', () => { await new Promise(process.nextTick); - expect(testBuffer1.flushAll).toBeCalledTimes(1); - expect(testBuffer1.release).toBeCalledTimes(1); + expect(testBuffer1.flushAll).toHaveBeenCalledTimes(1); + expect(testBuffer1.release).toHaveBeenCalledTimes(1); expect(testBuffer1).not.toBe(testBuffer2); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis-firehose/utils/resolveConfig.test.ts b/packages/analytics/__tests__/providers/kinesis-firehose/utils/resolveConfig.test.ts index 62ceaba295e..2180651b964 100644 --- a/packages/analytics/__tests__/providers/kinesis-firehose/utils/resolveConfig.test.ts +++ b/packages/analytics/__tests__/providers/kinesis-firehose/utils/resolveConfig.test.ts @@ -47,7 +47,9 @@ describe('Analytics KinesisFirehose Provider Util: resolveConfig', () => { it('throws if region is missing', () => { getConfigSpy.mockReturnValue({ - Analytics: { KinesisFirehose: { ...providedConfig, region: undefined } }, + Analytics: { + KinesisFirehose: { ...providedConfig, region: undefined as any }, + }, }); expect(resolveConfig).toThrow(); diff --git a/packages/analytics/__tests__/providers/kinesis/apis/flushEvents.test.ts b/packages/analytics/__tests__/providers/kinesis/apis/flushEvents.test.ts index 2a0a3d15c3d..cb6d50c1e33 100644 --- a/packages/analytics/__tests__/providers/kinesis/apis/flushEvents.test.ts +++ b/packages/analytics/__tests__/providers/kinesis/apis/flushEvents.test.ts @@ -6,7 +6,7 @@ import { resolveCredentials } from '../../../../src/utils'; import { mockKinesisConfig, mockCredentialConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { getEventBuffer } from '../../../../src/providers/kinesis/utils/getEventBuffer'; import { flushEvents } from '../../../../src/providers/kinesis/apis'; import { ConsoleLogger } from '@aws-amplify/core'; @@ -59,6 +59,9 @@ describe('Analytics Kinesis API: flushEvents', () => { flushEvents(); await new Promise(process.nextTick); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis/apis/record.test.ts b/packages/analytics/__tests__/providers/kinesis/apis/record.test.ts index 43a40f6052d..9ea439ed2fc 100644 --- a/packages/analytics/__tests__/providers/kinesis/apis/record.test.ts +++ b/packages/analytics/__tests__/providers/kinesis/apis/record.test.ts @@ -7,7 +7,7 @@ import { isAnalyticsEnabled, resolveCredentials } from '../../../../src/utils'; import { mockKinesisConfig, mockCredentialConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { record } from '../../../../src/providers/kinesis'; import { ConsoleLogger } from '@aws-amplify/core'; import { RecordInput as KinesisRecordInput } from '../../../../src/providers/kinesis/types'; @@ -54,7 +54,7 @@ describe('Analytics Kinesis API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockAppend).toBeCalledWith( + expect(mockAppend).toHaveBeenCalledWith( expect.objectContaining({ region: mockKinesisConfig.region, streamName: mockRecordInput.streamName, @@ -71,15 +71,18 @@ describe('Analytics Kinesis API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); it('logs and skip the event recoding if Analytics plugin is not enabled', async () => { mockIsAnalyticsEnabled.mockReturnValue(false); record(mockRecordInput); await new Promise(process.nextTick); - expect(loggerDebugSpy).toBeCalledWith(expect.any(String)); - expect(mockGetEventBuffer).not.toBeCalled(); - expect(mockAppend).not.toBeCalled(); + expect(loggerDebugSpy).toHaveBeenCalledWith(expect.any(String)); + expect(mockGetEventBuffer).not.toHaveBeenCalled(); + expect(mockAppend).not.toHaveBeenCalled(); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis/utils/getEventBuffer.test.ts b/packages/analytics/__tests__/providers/kinesis/utils/getEventBuffer.test.ts index 0230a0db0e5..828745f03f3 100644 --- a/packages/analytics/__tests__/providers/kinesis/utils/getEventBuffer.test.ts +++ b/packages/analytics/__tests__/providers/kinesis/utils/getEventBuffer.test.ts @@ -7,7 +7,7 @@ import { mockBufferConfig, mockKinesisConfig, mockCredentialConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; jest.mock('../../../../src/utils'); @@ -24,7 +24,7 @@ describe('Kinesis Provider Util: getEventBuffer', () => { ...mockCredentialConfig, }); - expect(mockEventBuffer).toBeCalledWith( + expect(mockEventBuffer).toHaveBeenCalledWith( mockBufferConfig, expect.any(Function) ); @@ -58,8 +58,8 @@ describe('Kinesis Provider Util: getEventBuffer', () => { }); await new Promise(process.nextTick); - expect(testBuffer1.flushAll).toBeCalledTimes(1); - expect(testBuffer1.release).toBeCalledTimes(1); + expect(testBuffer1.flushAll).toHaveBeenCalledTimes(1); + expect(testBuffer1.release).toHaveBeenCalledTimes(1); expect(testBuffer1).not.toBe(testBuffer2); }); }); diff --git a/packages/analytics/__tests__/providers/kinesis/utils/resolveConfig.test.ts b/packages/analytics/__tests__/providers/kinesis/utils/resolveConfig.test.ts index a0b39266770..a4e8954e8dc 100644 --- a/packages/analytics/__tests__/providers/kinesis/utils/resolveConfig.test.ts +++ b/packages/analytics/__tests__/providers/kinesis/utils/resolveConfig.test.ts @@ -47,7 +47,7 @@ describe('Analytics Kinesis Provider Util: resolveConfig', () => { it('throws if region is missing', () => { getConfigSpy.mockReturnValue({ - Analytics: { Kinesis: { ...kinesisConfig, region: undefined } }, + Analytics: { Kinesis: { ...kinesisConfig, region: undefined as any } }, }); expect(resolveConfig).toThrow(); diff --git a/packages/analytics/__tests__/providers/personalize/apis/flushEvents.test.ts b/packages/analytics/__tests__/providers/personalize/apis/flushEvents.test.ts index 5ae5e67c58b..e74374e8403 100644 --- a/packages/analytics/__tests__/providers/personalize/apis/flushEvents.test.ts +++ b/packages/analytics/__tests__/providers/personalize/apis/flushEvents.test.ts @@ -9,7 +9,7 @@ import { resolveCredentials } from '../../../../src/utils'; import { mockCredentialConfig, mockPersonalizeConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { flushEvents } from '../../../../src/providers/personalize'; import { ConsoleLogger } from '@aws-amplify/core'; @@ -61,6 +61,9 @@ describe('Analytics Personalize API: flushEvents', () => { flushEvents(); await new Promise(process.nextTick); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); }); diff --git a/packages/analytics/__tests__/providers/personalize/apis/record.test.ts b/packages/analytics/__tests__/providers/personalize/apis/record.test.ts index b203c4e141e..8ba019684bb 100644 --- a/packages/analytics/__tests__/providers/personalize/apis/record.test.ts +++ b/packages/analytics/__tests__/providers/personalize/apis/record.test.ts @@ -11,7 +11,7 @@ import { isAnalyticsEnabled, resolveCredentials } from '../../../../src/utils'; import { mockCredentialConfig, mockPersonalizeConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { record } from '../../../../src/providers/personalize'; import { ConsoleLogger } from '@aws-amplify/core'; import { RecordInput as PersonalizeRecordInput } from '../../../../src/providers/personalize/types'; @@ -75,7 +75,7 @@ describe('Analytics Personalize API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockAppend).toBeCalledWith( + expect(mockAppend).toHaveBeenCalledWith( expect.objectContaining({ trackingId: mockPersonalizeConfig.trackingId, ...mockCachedSession, @@ -105,12 +105,12 @@ describe('Analytics Personalize API: record', () => { await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockUpdateCachedSession).toBeCalledWith( + expect(mockUpdateCachedSession).toHaveBeenCalledWith( newSession.userId, mockCachedSession.sessionId, mockCachedSession.userId ); - expect(mockAppend).toBeCalledWith( + expect(mockAppend).toHaveBeenCalledWith( expect.objectContaining({ trackingId: mockPersonalizeConfig.trackingId, ...newSession, @@ -136,12 +136,12 @@ describe('Analytics Personalize API: record', () => { await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockUpdateCachedSession).toBeCalledWith( + expect(mockUpdateCachedSession).toHaveBeenCalledWith( newSession.userId, mockCachedSession.sessionId, mockCachedSession.userId ); - expect(mockAppend).toBeCalledWith( + expect(mockAppend).toHaveBeenCalledWith( expect.objectContaining({ trackingId: mockPersonalizeConfig.trackingId, ...newSession, @@ -159,7 +159,7 @@ describe('Analytics Personalize API: record', () => { await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockAutoTrackMedia).toBeCalledWith( + expect(mockAutoTrackMedia).toHaveBeenCalledWith( { trackingId: mockPersonalizeConfig.trackingId, ...mockCachedSession, @@ -167,7 +167,7 @@ describe('Analytics Personalize API: record', () => { }, mockEventBuffer ); - expect(mockAppend).not.toBeCalled(); + expect(mockAppend).not.toHaveBeenCalled(); }); it('flushEvents when buffer size is full', async () => { @@ -187,7 +187,7 @@ describe('Analytics Personalize API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); expect(mockGetEventBuffer).toHaveBeenCalledTimes(1); - expect(mockAppend).toBeCalledWith( + expect(mockAppend).toHaveBeenCalledWith( expect.objectContaining({ trackingId: mockPersonalizeConfig.trackingId, ...mockCachedSession, @@ -204,15 +204,18 @@ describe('Analytics Personalize API: record', () => { record(mockRecordInput); await new Promise(process.nextTick); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); it('logs and skip the event recoding if Analytics plugin is not enabled', async () => { mockIsAnalyticsEnabled.mockReturnValue(false); record(mockRecordInput); await new Promise(process.nextTick); - expect(loggerDebugSpy).toBeCalledWith(expect.any(String)); - expect(mockGetEventBuffer).not.toBeCalled(); - expect(mockAppend).not.toBeCalled(); + expect(loggerDebugSpy).toHaveBeenCalledWith(expect.any(String)); + expect(mockGetEventBuffer).not.toHaveBeenCalled(); + expect(mockAppend).not.toHaveBeenCalled(); }); }); diff --git a/packages/analytics/__tests__/providers/personalize/utils/cachedSession.test.ts b/packages/analytics/__tests__/providers/personalize/utils/cachedSession.test.ts index ec6bc5aa1da..10681b33c6e 100644 --- a/packages/analytics/__tests__/providers/personalize/utils/cachedSession.test.ts +++ b/packages/analytics/__tests__/providers/personalize/utils/cachedSession.test.ts @@ -57,7 +57,7 @@ describe('Analytics service provider Personalize utils: cachedSession', () => { it('updateCachedSession create a new session if user has changed', () => { updateCachedSession('newUserId', mockSession.sessionId, mockSession.userId); - expect(mockCache.setItem).toBeCalledTimes(2); + expect(mockCache.setItem).toHaveBeenCalledTimes(2); expect(mockCache.setItem).toHaveBeenNthCalledWith( 1, sessionIdCacheKey, @@ -74,7 +74,7 @@ describe('Analytics service provider Personalize utils: cachedSession', () => { it('updateCachedSession create a new session if user is signed out', () => { updateCachedSession(undefined, mockSession.sessionId, undefined); - expect(mockCache.setItem).toBeCalledTimes(2); + expect(mockCache.setItem).toHaveBeenCalledTimes(2); expect(mockCache.setItem).toHaveBeenNthCalledWith( 1, sessionIdCacheKey, @@ -91,7 +91,7 @@ describe('Analytics service provider Personalize utils: cachedSession', () => { it('updateCachedSession create a new session if no cached session', () => { updateCachedSession('newUserId', undefined, mockSession.userId); - expect(mockCache.setItem).toBeCalledTimes(2); + expect(mockCache.setItem).toHaveBeenCalledTimes(2); expect(mockCache.setItem).toHaveBeenNthCalledWith( 1, sessionIdCacheKey, @@ -108,7 +108,7 @@ describe('Analytics service provider Personalize utils: cachedSession', () => { it('updateCachedSession only updates userId if cached sessionId but no cached userId', () => { updateCachedSession('newUserId', mockSession.sessionId, undefined); - expect(mockCache.setItem).toBeCalledTimes(1); + expect(mockCache.setItem).toHaveBeenCalledTimes(1); expect(mockCache.setItem).toHaveBeenNthCalledWith( 1, userIdCacheKey, diff --git a/packages/analytics/__tests__/providers/personalize/utils/getEventBuffer.test.ts b/packages/analytics/__tests__/providers/personalize/utils/getEventBuffer.test.ts index 3e75967d4e9..cce4fc560cf 100644 --- a/packages/analytics/__tests__/providers/personalize/utils/getEventBuffer.test.ts +++ b/packages/analytics/__tests__/providers/personalize/utils/getEventBuffer.test.ts @@ -6,7 +6,7 @@ import { mockBufferConfig, mockPersonalizeConfig, mockCredentialConfig, -} from '../../../testUtils/mockConstants.test'; +} from '../../../testUtils/mockConstants'; import { getEventBuffer } from '../../../../src/providers/personalize/utils'; jest.mock('../../../../src/utils'); @@ -24,7 +24,7 @@ describe('Personalize Provider Util: getEventBuffer', () => { ...mockCredentialConfig, }); - expect(mockEventBuffer).toBeCalledWith( + expect(mockEventBuffer).toHaveBeenCalledWith( { ...mockBufferConfig, bufferSize: mockBufferConfig.flushSize + 1 }, expect.any(Function) ); @@ -58,8 +58,8 @@ describe('Personalize Provider Util: getEventBuffer', () => { }); await new Promise(process.nextTick); - expect(testBuffer1.flushAll).toBeCalledTimes(1); - expect(testBuffer1.release).toBeCalledTimes(1); + expect(testBuffer1.flushAll).toHaveBeenCalledTimes(1); + expect(testBuffer1.release).toHaveBeenCalledTimes(1); expect(testBuffer1).not.toBe(testBuffer2); }); }); diff --git a/packages/analytics/__tests__/providers/personalize/utils/resolveConfig.test.ts b/packages/analytics/__tests__/providers/personalize/utils/resolveConfig.test.ts index 093bc6079a6..293b09fc52b 100644 --- a/packages/analytics/__tests__/providers/personalize/utils/resolveConfig.test.ts +++ b/packages/analytics/__tests__/providers/personalize/utils/resolveConfig.test.ts @@ -52,7 +52,9 @@ describe('Analytics Personalize Provider Util: resolveConfig', () => { it('throws if region is missing', () => { getConfigSpy.mockReturnValue({ - Analytics: { Personalize: { ...providedConfig, region: undefined } }, + Analytics: { + Personalize: { ...providedConfig, region: undefined as any }, + }, }); expect(resolveConfig).toThrow(); diff --git a/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts b/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts index 90664582e73..41c3b10c45f 100644 --- a/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts +++ b/packages/analytics/__tests__/providers/pinpoint/apis/configureAutoTrack.test.ts @@ -50,7 +50,7 @@ describe('Pinpoint API: configureAutoTrack', () => { ...MOCK_INPUT, type: 'invalidTracker', } as any); - } catch (e) { + } catch (e: any) { expect(e.message).toBe('Invalid tracker type specified.'); } }); @@ -65,7 +65,7 @@ describe('Pinpoint API: configureAutoTrack', () => { configureAutoTrack(MOCK_INPUT); }); - expect(MockEventTracker).toBeCalledWith( + expect(MockEventTracker).toHaveBeenCalledWith( expect.any(Function), MOCK_INPUT.options ); @@ -85,7 +85,7 @@ describe('Pinpoint API: configureAutoTrack', () => { configureAutoTrack(testInput); }); - expect(MockSessionTracker).toBeCalledWith( + expect(MockSessionTracker).toHaveBeenCalledWith( expect.any(Function), testInput.options ); @@ -105,7 +105,7 @@ describe('Pinpoint API: configureAutoTrack', () => { configureAutoTrack(testInput); }); - expect(MockPageViewTracker).toBeCalledWith( + expect(MockPageViewTracker).toHaveBeenCalledWith( expect.any(Function), testInput.options ); @@ -119,7 +119,7 @@ describe('Pinpoint API: configureAutoTrack', () => { // Enable the tracker configureAutoTrack(MOCK_INPUT); - expect(MockEventTracker).toBeCalledWith( + expect(MockEventTracker).toHaveBeenCalledWith( expect.any(Function), MOCK_INPUT.options ); @@ -145,7 +145,7 @@ describe('Pinpoint API: configureAutoTrack', () => { // Enable the tracker configureAutoTrack(MOCK_INPUT); - expect(MockEventTracker).toBeCalledWith( + expect(MockEventTracker).toHaveBeenCalledWith( expect.any(Function), MOCK_INPUT.options ); diff --git a/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts b/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts index c89a31694f8..b28df4e618d 100644 --- a/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts +++ b/packages/analytics/__tests__/providers/pinpoint/apis/flushEvents.test.ts @@ -40,11 +40,11 @@ describe('Pinpoint API: flushEvents', () => { it('invokes the core flushEvents implementation', async () => { flushEvents(); - expect(mockResolveConfig).toBeCalledTimes(1); - expect(mockResolveCredentials).toBeCalledTimes(1); + expect(mockResolveConfig).toHaveBeenCalledTimes(1); + expect(mockResolveCredentials).toHaveBeenCalledTimes(1); await new Promise(process.nextTick); - expect(mockPinpointFlushEvents).toBeCalledWith({ + expect(mockPinpointFlushEvents).toHaveBeenCalledWith({ ...config, credentials, identityId, @@ -59,7 +59,10 @@ describe('Pinpoint API: flushEvents', () => { await new Promise(process.nextTick); - expect(mockPinpointFlushEvents).not.toBeCalled(); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(mockPinpointFlushEvents).not.toHaveBeenCalled(); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); }); diff --git a/packages/analytics/__tests__/providers/pinpoint/apis/identifyUser.test.ts b/packages/analytics/__tests__/providers/pinpoint/apis/identifyUser.test.ts index 57a093797d3..a64208f7c23 100644 --- a/packages/analytics/__tests__/providers/pinpoint/apis/identifyUser.test.ts +++ b/packages/analytics/__tests__/providers/pinpoint/apis/identifyUser.test.ts @@ -54,7 +54,7 @@ describe('Analytics Pinpoint Provider API: identifyUser', () => { }, }; await identifyUser(input); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ ...input, ...credentials, ...config, @@ -73,7 +73,7 @@ describe('Analytics Pinpoint Provider API: identifyUser', () => { userAttributes, }; await identifyUser({ ...input, options }); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ ...input, ...credentials, ...config, diff --git a/packages/analytics/__tests__/providers/pinpoint/apis/record.test.ts b/packages/analytics/__tests__/providers/pinpoint/apis/record.test.ts index 62c2082beb4..7ea5fdd0d5b 100644 --- a/packages/analytics/__tests__/providers/pinpoint/apis/record.test.ts +++ b/packages/analytics/__tests__/providers/pinpoint/apis/record.test.ts @@ -61,13 +61,13 @@ describe('Pinpoint API: record', () => { it('invokes the core record implementation', async () => { record(event); - expect(mockResolveCredentials).toBeCalledTimes(1); - expect(mockResolveConfig).toBeCalledTimes(1); + expect(mockResolveCredentials).toHaveBeenCalledTimes(1); + expect(mockResolveConfig).toHaveBeenCalledTimes(1); await new Promise(process.nextTick); - expect(mockPinpointRecord).toBeCalledTimes(1); - expect(mockPinpointRecord).toBeCalledWith({ + expect(mockPinpointRecord).toHaveBeenCalledTimes(1); + expect(mockPinpointRecord).toHaveBeenCalledWith({ appId, category: 'Analytics', credentials, @@ -85,8 +85,11 @@ describe('Pinpoint API: record', () => { await new Promise(process.nextTick); - expect(mockPinpointRecord).not.toBeCalled(); - expect(loggerWarnSpy).toBeCalledWith(expect.any(String), expect.any(Error)); + expect(mockPinpointRecord).not.toHaveBeenCalled(); + expect(loggerWarnSpy).toHaveBeenCalledWith( + expect.any(String), + expect.any(Error) + ); }); it('throws a validation error when event does not specify a name', () => { @@ -94,7 +97,7 @@ describe('Pinpoint API: record', () => { try { record(mockParams as RecordInput); - } catch (e) { + } catch (e: any) { expect(e.name).toEqual(AnalyticsValidationErrorCode.NoEventName); } @@ -108,7 +111,7 @@ describe('Pinpoint API: record', () => { await new Promise(process.nextTick); - expect(mockPinpointRecord).not.toBeCalled(); + expect(mockPinpointRecord).not.toHaveBeenCalled(); }); it('should dispatch a Hub event', async () => { @@ -116,7 +119,7 @@ describe('Pinpoint API: record', () => { await new Promise(process.nextTick); - expect(mockHubDispatch).toBeCalledWith( + expect(mockHubDispatch).toHaveBeenCalledWith( 'analytics', { event: 'record', data: event, message: 'Recording Analytics event' }, 'Analytics', diff --git a/packages/analytics/__tests__/testUtils/mockConstants.test.ts b/packages/analytics/__tests__/testUtils/mockConstants.ts similarity index 100% rename from packages/analytics/__tests__/testUtils/mockConstants.test.ts rename to packages/analytics/__tests__/testUtils/mockConstants.ts diff --git a/packages/analytics/__tests__/utils/eventBuffer/EventBuffer.test.ts b/packages/analytics/__tests__/utils/eventBuffer/EventBuffer.test.ts index 986e833e0d4..04104f50362 100644 --- a/packages/analytics/__tests__/utils/eventBuffer/EventBuffer.test.ts +++ b/packages/analytics/__tests__/utils/eventBuffer/EventBuffer.test.ts @@ -37,7 +37,7 @@ describe('EventBuffer', () => { }); it('flush all events at once', done => { - const results = []; + const results: number[] = []; const testEvents: TestEvent[] = [ { id: '1', timestamp: 1 }, { id: '2', timestamp: 2 }, @@ -69,7 +69,7 @@ describe('EventBuffer', () => { }); it('release all resources', done => { - const results = []; + const results: TestEvent[] = []; const testEvents: TestEvent[] = [ { id: '1', timestamp: 1 }, { id: '2', timestamp: 2 }, diff --git a/packages/analytics/jest.config.js b/packages/analytics/jest.config.js new file mode 100644 index 00000000000..96f85fb0774 --- /dev/null +++ b/packages/analytics/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 42, + functions: 58, + lines: 65, + statements: 68, + }, + }, + moduleNameMapper: { + uuid: require.resolve('uuid'), + }, +}; diff --git a/packages/analytics/package.json b/packages/analytics/package.json index 6baff7d8577..90468b3b4c8 100644 --- a/packages/analytics/package.json +++ b/packages/analytics/package.json @@ -110,47 +110,5 @@ "@rollup/plugin-typescript": "11.1.5", "rollup": "3.29.4", "typescript": "5.0.2" - }, - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testPathIgnorePatterns": [ - "/testUtils/" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ], - "setupFiles": [ - "/src/setupTests.ts" - ] } } diff --git a/packages/analytics/src/setupTests.ts b/packages/analytics/src/setupTests.ts deleted file mode 100644 index 980bec1759b..00000000000 --- a/packages/analytics/src/setupTests.ts +++ /dev/null @@ -1,8 +0,0 @@ -// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. -// SPDX-License-Identifier: Apache-2.0 -const anyGlobal = global as any; - -anyGlobal.navigator = anyGlobal.navigator || {}; - -// @ts-ignore -anyGlobal.navigator.sendBeacon = anyGlobal.navigator.sendBeacon || jest.fn(); diff --git a/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts b/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts index 7c16163a70c..70156efb52e 100644 --- a/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts +++ b/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts @@ -221,7 +221,7 @@ describe('AWSAppSyncRealTimeProvider', () => { }) ); - expect(mockError).toBeCalled(); + expect(mockError).toHaveBeenCalled(); }); test('subscription waiting for onopen with ws://localhost:8080 goes untranslated', async () => { @@ -334,7 +334,7 @@ describe('AWSAppSyncRealTimeProvider', () => { CS.ConnectionDisrupted, ]); // Watching for raised exception to be caught and logged - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', expect.stringContaining('error on bound '), expect.objectContaining({ @@ -442,7 +442,7 @@ describe('AWSAppSyncRealTimeProvider', () => { // When the socket is closed during handshake // Watching for raised exception to be caught and logged - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', expect.stringContaining('error on bound '), expect.objectContaining({ @@ -473,7 +473,7 @@ describe('AWSAppSyncRealTimeProvider', () => { payload: { data: {} }, }); - expect(mockNext).toBeCalled(); + expect(mockNext).toHaveBeenCalled(); }); test('subscription observer is triggered when a connection is formed and a data message is received after connection ack', async () => { @@ -499,7 +499,7 @@ describe('AWSAppSyncRealTimeProvider', () => { payload: { data: {} }, }); - expect(mockNext).toBeCalled(); + expect(mockNext).toHaveBeenCalled(); }); test('subscription observer is triggered when a connection is formed and a data message is received after connection ack and close triggered', async () => { @@ -524,7 +524,7 @@ describe('AWSAppSyncRealTimeProvider', () => { type: MESSAGE_TYPES.GQL_DATA, payload: { data: {} }, }); - expect(mockNext).toBeCalled(); + expect(mockNext).toHaveBeenCalled(); }); test('subscription observer error is triggered when a connection is formed the error is logged and reconnect is triggered', async () => { @@ -544,7 +544,7 @@ describe('AWSAppSyncRealTimeProvider', () => { type: MESSAGE_TYPES.GQL_ERROR, payload: { data: {} }, }); - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Connection failed: {"data":{}}' ); @@ -553,7 +553,7 @@ describe('AWSAppSyncRealTimeProvider', () => { ]); }); - test('subscription observer error is triggered when a connection is formed and a non-retriable connection_error data message is received', async done => { + test('subscription observer error is triggered when a connection is formed and a non-retriable connection_error data message is received', async () => { expect.assertions(3); const socketCloseSpy = jest.spyOn( @@ -571,7 +571,6 @@ describe('AWSAppSyncRealTimeProvider', () => { expect(e.errors[0].message).toEqual( 'Connection failed: Non-retriable Test' ); - done(); }, }); @@ -594,7 +593,7 @@ describe('AWSAppSyncRealTimeProvider', () => { ); // Watching for raised exception to be caught and logged - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', expect.stringContaining('error on bound '), expect.objectContaining({ @@ -618,7 +617,7 @@ describe('AWSAppSyncRealTimeProvider', () => { await fakeWebSocketInterface?.standardConnectionHandshake(); await fakeWebSocketInterface?.triggerError(); - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Disconnect error: Connection closed' ); @@ -661,7 +660,7 @@ describe('AWSAppSyncRealTimeProvider', () => { await openSocketAttempt(); // Watching for raised exception to be caught and logged - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', expect.stringContaining('error on bound '), expect.objectContaining({ @@ -673,7 +672,7 @@ describe('AWSAppSyncRealTimeProvider', () => { CS.ConnectionDisrupted, ]); - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Connection failed: Retriable Test' ); @@ -717,7 +716,7 @@ describe('AWSAppSyncRealTimeProvider', () => { CS.ConnectedPendingKeepAlive ); - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Disconnect error: Timeout disconnect' ); @@ -882,7 +881,7 @@ describe('AWSAppSyncRealTimeProvider', () => { CS.ConnectionDisrupted, ]); - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'timeoutStartSubscription', expect.anything() @@ -915,7 +914,7 @@ describe('AWSAppSyncRealTimeProvider', () => { ).toBe(CS.Connecting); // Watching for raised exception to be caught and logged - expect(loggerSpy).not.toBeCalledWith( + expect(loggerSpy).not.toHaveBeenCalledWith( 'DEBUG', expect.stringContaining('error on bound '), expect.objectContaining({ @@ -950,7 +949,7 @@ describe('AWSAppSyncRealTimeProvider', () => { ]); // Watching for raised exception to be caught and logged - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', expect.stringContaining('error on bound '), expect.objectContaining({ @@ -976,7 +975,7 @@ describe('AWSAppSyncRealTimeProvider', () => { await fakeWebSocketInterface?.readyForUse; - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Authenticating with "apiKey"' ); @@ -994,7 +993,7 @@ describe('AWSAppSyncRealTimeProvider', () => { await fakeWebSocketInterface?.readyForUse; - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Authenticating with "iam"' ); @@ -1012,7 +1011,7 @@ describe('AWSAppSyncRealTimeProvider', () => { await fakeWebSocketInterface?.readyForUse; - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Authenticating with "oidc"' ); @@ -1029,7 +1028,7 @@ describe('AWSAppSyncRealTimeProvider', () => { .subscribe({ error: () => {} }); await fakeWebSocketInterface?.readyForUse; - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Authenticating with "oidc"' ); @@ -1050,7 +1049,7 @@ describe('AWSAppSyncRealTimeProvider', () => { await fakeWebSocketInterface?.readyForUse; - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'Authenticating with "none"' ); @@ -1093,7 +1092,7 @@ describe('AWSAppSyncRealTimeProvider', () => { // TODO Find a better way to give the catch stack time to resolve await delay(10); - expect(loggerSpy).toBeCalledWith( + expect(loggerSpy).toHaveBeenCalledWith( 'DEBUG', 'AppSync Realtime subscription init error: Error: No auth token specified' ); diff --git a/packages/api-graphql/__tests__/GraphQLAPI.test.ts b/packages/api-graphql/__tests__/GraphQLAPI.test.ts index cff9b2d3ee4..066e53ba945 100644 --- a/packages/api-graphql/__tests__/GraphQLAPI.test.ts +++ b/packages/api-graphql/__tests__/GraphQLAPI.test.ts @@ -685,7 +685,7 @@ describe('API test', () => { variables: graphqlVariables, authMode: 'oidc', }) - ).rejects.toThrowError('No current user'); + ).rejects.toThrow('No current user'); // Cleanup: mockAccessToken = prevMockAccessToken; @@ -762,7 +762,7 @@ describe('API test', () => { variables: graphqlVariables, authMode: 'lambda', }) - ).rejects.toThrowError(GraphQLAuthError.NO_AUTH_TOKEN); + ).rejects.toThrow(GraphQLAuthError.NO_AUTH_TOKEN); }); test('multi-auth using API_KEY as auth mode, but no api-key configured', async () => { @@ -784,7 +784,7 @@ describe('API test', () => { variables: graphqlVariables, authMode: 'apiKey', }) - ).rejects.toThrowError(GraphQLAuthError.NO_API_KEY); + ).rejects.toThrow(GraphQLAuthError.NO_API_KEY); }); test('multi-auth using AWS_IAM as auth mode, but no credentials', async () => { @@ -810,7 +810,7 @@ describe('API test', () => { variables: graphqlVariables, authMode: 'iam', }) - ).rejects.toThrowError(GraphQLAuthError.NO_CREDENTIALS); + ).rejects.toThrow(GraphQLAuthError.NO_CREDENTIALS); // Cleanup: mockCredentials = prevMockCredentials; @@ -905,7 +905,7 @@ describe('API test', () => { }) as any ).subscribe(); - expect(spyon_appsync_realtime).toBeCalledWith( + expect(spyon_appsync_realtime).toHaveBeenCalledWith( expect.objectContaining({ authenticationType: 'oidc', }), @@ -913,7 +913,7 @@ describe('API test', () => { ); }); - test('happy-case-subscription', async done => { + test('happy-case-subscription', done => { const spyon_appsync_realtime = jest .spyOn(AWSAppSyncRealTimeProvider.prototype, 'subscribe') .mockImplementation(jest.fn(() => of({}) as any)); @@ -942,7 +942,7 @@ describe('API test', () => { expect(observable).not.toBe(undefined); }); - test('happy case subscription with additionalHeaders', async done => { + test('happy case subscription with additionalHeaders', done => { const spyon_appsync_realtime = jest .spyOn(AWSAppSyncRealTimeProvider.prototype, 'subscribe') .mockImplementation(jest.fn(() => of({}) as any)); diff --git a/packages/api-graphql/__tests__/generateClient.test.ts b/packages/api-graphql/__tests__/generateClient.test.ts index fb46142dd87..efe6ac50b5a 100644 --- a/packages/api-graphql/__tests__/generateClient.test.ts +++ b/packages/api-graphql/__tests__/generateClient.test.ts @@ -1298,7 +1298,7 @@ describe('generateClient', () => { client.models.Note.onDelete({ authMode: 'userPool', - }).subscribe({ + } as any).subscribe({ next(value) { expect(spy).toHaveBeenCalledWith( expect.objectContaining({ @@ -1926,7 +1926,7 @@ describe('generateClient', () => { client.models.Note.onUpdate({ authMode: 'lambda', authToken: 'some-token', - }).subscribe({ + } as any).subscribe({ next(value) { expect(spy).toHaveBeenCalledWith( expect.objectContaining({ @@ -1964,7 +1964,7 @@ describe('generateClient', () => { client.models.Note.onDelete({ authMode: 'lambda', authToken: 'some-token', - }).subscribe({ + } as any).subscribe({ next(value) { expect(spy).toHaveBeenCalledWith( expect.objectContaining({ @@ -4736,7 +4736,7 @@ describe('generateClient', () => { }); }); - test('can see creates - with non-empty query result', async done => { + test('can see creates - with non-empty query result', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ @@ -4805,7 +4805,7 @@ describe('generateClient', () => { }); }); - test('can see creates - with empty query result', async done => { + test('can see creates - with empty query result', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ @@ -4854,7 +4854,7 @@ describe('generateClient', () => { }); }); - test('can see onCreates that are received prior to fetch completion', async done => { + test('can see onCreates that are received prior to fetch completion', done => { const client = generateClient({ amplify: Amplify }); // to record which order @@ -4937,7 +4937,7 @@ describe('generateClient', () => { callSequence.push('onCreate'); }); - test('can see onUpdates that are received prior to fetch completion', async done => { + test('can see onUpdates that are received prior to fetch completion', done => { const client = generateClient({ amplify: Amplify }); // to record which order @@ -5013,7 +5013,7 @@ describe('generateClient', () => { callSequence.push('onUpdate'); }); - test('can see onDeletes that are received prior to fetch completion', async done => { + test('can see onDeletes that are received prior to fetch completion', done => { const client = generateClient({ amplify: Amplify }); // to record which order @@ -5082,7 +5082,7 @@ describe('generateClient', () => { callSequence.push('onDelete'); }); - test('can see updates', async done => { + test('can see updates', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ @@ -5143,7 +5143,7 @@ describe('generateClient', () => { }); }); - test('can see deletions', async done => { + test('can see deletions', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ @@ -5219,7 +5219,7 @@ describe('generateClient', () => { }); }); - test('uses configured authMode by default', async done => { + test('uses configured authMode by default', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ data: { @@ -5247,7 +5247,7 @@ describe('generateClient', () => { }); }); - test('uses provided authMode at call site', async done => { + test('uses provided authMode at call site', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ data: { @@ -5274,7 +5274,7 @@ describe('generateClient', () => { }); }); - test('uses provided authToken at call site', async done => { + test('uses provided authToken at call site', done => { const client = generateClient({ amplify: Amplify }); mockApiResponse({ data: { @@ -5305,7 +5305,7 @@ describe('generateClient', () => { }); }); - test('uses provided authMode from the client', async done => { + test('uses provided authMode from the client', done => { const client = generateClient({ amplify: Amplify, authMode: 'userPool', @@ -5335,7 +5335,7 @@ describe('generateClient', () => { }); }); - test('uses provided authToken from the client', async done => { + test('uses provided authToken from the client', done => { const client = generateClient({ amplify: Amplify, authMode: 'lambda', diff --git a/packages/api-graphql/__tests__/helpers.ts b/packages/api-graphql/__tests__/helpers.ts index c9714e6f67a..08a8261546d 100644 --- a/packages/api-graphql/__tests__/helpers.ts +++ b/packages/api-graphql/__tests__/helpers.ts @@ -15,13 +15,11 @@ export function delay(timeout) { export class HubConnectionListener { teardownHubListener: () => void; observedConnectionStates: CS[] = []; - currentConnectionState: CS; + currentConnectionState!: CS; private connectionStateObservers: Observer[] = []; constructor(channel: string) { - let closeResolver: (value: PromiseLike) => void; - this.teardownHubListener = Hub.listen(channel, (data: any) => { const { payload } = data; if (payload.event === CONNECTION_STATE_CHANGE) { @@ -87,12 +85,12 @@ export class HubConnectionListener { } export class FakeWebSocketInterface { - webSocket: FakeWebSocket; - readyForUse: Promise; - hasClosed: Promise; + webSocket!: FakeWebSocket; + readyForUse!: Promise; + hasClosed!: Promise; hubConnectionListener: HubConnectionListener; - private readyResolve: (value: PromiseLike) => void; + private readyResolve!: (value: PromiseLike) => void; constructor() { this.hubConnectionListener = new HubConnectionListener('api'); @@ -299,16 +297,16 @@ class FakeWebSocket implements WebSocket { subscriptionId: string | undefined; closeResolverFcn: () => (value: PromiseLike) => void; - binaryType: BinaryType; - bufferedAmount: number; - extensions: string; - onclose: (this: WebSocket, ev: CloseEvent) => any; - onerror: (this: WebSocket, ev: Event) => any; - onmessage: (this: WebSocket, ev: MessageEvent) => any; - onopen: (this: WebSocket, ev: Event) => any; - protocol: string; - readyState: number; - url: string; + binaryType!: BinaryType; + bufferedAmount!: number; + extensions!: string; + onclose!: (this: WebSocket, ev: CloseEvent) => any; + onerror!: (this: WebSocket, ev: Event) => any; + onmessage!: (this: WebSocket, ev: MessageEvent) => any; + onopen!: (this: WebSocket, ev: Event) => any; + protocol!: string; + readyState!: number; + url!: string; close(code?: number, reason?: string): void { const closeResolver = this.closeResolverFcn(); if (closeResolver) closeResolver(Promise.resolve(undefined)); @@ -354,10 +352,10 @@ class FakeWebSocket implements WebSocket { constructor(closeResolver: () => (value: PromiseLike) => void) { this.closeResolverFcn = closeResolver; } - CONNECTING: 0; - OPEN: 1; - CLOSING: 2; - CLOSED: 3; + CONNECTING: 0 = 0; + OPEN: 1 = 1; + CLOSING: 2 = 2; + CLOSED: 3 = 3; } export async function replaceConstant( diff --git a/packages/api-graphql/__tests__/server/generateClient.test.ts b/packages/api-graphql/__tests__/server/generateClient.test.ts index 06d7b78ef18..704b4165557 100644 --- a/packages/api-graphql/__tests__/server/generateClient.test.ts +++ b/packages/api-graphql/__tests__/server/generateClient.test.ts @@ -57,7 +57,7 @@ describe('server generateClient', () => { expect(() => { // @ts-expect-error client.models.Note.onCreate().subscribe(); - }).toThrowError(); + }).toThrow(); }); test('can list', async () => { @@ -277,7 +277,7 @@ describe('server generateClient', () => { expect(() => { // @ts-expect-error client.models.Note.onCreate().subscribe(); - }).toThrowError(); + }).toThrow(); }); test('contextSpec param gets passed through to client.graphql', async () => { diff --git a/packages/api-graphql/jest.config.js b/packages/api-graphql/jest.config.js new file mode 100644 index 00000000000..5a542c861b5 --- /dev/null +++ b/packages/api-graphql/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 61, + functions: 71, + lines: 75, + statements: 76, + }, + }, +}; diff --git a/packages/api-graphql/package.json b/packages/api-graphql/package.json index 93d8e8aa321..cf902fe5986 100644 --- a/packages/api-graphql/package.json +++ b/packages/api-graphql/package.json @@ -95,55 +95,5 @@ "import": "{ Amplify, GraphQLAPI }", "limit": "91.7 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "lib": [ - "dom", - "es2020" - ], - "allowJs": true, - "noEmitOnError": false, - "strictNullChecks": true, - "types": [ - "@types/jest" - ] - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "/__tests__/helpers.ts", - "/__tests__/fixtures/", - "/__tests__/utils/" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "/dist", - "/__tests__" - ] - } + ] } diff --git a/packages/api-rest/__tests__/apis/common/internalPost.test.ts b/packages/api-rest/__tests__/apis/common/internalPost.test.ts index 001c684c2fd..0d4014532f6 100644 --- a/packages/api-rest/__tests__/apis/common/internalPost.test.ts +++ b/packages/api-rest/__tests__/apis/common/internalPost.test.ts @@ -62,7 +62,7 @@ describe('internal post', () => { }, }, }); - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: apiGatewayUrl, method: 'POST', @@ -81,7 +81,7 @@ describe('internal post', () => { }, }, }); - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: apiGatewayUrl, method: 'POST', @@ -97,7 +97,7 @@ describe('internal post', () => { signingServiceInfo: {}, }, }); - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: apiGatewayUrl, method: 'POST', @@ -115,7 +115,7 @@ describe('internal post', () => { signingServiceInfo: {}, }, }); - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: apiGatewayUrl, method: 'POST', @@ -137,7 +137,7 @@ describe('internal post', () => { signingServiceInfo: {}, }, }); - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: apiGatewayUrl, method: 'POST', @@ -154,7 +154,7 @@ describe('internal post', () => { await post(mockAmplifyInstance, { url: apiGatewayUrl, }); - expect(mockUnauthenticatedHandler).toBeCalledWith( + expect(mockUnauthenticatedHandler).toHaveBeenCalledWith( { url: apiGatewayUrl, method: 'POST', @@ -174,7 +174,7 @@ describe('internal post', () => { signingServiceInfo: {}, }, }); - expect(mockUnauthenticatedHandler).toBeCalledWith( + expect(mockUnauthenticatedHandler).toHaveBeenCalledWith( expect.objectContaining({ headers: { 'x-api-key': '123', @@ -182,7 +182,7 @@ describe('internal post', () => { }), expect.anything() ); - expect(mockAuthenticatedHandler).not.toBeCalled(); + expect(mockAuthenticatedHandler).not.toHaveBeenCalled(); }); it('should call unauthenticatedHandler with custom authorization header and signingServiceInfo', async () => { @@ -195,7 +195,7 @@ describe('internal post', () => { signingServiceInfo: {}, }, }); - expect(mockUnauthenticatedHandler).toBeCalledWith( + expect(mockUnauthenticatedHandler).toHaveBeenCalledWith( expect.objectContaining({ headers: { authorization: '123', @@ -203,7 +203,7 @@ describe('internal post', () => { }), expect.anything() ); - expect(mockAuthenticatedHandler).not.toBeCalled(); + expect(mockAuthenticatedHandler).not.toHaveBeenCalled(); }); it('should abort request when cancel is called', async () => { @@ -236,7 +236,7 @@ describe('internal post', () => { try { await promise; fail('should throw cancel error'); - } catch (error) { + } catch (error: any) { expect(abortSignal.aborted).toBe(true); expect(isCancelError(error)).toBe(true); expect(error.message).toBe(cancelMessage); @@ -264,7 +264,7 @@ describe('internal post', () => { }); fail('should throw RestApiError'); } catch (error) { - expect(mockParseJsonError).toBeCalledWith(errorResponse); + expect(mockParseJsonError).toHaveBeenCalledWith(errorResponse); expect(error).toEqual(expect.any(RestApiError)); } }); diff --git a/packages/api-rest/__tests__/apis/common/publicApis.test.ts b/packages/api-rest/__tests__/apis/common/publicApis.test.ts index ac7ee59cc3b..82adcea15cf 100644 --- a/packages/api-rest/__tests__/apis/common/publicApis.test.ts +++ b/packages/api-rest/__tests__/apis/common/publicApis.test.ts @@ -99,7 +99,7 @@ describe('public APIs', () => { withCredentials: true, }, }).response; - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: new URL( 'https://123.execute-api.us-west-2.amazonaws.com/development/items' @@ -132,7 +132,7 @@ describe('public APIs', () => { apiName: 'restApi1', path: '/items', }).response; - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: new URL( 'https://123.execute-api.us-west-2.amazonaws.com/development/items' @@ -160,7 +160,7 @@ describe('public APIs', () => { }, }, }).response; - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( { url: new URL( 'https://123.execute-api.us-west-2.amazonaws.com/development/items' @@ -183,7 +183,7 @@ describe('public APIs', () => { apiName: 'restApi1', path: '/items/123', }).response; - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( expect.objectContaining({ url: new URL( 'https://123.execute-api.us-west-2.amazonaws.com/development/items/123' @@ -203,13 +203,11 @@ describe('public APIs', () => { }, }, }).response; - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( expect.objectContaining({ - url: expect.objectContaining( - new URL( - 'https://123.execute-api.us-west-2.amazonaws.com/development/items?param1=value1' - ) - ), + url: expect.objectContaining({ + href: 'https://123.execute-api.us-west-2.amazonaws.com/development/items?param1=value1', + }), }), expect.anything() ); @@ -225,13 +223,11 @@ describe('public APIs', () => { }, }, }).response; - expect(mockAuthenticatedHandler).toBeCalledWith( + expect(mockAuthenticatedHandler).toHaveBeenCalledWith( expect.objectContaining({ - url: expect.objectContaining( - new URL( - 'https://123.execute-api.us-west-2.amazonaws.com/development/items?param1=value1&foo=bar' - ) - ), + url: expect.objectContaining({ + href: 'https://123.execute-api.us-west-2.amazonaws.com/development/items?param1=value1&foo=bar', + }), }), expect.anything() ); @@ -308,7 +304,7 @@ describe('public APIs', () => { }).response; fail('should throw RestApiError'); } catch (error) { - expect(mockParseJsonError).toBeCalledWith(errorResponse); + expect(mockParseJsonError).toHaveBeenCalledWith(errorResponse); expect(error).toEqual(expect.any(RestApiError)); } }); @@ -334,11 +330,13 @@ describe('public APIs', () => { path: '/items', }); const cancelMessage = 'cancelMessage'; - cancel(cancelMessage); try { + setTimeout(() => { + cancel(cancelMessage); + }); await response; fail('should throw cancel error'); - } catch (error) { + } catch (error: any) { expect(isCancelError(error)).toBe(true); expect(error.message).toBe(cancelMessage); } diff --git a/packages/api-rest/jest.config.js b/packages/api-rest/jest.config.js new file mode 100644 index 00000000000..f9b0f5880d9 --- /dev/null +++ b/packages/api-rest/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 82, + functions: 89, + lines: 94, + statements: 95, + }, + }, +}; diff --git a/packages/api-rest/package.json b/packages/api-rest/package.json index dd15c55947d..e00d79ead82 100644 --- a/packages/api-rest/package.json +++ b/packages/api-rest/package.json @@ -100,47 +100,5 @@ "import": "{ Amplify, RestAPI }", "limit": "31.5 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testPathIgnorePatterns": [ - "/testUtils/" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ], - "setupFiles": [ - "/setupTests.ts" - ] - } + ] } diff --git a/packages/api-rest/src/utils/createCancellableOperation.ts b/packages/api-rest/src/utils/createCancellableOperation.ts index d4b592d2a67..26535a7e71d 100644 --- a/packages/api-rest/src/utils/createCancellableOperation.ts +++ b/packages/api-rest/src/utils/createCancellableOperation.ts @@ -45,6 +45,7 @@ export function createCancellableOperation( const publicApisAbortController = new AbortController(); const publicApisAbortSignal = publicApisAbortController.signal; const internalPostAbortSignal = abortController?.signal; + let abortReason: string; const job = async () => { try { @@ -58,9 +59,10 @@ export function createCancellableOperation( return response; } catch (error: any) { const abortSignal = internalPostAbortSignal ?? publicApisAbortSignal; + const message = abortReason ?? abortSignal.reason; if (error.name === 'AbortError' || abortSignal?.aborted === true) { const canceledError = new CanceledError({ - ...(abortSignal.reason ? { message: abortSignal.reason } : undefined), + ...(message && { message }), underlyingError: error, }); logger.debug(error); @@ -79,14 +81,10 @@ export function createCancellableOperation( return; } publicApisAbortController.abort(abortMessage); - // Abort reason is not widely support enough across runtimes and and browsers, so we set it - // if it is not already set. + // If abort reason is not supported, set a scoped reasons instead. The reason property inside an + // AbortSignal is a readonly property and trying to set it would throw an error. if (abortMessage && publicApisAbortSignal.reason !== abortMessage) { - type AbortSignalWithReasonSupport = Omit & { - reason?: string; - }; - (publicApisAbortSignal as AbortSignalWithReasonSupport)['reason'] = - abortMessage; + abortReason = abortMessage; } }; return { response: job(), cancel }; diff --git a/packages/api/__tests__/API.test.ts b/packages/api/__tests__/API.test.ts index 241d6fcc1db..10db1dd078b 100644 --- a/packages/api/__tests__/API.test.ts +++ b/packages/api/__tests__/API.test.ts @@ -27,7 +27,7 @@ describe('API generateClient', () => { .mockResolvedValue('grapqhqlResponse' as any); const client = generateClient(); expect(await client.graphql({ query: 'query' })).toBe('grapqhqlResponse'); - expect(spy).toBeCalledWith( + expect(spy).toHaveBeenCalledWith( { Auth: {}, libraryOptions: {}, resourcesConfig: {} }, { query: 'query' }, undefined, diff --git a/packages/api/jest.config.js b/packages/api/jest.config.js new file mode 100644 index 00000000000..3a0e3340f9f --- /dev/null +++ b/packages/api/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}; diff --git a/packages/api/package.json b/packages/api/package.json index 12704b1f978..1d4d12d3ff7 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -84,55 +84,5 @@ "@aws-amplify/api-graphql": "4.0.5", "@aws-amplify/api-rest": "4.0.5", "tslib": "^2.5.0" - }, - "jest": { - "globals": { - "ts-jest": { - "diagnostics": { - "pathRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$" - }, - "tsConfig": { - "lib": [ - "es5", - "es2015", - "dom", - "esnext.asynciterable", - "es2017.object" - ], - "allowJs": true, - "noEmitOnError": false, - "strictNullChecks": true, - "types": [ - "@types/jest" - ] - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist", - "__tests__" - ] } } diff --git a/packages/auth/__tests__/providers/cognito/assertServiceError.test.ts b/packages/auth/__tests__/providers/cognito/assertServiceError.test.ts index 2d9a4e0a3e1..873801dfec0 100644 --- a/packages/auth/__tests__/providers/cognito/assertServiceError.test.ts +++ b/packages/auth/__tests__/providers/cognito/assertServiceError.test.ts @@ -7,8 +7,8 @@ describe('asserts service errors', () => { test('it should throw an unknown error when error is null', () => { try { const error = null; - expect(assertServiceError(error)).toThrowError(); - } catch (error) { + expect(assertServiceError(error)).toThrow(); + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AmplifyErrorCode.Unknown); } @@ -16,8 +16,8 @@ describe('asserts service errors', () => { test('it should throw an unknown error when error is a TypeError', () => { try { const error = new TypeError('TypeError'); - expect(assertServiceError(error)).toThrowError(); - } catch (error) { + expect(assertServiceError(error)).toThrow(); + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AmplifyErrorCode.Unknown); } @@ -25,8 +25,8 @@ describe('asserts service errors', () => { test('it should throw an unknown error when error does not have a name', () => { try { const error = new Error('Error'); - expect(assertServiceError(error)).toThrowError(); - } catch (error) { + expect(assertServiceError(error)).toThrow(); + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AmplifyErrorCode.Unknown); } diff --git a/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts b/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts index 8765a94aa72..db8ac93c9eb 100644 --- a/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts +++ b/packages/auth/__tests__/providers/cognito/autoSignIn.test.ts @@ -8,11 +8,13 @@ import { import { autoSignIn } from '../../../src/providers/cognito/apis/autoSignIn'; import * as signUpClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { authAPITestParams } from './testUtils/authApiTestParams'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; +import { + RespondToAuthChallengeCommandOutput, + SignUpCommandOutput, +} from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { Amplify } from 'aws-amplify'; import * as initiateAuthHelpers from '../../../src/providers/cognito/utils/signInHelpers'; import { AuthError } from '../../../src/errors/AuthError'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); const authConfig = { Cognito: { @@ -31,11 +33,9 @@ describe('Auto sign-in API Happy Path Cases:', () => { beforeEach(async () => { signUpSpy = jest .spyOn(signUpClient, 'signUp') - .mockImplementationOnce(async () => { - return { - UserConfirmed: true, - }; - }); + .mockImplementationOnce( + async () => ({ UserConfirmed: true } as SignUpCommandOutput) + ); handleUserSRPAuthflowSpy = jest .spyOn(initiateAuthHelpers, 'handleUserSRPAuthFlow') @@ -63,13 +63,13 @@ describe('Auto sign-in API Happy Path Cases:', () => { signUpStep: 'COMPLETE_AUTO_SIGN_IN', }, }); - expect(signUpSpy).toBeCalledTimes(1); + expect(signUpSpy).toHaveBeenCalledTimes(1); }); test('Auto sign-in should resolve to a signIn output', async () => { const signInOutput = await autoSignIn(); expect(signInOutput).toEqual(authAPITestParams.signInResult()); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); }); }); @@ -77,7 +77,7 @@ describe('Auto sign-in API Error Path Cases:', () => { test('autoSignIn should throw an error when autoSignIn is not enabled', async () => { try { await autoSignIn(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe('AutoSignInException'); } diff --git a/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts b/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts index 7f169c1c870..62220174c56 100644 --- a/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmResetPassword.test.ts @@ -1,48 +1,50 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { Amplify } from 'aws-amplify'; +import { Amplify } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { confirmResetPassword } from '../../../src/providers/cognito'; import { ConfirmForgotPasswordException } from '../../../src/providers/cognito/types/errors'; -import * as confirmResetPasswordClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { confirmForgotPassword } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { authAPITestParams } from './testUtils/authApiTestParams'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, - }, -}); -describe('ConfirmResetPassword API happy path cases', () => { - let confirmForgotPasswordSpy; +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('confirmResetPassword', () => { + // assert mocks + const mockConfirmForgotPassword = confirmForgotPassword as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + }); beforeEach(() => { - confirmForgotPasswordSpy = jest - .spyOn(confirmResetPasswordClient, 'confirmForgotPassword') - .mockImplementationOnce(async () => { - return authAPITestParams.confirmResetPasswordHttpCallResult; - }); + mockConfirmForgotPassword.mockResolvedValue( + authAPITestParams.confirmResetPasswordHttpCallResult + ); }); afterEach(() => { - confirmForgotPasswordSpy.mockClear(); + mockConfirmForgotPassword.mockReset(); }); - test('ConfirmResetPassword API should call the UserPoolClient and return void', async () => { + it('should call the confirmForgotPassword and return void', async () => { expect( await confirmResetPassword(authAPITestParams.confirmResetPasswordRequest) ).toBeUndefined(); - expect(confirmForgotPasswordSpy).toBeCalled(); + expect(mockConfirmForgotPassword).toHaveBeenCalled(); }); - test('ConfirmResetPassword API input should contain clientMetadata from request', async () => { + it('should contain clientMetadata from request', async () => { await confirmResetPassword({ username: 'username', newPassword: 'password', @@ -51,7 +53,7 @@ describe('ConfirmResetPassword API happy path cases', () => { clientMetadata: { fooo: 'fooo' }, }, }); - expect(confirmForgotPasswordSpy).toHaveBeenCalledWith( + expect(mockConfirmForgotPassword).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ Username: 'username', @@ -62,10 +64,8 @@ describe('ConfirmResetPassword API happy path cases', () => { }) ); }); -}); -describe('ConfirmResetPassword API error path cases', () => { - test('ConfirmResetPassword API should throw a validation AuthError when username is empty', async () => { + it('should throw an error when username is empty', async () => { expect.assertions(2); try { await confirmResetPassword({ @@ -73,7 +73,7 @@ describe('ConfirmResetPassword API error path cases', () => { newPassword: 'password', confirmationCode: 'code', }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AuthValidationErrorCode.EmptyConfirmResetPasswordUsername @@ -81,7 +81,7 @@ describe('ConfirmResetPassword API error path cases', () => { } }); - test('ConfirmResetPassword API should throw a validation AuthError when newPassword is empty', async () => { + it('should throw an error when newPassword is empty', async () => { expect.assertions(2); try { await confirmResetPassword({ @@ -89,7 +89,7 @@ describe('ConfirmResetPassword API error path cases', () => { newPassword: '', confirmationCode: 'code', }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AuthValidationErrorCode.EmptyConfirmResetPasswordNewPassword @@ -97,7 +97,7 @@ describe('ConfirmResetPassword API error path cases', () => { } }); - test('ConfirmResetPassword API should throw a validation AuthError when confirmationCode is empty', async () => { + it('should throw an error when confirmationCode is empty', async () => { expect.assertions(2); try { await confirmResetPassword({ @@ -105,7 +105,7 @@ describe('ConfirmResetPassword API error path cases', () => { newPassword: 'password', confirmationCode: '', }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AuthValidationErrorCode.EmptyConfirmResetPasswordConfirmationCode @@ -113,48 +113,30 @@ describe('ConfirmResetPassword API error path cases', () => { } }); - test('ConfirmResetPassword API should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - ConfirmForgotPasswordException.InvalidParameterException - ) - ) - ); + mockConfirmForgotPassword.mockImplementation(() => { + throw getMockError( + ConfirmForgotPasswordException.InvalidParameterException + ); + }); try { await confirmResetPassword(authAPITestParams.confirmResetPasswordRequest); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( ConfirmForgotPasswordException.InvalidParameterException ); } }); -}); - -describe('Cognito ASF', () => { - let confirmForgotPasswordSpy; - beforeEach(() => { - // load Cognito ASF polyfill + it('should add UserContextData', async () => { window['AmazonCognitoAdvancedSecurityData'] = { getData() { return 'abcd'; }, }; - confirmForgotPasswordSpy = jest - .spyOn(confirmResetPasswordClient, 'confirmForgotPassword') - .mockImplementationOnce(async () => { - return authAPITestParams.confirmResetPasswordHttpCallResult; - }); - }); - afterEach(() => { - confirmForgotPasswordSpy.mockClear(); - window['AmazonCognitoAdvancedSecurityData'] = undefined; - }); - test('Check UserContextData is added', async () => { await confirmResetPassword({ username: 'username', newPassword: 'password', @@ -163,7 +145,7 @@ describe('Cognito ASF', () => { clientMetadata: { fooo: 'fooo' }, }, }); - expect(confirmForgotPasswordSpy).toHaveBeenCalledWith( + expect(mockConfirmForgotPassword).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ Username: 'username', @@ -176,5 +158,6 @@ describe('Cognito ASF', () => { }, }) ); + window['AmazonCognitoAdvancedSecurityData'] = undefined; }); }); diff --git a/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts b/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts index 107e9a07299..e8a3108205b 100644 --- a/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmSignInErrorCases.test.ts @@ -1,84 +1,74 @@ +import { Amplify } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { authAPITestParams } from './testUtils/authApiTestParams'; -import { signIn } from '../../../src/providers/cognito/apis/signIn'; -import * as signInHelpers from '../../../src/providers/cognito/utils/signInHelpers'; import { confirmSignIn } from '../../../src/providers/cognito/apis/confirmSignIn'; import { RespondToAuthChallengeException } from '../../../src/providers/cognito/types/errors'; -import { RespondToAuthChallengeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { Amplify } from 'aws-amplify'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { respondToAuthChallenge } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; +import { signInStore } from '../../../src/providers/cognito/utils/signInStore'; + +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); +jest.mock('../../../src/providers/cognito/utils/signInStore'); -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, - }, -}); describe('confirmSignIn API error path cases:', () => { - let handleUserSRPAuthflowSpy; + const challengeName = 'SELECT_MFA_TYPE'; + const signInSession = '1234234232'; const username = authAPITestParams.user1.username; - const password = authAPITestParams.user1.password; - beforeEach(async () => { - handleUserSRPAuthflowSpy = jest - .spyOn(signInHelpers, 'handleUserSRPAuthFlow') - .mockImplementationOnce( - async (): Promise => ({ - ChallengeName: 'SELECT_MFA_TYPE', - Session: '1234234232', - $metadata: {}, - ChallengeParameters: { - MFAS_CAN_CHOOSE: '["SMS_MFA","SOFTWARE_TOKEN_MFA"]', - }, - }) - ); + // assert mocks + const mockStoreGetState = signInStore.getState as jest.Mock; + const mockRespondToAuthChallenge = respondToAuthChallenge as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockStoreGetState.mockReturnValue({ + username, + challengeName, + signInSession, + }); }); afterEach(() => { - handleUserSRPAuthflowSpy.mockClear(); + mockRespondToAuthChallenge.mockReset(); }); - test('confirmSignIn API should throw a validation AuthError when challengeResponse is empty', async () => { + it('confirmSignIn API should throw an error when challengeResponse is empty', async () => { expect.assertions(2); try { await confirmSignIn({ challengeResponse: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptyChallengeResponse); } }); - test(`confirmSignIn API should throw a validation AuthError when sign-in step is - ${'CONTINUE_SIGN_IN_WITH_MFA_SELECTION'} and challengeResponse is not "SMS" or "TOTP" `, async () => { + it('should throw an error when sign-in step is CONTINUE_SIGN_IN_WITH_MFA_SELECTION and challengeResponse is not "SMS" or "TOTP"', async () => { expect.assertions(2); try { - await signIn({ username, password }); await confirmSignIn({ challengeResponse: 'NO_SMS' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.IncorrectMFAMethod); } }); - test('confirmSignIn API should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - RespondToAuthChallengeException.InvalidParameterException - ) - ) - ); + mockRespondToAuthChallenge.mockImplementation(() => { + throw getMockError( + RespondToAuthChallengeException.InvalidParameterException + ); + }); try { - await signIn({ username, password }); - await confirmSignIn({ - challengeResponse: 'TOTP', - }); - } catch (error) { + await confirmSignIn({ challengeResponse: 'TOTP' }); + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( RespondToAuthChallengeException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts b/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts index ce6cc7457af..2e3759ab807 100644 --- a/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmSignInHappyCases.test.ts @@ -113,9 +113,9 @@ describe('confirmSignIn API happy path cases', () => { }, }); - expect(handleChallengeNameSpy).toBeCalledTimes(1); + expect(handleChallengeNameSpy).toHaveBeenCalledTimes(1); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); handleUserSRPAuthflowSpy.mockClear(); mockedGetCurrentUser.mockClear(); }); @@ -154,9 +154,9 @@ describe('confirmSignIn API happy path cases', () => { }, }); - expect(handleChallengeNameSpy).toBeCalledTimes(1); + expect(handleChallengeNameSpy).toHaveBeenCalledTimes(1); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); handleUserSRPAuthflowSpy.mockClear(); }); @@ -217,9 +217,9 @@ describe('confirmSignIn API happy path cases', () => { }, }); - expect(handleChallengeNameSpy).toBeCalledTimes(1); + expect(handleChallengeNameSpy).toHaveBeenCalledTimes(1); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); handleUserSRPAuthflowSpy.mockClear(); }); @@ -258,7 +258,7 @@ describe('confirmSignIn API happy path cases', () => { options: authAPITestParams.configWithClientMetadata, }); const options = authAPITestParams.configWithClientMetadata; - expect(handleChallengeNameSpy).toBeCalledWith( + expect(handleChallengeNameSpy).toHaveBeenCalledWith( mockedUserSub, activeChallengeName, activeSignInSession, diff --git a/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts b/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts index 386ab9eccf9..256c5d23e5e 100644 --- a/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmSignUp.test.ts @@ -1,46 +1,44 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Amplify } from '@aws-amplify/core'; import { confirmSignUp } from '../../../src/providers/cognito'; -import * as confirmSignUpClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { confirmSignUp as providerConfirmSignUp } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { AuthError } from '../../../src/errors/AuthError'; import { ConfirmSignUpException } from '../../../src/providers/cognito/types/errors'; -import { Amplify } from '@aws-amplify/core'; import { ConfirmSignUpCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -const authConfig = { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, -}; +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -describe('confirmSignUp API Happy Path Cases:', () => { - Amplify.configure({ - Auth: authConfig, - }); - let confirmSignUpClientSpy; +describe('confirmSignUp', () => { const { user1 } = authAPITestParams; const confirmationCode = '123456'; + // assert mocks + const mockConfirmSignUp = providerConfirmSignUp as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + }); + beforeEach(() => { - confirmSignUpClientSpy = jest - .spyOn(confirmSignUpClient, 'confirmSignUp') - .mockImplementationOnce(async (): Promise => { - return {} as ConfirmSignUpCommandOutput; - }); + mockConfirmSignUp.mockResolvedValue({} as ConfirmSignUpCommandOutput); }); + afterEach(() => { - confirmSignUpClientSpy.mockClear(); - }); - afterAll(() => { - jest.restoreAllMocks(); + mockConfirmSignUp.mockReset(); }); - test('confirmSignUp API should call the UserPoolClient and should return a SignUpResult', async () => { + + it('should call confirmSignUp and return a SignUpResult', async () => { const result = await confirmSignUp({ username: user1.username, confirmationCode, @@ -51,7 +49,7 @@ describe('confirmSignUp API Happy Path Cases:', () => { signUpStep: 'DONE', }, }); - expect(confirmSignUpClientSpy).toHaveBeenCalledWith( + expect(mockConfirmSignUp).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), { ClientMetadata: undefined, @@ -61,9 +59,10 @@ describe('confirmSignUp API Happy Path Cases:', () => { ClientId: '111111-aaaaa-42d8-891d-ee81a1549398', } ); - expect(confirmSignUpClientSpy).toBeCalledTimes(1); + expect(mockConfirmSignUp).toHaveBeenCalledTimes(1); }); - test('confirmSignUp API input should contain force alias creation', async () => { + + it('should contain force alias creation', async () => { await confirmSignUp({ username: user1.username, confirmationCode, @@ -71,7 +70,7 @@ describe('confirmSignUp API Happy Path Cases:', () => { forceAliasCreation: true, }, }); - expect(confirmSignUpClientSpy).toHaveBeenCalledWith( + expect(mockConfirmSignUp).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ ClientMetadata: undefined, @@ -82,7 +81,7 @@ describe('confirmSignUp API Happy Path Cases:', () => { ); }); - test('confirmSignUp API input should contain clientMetadata from request', async () => { + it('should contain clientMetadata from request', async () => { const clientMetadata = { data: 'abcd' }; await confirmSignUp({ username: user1.username, @@ -91,7 +90,7 @@ describe('confirmSignUp API Happy Path Cases:', () => { clientMetadata, }, }); - expect(confirmSignUpClientSpy).toHaveBeenCalledWith( + expect(mockConfirmSignUp).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ ClientMetadata: clientMetadata, @@ -102,19 +101,12 @@ describe('confirmSignUp API Happy Path Cases:', () => { }) ); }); -}); -describe('confirmSignUp API Error Path Cases:', () => { - Amplify.configure({ - Auth: authConfig, - }); - const { user1 } = authAPITestParams; - const confirmationCode = '123456'; - test('confirmSignUp API should throw a validation AuthError when username is empty', async () => { + it('should throw an error when username is empty', async () => { expect.assertions(2); try { await confirmSignUp({ username: '', confirmationCode }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AuthValidationErrorCode.EmptyConfirmSignUpUsername @@ -122,62 +114,35 @@ describe('confirmSignUp API Error Path Cases:', () => { } }); - test('confirmSignUp API should throw a validation AuthError when confirmation code is empty', async () => { + it('should throw an error when confirmation code is empty', async () => { expect.assertions(2); try { await confirmSignUp({ username: user1.username, confirmationCode: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptyConfirmSignUpCode); } }); - test('confirmSignUp API should expect a service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(ConfirmSignUpException.InvalidParameterException) - ) - ); + mockConfirmSignUp.mockImplementation(() => { + throw getMockError(ConfirmSignUpException.InvalidParameterException); + }); try { await confirmSignUp({ username: user1.username, confirmationCode }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(ConfirmSignUpException.InvalidParameterException); } }); -}); - -describe('Cognito ASF', () => { - Amplify.configure({ - Auth: authConfig, - }); - let confirmSignUpClientSpy; - const { user1 } = authAPITestParams; - const confirmationCode = '123456'; - beforeEach(() => { - confirmSignUpClientSpy = jest - .spyOn(confirmSignUpClient, 'confirmSignUp') - .mockImplementationOnce(async (): Promise => { - return {} as ConfirmSignUpCommandOutput; - }); - // load Cognito ASF polyfill + it('should send UserContextData', async () => { window['AmazonCognitoAdvancedSecurityData'] = { getData() { return 'abcd'; }, }; - }); - - afterEach(() => { - confirmSignUpClientSpy.mockClear(); - window['AmazonCognitoAdvancedSecurityData'] = undefined; - }); - afterAll(() => { - jest.restoreAllMocks(); - }); - test('confirmSignUp should send UserContextData', async () => { const result = await confirmSignUp({ username: user1.username, confirmationCode, @@ -188,7 +153,7 @@ describe('Cognito ASF', () => { signUpStep: 'DONE', }, }); - expect(confirmSignUpClientSpy).toHaveBeenCalledWith( + expect(mockConfirmSignUp).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), { ClientMetadata: undefined, @@ -199,6 +164,7 @@ describe('Cognito ASF', () => { UserContextData: { EncodedData: 'abcd' }, } ); - expect(confirmSignUpClientSpy).toBeCalledTimes(1); + expect(mockConfirmSignUp).toHaveBeenCalledTimes(1); + window['AmazonCognitoAdvancedSecurityData'] = undefined; }); }); diff --git a/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts b/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts index f89de538486..1e2e9d1bdb9 100644 --- a/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts +++ b/packages/auth/__tests__/providers/cognito/confirmUserAttribute.test.ts @@ -1,128 +1,90 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Amplify } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { fetchAuthSession } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { confirmUserAttribute } from '../../../src/providers/cognito'; import { VerifyUserAttributeException } from '../../../src/providers/cognito/types/errors'; -import * as userPoolClients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -import { VerifyUserAttributeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; +import { verifyUserAttribute } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +describe('confirmUserAttribute', () => { + const confirmationCode = '123456'; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockVerifyUserAttribute = verifyUserAttribute as jest.Mock; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; - -describe('confirm user attribute API happy path cases', () => { - let confirmUserAttributeSpy; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - - confirmUserAttributeSpy = jest - .spyOn(userPoolClients, 'verifyUserAttribute') - .mockImplementationOnce( - async (): Promise => { - return { - $metadata: {}, - }; - } - ); + mockVerifyUserAttribute.mockResolvedValue({ $metadata: {} }); }); afterEach(() => { + mockVerifyUserAttribute.mockReset(); mockFetchAuthSession.mockClear(); - confirmUserAttributeSpy.mockClear(); }); - test('confirmUserAttribute API should call the service', async () => { - const confirmationCode = '123456'; + it('should call the service', async () => { await confirmUserAttribute({ userAttributeKey: 'email', confirmationCode, }); - expect(confirmUserAttributeSpy).toHaveBeenCalledWith( + expect(mockVerifyUserAttribute).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, AttributeName: 'email', Code: confirmationCode, }) ); }); -}); -describe('confirmUserAttribute API error path cases:', () => { - test('confirmUserAttribute API should raise a validation error when confirmationCode is not defined', async () => { + it('should throw an error when confirmationCode is not defined', async () => { try { - const confirmationCode = ''; await confirmUserAttribute({ userAttributeKey: 'email', - confirmationCode, + confirmationCode: '', }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AuthValidationErrorCode.EmptyConfirmUserAttributeCode ); } }); - test('confirmUserAttribute API should raise service error', async () => { + + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - VerifyUserAttributeException.InvalidParameterException - ) - ) - ); + mockVerifyUserAttribute.mockImplementation(() => { + throw getMockError( + VerifyUserAttributeException.InvalidParameterException + ); + }); try { - const confirmationCode = '123456'; await confirmUserAttribute({ userAttributeKey: 'email', confirmationCode, }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( VerifyUserAttributeException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/credentialsProvider.test.ts b/packages/auth/__tests__/providers/cognito/credentialsProvider.test.ts index b809b5e919c..8aa73f0411f 100644 --- a/packages/auth/__tests__/providers/cognito/credentialsProvider.test.ts +++ b/packages/auth/__tests__/providers/cognito/credentialsProvider.test.ts @@ -92,8 +92,8 @@ describe('Guest Credentials', () => { authAPITestParams.CredentialsForIdentityIdResult.Credentials.AccessKeyId ); - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); - expect(credentialsForIdentityIdSpy).toBeCalledWith( + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith( { region: 'us-east-1' }, { IdentityId: 'identity-id-test' } ); @@ -106,7 +106,7 @@ describe('Guest Credentials', () => { authenticated: false, authConfig: validAuthConfig.Auth!, }); - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); const res = await cognitoCredentialsProvider.getCredentialsAndIdentityId({ authenticated: false, authConfig: validAuthConfig.Auth!, @@ -115,7 +115,7 @@ describe('Guest Credentials', () => { authAPITestParams.CredentialsForIdentityIdResult.Credentials.AccessKeyId ); // expecting to be called only once becasue in-memory creds should be returned - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); }); }); describe('Error Path Cases:', () => { @@ -184,7 +184,7 @@ describe('Primary Credentials', () => { authAPITestParams.CredentialsForIdentityIdResult.Credentials.AccessKeyId ); - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); }); test('in-memory primary creds are returned if not expired and not past TTL', async () => { await cognitoCredentialsProvider.getCredentialsAndIdentityId({ @@ -192,13 +192,13 @@ describe('Primary Credentials', () => { authConfig: validAuthConfig.Auth!, tokens: authAPITestParams.ValidAuthTokens, }); - expect(credentialsForIdentityIdSpy).toBeCalledWith( + expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith( { region: authAPITestParams.CredentialsClientRequest.region, }, authAPITestParams.CredentialsClientRequest.withValidAuthToken ); - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); const res = await cognitoCredentialsProvider.getCredentialsAndIdentityId({ authenticated: true, @@ -209,7 +209,7 @@ describe('Primary Credentials', () => { authAPITestParams.CredentialsForIdentityIdResult.Credentials.AccessKeyId ); // expecting to be called only once becasue in-memory creds should be returned - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); }); test('Should get new credentials when tokens have changed', async () => { await cognitoCredentialsProvider.getCredentialsAndIdentityId({ @@ -217,26 +217,26 @@ describe('Primary Credentials', () => { authConfig: validAuthConfig.Auth!, tokens: authAPITestParams.ValidAuthTokens, }); - expect(credentialsForIdentityIdSpy).toBeCalledWith( + expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith( { region: authAPITestParams.CredentialsClientRequest.region, }, authAPITestParams.CredentialsClientRequest.withValidAuthToken ); - expect(credentialsForIdentityIdSpy).toBeCalledTimes(1); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(1); const res = await cognitoCredentialsProvider.getCredentialsAndIdentityId({ authenticated: true, authConfig: validAuthConfig.Auth!, tokens: authAPITestParams.NewValidAuthTokens, }); - expect(credentialsForIdentityIdSpy).toBeCalledWith( + expect(credentialsForIdentityIdSpy).toHaveBeenCalledWith( { region: authAPITestParams.CredentialsClientRequest.region, }, authAPITestParams.CredentialsClientRequest.withNewValidAuthToken ); - expect(credentialsForIdentityIdSpy).toBeCalledTimes(2); + expect(credentialsForIdentityIdSpy).toHaveBeenCalledTimes(2); }); }); describe('Error Path Cases:', () => { diff --git a/packages/auth/__tests__/providers/cognito/deleteUser.test.ts b/packages/auth/__tests__/providers/cognito/deleteUser.test.ts index 889413d2b94..156aa5cd00a 100644 --- a/packages/auth/__tests__/providers/cognito/deleteUser.test.ts +++ b/packages/auth/__tests__/providers/cognito/deleteUser.test.ts @@ -1,117 +1,79 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { deleteUser } from '../../../src/providers/cognito'; -import * as cognitoApis from '../../../src/providers/cognito'; -import * as TokenProvider from '../../../src/providers/cognito/tokenProvider'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; +import { deleteUser as providerDeleteUser } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; import { DeleteUserException } from '../../../src/providers/cognito/types/errors'; import { signOut } from '../../../src/providers/cognito/apis/signOut'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); -jest.mock('../../../src/providers/cognito/apis/signOut'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; + jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock('../../../src/providers/cognito/apis/signOut'); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); +jest.mock('../../../src/providers/cognito/tokenProvider'); -const mockedAccessToken = - 'test_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +describe('deleteUser', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockDeleteUser = providerDeleteUser as jest.Mock; + const mockSignOut = signOut as jest.Mock; + const mockClearDeviceMetadata = + tokenOrchestrator.clearDeviceMetadata as jest.Mock; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -const mockSignOut = signOut as jest.Mock; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); -describe('deleteUser API happy path cases', () => { - let deleteUserClientSpy; - let tokenOrchestratorSpy; beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - deleteUserClientSpy = jest - .spyOn(clients, 'deleteUser') - .mockImplementationOnce(async () => { - return { - $metadata: {}, - }; - }); - tokenOrchestratorSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'clearDeviceMetadata') - .mockImplementation(async () => {}); + mockDeleteUser.mockResolvedValue({ $metadata: {} }); }); afterEach(() => { + mockDeleteUser.mockReset(); + mockClearDeviceMetadata.mockClear(); mockFetchAuthSession.mockClear(); - deleteUserClientSpy.mockClear(); }); - it('Should delete user, signout and clear device tokens', async () => { - mockSignOut.mockImplementationOnce(async () => { - return new Promise(resolve => resolve(void 0)); - }); - + it('should delete user, sign out and clear device tokens', async () => { await deleteUser(); - // deleteUserClient - expect(deleteUserClientSpy).toHaveBeenCalledWith( + expect(mockDeleteUser).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, }) ); - expect(deleteUserClientSpy).toBeCalledTimes(1); - expect(tokenOrchestratorSpy).toHaveBeenCalledTimes(1); + expect(mockDeleteUser).toHaveBeenCalledTimes(1); + expect(mockClearDeviceMetadata).toHaveBeenCalledTimes(1); expect(mockSignOut).toHaveBeenCalledTimes(1); // make sure we clearDeviceToken -> signout, in that order - expect(tokenOrchestratorSpy.mock.invocationCallOrder[0]).toBeLessThan( + expect(mockClearDeviceMetadata.mock.invocationCallOrder[0]).toBeLessThan( mockSignOut.mock.invocationCallOrder[0] ); }); -}); -describe('deleteUser API error path cases', () => { - test('Should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(DeleteUserException.InvalidParameterException) - ) - ); + mockDeleteUser.mockImplementation(() => { + throw getMockError(DeleteUserException.InvalidParameterException); + }); try { await deleteUser(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(DeleteUserException.InvalidParameterException); } diff --git a/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts b/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts index 2365b2caa7b..89409f318d5 100644 --- a/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts +++ b/packages/auth/__tests__/providers/cognito/deleteUserAttributes.test.ts @@ -1,109 +1,71 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { deleteUserAttributes } from '../../../src/providers/cognito'; import { DeleteUserAttributesException } from '../../../src/providers/cognito/types/errors'; -import * as deleteUserAttributesClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { deleteUserAttributes as providerDeleteUserAttributes } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -const mockedAccessToken = - 'test_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +describe('deleteUserAttributes', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockDeleteUserAttributes = providerDeleteUserAttributes as jest.Mock; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); -describe('deleteUserAttributes API happy path cases', () => { - let deleteUserAttributesClientSpy; beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - deleteUserAttributesClientSpy = jest - .spyOn(deleteUserAttributesClient, 'deleteUserAttributes') - .mockImplementation(async () => { - return { - $metadata: {}, - }; - }); + mockDeleteUserAttributes.mockResolvedValue({ $metadata: {} }); }); afterEach(() => { + mockDeleteUserAttributes.mockReset(); mockFetchAuthSession.mockClear(); - deleteUserAttributesClientSpy.mockClear(); - }); - - afterAll(() => { - mockFetchAuthSession.mockRestore(); - deleteUserAttributesClientSpy.mockRestore(); }); - it('Should delete user attributes', async () => { + it('should delete user attributes', async () => { expect.assertions(2); await deleteUserAttributes({ userAttributeKeys: ['given_name', 'address'], }); - expect(deleteUserAttributesClientSpy).toHaveBeenCalledWith( + expect(mockDeleteUserAttributes).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, UserAttributeNames: ['given_name', 'address'], }) ); - expect(deleteUserAttributesClientSpy).toBeCalledTimes(1); + expect(mockDeleteUserAttributes).toHaveBeenCalledTimes(1); }); -}); -describe('deleteUserAttributes API error path cases', () => { - it('should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - DeleteUserAttributesException.InvalidParameterException - ) - ) - ); + mockDeleteUserAttributes.mockImplementation(() => { + throw getMockError( + DeleteUserAttributesException.InvalidParameterException + ); + }); try { await deleteUserAttributes({ userAttributeKeys: ['address', 'given_name'], }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( DeleteUserAttributesException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/fetchAuthSession.test.ts b/packages/auth/__tests__/providers/cognito/fetchAuthSession.test.ts index fd32724b43f..410cb41e257 100644 --- a/packages/auth/__tests__/providers/cognito/fetchAuthSession.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchAuthSession.test.ts @@ -61,7 +61,7 @@ describe('fetchAuthSession behavior for IdentityPools only', () => { userSub: undefined, }); - expect(credentialsProviderSpy).toBeCalledWith({ + expect(credentialsProviderSpy).toHaveBeenCalledWith({ authConfig: { Cognito: { allowGuestAccess: true, @@ -74,7 +74,7 @@ describe('fetchAuthSession behavior for IdentityPools only', () => { }); }); -describe.only('fetchAuthSession behavior for UserPools only', () => { +describe('fetchAuthSession behavior for UserPools only', () => { let tokenProviderSpy; beforeEach(() => { tokenProviderSpy = jest diff --git a/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts b/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts index 1dc046fe2ed..c7fd8e89ef7 100644 --- a/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchDevices.test.ts @@ -1,115 +1,86 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { fetchDevices } from '../../../src/providers/cognito'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; +import { listDevices } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { ListDevicesException } from '../../../src/providers/cognito/types/errors'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -const mockedAccessToken = - 'test_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const dateEpoch = 1.696296885807e9; -const date = new Date(dateEpoch * 1000); -const clientResponseDevice = { - DeviceAttributes: [{ Name: 'attributeName', Value: 'attributeValue' }], - DeviceCreateDate: dateEpoch, - DeviceKey: 'DeviceKey', - DeviceLastAuthenticatedDate: dateEpoch, - DeviceLastModifiedDate: dateEpoch, -}; -const apiOutputDevice = { - id: 'DeviceKey', - name: undefined, - attributes: { - attributeName: 'attributeValue', - }, - createDate: date, - lastModifiedDate: date, - lastAuthenticatedDate: date, -}; +describe('fetchDevices', () => { + const dateEpoch = 1.696296885807e9; + const date = new Date(dateEpoch * 1000); + const clientResponseDevice = { + DeviceAttributes: [{ Name: 'attributeName', Value: 'attributeValue' }], + DeviceCreateDate: dateEpoch, + DeviceKey: 'DeviceKey', + DeviceLastAuthenticatedDate: dateEpoch, + DeviceLastModifiedDate: dateEpoch, + }; + const apiOutputDevice = { + id: 'DeviceKey', + name: undefined, + attributes: { + attributeName: 'attributeValue', + }, + createDate: date, + lastModifiedDate: date, + lastAuthenticatedDate: date, + }; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockListDevices = listDevices as jest.Mock; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); -describe('fetchDevices API happy path cases', () => { beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); + mockListDevices.mockResolvedValue({ + Devices: [clientResponseDevice], + $metadata: {}, + }); }); + afterEach(() => { + mockListDevices.mockReset(); mockFetchAuthSession.mockClear(); }); it('should fetch devices and parse client response correctly', async () => { - const fetchDevicesClientSpy = jest - .spyOn(clients, 'listDevices') - .mockImplementationOnce(async () => { - return { - Devices: [clientResponseDevice], - $metadata: {}, - }; - }); - expect(await fetchDevices()).toEqual([apiOutputDevice]); - expect(fetchDevicesClientSpy).toHaveBeenCalledWith( + expect(mockListDevices).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, Limit: 60, }) ); - expect(fetchDevicesClientSpy).toBeCalledTimes(1); + expect(mockListDevices).toHaveBeenCalledTimes(1); }); -}); -describe('fetchDevices API error path cases', () => { - it('should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(ListDevicesException.InvalidParameterException) - ) - ); + mockListDevices.mockImplementation(() => { + throw getMockError(ListDevicesException.InvalidParameterException); + }); try { await fetchDevices(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(ListDevicesException.InvalidParameterException); } diff --git a/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts b/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts index 84242f6338c..0223513bd41 100644 --- a/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchMFAPreference.test.ts @@ -1,105 +1,73 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; -import * as getUserClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; +import { getUser } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthError } from '../../../src/errors/AuthError'; import { fetchMFAPreference } from '../../../src/providers/cognito/apis/fetchMFAPreference'; import { GetUserException } from '../../../src/providers/cognito/types/errors'; -import { GetUserCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; +describe('fetchMFAPreference', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockGetUser = getUser as jest.Mock; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; - -describe('fetchMFAPreference Happy Path Cases:', () => { - let getUserClientSpy; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - getUserClientSpy = jest - .spyOn(getUserClient, 'getUser') - .mockImplementationOnce(async (): Promise => { - return { - UserAttributes: [], - Username: 'XXXXXXXX', - PreferredMfaSetting: 'SMS_MFA', - UserMFASettingList: ['SMS_MFA', 'SOFTWARE_TOKEN_MFA'], - $metadata: {}, - }; - }); + mockGetUser.mockResolvedValue({ + UserAttributes: [], + Username: 'XXXXXXXX', + PreferredMfaSetting: 'SMS_MFA', + UserMFASettingList: ['SMS_MFA', 'SOFTWARE_TOKEN_MFA'], + $metadata: {}, + }); }); + afterEach(() => { - getUserClientSpy.mockClear(); + mockGetUser.mockReset(); mockFetchAuthSession.mockClear(); }); - test('fetchMFAPreference should return the preferred MFA setting', async () => { + it('should return the preferred MFA setting', async () => { const resp = await fetchMFAPreference(); expect(resp).toEqual({ preferred: 'SMS', enabled: ['SMS', 'TOTP'] }); - expect(getUserClientSpy).toHaveBeenCalledTimes(1); - expect(getUserClientSpy).toHaveBeenCalledWith( + expect(mockGetUser).toHaveBeenCalledTimes(1); + expect(mockGetUser).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), }, { - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, } ); }); -}); -describe('fetchMFAPreference Error Path Cases:', () => { - test('fetchMFAPreference should expect a service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(GetUserException.InvalidParameterException) - ) - ); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); + mockGetUser.mockImplementation(() => { + throw getMockError(GetUserException.InvalidParameterException); + }); try { await fetchMFAPreference(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(GetUserException.InvalidParameterException); } diff --git a/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts b/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts index 0787bc31106..a1370c7f190 100644 --- a/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts +++ b/packages/auth/__tests__/providers/cognito/fetchUserAttributes.test.ts @@ -1,100 +1,88 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { Amplify } from 'aws-amplify'; +import { Amplify } from '@aws-amplify/core'; import { decodeJWT, fetchAuthSession } from '@aws-amplify/core/internals/utils'; -import * as getUserClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getUser } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthError } from '../../../src/errors/AuthError'; import { GetUserException } from '../../../src/providers/cognito/types/errors'; -import { GetUserCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; import { fetchUserAttributes } from '../../../src/providers/cognito/apis/fetchUserAttributes'; +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); jest.mock('@aws-amplify/core/internals/utils', () => ({ ...jest.requireActual('@aws-amplify/core/internals/utils'), fetchAuthSession: jest.fn(), })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, -}); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; +describe('fetchUserAttributes', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockGetUser = getUser as jest.Mock; -describe('fetchUserAttributes Happy Path Cases:', () => { - let getUserClientSpy; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); beforeEach(() => { - mockFetchAuthSession.mockResolvedValue({ - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, + mockGetUser.mockResolvedValue({ + UserAttributes: [ + { Name: 'email', Value: 'XXXXXXXXXXXXX' }, + { Name: 'phone_number', Value: '000000000000000' }, + ], + Username: 'XXXXXXXX', + PreferredMfaSetting: 'SMS_MFA', + UserMFASettingList: ['SMS_MFA', 'SOFTWARE_TOKEN_MFA'], + $metadata: {}, }); - getUserClientSpy = jest - .spyOn(getUserClient, 'getUser') - .mockImplementationOnce(async (): Promise => { - return { - UserAttributes: [ - { Name: 'email', Value: 'XXXXXXXXXXXXX' }, - { Name: 'phone_number', Value: '000000000000000' }, - ], - Username: 'XXXXXXXX', - PreferredMfaSetting: 'SMS_MFA', - UserMFASettingList: ['SMS_MFA', 'SOFTWARE_TOKEN_MFA'], - $metadata: {}, - }; - }); }); + afterEach(() => { - getUserClientSpy.mockClear(); + mockGetUser.mockReset(); mockFetchAuthSession.mockClear(); }); - test('fetchUserAttributes should return the current user attributes into a map format', async () => { - const resp = await fetchUserAttributes(); - expect(resp).toEqual({ + it('should return the current user attributes into a map format', async () => { + expect(await fetchUserAttributes()).toEqual({ email: 'XXXXXXXXXXXXX', phone_number: '000000000000000', }); - expect(getUserClientSpy).toHaveBeenCalledTimes(1); - expect(getUserClientSpy).toHaveBeenCalledWith( + expect(mockGetUser).toHaveBeenCalledTimes(1); + expect(mockGetUser).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), }, { - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, } ); }); -}); -describe('fetchUserAttributes Error Path Cases:', () => { - test('fetchUserAttributes should expect a service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(GetUserException.InvalidParameterException) - ) - ); + mockGetUser.mockImplementation(() => { + throw getMockError(GetUserException.InvalidParameterException); + }); mockFetchAuthSession.mockResolvedValueOnce({ tokens: { - accessToken: decodeJWT(mockedAccessToken), + accessToken: decodeJWT(mockAccessToken), }, }); try { await fetchUserAttributes(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(GetUserException.InvalidParameterException); } diff --git a/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts b/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts index fb9c2cf93c1..78244f1c577 100644 --- a/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts +++ b/packages/auth/__tests__/providers/cognito/forgetDevice.test.ts @@ -1,202 +1,150 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { DEVICE_METADATA_NOT_FOUND_EXCEPTION } from '../../../src/errors/constants'; import { forgetDevice } from '../../../src/providers/cognito'; import { ForgetDeviceException } from '../../../src/providers/cognito/types/errors'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import * as TokenProvider from '../../../src/providers/cognito/tokenProvider'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { forgetDevice as providerForgetDevice } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); +jest.mock('../../../src/providers/cognito/tokenProvider'); -const mockedAccessToken = - 'test_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockDeviceMetadata = { - deviceKey: 'deviceKey', - deviceGroupKey: 'deviceGroupKey', - randomPassword: 'randomPassword', -}; +describe('fetchMFAPreference', () => { + const mockDeviceMetadata = { + deviceKey: 'deviceKey', + deviceGroupKey: 'deviceGroupKey', + randomPassword: 'randomPassword', + }; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockForgetDevice = providerForgetDevice as jest.Mock; + const mockClearDeviceMetadata = + tokenOrchestrator.clearDeviceMetadata as jest.Mock; + const mockGetDeviceMetadata = + tokenOrchestrator.getDeviceMetadata as jest.Mock; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); -describe('forgetDevice API happy path cases', () => { - let forgetDeviceStatusClientSpy; - let getDeviceMetadataSpy; - let clearDeviceMetadataSpy; beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - forgetDeviceStatusClientSpy = jest - .spyOn(clients, 'forgetDevice') - .mockImplementationOnce(async () => { - return { - $metadata: {}, - }; - }); - getDeviceMetadataSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'getDeviceMetadata') - .mockImplementationOnce(async () => mockDeviceMetadata); - clearDeviceMetadataSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'clearDeviceMetadata') - .mockImplementationOnce(async () => {}); + mockForgetDevice.mockResolvedValue({ $metadata: {} }); + mockGetDeviceMetadata.mockResolvedValue(mockDeviceMetadata); }); afterEach(() => { + mockForgetDevice.mockReset(); + mockGetDeviceMetadata.mockReset(); mockFetchAuthSession.mockClear(); - forgetDeviceStatusClientSpy.mockClear(); - getDeviceMetadataSpy.mockClear(); - clearDeviceMetadataSpy.mockClear(); - }); - - afterAll(() => { - jest.restoreAllMocks(); + mockClearDeviceMetadata.mockClear(); }); it(`should forget 'external device' 'with' inputParams when tokenStore deviceMetadata 'present'`, async () => { expect.assertions(3); await forgetDevice({ device: { id: 'externalDeviceKey' } }); - expect(forgetDeviceStatusClientSpy).toHaveBeenCalledWith( + expect(mockForgetDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, DeviceKey: 'externalDeviceKey', }) ); - expect(forgetDeviceStatusClientSpy).toBeCalledTimes(1); - expect(clearDeviceMetadataSpy).not.toBeCalled(); + expect(mockForgetDevice).toHaveBeenCalledTimes(1); + expect(mockClearDeviceMetadata).not.toHaveBeenCalled(); }); it(`should forget 'current device' 'with' inputParams when tokenStore deviceMetadata 'present'`, async () => { expect.assertions(3); await forgetDevice({ device: { id: mockDeviceMetadata.deviceKey } }); - expect(forgetDeviceStatusClientSpy).toHaveBeenCalledWith( + expect(mockForgetDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, DeviceKey: mockDeviceMetadata.deviceKey, }) ); - expect(forgetDeviceStatusClientSpy).toBeCalledTimes(1); - expect(clearDeviceMetadataSpy).toBeCalled(); + expect(mockForgetDevice).toHaveBeenCalledTimes(1); + expect(mockClearDeviceMetadata).toHaveBeenCalled(); }); it(`should forget 'current device' 'without' inputParams when tokenStore deviceMetadata 'present'`, async () => { expect.assertions(3); await forgetDevice(); - expect(forgetDeviceStatusClientSpy).toHaveBeenCalledWith( + expect(mockForgetDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, DeviceKey: mockDeviceMetadata.deviceKey, }) ); - expect(forgetDeviceStatusClientSpy).toBeCalledTimes(1); - expect(clearDeviceMetadataSpy).toBeCalled(); + expect(mockForgetDevice).toHaveBeenCalledTimes(1); + expect(mockClearDeviceMetadata).toHaveBeenCalled(); }); it(`should forget 'external device' 'with' inputParams when tokenStore deviceMetadata 'not present'`, async () => { - getDeviceMetadataSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'getDeviceMetadata') - .mockImplementationOnce(async () => null); + mockGetDeviceMetadata.mockResolvedValue(null); await forgetDevice({ device: { id: 'externalDeviceKey' } }); - expect(forgetDeviceStatusClientSpy).toHaveBeenCalledWith( + expect(mockForgetDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, DeviceKey: 'externalDeviceKey', }) ); - expect(forgetDeviceStatusClientSpy).toBeCalledTimes(1); - expect(clearDeviceMetadataSpy).not.toBeCalled(); + expect(mockForgetDevice).toHaveBeenCalledTimes(1); + expect(mockClearDeviceMetadata).not.toHaveBeenCalled(); }); it(`should forget 'current device' 'with' inputParams when tokenStore deviceMetadata 'not present'`, async () => { - getDeviceMetadataSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'getDeviceMetadata') - .mockImplementationOnce(async () => null); + mockGetDeviceMetadata.mockResolvedValue(null); expect.assertions(3); await forgetDevice({ device: { id: mockDeviceMetadata.deviceKey } }); - expect(forgetDeviceStatusClientSpy).toHaveBeenCalledWith( + expect(mockForgetDevice).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, DeviceKey: mockDeviceMetadata.deviceKey, }) ); - expect(forgetDeviceStatusClientSpy).toBeCalledTimes(1); - expect(clearDeviceMetadataSpy).not.toBeCalled(); + expect(mockForgetDevice).toHaveBeenCalledTimes(1); + expect(mockClearDeviceMetadata).not.toHaveBeenCalled(); }); -}); -describe('forgetDevice API error path cases', () => { - let getDeviceMetadataSpy; - beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - getDeviceMetadataSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'getDeviceMetadata') - .mockImplementationOnce(async () => null); - }); - afterEach(() => { - mockFetchAuthSession.mockClear(); - getDeviceMetadataSpy.mockClear(); - }); - - it(`should raise deviceMatadata not found exception when forget 'current device' 'without' inputParams when tokenStore deviceMetadata 'not present'`, async () => { + it(`should throw and error when forget 'current device' 'without' inputParams when tokenStore deviceMetadata 'not present'`, async () => { + mockGetDeviceMetadata.mockResolvedValue(null); expect.assertions(2); try { await forgetDevice(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(DEVICE_METADATA_NOT_FOUND_EXCEPTION); } }); - it('should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { + mockGetDeviceMetadata.mockResolvedValue(null); expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(ForgetDeviceException.InvalidParameterException) - ) - ); + mockForgetDevice.mockImplementation(() => { + throw getMockError(ForgetDeviceException.InvalidParameterException); + }); try { await forgetDevice({ device: { id: mockDeviceMetadata.deviceKey } }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(ForgetDeviceException.InvalidParameterException); } diff --git a/packages/auth/__tests__/providers/cognito/getCurrentUser.test.ts b/packages/auth/__tests__/providers/cognito/getCurrentUser.test.ts index fa54690b375..3df362f3baa 100644 --- a/packages/auth/__tests__/providers/cognito/getCurrentUser.test.ts +++ b/packages/auth/__tests__/providers/cognito/getCurrentUser.test.ts @@ -1,33 +1,32 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { Amplify } from 'aws-amplify'; +import { Amplify } from '@aws-amplify/core'; import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { getCurrentUser } from '../../../src/providers/cognito'; -import { Amplify as AmplifyV6 } from '@aws-amplify/core'; import { USER_UNAUTHENTICATED_EXCEPTION } from '../../../src/errors/constants'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, -}); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockGetTokensFunction = jest.spyOn(AmplifyV6.Auth, 'getTokens'); -const mockedSub = 'mockedSub'; -const mockedUsername = 'XXXXXXXXXXXXXX'; +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { Auth: { getTokens: jest.fn() }, getConfig: jest.fn(() => ({})) }, +})); + +describe('getCurrentUser', () => { + const mockedSub = 'mockedSub'; + const mockedUsername = 'XXXXXXXXXXXXXX'; + // assert mocks + const mockGetTokensFunction = Amplify.Auth.getTokens as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + }); -describe('getUser API happy path cases', () => { beforeEach(() => { mockGetTokensFunction.mockResolvedValue({ - accessToken: decodeJWT(mockedAccessToken), + accessToken: decodeJWT(mockAccessToken), idToken: { payload: { sub: mockedSub, @@ -42,10 +41,10 @@ describe('getUser API happy path cases', () => { }); afterEach(() => { - mockGetTokensFunction.mockClear(); + mockGetTokensFunction.mockReset(); }); - test('get current user', async () => { + it('should get current user', async () => { const result = await getCurrentUser(); expect(result).toEqual({ username: mockedUsername, @@ -56,20 +55,12 @@ describe('getUser API happy path cases', () => { }, }); }); -}); - -describe('getUser API error path cases:', () => { - beforeEach(() => { - mockGetTokensFunction.mockResolvedValue(null); - }); - afterEach(() => { - mockGetTokensFunction.mockClear(); - }); - test('getUser API should raise a validation error when tokens are not found', async () => { + it('should throw an error when tokens are not found', async () => { + mockGetTokensFunction.mockResolvedValue(undefined); try { - const result = await getCurrentUser(); - } catch (error) { + await getCurrentUser(); + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(USER_UNAUTHENTICATED_EXCEPTION); } diff --git a/packages/auth/__tests__/providers/cognito/identityIdProvider.test.ts b/packages/auth/__tests__/providers/cognito/identityIdProvider.test.ts index 0b4b42427df..ebb37ca3a7a 100644 --- a/packages/auth/__tests__/providers/cognito/identityIdProvider.test.ts +++ b/packages/auth/__tests__/providers/cognito/identityIdProvider.test.ts @@ -57,6 +57,11 @@ describe('Cognito IdentityId Provider Happy Path Cases:', () => { } }); }); + + afterEach(() => { + mockGetId.mockClear(); + }); + test('Should return stored guest identityId', async () => { mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce( async () => { @@ -69,7 +74,7 @@ describe('Cognito IdentityId Provider Happy Path Cases:', () => { identityIdStore: mockDefaultIdentityIdStoreInstance, }) ).toBe(authAPITestParams.GuestIdentityId.id); - expect(mockGetId).toBeCalledTimes(0); + expect(mockGetId).toHaveBeenCalledTimes(0); }); test('Should generate a guest identityId and return it', async () => { mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce( @@ -91,7 +96,7 @@ describe('Cognito IdentityId Provider Happy Path Cases:', () => { identityIdStore: mockDefaultIdentityIdStoreInstance, }) ).toBe(authAPITestParams.GuestIdentityId.id); - expect(mockGetId).toBeCalledTimes(1); + expect(mockGetId).toHaveBeenCalledTimes(1); }); test('Should return stored primary identityId', async () => { mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce( @@ -106,7 +111,7 @@ describe('Cognito IdentityId Provider Happy Path Cases:', () => { identityIdStore: mockDefaultIdentityIdStoreInstance, }) ).toBe(authAPITestParams.PrimaryIdentityId.id); - expect(mockGetId).toBeCalledTimes(0); + expect(mockGetId).toHaveBeenCalledTimes(0); }); test('Should generate a primary identityId and return it', async () => { mockDefaultIdentityIdStoreInstance.loadIdentityId.mockImplementationOnce( @@ -129,6 +134,6 @@ describe('Cognito IdentityId Provider Happy Path Cases:', () => { identityIdStore: mockDefaultIdentityIdStoreInstance, }) ).toBe(authAPITestParams.PrimaryIdentityId.id); - expect(mockGetId).toBeCalledTimes(1); + expect(mockGetId).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts b/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts index 3a9fa1ab049..21e44cc4b5d 100644 --- a/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts +++ b/packages/auth/__tests__/providers/cognito/identityIdStore.test.ts @@ -49,7 +49,7 @@ describe('DefaultIdentityIdStore', () => { }); it('Should store guest identityId in keyValueStorage', async () => { defaultIdStore.storeIdentityId(validGuestIdentityId); - expect(mockKeyValueStorage.setItem).toBeCalledWith( + expect(mockKeyValueStorage.setItem).toHaveBeenCalledWith( validAuthKey.identityId, validGuestIdentityId.id ); @@ -64,7 +64,7 @@ describe('DefaultIdentityIdStore', () => { }); it('Should store primary identityId in keyValueStorage', async () => { defaultIdStore.storeIdentityId(validPrimaryIdentityId); - expect(mockKeyValueStorage.removeItem).toBeCalledWith( + expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith( validAuthKey.identityId ); expect(defaultIdStore._primaryIdentityId).toEqual( @@ -78,7 +78,7 @@ describe('DefaultIdentityIdStore', () => { }); it('Should clear the cached identityId', async () => { defaultIdStore.clearIdentityId(); - expect(mockKeyValueStorage.removeItem).toBeCalledWith( + expect(mockKeyValueStorage.removeItem).toHaveBeenCalledWith( validAuthKey.identityId ); expect(defaultIdStore._primaryIdentityId).toBeUndefined(); @@ -88,7 +88,7 @@ describe('DefaultIdentityIdStore', () => { it('Should assert when identityPoolId is not present while setting the auth config', async () => { try { defaultIdStore.setAuthConfig(noIdentityPoolIdAuthConfig.Auth!); - } catch (e) { + } catch (e: any) { expect(e.name).toEqual('InvalidIdentityPoolIdException'); } }); diff --git a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts index 6ce812dc43a..78f087d4873 100644 --- a/packages/auth/__tests__/providers/cognito/refreshToken.test.ts +++ b/packages/auth/__tests__/providers/cognito/refreshToken.test.ts @@ -1,77 +1,51 @@ import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { mockJsonResponse, mockRequestId } from './testUtils/data'; import { refreshAuthTokens } from '../../../src/providers/cognito/utils/refreshAuthTokens'; import { CognitoAuthTokens } from '../../../src/providers/cognito/tokenProvider/types'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { initiateAuth } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { mockAccessToken, mockRequestId } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -describe('refresh token tests', () => { +describe('refreshToken', () => { const mockedUsername = 'mockedUsername'; const mockedRefreshToken = 'mockedRefreshToken'; - test('Default Cognito Token Refresh Handler', async () => { - const succeedResponse = { - status: 200, - headers: { - 'x-amzn-requestid': mockRequestId, + // assert mocks + const mockInitiateAuth = initiateAuth as jest.Mock; + + beforeEach(() => { + mockInitiateAuth.mockResolvedValue({ + AuthenticationResult: { + AccessToken: mockAccessToken, + ExpiresIn: 3600, + IdToken: mockAccessToken, + TokenType: 'Bearer', }, - body: { - AuthenticationResult: { - AccessToken: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', - ExpiresIn: 3600, - IdToken: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', - TokenType: 'Bearer', - }, - ChallengeParameters: {}, - $metadata: { - attempts: 1, - httpStatusCode: 200, - requestId: mockRequestId, - }, + ChallengeParameters: {}, + $metadata: { + attempts: 1, + httpStatusCode: 200, + requestId: mockRequestId, }, - }; - const expectedOutput: CognitoAuthTokens = { - accessToken: decodeJWT( - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0' - ), - idToken: decodeJWT( - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0' - ), + }); + }); - refreshToken: mockedRefreshToken, + afterEach(() => { + mockInitiateAuth.mockReset(); + }); - clockDrift: 0, + it('should refresh token', async () => { + const expectedOutput = { + accessToken: decodeJWT(mockAccessToken), + idToken: decodeJWT(mockAccessToken), + refreshToken: mockedRefreshToken, username: mockedUsername, - }; - const expectedRequest = { - url: new URL('https://cognito-idp.us-east-1.amazonaws.com/'), - method: 'POST', - headers: expect.objectContaining({ - 'cache-control': 'no-store', - 'content-type': 'application/x-amz-json-1.1', - 'x-amz-target': 'AWSCognitoIdentityProviderService.InitiateAuth', - 'x-amz-user-agent': expect.any(String), - }), - body: JSON.stringify({ - ClientId: 'aaaaaaaaaaaa', - AuthFlow: 'REFRESH_TOKEN_AUTH', - AuthParameters: { - REFRESH_TOKEN: mockedRefreshToken, - }, - }), - }; + } as CognitoAuthTokens; - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse(succeedResponse) - ); const response = await refreshAuthTokens({ tokens: { - accessToken: { - payload: {}, - }, + accessToken: { payload: {} }, clockDrift: 0, refreshToken: mockedRefreshToken, username: mockedUsername, @@ -85,58 +59,29 @@ describe('refresh token tests', () => { username: mockedUsername, }); - expect(response.accessToken.toString()).toEqual( - expectedOutput.accessToken.toString() + // stringify and re-parse for JWT equality + expect(JSON.parse(JSON.stringify(response))).toMatchObject( + JSON.parse(JSON.stringify(expectedOutput)) ); - - expect(response.refreshToken).toEqual(expectedOutput.refreshToken); - - expect(fetchTransferHandler).toBeCalledWith( - expectedRequest, - expect.anything() + expect(mockInitiateAuth).toHaveBeenCalledWith( + expect.objectContaining({ region: 'us-east-1' }), + expect.objectContaining({ + ClientId: 'aaaaaaaaaaaa', + AuthFlow: 'REFRESH_TOKEN_AUTH', + AuthParameters: { + REFRESH_TOKEN: mockedRefreshToken, + }, + }) ); }); -}); -describe('Cognito ASF', () => { - let initiateAuthSpy; - afterAll(() => { - jest.restoreAllMocks(); - }); - beforeEach(() => { - initiateAuthSpy = jest - .spyOn(clients, 'initiateAuth') - .mockImplementationOnce(async () => ({ - AuthenticationResult: { - AccessToken: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', - ExpiresIn: 3600, - IdToken: - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyLCJleHAiOjE3MTAyOTMxMzB9.YzDpgJsrB3z-ZU1XxMcXSQsMbgCzwH_e-_76rnfehh0', - TokenType: 'Bearer', - }, - ChallengeParameters: {}, - $metadata: { - attempts: 1, - httpStatusCode: 200, - requestId: mockRequestId, - }, - })); - // load Cognito ASF polyfill + it('should send UserContextData', async () => { window['AmazonCognitoAdvancedSecurityData'] = { getData() { return 'abcd'; }, }; - }); - - afterEach(() => { - initiateAuthSpy.mockClear(); - window['AmazonCognitoAdvancedSecurityData'] = undefined; - }); - - test('refreshTokens API should send UserContextData', async () => { - const response = await refreshAuthTokens({ + await refreshAuthTokens({ username: 'username', tokens: { accessToken: decodeJWT( @@ -156,10 +101,8 @@ describe('Cognito ASF', () => { }, }, }); - expect(initiateAuthSpy).toBeCalledWith( - expect.objectContaining({ - region: 'us-east-1', - }), + expect(mockInitiateAuth).toHaveBeenCalledWith( + expect.objectContaining({ region: 'us-east-1' }), expect.objectContaining({ AuthFlow: 'REFRESH_TOKEN_AUTH', AuthParameters: { REFRESH_TOKEN: 'refreshtoken' }, @@ -167,5 +110,6 @@ describe('Cognito ASF', () => { UserContextData: { EncodedData: 'abcd' }, }) ); + window['AmazonCognitoAdvancedSecurityData'] = undefined; }); }); diff --git a/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts b/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts index b7c46445dd6..930b729a93f 100644 --- a/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts +++ b/packages/auth/__tests__/providers/cognito/rememberDevice.test.ts @@ -1,111 +1,78 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { rememberDevice } from '../../../src/providers/cognito'; import { UpdateDeviceStatusException } from '../../../src/providers/cognito/types/errors'; -import * as clients from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import * as TokenProvider from '../../../src/providers/cognito/tokenProvider'; +import { updateDeviceStatus } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { tokenOrchestrator } from '../../../src/providers/cognito/tokenProvider'; import { DeviceMetadata } from '../../../src/providers/cognito/tokenProvider/types'; -import { decodeJWT, retry } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); -const mockedAccessToken = - 'test_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockDeviceMetadata: DeviceMetadata = { - deviceKey: 'deviceKey', - deviceGroupKey: 'deviceGroupKey', - randomPassword: 'randomPassword', -}; +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); +jest.mock('../../../src/providers/cognito/tokenProvider'); -const mockFetchAuthSession = fetchAuthSession as jest.Mock; +describe('rememberDevice', () => { + const mockDeviceMetadata: DeviceMetadata = { + deviceKey: 'deviceKey', + deviceGroupKey: 'deviceGroupKey', + randomPassword: 'randomPassword', + }; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockUpdateDeviceStatus = updateDeviceStatus as jest.Mock; + const mockGetDeviceMetadata = + tokenOrchestrator.getDeviceMetadata as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); -describe('rememberDevice API happy path cases', () => { - let updateDeviceStatusClientSpy; - let tokenOrchestratorSpy; beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - updateDeviceStatusClientSpy = jest - .spyOn(clients, 'updateDeviceStatus') - .mockImplementationOnce(async () => { - return { - $metadata: {}, - }; - }); - tokenOrchestratorSpy = jest - .spyOn(TokenProvider.tokenOrchestrator, 'getDeviceMetadata') - .mockImplementation(async () => mockDeviceMetadata); + mockGetDeviceMetadata.mockResolvedValue(mockDeviceMetadata); + mockUpdateDeviceStatus.mockResolvedValue({ $metadata: {} }); }); afterEach(() => { + mockGetDeviceMetadata.mockReset(); + mockUpdateDeviceStatus.mockReset(); mockFetchAuthSession.mockClear(); - updateDeviceStatusClientSpy.mockClear(); }); it('should call updateDeviceStatus client with correct request', async () => { expect.assertions(2); await rememberDevice(); - expect(updateDeviceStatusClientSpy).toHaveBeenCalledWith( + expect(mockUpdateDeviceStatus).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, DeviceKey: mockDeviceMetadata.deviceKey, DeviceRememberedStatus: 'remembered', }) ); - expect(updateDeviceStatusClientSpy).toBeCalledTimes(1); + expect(mockUpdateDeviceStatus).toHaveBeenCalledTimes(1); }); -}); -describe('rememberDevice API error path cases', () => { - it('should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - UpdateDeviceStatusException.InvalidParameterException - ) - ) - ); + mockUpdateDeviceStatus.mockImplementation(() => { + throw getMockError(UpdateDeviceStatusException.InvalidParameterException); + }); try { await rememberDevice(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( UpdateDeviceStatusException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts b/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts index a2f1c7b5506..a4698fbee89 100644 --- a/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts +++ b/packages/auth/__tests__/providers/cognito/resendSignUpCode.test.ts @@ -1,48 +1,49 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Amplify } from '@aws-amplify/core'; import { resendSignUpCode } from '../../../src/providers/cognito'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { AuthError } from '../../../src/errors/AuthError'; import { ResendConfirmationException } from '../../../src/providers/cognito/types/errors'; -import * as resendSignUpConfirmationCodeClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { ResendConfirmationCodeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { Amplify } from 'aws-amplify'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { resendConfirmationCode } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, - }, -}); -describe('ResendSignUp API Happy Path Cases:', () => { - let resendSignUpSpy; +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('resendSignUpCode', () => { const { user1 } = authAPITestParams; + // assert mocks + const mockResendConfirmationCode = resendConfirmationCode as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + }); + beforeEach(() => { - resendSignUpSpy = jest - .spyOn(resendSignUpConfirmationCodeClient, 'resendConfirmationCode') - .mockImplementationOnce(async () => { - return authAPITestParams.resendSignUpClientResult as ResendConfirmationCodeCommandOutput; - }); + mockResendConfirmationCode.mockResolvedValue( + authAPITestParams.resendSignUpClientResult + ); }); + afterEach(() => { - resendSignUpSpy.mockClear(); + mockResendConfirmationCode.mockReset(); }); - afterAll(() => { - jest.restoreAllMocks(); - }); - test('ResendSignUp API should call the UserPoolClient and should return a ResendSignUpCodeResult', async () => { + + it('should call resendConfirmationCode and return a result', async () => { const result = await resendSignUpCode({ username: user1.username, }); expect(result).toEqual(authAPITestParams.resendSignUpAPIResult); - expect(resendSignUpSpy).toHaveBeenCalledWith( + expect(mockResendConfirmationCode).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), @@ -53,79 +54,45 @@ describe('ResendSignUp API Happy Path Cases:', () => { ClientId: '111111-aaaaa-42d8-891d-ee81a1549398', } ); - expect(resendSignUpSpy).toBeCalledTimes(1); + expect(mockResendConfirmationCode).toHaveBeenCalledTimes(1); }); -}); -describe('ResendSignUp API Error Path Cases:', () => { - const { user1 } = authAPITestParams; - afterAll(() => { - jest.restoreAllMocks(); - }); - test('ResendSignUp API should throw a validation AuthError when username is empty', async () => { + it('should throw an error when username is empty', async () => { expect.assertions(2); try { await resendSignUpCode({ username: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptySignUpUsername); } }); - test('ResendSignUp API should expect a service error', async () => { - expect.assertions(2); + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - ResendConfirmationException.InvalidParameterException - ) - ) - ); + mockResendConfirmationCode.mockImplementation(() => { + throw getMockError(ResendConfirmationException.InvalidParameterException); + }); try { await resendSignUpCode({ username: user1.username }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( ResendConfirmationException.InvalidParameterException ); } }); -}); -describe('ResendSignUp API Edge Cases:', () => {}); - -describe('Cognito ASF', () => { - let resendSignUpSpy; - const { user1 } = authAPITestParams; - beforeEach(() => { - resendSignUpSpy = jest - .spyOn(resendSignUpConfirmationCodeClient, 'resendConfirmationCode') - .mockImplementationOnce(async () => { - return authAPITestParams.resendSignUpClientResult as ResendConfirmationCodeCommandOutput; - }); - - // load Cognito ASF polyfill + it('should send UserContextData', async () => { window['AmazonCognitoAdvancedSecurityData'] = { getData() { return 'abcd'; }, }; - }); - - afterEach(() => { - resendSignUpSpy.mockClear(); - window['AmazonCognitoAdvancedSecurityData'] = undefined; - }); - afterAll(() => { - jest.restoreAllMocks(); - }); - test('ResendSignUp API should send UserContextData', async () => { const result = await resendSignUpCode({ username: user1.username, }); expect(result).toEqual(authAPITestParams.resendSignUpAPIResult); - expect(resendSignUpSpy).toHaveBeenCalledWith( + expect(mockResendConfirmationCode).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), @@ -137,6 +104,7 @@ describe('Cognito ASF', () => { UserContextData: { EncodedData: 'abcd' }, } ); - expect(resendSignUpSpy).toBeCalledTimes(1); + expect(mockResendConfirmationCode).toHaveBeenCalledTimes(1); + window['AmazonCognitoAdvancedSecurityData'] = undefined; }); }); diff --git a/packages/auth/__tests__/providers/cognito/resetPassword.test.ts b/packages/auth/__tests__/providers/cognito/resetPassword.test.ts index 99dccca9c9f..31a75be379a 100644 --- a/packages/auth/__tests__/providers/cognito/resetPassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/resetPassword.test.ts @@ -1,57 +1,54 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Amplify } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { resetPassword } from '../../../src/providers/cognito'; import { ForgotPasswordException } from '../../../src/providers/cognito/types/errors'; -import * as resetPasswordClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { authAPITestParams } from './testUtils/authApiTestParams'; -import { ForgotPasswordCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { Amplify } from 'aws-amplify'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { forgotPassword } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, - }, -}); -describe('ResetPassword API happy path cases', () => { - let resetPasswordSpy; +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); - beforeEach(() => { - resetPasswordSpy = jest - .spyOn(resetPasswordClient, 'forgotPassword') - .mockImplementationOnce(async () => { - return authAPITestParams.resetPasswordHttpCallResult as ForgotPasswordCommandOutput; - }); +describe('resetPassword', () => { + // assert mocks + const mockForgotPassword = forgotPassword as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); }); - afterEach(() => { - resetPasswordSpy.mockClear(); + beforeEach(() => { + mockForgotPassword.mockResolvedValue( + authAPITestParams.resetPasswordHttpCallResult + ); }); - afterAll(() => { - jest.restoreAllMocks(); + afterEach(() => { + mockForgotPassword.mockReset(); }); - test('ResetPassword API should call the UserPoolClient and should return a ResetPasswordResult', async () => { + it('should call forgotPassword and return a result', async () => { const result = await resetPassword(authAPITestParams.resetPasswordRequest); expect(result).toEqual(authAPITestParams.resetPasswordResult); }); - test('ResetPassword API input should contain clientMetadata from request', async () => { + it('should contain clientMetadata from request', async () => { await resetPassword({ username: 'username', options: { clientMetadata: { foo: 'foo' }, }, }); - expect(resetPasswordSpy).toHaveBeenCalledWith( + expect(mockForgotPassword).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ Username: 'username', @@ -60,14 +57,12 @@ describe('ResetPassword API happy path cases', () => { }) ); }); -}); -describe('ResetPassword API error path cases:', () => { - test('ResetPassword API should throw a validation AuthError when username is empty', async () => { + it('should throw an error when username is empty', async () => { expect.assertions(2); try { await resetPassword({ username: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AuthValidationErrorCode.EmptyResetPasswordUsername @@ -75,60 +70,34 @@ describe('ResetPassword API error path cases:', () => { } }); - test('ResetPassword API should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - ForgotPasswordException.InvalidParameterException - ) - ) - ); + mockForgotPassword.mockImplementation(() => { + throw getMockError(ForgotPasswordException.InvalidParameterException); + }); try { await resetPassword(authAPITestParams.resetPasswordRequest); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( ForgotPasswordException.InvalidParameterException ); } }); -}); -describe('Cognito ASF', () => { - let resetPasswordSpy; - - beforeEach(() => { - resetPasswordSpy = jest - .spyOn(resetPasswordClient, 'forgotPassword') - .mockImplementationOnce(async () => { - return authAPITestParams.resetPasswordHttpCallResult as ForgotPasswordCommandOutput; - }); - // load Cognito ASF polyfill + it('should send UserContextData', async () => { window['AmazonCognitoAdvancedSecurityData'] = { getData() { return 'abcd'; }, }; - }); - - afterEach(() => { - resetPasswordSpy.mockClear(); - window['AmazonCognitoAdvancedSecurityData'] = undefined; - }); - - afterAll(() => { - jest.restoreAllMocks(); - }); - - test('ResetPassword API should send UserContextData', async () => { await resetPassword({ username: 'username', options: { clientMetadata: { foo: 'foo' }, }, }); - expect(resetPasswordSpy).toHaveBeenCalledWith( + expect(mockForgotPassword).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ Username: 'username', @@ -137,5 +106,6 @@ describe('Cognito ASF', () => { UserContextData: { EncodedData: 'abcd' }, }) ); + window['AmazonCognitoAdvancedSecurityData'] = undefined; }); }); diff --git a/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts b/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts index 301ef39db41..92399e59a33 100644 --- a/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts +++ b/packages/auth/__tests__/providers/cognito/sendUserAttributeVerificationCode.test.ts @@ -1,66 +1,49 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { sendUserAttributeVerificationCode } from '../../../src/providers/cognito'; import { GetUserAttributeVerificationException } from '../../../src/providers/cognito/types/errors'; -import * as getUserAttributeVerificationCodeClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -import { GetUserAttributeVerificationCodeCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getUserAttributeVerificationCode } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -describe('resendUserAttributeConfirmationCode API happy path cases', () => { - let getUserAttributeVerificationCodeClientSpy; +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('sendUserAttributeVerificationCode', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockGetUserAttributeVerificationCode = + getUserAttributeVerificationCode as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); + beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } + mockGetUserAttributeVerificationCode.mockResolvedValue( + authAPITestParams.resendSignUpClientResult ); - getUserAttributeVerificationCodeClientSpy = jest - .spyOn( - getUserAttributeVerificationCodeClient, - 'getUserAttributeVerificationCode' - ) - .mockImplementationOnce( - async () => - authAPITestParams.resendSignUpClientResult as GetUserAttributeVerificationCodeCommandOutput - ); }); afterEach(() => { + mockGetUserAttributeVerificationCode.mockReset(); mockFetchAuthSession.mockClear(); - getUserAttributeVerificationCodeClientSpy.mockClear(); }); - it('Should return a resendUserAttributeConfirmationCodeRequest', async () => { + it('should return a result', async () => { const result = await sendUserAttributeVerificationCode({ userAttributeKey: 'email', options: { @@ -69,37 +52,24 @@ describe('resendUserAttributeConfirmationCode API happy path cases', () => { }); expect(result).toEqual(authAPITestParams.resendSignUpAPIResult); - expect(getUserAttributeVerificationCodeClientSpy).toHaveBeenCalledWith( + expect(mockGetUserAttributeVerificationCode).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, AttributeName: 'email', ClientMetadata: { foo: 'bar' }, }) ); - expect(getUserAttributeVerificationCodeClientSpy).toBeCalledTimes(1); + expect(mockGetUserAttributeVerificationCode).toHaveBeenCalledTimes(1); }); -}); -describe('resendUserAttributeConfirmationCode API error path cases', () => { - test('Should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - GetUserAttributeVerificationException.InvalidParameterException - ) - ) - ); + mockGetUserAttributeVerificationCode.mockImplementation(() => { + throw getMockError( + GetUserAttributeVerificationException.InvalidParameterException + ); + }); try { await sendUserAttributeVerificationCode({ userAttributeKey: 'email', @@ -107,7 +77,7 @@ describe('resendUserAttributeConfirmationCode API error path cases', () => { clientMetadata: { foo: 'bar' }, }, }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( GetUserAttributeVerificationException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts b/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts index 6b2fe0280ae..4b83ec24769 100644 --- a/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts +++ b/packages/auth/__tests__/providers/cognito/setUpTOTP.test.ts @@ -1,106 +1,73 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { AssociateSoftwareTokenException } from '../../../src/providers/cognito/types/errors'; -import * as associateSoftwareTokenClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { associateSoftwareToken } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { setUpTOTP } from '../../../src/providers/cognito'; -import { AssociateSoftwareTokenCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('setUpTOTP', () => { + const secretCode = 'secret-code'; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockAssociateSoftwareToken = associateSoftwareToken as jest.Mock; -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); -describe('setUpTOTP API happy path cases', () => { - let associateSoftwareTokenClientSpy; - const secretCode = 'asfdasdfwefasdfasf'; beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - associateSoftwareTokenClientSpy = jest - .spyOn(associateSoftwareTokenClient, 'associateSoftwareToken') - .mockImplementationOnce( - async (): Promise => { - return { - SecretCode: secretCode, - $metadata: {}, - }; - } - ); + mockAssociateSoftwareToken.mockResolvedValue({ + SecretCode: secretCode, + $metadata: {}, + }); }); afterEach(() => { - associateSoftwareTokenClientSpy.mockClear(); + mockAssociateSoftwareToken.mockReset(); mockFetchAuthSession.mockClear(); }); - test('setUpTOTP API should call the UserPoolClient and should return a TOTPSetupDetails', async () => { + it('setUpTOTP API should call the UserPoolClient and should return a TOTPSetupDetails', async () => { const result = await setUpTOTP(); - expect(associateSoftwareTokenClientSpy).toHaveBeenCalledWith( + expect(mockAssociateSoftwareToken).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), }, { - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, } ); expect(result.sharedSecret).toEqual(secretCode); expect(result.getSetupUri('appName', 'amplify')).toBeInstanceOf(URL); }); -}); -describe('setUpTOTP API error path cases:', () => { - test('setUpTOTP API should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - AssociateSoftwareTokenException.InvalidParameterException - ) - ) - ); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); + mockAssociateSoftwareToken.mockImplementation(() => { + throw getMockError( + AssociateSoftwareTokenException.InvalidParameterException + ); + }); try { await setUpTOTP(); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( AssociateSoftwareTokenException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts b/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts index e050dfab6a1..46d192f872f 100644 --- a/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInErrorCases.test.ts @@ -1,94 +1,94 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Amplify } from '@aws-amplify/core'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { authAPITestParams } from './testUtils/authApiTestParams'; -import { - signIn, - getCurrentUser, - cognitoUserPoolsTokenProvider, -} from '../../../src/providers/cognito'; +import { signIn, getCurrentUser } from '../../../src/providers/cognito'; +import { initiateAuth } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { InitiateAuthException } from '../../../src/providers/cognito/types/errors'; -import { Amplify } from 'aws-amplify'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; import { USER_ALREADY_AUTHENTICATED_EXCEPTION } from '../../../src/errors/constants'; +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; + +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); jest.mock('../../../src/providers/cognito/apis/getCurrentUser'); -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -const authConfig = { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, -}; +describe('signIn API error path cases:', () => { + // assert mocks + const mockInitiateAuth = initiateAuth as jest.Mock; + const mockedGetCurrentUser = getCurrentUser as jest.Mock; -Amplify.configure({ - Auth: authConfig, -}); -cognitoUserPoolsTokenProvider.setAuthConfig(authConfig); + beforeAll(() => { + setUpGetConfig(Amplify); + }); -describe('signIn API error path cases:', () => { - test('signIn API should throw a validation AuthError when a user is already signed-in', async () => { - const mockedGetCurrentUser = getCurrentUser as jest.Mock; + afterEach(() => { + mockedGetCurrentUser.mockReset(); + mockInitiateAuth.mockClear(); + }); - mockedGetCurrentUser.mockImplementationOnce(async () => { - return { - username: 'username', - userId: 'userId', - }; + it('should throw an error when a user is already signed-in', async () => { + mockedGetCurrentUser.mockResolvedValue({ + username: 'username', + userId: 'userId', }); try { await signIn({ username: 'username', password: 'password' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(USER_ALREADY_AUTHENTICATED_EXCEPTION); } mockedGetCurrentUser.mockClear(); }); - test('signIn API should throw a validation AuthError when username is empty', async () => { + + it('should throw an error when username is empty', async () => { expect.assertions(2); try { await signIn({ username: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptySignInUsername); } }); - test('signIn API should raise service error', async () => { + it('should throw an error when password is not empty and authFlow is CUSTOM_WITHOUT_SRP', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(InitiateAuthException.InvalidParameterException) - ) - ); try { await signIn({ username: authAPITestParams.user1.username, password: authAPITestParams.user1.password, + options: { + authFlowType: 'CUSTOM_WITHOUT_SRP', + }, }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); - expect(error.name).toBe(InitiateAuthException.InvalidParameterException); + expect(error.name).toBe(AuthValidationErrorCode.CustomAuthSignInPassword); } }); - test('signIn API should throw a validation AuthError when password is not empty and when authFlow is CUSTOM_WITHOUT_SRP', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); + mockInitiateAuth.mockImplementation(() => { + throw getMockError(InitiateAuthException.InvalidParameterException); + }); try { await signIn({ username: authAPITestParams.user1.username, password: authAPITestParams.user1.password, - options: { - authFlowType: 'CUSTOM_WITHOUT_SRP', - }, }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); - expect(error.name).toBe(AuthValidationErrorCode.CustomAuthSignInPassword); + expect(error.name).toBe(InitiateAuthException.InvalidParameterException); } }); }); diff --git a/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts b/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts index 9cb49b83b29..c3daea90f67 100644 --- a/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInStateManagement.test.ts @@ -54,7 +54,7 @@ describe('local sign-in state management tests', () => { const localSignInState = signInStore.getState(); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); expect(localSignInState).toEqual({ challengeName, signInSession: session, @@ -92,7 +92,7 @@ describe('local sign-in state management tests', () => { const localSignInState = signInStore.getState(); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); expect(localSignInState).toEqual({ challengeName: undefined, signInSession: undefined, diff --git a/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts b/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts index 567a706b82f..13674d158cb 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithCustomAuth.test.ts @@ -51,7 +51,7 @@ describe('signIn API happy path cases', () => { }, }); expect(result).toEqual(authAPITestParams.signInResultWithCustomAuth()); - expect(handleCustomAuthFlowWithoutSRPSpy).toBeCalledTimes(1); + expect(handleCustomAuthFlowWithoutSRPSpy).toHaveBeenCalledTimes(1); }); test('signInWithCustomAuth API should return a SignInResult', async () => { @@ -59,7 +59,7 @@ describe('signIn API happy path cases', () => { username: authAPITestParams.user1.username, }); expect(result).toEqual(authAPITestParams.signInResultWithCustomAuth()); - expect(handleCustomAuthFlowWithoutSRPSpy).toBeCalledTimes(1); + expect(handleCustomAuthFlowWithoutSRPSpy).toHaveBeenCalledTimes(1); }); test('handleCustomAuthFlowWithoutSRP should be called with clientMetada from request', async () => { const username = authAPITestParams.user1.username; @@ -68,7 +68,7 @@ describe('signIn API happy path cases', () => { username, options: authAPITestParams.configWithClientMetadata, }); - expect(handleCustomAuthFlowWithoutSRPSpy).toBeCalledWith( + expect(handleCustomAuthFlowWithoutSRPSpy).toHaveBeenCalledWith( username, authAPITestParams.configWithClientMetadata.clientMetadata, authConfig.Cognito, @@ -117,7 +117,7 @@ describe('Cognito ASF', () => { authFlowType: 'CUSTOM_WITHOUT_SRP', }, }); - expect(initiateAuthSpy).toBeCalledWith( + expect(initiateAuthSpy).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts b/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts index c49983466f9..72e5ab315f5 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithCustomSRPAuth.test.ts @@ -54,7 +54,7 @@ describe('signIn API happy path cases', () => { }, }); expect(result).toEqual(authAPITestParams.signInResultWithCustomAuth()); - expect(handleCustomSRPAuthFlowSpy).toBeCalledTimes(1); + expect(handleCustomSRPAuthFlowSpy).toHaveBeenCalledTimes(1); }); test('signInWithCustomSRPAuth API should return a SignInResult', async () => { @@ -63,7 +63,7 @@ describe('signIn API happy path cases', () => { password: authAPITestParams.user1.password, }); expect(result).toEqual(authAPITestParams.signInResultWithCustomAuth()); - expect(handleCustomSRPAuthFlowSpy).toBeCalledTimes(1); + expect(handleCustomSRPAuthFlowSpy).toHaveBeenCalledTimes(1); }); test('handleCustomSRPAuthFlow should be called with clientMetada from request', async () => { @@ -74,7 +74,7 @@ describe('signIn API happy path cases', () => { password, options: authAPITestParams.configWithClientMetadata, }); - expect(handleCustomSRPAuthFlowSpy).toBeCalledWith( + expect(handleCustomSRPAuthFlowSpy).toHaveBeenCalledWith( username, password, authAPITestParams.configWithClientMetadata.clientMetadata, @@ -126,7 +126,7 @@ describe('Cognito ASF', () => { } catch (_) { // only want to test the contents } - expect(initiateAuthSpy).toBeCalledWith( + expect(initiateAuthSpy).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts b/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts index 2589f9d49d3..393854f3fee 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts @@ -83,7 +83,7 @@ describe('getRedirectUrl on web', () => { try { return getRedirectUrl(['http://localhost:3000/', 'https://example.com/']); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(INVALID_ORIGIN_EXCEPTION); } @@ -99,7 +99,7 @@ describe('getRedirectUrl on web', () => { try { return getRedirectUrl(['novalid']); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(INVALID_REDIRECT_EXCEPTION); } @@ -118,7 +118,7 @@ describe('getRedirectUrl on React Native', () => { it('should throw if the redirect is invalid or not found', async () => { try { return getRedirectUrlRN(['invalid']); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(INVALID_REDIRECT_EXCEPTION); } diff --git a/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts b/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts index 11d1a30812e..6845b63b1e7 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithSRP.test.ts @@ -120,7 +120,7 @@ describe('signIn API happy path cases', () => { }, }); expect(result).toEqual(authAPITestParams.signInResult()); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); }); test('signIn API should delegate to signinWithSRP API by default and return a SignInResult', async () => { @@ -129,7 +129,7 @@ describe('signIn API happy path cases', () => { password: authAPITestParams.user1.password, }); expect(result).toEqual(authAPITestParams.signInResult()); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); }); test('signInWithSRP API should return a SignInResult', async () => { @@ -138,7 +138,7 @@ describe('signIn API happy path cases', () => { password: authAPITestParams.user1.password, }); expect(result).toEqual(authAPITestParams.signInResult()); - expect(handleUserSRPAuthflowSpy).toBeCalledTimes(1); + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledTimes(1); }); test('handleUserSRPFlow should be called with clientMetada from request', async () => { @@ -149,7 +149,7 @@ describe('signIn API happy path cases', () => { password, options: authAPITestParams.configWithClientMetadata, }); - expect(handleUserSRPAuthflowSpy).toBeCalledWith( + expect(handleUserSRPAuthflowSpy).toHaveBeenCalledWith( username, password, authAPITestParams.configWithClientMetadata.clientMetadata, @@ -198,7 +198,7 @@ describe('Cognito ASF', () => { } catch (_) { // only want to test the contents } - expect(initiateAuthSpy).toBeCalledWith( + expect(initiateAuthSpy).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts b/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts index 2fd5e0b6fd1..87de0c29eb2 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithUserPassword.test.ts @@ -49,7 +49,7 @@ describe('signIn API happy path cases', () => { }, }); expect(result).toEqual(authAPITestParams.signInResult()); - expect(handleUserPasswordFlowSpy).toBeCalledTimes(1); + expect(handleUserPasswordFlowSpy).toHaveBeenCalledTimes(1); }); test('handleUserPasswordAuthFlow should be called with clientMetada from request', async () => { @@ -60,7 +60,7 @@ describe('signIn API happy path cases', () => { password, options: authAPITestParams.configWithClientMetadata, }); - expect(handleUserPasswordFlowSpy).toBeCalledWith( + expect(handleUserPasswordFlowSpy).toHaveBeenCalledWith( username, password, authAPITestParams.configWithClientMetadata.clientMetadata, @@ -112,7 +112,7 @@ describe('Cognito ASF', () => { } catch (_) { // only want to test the contents } - expect(initiateAuthSpy).toBeCalledWith( + expect(initiateAuthSpy).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2', }), diff --git a/packages/auth/__tests__/providers/cognito/signOut.test.ts b/packages/auth/__tests__/providers/cognito/signOut.test.ts index d1ff7c921b1..81b30bbca68 100644 --- a/packages/auth/__tests__/providers/cognito/signOut.test.ts +++ b/packages/auth/__tests__/providers/cognito/signOut.test.ts @@ -19,15 +19,7 @@ import { DefaultOAuthStore } from '../../../src/providers/cognito/utils/signInWi import { handleOAuthSignOut } from '../../../src/providers/cognito/utils/oauth'; import { AuthTokenStore } from '../../../src/providers/cognito/tokenProvider/types'; -jest.mock('@aws-amplify/core', () => { - return { - ...(jest.genMockFromModule('@aws-amplify/core') as object), - // must do this as auth tests import `signInWithRedirect` - Amplify: { - getConfig: jest.fn().mockReturnValue({}), - }, - }; -}); +jest.mock('@aws-amplify/core'); jest.mock('../../../src/providers/cognito/tokenProvider'); jest.mock( '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' @@ -79,9 +71,9 @@ describe('signOut', () => { // create test helpers const expectSignOut = () => ({ toComplete: () => { - expect(mockTokenOrchestrator.clearTokens).toBeCalledTimes(1); - expect(mockClearCredentials).toBeCalledTimes(1); - expect(mockHub.dispatch).toBeCalledWith( + expect(mockTokenOrchestrator.clearTokens).toHaveBeenCalledTimes(1); + expect(mockClearCredentials).toHaveBeenCalledTimes(1); + expect(mockHub.dispatch).toHaveBeenCalledWith( 'auth', { event: 'signedOut' }, 'Auth', @@ -90,9 +82,9 @@ describe('signOut', () => { }, not: { toComplete: () => { - expect(mockTokenOrchestrator.clearTokens).not.toBeCalled(); - expect(mockClearCredentials).not.toBeCalled(); - expect(mockHub.dispatch).not.toBeCalled(); + expect(mockTokenOrchestrator.clearTokens).not.toHaveBeenCalled(); + expect(mockClearCredentials).not.toHaveBeenCalled(); + expect(mockHub.dispatch).not.toHaveBeenCalled(); }, }, }); @@ -127,12 +119,12 @@ describe('signOut', () => { it('should perform client sign out on a revocable session', async () => { await signOut(); - expect(mockRevokeToken).toBeCalledWith( + expect(mockRevokeToken).toHaveBeenCalledWith( { region }, { ClientId: cognitoConfig.userPoolClientId, Token: refreshToken } ); - expect(mockGetRegion).toBeCalledTimes(1); - expect(mockGlobalSignOut).not.toBeCalled(); + expect(mockGetRegion).toHaveBeenCalledTimes(1); + expect(mockGlobalSignOut).not.toHaveBeenCalled(); expectSignOut().toComplete(); }); @@ -144,21 +136,21 @@ describe('signOut', () => { await signOut(); - expect(mockRevokeToken).not.toBeCalled(); - expect(mockGlobalSignOut).not.toBeCalled(); - expect(mockGetRegion).not.toBeCalled(); + expect(mockRevokeToken).not.toHaveBeenCalled(); + expect(mockGlobalSignOut).not.toHaveBeenCalled(); + expect(mockGetRegion).not.toHaveBeenCalled(); expectSignOut().toComplete(); }); it('should perform global sign out', async () => { await signOut({ global: true }); - expect(mockGlobalSignOut).toBeCalledWith( + expect(mockGlobalSignOut).toHaveBeenCalledWith( { region: 'us-west-2' }, { AccessToken: accessToken.toString() } ); - expect(mockGetRegion).toBeCalledTimes(1); - expect(mockRevokeToken).not.toBeCalled(); + expect(mockGetRegion).toHaveBeenCalledTimes(1); + expect(mockRevokeToken).not.toHaveBeenCalled(); expectSignOut().toComplete(); }); @@ -167,10 +159,10 @@ describe('signOut', () => { await signOut(); - expect(loggerDebugSpy).toBeCalledWith( + expect(loggerDebugSpy).toHaveBeenCalledWith( expect.stringContaining('Client signOut error caught') ); - expect(mockGetRegion).toBeCalledTimes(1); + expect(mockGetRegion).toHaveBeenCalledTimes(1); expectSignOut().toComplete(); }); @@ -179,10 +171,10 @@ describe('signOut', () => { await signOut({ global: true }); - expect(loggerDebugSpy).toBeCalledWith( + expect(loggerDebugSpy).toHaveBeenCalledWith( expect.stringContaining('Global signOut error caught') ); - expect(mockGetRegion).toBeCalledTimes(1); + expect(mockGetRegion).toHaveBeenCalledTimes(1); expectSignOut().toComplete(); }); }); @@ -216,11 +208,11 @@ describe('signOut', () => { it('should perform OAuth sign out', async () => { await signOut(); - expect(MockDefaultOAuthStore).toBeCalledTimes(1); - expect(mockDefaultOAuthStoreInstance.setAuthConfig).toBeCalledWith( + expect(MockDefaultOAuthStore).toHaveBeenCalledTimes(1); + expect(mockDefaultOAuthStoreInstance.setAuthConfig).toHaveBeenCalledWith( cognitoConfigWithOauth ); - expect(mockHandleOAuthSignOut).toBeCalledWith( + expect(mockHandleOAuthSignOut).toHaveBeenCalledWith( cognitoConfigWithOauth, mockDefaultOAuthStoreInstance ); diff --git a/packages/auth/__tests__/providers/cognito/signUp.test.ts b/packages/auth/__tests__/providers/cognito/signUp.test.ts index 6839aa94385..5ff8729e00c 100644 --- a/packages/auth/__tests__/providers/cognito/signUp.test.ts +++ b/packages/auth/__tests__/providers/cognito/signUp.test.ts @@ -1,40 +1,42 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Amplify } from '@aws-amplify/core'; import { signUp } from '../../../src/providers/cognito'; -import * as signUpClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { signUp as providerSignUp } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { authAPITestParams } from './testUtils/authApiTestParams'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { AuthError } from '../../../src/errors/AuthError'; import { SignUpException } from '../../../src/providers/cognito/types/errors'; -import { SignUpCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { Amplify } from 'aws-amplify'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; -Amplify.configure({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - }, - }, -}); -describe('SignUp API Happy Path Cases:', () => { - let signUpSpy; +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, +})); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('signUp', () => { const { user1 } = authAPITestParams; + // assert mocks + const mockSignUp = providerSignUp as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + }); + beforeEach(() => { - signUpSpy = jest - .spyOn(signUpClient, 'signUp') - .mockImplementationOnce(async () => { - return authAPITestParams.signUpHttpCallResult as SignUpCommandOutput; - }); + mockSignUp.mockResolvedValue(authAPITestParams.signUpHttpCallResult); }); + afterEach(() => { - signUpSpy.mockClear(); + mockSignUp.mockReset(); }); - test('SignUp API should call the UserPoolClient and should return a SignUpResult', async () => { + + it('should call signUp and return a result', async () => { const result = await signUp({ username: user1.username, password: user1.password, @@ -54,7 +56,7 @@ describe('SignUp API Happy Path Cases:', () => { }, userId: '1234567890', }); - expect(signUpSpy).toHaveBeenCalledWith( + expect(mockSignUp).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), @@ -68,47 +70,39 @@ describe('SignUp API Happy Path Cases:', () => { ClientId: '111111-aaaaa-42d8-891d-ee81a1549398', } ); - expect(signUpSpy).toBeCalledTimes(1); + expect(mockSignUp).toHaveBeenCalledTimes(1); }); -}); - -describe('SignUp API Error Path Cases:', () => { - const { user1 } = authAPITestParams; - test('SignUp API should throw a validation AuthError when username is empty', async () => { + it('should throw an error when username is empty', async () => { expect.assertions(2); try { await signUp({ username: '', password: user1.password }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptySignUpUsername); } }); - test('SignUp API should throw a validation AuthError when password is empty', async () => { + it('should throw an error when password is empty', async () => { expect.assertions(2); try { await signUp({ username: user1.username, password: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptySignUpPassword); } }); - test('SignUp API should expect a service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(SignUpException.InvalidParameterException) - ) - ); + mockSignUp.mockImplementation(() => { + throw getMockError(SignUpException.InvalidParameterException); + }); try { await signUp({ username: user1.username, password: user1.password }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(SignUpException.InvalidParameterException); } }); }); - -describe('SignUp API Edge Cases:', () => {}); diff --git a/packages/auth/__tests__/providers/cognito/testUtils/authApiTestParams.ts b/packages/auth/__tests__/providers/cognito/testUtils/authApiTestParams.ts index f59dcf04153..23e580d2e5f 100644 --- a/packages/auth/__tests__/providers/cognito/testUtils/authApiTestParams.ts +++ b/packages/auth/__tests__/providers/cognito/testUtils/authApiTestParams.ts @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { AuthSignInResult } from '../../../../src/types'; +import { AuthSignInOutput } from '../../../../src/types'; export const authAPITestParams = { user1: { @@ -207,7 +207,7 @@ export const authAPITestParams = { }, }; }, - signInResult: (): AuthSignInResult => { + signInResult: (): AuthSignInOutput => { return { isSignedIn: true, nextStep: { diff --git a/packages/auth/__tests__/providers/cognito/testUtils/data.ts b/packages/auth/__tests__/providers/cognito/testUtils/data.ts index 9a7dfb0a0ed..63b5d2a51bb 100644 --- a/packages/auth/__tests__/providers/cognito/testUtils/data.ts +++ b/packages/auth/__tests__/providers/cognito/testUtils/data.ts @@ -2,10 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { HttpResponse } from '@aws-amplify/core/src/clients/types'; +import { AuthError } from '../../../../src/errors/AuthError'; // Common -const region = 'us-east-1'; - export const MOCK_REQUEST_ID = 'requestId'; export const MOCK_EXTENDED_REQUEST_ID = 'requestId2'; export const DEFAULT_RESPONSE_HEADERS = { @@ -78,3 +77,12 @@ export function buildMockErrorResponse(errorName: string): { }, }; } + +export const getMockError = (name: string) => + new AuthError({ + name, + message: 'Error message', + }); + +export const mockAccessToken = + 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; diff --git a/packages/auth/__tests__/providers/cognito/testUtils/setUpGetConfig.ts b/packages/auth/__tests__/providers/cognito/testUtils/setUpGetConfig.ts new file mode 100644 index 00000000000..0f638b84e37 --- /dev/null +++ b/packages/auth/__tests__/providers/cognito/testUtils/setUpGetConfig.ts @@ -0,0 +1,14 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +export const setUpGetConfig = (mockAmplify: any) => { + mockAmplify.getConfig.mockReturnValue({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + }, + }, + }); +}; diff --git a/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts b/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts index 349418ee95e..8246bb27392 100644 --- a/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts +++ b/packages/auth/__tests__/providers/cognito/updateMFAPreference.test.ts @@ -1,39 +1,29 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { UpdateMFAPreferenceInput, updateMFAPreference, } from '../../../src/providers/cognito'; -import * as setUserMFAPreferenceClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { setUserMFAPreference } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { AuthError } from '../../../src/errors/AuthError'; import { SetUserMFAPreferenceException } from '../../../src/providers/cognito/types/errors'; import { getMFASettings } from '../../../src/providers/cognito/apis/updateMFAPreference'; import { SetUserMFAPreferenceCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); -const mfaChoises: UpdateMFAPreferenceInput[] = [ +const mfaChoices: UpdateMFAPreferenceInput[] = [ { sms: 'DISABLED', totp: 'DISABLED' }, { sms: 'DISABLED', totp: 'ENABLED' }, { sms: 'DISABLED', totp: 'PREFERRED' }, @@ -50,75 +40,63 @@ const mfaChoises: UpdateMFAPreferenceInput[] = [ { sms: 'NOT_PREFERRED', totp: 'ENABLED' }, { sms: 'NOT_PREFERRED', totp: 'PREFERRED' }, { sms: 'NOT_PREFERRED', totp: 'NOT_PREFERRED' }, - {}, + { sms: undefined, totp: undefined }, ]; -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -describe('updateMFAPreference Happy Path Cases:', () => { - let setUserMFAPreferenceClientSpy; + +describe('updateMFAPreference', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockSetUserMFAPreference = setUserMFAPreference as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); + beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - setUserMFAPreferenceClientSpy = jest - .spyOn(setUserMFAPreferenceClient, 'setUserMFAPreference') - .mockImplementationOnce(async () => { - return {} as SetUserMFAPreferenceCommandOutput; - }); + mockSetUserMFAPreference.mockResolvedValue({}); }); + afterEach(() => { - setUserMFAPreferenceClientSpy.mockClear(); + mockSetUserMFAPreference.mockReset(); mockFetchAuthSession.mockClear(); }); - test.each(mfaChoises)( - 'setUserMFAPreferenceClient should be called with all possible mfa combinations', + + it.each(mfaChoices)( + 'should update with sms $sms and totp $totp', async mfaChoise => { const { totp, sms } = mfaChoise; await updateMFAPreference(mfaChoise); - expect(setUserMFAPreferenceClientSpy).toHaveBeenCalledWith( + expect(mockSetUserMFAPreference).toHaveBeenCalledWith( { region: 'us-west-2', userAgentValue: expect.any(String), }, { - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, SMSMfaSettings: getMFASettings(sms), SoftwareTokenMfaSettings: getMFASettings(totp), } ); } ); -}); -describe('updateMFAPreference Error Path Cases:', () => { - test('updateMFAPreference should expect a service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse(SetUserMFAPreferenceException.ForbiddenException) - ) - ); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); + mockSetUserMFAPreference.mockImplementation(() => { + throw getMockError( + SetUserMFAPreferenceException.InvalidParameterException + ); + }); try { await updateMFAPreference({ sms: 'ENABLED', totp: 'PREFERRED' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); - expect(error.name).toBe(SetUserMFAPreferenceException.ForbiddenException); + expect(error.name).toBe( + SetUserMFAPreferenceException.InvalidParameterException + ); } }); }); diff --git a/packages/auth/__tests__/providers/cognito/updatePassword.test.ts b/packages/auth/__tests__/providers/cognito/updatePassword.test.ts index 9ab20380d61..a7435967921 100644 --- a/packages/auth/__tests__/providers/cognito/updatePassword.test.ts +++ b/packages/auth/__tests__/providers/cognito/updatePassword.test.ts @@ -1,125 +1,89 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { updatePassword } from '../../../src/providers/cognito'; import { ChangePasswordException } from '../../../src/providers/cognito/types/errors'; -import * as changePasswordClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { ChangePasswordCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { changePassword } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -describe('updatePassword API happy path cases', () => { +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('updatePassword', () => { const oldPassword = 'oldPassword'; const newPassword = 'newPassword'; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockChangePassword = changePassword as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); - let changePasswordClientSpy; beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - changePasswordClientSpy = jest - .spyOn(changePasswordClient, 'changePassword') - .mockImplementationOnce( - async (): Promise => { - return {} as ChangePasswordCommandOutput; - } - ); + mockChangePassword.mockResolvedValue({}); }); afterEach(() => { - changePasswordClientSpy.mockClear(); + mockChangePassword.mockReset(); mockFetchAuthSession.mockClear(); }); - test('updatePassword should call changePassword', async () => { + it('should call changePassword', async () => { await updatePassword({ oldPassword, newPassword }); - expect(changePasswordClientSpy).toHaveBeenCalledWith( + expect(mockChangePassword).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, PreviousPassword: oldPassword, ProposedPassword: newPassword, }) ); }); -}); - -describe('updatePassword API error path cases:', () => { - const oldPassword = 'oldPassword'; - const newPassword = 'newPassword'; - test('updatePassword API should throw a validation AuthError when oldPassword is empty', async () => { + it('should throw an error when oldPassword is empty', async () => { expect.assertions(2); try { await updatePassword({ oldPassword: '', newPassword }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptyUpdatePassword); } }); - test('updatePassword API should throw a validation AuthError when newPassword is empty', async () => { + it('should throw an error when newPassword is empty', async () => { expect.assertions(2); try { await updatePassword({ oldPassword, newPassword: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptyUpdatePassword); } }); - test('updatePassword API should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - ChangePasswordException.InvalidParameterException - ) - ) - ); + mockChangePassword.mockImplementation(() => { + throw getMockError(ChangePasswordException.InvalidParameterException); + }); + try { await updatePassword({ oldPassword, newPassword }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( ChangePasswordException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/updateUserAttribute.test.ts b/packages/auth/__tests__/providers/cognito/updateUserAttribute.test.ts index abc46c68c17..1b35c20daef 100644 --- a/packages/auth/__tests__/providers/cognito/updateUserAttribute.test.ts +++ b/packages/auth/__tests__/providers/cognito/updateUserAttribute.test.ts @@ -1,59 +1,36 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; -import { AuthError } from '../../../src/errors/AuthError'; -import { - updateUserAttribute, - UpdateUserAttributesOutput, -} from '../../../src/providers/cognito'; -import * as updateUserAttributesApi from '../../../src/providers/cognito'; -import { UpdateUserAttributesException } from '../../../src/providers/cognito/types/errors'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; +import { updateUserAttribute } from '../../../src/providers/cognito'; import { updateUserAttributes } from '../../../src/providers/cognito/apis/updateUserAttributes'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); -jest.mock('../../../src/providers/cognito/apis/updateUserAttributes'); +import { mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); -const mockedAccessToken = - 'test_eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -const mockUpdateUserAttributes = updateUserAttributes as jest.Mock; +jest.mock('../../../src/providers/cognito/apis/updateUserAttributes'); + describe('updateUserAttribute API happy path cases', () => { - beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockUpdateUserAttributes = updateUserAttributes as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); }); afterEach(() => { + mockUpdateUserAttributes.mockReset(); mockFetchAuthSession.mockClear(); }); - it('should call updateUserAttributes with correct input and should return correct output', async () => { + it('should return correct output', async () => { const mockInput = { userAttribute: { attributeKey: 'email', @@ -74,12 +51,10 @@ describe('updateUserAttribute API happy path cases', () => { }, }, }; - mockUpdateUserAttributes.mockImplementationOnce(async () => { - return { email: mockOutput } as UpdateUserAttributesOutput; - }); + mockUpdateUserAttributes.mockResolvedValue({ email: mockOutput }); const result = await updateUserAttribute(mockInput); expect(result).toEqual(mockOutput); - expect(mockUpdateUserAttributes).toBeCalledTimes(1); + expect(mockUpdateUserAttributes).toHaveBeenCalledTimes(1); expect(mockUpdateUserAttributes).toHaveBeenCalledWith({ userAttributes: { [mockInput.userAttribute.attributeKey]: mockInput.userAttribute.value, diff --git a/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts b/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts index f02dcdc017f..9fa9170e069 100644 --- a/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts +++ b/packages/auth/__tests__/providers/cognito/updateUserAttributes.test.ts @@ -1,75 +1,59 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { updateUserAttributes } from '../../../src/providers/cognito'; import { UpdateUserAttributesException } from '../../../src/providers/cognito/types/errors'; -import * as updateUserAttributesClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -import { UpdateUserAttributesCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; +import { updateUserAttributes as providerUpdateUserAttributes } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; import { toAttributeType } from '../../../src/providers/cognito/utils/apiHelpers'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -describe('updateUserAttributes API happy path cases', () => { +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('updateUserAttributes', () => { + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockUpdateUserAttributes = providerUpdateUserAttributes as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); + beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); + mockUpdateUserAttributes.mockResolvedValue({ + CodeDeliveryDetailsList: [ + { + AttributeName: 'email', + DeliveryMedium: 'EMAIL', + Destination: 'mockedEmail', + }, + { + AttributeName: 'phone_number', + DeliveryMedium: 'SMS', + Destination: 'mockedPhoneNumber', + }, + ], + }); }); afterEach(() => { + mockUpdateUserAttributes.mockReset(); mockFetchAuthSession.mockClear(); }); - test('updateUserAttributes API should return a map with updated and not updated attributes', async () => { - const updateUserAttributesClientSpy = jest - .spyOn(updateUserAttributesClient, 'updateUserAttributes') - .mockImplementationOnce( - async (): Promise => { - return { - CodeDeliveryDetailsList: [ - { - AttributeName: 'email', - DeliveryMedium: 'EMAIL', - Destination: 'mockedEmail', - }, - { - AttributeName: 'phone_number', - DeliveryMedium: 'SMS', - Destination: 'mockedPhoneNumber', - }, - ], - } as UpdateUserAttributesCommandOutput; - } - ); + it('should return a map with updated and not updated attributes', async () => { const userAttributes = { address: 'mockedAddress', name: 'mockedName', @@ -121,24 +105,18 @@ describe('updateUserAttributes API happy path cases', () => { }, }); - expect(updateUserAttributesClientSpy).toHaveBeenCalledWith( + expect(mockUpdateUserAttributes).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, UserAttributes: toAttributeType(userAttributes), ClientMetadata: { foo: 'bar' }, }) ); }); - test('updateUserAttributes API should return a map with updated attributes only', async () => { - const updateUserAttributesClientSpy = jest - .spyOn(updateUserAttributesClient, 'updateUserAttributes') - .mockImplementationOnce( - async (): Promise => { - return {} as UpdateUserAttributesCommandOutput; - } - ); + it('updateUserAttributes API should return a map with updated attributes only', async () => { + mockUpdateUserAttributes.mockResolvedValue({}); const userAttributes = { address: 'mockedAddress', name: 'mockedName', @@ -164,37 +142,31 @@ describe('updateUserAttributes API happy path cases', () => { }, }); - expect(updateUserAttributesClientSpy).toHaveBeenCalledWith( + expect(mockUpdateUserAttributes).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, UserAttributes: toAttributeType(userAttributes), ClientMetadata: { foo: 'bar' }, }) ); }); - test('updateUserAttributes API should return a map with not updated attributes only', async () => { - const updateUserAttributesClientSpy = jest - .spyOn(updateUserAttributesClient, 'updateUserAttributes') - .mockImplementationOnce( - async (): Promise => { - return { - CodeDeliveryDetailsList: [ - { - AttributeName: 'email', - DeliveryMedium: 'EMAIL', - Destination: 'mockedEmail', - }, - { - AttributeName: 'phone_number', - DeliveryMedium: 'SMS', - Destination: 'mockedPhoneNumber', - }, - ], - } as UpdateUserAttributesCommandOutput; - } - ); + it('updateUserAttributes API should return a map with not updated attributes only', async () => { + mockUpdateUserAttributes.mockResolvedValue({ + CodeDeliveryDetailsList: [ + { + AttributeName: 'email', + DeliveryMedium: 'EMAIL', + Destination: 'mockedEmail', + }, + { + AttributeName: 'phone_number', + DeliveryMedium: 'SMS', + Destination: 'mockedPhoneNumber', + }, + ], + }); const userAttributes = { email: 'mockedEmail', phone_number: 'mockedPhoneNumber', @@ -230,36 +202,23 @@ describe('updateUserAttributes API happy path cases', () => { }, }); - expect(updateUserAttributesClientSpy).toHaveBeenCalledWith( + expect(mockUpdateUserAttributes).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, UserAttributes: toAttributeType(userAttributes), ClientMetadata: { foo: 'bar' }, }) ); }); -}); -describe('updateUserAttributes API error path cases:', () => { - test('updateUserAttributes API should raise service error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - UpdateUserAttributesException.InvalidParameterException - ) - ) - ); + mockUpdateUserAttributes.mockImplementation(() => { + throw getMockError( + UpdateUserAttributesException.InvalidParameterException + ); + }); try { await updateUserAttributes({ userAttributes: { @@ -269,7 +228,7 @@ describe('updateUserAttributes API error path cases:', () => { clientMetadata: { foo: 'bar' }, }, }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( UpdateUserAttributesException.InvalidParameterException diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthSignOut.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthSignOut.test.ts index 3df60822a6d..0fde8a1cf9a 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthSignOut.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/completeOAuthSignOut.test.ts @@ -41,10 +41,10 @@ describe('completeOAuthSignOut', () => { it('should complete OAuth sign out', async () => { await completeOAuthSignOut(mockStore); - expect(mockStore.clearOAuthData).toBeCalledTimes(1); - expect(mockTokenOrchestrator.clearTokens).toBeCalledTimes(1); - expect(mockClearCredentials).toBeCalledTimes(1); - expect(mockHub.dispatch).toBeCalledWith( + expect(mockStore.clearOAuthData).toHaveBeenCalledTimes(1); + expect(mockTokenOrchestrator.clearTokens).toHaveBeenCalledTimes(1); + expect(mockClearCredentials).toHaveBeenCalledTimes(1); + expect(mockHub.dispatch).toHaveBeenCalledWith( 'auth', { event: 'signedOut' }, 'Auth', diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts index 95a50618c5d..ec4acbc8130 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.native.test.ts @@ -45,24 +45,33 @@ describe('handleOAuthSignOut (native)', () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'success' }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockOAuthSignOutRedirect).toBeCalledWith(cognitoConfig, false); - expect(mockCompleteOAuthSignOut).toBeCalledWith(mockStore); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( + cognitoConfig, + false + ); + expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); }); it('should not complete OAuth sign out if redirect is canceled', async () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'canceled' }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockOAuthSignOutRedirect).toBeCalledWith(cognitoConfig, false); - expect(mockCompleteOAuthSignOut).not.toBeCalled(); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( + cognitoConfig, + false + ); + expect(mockCompleteOAuthSignOut).not.toHaveBeenCalled(); }); it('should not complete OAuth sign out if redirect failed', async () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'error' }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockOAuthSignOutRedirect).toBeCalledWith(cognitoConfig, false); - expect(mockCompleteOAuthSignOut).not.toBeCalled(); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith( + cognitoConfig, + false + ); + expect(mockCompleteOAuthSignOut).not.toHaveBeenCalled(); }); }); @@ -74,8 +83,8 @@ describe('handleOAuthSignOut (native)', () => { mockOAuthSignOutRedirect.mockResolvedValue({ type: 'error' }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockOAuthSignOutRedirect).toBeCalledWith(cognitoConfig, true); - expect(mockCompleteOAuthSignOut).toBeCalledWith(mockStore); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith(cognitoConfig, true); + expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); }); it('should complete OAuth sign out but not redirect', async () => { @@ -85,7 +94,7 @@ describe('handleOAuthSignOut (native)', () => { }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockOAuthSignOutRedirect).not.toBeCalled(); - expect(mockCompleteOAuthSignOut).toBeCalledWith(mockStore); + expect(mockOAuthSignOutRedirect).not.toHaveBeenCalled(); + expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); }); }); diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts index a938b16245b..cf48e7bbf86 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/handleOAuthSignOut.test.ts @@ -41,8 +41,8 @@ describe('handleOAuthSignOut', () => { }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockCompleteOAuthSignOut).toBeCalledWith(mockStore); - expect(mockOAuthSignOutRedirect).toBeCalledWith(cognitoConfig); + expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); + expect(mockOAuthSignOutRedirect).toHaveBeenCalledWith(cognitoConfig); }); it('should complete OAuth sign out but not redirect', async () => { @@ -52,7 +52,7 @@ describe('handleOAuthSignOut', () => { }); await handleOAuthSignOut(cognitoConfig, mockStore); - expect(mockCompleteOAuthSignOut).toBeCalledWith(mockStore); - expect(mockOAuthSignOutRedirect).not.toBeCalled(); + expect(mockCompleteOAuthSignOut).toHaveBeenCalledWith(mockStore); + expect(mockOAuthSignOutRedirect).not.toHaveBeenCalled(); }); }); diff --git a/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts b/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts index 11cf7efc89f..cc92e7ae79e 100644 --- a/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/oauth/oAuthSignOutRedirect.test.ts @@ -45,10 +45,10 @@ describe('oAuthSignOutRedirect', () => { it('should construct the OAuth logout endpoint and open an auth session to it', async () => { await oAuthSignOutRedirect(authConfig); - expect(mockGetRedirectUrl).toBeCalledWith( + expect(mockGetRedirectUrl).toHaveBeenCalledWith( authConfig.loginWith.oauth.redirectSignOut ); - expect(mockOpenAuthSession).toBeCalledWith( + expect(mockOpenAuthSession).toHaveBeenCalledWith( `https://${domain}/logout?client_id=${userPoolClientId}&logout_uri=${encodedSignOutRedirectUrl}`, authConfig.loginWith.oauth.redirectSignOut, false @@ -58,7 +58,7 @@ describe('oAuthSignOutRedirect', () => { it('should allow preferPrivateSession to be set', async () => { await oAuthSignOutRedirect(authConfig, true); - expect(mockOpenAuthSession).toBeCalledWith( + expect(mockOpenAuthSession).toHaveBeenCalledWith( `https://${domain}/logout?client_id=${userPoolClientId}&logout_uri=${encodedSignOutRedirectUrl}`, authConfig.loginWith.oauth.redirectSignOut, true diff --git a/packages/auth/__tests__/providers/cognito/utils/srp/AuthenticationHelper.test.ts b/packages/auth/__tests__/providers/cognito/utils/srp/AuthenticationHelper.test.ts index f8dd7cb83d3..60d01ef753d 100644 --- a/packages/auth/__tests__/providers/cognito/utils/srp/AuthenticationHelper.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/srp/AuthenticationHelper.test.ts @@ -103,7 +103,7 @@ describe('AuthenticationHelper', () => { it('should instantiate the verifierDevices of the instance', async () => { await instance.generateHashDevice(deviceGroupKey, username); - expect(mockGetHashFromData).toBeCalledWith( + expect(mockGetHashFromData).toHaveBeenCalledWith( `${deviceGroupKey}${username}:${randomString}` ); expect(instance.getVerifierDevices()).toBeDefined(); @@ -161,10 +161,10 @@ describe('AuthenticationHelper', () => { salt, }) ).toBe(hkdfKey); - expect(mockCalculateU).toBeCalledWith({ A, B: serverBValue }); - expect(mockGetPaddedHex).toBeCalledWith(salt); - expect(mockGetHashFromHex).toBeCalledWith(usernamePasswordHash); - expect(mockCalculateS).toBeCalledWith({ + expect(mockCalculateU).toHaveBeenCalledWith({ A, B: serverBValue }); + expect(mockGetPaddedHex).toHaveBeenCalledWith(salt); + expect(mockGetHashFromHex).toHaveBeenCalledWith(usernamePasswordHash); + expect(mockCalculateS).toHaveBeenCalledWith({ a, g, k: expect.any(BigInteger), diff --git a/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateA.test.ts b/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateA.test.ts index bc0123cb73f..3dce88d132e 100644 --- a/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateA.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateA.test.ts @@ -17,7 +17,7 @@ describe('calculateA', () => { it('calculates A', async () => { expect(await calculateA({ a, g, N })).toBeDefined(); - expect(modPowSpy).toBeCalledWith(a, N, expect.any(Function)); + expect(modPowSpy).toHaveBeenCalledWith(a, N, expect.any(Function)); }); it('should throw an error if modPow fails', async () => { diff --git a/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateS.test.ts b/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateS.test.ts index 6aa93ade01a..5fde0d5e868 100644 --- a/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateS.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateS.test.ts @@ -31,7 +31,7 @@ describe('calculateS', () => { U, }) ).toBeDefined(); - expect(modPowSpy).toBeCalledWith(x, N, expect.any(Function)); + expect(modPowSpy).toHaveBeenCalledWith(x, N, expect.any(Function)); }); it('should throw an error if outer modPow fails', async () => { diff --git a/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateU.test.ts b/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateU.test.ts index 296be8f92d0..a052ac35db6 100644 --- a/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateU.test.ts +++ b/packages/auth/__tests__/providers/cognito/utils/srp/calculate/calculateU.test.ts @@ -29,9 +29,9 @@ describe('calculateU', () => { mockGetHashFromHex.mockReturnValue('A+B'); expect(calculateU({ A, B })).toBeDefined(); - expect(mockGetPaddedHex).toBeCalledWith(A); - expect(mockGetPaddedHex).toBeCalledWith(B); - expect(mockGetHashFromHex).toBeCalled(); + expect(mockGetPaddedHex).toHaveBeenCalledWith(A); + expect(mockGetPaddedHex).toHaveBeenCalledWith(B); + expect(mockGetHashFromHex).toHaveBeenCalled(); }); it('should throw an error if U equals BigInteger.ZERO', async () => { diff --git a/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts b/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts index 49bf8b3042c..025d2f63871 100644 --- a/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts +++ b/packages/auth/__tests__/providers/cognito/verifyTOTPSetup.test.ts @@ -1,117 +1,83 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -import { fetchAuthSession } from '@aws-amplify/core'; +import { Amplify, fetchAuthSession } from '@aws-amplify/core'; +import { decodeJWT } from '@aws-amplify/core/internals/utils'; import { AuthError } from '../../../src/errors/AuthError'; import { AuthValidationErrorCode } from '../../../src/errors/types/validation'; import { VerifySoftwareTokenException } from '../../../src/providers/cognito/types/errors'; import { verifyTOTPSetup } from '../../../src/providers/cognito'; -import * as verifySoftwareTokenClient from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; -import { VerifySoftwareTokenCommandOutput } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider/types'; -import { decodeJWT } from '@aws-amplify/core/internals/utils'; -import * as authUtils from '../../../src'; -import { fetchTransferHandler } from '@aws-amplify/core/internals/aws-client-utils'; -import { buildMockErrorResponse, mockJsonResponse } from './testUtils/data'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +import { verifySoftwareToken } from '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider'; +import { getMockError, mockAccessToken } from './testUtils/data'; +import { setUpGetConfig } from './testUtils/setUpGetConfig'; jest.mock('@aws-amplify/core', () => ({ - ...jest.requireActual('@aws-amplify/core'), - fetchAuthSession: jest.fn(), - Amplify: { - configure: jest.fn(), - getConfig: jest.fn(() => ({ - Auth: { - Cognito: { - userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', - userPoolId: 'us-west-2_zzzzz', - identityPoolId: 'us-west-2:xxxxxx', - }, - }, - })), - }, + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { getConfig: jest.fn(() => ({})) }, })); -const mockedAccessToken = - 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c'; -const mockFetchAuthSession = fetchAuthSession as jest.Mock; -describe('verifyTOTPSetup API happy path cases', () => { - let verifySoftwareTokenClientSpy; +jest.mock( + '../../../src/providers/cognito/utils/clients/CognitoIdentityProvider' +); + +describe('verifyTOTPSetup', () => { const code = '123456'; const friendlyDeviceName = 'FriendlyDeviceName'; + // assert mocks + const mockFetchAuthSession = fetchAuthSession as jest.Mock; + const mockVerifySoftwareToken = verifySoftwareToken as jest.Mock; + + beforeAll(() => { + setUpGetConfig(Amplify); + mockFetchAuthSession.mockResolvedValue({ + tokens: { accessToken: decodeJWT(mockAccessToken) }, + }); + }); beforeEach(() => { - mockFetchAuthSession.mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } - ); - verifySoftwareTokenClientSpy = jest - .spyOn(verifySoftwareTokenClient, 'verifySoftwareToken') - .mockImplementationOnce(async () => { - return {} as VerifySoftwareTokenCommandOutput; - }); + mockVerifySoftwareToken.mockResolvedValue({}); }); afterEach(() => { - verifySoftwareTokenClientSpy.mockClear(); + mockVerifySoftwareToken.mockReset(); mockFetchAuthSession.mockClear(); }); - test('verifyTOTPSetup API should return successful response', async () => { + it('should return successful response', async () => { await verifyTOTPSetup({ code, options: { friendlyDeviceName }, }); - expect(verifySoftwareTokenClientSpy).toHaveBeenCalledWith( + expect(mockVerifySoftwareToken).toHaveBeenCalledWith( expect.objectContaining({ region: 'us-west-2' }), expect.objectContaining({ - AccessToken: mockedAccessToken, + AccessToken: mockAccessToken, UserCode: code, FriendlyDeviceName: friendlyDeviceName, }) ); }); -}); -describe('verifyTOTPSetup API error path cases:', () => { - test('verifyTOTPSetup API should throw a validation AuthError when code is empty', async () => { + it('should throw an error when code is empty', async () => { expect.assertions(2); try { await verifyTOTPSetup({ code: '' }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe(AuthValidationErrorCode.EmptyVerifyTOTPSetupCode); } }); - test('verifyTOTPSetup API should raise an error when VerifySoftwareTokenClient throws an error', async () => { + it('should throw an error when service returns an error response', async () => { expect.assertions(2); - (fetchTransferHandler as jest.Mock).mockResolvedValue( - mockJsonResponse( - buildMockErrorResponse( - VerifySoftwareTokenException.InvalidParameterException - ) - ) - ); - jest - .spyOn(authUtils, 'fetchAuthSession') - .mockImplementationOnce( - async (): Promise<{ tokens: { accessToken: any } }> => { - return { - tokens: { - accessToken: decodeJWT(mockedAccessToken), - }, - }; - } + mockVerifySoftwareToken.mockImplementation(() => { + throw getMockError( + VerifySoftwareTokenException.InvalidParameterException ); + }); try { - const code = '123456'; await verifyTOTPSetup({ code }); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AuthError); expect(error.name).toBe( VerifySoftwareTokenException.InvalidParameterException diff --git a/packages/auth/__tests__/utils/getAuthUserAgentValue.test.ts b/packages/auth/__tests__/utils/getAuthUserAgentValue.test.ts index 081e6d917a0..e3a8248a9ed 100644 --- a/packages/auth/__tests__/utils/getAuthUserAgentValue.test.ts +++ b/packages/auth/__tests__/utils/getAuthUserAgentValue.test.ts @@ -21,7 +21,7 @@ describe('getAuthUserAgentValue', () => { const action = AuthAction.FederatedSignIn; getAuthUserAgentValue(action); - expect(mockGetAmplifyUserAgent).toBeCalledWith({ + expect(mockGetAmplifyUserAgent).toHaveBeenCalledWith({ category: Category.Auth, action, }); diff --git a/packages/auth/jest.config.js b/packages/auth/jest.config.js new file mode 100644 index 00000000000..ce6816e489f --- /dev/null +++ b/packages/auth/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 64, + functions: 74, + lines: 83, + statements: 83, + }, + }, +}; diff --git a/packages/auth/package.json b/packages/auth/package.json index 83cadc35941..ea3920e65f8 100644 --- a/packages/auth/package.json +++ b/packages/auth/package.json @@ -91,61 +91,9 @@ "devDependencies": { "@aws-amplify/core": "6.0.5", "@aws-amplify/react-native": "1.0.5", - "@jest/test-sequencer": "^24.9.0", + "@jest/test-sequencer": "^29.7.0", "@rollup/plugin-typescript": "11.1.5", "rollup": "3.29.4", "typescript": "5.0.2" - }, - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "preset": "ts-jest", - "testRegex": [ - "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist", - "lib", - "lib-esm" - ], - "testSequencer": "./testSequencer.js", - "testPathIgnorePatterns": [ - "__tests__/testUtils/*", - "__tests__/providers/cognito/testUtils/*", - "__tests__/hosted-ui" - ], - "setupFilesAfterEnv": [ - "/jest.setup.js" - ], - "clearMocks": true, - "collectCoverage": true } } diff --git a/packages/aws-amplify/__tests__/adapterCore/authProvidersFactories/cognito/createAWSCredentialsAndIdentityIdProvider.test.ts b/packages/aws-amplify/__tests__/adapterCore/authProvidersFactories/cognito/createAWSCredentialsAndIdentityIdProvider.test.ts index 0d3e2570fd3..d9b09a7c511 100644 --- a/packages/aws-amplify/__tests__/adapterCore/authProvidersFactories/cognito/createAWSCredentialsAndIdentityIdProvider.test.ts +++ b/packages/aws-amplify/__tests__/adapterCore/authProvidersFactories/cognito/createAWSCredentialsAndIdentityIdProvider.test.ts @@ -25,9 +25,11 @@ const mockKeyValueStorage: KeyValueStorageInterface = { clear: jest.fn(), }; const mockAuthConfig: AuthConfig = { - identityPoolId: '123', - userPoolId: 'abc', - userPoolWebClientId: 'def', + Cognito: { + identityPoolId: '123', + userPoolId: 'abc', + userPoolClientId: 'def', + }, }; describe('createAWSCredentialsAndIdentityIdProvider', () => { diff --git a/packages/aws-amplify/__tests__/adapterCore/storageFactories/createKeyValueStorageFromCookieStorageAdapter.ts b/packages/aws-amplify/__tests__/adapterCore/storageFactories/createKeyValueStorageFromCookieStorageAdapter.ts index 0e9b7a89d65..55bbedc713b 100644 --- a/packages/aws-amplify/__tests__/adapterCore/storageFactories/createKeyValueStorageFromCookieStorageAdapter.ts +++ b/packages/aws-amplify/__tests__/adapterCore/storageFactories/createKeyValueStorageFromCookieStorageAdapter.ts @@ -30,7 +30,7 @@ describe('keyValueStorage', () => { const testKey = 'testKey'; const testValue = 'testValue'; keyValueStorage.setItem(testKey, testValue); - expect(mockCookiesStorageAdapter.set).toBeCalledWith( + expect(mockCookiesStorageAdapter.set).toHaveBeenCalledWith( testKey, testValue, { @@ -44,7 +44,7 @@ describe('keyValueStorage', () => { const testKey = 'testKey'; const testValue = 'testValue'; keyValueStorage.setItem(testKey, testValue); - expect(mockCookiesStorageAdapter.set).toBeCalledWith( + expect(mockCookiesStorageAdapter.set).toHaveBeenCalledWith( testKey, testValue, { @@ -74,14 +74,14 @@ describe('keyValueStorage', () => { it('should remove item', async () => { const testKey = 'testKey'; keyValueStorage.removeItem(testKey); - expect(mockCookiesStorageAdapter.delete).toBeCalledWith(testKey); + expect(mockCookiesStorageAdapter.delete).toHaveBeenCalledWith(testKey); }); it('should clear', async () => { // TODO(HuiSF): update the test once the implementation is updated. expect(() => { keyValueStorage.clear(); - }).toThrowError('This method has not implemented.'); + }).toThrow('This method has not implemented.'); }); }); }); diff --git a/packages/aws-amplify/__tests__/initSingleton.test.ts b/packages/aws-amplify/__tests__/initSingleton.test.ts index 0ff21e68766..ddc523b8e65 100644 --- a/packages/aws-amplify/__tests__/initSingleton.test.ts +++ b/packages/aws-amplify/__tests__/initSingleton.test.ts @@ -159,13 +159,13 @@ describe('initSingleton (DefaultAmplify)', () => { const libraryOptions = { ssr: true }; Amplify.configure(mockResourceConfig, libraryOptions); - expect(mockCognitoUserPoolsTokenProviderSetAuthConfig).toBeCalledWith( - mockResourceConfig.Auth - ); + expect( + mockCognitoUserPoolsTokenProviderSetAuthConfig + ).toHaveBeenCalledWith(mockResourceConfig.Auth); expect(MockCookieStorage).toHaveBeenCalledWith({ sameSite: 'lax' }); expect( mockCognitoUserPoolsTokenProviderSetKeyValueStorage - ).toBeCalledWith(mockCookieStorageInstance); + ).toHaveBeenCalledWith(mockCookieStorageInstance); expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( mockResourceConfig, { @@ -182,12 +182,12 @@ describe('initSingleton (DefaultAmplify)', () => { const libraryOptions = {}; Amplify.configure(mockResourceConfig, libraryOptions); - expect(mockCognitoUserPoolsTokenProviderSetAuthConfig).toBeCalledWith( - mockResourceConfig.Auth - ); + expect( + mockCognitoUserPoolsTokenProviderSetAuthConfig + ).toHaveBeenCalledWith(mockResourceConfig.Auth); expect( mockCognitoUserPoolsTokenProviderSetKeyValueStorage - ).toBeCalledWith(defaultStorage); + ).toHaveBeenCalledWith(defaultStorage); expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( mockResourceConfig, { @@ -217,11 +217,11 @@ describe('initSingleton (DefaultAmplify)', () => { expect( mockCognitoUserPoolsTokenProviderSetAuthConfig - ).not.toBeCalled(); + ).not.toHaveBeenCalled(); expect(MockCookieStorage).toHaveBeenCalledWith({ sameSite: 'lax' }); expect( mockCognitoUserPoolsTokenProviderSetKeyValueStorage - ).toBeCalledWith(mockCookieStorageInstance); + ).toHaveBeenCalledWith(mockCookieStorageInstance); expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( mockResourceConfig, { @@ -237,10 +237,10 @@ describe('initSingleton (DefaultAmplify)', () => { expect( mockCognitoUserPoolsTokenProviderSetAuthConfig - ).not.toBeCalled(); + ).not.toHaveBeenCalled(); expect( mockCognitoUserPoolsTokenProviderSetKeyValueStorage - ).toBeCalledWith(defaultStorage); + ).toHaveBeenCalledWith(defaultStorage); expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( mockResourceConfig, { @@ -258,11 +258,11 @@ describe('initSingleton (DefaultAmplify)', () => { expect( mockCognitoUserPoolsTokenProviderSetAuthConfig - ).not.toBeCalled(); - expect(MockCookieStorage).not.toBeCalled(); + ).not.toHaveBeenCalled(); + expect(MockCookieStorage).not.toHaveBeenCalled(); expect( mockCognitoUserPoolsTokenProviderSetKeyValueStorage - ).not.toBeCalled(); + ).not.toHaveBeenCalled(); expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( mockResourceConfig, { diff --git a/packages/aws-amplify/jest.config.js b/packages/aws-amplify/jest.config.js new file mode 100644 index 00000000000..9f65be3c87a --- /dev/null +++ b/packages/aws-amplify/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 85, + functions: 44, + lines: 90, + statements: 91, + }, + }, + moduleNameMapper: { + uuid: require.resolve('uuid'), + }, +}; diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json index 096c74d26ba..b1d2a5de93c 100644 --- a/packages/aws-amplify/package.json +++ b/packages/aws-amplify/package.json @@ -489,45 +489,5 @@ "import": "{ uploadData }", "limit": "18.09 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testPathIgnorePatterns": [ - "dual-publish-tmp" - ], - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist", - "dual-publish-tmp" - ] - } + ] } diff --git a/packages/core/__tests__/BackgroundProcessManager.test.ts b/packages/core/__tests__/BackgroundProcessManager.test.ts index 3ebc978b932..8985996c7ab 100644 --- a/packages/core/__tests__/BackgroundProcessManager.test.ts +++ b/packages/core/__tests__/BackgroundProcessManager.test.ts @@ -26,7 +26,7 @@ describe('BackgroundProcessManager', () => { // we want to ensure that close() is called before the promise // completes. manager.add(async () => { - return new Promise(resolve => { + return new Promise(resolve => { setTimeout(() => { proof = true; resolve(); @@ -76,7 +76,7 @@ describe('BackgroundProcessManager', () => { const manager = new BackgroundProcessManager(); const resultPromise = manager.add(async () => { - return new Promise(resolve => { + return new Promise(resolve => { setTimeout(() => { resolve(); }, 50); @@ -193,7 +193,7 @@ describe('BackgroundProcessManager', () => { // manager can register completion. unblock(); - await new Promise(resume => setImmediate(resume)); + await new Promise(process.nextTick); expect(manager.state).toEqual(BackgroundProcessManagerState.Closed); expect(manager.isOpen).toBe(false); @@ -230,7 +230,7 @@ describe('BackgroundProcessManager', () => { const _i = i; results.push(false); manager.add(async () => { - return new Promise(resolve => { + return new Promise(resolve => { setTimeout(() => { results[_i] = true; resolve(); @@ -250,7 +250,7 @@ describe('BackgroundProcessManager', () => { const manager = new BackgroundProcessManager(); const resultPromise = manager.add(async onTerminate => { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const timer = setTimeout(() => { // this is the happy path that we plan not to reach in // this test. @@ -289,7 +289,7 @@ describe('BackgroundProcessManager', () => { const manager = new BackgroundProcessManager(); const resultPromise = manager.add(async onTerminate => { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const timer = setTimeout(() => { // this is the happy path that we plan not to reach in // this test. @@ -339,7 +339,7 @@ describe('BackgroundProcessManager', () => { const _i = i; results.push(false); manager.add(async onTerminate => { - return new Promise((resolve, reject) => { + return new Promise((resolve, reject) => { const timer = setTimeout(() => { results[_i] = true; resolve(); @@ -512,7 +512,7 @@ describe('BackgroundProcessManager', () => { outer.add(inner); inner.add( async () => - new Promise(resolve => + new Promise(resolve => setTimeout(() => { proof = true; resolve(); @@ -534,7 +534,7 @@ describe('BackgroundProcessManager', () => { outer.add(inner); inner.add( async onTerminate => - new Promise(resolve => + new Promise(resolve => onTerminate.then(() => { proof = true; resolve(); diff --git a/packages/core/__tests__/Cache/StorageCache.test.ts b/packages/core/__tests__/Cache/StorageCache.test.ts index e8c502cf454..4826662bbd3 100644 --- a/packages/core/__tests__/Cache/StorageCache.test.ts +++ b/packages/core/__tests__/Cache/StorageCache.test.ts @@ -1,4 +1,4 @@ -import { CacheConfig } from '../../src/Cache/types/Cache'; +import { CacheConfig } from '../../src/Cache/types'; import { defaultConfig } from '../../src/Cache/constants'; import { StorageCache } from '../../src/Cache/StorageCache'; import { getCurrentSizeKey } from '../../src/Cache/utils'; @@ -65,13 +65,13 @@ describe('StorageCache', () => { describe('constructor', () => { it('can be constructed with default configurations', () => { const cache = getStorageCache(); - expect(mockGetLocalStorageWithFallback).toBeCalled(); + expect(mockGetLocalStorageWithFallback).toHaveBeenCalled(); expect(cache.testGetConfig()).toStrictEqual(defaultConfig); }); it('can be constructed with custom configurations', () => { const cache = getStorageCache(config); - expect(mockGetLocalStorageWithFallback).toBeCalled(); + expect(mockGetLocalStorageWithFallback).toHaveBeenCalled(); expect(cache.testGetConfig()).toStrictEqual(config); }); }); diff --git a/packages/core/__tests__/Cache/StorageCacheCommon.test.ts b/packages/core/__tests__/Cache/StorageCacheCommon.test.ts index dd63e141e81..3fd95976c96 100644 --- a/packages/core/__tests__/Cache/StorageCacheCommon.test.ts +++ b/packages/core/__tests__/Cache/StorageCacheCommon.test.ts @@ -1,4 +1,4 @@ -import { CacheConfig } from '../../src/Cache/types/Cache'; +import { CacheConfig } from '../../src/Cache/types'; import { defaultConfig } from '../../src/Cache/constants'; import { StorageCacheCommon } from '../../src/Cache/StorageCacheCommon'; import { KeyValueStorageInterface } from '../../src/types'; @@ -96,7 +96,7 @@ describe('StorageCacheCommon', () => { itemMaxSize: config.capacityInBytes * 2, }); expect(cache.testGetConfig().itemMaxSize).toBe(defaultConfig.itemMaxSize); - expect(loggerSpy.error).toBeCalled(); + expect(loggerSpy.error).toHaveBeenCalled(); }); it('reverts to default defaultPriority if it is set below minimum range', () => { @@ -107,7 +107,7 @@ describe('StorageCacheCommon', () => { expect(cache.testGetConfig().defaultPriority).toBe( defaultConfig.defaultPriority ); - expect(loggerSpy.error).toBeCalled(); + expect(loggerSpy.error).toHaveBeenCalled(); }); it('reverts to default defaultPriority if it is set above maximum range', () => { @@ -118,7 +118,7 @@ describe('StorageCacheCommon', () => { expect(cache.testGetConfig().defaultPriority).toBe( defaultConfig.defaultPriority ); - expect(loggerSpy.error).toBeCalled(); + expect(loggerSpy.error).toHaveBeenCalled(); }); it('reverts to default warningThreshold if it is set below minimum range', () => { @@ -129,7 +129,7 @@ describe('StorageCacheCommon', () => { expect(cache.testGetConfig().warningThreshold).toBe( defaultConfig.warningThreshold ); - expect(loggerSpy.error).toBeCalled(); + expect(loggerSpy.error).toHaveBeenCalled(); }); it('reverts to default warningThreshold if it is set above maximum range', () => { @@ -140,7 +140,7 @@ describe('StorageCacheCommon', () => { expect(cache.testGetConfig().warningThreshold).toBe( defaultConfig.warningThreshold ); - expect(loggerSpy.error).toBeCalled(); + expect(loggerSpy.error).toHaveBeenCalled(); }); it('reverts to default capacityInBytes if it is set larger than 5MB limit', () => { @@ -152,7 +152,7 @@ describe('StorageCacheCommon', () => { expect(cache.testGetConfig().capacityInBytes).toBe( defaultConfig.capacityInBytes ); - expect(loggerSpy.error).toBeCalled(); + expect(loggerSpy.error).toHaveBeenCalled(); }); }); @@ -177,7 +177,7 @@ describe('StorageCacheCommon', () => { const cache = getStorageCache(config); cache.configure(config); - expect(loggerSpy.warn).toBeCalled(); + expect(loggerSpy.warn).toHaveBeenCalled(); }); }); @@ -187,19 +187,22 @@ describe('StorageCacheCommon', () => { it('returns the current cache size', async () => { mockKeyValueStorageGetItem.mockResolvedValue('10'); expect(await cache.getCurrentCacheSize()).toBe(10); - expect(mockKeyValueStorageGetItem).toBeCalledWith(currentSizeKey); + expect(mockKeyValueStorageGetItem).toHaveBeenCalledWith(currentSizeKey); }); it('returns zero if size set to zero', async () => { mockKeyValueStorageGetItem.mockResolvedValue('0'); expect(await cache.getCurrentCacheSize()).toBe(0); - expect(mockKeyValueStorageSetItem).not.toBeCalled(); + expect(mockKeyValueStorageSetItem).not.toHaveBeenCalled(); }); it('returns zero if size it not set', async () => { mockKeyValueStorageGetItem.mockResolvedValue(null); expect(await cache.getCurrentCacheSize()).toBe(0); - expect(mockKeyValueStorageSetItem).toBeCalledWith(currentSizeKey, '0'); + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( + currentSizeKey, + '0' + ); }); }); @@ -221,10 +224,10 @@ describe('StorageCacheCommon', () => { ['boolean', true], ])('sets an item if it does not exist (%s}', async (_, value: any) => { await cache.setItem(key, value); - expect(loggerSpy.debug).toBeCalledWith( + expect(loggerSpy.debug).toHaveBeenCalledWith( expect.stringContaining(`Set item: key is ${key}`) ); - expect(mockKeyValueStorageSetItem).toBeCalledWith( + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( prefixedKey, expect.stringContaining(JSON.stringify(value)) ); @@ -232,42 +235,42 @@ describe('StorageCacheCommon', () => { it('aborts on empty key', async () => { await cache.setItem('', 'abc'); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid key') ); - expect(mockKeyValueStorageSetItem).not.toBeCalled(); + expect(mockKeyValueStorageSetItem).not.toHaveBeenCalled(); }); it('aborts on reserved key', async () => { await cache.setItem('CurSize', 'abc'); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid key') ); - expect(mockKeyValueStorageSetItem).not.toBeCalled(); + expect(mockKeyValueStorageSetItem).not.toHaveBeenCalled(); }); it('aborts on undefined value', async () => { await cache.setItem(key, undefined); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('should not be undefined') ); - expect(mockKeyValueStorageGetItem).not.toBeCalled(); + expect(mockKeyValueStorageGetItem).not.toHaveBeenCalled(); }); it('aborts if priority is below minimum', async () => { await cache.setItem(key, 'abc', { priority: 0 }); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid parameter') ); - expect(mockKeyValueStorageGetItem).not.toBeCalled(); + expect(mockKeyValueStorageGetItem).not.toHaveBeenCalled(); }); it('aborts if priority is above maximum', async () => { await cache.setItem(key, 'abc', { priority: 6 }); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid parameter') ); - expect(mockKeyValueStorageGetItem).not.toBeCalled(); + expect(mockKeyValueStorageGetItem).not.toHaveBeenCalled(); }); it('aborts if item size is above maximum', async () => { @@ -276,10 +279,10 @@ describe('StorageCacheCommon', () => { ); const value = 'x'.repeat(config.itemMaxSize * 2); await cache.setItem(key, value); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('is too big') ); - expect(mockKeyValueStorageGetItem).not.toBeCalled(); + expect(mockKeyValueStorageGetItem).not.toHaveBeenCalled(); }); it('updates existing cache content with the same key', async () => { @@ -294,11 +297,17 @@ describe('StorageCacheCommon', () => { .mockReturnValueOnce(15); // get current cache size (increase) await cache.setItem(key, value); - expect(mockKeyValueStorageGetItem).toBeCalledTimes(5); - expect(mockKeyValueStorageSetItem).toBeCalledWith(currentSizeKey, '15'); // 25 - 10 - expect(mockKeyValueStorageRemoveItem).toBeCalledTimes(1); - expect(mockKeyValueStorageSetItem).toBeCalledWith(currentSizeKey, '35'); // 15 + 20 - expect(mockKeyValueStorageSetItem).toBeCalledWith( + expect(mockKeyValueStorageGetItem).toHaveBeenCalledTimes(5); + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( + currentSizeKey, + '15' + ); // 25 - 10 + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledTimes(1); + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( + currentSizeKey, + '35' + ); // 15 + 20 + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( prefixedKey, JSON.stringify({ key: prefixedKey, @@ -331,8 +340,8 @@ describe('StorageCacheCommon', () => { `${keyPrefix}valid-key`, ]); await cache.setItem(key, value); - expect(mockKeyValueStorageRemoveItem).toBeCalledTimes(1); - expect(mockKeyValueStorageSetItem).toBeCalledWith( + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledTimes(1); + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( prefixedKey, expect.stringContaining(value) ); @@ -381,12 +390,14 @@ describe('StorageCacheCommon', () => { lowPriorityItem.key, ]); await cache.setItem(key, value); - expect(mockKeyValueStorageRemoveItem).toBeCalledTimes(2); - expect(mockKeyValueStorageRemoveItem).toBeCalledWith(lowPriorityItem.key); - expect(mockKeyValueStorageRemoveItem).toBeCalledWith( + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledTimes(2); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledWith( + lowPriorityItem.key + ); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledWith( mediumPriorityItem.key ); - expect(mockKeyValueStorageSetItem).toBeCalledWith( + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( prefixedKey, expect.stringContaining(value) ); @@ -436,12 +447,14 @@ describe('StorageCacheCommon', () => { lastVisitedItem.key, ]); await cache.setItem(key, value); - expect(mockKeyValueStorageRemoveItem).toBeCalledTimes(2); - expect(mockKeyValueStorageRemoveItem).toBeCalledWith(lastVisitedItem.key); - expect(mockKeyValueStorageRemoveItem).toBeCalledWith( + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledTimes(2); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledWith( + lastVisitedItem.key + ); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledWith( recentlyVistedItem.key ); - expect(mockKeyValueStorageSetItem).toBeCalledWith( + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( prefixedKey, expect.stringContaining(value) ); @@ -464,26 +477,26 @@ describe('StorageCacheCommon', () => { ); expect(await cache.getItem(key)).toBe(value); - expect(loggerSpy.debug).toBeCalledWith( + expect(loggerSpy.debug).toHaveBeenCalledWith( expect.stringContaining(`Get item: key is ${key}`) ); - expect(mockKeyValueStorageGetItem).toBeCalledWith(prefixedKey); + expect(mockKeyValueStorageGetItem).toHaveBeenCalledWith(prefixedKey); }); it('aborts on empty key', async () => { expect(await cache.getItem('')).toBeNull(); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid key') ); - expect(mockKeyValueStorageGetItem).not.toBeCalled(); + expect(mockKeyValueStorageGetItem).not.toHaveBeenCalled(); }); it('aborts on reserved key', async () => { expect(await cache.getItem('CurSize')).toBeNull(); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid key') ); - expect(mockKeyValueStorageGetItem).not.toBeCalled(); + expect(mockKeyValueStorageGetItem).not.toHaveBeenCalled(); }); it('clears item if it expires when trying to get it', async () => { @@ -496,7 +509,7 @@ describe('StorageCacheCommon', () => { ); expect(await cache.getItem(key)).toBeNull(); - expect(mockKeyValueStorageRemoveItem).toBeCalledWith(prefixedKey); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledWith(prefixedKey); }); it('returns null if not in cache', async () => { @@ -508,8 +521,8 @@ describe('StorageCacheCommon', () => { mockKeyValueStorageGetItem.mockReturnValue(JSON.stringify(item)); expect(await cache.getItem(key)).toBe(value); - expect(mockKeyValueStorageGetItem).toBeCalledWith(prefixedKey); - expect(mockKeyValueStorageSetItem).toBeCalledWith( + expect(mockKeyValueStorageGetItem).toHaveBeenCalledWith(prefixedKey); + expect(mockKeyValueStorageSetItem).toHaveBeenCalledWith( prefixedKey, JSON.stringify({ ...item, visitedTime: currentTime }) ); @@ -519,8 +532,8 @@ describe('StorageCacheCommon', () => { mockGetByteLength.mockReturnValue(20); const callback = jest.fn(() => value); expect(await cache.getItem(key, { callback })).toBe(value); - expect(callback).toBeCalled(); - expect(mockKeyValueStorageSetItem).toBeCalled(); + expect(callback).toHaveBeenCalled(); + expect(mockKeyValueStorageSetItem).toHaveBeenCalled(); }); }); @@ -537,32 +550,32 @@ describe('StorageCacheCommon', () => { it('removes an item', async () => { await cache.removeItem(key); - expect(loggerSpy.debug).toBeCalledWith( + expect(loggerSpy.debug).toHaveBeenCalledWith( expect.stringContaining(`Remove item: key is ${key}`) ); - expect(mockKeyValueStorageRemoveItem).toBeCalledWith(prefixedKey); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledWith(prefixedKey); }); it('aborts on empty key', async () => { await cache.removeItem(''); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid key') ); - expect(mockKeyValueStorageRemoveItem).not.toBeCalled(); + expect(mockKeyValueStorageRemoveItem).not.toHaveBeenCalled(); }); it('aborts on reserved key', async () => { await cache.removeItem('CurSize'); - expect(loggerSpy.warn).toBeCalledWith( + expect(loggerSpy.warn).toHaveBeenCalledWith( expect.stringContaining('Invalid key') ); - expect(mockKeyValueStorageRemoveItem).not.toBeCalled(); + expect(mockKeyValueStorageRemoveItem).not.toHaveBeenCalled(); }); it('does nothing if item not found', async () => { mockKeyValueStorageGetItem.mockReturnValue(null); await cache.removeItem(key); - expect(mockKeyValueStorageRemoveItem).not.toBeCalled(); + expect(mockKeyValueStorageRemoveItem).not.toHaveBeenCalled(); }); }); @@ -575,8 +588,8 @@ describe('StorageCacheCommon', () => { `${keyPrefix}some-key`, ]); await cache.clear(); - expect(loggerSpy.debug).toBeCalledWith('Clear Cache'); - expect(mockKeyValueStorageRemoveItem).toBeCalledTimes(2); + expect(loggerSpy.debug).toHaveBeenCalledWith('Clear Cache'); + expect(mockKeyValueStorageRemoveItem).toHaveBeenCalledTimes(2); }); }); diff --git a/packages/core/__tests__/ConsoleLogger.test.ts b/packages/core/__tests__/ConsoleLogger.test.ts index 5024ec9b8bf..c52039cbc03 100644 --- a/packages/core/__tests__/ConsoleLogger.test.ts +++ b/packages/core/__tests__/ConsoleLogger.test.ts @@ -1,4 +1,5 @@ import { ConsoleLogger } from '../src'; +import { LoggingProvider } from '../src/Logger/types'; describe('ConsoleLogger', () => { describe('pluggables', () => { @@ -16,7 +17,7 @@ describe('ConsoleLogger', () => { it('should do nothing when no plugin is provided to addPluggable', () => { const logger = new ConsoleLogger('name'); - logger.addPluggable(); + logger.addPluggable(null as any); const pluggables = logger.listPluggables(); expect(pluggables).toHaveLength(0); @@ -33,8 +34,8 @@ describe('ConsoleLogger', () => { configure: function () { return {}; }, - pushLogs: null, - }; + pushLogs: () => {}, + } as LoggingProvider; const logger = new ConsoleLogger('name'); logger.addPluggable(provider); diff --git a/packages/core/__tests__/DateUtils.test.ts b/packages/core/__tests__/DateUtils.test.ts index 8b82c7cf14e..10541d47dad 100644 --- a/packages/core/__tests__/DateUtils.test.ts +++ b/packages/core/__tests__/DateUtils.test.ts @@ -29,9 +29,11 @@ describe('DateUtils', () => { }); describe('getDateWithClockOffset()', () => { - expect(DateUtils.getDateWithClockOffset()).toEqual( - new Date(new Date().getTime() + 1000) - ); + it('should return a new Date()', () => { + expect(DateUtils.getDateWithClockOffset()).toEqual( + new Date(new Date().getTime() + 1000) + ); + }); }); }); diff --git a/packages/core/__tests__/HubClass.test.ts b/packages/core/__tests__/HubClass.test.ts index f52c6e8f583..a227fb832c2 100644 --- a/packages/core/__tests__/HubClass.test.ts +++ b/packages/core/__tests__/HubClass.test.ts @@ -1,4 +1,4 @@ -Symbol = undefined; // this should be undefined before loading Hub +Symbol = undefined as any; // this should be undefined before loading Hub import { Hub } from '../src'; import { ConsoleLogger } from '../src'; diff --git a/packages/core/__tests__/I18n.test.ts b/packages/core/__tests__/I18n.test.ts index a3ff44fd541..49f3ab134b8 100644 --- a/packages/core/__tests__/I18n.test.ts +++ b/packages/core/__tests__/I18n.test.ts @@ -61,11 +61,11 @@ describe('I18n test', () => { }); }); - describe('getByLangurage test', () => { + describe('getByLanguage test', () => { test('happy case', () => { const i18n = new I18n(); - expect(i18n.getByLanguage('key', undefined)).toBeNull(); + expect(i18n.getByLanguage('key', '')).toBeNull(); }); test('has dict', () => { diff --git a/packages/core/__tests__/JS-browser-runtime.test.ts b/packages/core/__tests__/JS-browser-runtime.test.ts index 697e47f931a..7050481bb5c 100644 --- a/packages/core/__tests__/JS-browser-runtime.test.ts +++ b/packages/core/__tests__/JS-browser-runtime.test.ts @@ -1,7 +1,3 @@ -/** - * @jest-environment jsdom - */ - /** The doc block above is to change the running environment of Jest to * jsdom (which is also the default) Since this is allowed per test file * and not per test or describe, we have two tests, one for node and other for browser diff --git a/packages/core/__tests__/Mutex.test.ts b/packages/core/__tests__/Mutex.test.ts index fca3516155d..c595e91cf94 100644 --- a/packages/core/__tests__/Mutex.test.ts +++ b/packages/core/__tests__/Mutex.test.ts @@ -83,7 +83,7 @@ describe('Mutex', function () { mutex.runExclusive( () => - new Promise(resolve => + new Promise(resolve => setTimeout(() => { flag = true; resolve(); diff --git a/packages/core/__tests__/ServiceWorker.test.ts b/packages/core/__tests__/ServiceWorker.test.ts index 4c6d172e297..8ee74b3f60c 100644 --- a/packages/core/__tests__/ServiceWorker.test.ts +++ b/packages/core/__tests__/ServiceWorker.test.ts @@ -28,7 +28,7 @@ describe('ServiceWorker test', () => { try { await serviceWorker.register(); - } catch (e) { + } catch (e: any) { expect(e).toBeInstanceOf(AmplifyError); expect(e.name).toBe(ServiceWorkerErrorCode.Unavailable); } @@ -96,7 +96,9 @@ describe('ServiceWorker test', () => { serviceWorker.send('A message'); - return expect(bla.installing.postMessage).toBeCalledWith('A message'); + return expect(bla.installing.postMessage).toHaveBeenCalledWith( + 'A message' + ); }); test('can send object message after registration', async () => { const bla = { @@ -112,7 +114,7 @@ describe('ServiceWorker test', () => { serviceWorker.send({ property: 'value' }); - return expect(bla.installing.postMessage).toBeCalledWith( + return expect(bla.installing.postMessage).toHaveBeenCalledWith( JSON.stringify({ property: 'value' }) ); }); diff --git a/packages/core/__tests__/Signer.test.ts b/packages/core/__tests__/Signer.test.ts index f8d69f07b80..b5638ea2269 100644 --- a/packages/core/__tests__/Signer.test.ts +++ b/packages/core/__tests__/Signer.test.ts @@ -62,7 +62,7 @@ describe('Signer.sign', () => { }; const signedRequest = Signer.sign( { ...request, url: url.toString() }, - accessInfo, + accessInfo as any, serviceInfo as any ); expect(signedRequest.headers?.Authorization).toBe(expected); @@ -89,7 +89,7 @@ describe('Signer.sign', () => { }; expect(() => { - Signer.sign(request, accessInfo, serviceInfo as any); + Signer.sign(request, accessInfo as any, serviceInfo as any); }).toThrow(); }); @@ -101,7 +101,7 @@ describe('Signer.sign', () => { }; expect(() => { - Signer.sign(request, accessInfo, serviceInfo as any); + Signer.sign(request, accessInfo as any, serviceInfo as any); }).not.toThrow(); }); }); @@ -118,7 +118,7 @@ describe('Signer.sign', () => { }; const { headers: { Authorization }, - } = Signer.sign(request, accessInfo, undefined); + } = Signer.sign(request as any, accessInfo as any, undefined as any); expect(Authorization).toEqual( expect.stringContaining( 'Credential=access-key-id/20200918/us-east-1/foo/aws4_request' diff --git a/packages/core/__tests__/StringUtils.test.ts b/packages/core/__tests__/StringUtils.test.ts index 4d29d9c3fe6..b60ad97a958 100644 --- a/packages/core/__tests__/StringUtils.test.ts +++ b/packages/core/__tests__/StringUtils.test.ts @@ -1,7 +1,7 @@ import { urlSafeEncode, urlSafeDecode } from '../src/utils'; import { TextDecoder, TextEncoder } from 'util'; -global.TextEncoder = TextEncoder; -global.TextDecoder = TextDecoder; +(global as any).TextEncoder = TextEncoder; +(global as any).TextDecoder = TextDecoder; const complexCustomState = 'https://amplify-app:300/?empty=&list=1,a,%,@'; diff --git a/packages/core/__tests__/adapterCore/serverContext.test.ts b/packages/core/__tests__/adapterCore/serverContext.test.ts index 11589d3aa85..b78cb0dd3a6 100644 --- a/packages/core/__tests__/adapterCore/serverContext.test.ts +++ b/packages/core/__tests__/adapterCore/serverContext.test.ts @@ -33,7 +33,7 @@ describe('serverContext', () => { }, }); - expect(mockConfigure).toBeCalledWith(mockAmplifyConfig, { + expect(mockConfigure).toHaveBeenCalledWith(mockAmplifyConfig, { Auth: { tokenProvider: mockTokenProvider, credentialsProvider: mockCredentialAndIdentityProvider, @@ -69,7 +69,7 @@ describe('serverContext', () => { it('should throw an error if the context is not found', () => { expect(() => getAmplifyServerContext({ token: { value: Symbol('test') } }) - ).toThrowError( + ).toThrow( 'Attempted to get the Amplify Server Context that may have been destroyed.' ); }); @@ -86,7 +86,7 @@ describe('serverContext', () => { destroyAmplifyServerContext(contextSpec); - expect(() => getAmplifyServerContext(contextSpec)).toThrowError( + expect(() => getAmplifyServerContext(contextSpec)).toThrow( 'Attempted to get the Amplify Server Context that may have been destroyed.' ); }); diff --git a/packages/core/__tests__/awsClients/cognitoIdentity/getCredentialsForIdentity.test.ts b/packages/core/__tests__/awsClients/cognitoIdentity/getCredentialsForIdentity.test.ts index 51c2a5c2ecb..3c933fb05fc 100644 --- a/packages/core/__tests__/awsClients/cognitoIdentity/getCredentialsForIdentity.test.ts +++ b/packages/core/__tests__/awsClients/cognitoIdentity/getCredentialsForIdentity.test.ts @@ -1,7 +1,3 @@ -/** - * @jest-environment jsdom - */ - import { fetchTransferHandler } from '../../../src/clients/handlers/fetch'; import { getCredentialsForIdentity, @@ -69,7 +65,7 @@ describe('CognitoIdentity - getCredentialsForIdentity', () => { params ); expect(response).toEqual(expectedOutput); - expect(fetchTransferHandler).toBeCalledWith( + expect(fetchTransferHandler).toHaveBeenCalledWith( expectedRequest, expect.anything() ); diff --git a/packages/core/__tests__/awsClients/cognitoIdentity/getId.test.ts b/packages/core/__tests__/awsClients/cognitoIdentity/getId.test.ts index b65ab75af07..a7d9794e9e1 100644 --- a/packages/core/__tests__/awsClients/cognitoIdentity/getId.test.ts +++ b/packages/core/__tests__/awsClients/cognitoIdentity/getId.test.ts @@ -1,7 +1,3 @@ -/** - * @jest-environment jsdom - */ - import { fetchTransferHandler } from '../../../src/clients/handlers/fetch'; import { getId, @@ -63,7 +59,7 @@ describe('CognitoIdentity - getId', () => { ); const response = await getId(cognitoIdentityHandlerOptions, params); expect(response).toEqual(expectedOutput); - expect(fetchTransferHandler).toBeCalledWith( + expect(fetchTransferHandler).toHaveBeenCalledWith( expectedRequest, expect.anything() ); diff --git a/packages/core/__tests__/awsClients/pinpoint/getInAppMessages.test.ts b/packages/core/__tests__/awsClients/pinpoint/getInAppMessages.test.ts index d4044084aaf..c0c2824baef 100644 --- a/packages/core/__tests__/awsClients/pinpoint/getInAppMessages.test.ts +++ b/packages/core/__tests__/awsClients/pinpoint/getInAppMessages.test.ts @@ -62,7 +62,7 @@ describe('Pinpoint - getInAppMessages', () => { ); const response = await getInAppMessages(pinpointHandlerOptions, params); expect(response).toEqual(expectedOutput); - expect(fetchTransferHandler).toBeCalledWith( + expect(fetchTransferHandler).toHaveBeenCalledWith( expectedRequest, expect.anything() ); diff --git a/packages/core/__tests__/awsClients/pinpoint/putEvents.test.ts b/packages/core/__tests__/awsClients/pinpoint/putEvents.test.ts index e50f18c6055..2dabea88145 100644 --- a/packages/core/__tests__/awsClients/pinpoint/putEvents.test.ts +++ b/packages/core/__tests__/awsClients/pinpoint/putEvents.test.ts @@ -61,7 +61,7 @@ describe('Pinpoint - putEvents', () => { ); const response = await putEvents(pinpointHandlerOptions, params); expect(response).toEqual(expectedOutput); - expect(fetchTransferHandler).toBeCalledWith( + expect(fetchTransferHandler).toHaveBeenCalledWith( expectedRequest, expect.anything() ); diff --git a/packages/core/__tests__/awsClients/pinpoint/updateEndpoint.test.ts b/packages/core/__tests__/awsClients/pinpoint/updateEndpoint.test.ts index 05f713d0cca..ece0cdb4ba0 100644 --- a/packages/core/__tests__/awsClients/pinpoint/updateEndpoint.test.ts +++ b/packages/core/__tests__/awsClients/pinpoint/updateEndpoint.test.ts @@ -66,7 +66,7 @@ describe('Pinpoint - updateEndpoint', () => { ); const response = await updateEndpoint(pinpointHandlerOptions, params); expect(response).toEqual(expectedOutput); - expect(fetchTransferHandler).toBeCalledWith( + expect(fetchTransferHandler).toHaveBeenCalledWith( expectedRequest, expect.anything() ); diff --git a/packages/core/__tests__/clients/composeApiHandler.test.ts b/packages/core/__tests__/clients/composeApiHandler.test.ts index e89311e9a4d..1c8ad49be5c 100644 --- a/packages/core/__tests__/clients/composeApiHandler.test.ts +++ b/packages/core/__tests__/clients/composeApiHandler.test.ts @@ -33,8 +33,8 @@ describe(composeServiceApi.name, () => { defaultConfig ); const output = await api({ bar: 'baz', foo: 'foo' }, 'Input'); - expect(mockTransferHandler).toBeCalledTimes(1); - expect(mockTransferHandler).toBeCalledWith( + expect(mockTransferHandler).toHaveBeenCalledTimes(1); + expect(mockTransferHandler).toHaveBeenCalledWith( defaultRequest, expect.objectContaining({ bar: 'baz', @@ -58,8 +58,11 @@ describe(composeServiceApi.name, () => { defaultConfig ); await api(config, 'Input'); - expect(defaultConfig.endpointResolver).toBeCalledTimes(1); - expect(defaultConfig.endpointResolver).toBeCalledWith(config, 'Input'); + expect(defaultConfig.endpointResolver).toHaveBeenCalledTimes(1); + expect(defaultConfig.endpointResolver).toHaveBeenCalledWith( + config, + 'Input' + ); }); test('should call serializer and deserializer', async () => { @@ -79,12 +82,12 @@ describe(composeServiceApi.name, () => { defaultConfig ); const output = await api({ bar: 'baz', foo: 'foo' }, 'Input'); - expect(mockSerializer).toBeCalledTimes(1); - expect(mockSerializer).toBeCalledWith( + expect(mockSerializer).toHaveBeenCalledTimes(1); + expect(mockSerializer).toHaveBeenCalledWith( 'Input', defaultConfig.endpointResolver.mock.results[0].value ); - expect(mockDeserializer).toBeCalledTimes(1); - expect(mockDeserializer).toBeCalledWith(defaultResponse); + expect(mockDeserializer).toHaveBeenCalledTimes(1); + expect(mockDeserializer).toHaveBeenCalledWith(defaultResponse); }); }); diff --git a/packages/core/__tests__/clients/composeTransferHandler.test.ts b/packages/core/__tests__/clients/composeTransferHandler.test.ts index fef390e1a9f..3cc459ebc0f 100644 --- a/packages/core/__tests__/clients/composeTransferHandler.test.ts +++ b/packages/core/__tests__/clients/composeTransferHandler.test.ts @@ -18,7 +18,7 @@ describe(composeTransferHandler.name, () => { const handler = composeTransferHandler(coreHandler, []); const resp = await handler({ url: new URL('https://a.b') }, { foo: 'bar' }); expect(resp).toEqual({ body: 'Response' }); - expect(coreHandler).toBeCalledWith( + expect(coreHandler).toHaveBeenCalledWith( { url: new URL('https://a.b') }, { foo: 'bar' } ); @@ -57,7 +57,7 @@ describe(composeTransferHandler.name, () => { options ); expect(resp).toEqual({ body: 'BA' }); - expect(coreHandler).toBeCalledWith( + expect(coreHandler).toHaveBeenCalledWith( expect.objectContaining({ body: 'AB' }), expect.anything() ); @@ -72,7 +72,7 @@ describe(composeTransferHandler.name, () => { options ); expect(resp2).toEqual({ body: 'BA' }); - expect(coreHandler).toBeCalledWith( + expect(coreHandler).toHaveBeenCalledWith( expect.objectContaining({ body: 'AB' }), expect.anything() ); diff --git a/packages/core/__tests__/clients/fetch.test.ts b/packages/core/__tests__/clients/fetch.test.ts index 82f3fbcbd49..cc33ccb88d0 100644 --- a/packages/core/__tests__/clients/fetch.test.ts +++ b/packages/core/__tests__/clients/fetch.test.ts @@ -34,7 +34,7 @@ describe(fetchTransferHandler.name, () => { it('should support abort signal', async () => { const signal = new AbortController().signal; await fetchTransferHandler(mockRequest, { abortSignal: signal }); - expect(mockFetch).toBeCalledTimes(1); + expect(mockFetch).toHaveBeenCalledTimes(1); expect(mockFetch.mock.calls[0][1]).toEqual( expect.objectContaining({ signal }) ); @@ -43,7 +43,7 @@ describe(fetchTransferHandler.name, () => { it('should configure cache', async () => { const cacheMode = 'no-store'; await fetchTransferHandler(mockRequest, { cache: cacheMode }); - expect(mockFetch).toBeCalledTimes(1); + expect(mockFetch).toHaveBeenCalledTimes(1); expect(mockFetch.mock.calls[0][1]).toEqual( expect.objectContaining({ cache: cacheMode }) ); @@ -53,7 +53,7 @@ describe(fetchTransferHandler.name, () => { await fetchTransferHandler(mockRequest, { withCrossDomainCredentials: true, }); - expect(mockFetch).toBeCalledTimes(1); + expect(mockFetch).toHaveBeenCalledTimes(1); expect(mockFetch.mock.calls[0][1]).toEqual( expect.objectContaining({ credentials: 'include' }) ); @@ -61,7 +61,7 @@ describe(fetchTransferHandler.name, () => { it('should set credentials options to "same-origin" if cross domain credentials is not set', async () => { await fetchTransferHandler(mockRequest, {}); - expect(mockFetch).toBeCalledTimes(1); + expect(mockFetch).toHaveBeenCalledTimes(1); expect(mockFetch.mock.calls[0][1]).toEqual( expect.objectContaining({ credentials: 'same-origin' }) ); @@ -83,7 +83,7 @@ describe(fetchTransferHandler.name, () => { } expect(await body.text()).toBe(mockPayloadValue); expect(await body.text()).toBe(mockPayloadValue); - expect(mockBody.text).toBeCalledTimes(1); // test caching + expect(mockBody.text).toHaveBeenCalledTimes(1); // test caching }); it('should support blob() in response.body with caching', async () => { @@ -94,7 +94,7 @@ describe(fetchTransferHandler.name, () => { } expect(await body.blob()).toBe(mockPayloadValue); expect(await body.blob()).toBe(mockPayloadValue); - expect(mockBody.blob).toBeCalledTimes(1); // test caching + expect(mockBody.blob).toHaveBeenCalledTimes(1); // test caching }); it('should support json() in response.body with caching', async () => { @@ -105,7 +105,7 @@ describe(fetchTransferHandler.name, () => { } expect(await body.json()).toBe(mockPayloadValue); expect(await body.json()).toBe(mockPayloadValue); - expect(mockBody.json).toBeCalledTimes(1); // test caching + expect(mockBody.json).toHaveBeenCalledTimes(1); // test caching }); test.each(['GET', 'HEAD', 'DELETE'])( @@ -115,7 +115,7 @@ describe(fetchTransferHandler.name, () => { { ...mockRequest, method, body: 'Mock Body' }, {} ); - expect(mockFetch).toBeCalledTimes(1); + expect(mockFetch).toHaveBeenCalledTimes(1); expect(mockFetch.mock.calls[0][0].body).toBeUndefined(); } ); diff --git a/packages/core/__tests__/clients/middleware/retry/middleware.test.ts b/packages/core/__tests__/clients/middleware/retry/middleware.test.ts index ac501936861..1c035387ef1 100644 --- a/packages/core/__tests__/clients/middleware/retry/middleware.test.ts +++ b/packages/core/__tests__/clients/middleware/retry/middleware.test.ts @@ -38,7 +38,7 @@ describe(`${retryMiddleware.name} middleware`, () => { ...defaultRetryOptions, maxAttempts: 6, }); - expect(nextHandler).toBeCalledTimes(6); + expect(nextHandler).toHaveBeenCalledTimes(6); expect(resp).toEqual({ ...defaultResponse, $metadata: { attempts: 6 } }); } catch (error) { fail('this test should succeed'); @@ -59,8 +59,8 @@ describe(`${retryMiddleware.name} middleware`, () => { maxAttempts: 6, }); fail('this test should fail'); - } catch (error) { - expect(nextHandler).toBeCalledTimes(6); + } catch (error: any) { + expect(nextHandler).toHaveBeenCalledTimes(6); expect(error.message).toEqual('Error 6'); } }); @@ -76,8 +76,8 @@ describe(`${retryMiddleware.name} middleware`, () => { retryDecider, }); expect.assertions(3); - expect(nextHandler).toBeCalledTimes(1); - expect(retryDecider).toBeCalledTimes(1); + expect(nextHandler).toHaveBeenCalledTimes(1); + expect(retryDecider).toHaveBeenCalledTimes(1); expect(resp).toEqual({ ...defaultResponse, $metadata: { attempts: 1 } }); }); @@ -97,11 +97,11 @@ describe(`${retryMiddleware.name} middleware`, () => { retryDecider, }); fail('this test should fail'); - } catch (e) { + } catch (e: any) { expect(e.message).toBe('UnretryableError'); - expect(nextHandler).toBeCalledTimes(1); - expect(retryDecider).toBeCalledTimes(1); - expect(retryDecider).toBeCalledWith(undefined, expect.any(Error)); + expect(nextHandler).toHaveBeenCalledTimes(1); + expect(retryDecider).toHaveBeenCalledTimes(1); + expect(retryDecider).toHaveBeenCalledWith(undefined, expect.any(Error)); } expect.assertions(4); }); @@ -119,8 +119,8 @@ describe(`${retryMiddleware.name} middleware`, () => { expect(res).toEqual( expect.objectContaining({ $metadata: { attempts: 6 } }) ); - expect(nextHandler).toBeCalledTimes(6); - expect(computeDelay).toBeCalledTimes(5); // no interval after last attempt + expect(nextHandler).toHaveBeenCalledTimes(6); + expect(computeDelay).toHaveBeenCalledTimes(5); // no interval after last attempt } catch (error) { fail('this test should fail'); } @@ -138,9 +138,9 @@ describe(`${retryMiddleware.name} middleware`, () => { abortSignal: controller.signal, }); fail('this test should fail'); - } catch (error) { + } catch (error: any) { expect(error.message).toBe('Request aborted.'); - expect(nextHandler).toBeCalledTimes(0); + expect(nextHandler).toHaveBeenCalledTimes(0); } expect.assertions(2); }); @@ -165,10 +165,10 @@ describe(`${retryMiddleware.name} middleware`, () => { retryDecider, }); fail('this test should fail'); - } catch (error) { + } catch (error: any) { expect(error.message).toBe('Request aborted.'); - expect(setTimeout).toBeCalledTimes(2); // 1st attempt + mock back-off strategy - expect(clearTimeout).toBeCalledTimes(1); // cancel 2nd attempt + expect(setTimeout).toHaveBeenCalledTimes(2); // 1st attempt + mock back-off strategy + expect(clearTimeout).toHaveBeenCalledTimes(1); // cancel 2nd attempt } }); @@ -208,9 +208,9 @@ describe(`${retryMiddleware.name} middleware`, () => { ...defaultResponse, $metadata: { attempts: 3 }, }); - expect(coreHandler).toBeCalledTimes(2); - expect(betweenRetryFunction).toBeCalledTimes(2); - expect(retryDecider).toBeCalledTimes(4); + expect(coreHandler).toHaveBeenCalledTimes(2); + expect(betweenRetryFunction).toHaveBeenCalledTimes(2); + expect(retryDecider).toHaveBeenCalledTimes(4); // computeDelay is called by 2 retry middleware with continuous attempts count. expect(computeDelay).toHaveBeenNthCalledWith(1, 1); expect(computeDelay).toHaveBeenNthCalledWith(2, 2); diff --git a/packages/core/__tests__/clients/middleware/signing/middleware.test.ts b/packages/core/__tests__/clients/middleware/signing/middleware.test.ts index 3e3298991d5..5b47a01bcb2 100644 --- a/packages/core/__tests__/clients/middleware/signing/middleware.test.ts +++ b/packages/core/__tests__/clients/middleware/signing/middleware.test.ts @@ -63,7 +63,7 @@ describe('Signing middleware', () => { const signableHandler = getSignableHandler(nextHandler); const config = { ...defaultSigningOptions }; await signableHandler(defaultRequest, config); - expect(nextHandler).toBeCalledWith( + expect(nextHandler).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: basicTestCase.expectedAuthorization, @@ -79,7 +79,7 @@ describe('Signing middleware', () => { const signableHandler = getSignableHandler(nextHandler); const config = { ...defaultSigningOptions, systemClockOffset }; await signableHandler(defaultRequest, config); - expect(nextHandler).toBeCalledWith( + expect(nextHandler).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: basicTestCase.expectedAuthorization, @@ -101,7 +101,7 @@ describe('Signing middleware', () => { credentials: credentialsProvider, }; await signableHandler(defaultRequest, config); - expect(nextHandler).toBeCalledWith( + expect(nextHandler).toHaveBeenCalledWith( expect.objectContaining({ headers: expect.objectContaining({ authorization: basicTestCase.expectedAuthorization, @@ -109,7 +109,7 @@ describe('Signing middleware', () => { }), expect.anything() ); - expect(credentialsProvider).toBeCalledTimes(1); + expect(credentialsProvider).toHaveBeenCalledTimes(1); }); test.each([ @@ -130,12 +130,15 @@ describe('Signing middleware', () => { ); await middlewareFunction(defaultRequest); - expect(mockGetUpdatedSystemClockOffset).toBeCalledWith(parsedServerTime, 0); + expect(mockGetUpdatedSystemClockOffset).toHaveBeenCalledWith( + parsedServerTime, + 0 + ); jest.clearAllMocks(); await middlewareFunction(defaultRequest); - expect(mockGetSkewCorrectedDate).toBeCalledWith(updatedOffset); - expect(mockGetUpdatedSystemClockOffset).toBeCalledWith( + expect(mockGetSkewCorrectedDate).toHaveBeenCalledWith(updatedOffset); + expect(mockGetUpdatedSystemClockOffset).toHaveBeenCalledWith( parsedServerTime, updatedOffset ); diff --git a/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts b/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts index f324bc7054f..367773b2be0 100644 --- a/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts +++ b/packages/core/__tests__/providers/pinpoint/apis/flushEvents.test.ts @@ -29,7 +29,7 @@ describe('Pinpoint Provider API: flushEvents', () => { it('invokes flushAll on pinpoint buffer', () => { flushEvents({ appId, region, credentials, identityId }); - expect(mockGetEventBuffer).toBeCalledWith({ + expect(mockGetEventBuffer).toHaveBeenCalledWith({ appId, region, credentials, @@ -39,6 +39,6 @@ describe('Pinpoint Provider API: flushEvents', () => { flushSize: FLUSH_SIZE, resendLimit: RESEND_LIMIT, }); - expect(mockFlushAll).toBeCalledTimes(1); + expect(mockFlushAll).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/core/__tests__/providers/pinpoint/apis/record.test.ts b/packages/core/__tests__/providers/pinpoint/apis/record.test.ts index 43929ee1c44..9f466b58e81 100644 --- a/packages/core/__tests__/providers/pinpoint/apis/record.test.ts +++ b/packages/core/__tests__/providers/pinpoint/apis/record.test.ts @@ -60,8 +60,8 @@ describe('Pinpoint Provider API: record', () => { region, }); - expect(mockUpdateEndpoint).not.toBeCalled(); - expect(mockBufferPush).toBeCalledWith( + expect(mockUpdateEndpoint).not.toHaveBeenCalled(); + expect(mockBufferPush).toHaveBeenCalledWith( expect.objectContaining({ endpointId, event, @@ -81,7 +81,7 @@ describe('Pinpoint Provider API: record', () => { region, }); - expect(mockClientPutEvents).not.toBeCalled(); + expect(mockClientPutEvents).not.toHaveBeenCalled(); }); it('reuses an existing session if it exists', async () => { @@ -105,7 +105,7 @@ describe('Pinpoint Provider API: record', () => { region, }); - expect(mockBufferPush).toBeCalledWith( + expect(mockBufferPush).toHaveBeenCalledWith( expect.objectContaining({ endpointId, event, @@ -134,7 +134,7 @@ describe('Pinpoint Provider API: record', () => { region, }); - expect(mockBufferPush).toBeCalledWith( + expect(mockBufferPush).toHaveBeenCalledWith( expect.objectContaining({ endpointId, event: mockStartEvent, diff --git a/packages/core/__tests__/providers/pinpoint/apis/updateEndpoint.test.ts b/packages/core/__tests__/providers/pinpoint/apis/updateEndpoint.test.ts index dcfdaee1154..d9e5d5dc812 100644 --- a/packages/core/__tests__/providers/pinpoint/apis/updateEndpoint.test.ts +++ b/packages/core/__tests__/providers/pinpoint/apis/updateEndpoint.test.ts @@ -62,7 +62,7 @@ describe('Pinpoint Provider API: updateEndpoint', () => { it('calls the service API with a baseline input', async () => { await updateEndpoint({ appId, category, credentials, region }); - expect(mockClientUpdateEndpoint).toBeCalledWith( + expect(mockClientUpdateEndpoint).toHaveBeenCalledWith( { credentials, region }, getExpectedInput({}) ); @@ -99,7 +99,7 @@ describe('Pinpoint Provider API: updateEndpoint', () => { metrics, }, }); - expect(mockClientUpdateEndpoint).toBeCalledWith( + expect(mockClientUpdateEndpoint).toHaveBeenCalledWith( { credentials, region }, getExpectedInput({ address, @@ -132,7 +132,7 @@ describe('Pinpoint Provider API: updateEndpoint', () => { demographic: partialDemographic, }, }); - expect(mockClientUpdateEndpoint).toBeCalledWith( + expect(mockClientUpdateEndpoint).toHaveBeenCalledWith( { credentials, region }, getExpectedInput({ demographic: { @@ -148,11 +148,11 @@ describe('Pinpoint Provider API: updateEndpoint', () => { mockGetEndpointId.mockReturnValue(undefined); mockUuid.mockReturnValueOnce(createdEndpointId); await updateEndpoint({ appId, category, credentials, region }); - expect(mockClientUpdateEndpoint).toBeCalledWith( + expect(mockClientUpdateEndpoint).toHaveBeenCalledWith( { credentials, region }, getExpectedInput({ endpointId: createdEndpointId }) ); - expect(mockCacheEndpointId).toBeCalledWith( + expect(mockCacheEndpointId).toHaveBeenCalledWith( appId, category, createdEndpointId @@ -161,6 +161,6 @@ describe('Pinpoint Provider API: updateEndpoint', () => { it('does not cache endpoint if previously cached', async () => { await updateEndpoint({ appId, category, credentials, region }); - expect(mockCacheEndpointId).not.toBeCalled(); + expect(mockCacheEndpointId).not.toHaveBeenCalled(); }); }); diff --git a/packages/core/__tests__/providers/pinpoint/utils/cacheEndpointId.test.ts b/packages/core/__tests__/providers/pinpoint/utils/cacheEndpointId.test.ts index e4644a7ce80..98ba5c66da4 100644 --- a/packages/core/__tests__/providers/pinpoint/utils/cacheEndpointId.test.ts +++ b/packages/core/__tests__/providers/pinpoint/utils/cacheEndpointId.test.ts @@ -26,8 +26,8 @@ describe('Pinpoint Provider Util: cacheEndpointId', () => { it('writes an endpoint id to cache', async () => { await cacheEndpointId(appId, category, endpointId); - expect(mockGetCacheKey).toBeCalledWith(appId, category); - expect(setItemSpy).toBeCalledWith( + expect(mockGetCacheKey).toHaveBeenCalledWith(appId, category); + expect(setItemSpy).toHaveBeenCalledWith( cacheKey, endpointId, expect.objectContaining({ priority: 1 }) diff --git a/packages/core/__tests__/providers/pinpoint/utils/getEndpointId.test.ts b/packages/core/__tests__/providers/pinpoint/utils/getEndpointId.test.ts index b6f8f9d4874..3443fe8db50 100644 --- a/packages/core/__tests__/providers/pinpoint/utils/getEndpointId.test.ts +++ b/packages/core/__tests__/providers/pinpoint/utils/getEndpointId.test.ts @@ -27,8 +27,8 @@ describe('Pinpoint Provider Util: getEndpointId', () => { it('returns a cached endpoint id', async () => { getItemSpy.mockResolvedValue(endpointId); expect(await getEndpointId(appId, category)).toBe(endpointId); - expect(mockGetCacheKey).toBeCalledWith(appId, category); - expect(getItemSpy).toBeCalledWith(cacheKey); + expect(mockGetCacheKey).toHaveBeenCalledWith(appId, category); + expect(getItemSpy).toHaveBeenCalledWith(cacheKey); }); it('returns undefined if endpoint id not found in cache', async () => { diff --git a/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts b/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts index fe2347a0259..3e2b408c531 100644 --- a/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts +++ b/packages/core/__tests__/providers/pinpoint/utils/getEventBuffer.test.ts @@ -37,7 +37,7 @@ describe('Pinpoint Provider Util: bufferManager', () => { it("creates a buffer if one doesn't exist", async () => { const testBuffer = getEventBuffer(mockConfig); - expect(mockPinpointEventBuffer).toBeCalledWith(mockConfig); + expect(mockPinpointEventBuffer).toHaveBeenCalledWith(mockConfig); expect(testBuffer).toBeInstanceOf(Object); }); diff --git a/packages/core/__tests__/providers/pinpoint/utils/resolveEndpointId.test.ts b/packages/core/__tests__/providers/pinpoint/utils/resolveEndpointId.test.ts index f3614ff986b..e7ee227a247 100644 --- a/packages/core/__tests__/providers/pinpoint/utils/resolveEndpointId.test.ts +++ b/packages/core/__tests__/providers/pinpoint/utils/resolveEndpointId.test.ts @@ -56,7 +56,7 @@ describe('Pinpoint Provider Util: resolveEndpointId', () => { }) ).toBe(endpointId); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ appId, category, credentials, diff --git a/packages/core/__tests__/singleton/Singleton.test.ts b/packages/core/__tests__/singleton/Singleton.test.ts index 7db4f13ada9..7dd8c383b0c 100644 --- a/packages/core/__tests__/singleton/Singleton.test.ts +++ b/packages/core/__tests__/singleton/Singleton.test.ts @@ -312,7 +312,7 @@ describe('Session tests', () => { }); const session = await Amplify.Auth.fetchAuthSession(); - expect(spyTokenProvider).toBeCalled(); + expect(spyTokenProvider).toHaveBeenCalled(); expect(session.tokens?.accessToken.payload).toEqual({ exp: 1710293130, @@ -394,7 +394,7 @@ describe('Session tests', () => { expiration: new Date(123), }); - expect(credentialsSpy).toBeCalledWith({ + expect(credentialsSpy).toHaveBeenCalledWith({ authConfig: { Cognito: { identityPoolId: 'us-east-1:bbbbb', @@ -479,7 +479,7 @@ describe('Session tests', () => { expiration: new Date(123), }); - expect(credentialsSpy).toBeCalledWith({ + expect(credentialsSpy).toHaveBeenCalledWith({ authConfig: { Cognito: { allowGuestAccess: true, @@ -521,7 +521,7 @@ describe('Session tests', () => { ); await auth.fetchAuthSession({ forceRefresh: true }); - expect(tokenProvider).toBeCalledWith({ + expect(tokenProvider).toHaveBeenCalledWith({ forceRefresh: true, }); }); @@ -553,6 +553,6 @@ describe('Session tests', () => { await expect(action()).rejects.toThrow('no no no'); - expect(tokenProvider).toBeCalled(); + expect(tokenProvider).toHaveBeenCalled(); }); }); diff --git a/packages/core/__tests__/storage/CookieStorage.test.ts b/packages/core/__tests__/storage/CookieStorage.test.ts index 479160a1be4..bfa1a363f6c 100644 --- a/packages/core/__tests__/storage/CookieStorage.test.ts +++ b/packages/core/__tests__/storage/CookieStorage.test.ts @@ -1,17 +1,4 @@ import { CookieStorage } from '../../src/storage/CookieStorage'; -/** - * This mock is a workaround before we upgrade the ts-jest config. - * The current ts-jest config uses only the default tsconfig instead of the tsconfig.json in core package. - * The default tsconfig used by ts-jest does not set the `esModuleInterop` to true. This cause - * `import JsCookie from 'js-cookie'` to fail. - */ -jest.mock('js-cookie', () => ({ - default: { - get: jest.requireActual('js-cookie').get, - set: jest.requireActual('js-cookie').set, - remove: jest.requireActual('js-cookie').remove, - }, -})); const cookieStorageDomain = 'https://testdomain.com'; @@ -31,10 +18,10 @@ describe('CookieStorage', () => { 'The sameSite value of cookieStorage must be "lax", "strict" or "none"'; expect(() => { new CookieStorage({ sameSite: undefined }); - }).toThrowError(expectedError); + }).toThrow(expectedError); expect(() => { new CookieStorage({ sameSite: 'foo' as any }); - }).toThrowError(expectedError); + }).toThrow(expectedError); }); it('SameSite value is "none" while secure is false', () => { @@ -44,7 +31,7 @@ describe('CookieStorage', () => { secure: false, sameSite: 'none', }); - }).toThrowError( + }).toThrow( 'sameSite = None requires the Secure attribute in latest browser versions.' ); }); diff --git a/packages/core/__tests__/storage/storage-mechanisms-node-runtime.test.ts b/packages/core/__tests__/storage/storage-mechanisms-node-runtime.test.ts index c895d5fe6b4..0566237962b 100644 --- a/packages/core/__tests__/storage/storage-mechanisms-node-runtime.test.ts +++ b/packages/core/__tests__/storage/storage-mechanisms-node-runtime.test.ts @@ -12,7 +12,7 @@ describe('test mechanisms', () => { test('test defaultStorage operations in node environment', async () => { try { await defaultStorage.setItem(key, value); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AmplifyError); expect(error.name).toBe(AmplifyErrorCode.PlatformNotSupported); } @@ -21,7 +21,7 @@ describe('test mechanisms', () => { test('test sessionStorage operations in node environment', async () => { try { await sessionStorage.setItem(key, value); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(AmplifyError); expect(error.name).toBe(AmplifyErrorCode.PlatformNotSupported); } diff --git a/packages/core/__tests__/utils.test.ts b/packages/core/__tests__/utils.test.ts index 128e5eebbf5..176768ab0b1 100644 --- a/packages/core/__tests__/utils.test.ts +++ b/packages/core/__tests__/utils.test.ts @@ -90,7 +90,7 @@ describe('Util', () => { expect(err).toBe(nonRetryableError); } - expect(testFunc).toBeCalledTimes(1); + expect(testFunc).toHaveBeenCalledTimes(1); }); test('Should throw an Error when NetInfo is not passed to networkMonitor in React Native Reachability', () => { const subscribe = netInfo => { @@ -102,16 +102,16 @@ describe('Util', () => { subscribe({ addEventListener: {} }); } - expect(subscribe).toThrowError( + expect(subscribe).toThrow( 'NetInfo must be passed to networkMonitor to enable reachability in React Native' ); - expect(subscribeWithNetInfo).not.toThrowError(); + expect(subscribeWithNetInfo).not.toThrow(); }); test('Should not throw an Error when NetInfo is not passed to networkMonitor in Web Reachability', () => { const subscribe = () => { new Reachability().networkMonitor(); }; - expect(subscribe).not.toThrowError(); + expect(subscribe).not.toThrow(); }); }); diff --git a/packages/core/__tests__/utils/cryptoSecureRandomInt.test.ts b/packages/core/__tests__/utils/cryptoSecureRandomInt.test.ts index df9141be2ef..a4ed573fb5c 100644 --- a/packages/core/__tests__/utils/cryptoSecureRandomInt.test.ts +++ b/packages/core/__tests__/utils/cryptoSecureRandomInt.test.ts @@ -24,6 +24,6 @@ describe('cryptoSecureRandomInt test', () => { expect(window.crypto).toBeTruthy(); expect(cryptoSecureRandomInt()).toBe(12345); - expect(windowSpy).toBeCalledTimes(4); + expect(windowSpy).toHaveBeenCalledTimes(4); }); }); diff --git a/packages/core/__tests__/utils/globalHelpers/globalHelpers.native.test.ts b/packages/core/__tests__/utils/globalHelpers/globalHelpers.native.test.ts index 5c49126827e..131199c3e84 100644 --- a/packages/core/__tests__/utils/globalHelpers/globalHelpers.native.test.ts +++ b/packages/core/__tests__/utils/globalHelpers/globalHelpers.native.test.ts @@ -1,6 +1,8 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +const mockCrypto = { getRandomValues: jest.fn() }; + import { loadGetRandomValues, loadBase64 } from '@aws-amplify/react-native'; import { getAtob, @@ -8,10 +10,6 @@ import { getCrypto, } from '../../../src/utils/globalHelpers/index.native'; -const mockCrypto = { - getRandomValues: jest.fn(), -}; - jest.mock('react-native'); jest.mock('@aws-amplify/react-native', () => ({ loadGetRandomValues: jest.fn(() => { diff --git a/packages/core/__tests__/utils/sessionListener/SessionListener.native.test.ts b/packages/core/__tests__/utils/sessionListener/SessionListener.native.test.ts index 6ce1b35760b..40c040b878b 100644 --- a/packages/core/__tests__/utils/sessionListener/SessionListener.native.test.ts +++ b/packages/core/__tests__/utils/sessionListener/SessionListener.native.test.ts @@ -38,7 +38,7 @@ describe('[RN] Session Listener', () => { const mockStateListener = jest.fn(); sessionListener.addStateChangeListener(mockStateListener, true); - expect(mockStateListener).toBeCalledWith('ended'); + expect(mockStateListener).toHaveBeenCalledWith('ended'); expect(mockStateListener).toHaveBeenCalledTimes(1); // Simulate the app being already being in the foreground on add @@ -47,7 +47,7 @@ describe('[RN] Session Listener', () => { const mockStateListener2 = jest.fn(); sessionListener.addStateChangeListener(mockStateListener2, true); - expect(mockStateListener2).toBeCalledWith('started'); + expect(mockStateListener2).toHaveBeenCalledWith('started'); expect(mockStateListener2).toHaveBeenCalledTimes(1); }); @@ -58,12 +58,12 @@ describe('[RN] Session Listener', () => { // Simulate the app being in the foreground eventListenerCallback('active'); - expect(mockStateListener).toBeCalledWith('started'); + expect(mockStateListener).toHaveBeenCalledWith('started'); // Simulate the app moving to inactive eventListenerCallback('inactive'); - expect(mockStateListener).toBeCalledWith('ended'); + expect(mockStateListener).toHaveBeenCalledWith('ended'); // Simulate the app moving to background from inactive (shouldn't generate another call) eventListenerCallback('background'); @@ -76,11 +76,11 @@ describe('[RN] Session Listener', () => { // Check that the listener is working eventListenerCallback('active'); - expect(mockStateListener).toBeCalledWith('started'); + expect(mockStateListener).toHaveBeenCalledWith('started'); // Remove the listener and confirm it stops receiving updates sessionListener.removeStateChangeListener(mockStateListener); eventListenerCallback('background'); - expect(mockStateListener).toBeCalledTimes(1); + expect(mockStateListener).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/core/__tests__/utils/sessionListener/SessionListener.test.ts b/packages/core/__tests__/utils/sessionListener/SessionListener.test.ts index 66fd07f6e22..0560141d546 100644 --- a/packages/core/__tests__/utils/sessionListener/SessionListener.test.ts +++ b/packages/core/__tests__/utils/sessionListener/SessionListener.test.ts @@ -31,7 +31,7 @@ describe('[Web] Session Listener', () => { const mockStateListener = jest.fn(); sessionListener.addStateChangeListener(mockStateListener, true); - expect(mockStateListener).toBeCalledWith('started'); + expect(mockStateListener).toHaveBeenCalledWith('started'); expect(mockStateListener).toHaveBeenCalledTimes(1); }); @@ -43,13 +43,13 @@ describe('[Web] Session Listener', () => { jest.spyOn(document, 'visibilityState', 'get').mockReturnValue('hidden'); eventListenerCallback(); - expect(mockStateListener).toBeCalledWith('ended'); + expect(mockStateListener).toHaveBeenCalledWith('ended'); // Simulate a visible table jest.spyOn(document, 'visibilityState', 'get').mockReturnValue('visible'); eventListenerCallback(); - expect(mockStateListener).toBeCalledWith('started'); + expect(mockStateListener).toHaveBeenCalledWith('started'); }); it('Should remove subscribers correctly', () => { @@ -58,11 +58,11 @@ describe('[Web] Session Listener', () => { // Check that the listener is working eventListenerCallback(); - expect(mockStateListener).toBeCalledWith('started'); + expect(mockStateListener).toHaveBeenCalledWith('started'); // Remove the listener and confirm it stops receiving updates sessionListener.removeStateChangeListener(mockStateListener); eventListenerCallback(); - expect(mockStateListener).toBeCalledTimes(1); + expect(mockStateListener).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/core/jest.config.js b/packages/core/jest.config.js new file mode 100644 index 00000000000..858a5ddd5e8 --- /dev/null +++ b/packages/core/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 75, + functions: 72, + lines: 88, + statements: 88, + }, + }, +}; diff --git a/packages/core/package.json b/packages/core/package.json index 20fb3bc5b7f..0c38ce8a8dc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -193,45 +193,5 @@ "./dist/esm/libraryUtils.d.ts" ] } - }, - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": false - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "/testUtils/" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "setupFiles": [ - "./__mocks__/SessionStorage.js", - "./__mocks__/LocalStorage.js" - ], - "testEnvironment": "jsdom", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "testURL": "http://localhost/", - "coveragePathIgnorePatterns": [ - "/node_modules/", - "dist" - ] } } diff --git a/packages/core/src/Cache/StorageCacheCommon.ts b/packages/core/src/Cache/StorageCacheCommon.ts index 860ee87d666..89adff70953 100644 --- a/packages/core/src/Cache/StorageCacheCommon.ts +++ b/packages/core/src/Cache/StorageCacheCommon.ts @@ -544,7 +544,7 @@ export abstract class StorageCacheCommon { * @return The remaining valid keys */ private async clearInvalidAndGetRemainingKeys(): Promise { - const remainingKeys = []; + const remainingKeys: string[] = []; const keys = await this.getAllCacheKeys({ omitSizeKey: true, }); diff --git a/packages/datastore-storage-adapter/__tests__/SQLiteAdapter.test.ts b/packages/datastore-storage-adapter/__tests__/SQLiteAdapter.test.ts index 5daf5775d80..4e9fb67b497 100644 --- a/packages/datastore-storage-adapter/__tests__/SQLiteAdapter.test.ts +++ b/packages/datastore-storage-adapter/__tests__/SQLiteAdapter.test.ts @@ -15,7 +15,7 @@ import { InnerSQLiteDatabase, } from './helpers'; import { SyncEngine } from '@aws-amplify/datastore/dist/esm/sync'; -import { Observable } from 'rxjs'; +import { of } from 'rxjs'; import { pause, addCommonQueryTests, @@ -25,7 +25,7 @@ let innerSQLiteDatabase; jest.mock('@aws-amplify/datastore/src/sync/datastoreConnectivity', () => { return { - status: () => Observable.of(false) as any, + status: () => of(false) as any, unsubscribe: () => {}, socketDisconnected: () => {}, }; diff --git a/packages/datastore-storage-adapter/__tests__/SQLiteCPKDisabled.test.ts b/packages/datastore-storage-adapter/__tests__/SQLiteCPKDisabled.test.ts index 7eaa5c81b46..9391831c2e8 100644 --- a/packages/datastore-storage-adapter/__tests__/SQLiteCPKDisabled.test.ts +++ b/packages/datastore-storage-adapter/__tests__/SQLiteCPKDisabled.test.ts @@ -8,14 +8,13 @@ * * Both files should be removed when CPK support is added. */ -import { Observable } from 'rxjs'; +import { of } from 'rxjs'; import SQLiteAdapter from '../src/SQLiteAdapter/SQLiteAdapter'; import { testSchema, InnerSQLiteDatabase } from './helpers'; -import { initSchema, DataStore } from '@aws-amplify/datastore'; jest.mock('@aws-amplify/datastore/src/sync/datastoreConnectivity', () => { return { - status: () => Observable.of(false) as any, + status: () => of(false) as any, unsubscribe: () => {}, socketDisconnected: () => {}, }; diff --git a/packages/datastore-storage-adapter/__tests__/SQLiteCPKEnabled.test.ts b/packages/datastore-storage-adapter/__tests__/SQLiteCPKEnabled.test.ts index 8ea3f90b84d..1adf0355f36 100644 --- a/packages/datastore-storage-adapter/__tests__/SQLiteCPKEnabled.test.ts +++ b/packages/datastore-storage-adapter/__tests__/SQLiteCPKEnabled.test.ts @@ -8,14 +8,13 @@ * * Both files should be removed when CPK support is added. */ -import { Observable } from 'rxjs'; +import { of } from 'rxjs'; import SQLiteAdapter from '../src/SQLiteAdapter/SQLiteAdapter'; import { testSchema, InnerSQLiteDatabase } from './helpers'; -import { initSchema, DataStore } from '@aws-amplify/datastore'; jest.mock('@aws-amplify/datastore/src/sync/datastoreConnectivity', () => { return { - status: () => Observable.of(false) as any, + status: () => of(false) as any, unsubscribe: () => {}, socketDisconnected: () => {}, }; diff --git a/packages/datastore-storage-adapter/jest.config.js b/packages/datastore-storage-adapter/jest.config.js new file mode 100644 index 00000000000..cd3e90fab78 --- /dev/null +++ b/packages/datastore-storage-adapter/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 82, + functions: 97, + lines: 88, + statements: 88, + }, + }, +}; diff --git a/packages/datastore-storage-adapter/jest.setup.js b/packages/datastore-storage-adapter/jest.setup.js deleted file mode 100644 index a0f3d5370fa..00000000000 --- a/packages/datastore-storage-adapter/jest.setup.js +++ /dev/null @@ -1,7 +0,0 @@ -const crypto = require('crypto'); - -Object.defineProperty(globalThis, 'crypto', { - value: { - getRandomValues: arr => crypto.randomBytes(arr.length), - }, -}); diff --git a/packages/datastore-storage-adapter/package.json b/packages/datastore-storage-adapter/package.json index 4a51f4d77d9..50f6678e2e6 100644 --- a/packages/datastore-storage-adapter/package.json +++ b/packages/datastore-storage-adapter/package.json @@ -46,58 +46,5 @@ "rollup": "3.29.4", "sqlite3": "^5.0.2", "typescript": "5.0.2" - }, - "jest": { - "globals": { - "ts-jest": { - "diagnostics": true, - "tsConfig": { - "lib": [ - "es5", - "es2015", - "dom", - "esnext.asynciterable", - "es2019" - ], - "allowJs": true, - "esModuleInterop": true, - "downlevelIteration": true - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "__tests__/model.ts", - "__tests__/schema.ts", - "__tests__/helpers.ts" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "dist", - "../datastore" - ], - "setupFilesAfterEnv": [ - "/jest.setup.js" - ] } } diff --git a/packages/datastore-storage-adapter/src/common/SQLiteUtils.ts b/packages/datastore-storage-adapter/src/common/SQLiteUtils.ts index 17d883791bb..e1434c767c3 100644 --- a/packages/datastore-storage-adapter/src/common/SQLiteUtils.ts +++ b/packages/datastore-storage-adapter/src/common/SQLiteUtils.ts @@ -412,7 +412,7 @@ export function orderByClauseFromSort( ): string { const orderByParts = sortPredicate.map( ({ field, sortDirection }) => - `"${field}" ${sortDirectionMap[sortDirection]}` + `"${String(field)}" ${sortDirectionMap[sortDirection]}` ); // We always sort by _rowid_ last diff --git a/packages/datastore-storage-adapter/tsconfig.json b/packages/datastore-storage-adapter/tsconfig.json index de8a2d6ebd7..b21bccd02ed 100755 --- a/packages/datastore-storage-adapter/tsconfig.json +++ b/packages/datastore-storage-adapter/tsconfig.json @@ -12,7 +12,8 @@ "es2017.object", "es2018.asynciterable", "es2018.asyncgenerator", - "es2020.promise" + "es2020.promise", + "es2019" ], "sourceMap": true, "moduleResolution": "node", diff --git a/packages/datastore/__tests__/AsyncStorage.ts b/packages/datastore/__tests__/AsyncStorage.test.ts similarity index 100% rename from packages/datastore/__tests__/AsyncStorage.ts rename to packages/datastore/__tests__/AsyncStorage.test.ts diff --git a/packages/datastore/__tests__/DataStore.ts b/packages/datastore/__tests__/DataStore/DataStore.test.ts similarity index 55% rename from packages/datastore/__tests__/DataStore.ts rename to packages/datastore/__tests__/DataStore/DataStore.test.ts index e90ae98bb9d..b56b1c2f404 100644 --- a/packages/datastore/__tests__/DataStore.ts +++ b/packages/datastore/__tests__/DataStore/DataStore.test.ts @@ -1,1988 +1,50 @@ import 'fake-indexeddb/auto'; import { decodeTime } from 'ulid'; -import uuidValidate from 'uuid-validate'; -import { Observable, from, of } from 'rxjs'; +import { from, of } from 'rxjs'; import { DataStore as DataStoreType, initSchema as initSchemaType, - DataStoreClass, -} from '../src/datastore/datastore'; -import { Predicates } from '../src/predicates'; -import { ExclusiveStorage as StorageType } from '../src/storage/storage'; +} from '../../src/datastore/datastore'; +import { Predicates } from '../../src/predicates'; +import { ExclusiveStorage as StorageType } from '../../src/storage/storage'; import { NonModelTypeConstructor, PersistentModel, PersistentModelConstructor, - ModelInit, - SortDirection, -} from '../src/types'; +} from '../../src/types'; import { - Comment, Metadata, Model, BasicModelRequiredTS, getDataStore, - logDate, - expectIsolation, - configureSync, - unconfigureSync, - pretendModelsAreSynced, - warpTime, - unwarpTime, - pause, - Post, PostCustomPK as PostCustomPKType, - Profile, testSchema, - User, - ModelWithBoolean, -} from './helpers'; +} from '../helpers'; -type T = ModelInit; - -let initSchema: typeof initSchemaType; - -let { DataStore } = getDataStore() as { - DataStore: typeof DataStoreType; -}; -const nameOf = (name: keyof T) => name; - -/** - * Does nothing intentionally, we care only about type checking - */ -const expectType: (param: T) => void = () => {}; - -/** - * Renders more complete out of band traces. - */ -process.on('unhandledRejection', reason => { - console.log(reason); // log the reason including the stack trace -}); - -describe('DataStore sanity testing checks', () => { - beforeEach(async () => { - jest.resetAllMocks(); - jest.resetModules(); - }); - - afterEach(async () => { - await DataStore.clear(); - await unconfigureSync(DataStore); - }); - - test('getDataStore() returns fully fresh instances of DataStore and models', async () => { - /** - * Simulating connect/disconnect and/or `isNode` required the `getDataStore()` - * to reset modules. Hence, the returned DataStore instances should be different. - */ - - const { DataStore: DataStoreA, Post: PostA } = getDataStore(); - const { DataStore: DataStoreB, Post: PostB } = getDataStore(); - - expect(DataStoreA).not.toBe(DataStoreB); - expect(PostA).not.toBe(PostB); - - await DataStoreA.clear(); - await DataStoreB.clear(); - }); - - // HAS_MANY does not contain a FK. no constraint to validate. - test('maintains integrity when attempting to save BELONGS_TO FK at non-existent record', async () => { - const { DataStore: datastore, Post, Comment } = getDataStore(); - DataStore = datastore; - - await expect( - DataStore.save( - new Comment({ - content: 'newly created comment', - post: new Post({ - title: 'newly created post', - }), - }) - ) - ).rejects.toThrow( - `Data integrity error. You tried to save a Comment` // instructions specific to the instance follow - ); - }); - - describe('cleans up after itself', () => { - /** - * basically, if we spin up our test contexts repeatedly, put some - * data in there and do some things, stopping DataStore should - * sufficiently stop backgrounds jobs, clear data, etc. so that - * subsequent instantiations are not affected and no rogue, async - * errors show up out of nowhere (running queries against connections - * or other resources that no longer exist or are not ready.) - * - * aside from `await stop()`, we're going to be pretty careless with - * this test loop (e.g., skipping some awaits) to ensure DataStore - * *really* cleans up after itself. - */ - - /** - * PAY ATTENTION! - * - * 1. These tests run at 20x speed using `timeWarp()` to keep running - * times reasonable. If this becomes suspect, add a flag to allow - * conditional time warping. - * - * 2. If these tests start failing, run them individually, and then - * pick pairs, triads, etc. of tests to run together to find the - * smallest possible set of tests that fail together. - * - * Then, enable "focused logging." - * - * ``` - * await expectIsolation( - * async () => {...}, - * undefined, - * true // <-- this enables "focused logging" - * ); - * ``` - * - * This will start logging messages with timestamps around tests and - * each *cycle* generated by `expectIsolation`. And, It will filter out - * some less helpful messages generated by the auth package. - * - * While this is enabled, you can add console.(warn|error|debug) calls - * to your tests, and they'll be printed with timestamp prefixes to - * help sort out what's happening *when*. - * - */ - - test('sanity check for expectedIsolation helper', async () => { - // make sure expectIsolation is properly awaiting between executions. - // Logging is used to provide visual confirmation that the utility is - // working as expected. We create the same test *N* times. - - // Ths test was originally red-green tested by removing the `await` - // before the `script(...)` call in `expectIsolation`. - - const numberOfCycles = 5; - - let lastCycle = 0; - await expectIsolation(async ({ cycle }) => { - await new Promise(unsleep => - setTimeout(() => { - lastCycle = cycle; - unsleep(); - }, 20 * cycle) - ); - }, numberOfCycles); - - expect(lastCycle).toBe(numberOfCycles); - }); - - describe('during lifecycle events', () => { - let { DataStore, Post } = getDataStore(); - - beforeAll(async () => { - await DataStore.clear(); - }); - - afterEach(async () => { - await DataStore.clear(); - }); - - describe('simple cases', () => { - for (const online of [true, false]) { - for (const isNode of [true, false]) { - const connectedState = online ? 'online' : 'offline'; - const environment = isNode ? 'node' : 'browser'; - - test(`clearing after awaited start (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - await DataStore.start(); - await DataStore.clear(); - await DataStore.start(); - }); - - test(`clearing after unawaited start (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - DataStore.start(); - await DataStore.clear(); - await DataStore.start(); - }); - - test(`clearing after unawaited start, then a small pause (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - DataStore.start(); - await pause(1); - await DataStore.clear(); - await DataStore.start(); - }); - - test(`stopping after awaited start (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - await DataStore.start(); - await DataStore.stop(); - await DataStore.start(); - }); - - test(`stopping after unawaited start (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - DataStore.start(); - await DataStore.stop(); - await DataStore.start(); - }); - - test(`stopping after unawaited start, then a small pause (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - DataStore.start(); - await pause(1); - await DataStore.stop(); - await DataStore.start(); - }); - - // tslint:disable-next-line: max-line-length - test(`starting after unawaited clear results in a DX-friendly error (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - await DataStore.start(); - const clearing = DataStore.clear(); - - // At minimum: looking for top-level error, operation that failed, state while in failure. - expect(DataStore.start()).rejects.toThrow( - /DataStoreStateError:.+`DataStore\.start\(\)`.+Clearing/ - ); - - await clearing; - }); - - // tslint:disable-next-line: max-line-length - test(`starting after unawaited stop results in a DX-friendly error (${connectedState}, ${environment})`, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - await DataStore.start(); - const stopping = DataStore.stop(); - - // At minimum: looking for top-level error, operation that failed, state while in failure. - expect(DataStore.start()).rejects.toThrow( - /DataStoreStateError:.+`DataStore\.start\(\)`.+Stopping/ - ); - - await stopping; - }); - } - } - }); - - /** - * When fuzzing discovers issues, recreate them here to prevent regressions. - */ - describe('edges discovered by fuzz', () => { - /** - * As explained below, DataStore can't actually handle the fuzz yet. :( - */ - }); - - /** - * We're not fuzzable yet ... also, these fuzz tests may need to accumulate - * assertions along the way as well, because some of the behavior will - * likely change from "everything is happy, DataStore figures it out" to - * predictable error cases. - */ - describe.skip('fuzz', () => { - function fuzz() { - const steps = [] as any[]; - - // increase when we can actually deal with the fuzz. - const stepsToProduce = 3; // + Math.random() * 10; - for (let i = 0; i < stepsToProduce; i++) { - let awaited = true; - if (Math.random() > 0.5) { - awaited = false; - } - const methods = ['start', 'stop', 'clear', 'query', 'save']; - const action = { - method: methods.sort(() => Math.random() - 0.5)[0], - awaited, - }; - steps.push(action); - } - return steps; - } - - // increase when we can actually deal efficiently with the fuzz - for (let i = 0; i < 3; i++) { - const steps = fuzz(); - const name = steps - .map(s => `${s.awaited ? 'awaited' : 'unawaited'} ${s.method}`) - .join(', '); - - for (const online of [true, false]) { - for (const isNode of [true, false]) { - const connectedState = online ? 'online' : 'offline'; - const environment = isNode ? 'node' : 'browser'; - const testName = `${name} (${connectedState}, ${environment})`; - - test(testName, async () => { - ({ DataStore, Post } = getDataStore({ online, isNode })); - for (const step of steps) { - const f = { - start: () => DataStore.start(), - stop: () => DataStore.stop(), - clear: () => DataStore.clear(), - save: () => DataStore.save(new Post({ title: testName })), - query: () => DataStore.query(Post), - }[step.method]; - - if (step.awaited) { - await f(); - } else { - f(); - } - - // no explicit assertions for now. at this point, we just - // want things NOT to blow up. :) - } - }); - } - } - } - }); - }); - - test('awaited save', async () => { - await expectIsolation( - async ({ DataStore, Post }) => - await DataStore.save(new Post({ title: 'some title' })) - ); - }); - - test('un-awaited saves', async () => { - await expectIsolation(async ({ DataStore, Post }) => { - DataStore.save(new Post({ title: 'some title' })); - }); - }); - - test('queries against locked DataStore are rejected', async () => { - const { DataStore, Post } = getDataStore(); - - // shedule a promise that will NOT be done for "awhile" - let unblock; - - (DataStore as any).runningProcesses.add( - async () => new Promise(_unblock => (unblock = _unblock)), - 'artificial query blocker' - ); - - // begin clearing, which should lock DataStore - const clearing = DataStore.clear(); - - // pass control back to handlers briefly, so that `clear()` - // activities can start occurring. - await new Promise(unsleep => setTimeout(unsleep, 1)); - - // and now attempt an ill-fated operation - await expect(DataStore.query(Post)) - // looking top-level error name, operation that failed, state DS was in - .rejects.toThrow(/DataStoreStateError.+DataStore\.query\(\).+Clearing/i) - .finally(async () => { - unblock(); - await clearing; - }); - }); - - test('saves against locked DataStore are rejected', async () => { - const { DataStore, Post } = getDataStore(); - - // shedule a promise that will NOT be done for "awhile" - let unblock; - (DataStore as any).runningProcesses.add( - async () => new Promise(_unblock => (unblock = _unblock)), - 'artificial save blocker' - ); - - // begin clearing, which should lock DataStore - const clearing = DataStore.clear(); - - // pass control back to handlers briefly, so that `clear()` - // activities can start occurring. - await new Promise(unsleep => setTimeout(unsleep, 1)); - - // and now attempt an ill-fated operation - await expect( - DataStore.save(new Post({ title: 'title that should fail' })) - ) - // looking top-level error name, operation that failed, state DS was in - .rejects.toThrow(/DataStoreStateError.+DataStore\.save\(\).+Clearing/i) - .finally(async () => { - unblock(); - await clearing; - }); - }); - - test('deletes against locked DataStore are rejected', async () => { - const { DataStore, Post } = getDataStore(); - - // shedule a promise that will NOT be done for "awhile" - let unblock; - (DataStore as any).runningProcesses.add( - async () => new Promise(_unblock => (unblock = _unblock)), - 'artificial delete blocker' - ); - - // begin clearing, which should lock DataStore - const clearing = DataStore.clear(); - - // pass control back to handlers briefly, so that `clear()` - // activities can start occurring. - await new Promise(unsleep => setTimeout(unsleep, 1)); - - // and now attempt an ill-fated operation - await expect(DataStore.delete(Post, Predicates.ALL)) - // looking top-level error name, operation that failed, state DS was in - .rejects.toThrow(/DataStoreStateError.+DataStore\.delete\(\).+Clearing/) - .finally(async () => { - unblock(); - await clearing; - }); - }); - - test('observes against locked DataStore are rejected', async () => { - const { DataStore, Post } = getDataStore(); - - // shedule a promise that will NOT be done for "awhile" - let unblock; - (DataStore as any).runningProcesses.add( - async () => new Promise(_unblock => (unblock = _unblock)), - 'artificial observe blocker' - ); - - // begin clearing, which should lock DataStore - const clearing = DataStore.clear(); - - // pass control back to handlers briefly, so that `clear()` - // activities can start occurring. - await new Promise(unsleep => setTimeout(unsleep, 1)); - - // and now attempt an ill-fated operation - DataStore.observe(Post).subscribe({ - next() { - expect(true).toBe(false); - }, - error(error) { - expect(error.message).toContain('DataStoreStateError'); - expect(error.message).toContain('DataStore.observe()'); - expect(error.message).toContain('Clearing'); - unblock(); - }, - }); - - await clearing; - }); - - test('observeQueries against locked DataStore are rejected', async () => { - const { DataStore, Post } = getDataStore(); - - // shedule a promise that will NOT be done for "awhile" - let unblock; - (DataStore as any).runningProcesses.add( - async () => new Promise(_unblock => (unblock = _unblock)), - 'artificial observeQuery blocker' - ); - - // begin clearing, which should lock DataStore - const clearing = DataStore.clear(); - - // pass control back to handlers briefly, so that `clear()` - // activities can start occurring. - await new Promise(unsleep => setTimeout(unsleep, 1)); - - // and now attempt an ill-fated operation - DataStore.observeQuery(Post).subscribe({ - next() { - expect(true).toBe(false); - }, - error(error) { - expect(error.message).toContain('DataStoreStateError'); - expect(error.message).toContain('DataStore.observeQuery()'); - expect(error.message).toContain('Clearing'); - unblock(); - }, - }); - - await clearing; - }); - - test('data stays in its lane for save then query with good awaits', async () => { - // in other words, a well-formed (awaited) save from one instance - // does not infect another. - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await DataStore.save(new Post({ title: `title from ${cycle}` })); - const post = await DataStore.query(Post); - expect(post.length).toEqual(1); - expect(post[0].title).toEqual(`title from ${cycle}`); - }); - }); - - test('data stays in its lane for save, query, delete all, then query with good awaits', async () => { - // in other words, a well-formed (awaited) save from one instance - // does not infect another. - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await DataStore.save(new Post({ title: `title from ${cycle}` })); - const posts = await DataStore.query(Post); - expect(posts.length).toEqual(1); - expect(posts[0].title).toEqual(`title from ${cycle}`); - - await DataStore.delete(Post, Predicates.ALL); - const afterDelete = await DataStore.query(Post); - expect(afterDelete.length).toEqual(0); - }); - }); - - test('data stays in its lane for basic queries with late un-awaited saves', async () => { - // in other words, a save from one instance does not infect another. - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await DataStore.save(new Post({ title: `title from ${cycle}` })); - const post = await DataStore.query(Post); - - expect(post.length).toEqual(1); - expect(post[0].title).toEqual(`title from ${cycle}`); - - // try to pollute the next test - DataStore.save(new Post({ title: `title from ${cycle}` })); - }); - }); - - test('polite observe() is cleaned up', async () => { - await expectIsolation(async ({ DataStore, Post, cycle }) => { - return new Promise(resolve => { - const sub = DataStore.observe(Post).subscribe( - ({ element, opType, model }) => { - expect(opType).toEqual('INSERT'); - expect(element.title).toEqual( - `a title from polite cycle ${cycle}` - ); - sub.unsubscribe(); - resolve(); - } - ); - DataStore.save( - new Post({ title: `a title from polite cycle ${cycle}` }) - ); - }); - }); - }); - - test('impolite observe() is cleaned up', async () => { - await expectIsolation(async ({ DataStore, Post, cycle }) => { - return new Promise(resolve => { - const sub = DataStore.observe(Post).subscribe( - ({ element, opType, model }) => { - expect(opType).toEqual('INSERT'); - expect(element.title).toEqual( - `a title from impolite cycle ${cycle}` - ); - // omitted: - // sub.unsubscribe(); - // (that's what makes it impolite) - resolve(); - } - ); - DataStore.save( - new Post({ title: `a title from impolite cycle ${cycle}` }) - ); - }); - }); - }); - - test('polite observeQuery() is cleaned up', async () => { - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await pretendModelsAreSynced(DataStore); - await DataStore.save( - new Post({ title: `a title from polite cycle ${cycle} post 1` }) - ); - - const sanityCheck = await DataStore.query(Post); - expect(sanityCheck.length).toEqual(1); - expect(sanityCheck[0].title).toEqual( - `a title from polite cycle ${cycle} post 1` - ); - - return new Promise(async resolve => { - let first = true; - const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { - if (first) { - first = false; - expect(items.length).toEqual(1); - expect(items[0].title).toEqual( - `a title from polite cycle ${cycle} post 1` - ); - DataStore.save( - new Post({ title: `a title from polite cycle ${cycle} post 2` }) - ); - } else { - expect(items.length).toEqual(2); - expect(items.map(p => p.title)).toEqual([ - `a title from polite cycle ${cycle} post 1`, - `a title from polite cycle ${cycle} post 2`, - ]); - sub.unsubscribe(); - resolve(); - } - }); - }); - }); - }); - - test('polite observeQuery() with unsynced models is cleaned up', async () => { - await expectIsolation(async ({ DataStore, Post, cycle }) => { - console.debug(`before configureSync cycle ${cycle}`); - await configureSync(DataStore); - console.debug(`after configureSync cycle ${cycle}`); - return new Promise(async doneTesting => { - let first = true; - const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { - console.debug(`message received in cycle ${cycle}`, items); - if (first) { - first = false; - expect(items.length).toEqual(0); - DataStore.save( - new Post({ - title: `a title from polite unsynced cycle ${cycle} post 1`, - }) - ); - } else { - expect(items.length).toEqual(1); - expect(items[0].title).toEqual( - `a title from polite unsynced cycle ${cycle} post 1` - ); - sub.unsubscribe(); - doneTesting(); - } - }); - }); - }); - }); - - test('less polite observeQuery() is cleaned up', async () => { - // i.e., do not unsubscribe in the last step fo the observeQuery - // event handler. - - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await pretendModelsAreSynced(DataStore); - - await DataStore.save( - new Post({ title: `a title from impolite cycle ${cycle} post 1` }) - ); - const sanityCheck = await DataStore.query(Post); - expect(sanityCheck.length).toEqual(1); - expect(sanityCheck[0].title).toEqual( - `a title from impolite cycle ${cycle} post 1` - ); - - await new Promise(doneTesting => { - let first = true; - const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { - if (first) { - first = false; - expect(items.length).toEqual(1); - expect(items[0].title).toEqual( - `a title from impolite cycle ${cycle} post 1` - ); - DataStore.save( - new Post({ - title: `a title from impolite cycle ${cycle} post 2`, - }) - ); - } else { - expect(items.length).toEqual(2); - expect(items.map(p => p.title)).toEqual([ - `a title from impolite cycle ${cycle} post 1`, - `a title from impolite cycle ${cycle} post 2`, - ]); - - // missing unsubscribe is what makes it "less polite" - doneTesting(); - } - }); - }); - }); - }); - - test.skip('impolite observeQuery() is cleaned up', async () => { - // TODO: observeQuery example that prematurely returns and leaves - // lingering saves in the pipeline ... not 100% sure if that - // cleanup is even in-scope for DataStore to clean up. - }); - - test('sync is cleaned up', async () => { - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await configureSync(DataStore); - - // save an item to kickstart outbox processing. - await DataStore.save( - new Post({ title: `post from "sync is cleaned" up cycle ${cycle}` }) - ); - }); - }); - - test('rude synchronized observe-save is cleaned up', async () => { - await expectIsolation(async ({ DataStore, Post, cycle }) => { - await configureSync(DataStore); - - DataStore.observe(Post).subscribe(() => {}); - - // save an item to kickstart outbox processing. - DataStore.save( - new Post({ - title: `post from "rude synchronized observe-save" up cycle ${cycle}`, - }) - ); - }); - }); - - // - // TODO: once we have a clean way to fake a not-node environment, we - // need an isolation test to prove DataStore shuts **subscription** - // connections/ops down against mocked AppSync backend. - // - }); -}); - -describe('DataStore observe, unmocked, with fake-indexeddb', () => { - let Comment: PersistentModelConstructor; - let Model: PersistentModelConstructor; - let Post: PersistentModelConstructor; - - beforeEach(async () => { - ({ initSchema, DataStore } = require('../src/datastore/datastore')); - const classes = initSchema(testSchema()); - ({ Comment, Model, Post } = classes as { - Comment: PersistentModelConstructor; - Model: PersistentModelConstructor; - Post: PersistentModelConstructor; - }); - warpTime(); - }); - - afterEach(async () => { - await DataStore.clear(); - await unconfigureSync(DataStore); - unwarpTime(); - }); - - test('clear without starting', async () => { - await DataStore.save( - new Model({ - field1: 'Smurfs', - optionalField1: 'More Smurfs', - dateCreated: new Date().toISOString(), - }) - ); - expect(await DataStore.query(Model)).toHaveLength(1); - await DataStore.stop(); - await DataStore.clear(); - expect(await DataStore.query(Model)).toHaveLength(0); - }); - - test('subscribe to all models', async done => { - try { - const sub = DataStore.observe().subscribe( - ({ element, opType, model }) => { - expectType>(model); - expectType(element); - expect(opType).toEqual('INSERT'); - expect(element.field1).toEqual('Smurfs'); - expect(element.optionalField1).toEqual('More Smurfs'); - sub.unsubscribe(); - done(); - } - ); - DataStore.save( - new Model({ - field1: 'Smurfs', - optionalField1: 'More Smurfs', - dateCreated: new Date().toISOString(), - }) - ); - } catch (error) { - done(error); - } - }); - - test('subscribe to model instance', async done => { - try { - const original = await DataStore.save( - new Model({ - field1: 'somevalue', - optionalField1: 'This one should be returned', - dateCreated: new Date().toISOString(), - }) - ); - - const sub = DataStore.observe(original).subscribe( - ({ element, opType, model }) => { - expectType>(model); - expectType(element); - expect(opType).toEqual('UPDATE'); - expect(element.id).toEqual(original.id); - expect(element.field1).toEqual('new field 1 value'); - // We expect all fields, including ones that haven't been updated, to be returned: - expect(element.optionalField1).toEqual('This one should be returned'); - sub.unsubscribe(); - done(); - } - ); - - // decoy - await DataStore.save( - new Model({ - field1: "this one shouldn't get through", - dateCreated: new Date().toISOString(), - }) - ); - - await DataStore.save( - Model.copyOf(original, m => (m.field1 = 'new field 1 value')) - ); - } catch (error) { - done(error); - } - }); - - test('subscribe to Model', async done => { - try { - const original = await DataStore.save( - new Model({ - field1: 'somevalue', - optionalField1: 'additional value', - dateCreated: new Date().toISOString(), - }) - ); - - const sub = DataStore.observe(Model).subscribe( - ({ element, opType, model }) => { - expectType>(model); - expectType(element); - expect(opType).toEqual('UPDATE'); - expect(element.id).toEqual(original.id); - expect(element.field1).toEqual('new field 1 value'); - expect(element.optionalField1).toEqual('additional value'); - sub.unsubscribe(); - done(); - } - ); - - // decoy - await DataStore.save( - new Post({ - title: "This one's a decoy! (kzazulhk)", - }) - ); - - await DataStore.save( - Model.copyOf(original, m => (m.field1 = 'new field 1 value')) - ); - } catch (error) { - done(error); - } - }); - - test('subscribe with criteria', async done => { - const original = await DataStore.save( - new Model({ - field1: 'somevalue', - dateCreated: new Date().toISOString(), - }) - ); - - const sub = DataStore.observe(Model, m => - m.field1.contains('new field 1') - ).subscribe(({ element, opType, model }) => { - expectType>(model); - expectType(element); - expect(opType).toEqual('UPDATE'); - expect(element.id).toEqual(original.id); - expect(element.field1).toEqual('new field 1 value'); - sub.unsubscribe(); - done(); - }); - - // decoy - await DataStore.save( - new Model({ - field1: "This one's a decoy! (sfqpjzja)", - dateCreated: new Date().toISOString(), - }) - ); - - await DataStore.save( - Model.copyOf(original, m => (m.field1 = 'new field 1 value')) - ); - }); - - test('subscribe with criteria on deletes', async done => { - const original = await DataStore.save( - new Model({ - field1: 'somevalue', - dateCreated: new Date().toISOString(), - }) - ); - - const sub = DataStore.observe(Model, m => - m.field1.contains('value') - ).subscribe(({ element, opType, model }) => { - expectType>(model); - expectType(element); - expect(opType).toEqual('DELETE'); - expect(element.id).toEqual(original.id); - expect(element.field1).toEqual('somevalue'); - sub.unsubscribe(); - done(); - }); - - // decoy - await DataStore.save( - new Model({ - field1: "This one's a decoy! (xgxbubyd)", - dateCreated: new Date().toISOString(), - }) - ); - - await DataStore.delete(original); - }); - - test('subscribe with belongsTo criteria', async done => { - const targetPost = await DataStore.save( - new Post({ - title: 'this is my post. hooray!', - }) - ); - - const nonTargetPost = await DataStore.save( - new Post({ - title: 'this is NOT my post. boo!', - }) - ); - - const sub = DataStore.observe(Comment, comment => - comment.post.title.eq(targetPost.title) - ).subscribe(({ element: comment, opType, model }) => { - expect(comment.content).toEqual('good comment'); - sub.unsubscribe(); - done(); - }); - - await DataStore.save( - new Comment({ - content: 'bad comment', - post: nonTargetPost, - }) - ); - - await DataStore.save( - new Comment({ - content: 'good comment', - post: targetPost, - }) - ); - }); - - test('subscribe with hasMany criteria', async done => { - // want to set up a few posts and a few "non-target" comments - // to ensure we can observe post based on a single comment that's - // somewhat "buried" alongside other comments. - - const targetPost = await DataStore.save( - new Post({ - title: 'this is my post. hooray!', - }) - ); - - const nonTargetPost = await DataStore.save( - new Post({ - title: 'this is NOT my post. boo!', - }) - ); - - await DataStore.save( - new Comment({ content: 'bad comment', post: nonTargetPost }) - ); - await DataStore.save( - new Comment({ content: 'pre good comment', post: targetPost }) - ); - - const targetComment = await DataStore.save( - new Comment({ - content: 'good comment', - post: targetPost, - }) - ); - - await DataStore.save( - new Comment({ content: 'post good comment', post: targetPost }) - ); - - const sub = DataStore.observe(Post, post => - post.comments.content.eq(targetComment.content) - ).subscribe(async ({ element: post, opType, model }) => { - expect(post.title).toEqual('expected update'); - sub.unsubscribe(); - done(); - }); - - // should not see this one come through the subscription. - await DataStore.save( - Post.copyOf(nonTargetPost, p => (p.title = 'decoy update')) - ); - - // this is the update we expect to see come through, as it has - // 'good comment' in its `comments` field. - await DataStore.save( - Post.copyOf(targetPost, p => (p.title = 'expected update')) - ); - }); -}); - -describe('DataStore observeQuery, with fake-indexeddb and fake sync', () => { - // - // ~~~~ OH HEY! ~~~~~ - // - // Remember that `observeQuery()` always issues a first snapshot from the data - // already in storage. This is naturally performed async. Because of this, - // if you insert items immediately after `observeQuery()`, some of those items - // MAY show up in the initial snapshot. (Or maybe they won't!) - // - // Many of these tests should therefore include timeouts when adding records. - // These timeouts let `observeQuery()` sneak in and grab its first snapshot - // before those records hit storage, making for predictable tests. - // - // The tests should also account for that initial, empty snapshot. - // - // Remember: Snapshots are cumulative. - // - // And Also: Be careful when saving decoy records! Calling `done()` in a - // subscription body while any `DataStore.save()`'s are outstanding WILL - // result in cryptic errors that surface in subsequent tests! - // - // ("Error: An operation was called on an object on which it is not allowed ...") - // - // ~~~~ OK. Thanks! ~~~~ - // - // (That's it) - // - - let Comment: PersistentModelConstructor; - let Post: PersistentModelConstructor; - let User: PersistentModelConstructor; - let Profile: PersistentModelConstructor; - - /** - * Saves and item and waits until the item surfaces through `observe()` - * before returning the saved item. Creates a new subscription specific - * to the item being saved, which helps ensure all other observers receive - * the item before this function returns. - * - * @param item The model instance to save - * @returns The saved instance, returned from `DataStore.save()` - */ - const fullSave = async item => { - return new Promise(async returnSaved => { - const monitor = DataStore.observe().subscribe( - ({ element, opType, model }) => { - if (JSON.stringify(element) === JSON.stringify(savedItem)) { - monitor.unsubscribe(); - returnSaved(savedItem); - } - } - ); - const savedItem = await DataStore.save(item); - }); - }; - - beforeEach(async () => { - jest.clearAllMocks(); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); - const classes = initSchema(testSchema()); - ({ Comment, Post, User, Profile } = classes as { - Comment: PersistentModelConstructor; - Post: PersistentModelConstructor; - User: PersistentModelConstructor; - Profile: PersistentModelConstructor; - }); - - jest.useFakeTimers(); - await configureSync(DataStore); - }); - - afterEach(async () => { - await DataStore.clear(); - await unconfigureSync(DataStore); - jest.useRealTimers(); - }); - - test('publishes preexisting local data immediately', async done => { - try { - for (let i = 0; i < 5; i++) { - await DataStore.save( - new Post({ - title: `the post ${i}`, - }) - ); - } - - const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { - expect(items.length).toBe(5); - for (let i = 0; i < 5; i++) { - expect(items[i].title).toEqual(`the post ${i}`); - } - sub.unsubscribe(); - done(); - }); - } catch (error) { - done(error); - } - }); - - test('publishes data saved after first snapshot', async done => { - try { - const expecteds = [0, 5]; - - const sub = DataStore.observeQuery(Post).subscribe( - ({ items, isSynced }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].title).toEqual(`the post ${i}`); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - } - ); - - for (let i = 0; i < 5; i++) { - await fullSave( - new Post({ - title: `the post ${i}`, - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - test('can filter items', async done => { - try { - const expecteds = [0, 5]; - - const sub = DataStore.observeQuery(Post, p => - p.title.contains('include') - ).subscribe(({ items }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (const item of items) { - expect(item.title).toMatch('include'); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - }); - - for (let i = 0; i < 10; i++) { - await fullSave( - new Post({ - title: `the post ${i} - ${Boolean(i % 2) ? 'include' : 'omit'}`, - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - // Fix for: https://github.com/aws-amplify/amplify-js/issues/9325 - test('can remove newly-unmatched items out of the snapshot on subsequent saves', async done => { - try { - // watch for post snapshots. - // the first "real" snapshot should include all five posts with "include" - // in the title. after the update to change ONE of those posts to "omit" instead, - // we should see a snapshot of 4 posts with the updated post removed. - const expecteds = [0, 4, 3]; - - const sub = DataStore.observeQuery(Post, p => - p.title.contains('include') - ).subscribe(async ({ items }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (const item of items) { - expect(item.title).toMatch('include'); - } - - if (expecteds.length === 1) { - // After the second snapshot arrives, changes a single post from - // "the post # - include" - // to - // "edited post - omit" - - // This is intended to trigger a new, after-sync'd snapshot. - // This sanity-checks helps confirms we're testing what we think - // we're testing: - expect( - ((DataStore as any).sync as any).getModelSyncedStatus({}) - ).toBe(true); - - await pause(100); - - const itemToEdit = ( - await DataStore.query(Post, p => p.title.contains('include')) - ).pop()!; - await fullSave( - Post.copyOf(itemToEdit, draft => { - draft.title = 'second edited post - omit'; - }) - ); - - jest.advanceTimersByTime(2000); - } else if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - }); - - // Creates posts like: - // - // "the post 0 - include" - // "the post 1 - omit" - // "the post 2 - include" - // "the post 3 - omit" - // - // etc. - // - // ... so that we can expect to see each other one filtered out. - for (let i = 0; i < 10; i++) { - await fullSave( - new Post({ - title: `the post ${i} - ${Boolean(i % 2) ? 'include' : 'omit'}`, - }) - ); - } - - // Changes a single post from - // "the post # - include" - // to - // "edited post - omit" - // - // to add an UPDATE to the first snapshot that we should expect to - // see filtered out. - ((DataStore as any).sync as any).getModelSyncedStatus = (model: any) => - true; - - const itemToEdit = ( - await DataStore.query(Post, p => p.title.contains('include')) - ).pop()!; - - await fullSave( - Post.copyOf(itemToEdit, draft => { - draft.title = 'first edited post - omit'; - }) - ); - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - test('publishes preexisting local data AND follows up with subsequent saves', async done => { - try { - const expecteds = [5, 15]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new Post({ - title: `the post ${i}`, - }) - ); - } - - const sub = DataStore.observeQuery(Post).subscribe( - ({ items, isSynced }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].title).toEqual(`the post ${i}`); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - } - ); - - for (let i = 5; i < 15; i++) { - await fullSave( - new Post({ - title: `the post ${i}`, - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - test('removes deleted items from the snapshot', async done => { - try { - const expecteds = [5, 4]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new Post({ - title: `the post ${i}`, - }) - ); - } - - const sub = DataStore.observeQuery(Post).subscribe( - async ({ items, isSynced }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].title).toContain(`the post`); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } else { - const itemToDelete = (await DataStore.query(Post)).pop()!; - await DataStore.delete(itemToDelete); - jest.advanceTimersByTime(2000); - } - } - ); - } catch (error) { - done(error); - } - }); - - test('removes deleted items from the snapshot with a predicate', done => { - (async () => { - try { - const expecteds = [5, 4]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new Post({ - title: `the post ${i}`, - }) - ); - } - - const sub = DataStore.observeQuery(Post, p => - p.title.beginsWith('the post') - ).subscribe(({ items, isSynced }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].title).toContain(`the post`); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - }); - - const itemToDelete = (await DataStore.query(Post)).pop()!; - await DataStore.delete(itemToDelete); - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - })(); - }); - - test('attaches related belongsTo properties consistently with query() on INSERT', async done => { - try { - const expecteds = [5, 15]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new Comment({ - content: `comment content ${i}`, - post: await DataStore.save( - new Post({ - title: `new post ${i}`, - }) - ), - }) - ); - } - - const sub = DataStore.observeQuery(Comment).subscribe( - async ({ items, isSynced }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].content).toEqual(`comment content ${i}`); - expect((await items[i].post).title).toEqual(`new post ${i}`); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - } - ); - - for (let i = 5; i < 15; i++) { - await fullSave( - new Comment({ - content: `comment content ${i}`, - post: await DataStore.save( - new Post({ - title: `new post ${i}`, - }) - ), - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - test('attaches related hasOne properties consistently with query() on INSERT', async done => { - try { - const expecteds = [5, 15]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new User({ - name: `user ${i}`, - profile: await DataStore.save( - new Profile({ - firstName: `firstName ${i}`, - lastName: `lastName ${i}`, - }) - ), - }) - ); - } - - const sub = DataStore.observeQuery(User).subscribe( - async ({ items, isSynced }) => { - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].name).toEqual(`user ${i}`); - expect((await items[i].profile)!.firstName).toEqual( - `firstName ${i}` - ); - expect((await items[i].profile)!.lastName).toEqual(`lastName ${i}`); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - } - ); - - for (let i = 5; i < 15; i++) { - await fullSave( - new User({ - name: `user ${i}`, - profile: await DataStore.save( - new Profile({ - firstName: `firstName ${i}`, - lastName: `lastName ${i}`, - }) - ), - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - test('attaches related belongsTo properties consistently with query() on UPDATE', async done => { - try { - const expecteds = [ - ['old post 0', 'old post 1', 'old post 2', 'old post 3', 'old post 4'], - ['new post 0', 'new post 1', 'new post 2', 'new post 3', 'new post 4'], - ]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new Comment({ - content: `comment content ${i}`, - post: await DataStore.save( - new Post({ - title: `old post ${i}`, - }) - ), - }) - ); - } - - const sub = DataStore.observeQuery(Comment).subscribe( - async ({ items, isSynced }) => { - const expected = expecteds.shift() || []; - expect(items.length).toBe(expected.length); - - for (let i = 0; i < expected.length; i++) { - expect(items[i].content).toContain(`comment content ${i}`); - expect((await items[i].post).title).toEqual(expected[i]); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - } - ); - - let postIndex = 0; - const comments = await DataStore.query(Comment); - for (const comment of comments) { - const newPost = await DataStore.save( - new Post({ - title: `new post ${postIndex++}`, - }) - ); - - await fullSave( - Comment.copyOf(comment, draft => { - draft.content = `updated: ${comment.content}`; - draft.post = newPost; - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); - - test('attaches related hasOne properties consistently with query() on UPDATE', async done => { - try { - const expecteds = [ - [ - 'first name 0', - 'first name 1', - 'first name 2', - 'first name 3', - 'first name 4', - ], - [ - 'new first name 0', - 'new first name 1', - 'new first name 2', - 'new first name 3', - 'new first name 4', - ], - ]; - - for (let i = 0; i < 5; i++) { - await DataStore.save( - new User({ - name: `user ${i}`, - profile: await DataStore.save( - new Profile({ - firstName: `first name ${i}`, - lastName: `last name ${i}`, - }) - ), - }) - ); - } - - const sub = DataStore.observeQuery(User).subscribe( - async ({ items, isSynced }) => { - const expected = expecteds.shift() || []; - expect(items.length).toBe(expected.length); - - for (let i = 0; i < expected.length; i++) { - expect(items[i].name).toContain(`user ${i}`); - expect((await items[i].profile)!.firstName).toEqual(expected[i]); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - } - ); - - let userIndex = 0; - const users = await DataStore.query(User); - for (const user of users) { - const newProfile = await DataStore.save( - new Profile({ - firstName: `new first name ${userIndex++}`, - lastName: `new last name ${userIndex}`, - }) - ); - - await fullSave( - User.copyOf(user, draft => { - draft.name = `updated: ${user.name}`; - draft.profile = newProfile; - }) - ); - } - - jest.advanceTimersByTime(2000); - } catch (error) { - done(error); - } - }); -}); - -describe('Model behavior', () => { - beforeEach(() => { - warpTime(); - }); - - afterEach(() => { - unwarpTime(); - }); - - test('newly instantiated models do not lazy load belongsTo', async () => { - const { DataStore, DefaultPKChild, DefaultPKParent } = getDataStore(); - - const parent = await DataStore.save( - new DefaultPKParent({ - content: 'this is a decoy!', - }) - ); - - const comment = await DataStore.save( - new DefaultPKChild({ - id: "not such a random id, but it's ok", - content: 'here is some content', - parent, - }) - ); - - const detachedComment = new DefaultPKChild({ - id: "not such a random id, but it's ok", - content: 'here is some content', - defaultPKParentChildrenId: parent.id, - }); - - expect(detachedComment.defaultPKParentChildrenId).toEqual( - comment.defaultPKParentChildrenId - ); - expect(await detachedComment.parent).toBeUndefined(); - - await DataStore.clear(); - }); - - test('newly instantiated models do not lazy load hasMany', async () => { - const { DataStore, DefaultPKChild, DefaultPKParent } = getDataStore(); - - const parent = await DataStore.save( - new DefaultPKParent({ - content: 'this is a decoy!', - }) - ); - - const comment = await DataStore.save( - new DefaultPKChild({ - id: "not such a random id, but it's ok", - content: 'here is some content', - parent, - }) - ); - - const detachedParent = new DefaultPKParent({ - id: parent.id, - content: parent.content, - }); - - expect(detachedParent.id).toEqual(parent.id); - - expect(await detachedParent.children.toArray()).toEqual([]); - - await DataStore.clear(); - }); - - test('newly instantiated models do not lazy load hasOne', async () => { - const { DataStore, HasOneChild, HasOneParent } = getDataStore(); - - const child = await DataStore.save(new HasOneChild({})); - const parent = await DataStore.save( - new HasOneParent({ - child, - }) - ); - - const disconnectedParent = new HasOneParent({ - id: parent.id, - hasOneParentChildId: child.id, - }); - - expect(disconnectedParent.id).toEqual(parent.id); - expect(disconnectedParent.hasOneParentChildId).toEqual(child.id); - expect(await disconnectedParent.child).toBeUndefined(); - - await DataStore.clear(); - }); - - [null, undefined].forEach(value => { - test(`model field can be set to ${value} to remove connection hasOne parent`, async () => { - const { DataStore, HasOneChild, HasOneParent } = getDataStore(); - - const child = await DataStore.save( - new HasOneChild({ content: 'child content' }) - ); - const parent = await DataStore.save( - new HasOneParent({ - child, - }) - ); - - const parentWithoutChild = HasOneParent.copyOf(parent, draft => { - draft.child = value; - }); - - expect(parentWithoutChild.hasOneParentChildId).toBeNull(); - expect( - (await DataStore.save(parentWithoutChild)).hasOneParentChildId - ).toBeNull(); - expect( - (await DataStore.query(HasOneParent, parent.id))!.hasOneParentChildId - ).toBeNull(); - - await DataStore.clear(); - }); - - test(`model field can be set to ${value} to remove connection on child hasMany`, async () => { - const { DataStore, CompositePKParent, CompositePKChild } = getDataStore(); - - const parent = await DataStore.save( - new CompositePKParent({ - customId: 'customId', - content: 'content', - }) - ); - - const child = await DataStore.save( - new CompositePKChild({ childId: 'childId', content: 'content', parent }) - ); - - const childWithoutParent = CompositePKChild.copyOf(child, draft => { - draft.parent = value; - }); - - expect(await childWithoutParent.parent).toBeUndefined(); - expect( - await DataStore.save(childWithoutParent).then(c => c.parent) - ).toBeUndefined(); - expect( - await DataStore.query(CompositePKChild, { - childId: child.childId, - content: child.content, - }).then(c => c!.parent) - ).toBeUndefined(); - expect( - await DataStore.query(CompositePKParent, { - customId: parent.customId, - content: parent.content, - }).then(c => c!.children.toArray()) - ).toEqual([]); - - await DataStore.clear(); - }); - }); - - test('removes no-longer-matching items from the snapshot when using an eq() predicate on boolean field', done => { - (async () => { - const { DataStore, ModelWithBoolean } = getDataStore(); - try { - // the number of records we expect in each snapshot - const expecteds = [5, 4]; - - // initial data set, 5 records that will match our predicate. - for (let i = 0; i < 5; i++) { - await DataStore.save( - new ModelWithBoolean({ - boolField: true, - }) - ); - } - - const sub = DataStore.observeQuery(ModelWithBoolean, m => - m.boolField.eq(true) - ).subscribe(async ({ items, isSynced }) => { - // we don't actually expect 0 records in our snapshots after our list runs out. - // we just want to make TS happy. - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].boolField).toEqual(true); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - await DataStore.clear(); - done(); - } - }); - - // update an item to no longer match our criteria. - // we want to see a snapshot come through WITHOUT this item. - const itemToUpdate = (await DataStore.query(ModelWithBoolean)).pop()!; - await DataStore.save( - ModelWithBoolean.copyOf(itemToUpdate, m => { - m.boolField = false; - }) - ); - - // advance time to trigger another snapshot. - await pause(2000); - await DataStore.clear(); - } catch (error) { - await DataStore.clear(); - - done(error); - } - })(); - }); - - test('removes no-longer-matching items from the snapshot when using an ne() predicate on boolean field', done => { - (async () => { - const { DataStore, ModelWithBoolean } = getDataStore(); - try { - // the number of records we expect in each snapshot - const expecteds = [5, 4]; - - // initial data set, 5 records that will match our predicate. - for (let i = 0; i < 5; i++) { - await DataStore.save( - new ModelWithBoolean({ - boolField: true, - }) - ); - } - - const sub = DataStore.observeQuery(ModelWithBoolean, m => - m.boolField.ne(false) - ).subscribe(({ items, isSynced }) => { - // we don't actually expect 0 records in our snapshots after our list runs out. - // we just want to make TS happy. - const expected = expecteds.shift() || 0; - expect(items.length).toBe(expected); - - for (let i = 0; i < expected; i++) { - expect(items[i].boolField).toEqual(true); - } - - if (expecteds.length === 0) { - sub.unsubscribe(); - done(); - } - }); - - // update an item to no longer match our criteria. - // we want to see a snapshot come through WITHOUT this item. - const itemToUpdate = (await DataStore.query(ModelWithBoolean)).pop()!; - await DataStore.save( - ModelWithBoolean.copyOf(itemToUpdate, m => { - m.boolField = false; - }) - ); - - // advance time to trigger another snapshot. - await pause(2000); - await DataStore.clear(); - } catch (error) { - await DataStore.clear(); - - done(error); - } - })(); - }); - - // ref: https://github.com/aws-amplify/amplify-js/issues/11101 - test('returns fresh snapshot when sorting by descending', async done => { - const { DataStore, Post } = getDataStore(); - - const expectedTitles = ['create', 'update', 'update2']; - - const newPost = await DataStore.save( - new Post({ - title: 'create', - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), - }) - ); - - const sub = DataStore.observeQuery(Post, Predicates.ALL, { - sort: s => s.updatedAt(SortDirection.DESCENDING), - }).subscribe(async ({ items }) => { - if (items.length === 0) { - return; - } - - const [item] = items; - const expected = expectedTitles.shift(); - - expect(item!.title).toEqual(expected); - - if (expectedTitles.length === 0) { - sub.unsubscribe(); - await DataStore.clear(); - done(); - } - }); +let initSchema: typeof initSchemaType; - await DataStore.save( - Post.copyOf(newPost, updated => { - updated.title = 'update'; - updated.updatedAt = new Date().toISOString(); - }) - ); +let { DataStore } = getDataStore() as { + DataStore: typeof DataStoreType; +}; +const nameOf = (name: keyof T) => name; - // observeQuery snapshots are debounced by 2s - await pause(2000); +/** + * Does nothing intentionally, we care only about type checking + */ +const expectType: (param: T) => void = () => {}; - await DataStore.save( - Post.copyOf(newPost, updated => { - updated.title = 'update2'; - updated.updatedAt = new Date().toISOString(); - }) - ); - }); +/** + * Renders more complete out of band traces. + */ +process.on('unhandledRejection', reason => { + console.log(reason); // log the reason including the stack trace }); describe('DataStore tests', () => { beforeEach(() => { jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => ({ init: jest.fn(), runExclusive: jest.fn(), @@ -1996,7 +58,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); }); afterEach(async () => { @@ -2069,6 +131,7 @@ describe('DataStore tests', () => { }); test('Model class can be instantiated', () => { + const validate = require('uuid-validate'); const { Model } = initSchema(testSchema()) as { Model: PersistentModelConstructor; }; @@ -2083,7 +146,7 @@ describe('DataStore tests', () => { expect(model.id).toBeDefined(); // syncable models use uuid v4 - expect(uuidValidate(model.id, 4)).toBe(true); + expect(validate(model.id, 4)).toBe(true); }); test('Non-syncable models get a ulid', () => { @@ -2117,7 +180,9 @@ describe('DataStore tests', () => { initSchema(testSchema()); }).not.toThrow(); - expect(spy).toBeCalledWith('The schema has already been initialized'); + expect(spy).toHaveBeenCalledWith( + 'The schema has already been initialized' + ); }); test('Non @model class is created', () => { @@ -2211,7 +276,7 @@ describe('DataStore tests', () => { expect(() => { (model).field1 = 'edit'; - }).toThrowError("Cannot assign to read only property 'field1' of object"); + }).toThrow("Cannot assign to read only property 'field1' of object"); }); test('Model can be copied+edited by creating an edited copy', () => { @@ -2379,7 +444,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -2397,7 +462,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -2459,14 +524,14 @@ describe('DataStore tests', () => { expect(() => { (nonModel).author = 'edit'; - }).toThrowError("Cannot assign to read only property 'author' of object"); + }).toThrow("Cannot assign to read only property 'author' of object"); }); }); describe('Initialization', () => { test('start is called only once', async () => { const storage: StorageType = - require('../src/storage/storage').ExclusiveStorage; + require('../../src/storage/storage').ExclusiveStorage; const classes = initSchema(testSchema()); @@ -2488,7 +553,7 @@ describe('DataStore tests', () => { test('It is initialized when observing (no query)', async () => { const storage: StorageType = - require('../src/storage/storage').ExclusiveStorage; + require('../../src/storage/storage').ExclusiveStorage; const classes = initSchema(testSchema()); @@ -2508,7 +573,7 @@ describe('DataStore tests', () => { beforeEach(() => { jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => ({ init: jest.fn(), runExclusive: jest.fn(() => []), @@ -2521,7 +586,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -2537,7 +602,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -2555,7 +620,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -2594,7 +659,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -2612,7 +677,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -2650,7 +715,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -2668,7 +733,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -2733,7 +798,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -2751,7 +816,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -2792,7 +857,7 @@ describe('DataStore tests', () => { field1: undefined!, dateCreated: new Date().toISOString(), }); - }).toThrowError('Field field1 is required'); + }).toThrow('Field field1 is required'); }); test('required field (null)', () => { @@ -2801,7 +866,7 @@ describe('DataStore tests', () => { field1: null!, dateCreated: new Date().toISOString(), }); - }).toThrowError('Field field1 is required'); + }).toThrow('Field field1 is required'); }); test('wrong type (number -> string)', () => { @@ -2810,7 +875,7 @@ describe('DataStore tests', () => { field1: 1234, dateCreated: new Date().toISOString(), }); - }).toThrowError( + }).toThrow( 'Field field1 should be of type string, number received. 1234' ); }); @@ -2821,7 +886,7 @@ describe('DataStore tests', () => { field1: 'someField', dateCreated: 'not-a-date', }); - }).toThrowError( + }).toThrow( 'Field dateCreated should be of type AWSDateTime, validation failed. not-a-date' ); }); @@ -2856,7 +921,7 @@ describe('DataStore tests', () => { nominations: [], }), }); - }).toThrowError( + }).toThrow( 'All elements in the rewards array should be of type string, [null] received. ' ); }); @@ -2875,7 +940,7 @@ describe('DataStore tests', () => { nominations: [], }, }); - }).toThrowError( + }).toThrow( 'All elements in the rewards array should be of type string, [null] received. ' ); }); @@ -2944,7 +1009,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), emails: [null!], }); - }).toThrowError( + }).toThrow( 'All elements in the emails array should be of type string, [null] received. ' ); }); @@ -2976,7 +1041,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), ips: ['not.an.ip'], }); - }).toThrowError( + }).toThrow( `All elements in the ips array should be of type AWSIPAddress, validation failed for one or more elements. not.an.ip` ); }); @@ -2988,7 +1053,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), ips: ['1.1.1.1', 'not.an.ip'], }); - }).toThrowError( + }).toThrow( `All elements in the ips array should be of type AWSIPAddress, validation failed for one or more elements. 1.1.1.1,not.an.ip` ); }); @@ -3021,7 +1086,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), emails: ['not-an-email'], }); - }).toThrowError( + }).toThrow( 'All elements in the emails array should be of type AWSEmail, validation failed for one or more elements. not-an-email' ); }); @@ -3039,7 +1104,7 @@ describe('DataStore tests', () => { nominations: null!, }), }); - }).toThrowError('Field nominations is required'); + }).toThrow('Field nominations is required'); }); test('required sub non model field without constructor', () => { @@ -3055,7 +1120,7 @@ describe('DataStore tests', () => { nominations: null!, }, }); - }).toThrowError('Field nominations is required'); + }).toThrow('Field nominations is required'); }); test('sub non model non nullable array field with constructor', () => { @@ -3071,7 +1136,7 @@ describe('DataStore tests', () => { nominations: [], }), }); - }).toThrowError( + }).toThrow( 'All elements in the penNames array should be of type string, [undefined] received. ' ); }); @@ -3090,7 +1155,7 @@ describe('DataStore tests', () => { nominations: [], }, }); - }).toThrowError( + }).toThrow( 'All elements in the penNames array should be of type string, [undefined] received. ' ); }); @@ -3108,7 +1173,7 @@ describe('DataStore tests', () => { nominations: [], }), }); - }).toThrowError( + }).toThrow( 'All elements in the tags array should be of type string | null | undefined, [number] received. 1234' ); }); @@ -3127,7 +1192,7 @@ describe('DataStore tests', () => { nominations: [], }, }); - }).toThrowError( + }).toThrow( 'All elements in the tags array should be of type string | null | undefined, [number] received. 1234' ); }); @@ -3273,7 +1338,7 @@ describe('DataStore tests', () => { misc: [null, 123], }), }); - }).toThrowError( + }).toThrow( 'All elements in the misc array should be of type string | null | undefined, [null,number] received. ,123' ); }); @@ -3291,7 +1356,7 @@ describe('DataStore tests', () => { misc: [null, 123], }, }); - }).toThrowError( + }).toThrow( 'All elements in the misc array should be of type string | null | undefined, [null,number] received. ,123' ); }); @@ -3328,7 +1393,7 @@ describe('DataStore tests', () => { // @ts-ignore metadata: 'invalid', }); - }).toThrowError( + }).toThrow( 'Field metadata should be of type Metadata, string recieved. invalid' ); }); @@ -3340,7 +1405,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), metadata: null, }); - }).not.toThrowError( + }).not.toThrow( 'Field metadata should be of type Metadata, string recieved. invalid' ); }); @@ -3359,7 +1424,7 @@ describe('DataStore tests', () => { login: 'login', }, }); - }).toThrowError( + }).toThrow( 'Field login should be of type Login, string recieved. login' ); }); @@ -3372,7 +1437,7 @@ describe('DataStore tests', () => { // @ts-ignore logins: ['bad type', 'another bad type'], }); - }).toThrowError( + }).toThrow( 'All elements in the logins array should be of type Login, [string] received. bad type' ); }); @@ -3385,7 +1450,7 @@ describe('DataStore tests', () => { // @ts-ignore logins: [{ username: 4 }], }); - }).toThrowError( + }).toThrow( 'Field username should be of type string, number received. 4' ); }); @@ -3397,7 +1462,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), logins: [null!, { username: 'user' }], }); - }).not.toThrowError(); + }).not.toThrow(); }); test('array sub non model wrong type', () => { @@ -3408,7 +1473,7 @@ describe('DataStore tests', () => { // @ts-ignore logins: 'my login', }); - }).toThrowError( + }).toThrow( 'Field logins should be of type [Login | null | undefined], string received. my login' ); }); @@ -3420,7 +1485,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), logins: null, }); - }).not.toThrowError(); + }).not.toThrow(); }); }); @@ -3461,7 +1526,7 @@ describe('DataStore tests', () => { const _delete = jest.fn(() => [models, models]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -3480,7 +1545,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -3521,7 +1586,7 @@ describe('DataStore tests', () => { const _delete = jest.fn(() => [[model], [model]]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -3539,7 +1604,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -3608,7 +1673,7 @@ describe('DataStore tests', () => { let model: Model; jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => ({ init: jest.fn(), runExclusive: jest.fn(() => [model]), @@ -3621,7 +1686,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -3838,9 +1903,7 @@ describe('DataStore tests', () => { expect(() => { (model).title = 'edit'; - }).toThrowError( - "Cannot assign to read only property 'title' of object" - ); + }).toThrow("Cannot assign to read only property 'title' of object"); }); test('PostCustomPK can be copied+edited by creating an edited copy', () => { @@ -3987,9 +2050,7 @@ describe('DataStore tests', () => { expect(() => { (nonPostCustomPK).author = 'edit'; - }).toThrowError( - "Cannot assign to read only property 'author' of object" - ); + }).toThrow("Cannot assign to read only property 'author' of object"); }); }); @@ -3997,7 +2058,7 @@ describe('DataStore tests', () => { let PostCustomPK; test('start is called only once', async () => { const storage: StorageType = - require('../src/storage/storage').ExclusiveStorage; + require('../../src/storage/storage').ExclusiveStorage; const classes = initSchema(testSchema()); @@ -4019,7 +2080,7 @@ describe('DataStore tests', () => { test('It is initialized when observing (no query)', async () => { const storage: StorageType = - require('../src/storage/storage').ExclusiveStorage; + require('../../src/storage/storage').ExclusiveStorage; const classes = initSchema(testSchema()); @@ -4038,7 +2099,7 @@ describe('DataStore tests', () => { beforeEach(() => { jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => ({ init: jest.fn(), runExclusive: jest.fn(() => []), @@ -4051,7 +2112,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4066,7 +2127,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4084,7 +2145,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4124,7 +2185,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4142,7 +2203,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4181,7 +2242,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4199,7 +2260,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4270,7 +2331,7 @@ describe('DataStore tests', () => { const query = jest.fn(() => [model]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4288,7 +2349,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4331,7 +2392,7 @@ describe('DataStore tests', () => { title: undefined as any, // because we're trying to trigger JS error dateCreated: new Date().toISOString(), }); - }).toThrowError('Field title is required'); + }).toThrow('Field title is required'); expect(() => { new PostCustomPK({ @@ -4339,7 +2400,7 @@ describe('DataStore tests', () => { title: null as any, // because we're trying to trigger JS error dateCreated: new Date().toISOString(), }); - }).toThrowError('Field title is required'); + }).toThrow('Field title is required'); expect(() => { new PostCustomPK({ @@ -4347,7 +2408,7 @@ describe('DataStore tests', () => { title: 1234, dateCreated: new Date().toISOString(), }); - }).toThrowError( + }).toThrow( 'Field title should be of type string, number received. 1234' ); @@ -4357,7 +2418,7 @@ describe('DataStore tests', () => { title: 'someField', dateCreated: 'not-a-date', }); - }).toThrowError( + }).toThrow( 'Field dateCreated should be of type AWSDateTime, validation failed. not-a-date' ); @@ -4368,7 +2429,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), emails: [null as any], // because we're trying to trigger JS error }); - }).toThrowError( + }).toThrow( 'All elements in the emails array should be of type string, [null] received. ' ); @@ -4388,7 +2449,7 @@ describe('DataStore tests', () => { dateCreated: new Date().toISOString(), emails: ['not-an-email'], }); - }).toThrowError( + }).toThrow( 'All elements in the emails array should be of type AWSEmail, validation failed for one or more elements. not-an-email' ); @@ -4452,7 +2513,7 @@ describe('DataStore tests', () => { const _delete = jest.fn(() => [models, models]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock: jest.Mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4471,7 +2532,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4513,7 +2574,7 @@ describe('DataStore tests', () => { const _delete = jest.fn(() => [[model], [model]]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4531,7 +2592,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4563,7 +2624,7 @@ describe('DataStore tests', () => { const _delete = jest.fn(() => [[model], [model]]); jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => { const _mock = { init: jest.fn(), @@ -4581,7 +2642,7 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); @@ -4653,7 +2714,7 @@ describe('DataStore tests', () => { let model: PostCustomPKType; jest.resetModules(); - jest.doMock('../src/storage/storage', () => { + jest.doMock('../../src/storage/storage', () => { const mock = jest.fn().mockImplementation(() => ({ init: jest.fn(), runExclusive: jest.fn(() => [model]), @@ -4666,7 +2727,10 @@ describe('DataStore tests', () => { return { ExclusiveStorage: mock }; }); - ({ initSchema, DataStore } = require('../src/datastore/datastore')); + ({ + initSchema, + DataStore, + } = require('../../src/datastore/datastore')); const classes = initSchema(testSchema()); diff --git a/packages/datastore/__tests__/DataStore/modelBehavior.test.ts b/packages/datastore/__tests__/DataStore/modelBehavior.test.ts new file mode 100644 index 00000000000..c2f87a2cd20 --- /dev/null +++ b/packages/datastore/__tests__/DataStore/modelBehavior.test.ts @@ -0,0 +1,329 @@ +import 'fake-indexeddb/auto'; +import { Predicates } from '../../src/predicates'; +import { SortDirection } from '../../src/types'; +import { getDataStore, warpTime, unwarpTime, pause } from '../helpers'; + +/** + * Renders more complete out of band traces. + */ +process.on('unhandledRejection', reason => { + console.log(reason); // log the reason including the stack trace +}); + +describe('Model behavior', () => { + beforeEach(() => { + warpTime(); + }); + + afterEach(() => { + unwarpTime(); + }); + + test('newly instantiated models do not lazy load belongsTo', async () => { + const { DataStore, DefaultPKChild, DefaultPKParent } = getDataStore(); + + const parent = await DataStore.save( + new DefaultPKParent({ + content: 'this is a decoy!', + }) + ); + + const comment = await DataStore.save( + new DefaultPKChild({ + id: "not such a random id, but it's ok", + content: 'here is some content', + parent, + }) + ); + + const detachedComment = new DefaultPKChild({ + id: "not such a random id, but it's ok", + content: 'here is some content', + defaultPKParentChildrenId: parent.id, + }); + + expect(detachedComment.defaultPKParentChildrenId).toEqual( + comment.defaultPKParentChildrenId + ); + expect(await detachedComment.parent).toBeUndefined(); + + await DataStore.clear(); + }); + + test('newly instantiated models do not lazy load hasMany', async () => { + const { DataStore, DefaultPKChild, DefaultPKParent } = getDataStore(); + + const parent = await DataStore.save( + new DefaultPKParent({ + content: 'this is a decoy!', + }) + ); + + const comment = await DataStore.save( + new DefaultPKChild({ + id: "not such a random id, but it's ok", + content: 'here is some content', + parent, + }) + ); + + const detachedParent = new DefaultPKParent({ + id: parent.id, + content: parent.content, + }); + + expect(detachedParent.id).toEqual(parent.id); + + expect(await detachedParent.children.toArray()).toEqual([]); + + await DataStore.clear(); + }); + + test('newly instantiated models do not lazy load hasOne', async () => { + const { DataStore, HasOneChild, HasOneParent } = getDataStore(); + + const child = await DataStore.save(new HasOneChild({})); + const parent = await DataStore.save( + new HasOneParent({ + child, + }) + ); + + const disconnectedParent = new HasOneParent({ + id: parent.id, + hasOneParentChildId: child.id, + }); + + expect(disconnectedParent.id).toEqual(parent.id); + expect(disconnectedParent.hasOneParentChildId).toEqual(child.id); + expect(await disconnectedParent.child).toBeUndefined(); + + await DataStore.clear(); + }); + + [null, undefined].forEach(value => { + test(`model field can be set to ${value} to remove connection hasOne parent`, async () => { + const { DataStore, HasOneChild, HasOneParent } = getDataStore(); + + const child = await DataStore.save( + new HasOneChild({ content: 'child content' }) + ); + const parent = await DataStore.save( + new HasOneParent({ + child, + }) + ); + + const parentWithoutChild = HasOneParent.copyOf(parent, draft => { + draft.child = value; + }); + + expect(parentWithoutChild.hasOneParentChildId).toBeNull(); + expect( + (await DataStore.save(parentWithoutChild)).hasOneParentChildId + ).toBeNull(); + expect( + (await DataStore.query(HasOneParent, parent.id))!.hasOneParentChildId + ).toBeNull(); + + await DataStore.clear(); + }); + + test(`model field can be set to ${value} to remove connection on child hasMany`, async () => { + const { DataStore, CompositePKParent, CompositePKChild } = getDataStore(); + + const parent = await DataStore.save( + new CompositePKParent({ + customId: 'customId', + content: 'content', + }) + ); + + const child = await DataStore.save( + new CompositePKChild({ childId: 'childId', content: 'content', parent }) + ); + + const childWithoutParent = CompositePKChild.copyOf(child, draft => { + draft.parent = value; + }); + + expect(await childWithoutParent.parent).toBeUndefined(); + expect( + await DataStore.save(childWithoutParent).then(c => c.parent) + ).toBeUndefined(); + expect( + await DataStore.query(CompositePKChild, { + childId: child.childId, + content: child.content, + }).then(c => c!.parent) + ).toBeUndefined(); + expect( + await DataStore.query(CompositePKParent, { + customId: parent.customId, + content: parent.content, + }).then(c => c!.children.toArray()) + ).toEqual([]); + + await DataStore.clear(); + }); + }); + + test('removes no-longer-matching items from the snapshot when using an eq() predicate on boolean field', done => { + (async () => { + const { DataStore, ModelWithBoolean } = getDataStore(); + try { + // the number of records we expect in each snapshot + const expecteds = [5, 4]; + + // initial data set, 5 records that will match our predicate. + for (let i = 0; i < 5; i++) { + await DataStore.save( + new ModelWithBoolean({ + boolField: true, + }) + ); + } + + const sub = DataStore.observeQuery(ModelWithBoolean, m => + m.boolField.eq(true) + ).subscribe(async ({ items, isSynced }) => { + // we don't actually expect 0 records in our snapshots after our list runs out. + // we just want to make TS happy. + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].boolField).toEqual(true); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + await DataStore.clear(); + done(); + } + }); + + // update an item to no longer match our criteria. + // we want to see a snapshot come through WITHOUT this item. + const itemToUpdate = (await DataStore.query(ModelWithBoolean)).pop()!; + await DataStore.save( + ModelWithBoolean.copyOf(itemToUpdate, m => { + m.boolField = false; + }) + ); + + // advance time to trigger another snapshot. + await pause(2000); + await DataStore.clear(); + } catch (error) { + await DataStore.clear(); + + done(error); + } + })(); + }); + + test('removes no-longer-matching items from the snapshot when using an ne() predicate on boolean field', done => { + (async () => { + const { DataStore, ModelWithBoolean } = getDataStore(); + try { + // the number of records we expect in each snapshot + const expecteds = [5, 4]; + + // initial data set, 5 records that will match our predicate. + for (let i = 0; i < 5; i++) { + await DataStore.save( + new ModelWithBoolean({ + boolField: true, + }) + ); + } + + const sub = DataStore.observeQuery(ModelWithBoolean, m => + m.boolField.ne(false) + ).subscribe(({ items, isSynced }) => { + // we don't actually expect 0 records in our snapshots after our list runs out. + // we just want to make TS happy. + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].boolField).toEqual(true); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + done(); + } + }); + + // update an item to no longer match our criteria. + // we want to see a snapshot come through WITHOUT this item. + const itemToUpdate = (await DataStore.query(ModelWithBoolean)).pop()!; + await DataStore.save( + ModelWithBoolean.copyOf(itemToUpdate, m => { + m.boolField = false; + }) + ); + + // advance time to trigger another snapshot. + await pause(2000); + await DataStore.clear(); + } catch (error) { + await DataStore.clear(); + + done(error); + } + })(); + }); + + // ref: https://github.com/aws-amplify/amplify-js/issues/11101 + test('returns fresh snapshot when sorting by descending', async () => { + const { DataStore, Post } = getDataStore(); + + const expectedTitles = ['create', 'update', 'update2']; + + const newPost = await DataStore.save( + new Post({ + title: 'create', + createdAt: new Date().toISOString(), + updatedAt: new Date().toISOString(), + }) + ); + + const sub = DataStore.observeQuery(Post, Predicates.ALL, { + sort: s => s.updatedAt(SortDirection.DESCENDING), + }).subscribe(async ({ items }) => { + if (items.length === 0) { + return; + } + + const [item] = items; + const expected = expectedTitles.shift(); + + expect(item!.title).toEqual(expected); + + if (expectedTitles.length === 0) { + sub.unsubscribe(); + await DataStore.clear(); + } + }); + + await DataStore.save( + Post.copyOf(newPost, updated => { + updated.title = 'update'; + updated.updatedAt = new Date().toISOString(); + }) + ); + + // observeQuery snapshots are debounced by 2s + await pause(2000); + + await DataStore.save( + Post.copyOf(newPost, updated => { + updated.title = 'update2'; + updated.updatedAt = new Date().toISOString(); + }) + ); + }); +}); diff --git a/packages/datastore/__tests__/DataStore/observe.test.ts b/packages/datastore/__tests__/DataStore/observe.test.ts new file mode 100644 index 00000000000..f83c4551a3f --- /dev/null +++ b/packages/datastore/__tests__/DataStore/observe.test.ts @@ -0,0 +1,327 @@ +import 'fake-indexeddb/auto'; +import { + DataStore as DataStoreType, + initSchema as initSchemaType, +} from '../../src/datastore/datastore'; +import { PersistentModel, PersistentModelConstructor } from '../../src/types'; +import { + Comment, + Model, + getDataStore, + unconfigureSync, + warpTime, + unwarpTime, + pause, + Post, + testSchema, +} from '../helpers'; + +let initSchema: typeof initSchemaType; + +let { DataStore } = getDataStore() as { + DataStore: typeof DataStoreType; +}; + +/** + * Does nothing intentionally, we care only about type checking + */ +const expectType: (param: T) => void = () => {}; + +/** + * Renders more complete out of band traces. + */ +process.on('unhandledRejection', reason => { + console.log(reason); // log the reason including the stack trace +}); + +describe('DataStore observe, unmocked, with fake-indexeddb', () => { + let Comment: PersistentModelConstructor; + let Model: PersistentModelConstructor; + let Post: PersistentModelConstructor; + + beforeEach(async () => { + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); + const classes = initSchema(testSchema()); + ({ Comment, Model, Post } = classes as { + Comment: PersistentModelConstructor; + Model: PersistentModelConstructor; + Post: PersistentModelConstructor; + }); + warpTime(); + }); + + afterEach(async () => { + await DataStore.clear(); + await unconfigureSync(DataStore); + unwarpTime(); + }); + + test('clear without starting', async () => { + await DataStore.save( + new Model({ + field1: 'Smurfs', + optionalField1: 'More Smurfs', + dateCreated: new Date().toISOString(), + }) + ); + expect(await DataStore.query(Model)).toHaveLength(1); + await DataStore.stop(); + await DataStore.clear(); + expect(await DataStore.query(Model)).toHaveLength(0); + }); + + test('subscribe to all models', done => { + try { + const sub = DataStore.observe().subscribe( + ({ element, opType, model }) => { + expectType>(model); + expectType(element); + expect(opType).toEqual('INSERT'); + expect(element.field1).toEqual('Smurfs'); + expect(element.optionalField1).toEqual('More Smurfs'); + sub.unsubscribe(); + done(); + } + ); + DataStore.save( + new Model({ + field1: 'Smurfs', + optionalField1: 'More Smurfs', + dateCreated: new Date().toISOString(), + }) + ); + } catch (error) { + done(error); + } + }); + + test('subscribe to model instance', async () => { + expect.assertions(4); + const original = await DataStore.save( + new Model({ + field1: 'somevalue', + optionalField1: 'This one should be returned', + dateCreated: new Date().toISOString(), + }) + ); + + const sub = DataStore.observe(original).subscribe( + ({ element, opType, model }) => { + expectType>(model); + expectType(element); + expect(opType).toEqual('UPDATE'); + expect(element.id).toEqual(original.id); + expect(element.field1).toEqual('new field 1 value'); + // We expect all fields, including ones that haven't been updated, to be returned: + expect(element.optionalField1).toEqual('This one should be returned'); + sub.unsubscribe(); + } + ); + + // decoy + await DataStore.save( + new Model({ + field1: "this one shouldn't get through", + dateCreated: new Date().toISOString(), + }) + ); + + await DataStore.save( + Model.copyOf(original, m => (m.field1 = 'new field 1 value')) + ); + }); + + test('subscribe to Model', async () => { + expect.assertions(4); + const original = await DataStore.save( + new Model({ + field1: 'somevalue', + optionalField1: 'additional value', + dateCreated: new Date().toISOString(), + }) + ); + + const sub = DataStore.observe(Model).subscribe( + ({ element, opType, model }) => { + expectType>(model); + expectType(element); + expect(opType).toEqual('UPDATE'); + expect(element.id).toEqual(original.id); + expect(element.field1).toEqual('new field 1 value'); + expect(element.optionalField1).toEqual('additional value'); + sub.unsubscribe(); + } + ); + + // decoy + await DataStore.save( + new Post({ + title: "This one's a decoy! (kzazulhk)", + }) + ); + + await DataStore.save( + Model.copyOf(original, m => (m.field1 = 'new field 1 value')) + ); + }); + + test('subscribe with criteria', async () => { + expect.assertions(3); + const original = await DataStore.save( + new Model({ + field1: 'somevalue', + dateCreated: new Date().toISOString(), + }) + ); + + const sub = DataStore.observe(Model, m => + m.field1.contains('new field 1') + ).subscribe(({ element, opType, model }) => { + expectType>(model); + expectType(element); + expect(opType).toEqual('UPDATE'); + expect(element.id).toEqual(original.id); + expect(element.field1).toEqual('new field 1 value'); + sub.unsubscribe(); + }); + + // decoy + await DataStore.save( + new Model({ + field1: "This one's a decoy! (sfqpjzja)", + dateCreated: new Date().toISOString(), + }) + ); + + await DataStore.save( + Model.copyOf(original, m => (m.field1 = 'new field 1 value')) + ); + }); + + test('subscribe with criteria on deletes', async () => { + expect.assertions(3); + const original = await DataStore.save( + new Model({ + field1: 'somevalue', + dateCreated: new Date().toISOString(), + }) + ); + + const sub = DataStore.observe(Model, m => + m.field1.contains('value') + ).subscribe(({ element, opType, model }) => { + expectType>(model); + expectType(element); + expect(opType).toEqual('DELETE'); + expect(element.id).toEqual(original.id); + expect(element.field1).toEqual('somevalue'); + sub.unsubscribe(); + }); + + // decoy + await DataStore.save( + new Model({ + field1: "This one's a decoy! (xgxbubyd)", + dateCreated: new Date().toISOString(), + }) + ); + + await DataStore.delete(original); + }); + + test('subscribe with belongsTo criteria', async () => { + expect.assertions(1); + const targetPost = await DataStore.save( + new Post({ + title: 'this is my post. hooray!', + }) + ); + + const nonTargetPost = await DataStore.save( + new Post({ + title: 'this is NOT my post. boo!', + }) + ); + + const sub = DataStore.observe(Comment, comment => + comment.post.title.eq(targetPost.title) + ).subscribe(({ element: comment, opType, model }) => { + expect(comment.content).toEqual('good comment'); + sub.unsubscribe(); + }); + + await DataStore.save( + new Comment({ + content: 'bad comment', + post: nonTargetPost, + }) + ); + + await DataStore.save( + new Comment({ + content: 'good comment', + post: targetPost, + }) + ); + + await pause(0); + }); + + test('subscribe with hasMany criteria', async () => { + expect.assertions(1); + + // want to set up a few posts and a few "non-target" comments + // to ensure we can observe post based on a single comment that's + // somewhat "buried" alongside other comments. + + const targetPost = await DataStore.save( + new Post({ + title: 'this is my post. hooray!', + }) + ); + + const nonTargetPost = await DataStore.save( + new Post({ + title: 'this is NOT my post. boo!', + }) + ); + + await DataStore.save( + new Comment({ content: 'bad comment', post: nonTargetPost }) + ); + await DataStore.save( + new Comment({ content: 'pre good comment', post: targetPost }) + ); + + const targetComment = await DataStore.save( + new Comment({ + content: 'good comment', + post: targetPost, + }) + ); + + await DataStore.save( + new Comment({ content: 'post good comment', post: targetPost }) + ); + + const sub = DataStore.observe(Post, post => + post.comments.content.eq(targetComment.content) + ).subscribe(async ({ element: post, opType, model }) => { + expect(post.title).toEqual('expected update'); + sub.unsubscribe(); + }); + + // should not see this one come through the subscription. + await DataStore.save( + Post.copyOf(nonTargetPost, p => (p.title = 'decoy update')) + ); + + // this is the update we expect to see come through, as it has + // 'good comment' in its `comments` field. + await DataStore.save( + Post.copyOf(targetPost, p => (p.title = 'expected update')) + ); + + await pause(0); + }); +}); diff --git a/packages/datastore/__tests__/DataStore/observeQuery.test.ts b/packages/datastore/__tests__/DataStore/observeQuery.test.ts new file mode 100644 index 00000000000..97ba55a5b0d --- /dev/null +++ b/packages/datastore/__tests__/DataStore/observeQuery.test.ts @@ -0,0 +1,643 @@ +import 'fake-indexeddb/auto'; +import { decodeTime } from 'ulid'; +import { from, of } from 'rxjs'; +import { + DataStore as DataStoreType, + initSchema as initSchemaType, +} from '../../src/datastore/datastore'; +import { Predicates } from '../../src/predicates'; +import { ExclusiveStorage as StorageType } from '../../src/storage/storage'; +import { + NonModelTypeConstructor, + PersistentModel, + PersistentModelConstructor, + SortDirection, +} from '../../src/types'; +import { + Comment, + Metadata, + Model, + BasicModelRequiredTS, + getDataStore, + configureSync, + unconfigureSync, + warpTime, + unwarpTime, + pause, + Post, + PostCustomPK as PostCustomPKType, + Profile, + testSchema, + User, +} from '../helpers'; + +let initSchema: typeof initSchemaType; + +let { DataStore } = getDataStore() as { + DataStore: typeof DataStoreType; +}; +const nameOf = (name: keyof T) => name; + +/** + * Does nothing intentionally, we care only about type checking + */ +const expectType: (param: T) => void = () => {}; + +/** + * Renders more complete out of band traces. + */ +process.on('unhandledRejection', reason => { + console.log(reason); // log the reason including the stack trace +}); + +describe('DataStore observeQuery, with fake-indexeddb and fake sync', () => { + // + // ~~~~ OH HEY! ~~~~~ + // + // Remember that `observeQuery()` always issues a first snapshot from the data + // already in storage. This is naturally performed async. Because of this, + // if you insert items immediately after `observeQuery()`, some of those items + // MAY show up in the initial snapshot. (Or maybe they won't!) + // + // Many of these tests should therefore include timeouts when adding records. + // These timeouts let `observeQuery()` sneak in and grab its first snapshot + // before those records hit storage, making for predictable tests. + // + // The tests should also account for that initial, empty snapshot. + // + // Remember: Snapshots are cumulative. + // + // And Also: Be careful when saving decoy records! Calling `done()` in a + // subscription body while any `DataStore.save()`'s are outstanding WILL + // result in cryptic errors that surface in subsequent tests! + // + // ("Error: An operation was called on an object on which it is not allowed ...") + // + // ~~~~ OK. Thanks! ~~~~ + // + // (That's it) + // + + let Comment: PersistentModelConstructor; + let Post: PersistentModelConstructor; + let User: PersistentModelConstructor; + let Profile: PersistentModelConstructor; + + /** + * Saves and item and waits until the item surfaces through `observe()` + * before returning the saved item. Creates a new subscription specific + * to the item being saved, which helps ensure all other observers receive + * the item before this function returns. + * + * @param item The model instance to save + * @returns The saved instance, returned from `DataStore.save()` + */ + const fullSave = async item => { + return new Promise(async returnSaved => { + const monitor = DataStore.observe().subscribe( + ({ element, opType, model }) => { + if (JSON.stringify(element) === JSON.stringify(savedItem)) { + monitor.unsubscribe(); + returnSaved(savedItem); + } + } + ); + const savedItem = await DataStore.save(item); + }); + }; + + beforeEach(async () => { + jest.resetModules(); + jest.clearAllMocks(); + ({ initSchema, DataStore } = require('../../src/datastore/datastore')); + const classes = initSchema(testSchema()); + ({ Comment, Post, User, Profile } = classes as { + Comment: PersistentModelConstructor; + Post: PersistentModelConstructor; + User: PersistentModelConstructor; + Profile: PersistentModelConstructor; + }); + + jest.useFakeTimers(); + await configureSync(DataStore); + }); + + afterEach(async () => { + await DataStore.clear(); + await unconfigureSync(DataStore); + jest.useRealTimers(); + }); + + test('publishes preexisting local data immediately', async () => { + expect.assertions(6); + for (let i = 0; i < 5; i++) { + await DataStore.save( + new Post({ + title: `the post ${i}`, + }) + ); + } + + const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { + expect(items.length).toBe(5); + for (let i = 0; i < 5; i++) { + expect(items[i].title).toEqual(`the post ${i}`); + } + sub.unsubscribe(); + }); + + jest.advanceTimersByTime(0); + }); + + test('publishes data saved after first snapshot', async () => { + expect.assertions(7); + const expecteds = [0, 5]; + + const sub = DataStore.observeQuery(Post).subscribe( + ({ items, isSynced }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].title).toEqual(`the post ${i}`); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + } + ); + + for (let i = 0; i < 5; i++) { + await fullSave( + new Post({ + title: `the post ${i}`, + }) + ); + } + + jest.advanceTimersByTime(2000); + }); + + test('can filter items', async () => { + expect.assertions(7); + const expecteds = [0, 5]; + + const sub = DataStore.observeQuery(Post, p => + p.title.contains('include') + ).subscribe(({ items }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (const item of items) { + expect(item.title).toMatch('include'); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + }); + + for (let i = 0; i < 10; i++) { + await fullSave( + new Post({ + title: `the post ${i} - ${Boolean(i % 2) ? 'include' : 'omit'}`, + }) + ); + } + + jest.advanceTimersByTime(2000); + }); + + // Fix for: https://github.com/aws-amplify/amplify-js/issues/9325 + test('can remove newly-unmatched items out of the snapshot on subsequent saves', async () => { + expect.assertions(7); + + // watch for post snapshots. + // the first "real" snapshot should include all five posts with "include" + // in the title. after the update to change ONE of those posts to "omit" instead, + // we should see a snapshot of 4 posts with the updated post removed. + const expecteds = [0, 4, 3]; + + const sub = DataStore.observeQuery(Post, p => + p.title.contains('include') + ).subscribe(async ({ items }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (const item of items) { + expect(item.title).toMatch('include'); + } + + if (expecteds.length === 1) { + // After the second snapshot arrives, changes a single post from + // "the post # - include" + // to + // "edited post - omit" + + // This is intended to trigger a new, after-sync'd snapshot. + // This sanity-checks helps confirms we're testing what we think + // we're testing: + expect(((DataStore as any).sync as any).getModelSyncedStatus({})).toBe( + true + ); + + await pause(2001); + + const itemToEdit = ( + await DataStore.query(Post, p => p.title.contains('include')) + ).pop()!; + await fullSave( + Post.copyOf(itemToEdit, draft => { + draft.title = 'second edited post - omit'; + }) + ); + + jest.advanceTimersByTime(2000); + } else if (expecteds.length === 0) { + sub.unsubscribe(); + } + }); + + // Creates posts like: + // + // "the post 0 - include" + // "the post 1 - omit" + // "the post 2 - include" + // "the post 3 - omit" + // + // etc. + // + // ... so that we can expect to see each other one filtered out. + for (let i = 0; i < 10; i++) { + await fullSave( + new Post({ + title: `the post ${i} - ${Boolean(i % 2) ? 'include' : 'omit'}`, + }) + ); + } + + // Changes a single post from + // "the post # - include" + // to + // "edited post - omit" + + // to add an UPDATE to the first snapshot that we should expect to + // see filtered out. + ((DataStore as any).sync as any).getModelSyncedStatus = (model: any) => + true; + + const itemToEdit = ( + await DataStore.query(Post, p => p.title.contains('include')) + ).pop()!; + + await fullSave( + Post.copyOf(itemToEdit, draft => { + draft.title = 'first edited post - omit'; + }) + ); + + jest.advanceTimersByTime(2000); + }); + + test('publishes preexisting local data AND follows up with subsequent saves', async () => { + expect.assertions(22); + const expecteds = [5, 15]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new Post({ + title: `the post ${i}`, + }) + ); + } + + const sub = DataStore.observeQuery(Post).subscribe( + ({ items, isSynced }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].title).toEqual(`the post ${i}`); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + } + ); + + for (let i = 5; i < 15; i++) { + await fullSave( + new Post({ + title: `the post ${i}`, + }) + ); + } + + jest.advanceTimersByTime(2000); + }); + + test('removes deleted items from the snapshot', async () => { + expect.assertions(11); + const expecteds = [5, 4]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new Post({ + title: `the post ${i}`, + }) + ); + } + + const sub = DataStore.observeQuery(Post).subscribe( + async ({ items, isSynced }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].title).toContain(`the post`); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } else { + const itemToDelete = (await DataStore.query(Post)).pop()!; + await DataStore.delete(itemToDelete); + jest.advanceTimersByTime(2000); + } + } + ); + + await pause(0); + }); + + test('removes deleted items from the snapshot with a predicate', done => { + (async () => { + try { + const expecteds = [5, 4]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new Post({ + title: `the post ${i}`, + }) + ); + } + + const sub = DataStore.observeQuery(Post, p => + p.title.beginsWith('the post') + ).subscribe(({ items, isSynced }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].title).toContain(`the post`); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + done(); + } + }); + + const itemToDelete = (await DataStore.query(Post)).pop()!; + await DataStore.delete(itemToDelete); + jest.advanceTimersByTime(2000); + } catch (error) { + done(error); + } + })(); + }); + + test('attaches related belongsTo properties consistently with query() on INSERT', async () => { + expect.assertions(6); + const expecteds = [5, 15]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new Comment({ + content: `comment content ${i}`, + post: await DataStore.save( + new Post({ + title: `new post ${i}`, + }) + ), + }) + ); + } + + const sub = DataStore.observeQuery(Comment).subscribe( + async ({ items, isSynced }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].content).toEqual(`comment content ${i}`); + await pause(0); + expect((await items[i].post).title).toEqual(`new post ${i}`); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + } + ); + + for (let i = 5; i < 15; i++) { + await fullSave( + new Comment({ + content: `comment content ${i}`, + post: await DataStore.save( + new Post({ + title: `new post ${i}`, + }) + ), + }) + ); + } + + jest.advanceTimersByTime(2000); + }); + + test('attaches related hasOne properties consistently with query() on INSERT', async () => { + expect.assertions(7); + const expecteds = [5, 15]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new User({ + name: `user ${i}`, + profile: await DataStore.save( + new Profile({ + firstName: `firstName ${i}`, + lastName: `lastName ${i}`, + }) + ), + }) + ); + } + + const sub = DataStore.observeQuery(User).subscribe( + async ({ items, isSynced }) => { + const expected = expecteds.shift() || 0; + expect(items.length).toBe(expected); + + for (let i = 0; i < expected; i++) { + expect(items[i].name).toEqual(`user ${i}`); + await pause(0); + expect((await items[i].profile)!.firstName).toEqual(`firstName ${i}`); + expect((await items[i].profile)!.lastName).toEqual(`lastName ${i}`); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + } + ); + + for (let i = 5; i < 15; i++) { + await fullSave( + new User({ + name: `user ${i}`, + profile: await DataStore.save( + new Profile({ + firstName: `firstName ${i}`, + lastName: `lastName ${i}`, + }) + ), + }) + ); + } + + jest.advanceTimersByTime(2000); + }); + + test('attaches related belongsTo properties consistently with query() on UPDATE', async () => { + expect.assertions(6); + const expecteds = [ + ['old post 0', 'old post 1', 'old post 2', 'old post 3', 'old post 4'], + ['new post 0', 'new post 1', 'new post 2', 'new post 3', 'new post 4'], + ]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new Comment({ + content: `comment content ${i}`, + post: await DataStore.save( + new Post({ + title: `old post ${i}`, + }) + ), + }) + ); + } + + const sub = DataStore.observeQuery(Comment).subscribe( + async ({ items, isSynced }) => { + const expected = expecteds.shift() || []; + expect(items.length).toBe(expected.length); + + for (let i = 0; i < expected.length; i++) { + expect(items[i].content).toContain(`comment content ${i}`); + await pause(0); + expect((await items[i].post).title).toEqual(expected[i]); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + } + ); + + let postIndex = 0; + const comments = await DataStore.query(Comment); + for (const comment of comments) { + const newPost = await DataStore.save( + new Post({ + title: `new post ${postIndex++}`, + }) + ); + + await fullSave( + Comment.copyOf(comment, draft => { + draft.content = `updated: ${comment.content}`; + draft.post = newPost; + }) + ); + } + + jest.advanceTimersByTime(2000); + }); + + test('attaches related hasOne properties consistently with query() on UPDATE', async () => { + expect.assertions(6); + const expecteds = [ + [ + 'first name 0', + 'first name 1', + 'first name 2', + 'first name 3', + 'first name 4', + ], + [ + 'new first name 0', + 'new first name 1', + 'new first name 2', + 'new first name 3', + 'new first name 4', + ], + ]; + + for (let i = 0; i < 5; i++) { + await DataStore.save( + new User({ + name: `user ${i}`, + profile: await DataStore.save( + new Profile({ + firstName: `first name ${i}`, + lastName: `last name ${i}`, + }) + ), + }) + ); + } + + const sub = DataStore.observeQuery(User).subscribe( + async ({ items, isSynced }) => { + const expected = expecteds.shift() || []; + expect(items.length).toBe(expected.length); + + for (let i = 0; i < expected.length; i++) { + expect(items[i].name).toContain(`user ${i}`); + await pause(0); + expect((await items[i].profile)!.firstName).toEqual(expected[i]); + } + + if (expecteds.length === 0) { + sub.unsubscribe(); + } + } + ); + + let userIndex = 0; + const users = await DataStore.query(User); + for (const user of users) { + const newProfile = await DataStore.save( + new Profile({ + firstName: `new first name ${userIndex++}`, + lastName: `new last name ${userIndex}`, + }) + ); + + await fullSave( + User.copyOf(user, draft => { + draft.name = `updated: ${user.name}`; + draft.profile = newProfile; + }) + ); + } + + jest.advanceTimersByTime(2000); + }); +}); diff --git a/packages/datastore/__tests__/DataStore/sanityCheck.test.ts b/packages/datastore/__tests__/DataStore/sanityCheck.test.ts new file mode 100644 index 00000000000..1148d96a5f0 --- /dev/null +++ b/packages/datastore/__tests__/DataStore/sanityCheck.test.ts @@ -0,0 +1,703 @@ +import 'fake-indexeddb/auto'; +import { DataStore as DataStoreType } from '../../src/datastore/datastore'; +import { Predicates } from '../../src/predicates'; +import { + getDataStore, + expectIsolation, + configureSync, + unconfigureSync, + pretendModelsAreSynced, + pause, +} from '../helpers'; + +let { DataStore } = getDataStore() as { + DataStore: typeof DataStoreType; +}; + +/** + * Renders more complete out of band traces. + */ +process.on('unhandledRejection', reason => { + console.log(reason); // log the reason including the stack trace +}); + +describe('DataStore sanity testing checks', () => { + beforeEach(async () => { + jest.resetAllMocks(); + jest.resetModules(); + }); + + afterEach(async () => { + await DataStore.clear(); + await unconfigureSync(DataStore); + }); + + test('getDataStore() returns fully fresh instances of DataStore and models', async () => { + /** + * Simulating connect/disconnect and/or `isNode` required the `getDataStore()` + * to reset modules. Hence, the returned DataStore instances should be different. + */ + + const { DataStore: DataStoreA, Post: PostA } = getDataStore(); + const { DataStore: DataStoreB, Post: PostB } = getDataStore(); + + expect(DataStoreA).not.toBe(DataStoreB); + expect(PostA).not.toBe(PostB); + + await DataStoreA.clear(); + await DataStoreB.clear(); + }); + + // HAS_MANY does not contain a FK. no constraint to validate. + test('maintains integrity when attempting to save BELONGS_TO FK at non-existent record', async () => { + const { DataStore: datastore, Post, Comment } = getDataStore(); + DataStore = datastore; + + await expect( + DataStore.save( + new Comment({ + content: 'newly created comment', + post: new Post({ + title: 'newly created post', + }), + }) + ) + ).rejects.toThrow( + `Data integrity error. You tried to save a Comment` // instructions specific to the instance follow + ); + }); + + describe('cleans up after itself', () => { + /** + * basically, if we spin up our test contexts repeatedly, put some + * data in there and do some things, stopping DataStore should + * sufficiently stop backgrounds jobs, clear data, etc. so that + * subsequent instantiations are not affected and no rogue, async + * errors show up out of nowhere (running queries against connections + * or other resources that no longer exist or are not ready.) + * + * aside from `await stop()`, we're going to be pretty careless with + * this test loop (e.g., skipping some awaits) to ensure DataStore + * *really* cleans up after itself. + */ + + /** + * PAY ATTENTION! + * + * 1. These tests run at 20x speed using `timeWarp()` to keep running + * times reasonable. If this becomes suspect, add a flag to allow + * conditional time warping. + * + * 2. If these tests start failing, run them individually, and then + * pick pairs, triads, etc. of tests to run together to find the + * smallest possible set of tests that fail together. + * + * Then, enable "focused logging." + * + * ``` + * await expectIsolation( + * async () => {...}, + * undefined, + * true // <-- this enables "focused logging" + * ); + * ``` + * + * This will start logging messages with timestamps around tests and + * each *cycle* generated by `expectIsolation`. And, It will filter out + * some less helpful messages generated by the auth package. + * + * While this is enabled, you can add console.(warn|error|debug) calls + * to your tests, and they'll be printed with timestamp prefixes to + * help sort out what's happening *when*. + * + */ + + test('sanity check for expectedIsolation helper', async () => { + // make sure expectIsolation is properly awaiting between executions. + // Logging is used to provide visual confirmation that the utility is + // working as expected. We create the same test *N* times. + + // Ths test was originally red-green tested by removing the `await` + // before the `script(...)` call in `expectIsolation`. + + const numberOfCycles = 5; + + let lastCycle = 0; + await expectIsolation(async ({ cycle }) => { + await new Promise(unsleep => + setTimeout(() => { + lastCycle = cycle; + unsleep(); + }, 20 * cycle) + ); + }, numberOfCycles); + + expect(lastCycle).toBe(numberOfCycles); + }); + + describe('during lifecycle events', () => { + let { DataStore, Post } = getDataStore(); + + beforeAll(async () => { + await DataStore.clear(); + }); + + afterEach(async () => { + await DataStore.clear(); + }); + + describe('simple cases', () => { + for (const online of [true, false]) { + for (const isNode of [true, false]) { + const connectedState = online ? 'online' : 'offline'; + const environment = isNode ? 'node' : 'browser'; + + test(`clearing after awaited start (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + await DataStore.start(); + await DataStore.clear(); + await DataStore.start(); + }); + + test(`clearing after unawaited start (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + DataStore.start(); + await DataStore.clear(); + await DataStore.start(); + }); + + test(`clearing after unawaited start, then a small pause (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + DataStore.start(); + await pause(1); + await DataStore.clear(); + await DataStore.start(); + }); + + test(`stopping after awaited start (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + await DataStore.start(); + await DataStore.stop(); + await DataStore.start(); + }); + + test(`stopping after unawaited start (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + DataStore.start(); + await DataStore.stop(); + await DataStore.start(); + }); + + test(`stopping after unawaited start, then a small pause (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + DataStore.start(); + await pause(1); + await DataStore.stop(); + await DataStore.start(); + }); + + // tslint:disable-next-line: max-line-length + test(`starting after unawaited clear results in a DX-friendly error (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + await DataStore.start(); + const clearing = DataStore.clear(); + + // At minimum: looking for top-level error, operation that failed, state while in failure. + expect(DataStore.start()).rejects.toThrow( + /DataStoreStateError:.+`DataStore\.start\(\)`.+Clearing/ + ); + + await clearing; + }); + + // tslint:disable-next-line: max-line-length + test(`starting after unawaited stop results in a DX-friendly error (${connectedState}, ${environment})`, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + await DataStore.start(); + const stopping = DataStore.stop(); + + // At minimum: looking for top-level error, operation that failed, state while in failure. + expect(DataStore.start()).rejects.toThrow( + /DataStoreStateError:.+`DataStore\.start\(\)`.+Stopping/ + ); + + await stopping; + }); + } + } + }); + + /** + * When fuzzing discovers issues, recreate them here to prevent regressions. + */ + describe('edges discovered by fuzz', () => { + /** + * As explained below, DataStore can't actually handle the fuzz yet. :( + */ + }); + + /** + * We're not fuzzable yet ... also, these fuzz tests may need to accumulate + * assertions along the way as well, because some of the behavior will + * likely change from "everything is happy, DataStore figures it out" to + * predictable error cases. + */ + describe.skip('fuzz', () => { + function fuzz() { + const steps = [] as any[]; + + // increase when we can actually deal with the fuzz. + const stepsToProduce = 3; // + Math.random() * 10; + for (let i = 0; i < stepsToProduce; i++) { + let awaited = true; + if (Math.random() > 0.5) { + awaited = false; + } + const methods = ['start', 'stop', 'clear', 'query', 'save']; + const action = { + method: methods.sort(() => Math.random() - 0.5)[0], + awaited, + }; + steps.push(action); + } + return steps; + } + + // increase when we can actually deal efficiently with the fuzz + for (let i = 0; i < 3; i++) { + const steps = fuzz(); + const name = steps + .map(s => `${s.awaited ? 'awaited' : 'unawaited'} ${s.method}`) + .join(', '); + + for (const online of [true, false]) { + for (const isNode of [true, false]) { + const connectedState = online ? 'online' : 'offline'; + const environment = isNode ? 'node' : 'browser'; + const testName = `${name} (${connectedState}, ${environment})`; + + test(testName, async () => { + ({ DataStore, Post } = getDataStore({ online, isNode })); + for (const step of steps) { + const f = { + start: () => DataStore.start(), + stop: () => DataStore.stop(), + clear: () => DataStore.clear(), + save: () => DataStore.save(new Post({ title: testName })), + query: () => DataStore.query(Post), + }[step.method]; + + if (step.awaited) { + await f(); + } else { + f(); + } + + // no explicit assertions for now. at this point, we just + // want things NOT to blow up. :) + } + }); + } + } + } + }); + }); + + test('awaited save', async () => { + await expectIsolation( + async ({ DataStore, Post }) => + await DataStore.save(new Post({ title: 'some title' })) + ); + }); + + test('un-awaited saves', async () => { + await expectIsolation(async ({ DataStore, Post }) => { + DataStore.save(new Post({ title: 'some title' })); + }); + }); + + test('queries against locked DataStore are rejected', async () => { + const { DataStore, Post } = getDataStore(); + + // shedule a promise that will NOT be done for "awhile" + let unblock; + + (DataStore as any).runningProcesses.add( + async () => new Promise(_unblock => (unblock = _unblock)), + 'artificial query blocker' + ); + + // begin clearing, which should lock DataStore + const clearing = DataStore.clear(); + + // pass control back to handlers briefly, so that `clear()` + // activities can start occurring. + await new Promise(unsleep => setTimeout(unsleep, 1)); + + // and now attempt an ill-fated operation + await expect(DataStore.query(Post)) + // looking top-level error name, operation that failed, state DS was in + .rejects.toThrow(/DataStoreStateError.+DataStore\.query\(\).+Clearing/i) + .finally(async () => { + unblock(); + await clearing; + }); + }); + + test('saves against locked DataStore are rejected', async () => { + const { DataStore, Post } = getDataStore(); + + // shedule a promise that will NOT be done for "awhile" + let unblock; + (DataStore as any).runningProcesses.add( + async () => new Promise(_unblock => (unblock = _unblock)), + 'artificial save blocker' + ); + + // begin clearing, which should lock DataStore + const clearing = DataStore.clear(); + + // pass control back to handlers briefly, so that `clear()` + // activities can start occurring. + await new Promise(unsleep => setTimeout(unsleep, 1)); + + // and now attempt an ill-fated operation + await expect( + DataStore.save(new Post({ title: 'title that should fail' })) + ) + // looking top-level error name, operation that failed, state DS was in + .rejects.toThrow(/DataStoreStateError.+DataStore\.save\(\).+Clearing/i) + .finally(async () => { + unblock(); + await clearing; + }); + }); + + test('deletes against locked DataStore are rejected', async () => { + const { DataStore, Post } = getDataStore(); + + // shedule a promise that will NOT be done for "awhile" + let unblock; + (DataStore as any).runningProcesses.add( + async () => new Promise(_unblock => (unblock = _unblock)), + 'artificial delete blocker' + ); + + // begin clearing, which should lock DataStore + const clearing = DataStore.clear(); + + // pass control back to handlers briefly, so that `clear()` + // activities can start occurring. + await new Promise(unsleep => setTimeout(unsleep, 1)); + + // and now attempt an ill-fated operation + await expect(DataStore.delete(Post, Predicates.ALL)) + // looking top-level error name, operation that failed, state DS was in + .rejects.toThrow(/DataStoreStateError.+DataStore\.delete\(\).+Clearing/) + .finally(async () => { + unblock(); + await clearing; + }); + }); + + test('observes against locked DataStore are rejected', async () => { + const { DataStore, Post } = getDataStore(); + + // shedule a promise that will NOT be done for "awhile" + let unblock; + (DataStore as any).runningProcesses.add( + async () => new Promise(_unblock => (unblock = _unblock)), + 'artificial observe blocker' + ); + + // begin clearing, which should lock DataStore + const clearing = DataStore.clear(); + + // pass control back to handlers briefly, so that `clear()` + // activities can start occurring. + await new Promise(unsleep => setTimeout(unsleep, 1)); + + // and now attempt an ill-fated operation + DataStore.observe(Post).subscribe({ + next() { + expect(true).toBe(false); + }, + error(error) { + expect(error.message).toContain('DataStoreStateError'); + expect(error.message).toContain('DataStore.observe()'); + expect(error.message).toContain('Clearing'); + unblock(); + }, + }); + + await clearing; + }); + + test('observeQueries against locked DataStore are rejected', async () => { + const { DataStore, Post } = getDataStore(); + + // shedule a promise that will NOT be done for "awhile" + let unblock; + (DataStore as any).runningProcesses.add( + async () => new Promise(_unblock => (unblock = _unblock)), + 'artificial observeQuery blocker' + ); + + // begin clearing, which should lock DataStore + const clearing = DataStore.clear(); + + // pass control back to handlers briefly, so that `clear()` + // activities can start occurring. + await new Promise(unsleep => setTimeout(unsleep, 1)); + + // and now attempt an ill-fated operation + DataStore.observeQuery(Post).subscribe({ + next() { + expect(true).toBe(false); + }, + error(error) { + expect(error.message).toContain('DataStoreStateError'); + expect(error.message).toContain('DataStore.observeQuery()'); + expect(error.message).toContain('Clearing'); + unblock(); + }, + }); + + await clearing; + }); + + test('data stays in its lane for save then query with good awaits', async () => { + // in other words, a well-formed (awaited) save from one instance + // does not infect another. + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await DataStore.save(new Post({ title: `title from ${cycle}` })); + const post = await DataStore.query(Post); + expect(post.length).toEqual(1); + expect(post[0].title).toEqual(`title from ${cycle}`); + }); + }); + + test('data stays in its lane for save, query, delete all, then query with good awaits', async () => { + // in other words, a well-formed (awaited) save from one instance + // does not infect another. + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await DataStore.save(new Post({ title: `title from ${cycle}` })); + const posts = await DataStore.query(Post); + expect(posts.length).toEqual(1); + expect(posts[0].title).toEqual(`title from ${cycle}`); + + await DataStore.delete(Post, Predicates.ALL); + const afterDelete = await DataStore.query(Post); + expect(afterDelete.length).toEqual(0); + }); + }); + + test('data stays in its lane for basic queries with late un-awaited saves', async () => { + // in other words, a save from one instance does not infect another. + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await DataStore.save(new Post({ title: `title from ${cycle}` })); + const post = await DataStore.query(Post); + + expect(post.length).toEqual(1); + expect(post[0].title).toEqual(`title from ${cycle}`); + + // try to pollute the next test + DataStore.save(new Post({ title: `title from ${cycle}` })); + }); + }); + + test('polite observe() is cleaned up', async () => { + await expectIsolation(async ({ DataStore, Post, cycle }) => { + return new Promise(resolve => { + const sub = DataStore.observe(Post).subscribe( + ({ element, opType, model }) => { + expect(opType).toEqual('INSERT'); + expect(element.title).toEqual( + `a title from polite cycle ${cycle}` + ); + sub.unsubscribe(); + resolve(); + } + ); + DataStore.save( + new Post({ title: `a title from polite cycle ${cycle}` }) + ); + }); + }); + }); + + test('impolite observe() is cleaned up', async () => { + await expectIsolation(async ({ DataStore, Post, cycle }) => { + return new Promise(resolve => { + const sub = DataStore.observe(Post).subscribe( + ({ element, opType, model }) => { + expect(opType).toEqual('INSERT'); + expect(element.title).toEqual( + `a title from impolite cycle ${cycle}` + ); + // omitted: + // sub.unsubscribe(); + // (that's what makes it impolite) + resolve(); + } + ); + DataStore.save( + new Post({ title: `a title from impolite cycle ${cycle}` }) + ); + }); + }); + }); + + test('polite observeQuery() is cleaned up', async () => { + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await pretendModelsAreSynced(DataStore); + await DataStore.save( + new Post({ title: `a title from polite cycle ${cycle} post 1` }) + ); + + const sanityCheck = await DataStore.query(Post); + expect(sanityCheck.length).toEqual(1); + expect(sanityCheck[0].title).toEqual( + `a title from polite cycle ${cycle} post 1` + ); + + return new Promise(async resolve => { + let first = true; + const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { + if (first) { + first = false; + expect(items.length).toEqual(1); + expect(items[0].title).toEqual( + `a title from polite cycle ${cycle} post 1` + ); + DataStore.save( + new Post({ title: `a title from polite cycle ${cycle} post 2` }) + ); + } else { + expect(items.length).toEqual(2); + expect(items.map(p => p.title)).toEqual([ + `a title from polite cycle ${cycle} post 1`, + `a title from polite cycle ${cycle} post 2`, + ]); + sub.unsubscribe(); + resolve(); + } + }); + }); + }); + }); + + test('polite observeQuery() with unsynced models is cleaned up', async () => { + await expectIsolation(async ({ DataStore, Post, cycle }) => { + console.debug(`before configureSync cycle ${cycle}`); + await configureSync(DataStore); + console.debug(`after configureSync cycle ${cycle}`); + return new Promise(async doneTesting => { + let first = true; + const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { + console.debug(`message received in cycle ${cycle}`, items); + if (first) { + first = false; + expect(items.length).toEqual(0); + DataStore.save( + new Post({ + title: `a title from polite unsynced cycle ${cycle} post 1`, + }) + ); + } else { + expect(items.length).toEqual(1); + expect(items[0].title).toEqual( + `a title from polite unsynced cycle ${cycle} post 1` + ); + sub.unsubscribe(); + doneTesting(); + } + }); + }); + }); + }); + + test('less polite observeQuery() is cleaned up', async () => { + // i.e., do not unsubscribe in the last step fo the observeQuery + // event handler. + + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await pretendModelsAreSynced(DataStore); + + await DataStore.save( + new Post({ title: `a title from impolite cycle ${cycle} post 1` }) + ); + const sanityCheck = await DataStore.query(Post); + expect(sanityCheck.length).toEqual(1); + expect(sanityCheck[0].title).toEqual( + `a title from impolite cycle ${cycle} post 1` + ); + + await new Promise(doneTesting => { + let first = true; + const sub = DataStore.observeQuery(Post).subscribe(({ items }) => { + if (first) { + first = false; + expect(items.length).toEqual(1); + expect(items[0].title).toEqual( + `a title from impolite cycle ${cycle} post 1` + ); + DataStore.save( + new Post({ + title: `a title from impolite cycle ${cycle} post 2`, + }) + ); + } else { + expect(items.length).toEqual(2); + expect(items.map(p => p.title)).toEqual([ + `a title from impolite cycle ${cycle} post 1`, + `a title from impolite cycle ${cycle} post 2`, + ]); + + // missing unsubscribe is what makes it "less polite" + doneTesting(); + } + }); + }); + }); + }); + + test.skip('impolite observeQuery() is cleaned up', async () => { + // TODO: observeQuery example that prematurely returns and leaves + // lingering saves in the pipeline ... not 100% sure if that + // cleanup is even in-scope for DataStore to clean up. + }); + + test('sync is cleaned up', async () => { + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await configureSync(DataStore); + + // save an item to kickstart outbox processing. + await DataStore.save( + new Post({ title: `post from "sync is cleaned" up cycle ${cycle}` }) + ); + }); + }); + + test('rude synchronized observe-save is cleaned up', async () => { + await expectIsolation(async ({ DataStore, Post, cycle }) => { + await configureSync(DataStore); + + DataStore.observe(Post).subscribe(() => {}); + + // save an item to kickstart outbox processing. + DataStore.save( + new Post({ + title: `post from "rude synchronized observe-save" up cycle ${cycle}`, + }) + ); + }); + }); + + // + // TODO: once we have a clean way to fake a not-node environment, we + // need an isolation test to prove DataStore shuts **subscription** + // connections/ops down against mocked AppSync backend. + // + }); +}); diff --git a/packages/datastore/__tests__/IndexedDBAdapter.test.ts b/packages/datastore/__tests__/IndexedDBAdapter.test.ts index a9702ea978c..af24ad080ae 100644 --- a/packages/datastore/__tests__/IndexedDBAdapter.test.ts +++ b/packages/datastore/__tests__/IndexedDBAdapter.test.ts @@ -9,7 +9,6 @@ import { import { PersistentModelConstructor, SortDirection } from '../src/types'; import { pause, - expectMutation, Model, User, Profile, @@ -21,7 +20,6 @@ import { DefaultPKChild, CompositePKParent, CompositePKChild, - testSchema, getDataStore, } from './helpers'; import { Predicates as PredicatesClass } from '../src/predicates'; diff --git a/packages/datastore/__tests__/Predicate.ts b/packages/datastore/__tests__/Predicate.test.ts similarity index 99% rename from packages/datastore/__tests__/Predicate.ts rename to packages/datastore/__tests__/Predicate.test.ts index 6c24e9950da..99ad55a4ed2 100644 --- a/packages/datastore/__tests__/Predicate.ts +++ b/packages/datastore/__tests__/Predicate.test.ts @@ -1286,7 +1286,7 @@ describe('Predicates', () => { describe('predicate typings', () => { test('not group builders must return single child condition - recursive/relational predicates', async () => { expect(() => - // @ts-expect-error doesn't work until TS 3.9 ... until then: + // TODO: @ts-expect-error doesn't work until TS 3.9 ... until then: // @ts-ignore recursivePredicateFor(AuthorMeta).not(a => [ a.name.contains('Bob'), @@ -1298,7 +1298,7 @@ describe('Predicates', () => { test('and group builders must return an array of child conditions - recursive/relational predicates', async () => { expect(() => - // @ts-expect-error doesn't work until TS 3.9 ... until then: + // TODO: @ts-expect-error doesn't work until TS 3.9 ... until then: // @ts-ignore recursivePredicateFor(AuthorMeta).and(a => a.name.contains('Bob')) ).toThrow( @@ -1308,7 +1308,7 @@ describe('Predicates', () => { test('or group builders must return array of child conditions - recursive/relational predicates', async () => { expect(() => - // @ts-expect-error doesn't work until TS 3.9 ... until then: + // TODO: @ts-expect-error doesn't work until TS 3.9 ... until then: // @ts-ignore recursivePredicateFor(AuthorMeta).or(a => a.name.contains('Bob')) ).toThrow( @@ -1318,7 +1318,7 @@ describe('Predicates', () => { test('not group builders must return single child condition - flat predicates', async () => { expect(() => - // @ts-expect-error doesn't work until TS 3.9 ... until then: + // TODO: @ts-expect-error doesn't work until TS 3.9 ... until then: // @ts-ignore predicateFor(AuthorMeta).not(a => [a.name.contains('Bob')]) ).toThrow( @@ -1328,7 +1328,7 @@ describe('Predicates', () => { test('and group builders must return an array of child conditions - flat predicates', async () => { expect(() => - // @ts-expect-error doesn't work until TS 3.9 ... until then: + // TODO: @ts-expect-error doesn't work until TS 3.9 ... until then: // @ts-ignore predicateFor(AuthorMeta).and(a => a.name.contains('Bob')) ).toThrow( @@ -1338,7 +1338,7 @@ describe('Predicates', () => { test('or group builders must return array of child conditions - flat predicates', async () => { expect(() => - // @ts-expect-error doesn't work until TS 3.9 ... until then: + // TODO: @ts-expect-error doesn't work until TS 3.9 ... until then: // @ts-ignore predicateFor(AuthorMeta).or(a => a.name.contains('Bob')) ).toThrow( diff --git a/packages/datastore/__tests__/__snapshots__/AsyncStorage.ts.snap b/packages/datastore/__tests__/__snapshots__/AsyncStorage.test.ts.snap similarity index 99% rename from packages/datastore/__tests__/__snapshots__/AsyncStorage.ts.snap rename to packages/datastore/__tests__/__snapshots__/AsyncStorage.test.ts.snap index 5a814ef5792..971980d18a3 100644 --- a/packages/datastore/__tests__/__snapshots__/AsyncStorage.ts.snap +++ b/packages/datastore/__tests__/__snapshots__/AsyncStorage.test.ts.snap @@ -1,7 +1,7 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`AsyncStorage tests Internal AsyncStorage key schema changes Keys are migrated to the new format with ulid 1`] = ` -Array [ +[ "@AmplifyDatastore::datastore_Setting::Collection", "@AmplifyDatastore::datastore_Setting::Data::11ea-9555-bb149af0-bd99-91dc40efda36", "@AmplifyDatastore::user_BlogOwner::Collection", diff --git a/packages/datastore/__tests__/__snapshots__/indexeddb.test.ts.snap b/packages/datastore/__tests__/__snapshots__/indexeddb.test.ts.snap index 768efb9f134..7716d705264 100644 --- a/packages/datastore/__tests__/__snapshots__/indexeddb.test.ts.snap +++ b/packages/datastore/__tests__/__snapshots__/indexeddb.test.ts.snap @@ -1,45 +1,45 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`DB versions migration Migration from v1 to v3: v3-schema 1`] = ` -Object { - "data": Object { - "data": Array [ - Object { +{ + "data": { + "data": [ + { "inbound": false, - "rows": Array [ - Array [ + "rows": [ + [ 1, - Object { + { "id": "094a722a-4f00-4723-928a-536aa04b3470", "key": "schemaVersion", - "value": "\\"a66372d29356c40e7cd29e41527cead7\\"", + "value": ""a66372d29356c40e7cd29e41527cead7"", }, ], ], "tableName": "datastore_Setting", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "sync_ModelMetadata", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "sync_MutationEvent", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Album", }, - Object { + { "inbound": false, - "rows": Array [ - Object { - "$": Array [ + "rows": [ + { + "$": [ 1, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -47,18 +47,18 @@ Object { "name": "author2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 2, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -66,8 +66,8 @@ Object { "name": "author1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -77,13 +77,13 @@ Object { ], "tableName": "user_Author", }, - Object { + { "inbound": false, - "rows": Array [ - Object { - "$": Array [ + "rows": [ + { + "$": [ 1, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -92,24 +92,24 @@ Object { "name": "blog2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 2, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, "id": "844724fe-373c-4505-b202-2852580058e3", "name": "B1", - "owner": Object { + "owner": { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -118,8 +118,8 @@ Object { }, }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -129,16 +129,16 @@ Object { }, }, }, - Object { - "$": Array [ + { + "$": [ 3, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, "id": "91e67f1e-aba4-497d-a2c1-f2d3133468c0", "name": "Avatar: Last Airbender", - "owner": Object { + "owner": { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -147,8 +147,8 @@ Object { }, }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -158,10 +158,10 @@ Object { }, }, }, - Object { - "$": Array [ + { + "$": [ 4, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -170,24 +170,24 @@ Object { "name": "The Blog", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 5, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, "id": "d5e7eb84-2aa1-4bb2-8e2a-21ccc06d2d69", "name": "Avatar: Last Airbender", - "owner": Object { + "owner": { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -196,8 +196,8 @@ Object { }, }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -207,10 +207,10 @@ Object { }, }, }, - Object { - "$": Array [ + { + "$": [ 6, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -219,8 +219,8 @@ Object { "name": "blog2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -230,13 +230,13 @@ Object { ], "tableName": "user_Blog", }, - Object { + { "inbound": false, - "rows": Array [ - Object { - "$": Array [ + "rows": [ + { + "$": [ 1, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -244,18 +244,18 @@ Object { "name": "Owner 2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 2, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -263,18 +263,18 @@ Object { "name": "Owner 2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 3, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -282,18 +282,18 @@ Object { "name": "Owner 1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 4, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -301,18 +301,18 @@ Object { "name": "owner 3", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 5, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -320,18 +320,18 @@ Object { "name": "owner 3", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 6, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -339,18 +339,18 @@ Object { "name": "Owner 1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 7, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -358,18 +358,18 @@ Object { "name": "Owner 1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 8, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -377,18 +377,18 @@ Object { "name": "Owner 1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 9, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -396,8 +396,8 @@ Object { "name": "Owner 1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -407,38 +407,38 @@ Object { ], "tableName": "user_BlogOwner", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Comment", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Editor", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Forum", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_ForumEditorJoin", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Person", }, - Object { + { "inbound": false, - "rows": Array [ - Object { - "$": Array [ + "rows": [ + { + "$": [ 1, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -448,18 +448,18 @@ Object { "title": "Post 2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 2, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -469,8 +469,8 @@ Object { "title": "Post 1", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -480,111 +480,111 @@ Object { ], "tableName": "user_Post", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_PostAuthorJoin", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Project", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Song", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "user_Team", }, ], "databaseName": "amplify-datastore", "databaseVersion": 0.3, - "tables": Array [ - Object { + "tables": [ + { "name": "datastore_Setting", "rowCount": 1, "schema": "++,&[id]", }, - Object { + { "name": "sync_ModelMetadata", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "sync_MutationEvent", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Album", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Author", "rowCount": 2, "schema": "++,&[id]", }, - Object { + { "name": "user_Blog", "rowCount": 6, "schema": "++,[blogOwnerId],&[id]", }, - Object { + { "name": "user_BlogOwner", "rowCount": 9, "schema": "++,&[id]", }, - Object { + { "name": "user_Comment", "rowCount": 0, "schema": "++,&[id],[commentPostId]", }, - Object { + { "name": "user_Editor", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Forum", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_ForumEditorJoin", "rowCount": 0, "schema": "++,&[id],[editorID],[editorID+forumID],[forumID],[forumID+editorID]", }, - Object { + { "name": "user_Person", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Post", "rowCount": 2, "schema": "++,&[id],[postBlogId],[referencePostId]", }, - Object { + { "name": "user_PostAuthorJoin", "rowCount": 0, "schema": "++,[authorId],&[id],[postId]", }, - Object { + { "name": "user_Project", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Song", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Team", "rowCount": 0, "schema": "++,&[id]", diff --git a/packages/datastore/__tests__/__snapshots__/indexeddb.upgrade.test.ts.snap b/packages/datastore/__tests__/__snapshots__/indexeddb.upgrade.test.ts.snap index 98bab81888f..a8cfa106c7d 100644 --- a/packages/datastore/__tests__/__snapshots__/indexeddb.upgrade.test.ts.snap +++ b/packages/datastore/__tests__/__snapshots__/indexeddb.upgrade.test.ts.snap @@ -1,40 +1,40 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`DB versions migration with destructive schema change Migration from v1 to v3: v3-destructive-schema 1`] = ` -Object { - "data": Object { - "data": Array [ - Object { +{ + "data": { + "data": [ + { "inbound": false, - "rows": Array [ - Array [ + "rows": [ + [ 1, - Object { + { "id": "094a722a-4f00-4723-928a-536aa04b3470", "key": "schemaVersion", - "value": "\\"a66372d29356c40e7cd29e41527cead7\\"", + "value": ""a66372d29356c40e7cd29e41527cead7"", }, ], ], "tableName": "datastore_Setting", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "sync_ModelMetadata", }, - Object { + { "inbound": false, - "rows": Array [], + "rows": [], "tableName": "sync_MutationEvent", }, - Object { + { "inbound": false, - "rows": Array [ - Object { - "$": Array [ + "rows": [ + { + "$": [ 1, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -43,24 +43,24 @@ Object { "name": "blog2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 2, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, "id": "844724fe-373c-4505-b202-2852580058e3", "name": "B1", - "owner": Object { + "owner": { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -69,8 +69,8 @@ Object { }, }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -80,16 +80,16 @@ Object { }, }, }, - Object { - "$": Array [ + { + "$": [ 3, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, "id": "91e67f1e-aba4-497d-a2c1-f2d3133468c0", "name": "Avatar: Last Airbender", - "owner": Object { + "owner": { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -98,8 +98,8 @@ Object { }, }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -109,10 +109,10 @@ Object { }, }, }, - Object { - "$": Array [ + { + "$": [ 4, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -121,24 +121,24 @@ Object { "name": "The Blog", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", }, }, }, - Object { - "$": Array [ + { + "$": [ 5, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, "id": "d5e7eb84-2aa1-4bb2-8e2a-21ccc06d2d69", "name": "Avatar: Last Airbender", - "owner": Object { + "owner": { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -147,8 +147,8 @@ Object { }, }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -158,10 +158,10 @@ Object { }, }, }, - Object { - "$": Array [ + { + "$": [ 6, - Object { + { "_deleted": null, "_lastChangedAt": null, "_version": null, @@ -170,8 +170,8 @@ Object { "name": "blog2", }, ], - "$types": Object { - "$": Object { + "$types": { + "$": { "1._deleted": "undef", "1._lastChangedAt": "undef", "1._version": "undef", @@ -184,23 +184,23 @@ Object { ], "databaseName": "amplify-datastore", "databaseVersion": 0.3, - "tables": Array [ - Object { + "tables": [ + { "name": "datastore_Setting", "rowCount": 1, "schema": "++,&[id]", }, - Object { + { "name": "sync_ModelMetadata", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "sync_MutationEvent", "rowCount": 0, "schema": "++,&[id]", }, - Object { + { "name": "user_Blog", "rowCount": 6, "schema": "++,&[id]", diff --git a/packages/datastore/__tests__/__snapshots__/sync.test.ts.snap b/packages/datastore/__tests__/__snapshots__/sync.test.ts.snap index 4949b2ee383..31f9a036e44 100644 --- a/packages/datastore/__tests__/__snapshots__/sync.test.ts.snap +++ b/packages/datastore/__tests__/__snapshots__/sync.test.ts.snap @@ -1,15 +1,15 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`Sync jitteredRetry custom pk: should return all data 1`] = ` -Object { - "data": Object { - "syncPosts": Object { - "items": Array [ - Object { +{ + "data": { + "syncPosts": { + "items": [ + { "postId": "1", "title": "Item 1", }, - Object { + { "postId": "2", "title": "Item 2", }, @@ -20,15 +20,15 @@ Object { `; exports[`Sync jitteredRetry should return all data 1`] = ` -Object { - "data": Object { - "syncPosts": Object { - "items": Array [ - Object { +{ + "data": { + "syncPosts": { + "items": [ + { "id": "1", "title": "Item 1", }, - Object { + { "id": "2", "title": "Item 2", }, @@ -39,23 +39,23 @@ Object { `; exports[`Sync jitteredRetry should return partial data and send Hub event 1`] = ` -Object { - "data": Object { - "syncPosts": Object { - "items": Array [ - Object { +{ + "data": { + "syncPosts": { + "items": [ + { "id": "1", "title": "Item 1", }, - Object { + { "id": "3", "title": "Item 3", }, ], }, }, - "errors": Array [ - Object { + "errors": [ + { "message": "Item 2 error", }, ], @@ -63,10 +63,10 @@ Object { `; exports[`Sync jitteredRetry should throw error if no data is returned 1`] = ` -Object { +{ "data": null, - "errors": Array [ - Object { + "errors": [ + { "message": "General error", }, ], diff --git a/packages/datastore/__tests__/commonAdapterTests.ts b/packages/datastore/__tests__/commonAdapterTests.ts index a785f644c8f..76621d2a451 100644 --- a/packages/datastore/__tests__/commonAdapterTests.ts +++ b/packages/datastore/__tests__/commonAdapterTests.ts @@ -5,7 +5,7 @@ import { PersistentModelConstructor, PersistentModel, initSchema as initSchemaType, -} from '../src/'; +} from '../src'; import { ModelRelationship } from '../src/storage/relationship'; import { @@ -36,7 +36,7 @@ import { export { pause }; const isSQLiteAdapter = () => - expect.getState().testPath.includes('SQLiteAdapter'); + expect.getState().testPath?.includes('SQLiteAdapter'); /** * Adds common query test cases that all adapters should support. diff --git a/packages/datastore/__tests__/connectivityHandling.test.ts b/packages/datastore/__tests__/connectivityHandling.test.ts index de2281b996f..98de4c83c13 100644 --- a/packages/datastore/__tests__/connectivityHandling.test.ts +++ b/packages/datastore/__tests__/connectivityHandling.test.ts @@ -2263,40 +2263,40 @@ describe('DataStore sync engine', () => { expect(onCreate).toEqual(onUpdate); expect(onCreate).toEqual(onDelete); expect(onCreate).toMatchInlineSnapshot(` - Object { - "or": Array [ - Object { - "and": Array [ - Object { - "field1": Object { + { + "or": [ + { + "and": [ + { + "field1": { "eq": "field", }, }, - Object { - "createdAt": Object { + { + "createdAt": { "gt": "1/1/2023", }, }, ], }, - Object { - "and": Array [ - Object { - "or": Array [ - Object { - "optionalField1": Object { + { + "and": [ + { + "or": [ + { + "optionalField1": { "beginsWith": "a", }, }, - Object { - "optionalField1": Object { + { + "optionalField1": { "notContains": "z", }, }, ], }, - Object { - "emails": Object { + { + "emails": { "ne": "-", }, }, diff --git a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/composite-identifier.test.tsx b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/composite-identifier.test.tsx index aaa9c195c52..7135a440555 100644 --- a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/composite-identifier.test.tsx +++ b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/composite-identifier.test.tsx @@ -32,39 +32,39 @@ describe('Composite Identifier', () => { dob: '', name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); CompositeDefaultRO.copyOf({} as CompositeDefaultRO, d => { - // @ts-expect-error + // TODO: Uncomment below and update test // d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.tenant; - // @ts-expect-error + // TODO: Uncomment below and update test // d.tenant = ''; d.dob; - // @ts-expect-error + // TODO: Uncomment below and update test // d.dob = ''; d.name = ''; d.description = ''; d.createdAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdAt = ''; d.updatedAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedAt = ''; }); // Query - // @ts-expect-error + // TODO: Uncomment below and update test // await DataStore.query(CompositeDefaultRO, 'someid'); - // @ts-expect-error + // TODO: Uncomment below and update test // await DataStore.query(CompositeDefaultRO, { id: 'someid' }); expectType( @@ -90,7 +90,7 @@ describe('Composite Identifier', () => { // Delete - // @ts-expect-error + // TODO: Uncomment below and update test // await DataStore.delete(CompositeDefaultRO, '') expectType( @@ -158,32 +158,32 @@ describe('Composite Identifier', () => { dob: '', name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); CompositeCustomRO.copyOf({} as CompositeCustomRO, d => { - // @ts-expect-error + // TODO: Uncomment below and update test // d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.tenant; - // @ts-expect-error + // TODO: Uncomment below and update test // d.tenant = ''; d.dob; - // @ts-expect-error + // TODO: Uncomment below and update test // d.dob = ''; d.name = ''; d.description = ''; d.createdOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdOn = ''; d.updatedOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedOn = ''; }); }); diff --git a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/custom-identifier.test.tsx b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/custom-identifier.test.tsx index 789217c7229..29ed64c4d8d 100644 --- a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/custom-identifier.test.tsx +++ b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/custom-identifier.test.tsx @@ -28,29 +28,29 @@ describe('Custom Identifier', () => { myId: '', name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); CustomIdentifierDefaultRO.copyOf({} as CustomIdentifierDefaultRO, d => { - // @ts-expect-error + // TODO: Uncomment below and update test // d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.myId; - // @ts-expect-error + // TODO: Uncomment below and update test // d.myId = ''; d.name = ''; d.description = ''; d.createdAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdAt = ''; d.updatedAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedAt = ''; }); }); @@ -76,29 +76,29 @@ describe('Custom Identifier', () => { myId: '', name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); CustomIdentifierCustomRO.copyOf({} as CustomIdentifierCustomRO, d => { - // @ts-expect-error + // TODO: Uncomment below and update test // d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.myId; - // @ts-expect-error + // TODO: Uncomment below and update test // d.myId = ''; d.name = ''; d.description = ''; d.createdOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdOn = ''; d.updatedOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedOn = ''; }); }); diff --git a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/legacy-backwards-compatibility.test.tsx b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/legacy-backwards-compatibility.test.tsx index 47e908ed12a..95bc7c9f5b2 100644 --- a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/legacy-backwards-compatibility.test.tsx +++ b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/legacy-backwards-compatibility.test.tsx @@ -19,7 +19,7 @@ import { describe('Legacy - backwards compatibility', () => { test(`LegacyNoMetadata`, async () => { expectType>({ - // @ts-expect-error + // TODO: Uncomment below and update test // id: '234', name: '', description: '', @@ -28,7 +28,7 @@ describe('Legacy - backwards compatibility', () => { expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); @@ -40,7 +40,7 @@ describe('Legacy - backwards compatibility', () => { LegacyNoMetadata.copyOf({} as LegacyNoMetadata, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; @@ -139,7 +139,7 @@ describe('Legacy - backwards compatibility', () => { test(`LegacyDefaultRO`, async () => { expectType>({ - // @ts-expect-error + // TODO: Uncomment below and update test // id: '234', name: '', description: '', @@ -148,24 +148,24 @@ describe('Legacy - backwards compatibility', () => { expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); LegacyDefaultRO.copyOf({} as LegacyDefaultRO, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; d.description = ''; d.createdAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdAt = ''; d.updatedAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedAt = ''; }); @@ -246,7 +246,7 @@ describe('Legacy - backwards compatibility', () => { test(`LegacyCustomRO`, async () => { expectType>({ - // @ts-expect-error + // TODO: Uncomment below and update test // id: '234', name: '', description: '', @@ -255,37 +255,37 @@ describe('Legacy - backwards compatibility', () => { expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // createdOn: '', }); expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // createdAt: '', }); LegacyCustomRO.copyOf({} as LegacyCustomRO, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; d.description = ''; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedAt; d.createdOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdOn = ''; d.updatedOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedOn = ''; }); @@ -366,7 +366,7 @@ describe('Legacy - backwards compatibility', () => { test(`CustomIdentifierNoRO`, async () => { expectType>({ - // @ts-expect-error + // TODO: Uncomment below and update test // id: '234', myId: '23342', name: '', @@ -389,7 +389,7 @@ describe('Legacy - backwards compatibility', () => { CustomIdentifierNoRO.copyOf({} as CustomIdentifierNoRO, d => { d.myId; - // @ts-expect-error + // TODO: Uncomment below and update test // d.myId = ''; d.name = ''; @@ -401,10 +401,10 @@ describe('Legacy - backwards compatibility', () => { d.updatedAt; d.updatedAt = ''; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedOn; }); diff --git a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/managed-identifier.test.tsx b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/managed-identifier.test.tsx index c7da71e89c5..2e847e6caf6 100644 --- a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/managed-identifier.test.tsx +++ b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/managed-identifier.test.tsx @@ -15,7 +15,7 @@ import { describe('Managed Identifier', () => { test(`ManagedDefaultRO`, async () => { expectType>({ - // @ts-expect-error + // TODO: Uncomment below and update test // id: 'eeeeeee', name: '', description: '', @@ -24,31 +24,31 @@ describe('Managed Identifier', () => { expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); ManagedDefaultRO.copyOf({} as ManagedDefaultRO, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; d.description = ''; d.createdAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdAt = ''; d.updatedAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedAt = ''; }); @@ -134,7 +134,7 @@ describe('Managed Identifier', () => { test(`ManagedCustomRO`, async () => { expectType>({ - // @ts-expect-error + // TODO: Uncomment below and update test // id: 'eeeeeee', name: '', description: '', @@ -143,31 +143,31 @@ describe('Managed Identifier', () => { expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); expectType>({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); ManagedCustomRO.copyOf({} as ManagedCustomRO, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; d.description = ''; d.createdOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdOn = ''; d.updatedOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedOn = ''; }); diff --git a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/optionally-managed-identifier.test.tsx b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/optionally-managed-identifier.test.tsx index 2162e2d793e..5c7e1192b34 100644 --- a/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/optionally-managed-identifier.test.tsx +++ b/packages/datastore/__tests__/custom-pk-typings/model-init-mutable-model-typings/optionally-managed-identifier.test.tsx @@ -34,7 +34,7 @@ describe('Optionally Managed Identifier', () => { >({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); @@ -46,24 +46,24 @@ describe('Optionally Managed Identifier', () => { >({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); OptionallyManagedDefaultRO.copyOf({} as OptionallyManagedDefaultRO, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; d.description = ''; d.createdAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdAt = ''; d.updatedAt; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedAt = ''; }); @@ -186,7 +186,7 @@ describe('Optionally Managed Identifier', () => { >({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); @@ -198,24 +198,24 @@ describe('Optionally Managed Identifier', () => { >({ name: '', description: '', - // @ts-expect-error + // TODO: Uncomment below and update test // x: 234, }); OptionallyManagedCustomRO.copyOf({} as OptionallyManagedCustomRO, d => { d.id; - // @ts-expect-error + // TODO: Uncomment below and update test // d.id = ''; d.name = ''; d.description = ''; d.createdOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.createdOn = ''; d.updatedOn; - // @ts-expect-error + // TODO: Uncomment below and update test // d.updatedOn = ''; }); diff --git a/packages/datastore/__tests__/graphql.ts b/packages/datastore/__tests__/graphql.test.ts similarity index 100% rename from packages/datastore/__tests__/graphql.ts rename to packages/datastore/__tests__/graphql.test.ts diff --git a/packages/datastore/__tests__/indexeddb.test.ts b/packages/datastore/__tests__/indexeddb.test.ts index 24c39005836..f56740420cd 100644 --- a/packages/datastore/__tests__/indexeddb.test.ts +++ b/packages/datastore/__tests__/indexeddb.test.ts @@ -25,7 +25,7 @@ import { let db: idb.IDBPDatabase; const DB_VERSION = 3; -const indexedDB = require('fake-indexeddb'); +const { indexedDB } = require('fake-indexeddb'); const IDBKeyRange = require('fake-indexeddb/lib/FDBKeyRange'); Dexie.dependencies.indexedDB = indexedDB; Dexie.dependencies.IDBKeyRange = IDBKeyRange; @@ -317,7 +317,8 @@ describe('Indexed db storage test', () => { expect(q1Post!.id).toEqual(p.id); }); - test('query lazily HAS_ONE/BELONGS_TO with explicit Field', async done => { + test('query lazily HAS_ONE/BELONGS_TO with explicit Field', async () => { + expect.assertions(1); const team1 = new Team({ name: 'team' }); const savedTeam = await DataStore.save(team1); const project1 = new Project({ @@ -329,9 +330,8 @@ describe('Indexed db storage test', () => { await DataStore.save(project1); const q1 = (await DataStore.query(Project, project1.id))!; - q1.team.then(value => { + return q1.team.then(value => { expect(value!.id).toEqual(team1.id); - done(); }); }); @@ -756,7 +756,8 @@ describe('AsyncCollection toArray Test', () => { expected: [0, 1, 2], }, ].forEach(Parameter => { - test(`Testing input of ${Parameter.input}`, async done => { + test(`Testing input of ${Parameter.input}`, async () => { + expect.assertions(1); const { input, expected } = Parameter; const album1 = new Album({ name: "Lupe Fiasco's The Cool", @@ -789,9 +790,8 @@ describe('AsyncCollection toArray Test', () => { for (const num of expected) { expectedValues.push(songsArray[num]); } - songs.toArray(input).then(value => { + return songs.toArray(input).then(value => { expect(value).toStrictEqual(expectedValues); - done(); }); }); }); @@ -809,7 +809,7 @@ describe('DB versions migration', () => { const blob = new Blob([JSON.stringify(v1Data)], { type: 'application/json', - }); + } as any); // Import V1 (await Dexie.import(blob)).close(); diff --git a/packages/datastore/__tests__/indexeddb.upgrade.test.ts b/packages/datastore/__tests__/indexeddb.upgrade.test.ts index e2c8e1a2fb9..8f1827f9d77 100644 --- a/packages/datastore/__tests__/indexeddb.upgrade.test.ts +++ b/packages/datastore/__tests__/indexeddb.upgrade.test.ts @@ -14,7 +14,7 @@ import { Schema } from '../src/types'; const DB_VERSION = 3; let db: idb.IDBPDatabase; -const indexedDB = require('fake-indexeddb'); +const { indexedDB } = require('fake-indexeddb'); const IDBKeyRange = require('fake-indexeddb/lib/FDBKeyRange'); Dexie.dependencies.indexedDB = indexedDB; Dexie.dependencies.IDBKeyRange = IDBKeyRange; @@ -82,7 +82,7 @@ describe('DB versions migration with destructive schema change', () => { const blob = new Blob([JSON.stringify(v1Data)], { type: 'application/json', - }); + } as any); // Import V1 (await Dexie.import(blob)).close(); diff --git a/packages/datastore/__tests__/mutation.test.ts b/packages/datastore/__tests__/mutation.test.ts index 82150a08cac..458b6360b40 100644 --- a/packages/datastore/__tests__/mutation.test.ts +++ b/packages/datastore/__tests__/mutation.test.ts @@ -1,14 +1,7 @@ -const mockRestPost = jest.fn(() => { - return Promise.reject(serverError); -}); - -jest.mock('@aws-amplify/api/internals', () => { - const apiInternals = jest.requireActual('@aws-amplify/api/internals'); - apiInternals.InternalAPI._graphqlApi._api.post = mockRestPost; - return { - ...apiInternals, - }; +const mockRetry = jest.fn(async (fn, args) => { + await fn(...args); }); +const mockRestPost = jest.fn(() => Promise.reject(serverError)); import { Amplify } from '@aws-amplify/core'; @@ -37,6 +30,21 @@ import { import { createMutationInstanceFromModelOperation } from '../src/sync/utils'; import { SyncEngine, MutationEvent } from '../src/sync/'; +jest.mock('@aws-amplify/api/internals', () => { + const apiInternals = jest.requireActual('@aws-amplify/api/internals'); + apiInternals.InternalAPI._graphqlApi._api.post = mockRestPost; + return { + ...apiInternals, + }; +}); +// mocking jitteredBackoff to prevent it from retrying +// endlessly in the mutation processor and so that we can expect the thrown result in our test +// should throw a Network Error +jest.mock('@aws-amplify/core/internals/utils', () => ({ + ...jest.requireActual('@aws-amplify/core/internals/utils'), + retry: mockRetry, +})); + let syncClasses: any; let modelInstanceCreator: any; let Model: PersistentModelConstructor; @@ -304,20 +312,6 @@ describe('error handler', () => { }); }); -// mocking jitteredBackoff to prevent it from retrying -// endlessly in the mutation processor and so that we can expect the thrown result in our test -// should throw a Network Error -let mockRetry; -jest.mock('@aws-amplify/core/internals/utils', () => { - mockRetry = jest.fn().mockImplementation(async (fn, args) => { - await fn(...args); - }); - return { - ...jest.requireActual('@aws-amplify/core/internals/utils'), - retry: mockRetry, - }; -}); - // Mocking just enough dependencies for us to be able to // instantiate a working MutationProcessor // includes functional mocked outbox containing a single MutationEvent diff --git a/packages/datastore/__tests__/utils.test.ts b/packages/datastore/__tests__/utils.test.ts index 27a422ff683..c8e7aa4528e 100644 --- a/packages/datastore/__tests__/utils.test.ts +++ b/packages/datastore/__tests__/utils.test.ts @@ -484,14 +484,14 @@ _deleted`; limitTimerRace.start(); - expect(spyOnRace).toBeCalledTimes(1); + expect(spyOnRace).toHaveBeenCalledTimes(1); limitTimerRace.resolve(); const winner = await spyOnRace.mock.results[0].value; expect(winner).toEqual(LimitTimerRaceResolvedValues.LIMIT); expect(limitTimerRace.raceInFlight).toBe(false); - expect(limitTimerRaceCallback).toBeCalledTimes(1); + expect(limitTimerRaceCallback).toHaveBeenCalledTimes(1); limitTimerRace.clear(); }); @@ -512,13 +512,13 @@ _deleted`; limitTimerRace.start(); - expect(spyOnRace).toBeCalledTimes(1); + expect(spyOnRace).toHaveBeenCalledTimes(1); const winner = await spyOnRace.mock.results[0].value; expect(winner).toEqual(LimitTimerRaceResolvedValues.TIMER); expect(limitTimerRace.raceInFlight).toBe(false); - expect(limitTimerRaceCallback).toBeCalledTimes(1); + expect(limitTimerRaceCallback).toHaveBeenCalledTimes(1); limitTimerRace.clear(); }); @@ -545,11 +545,11 @@ _deleted`; limitTimerRace.start(); - expect(spyOnRace).toBeCalledTimes(1); + expect(spyOnRace).toHaveBeenCalledTimes(1); - expect(spyOnErrorHandler).toThrowError('DeferredCallbackResolver error'); + expect(spyOnErrorHandler).toThrow('DeferredCallbackResolver error'); - expect(limitTimerRaceCallback).toBeCalledTimes(0); + expect(limitTimerRaceCallback).toHaveBeenCalledTimes(0); limitTimerRace.clear(); }); @@ -582,11 +582,11 @@ _deleted`; limitTimerRace.start(); - expect(spyOnRace).toBeCalledTimes(1); + expect(spyOnRace).toHaveBeenCalledTimes(1); - expect(spyOnErrorHandler).toThrowError(customErrorMsg); + expect(spyOnErrorHandler).toThrow(customErrorMsg); - expect(limitTimerRaceCallback).toBeCalledTimes(0); + expect(limitTimerRaceCallback).toHaveBeenCalledTimes(0); limitTimerRace.clear(); }); diff --git a/packages/datastore/jest.config.js b/packages/datastore/jest.config.js new file mode 100644 index 00000000000..f15b76e5c41 --- /dev/null +++ b/packages/datastore/jest.config.js @@ -0,0 +1,15 @@ +module.exports = { + ...require('../../jest.config'), + moduleNameMapper: { + ...require('../../jest.config').moduleNameMapper, + '^dexie$': require.resolve('dexie'), + }, + coverageThreshold: { + global: { + branches: 82, + functions: 94, + lines: 89, + statements: 89, + }, + }, +}; diff --git a/packages/datastore/jest.setup.js b/packages/datastore/jest.setup.js deleted file mode 100644 index a0f3d5370fa..00000000000 --- a/packages/datastore/jest.setup.js +++ /dev/null @@ -1,7 +0,0 @@ -const crypto = require('crypto'); - -Object.defineProperty(globalThis, 'crypto', { - value: { - getRandomValues: arr => crypto.randomBytes(arr.length), - }, -}); diff --git a/packages/datastore/package.json b/packages/datastore/package.json index 170d8c984d3..011ed7cd25f 100644 --- a/packages/datastore/package.json +++ b/packages/datastore/package.json @@ -61,7 +61,7 @@ "@types/uuid-validate": "^0.0.1", "dexie": "3.2.2", "dexie-export-import": "1.0.3", - "fake-indexeddb": "3.0.0", + "fake-indexeddb": "^4.0.2", "graphql": "15.8.0", "rollup": "3.29.4", "typescript": "5.0.2" @@ -73,62 +73,5 @@ "import": "{ Amplify, DataStore }", "limit": "65.25 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": true, - "tsConfig": { - "lib": [ - "es5", - "es2015", - "dom", - "esnext.asynciterable", - "es2019" - ], - "target": "es5", - "allowJs": true, - "esModuleInterop": true, - "strictNullChecks": false, - "types": [ - "@types/jest" - ] - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "__tests__/model.ts", - "__tests__/schema.ts", - "__tests__/helpers/", - "__tests__/commonAdapterTests.ts" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "dist" - ], - "setupFilesAfterEnv": [ - "/jest.setup.js" - ] - } + ] } diff --git a/packages/geo/__tests__/util.test.ts b/packages/geo/__tests__/util.test.ts index e067bf3bbee..c02d46d8b7b 100644 --- a/packages/geo/__tests__/util.test.ts +++ b/packages/geo/__tests__/util.test.ts @@ -35,13 +35,13 @@ describe('Geo utility functions', () => { describe('validateCoordinates', () => { test('should not throw an error for valid coordinates', () => { validLinearRing.forEach(([lng, lat]) => { - expect(() => validateCoordinates(lng, lat)).not.toThrowError(); + expect(() => validateCoordinates(lng, lat)).not.toThrow(); }); }); test('should error with message for bad longitude', () => { invalidLngCoordinates.forEach(([lng, lat]) => { - expect(() => validateCoordinates(lng, lat)).toThrowError( + expect(() => validateCoordinates(lng, lat)).toThrow( 'Longitude must be between -180 and 180 degrees inclusive.' ); }); @@ -49,7 +49,7 @@ describe('Geo utility functions', () => { test('should error with message for bad latitude', () => { invalidLatCoordinates.forEach(([lng, lat]) => { - expect(() => validateCoordinates(lng, lat)).toThrowError( + expect(() => validateCoordinates(lng, lat)).toThrow( 'Latitude must be between -90 and 90 degrees inclusive.' ); }); @@ -57,7 +57,7 @@ describe('Geo utility functions', () => { test('should error with message for coordinates with infinity', () => { infiniteCoordinates.forEach(([lng, lat]) => { - expect(() => validateCoordinates(lng, lat)).toThrowError( + expect(() => validateCoordinates(lng, lat)).toThrow( `Invalid coordinates: [${lng},${lat}]` ); }); @@ -67,33 +67,33 @@ describe('Geo utility functions', () => { describe('validateLinearRing', () => { test('should not throw an error for a valid LinearRing', () => { const result = validateLinearRing(validLinearRing); - expect(() => result).not.toThrowError(); + expect(() => result).not.toThrow(); }); test('should error if first and last coordinates do not match', () => { expect(() => validateLinearRing(linearRingIncomplete, 'linearRingIncomplete') - ).toThrowError( + ).toThrow( `linearRingIncomplete: LinearRing's first and last coordinates are not the same` ); }); test('should error if LinearRing has less than 4 elements', () => { expect(() => validateLinearRing(linearRingTooSmall, 'linearRingTooSmall') - ).toThrowError( + ).toThrow( 'linearRingTooSmall: LinearRing must contain 4 or more coordinates.' ); }); test('should error if any coordinates are not valid', () => { expect(() => validateLinearRing(linearRingBadCoordinates, 'linearRingBadCoordinates') - ).toThrowError( + ).toThrow( 'linearRingBadCoordinates: One or more of the coordinates in the Polygon LinearRing are not valid: [{"coordinates":[181,0],"error":"Longitude must be between -180 and 180 degrees inclusive."},{"coordinates":[0,-91],"error":"Latitude must be between -90 and 90 degrees inclusive."}]' ); }); test('should error if the coordinates are not in counterclockwise order', () => { expect(() => validateLinearRing(clockwiseLinearRing, 'clockwiseLinearRing') - ).toThrowError( + ).toThrow( 'clockwiseLinearRing: LinearRing coordinates must be wound counterclockwise' ); }); @@ -101,22 +101,20 @@ describe('Geo utility functions', () => { describe('validatePolygon', () => { test('should not throw an error for a valid Polygon', () => { - expect(() => validatePolygon(validPolygon)).not.toThrowError(); + expect(() => validatePolygon(validPolygon)).not.toThrow(); }); test('should error if polygon is not a length of 1', () => { - expect(() => - validatePolygon(polygonTooBig, 'polygonTooBig') - ).toThrowError( + expect(() => validatePolygon(polygonTooBig, 'polygonTooBig')).toThrow( `polygonTooBig: Polygon must have a single LinearRing array. Note: We do not currently support polygons with holes, multipolygons, polygons that are wound clockwise, or that cross the antimeridian.` ); - expect(() => validatePolygon([], 'emptyPolygon')).toThrowError( + expect(() => validatePolygon([], 'emptyPolygon')).toThrow( `emptyPolygon: Polygon must have a single LinearRing array.` ); }); test('should error if polygon has more than 1000 vertices', () => { expect(() => validatePolygon(polygonTooManyVertices, 'polygonTooManyVertices') - ).toThrowError( + ).toThrow( 'polygonTooManyVertices: Polygon has more than the maximum 1000 vertices.' ); }); @@ -124,58 +122,56 @@ describe('Geo utility functions', () => { describe('validateGeofenceId', () => { test('should not throw an error for a geofence ID with letters and numbers', () => { - expect(() => validateGeofenceId('ExampleGeofence1')).not.toThrowError(); + expect(() => validateGeofenceId('ExampleGeofence1')).not.toThrow(); }); test('should not throw an error for a geofence ID with a dash', () => { - expect(() => validateGeofenceId('ExampleGeofence-1')).not.toThrowError(); + expect(() => validateGeofenceId('ExampleGeofence-1')).not.toThrow(); }); test('should not throw an error for a geofence ID with a period', () => { - expect(() => validateGeofenceId('ExampleGeofence.1')).not.toThrowError(); + expect(() => validateGeofenceId('ExampleGeofence.1')).not.toThrow(); }); test('should not throw an error for a geofence ID with an underscore', () => { - expect(() => validateGeofenceId('ExampleGeofence_1')).not.toThrowError(); + expect(() => validateGeofenceId('ExampleGeofence_1')).not.toThrow(); }); test('should not throw an error for a geofence ID with non-basic Latin character', () => { - expect(() => validateGeofenceId('ExampleGeòfence-1')).not.toThrowError(); + expect(() => validateGeofenceId('ExampleGeòfence-1')).not.toThrow(); }); test('should not throw an error for a geofence ID with superscript and subscript numbers', () => { - expect(() => validateGeofenceId('ExampleGeofence-⁴₆')).not.toThrowError(); + expect(() => validateGeofenceId('ExampleGeofence-⁴₆')).not.toThrow(); }); test('should throw an error for an empty string', () => { - expect(() => validateGeofenceId('')).toThrowError(); + expect(() => validateGeofenceId('')).toThrow(); }); test('should throw an error for a geofence ID with an invalid character', () => { - expect(() => validateGeofenceId('ExampleGeofence-1&')).toThrowError(); + expect(() => validateGeofenceId('ExampleGeofence-1&')).toThrow(); }); }); describe('validateGeofencesInput', () => { test('should not throw an error for valid geofences', () => { const result = validateGeofencesInput(validGeofences); - expect(() => result).not.toThrowError(); + expect(() => result).not.toThrow(); }); test('should error if a geofenceId is not unique', () => { - expect(() => validateGeofencesInput(geofencesWithDuplicate)).toThrowError( + expect(() => validateGeofencesInput(geofencesWithDuplicate)).toThrow( `Duplicate geofenceId: validGeofenceId1` ); }); test('should error if a geofenceId is not valid', () => { - expect(() => validateGeofencesInput(geofencesWithInvalidId)).toThrowError( + expect(() => validateGeofencesInput(geofencesWithInvalidId)).toThrow( `Invalid geofenceId: 't|-|!$ !$ N()T V@|_!D' - IDs can only contain alphanumeric characters, hyphens, underscores and periods.` ); }); }); test('should error if polygon has more than 1000 vertices', () => { - expect(() => - validateGeofencesInput([geofenceWithTooManyVertices]) - ).toThrowError( + expect(() => validateGeofencesInput([geofenceWithTooManyVertices])).toThrow( `Geofence 'geofenceWithTooManyVertices' has more than the maximum of 1000 vertices` ); }); @@ -225,7 +221,7 @@ describe('Geo utility functions', () => { biasPosition: [12345, 67890], searchAreaConstraints: [123, 456, 789, 321], }; - expect(() => mapSearchOptions(searchOptionsExtended, {})).toThrowError( + expect(() => mapSearchOptions(searchOptionsExtended, {})).toThrow( `BiasPosition and SearchAreaConstraints are mutually exclusive, please remove one or the other from the options object` ); }); diff --git a/packages/geo/jest.config.js b/packages/geo/jest.config.js new file mode 100644 index 00000000000..793f297724a --- /dev/null +++ b/packages/geo/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 86, + functions: 95, + lines: 89, + statements: 89, + }, + }, + moduleNameMapper: { + uuid: require.resolve('uuid'), + }, +}; diff --git a/packages/geo/package.json b/packages/geo/package.json index faaf4d5f554..10a071b514c 100644 --- a/packages/geo/package.json +++ b/packages/geo/package.json @@ -88,57 +88,5 @@ "import": "{ Amplify, Geo }", "limit": "43.9 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": true, - "tsConfig": { - "lib": [ - "es5", - "es2015", - "dom", - "esnext.asynciterable", - "es2019.object" - ], - "allowJs": true, - "noEmitOnError": false, - "esModuleInterop": true, - "downlevelIteration": true - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "__tests__/model.ts", - "__tests__/schema.ts", - "__tests__/helpers.ts", - "__tests__/testData.ts", - "__tests__/testUtils.ts" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ] - } + ] } diff --git a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts index 89e7369d429..051c2aa8029 100644 --- a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts +++ b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts @@ -369,19 +369,19 @@ describe('Interactions', () => { provider.onComplete(botConfig.BookTrip, inProgressCallback); provider.reportBotStatus(inProgressResp, botConfig.BookTrip); jest.runAllTimers(); - expect(inProgressCallback).toBeCalledTimes(0); + expect(inProgressCallback).toHaveBeenCalledTimes(0); // 2. task complete; success, callback be called with response provider.onComplete(botConfig.BookTrip, completeSuccessCallback); provider.reportBotStatus(completeSuccessResp, botConfig.BookTrip); jest.runAllTimers(); - expect(completeSuccessCallback).toBeCalledTimes(1); + expect(completeSuccessCallback).toHaveBeenCalledTimes(1); // 3. task complete; error, callback be called with error provider.onComplete(botConfig.BookTrip, completeFailCallback); provider.reportBotStatus(completeFailResp, botConfig.BookTrip); jest.runAllTimers(); - expect(completeFailCallback).toBeCalledTimes(1); + expect(completeFailCallback).toHaveBeenCalledTimes(1); expect.assertions(6); }); }); diff --git a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts b/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts index 6283055ae74..76d40ae7d10 100644 --- a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid'; import { lexProvider } from '../../../src/lex-v1/AWSLexProvider'; import { onComplete } from '../../../src/lex-v1/apis'; -import { generateRandomLexV1Config } from '../../testUtils/randomConfigGeneration.test'; +import { generateRandomLexV1Config } from '../../testUtils/randomConfigGeneration'; import { resolveBotConfig } from '../../../src/lex-v1/utils'; import { InteractionsError } from '../../../src/errors/InteractionsError'; @@ -30,8 +30,8 @@ describe('Interactions LexV1 API: onComplete', () => { const message = uuid(); const mockCallback = jest.fn(); onComplete({ botName: v1BotConfig.name, callback: mockCallback }); - expect(mockLexProvider).toBeCalledTimes(1); - expect(mockLexProvider).toBeCalledWith(v1BotConfig, mockCallback); + expect(mockLexProvider).toHaveBeenCalledTimes(1); + expect(mockLexProvider).toHaveBeenCalledWith(v1BotConfig, mockCallback); }); it('rejects when bot config does not exist', async () => { diff --git a/packages/interactions/__tests__/lex-v1/apis/send.test.ts b/packages/interactions/__tests__/lex-v1/apis/send.test.ts index 52d53a6f88e..63f3393f45d 100644 --- a/packages/interactions/__tests__/lex-v1/apis/send.test.ts +++ b/packages/interactions/__tests__/lex-v1/apis/send.test.ts @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid'; import { lexProvider } from '../../../src/lex-v1/AWSLexProvider'; import { send } from '../../../src/lex-v1/apis'; -import { generateRandomLexV1Config } from '../../testUtils/randomConfigGeneration.test'; +import { generateRandomLexV1Config } from '../../testUtils/randomConfigGeneration'; import { resolveBotConfig } from '../../../src/lex-v1/utils'; import { InteractionsError } from '../../../src/errors/InteractionsError'; @@ -29,8 +29,8 @@ describe('Interactions LexV1 API: send', () => { it('invokes provider sendMessage API', async () => { const message = uuid(); await send({ botName: v1BotConfig.name, message }); - expect(mockLexProvider).toBeCalledTimes(1); - expect(mockLexProvider).toBeCalledWith(v1BotConfig, message); + expect(mockLexProvider).toHaveBeenCalledTimes(1); + expect(mockLexProvider).toHaveBeenCalledWith(v1BotConfig, message); }); it('rejects when bot config does not exist', async () => { diff --git a/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts b/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts index a95305acf24..59c648f5d08 100644 --- a/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts +++ b/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts @@ -5,7 +5,7 @@ import { Amplify } from '@aws-amplify/core'; import { generateRandomLexV1Config, generateRandomLexV2Config, -} from '../../testUtils/randomConfigGeneration.test'; +} from '../../testUtils/randomConfigGeneration'; import { resolveBotConfig } from '../../../src/lex-v1/utils'; describe('Interactions LexV1 Util: resolveBotConfig', () => { diff --git a/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts b/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts index 8e085f69583..4f5c526edd7 100644 --- a/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts +++ b/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts @@ -479,7 +479,7 @@ describe('Interactions', () => { ); jest.runAllTimers(); - expect(inProgressCallback).toBeCalledTimes(0); + expect(inProgressCallback).toHaveBeenCalledTimes(0); expect.assertions(1); }); @@ -496,7 +496,7 @@ describe('Interactions', () => { ); jest.runAllTimers(); - expect(completeSuccessCallback).toBeCalledTimes(1); + expect(completeSuccessCallback).toHaveBeenCalledTimes(1); // 2 assertions from callback expect.assertions(3); }); @@ -512,7 +512,7 @@ describe('Interactions', () => { ); jest.runAllTimers(); - expect(completeFailCallback).toBeCalledTimes(1); + expect(completeFailCallback).toHaveBeenCalledTimes(1); // 1 assertion from callback expect.assertions(2); }); diff --git a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts b/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts index 63cc502e412..c81b120693c 100644 --- a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid'; import { lexProvider } from '../../../src/lex-v2/AWSLexV2Provider'; import { onComplete } from '../../../src/lex-v2/apis'; -import { generateRandomLexV2Config } from '../../testUtils/randomConfigGeneration.test'; +import { generateRandomLexV2Config } from '../../testUtils/randomConfigGeneration'; import { resolveBotConfig } from '../../../src/lex-v2/utils'; import { InteractionsError } from '../../../src/errors/InteractionsError'; @@ -30,8 +30,8 @@ describe('Interactions LexV2 API: onComplete', () => { const message = uuid(); const mockCallback = jest.fn(); onComplete({ botName: v2BotConfig.name, callback: mockCallback }); - expect(mockLexProvider).toBeCalledTimes(1); - expect(mockLexProvider).toBeCalledWith(v2BotConfig, mockCallback); + expect(mockLexProvider).toHaveBeenCalledTimes(1); + expect(mockLexProvider).toHaveBeenCalledWith(v2BotConfig, mockCallback); }); it('rejects when bot config does not exist', async () => { diff --git a/packages/interactions/__tests__/lex-v2/apis/send.test.ts b/packages/interactions/__tests__/lex-v2/apis/send.test.ts index 9ecbbdd6556..6d6ec998127 100644 --- a/packages/interactions/__tests__/lex-v2/apis/send.test.ts +++ b/packages/interactions/__tests__/lex-v2/apis/send.test.ts @@ -4,7 +4,7 @@ import { v4 as uuid } from 'uuid'; import { lexProvider } from '../../../src/lex-v2/AWSLexV2Provider'; import { send } from '../../../src/lex-v2/apis'; -import { generateRandomLexV2Config } from '../../testUtils/randomConfigGeneration.test'; +import { generateRandomLexV2Config } from '../../testUtils/randomConfigGeneration'; import { resolveBotConfig } from '../../../src/lex-v2/utils'; import { InteractionsError } from '../../../src/errors/InteractionsError'; @@ -29,8 +29,8 @@ describe('Interactions LexV2 API: send', () => { it('invokes provider sendMessage API', async () => { const message = uuid(); await send({ botName: v2BotConfig.name, message }); - expect(mockLexProvider).toBeCalledTimes(1); - expect(mockLexProvider).toBeCalledWith(v2BotConfig, message); + expect(mockLexProvider).toHaveBeenCalledTimes(1); + expect(mockLexProvider).toHaveBeenCalledWith(v2BotConfig, message); }); it('rejects when bot config does not exist', async () => { diff --git a/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts b/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts index d9f056d9a29..ff36b7f6c85 100644 --- a/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts +++ b/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts @@ -5,7 +5,7 @@ import { Amplify } from '@aws-amplify/core'; import { generateRandomLexV1Config, generateRandomLexV2Config, -} from '../../testUtils/randomConfigGeneration.test'; +} from '../../testUtils/randomConfigGeneration'; import { resolveBotConfig } from '../../../src/lex-v2/utils'; describe('Interactions LexV2 Util: resolveBotConfig', () => { diff --git a/packages/interactions/__tests__/testUtils/randomConfigGeneration.test.ts b/packages/interactions/__tests__/testUtils/randomConfigGeneration.ts similarity index 100% rename from packages/interactions/__tests__/testUtils/randomConfigGeneration.test.ts rename to packages/interactions/__tests__/testUtils/randomConfigGeneration.ts diff --git a/packages/interactions/jest.config.js b/packages/interactions/jest.config.js new file mode 100644 index 00000000000..73540b7bc7e --- /dev/null +++ b/packages/interactions/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 78, + functions: 94, + lines: 96, + statements: 96, + }, + }, + moduleNameMapper: { + uuid: require.resolve('uuid'), + }, +}; diff --git a/packages/interactions/package.json b/packages/interactions/package.json index f7a67ddace3..1efbb5a934d 100644 --- a/packages/interactions/package.json +++ b/packages/interactions/package.json @@ -105,44 +105,5 @@ "import": "{ Interactions }", "limit": "47.00 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testPathIgnorePatterns": [ - "/testUtils/" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ] - } + ] } diff --git a/packages/notifications/__tests__/eventListeners/eventListeners.test.ts b/packages/notifications/__tests__/eventListeners/eventListeners.test.ts index 0d73683685b..9ac105ea41e 100644 --- a/packages/notifications/__tests__/eventListeners/eventListeners.test.ts +++ b/packages/notifications/__tests__/eventListeners/eventListeners.test.ts @@ -31,7 +31,7 @@ describe('Event listeners', () => { addEventListener(eventType, mockHandler); notifyEventListeners(eventType, params); - expect(mockHandler).toBeCalledWith(params); + expect(mockHandler).toHaveBeenCalledWith(params); }); it('can be notified and awaited on', async () => { @@ -41,7 +41,7 @@ describe('Event listeners', () => { try { await notifyEventListenersAndAwaitHandlers(eventType, params); - expect(mockHandler).toBeCalledWith(params); + expect(mockHandler).toHaveBeenCalledWith(params); } catch (e) {} expect.assertions(1); @@ -57,7 +57,7 @@ describe('Event listeners', () => { await expect( notifyEventListenersAndAwaitHandlers(eventType, params) ).rejects.toThrow(); - expect(mockHandler).toBeCalledWith(params); + expect(mockHandler).toHaveBeenCalledWith(params); }); it('can handle multiple parameters', () => { @@ -66,7 +66,7 @@ describe('Event listeners', () => { addEventListener(eventType, mockHandler); notifyEventListeners(eventType, param1, param2); - expect(mockHandler).toBeCalledWith(param1, param2); + expect(mockHandler).toHaveBeenCalledWith(param1, param2); }); it('can be removed', () => { @@ -75,7 +75,7 @@ describe('Event listeners', () => { listener.remove(); notifyEventListeners(eventType); - expect(mockHandler).not.toBeCalled(); + expect(mockHandler).not.toHaveBeenCalled(); }); it('can be added in multiples', () => { @@ -93,11 +93,11 @@ describe('Event listeners', () => { notifyEventListeners(bazType); // two listeners added - expect(mockHandler).toBeCalledTimes(2); + expect(mockHandler).toHaveBeenCalledTimes(2); // listener added but not notified - expect(barHandler).toBeCalledTimes(0); + expect(barHandler).toHaveBeenCalledTimes(0); // one listener added - expect(bazHandler).toBeCalledTimes(1); + expect(bazHandler).toHaveBeenCalledTimes(1); }); it('will not error out on an unregistered type', async () => { diff --git a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/clearMessages.test.ts b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/clearMessages.test.ts index 870541da5a6..faffa251ee5 100644 --- a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/clearMessages.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/clearMessages.test.ts @@ -28,7 +28,7 @@ describe('clearMessages', () => { await expect(clearMessages()).rejects.toStrictEqual( expect.any(InAppMessagingError) ); - expect(mockDefaultStorage.removeItem).not.toBeCalled(); + expect(mockDefaultStorage.removeItem).not.toHaveBeenCalled(); }); it('Rejects if there is a failure storing messages', async () => { @@ -47,7 +47,7 @@ describe('clearMessages', () => { it('Succeeds in calling the removeItem API of defaultStorage with the correct key', async () => { initializeInAppMessaging(); await clearMessages(); - expect(mockDefaultStorage.removeItem).toBeCalledWith( + expect(mockDefaultStorage.removeItem).toHaveBeenCalledWith( `${PINPOINT_KEY_PREFIX}${STORAGE_KEY_SUFFIX}` ); }); diff --git a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/dispatchEvent.test.ts b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/dispatchEvent.test.ts index a16c0dd6323..1cdadd7a343 100644 --- a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/dispatchEvent.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/dispatchEvent.test.ts @@ -38,11 +38,14 @@ describe('dispatchEvent', () => { ); mockProcessInAppMessages.mockReturnValueOnce([message]); await dispatchEvent(simpleInAppMessagingEvent); - expect(mockProcessInAppMessages).toBeCalledWith( + expect(mockProcessInAppMessages).toHaveBeenCalledWith( simpleInAppMessages, simpleInAppMessagingEvent ); - expect(mockNotifyEventListeners).toBeCalledWith('messageReceived', message); + expect(mockNotifyEventListeners).toHaveBeenCalledWith( + 'messageReceived', + message + ); }); it('handles conflicts through default conflict handler', async () => { @@ -51,11 +54,11 @@ describe('dispatchEvent', () => { ); mockProcessInAppMessages.mockReturnValueOnce(inAppMessages); await dispatchEvent(simpleInAppMessagingEvent); - expect(mockProcessInAppMessages).toBeCalledWith( + expect(mockProcessInAppMessages).toHaveBeenCalledWith( simpleInAppMessages, simpleInAppMessagingEvent ); - expect(mockNotifyEventListeners).toBeCalledWith( + expect(mockNotifyEventListeners).toHaveBeenCalledWith( 'messageReceived', inAppMessages[4] ); @@ -69,7 +72,7 @@ describe('dispatchEvent', () => { await dispatchEvent(simpleInAppMessagingEvent); - expect(mockNotifyEventListeners).not.toBeCalled(); + expect(mockNotifyEventListeners).not.toHaveBeenCalled(); }); it('logs error if storage retrieval fails', async () => { diff --git a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/identifyUser.test.ts b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/identifyUser.test.ts index ae0e9eb8a14..20e3e895f02 100644 --- a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/identifyUser.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/identifyUser.test.ts @@ -60,7 +60,7 @@ describe('InAppMessaging Pinpoint Provider API: identifyUser', () => { }, }; await identifyUser(input); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ ...input, ...credentials, ...config, @@ -82,7 +82,7 @@ describe('InAppMessaging Pinpoint Provider API: identifyUser', () => { userAttributes, }; await identifyUser({ ...input, options }); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ ...input, ...options, ...credentials, diff --git a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/interactionEvents.test.ts b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/interactionEvents.test.ts index eb42f25ca5f..23862aaf31d 100644 --- a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/interactionEvents.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/interactionEvents.test.ts @@ -28,25 +28,37 @@ describe('Interaction events', () => { it('can be listened to by onMessageReceived', () => { onMessageReceived(handler); - expect(mockAddEventListener).toBeCalledWith('messageReceived', handler); + expect(mockAddEventListener).toHaveBeenCalledWith( + 'messageReceived', + handler + ); }); it('can be listened to by onMessageDisplayed', () => { onMessageDisplayed(handler); - expect(mockAddEventListener).toBeCalledWith('messageDisplayed', handler); + expect(mockAddEventListener).toHaveBeenCalledWith( + 'messageDisplayed', + handler + ); }); it('can be listened to by onMessageDismissed', () => { onMessageDismissed(handler); - expect(mockAddEventListener).toBeCalledWith('messageDismissed', handler); + expect(mockAddEventListener).toHaveBeenCalledWith( + 'messageDismissed', + handler + ); }); it('can be listened to by onMessageActionTaken', () => { onMessageActionTaken(handler); - expect(mockAddEventListener).toBeCalledWith('messageActionTaken', handler); + expect(mockAddEventListener).toHaveBeenCalledWith( + 'messageActionTaken', + handler + ); }); it('can be notified by notifyMessageInteraction', () => { const [message] = inAppMessages; @@ -56,6 +68,9 @@ describe('Interaction events', () => { message, }); - expect(mockNotifyEventListeners).toBeCalledWith('messageReceived', message); + expect(mockNotifyEventListeners).toHaveBeenCalledWith( + 'messageReceived', + message + ); }); }); diff --git a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/setConflictHandler.test.ts b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/setConflictHandler.test.ts index cac7f3ad26c..e62915c8110 100644 --- a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/setConflictHandler.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/setConflictHandler.test.ts @@ -41,7 +41,7 @@ describe('setConflictHandler', () => { setConflictHandler(customConflictHandler); await dispatchEvent(simpleInAppMessagingEvent); - expect(mockNotifyEventListeners).toBeCalledWith( + expect(mockNotifyEventListeners).toHaveBeenCalledWith( 'messageReceived', customHandledMessage ); diff --git a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/syncMessages.test.ts b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/syncMessages.test.ts index 37bc2c90f72..db1e7cab106 100644 --- a/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/syncMessages.test.ts +++ b/packages/notifications/__tests__/inAppMessaging/providers/pinpoint/apis/syncMessages.test.ts @@ -75,7 +75,7 @@ describe('syncMessages', () => { it('Gets in-app messages and stores them', async () => { await syncMessages(); - expect(mockDefaultStorage.setItem).toBeCalledWith( + expect(mockDefaultStorage.setItem).toHaveBeenCalledWith( expect.stringContaining(STORAGE_KEY_SUFFIX), JSON.stringify(simpleInAppMessages) ); @@ -85,7 +85,7 @@ describe('syncMessages', () => { mockGetInAppMessages.mockResolvedValueOnce(mockedEmptyMessages); await syncMessages(); - expect(mockDefaultStorage.setItem).not.toBeCalled(); + expect(mockDefaultStorage.setItem).not.toHaveBeenCalled(); }); it('Rejects if there is a validation error', async () => { @@ -96,7 +96,7 @@ describe('syncMessages', () => { expect.any(InAppMessagingError) ); - expect(mockDefaultStorage.setItem).not.toBeCalled(); + expect(mockDefaultStorage.setItem).not.toHaveBeenCalled(); }); it('Rejects if there is a failure getting messages', async () => { @@ -105,7 +105,7 @@ describe('syncMessages', () => { expect.any(InAppMessagingError) ); - expect(mockDefaultStorage.setItem).not.toBeCalled(); + expect(mockDefaultStorage.setItem).not.toHaveBeenCalled(); }); it('Rejects if there is a failure storing messages', async () => { diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/identifyUser.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/identifyUser.native.test.ts index d3a732f119a..7d33fc9f19d 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/identifyUser.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/identifyUser.native.test.ts @@ -72,7 +72,7 @@ describe('identifyUser (native)', () => { }, }; await identifyUser(input); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ ...input, ...credentials, ...pinpointConfig, @@ -92,7 +92,7 @@ describe('identifyUser (native)', () => { userAttributes, }; await identifyUser({ ...input, options }); - expect(mockUpdateEndpoint).toBeCalledWith({ + expect(mockUpdateEndpoint).toHaveBeenCalledWith({ ...input, ...credentials, ...pinpointConfig, diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.test.ts index f02be854236..9e4d69a8ec0 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/initializePushNotifications.native.test.ts @@ -65,13 +65,13 @@ describe('initializePushNotifications (native)', () => { // helpers const expectListenerForEvent = (event: string) => ({ toBeAdded: () => { - expect(mockAddMessageEventListener).toBeCalledWith( + expect(mockAddMessageEventListener).toHaveBeenCalledWith( event, expect.any(Function) ); }, notToBeAdded: () => { - expect(mockAddMessageEventListener).not.toBeCalledWith( + expect(mockAddMessageEventListener).not.toHaveBeenCalledWith( event, expect.any(Function) ); @@ -119,13 +119,15 @@ describe('initializePushNotifications (native)', () => { it('only enables once', () => { mockIsInitialized.mockReturnValue(true); initializePushNotifications(); - expect(mockInitialize).not.toBeCalled(); + expect(mockInitialize).not.toHaveBeenCalled(); }); describe('background notification', () => { it('registers a headless task if able', () => { initializePushNotifications(); - expect(mockRegisterHeadlessTask).toBeCalledWith(expect.any(Function)); + expect(mockRegisterHeadlessTask).toHaveBeenCalledWith( + expect.any(Function) + ); expectListenerForEvent( NativeEvent.BACKGROUND_MESSAGE_RECEIVED ).notToBeAdded(); @@ -136,7 +138,7 @@ describe('initializePushNotifications (native)', () => { task(simplePushMessage); }); initializePushNotifications(); - expect(mockNotifyEventListenersAndAwaitHandlers).toBeCalledWith( + expect(mockNotifyEventListenersAndAwaitHandlers).toHaveBeenCalledWith( 'backgroundMessageReceived', simplePushMessage ); @@ -149,8 +151,8 @@ describe('initializePushNotifications (native)', () => { expectListenerForEvent( NativeEvent.BACKGROUND_MESSAGE_RECEIVED ).toBeAdded(); - expect(mockRegisterHeadlessTask).not.toBeCalled(); - expect(mockNotifyEventListenersAndAwaitHandlers).toBeCalledWith( + expect(mockRegisterHeadlessTask).not.toHaveBeenCalled(); + expect(mockNotifyEventListenersAndAwaitHandlers).toHaveBeenCalledWith( 'backgroundMessageReceived', simplePushMessage ); @@ -163,7 +165,7 @@ describe('initializePushNotifications (native)', () => { } }); mockCompleteNotification.mockImplementation(() => { - expect(mockCompleteNotification).toBeCalled(); + expect(mockCompleteNotification).toHaveBeenCalled(); done(); }); mockGetConstants.mockReturnValue({ NativeEvent }); @@ -171,8 +173,8 @@ describe('initializePushNotifications (native)', () => { expectListenerForEvent( NativeEvent.BACKGROUND_MESSAGE_RECEIVED ).toBeAdded(); - expect(mockRegisterHeadlessTask).not.toBeCalled(); - expect(mockNotifyEventListenersAndAwaitHandlers).toBeCalledWith( + expect(mockRegisterHeadlessTask).not.toHaveBeenCalled(); + expect(mockNotifyEventListenersAndAwaitHandlers).toHaveBeenCalledWith( 'backgroundMessageReceived', simplePushMessage ); @@ -187,7 +189,7 @@ describe('initializePushNotifications (native)', () => { expectListenerForEvent( NativeEvent.LAUNCH_NOTIFICATION_OPENED ).toBeAdded(); - expect(mockNotifyEventListeners).toBeCalledWith( + expect(mockNotifyEventListeners).toHaveBeenCalledWith( 'launchNotificationOpened', simplePushMessage ); @@ -206,7 +208,7 @@ describe('initializePushNotifications (native)', () => { expectListenerForEvent( NativeEvent.LAUNCH_NOTIFICATION_OPENED ).notToBeAdded(); - expect(mockNotifyEventListeners).not.toBeCalled(); + expect(mockNotifyEventListeners).not.toHaveBeenCalled(); }); }); @@ -215,7 +217,7 @@ describe('initializePushNotifications (native)', () => { initializePushNotifications(); expectListenerForEvent(NativeEvent.FOREGROUND_MESSAGE_RECEIVED).toBeAdded(); - expect(mockNotifyEventListeners).toBeCalledWith( + expect(mockNotifyEventListeners).toHaveBeenCalledWith( 'foregroundMessageReceived', simplePushMessage ); @@ -226,7 +228,7 @@ describe('initializePushNotifications (native)', () => { initializePushNotifications(); expectListenerForEvent(NativeEvent.NOTIFICATION_OPENED).toBeAdded(); - expect(mockNotifyEventListeners).toBeCalledWith( + expect(mockNotifyEventListeners).toHaveBeenCalledWith( 'notificationOpened', simplePushMessage ); @@ -243,17 +245,17 @@ describe('initializePushNotifications (native)', () => { } ); mockUpdateEndpoint.mockImplementation(() => { - expect(mockUpdateEndpoint).toBeCalled(); + expect(mockUpdateEndpoint).toHaveBeenCalled(); done(); }); initializePushNotifications(); - expect(mockAddTokenEventListener).toBeCalledWith( + expect(mockAddTokenEventListener).toHaveBeenCalledWith( NativeEvent.TOKEN_RECEIVED, expect.any(Function) ); - expect(mockSetToken).toBeCalledWith(pushToken); - expect(mockNotifyEventListeners).toBeCalledWith( + expect(mockSetToken).toHaveBeenCalledWith(pushToken); + expect(mockNotifyEventListeners).toHaveBeenCalledWith( 'tokenReceived', pushToken ); @@ -271,7 +273,7 @@ describe('initializePushNotifications (native)', () => { }); initializePushNotifications(); - expect(mockNotifyEventListeners).toBeCalledTimes(1); + expect(mockNotifyEventListeners).toHaveBeenCalledTimes(1); }); it('token received should be invoked with different tokens', () => { @@ -286,7 +288,7 @@ describe('initializePushNotifications (native)', () => { }); initializePushNotifications(); - expect(mockNotifyEventListeners).toBeCalledTimes(2); + expect(mockNotifyEventListeners).toHaveBeenCalledTimes(2); }); it('throws if device registration fails', done => { diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.test.ts index ed34daf1504..3e4a692c151 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationOpened.native.test.ts @@ -29,7 +29,7 @@ describe('onNotificationOpened (native)', () => { it('adds an event listener', () => { onNotificationOpened(mockHandler); - expect(mockAddEventListener).toBeCalledWith( + expect(mockAddEventListener).toHaveBeenCalledWith( 'notificationOpened', mockHandler ); diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.test.ts index 32988cb27b2..298e611178e 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInBackground.native.test.ts @@ -29,7 +29,7 @@ describe('onNotificationReceivedInBackground (native)', () => { it('adds an event listener', () => { onNotificationReceivedInBackground(mockHandler); - expect(mockAddEventListener).toBeCalledWith( + expect(mockAddEventListener).toHaveBeenCalledWith( 'backgroundMessageReceived', mockHandler ); diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.test.ts index 87364bb238c..9a4a657d967 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onNotificationReceivedInForeground.native.test.ts @@ -29,7 +29,7 @@ describe('onNotificationReceivedInForeground (native)', () => { it('adds an event listener', () => { onNotificationReceivedInForeground(mockHandler); - expect(mockAddEventListener).toBeCalledWith( + expect(mockAddEventListener).toHaveBeenCalledWith( 'foregroundMessageReceived', mockHandler ); diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.test.ts index 18c94616ed2..5dd96673fa5 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/onTokenReceived.native.test.ts @@ -29,6 +29,9 @@ describe('onTokenReceived (native)', () => { it('adds an event listener', () => { onTokenReceived(mockHandler); - expect(mockAddEventListener).toBeCalledWith('tokenReceived', mockHandler); + expect(mockAddEventListener).toHaveBeenCalledWith( + 'tokenReceived', + mockHandler + ); }); }); diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.test.ts index 643dc5d6ef6..a316937cdcf 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/apis/setBadgeCount.native.test.ts @@ -38,6 +38,6 @@ describe('setBadgeCount (native)', () => { it('returns the result of the native call', async () => { setBadgeCount(42); - expect(mockSetBadgeCountNative).toBeCalledWith(42); + expect(mockSetBadgeCountNative).toHaveBeenCalledWith(42); }); }); diff --git a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.test.ts b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.test.ts index 4aa50685fed..fa073358b28 100644 --- a/packages/notifications/__tests__/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.test.ts +++ b/packages/notifications/__tests__/pushNotifications/providers/pinpoint/utils/createMessageEventRecorder.test.ts @@ -59,7 +59,7 @@ describe('createMessageEventRecorder', () => { it('accepts and invokes a callback', done => { const callback = jest.fn(); callback.mockImplementation(() => { - expect(callback).toBeCalled(); + expect(callback).toHaveBeenCalled(); done(); }); const recorder = createMessageEventRecorder( @@ -72,7 +72,7 @@ describe('createMessageEventRecorder', () => { describe('created message event recorder', () => { it('records a message event', done => { mockRecord.mockImplementation(() => { - expect(mockRecord).toBeCalledWith( + expect(mockRecord).toHaveBeenCalledWith( expect.objectContaining({ event: analyticsEvent }) ); done(); diff --git a/packages/notifications/__tests__/pushNotifications/utils/getPushNotificationUserAgentString.test.ts b/packages/notifications/__tests__/pushNotifications/utils/getPushNotificationUserAgentString.test.ts index bd392f0d356..44d9eb0114a 100644 --- a/packages/notifications/__tests__/pushNotifications/utils/getPushNotificationUserAgentString.test.ts +++ b/packages/notifications/__tests__/pushNotifications/utils/getPushNotificationUserAgentString.test.ts @@ -23,7 +23,7 @@ describe('getPushNotificationUserAgentString', () => { expect( getPushNotificationUserAgentString(PushNotificationAction.IdentifyUser) ).toBe(userAgentValue); - expect(mockGetAmplifyUserAgent).toBeCalledWith({ + expect(mockGetAmplifyUserAgent).toHaveBeenCalledWith({ category: Category.PushNotification, action: PushNotificationAction.IdentifyUser, }); diff --git a/packages/notifications/jest.config.js b/packages/notifications/jest.config.js new file mode 100644 index 00000000000..94bcc49fb00 --- /dev/null +++ b/packages/notifications/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 74, + functions: 90, + lines: 91, + statements: 92, + }, + }, +}; diff --git a/packages/notifications/package.json b/packages/notifications/package.json index 1f2763782d7..56a2dab9d4a 100644 --- a/packages/notifications/package.json +++ b/packages/notifications/package.json @@ -103,45 +103,5 @@ "@rollup/plugin-typescript": "11.1.5", "rollup": "3.29.4", "typescript": "5.0.2" - }, - "jest": { - "globals": { - "__DEV__": true, - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testPathIgnorePatterns": [ - "/testUtils/" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 70, - "functions": 85, - "lines": 85, - "statements": 85 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ] } } diff --git a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts index 7c63d7e1b60..b0e662a8f5e 100644 --- a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts @@ -403,7 +403,7 @@ describe('Predictions convert provider test', () => { const predictionsProvider = new AmazonAIConvertPredictionsProvider(); await predictionsProvider.convert(validSpeechToTextInput); - expect(downsampleBufferSpyon).toBeCalledWith( + expect(downsampleBufferSpyon).toHaveBeenCalledWith( expect.objectContaining({ outputSampleRate: 8000 }) ); downsampleBufferSpyon.mockClear(); diff --git a/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts index c759e73c369..5aa2140502f 100644 --- a/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts @@ -691,7 +691,7 @@ describe('Predictions identify provider test', () => { .mockImplementationOnce(command => { expect( (command as DetectLabelsCommand).input.Image?.Bytes - ).toMatchObject(fileInput); + ).toStrictEqual(fileInput); return {}; }); await predictionsProvider.identify(detectLabelInput); diff --git a/packages/predictions/jest.config.js b/packages/predictions/jest.config.js new file mode 100644 index 00000000000..8235622a9d1 --- /dev/null +++ b/packages/predictions/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 64, + functions: 86, + lines: 89, + statements: 89, + }, + }, + moduleNameMapper: { + uuid: require.resolve('uuid'), + }, +}; diff --git a/packages/predictions/package.json b/packages/predictions/package.json index 929ff1661d9..8920612083b 100644 --- a/packages/predictions/package.json +++ b/packages/predictions/package.json @@ -11,7 +11,7 @@ "./dist/esm/Predictions.mjs" ], "scripts": { - "test": "npm run lint && jest -w 1 --passWithNoTests --coverage --maxWorkers 2", + "test": "npm run lint && jest -w 1 --coverage", "test:size": "size-limit", "build-with-test": "npm run clean && npm run build", "build:umd": "webpack && webpack --config ./webpack.config.dev.js", @@ -71,50 +71,5 @@ "import": "{ Predictions }", "limit": "69.8 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": { - "pathRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$" - }, - "tsConfig": { - "downlevelIteration": true, - "allowJs": true, - "types": [ - "@types/jest" - ], - "outDir": "./tsconfig.json", - "noEmitOnError": false, - "noImplicitAny": false, - "skipLibCheck": true - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "dist" - ] - } + ] } diff --git a/packages/pubsub/__tests__/PubSub.test.ts b/packages/pubsub/__tests__/PubSub.test.ts index 37a9f0ac3c7..44b600c1a33 100644 --- a/packages/pubsub/__tests__/PubSub.test.ts +++ b/packages/pubsub/__tests__/PubSub.test.ts @@ -27,7 +27,6 @@ import { PubSub as MqttPubSub } from '../src/clients/mqtt'; import { HubConnectionListener } from './helpers'; import { Observable, Observer } from 'rxjs'; import * as constants from '../src/Providers/constants'; -import { NetworkStatus } from '@aws-amplify/core/lib-esm/Reachability/types'; const pahoClientMockCache = {}; @@ -105,6 +104,11 @@ afterEach(() => { }); describe('PubSub', () => { + // extend class for testing + class MqttPubSubTest extends MqttPubSub { + disconnect = this.disconnect; + } + describe('constructor test', () => { test('happy case', () => { const pubsub = new IotPubSub(); @@ -138,7 +142,9 @@ describe('PubSub', () => { }); describe('AWSIoTProvider', () => { - test('subscribe and publish to the same topic using AWSIoTProvider', async done => { + test('subscribe and publish to the same topic using AWSIoTProvider', async () => { + expect.assertions(1); + let hubConnectionListener = new HubConnectionListener('pubsub'); const config = { @@ -153,10 +159,9 @@ describe('PubSub', () => { value: 'my message', }; - const obs = pubsub.subscribe({ topics: 'topicA' }).subscribe({ + pubsub.subscribe({ topics: 'topicA' }).subscribe({ next: data => { expect(data).toMatchObject(expectedData); - done(); }, complete: () => console.log('done'), error: error => console.log('error', error), @@ -205,7 +210,7 @@ describe('PubSub', () => { describe('MqttOverWSProvider', () => { test('trigger observer error when connect failed', () => { - const pubsub = new MqttPubSub({ + const pubsub = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); @@ -227,7 +232,7 @@ describe('PubSub', () => { test('trigger reconnection when disconnected', async () => { let hubConnectionListener = new HubConnectionListener('pubsub'); - const pubsub = new MqttPubSub({ + const pubsub = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); @@ -257,12 +262,12 @@ describe('PubSub', () => { }); test('should remove MqttOverWSProvider', () => { - const pubsubClient = new MqttPubSub({ + const pubsubClient = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); jest.spyOn(pubsubClient, 'publish'); - const newPubsubClient = new MqttPubSub({ + const newPubsubClient = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); @@ -280,7 +285,7 @@ describe('PubSub', () => { describe('Hub connection state changes', () => { let hubConnectionListener: HubConnectionListener; - let reachabilityObserver: Observer; + let reachabilityObserver: Observer; beforeEach(() => { // Maintain the Hub connection listener, used to monitor the connection messages sent through Hub @@ -412,7 +417,7 @@ describe('PubSub', () => { describe('MqttOverWSProvider local testing config', () => { test('ssl should be disabled in the case of local testing', async () => { mockConnect.mockClear(); - const pubsub = new MqttPubSub({ + const pubsub = new MqttPubSubTest({ region: 'region', aws_appsync_dangerously_connect_to_http_endpoint_for_testing: true, }); @@ -422,7 +427,7 @@ describe('PubSub', () => { }); expect(pubsub['isSSLEnabled']).toBe(false); - expect(mockConnect).toBeCalledWith({ + expect(mockConnect).toHaveBeenCalledWith({ useSSL: false, mqttVersion: 3, onSuccess: expect.any(Function), @@ -438,7 +443,7 @@ describe('PubSub', () => { endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); - const mqttClient = new MqttPubSub({ + const mqttClient = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); @@ -471,7 +476,7 @@ describe('PubSub', () => { endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); - const mqttClient = new MqttPubSub({ + const mqttClient = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); @@ -490,15 +495,11 @@ describe('PubSub', () => { test('On unsubscribe when is the last observer it should disconnect the websocket', async () => { const hubConnectionListener = new HubConnectionListener('pubsub'); - const mqttClient = new MqttPubSub({ + const mqttClient = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mock-endpoint.org:443/mqtt', }); - const spyDisconnect = jest.spyOn( - MqttPubSub.prototype, - // @ts-ignore - 'disconnect' - ); + const spyDisconnect = jest.spyOn(mqttClient, 'disconnect'); const subscription1 = mqttClient .subscribe({ topics: ['topic1', 'topic2'] }) @@ -528,16 +529,12 @@ describe('PubSub', () => { 'For multiple observers, client should not be disconnected if there are ' + 'other observers connected when unsubscribing', async () => { - const pubsub = new MqttPubSub({ + const pubsub = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mock-endpoint.org:443/mqtt', }); - const spyDisconnect = jest.spyOn( - MqttPubSub.prototype, - // @ts-ignore - 'disconnect' - ); + const spyDisconnect = jest.spyOn(pubsub, 'disconnect'); const subscription1 = pubsub .subscribe({ topics: ['topic1', 'topic2'] }) diff --git a/packages/pubsub/__tests__/helpers.ts b/packages/pubsub/__tests__/helpers.ts index 225e411cb00..e9c4e4dc3e7 100644 --- a/packages/pubsub/__tests__/helpers.ts +++ b/packages/pubsub/__tests__/helpers.ts @@ -14,13 +14,11 @@ export function delay(timeout) { export class HubConnectionListener { teardownHubListener: () => void; observedConnectionStates: CS[] = []; - currentConnectionState: CS; + currentConnectionState!: CS; private connectionStateObservers: RxObserver[] = []; constructor(channel: string) { - let closeResolver: (value: PromiseLike) => void; - this.teardownHubListener = Hub.listen(channel, (data: any) => { const { payload } = data; if (payload.event === CONNECTION_STATE_CHANGE) { @@ -86,12 +84,12 @@ export class HubConnectionListener { } export class FakeWebSocketInterface { - webSocket: FakeWebSocket; - readyForUse: Promise; - hasClosed: Promise; - hubConnectionListener: HubConnectionListener; + webSocket!: FakeWebSocket; + readyForUse!: Promise; + hasClosed!: Promise; + hubConnectionListener!: HubConnectionListener; - private readyResolve: (value: PromiseLike) => void; + private readyResolve!: (value: PromiseLike) => void; constructor() { this.hubConnectionListener = new HubConnectionListener('api'); @@ -294,16 +292,16 @@ class FakeWebSocket implements WebSocket { subscriptionId: string | undefined; closeResolverFcn: () => (value: PromiseLike) => void; - binaryType: BinaryType; - bufferedAmount: number; - extensions: string; - onclose: (this: WebSocket, ev: CloseEvent) => any; - onerror: (this: WebSocket, ev: Event) => any; - onmessage: (this: WebSocket, ev: MessageEvent) => any; - onopen: (this: WebSocket, ev: Event) => any; - protocol: string; - readyState: number; - url: string; + binaryType!: BinaryType; + bufferedAmount!: number; + extensions!: string; + onclose!: (this: WebSocket, ev: CloseEvent) => any; + onerror!: (this: WebSocket, ev: Event) => any; + onmessage!: (this: WebSocket, ev: MessageEvent) => any; + onopen!: (this: WebSocket, ev: Event) => any; + protocol!: string; + readyState!: number; + url!: string; close(code?: number, reason?: string): void { const closeResolver = this.closeResolverFcn(); if (closeResolver) closeResolver(Promise.resolve(undefined)); @@ -312,10 +310,10 @@ class FakeWebSocket implements WebSocket { const parsedInput = JSON.parse(String(data)); this.subscriptionId = parsedInput.id; } - CLOSED: number; - CLOSING: number; - CONNECTING: number; - OPEN: number; + CONNECTING: 0 = 0; + OPEN: 1 = 1; + CLOSING: 2 = 2; + CLOSED: 3 = 3; addEventListener( type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, diff --git a/packages/pubsub/jest.config.js b/packages/pubsub/jest.config.js new file mode 100644 index 00000000000..b37fd6a8d1c --- /dev/null +++ b/packages/pubsub/jest.config.js @@ -0,0 +1,14 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 16, + functions: 41, + lines: 28, + statements: 28, + }, + }, + moduleNameMapper: { + uuid: require.resolve('uuid'), + }, +}; diff --git a/packages/pubsub/package.json b/packages/pubsub/package.json index b4b1c7779c6..66a2f1961be 100644 --- a/packages/pubsub/package.json +++ b/packages/pubsub/package.json @@ -102,47 +102,5 @@ "import": "{ generateClient }", "limit": "1.07 kB" } - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - }, - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "__tests__/helpers.ts" - ] - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testPathIgnorePatterns": [ - "__tests__/helpers.ts" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ] - } + ] } diff --git a/packages/react-native/jest.config.js b/packages/react-native/jest.config.js new file mode 100644 index 00000000000..3a0e3340f9f --- /dev/null +++ b/packages/react-native/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}; diff --git a/packages/rtn-push-notification/__tests__/apis/addMessageEventListener.test.ts b/packages/rtn-push-notification/__tests__/apis/addMessageEventListener.test.ts index c3091ed2119..407b808cfce 100644 --- a/packages/rtn-push-notification/__tests__/apis/addMessageEventListener.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/addMessageEventListener.test.ts @@ -27,7 +27,10 @@ describe('addMessageEventListener', () => { it('calls the native addMessageEventListener', () => { addMessageEventListener(event, jest.fn()); - expect(mockAddListenerNative).toBeCalledWith(event, expect.any(Function)); + expect(mockAddListenerNative).toHaveBeenCalledWith( + event, + expect.any(Function) + ); }); it('calls the registered handler with a normalized message', () => { @@ -41,7 +44,7 @@ describe('addMessageEventListener', () => { const listener = jest.fn(); addMessageEventListener(event, listener); - expect(listener).toBeCalledWith( + expect(listener).toHaveBeenCalledWith( expect.objectContaining({ body: `normalized-${nativeMessage.body}`, }), @@ -62,7 +65,7 @@ describe('addMessageEventListener', () => { }); const listener = jest.fn(); addMessageEventListener(event, listener); - expect(listener).toBeCalledWith( + expect(listener).toHaveBeenCalledWith( expect.objectContaining({ body: `normalized-${nativeMessage.body}`, }), diff --git a/packages/rtn-push-notification/__tests__/apis/addTokenEventListener.test.ts b/packages/rtn-push-notification/__tests__/apis/addTokenEventListener.test.ts index 0d7b6bd1f5a..96c22e416b4 100644 --- a/packages/rtn-push-notification/__tests__/apis/addTokenEventListener.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/addTokenEventListener.test.ts @@ -23,7 +23,7 @@ describe('addTokenEventListener', () => { it('calls the native addTokenEventListener', () => { addTokenEventListener(eventType, jest.fn()); - expect(mockAddListenerNative).toBeCalledWith( + expect(mockAddListenerNative).toHaveBeenCalledWith( eventType, expect.any(Function) ); @@ -36,6 +36,6 @@ describe('addTokenEventListener', () => { const listener = jest.fn(); addTokenEventListener(eventType, listener); - expect(listener).toBeCalledWith(token); + expect(listener).toHaveBeenCalledWith(token); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/completeNotification.test.ts b/packages/rtn-push-notification/__tests__/apis/completeNotification.test.ts index 9dcf583c516..53c5157a4e4 100644 --- a/packages/rtn-push-notification/__tests__/apis/completeNotification.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/completeNotification.test.ts @@ -27,6 +27,8 @@ describe('completeNotification', () => { it('calls the native completeNotification', () => { completeNotification(completionHandlerId); - expect(mockCompleteNotificationNative).toBeCalledWith(completionHandlerId); + expect(mockCompleteNotificationNative).toHaveBeenCalledWith( + completionHandlerId + ); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/getBadgeCount.test.ts b/packages/rtn-push-notification/__tests__/apis/getBadgeCount.test.ts index 3dab0978672..5197f857844 100644 --- a/packages/rtn-push-notification/__tests__/apis/getBadgeCount.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/getBadgeCount.test.ts @@ -24,6 +24,6 @@ describe('getBadgeCount', () => { it('calls the native getBadgeCount', async () => { expect(await getBadgeCount()).toBe(42); - expect(mockGetBadgeCountNative).toBeCalled(); + expect(mockGetBadgeCountNative).toHaveBeenCalled(); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/getConstants.test.ts b/packages/rtn-push-notification/__tests__/apis/getConstants.test.ts index 63bdfb34674..2b32b6771c7 100644 --- a/packages/rtn-push-notification/__tests__/apis/getConstants.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/getConstants.test.ts @@ -25,6 +25,6 @@ describe('getConstants', () => { it('calls the native getConstants', () => { expect(getConstants()).toStrictEqual(constants); - expect(mockGetConstantsNative).toBeCalled(); + expect(mockGetConstantsNative).toHaveBeenCalled(); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/getLaunchNotification.test.ts b/packages/rtn-push-notification/__tests__/apis/getLaunchNotification.test.ts index 38134ebac0c..d628c43f2b6 100644 --- a/packages/rtn-push-notification/__tests__/apis/getLaunchNotification.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/getLaunchNotification.test.ts @@ -36,8 +36,8 @@ describe('getLaunchNotification', () => { body: `normalized-${nativeMessage.body}`, }) ); - expect(mockGetLaunchNotificationNative).toBeCalled(); - expect(mockNormalizeNativeMessage).toBeCalledWith(nativeMessage); + expect(mockGetLaunchNotificationNative).toHaveBeenCalled(); + expect(mockNormalizeNativeMessage).toHaveBeenCalledWith(nativeMessage); }); it('can handle a null value', async () => { @@ -45,7 +45,7 @@ describe('getLaunchNotification', () => { mockGetLaunchNotificationNative.mockResolvedValue(null); expect(await getLaunchNotification()).toBeNull(); - expect(mockGetLaunchNotificationNative).toBeCalled(); - expect(mockNormalizeNativeMessage).toBeCalledWith(undefined); + expect(mockGetLaunchNotificationNative).toHaveBeenCalled(); + expect(mockNormalizeNativeMessage).toHaveBeenCalledWith(undefined); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/getPermissionStatus.test.ts b/packages/rtn-push-notification/__tests__/apis/getPermissionStatus.test.ts index f6ade15ac8f..1588e665216 100644 --- a/packages/rtn-push-notification/__tests__/apis/getPermissionStatus.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/getPermissionStatus.test.ts @@ -34,7 +34,7 @@ describe('getPermissionStatus', () => { it('calls the native getPermissionStatus', async () => { expect(await getPermissionStatus()).toBe(`normalized-${status}`); - expect(mockGetPermissionStatusNative).toBeCalled(); - expect(mockNormalizeNativePermissionStatus).toBeCalledWith(status); + expect(mockGetPermissionStatusNative).toHaveBeenCalled(); + expect(mockNormalizeNativePermissionStatus).toHaveBeenCalledWith(status); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/registerHeadlessTask.test.ts b/packages/rtn-push-notification/__tests__/apis/registerHeadlessTask.test.ts index 24bbfec321c..ed47bf17c07 100644 --- a/packages/rtn-push-notification/__tests__/apis/registerHeadlessTask.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/registerHeadlessTask.test.ts @@ -42,7 +42,7 @@ describe('registerHeadlessTask', () => { it('registers a task', () => { registerHeadlessTask(jest.fn()); - expect(mockReactNativeRegisterHeadlessTask).toBeCalledWith( + expect(mockReactNativeRegisterHeadlessTask).toHaveBeenCalledWith( nativeHeadlessTaskKey, expect.any(Function) ); @@ -60,7 +60,7 @@ describe('registerHeadlessTask', () => { const listener = jest.fn(); registerHeadlessTask(listener); - expect(listener).toBeCalledWith( + expect(listener).toHaveBeenCalledWith( expect.objectContaining({ body: `normalized-${nativeMessage.body}`, }) @@ -71,6 +71,6 @@ describe('registerHeadlessTask', () => { mockGetConstants.mockReturnValue({}); registerHeadlessTask(jest.fn()); - expect(mockReactNativeRegisterHeadlessTask).not.toBeCalled(); + expect(mockReactNativeRegisterHeadlessTask).not.toHaveBeenCalled(); }); }); diff --git a/packages/rtn-push-notification/__tests__/apis/requestPermissions.test.ts b/packages/rtn-push-notification/__tests__/apis/requestPermissions.test.ts index 788e01390ab..37a955ec1c9 100644 --- a/packages/rtn-push-notification/__tests__/apis/requestPermissions.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/requestPermissions.test.ts @@ -25,7 +25,7 @@ describe('requestPermissions', () => { it('calls the native requestPermissions with defaults', async () => { expect(await requestPermissions()).toBe(true); - expect(mockRequestPermissionsNative).toBeCalledWith({ + expect(mockRequestPermissionsNative).toHaveBeenCalledWith({ alert: true, badge: true, sound: true, @@ -39,7 +39,7 @@ describe('requestPermissions', () => { sound: false, }) ).toBe(true); - expect(mockRequestPermissionsNative).toBeCalledWith({ + expect(mockRequestPermissionsNative).toHaveBeenCalledWith({ alert: true, badge: false, sound: false, diff --git a/packages/rtn-push-notification/__tests__/apis/setBadgeCount.test.ts b/packages/rtn-push-notification/__tests__/apis/setBadgeCount.test.ts index 728e8b617a0..17fb95f9d3e 100644 --- a/packages/rtn-push-notification/__tests__/apis/setBadgeCount.test.ts +++ b/packages/rtn-push-notification/__tests__/apis/setBadgeCount.test.ts @@ -21,6 +21,6 @@ describe('setBadgeCount', () => { it('calls the native setBadgeCount', () => { setBadgeCount(42); - expect(mockSetBadgeCountNative).toBeCalledWith(42); + expect(mockSetBadgeCountNative).toHaveBeenCalledWith(42); }); }); diff --git a/packages/rtn-push-notification/jest.config.js b/packages/rtn-push-notification/jest.config.js new file mode 100644 index 00000000000..cbee5767b39 --- /dev/null +++ b/packages/rtn-push-notification/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 94, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}; diff --git a/packages/rtn-push-notification/package.json b/packages/rtn-push-notification/package.json index 089ae73fcf0..879777c2350 100644 --- a/packages/rtn-push-notification/package.json +++ b/packages/rtn-push-notification/package.json @@ -46,44 +46,5 @@ "dist/cjs", "dist/esm", "src" - ], - "jest": { - "globals": { - "ts-jest": { - "diagnostics": false, - "tsConfig": { - "allowJs": true, - "noEmitOnError": false - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testPathIgnorePatterns": [ - "/testUtils/" - ], - "testRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$", - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "node_modules", - "dist" - ] - } + ] } diff --git a/packages/rtn-web-browser/jest.config.js b/packages/rtn-web-browser/jest.config.js new file mode 100644 index 00000000000..3a0e3340f9f --- /dev/null +++ b/packages/rtn-web-browser/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 100, + functions: 100, + lines: 100, + statements: 100, + }, + }, +}; diff --git a/packages/storage/__tests__/providers/s3/apis/copy.test.ts b/packages/storage/__tests__/providers/s3/apis/copy.test.ts index 74c1821c5bc..ec7dcbd1b16 100644 --- a/packages/storage/__tests__/providers/s3/apis/copy.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/copy.test.ts @@ -166,7 +166,7 @@ describe('copy API', () => { }, }) ).toEqual(copyResult); - expect(copyObject).toBeCalledTimes(1); + expect(copyObject).toHaveBeenCalledTimes(1); expect(copyObject).toHaveBeenCalledWith(copyObjectClientConfig, { ...copyObjectClientBaseParams, CopySource: expectedSourceKey, @@ -196,8 +196,8 @@ describe('copy API', () => { source: { key: sourceKey }, destination: { key: destinationKey }, }); - } catch (error) { - expect(copyObject).toBeCalledTimes(1); + } catch (error: any) { + expect(copyObject).toHaveBeenCalledTimes(1); expect(copyObject).toHaveBeenCalledWith(copyObjectClientConfig, { ...copyObjectClientBaseParams, CopySource: `${bucket}/public/${sourceKey}`, diff --git a/packages/storage/__tests__/providers/s3/apis/downloadData.test.ts b/packages/storage/__tests__/providers/s3/apis/downloadData.test.ts index 646799c77cb..9d894b45ddf 100644 --- a/packages/storage/__tests__/providers/s3/apis/downloadData.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/downloadData.test.ts @@ -101,7 +101,7 @@ describe('downloadData', () => { }); const job = mockCreateDownloadTask.mock.calls[0][0].job; await job(); - expect(getObject).toBeCalledTimes(1); + expect(getObject).toHaveBeenCalledTimes(1); expect(getObject).toHaveBeenCalledWith( { credentials, @@ -141,7 +141,7 @@ describe('downloadData', () => { downloadData({ key }); const job = mockCreateDownloadTask.mock.calls[0][0].job; const result = await job(); - expect(getObject).toBeCalledTimes(1); + expect(getObject).toHaveBeenCalledTimes(1); expect(result).toEqual({ key, body, diff --git a/packages/storage/__tests__/providers/s3/apis/getProperties.test.ts b/packages/storage/__tests__/providers/s3/apis/getProperties.test.ts index 9ec68618a05..b10050156d9 100644 --- a/packages/storage/__tests__/providers/s3/apis/getProperties.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/getProperties.test.ts @@ -114,7 +114,7 @@ describe('getProperties api', () => { options: options as GetPropertiesOptions, }) ).toEqual(expected); - expect(headObject).toBeCalledTimes(1); + expect(headObject).toHaveBeenCalledTimes(1); expect(headObject).toHaveBeenCalledWith(config, headObjectOptions); }); }); @@ -131,11 +131,11 @@ describe('getProperties api', () => { name: 'NotFound', }) ); + expect.assertions(3); try { await getProperties({ key: 'keyed' }); - } catch (error) { - expect.assertions(3); - expect(headObject).toBeCalledTimes(1); + } catch (error: any) { + expect(headObject).toHaveBeenCalledTimes(1); expect(headObject).toHaveBeenCalledWith( { credentials, diff --git a/packages/storage/__tests__/providers/s3/apis/getUrl.test.ts b/packages/storage/__tests__/providers/s3/apis/getUrl.test.ts index d32bf670a32..1cdf1a59b72 100644 --- a/packages/storage/__tests__/providers/s3/apis/getUrl.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/getUrl.test.ts @@ -114,8 +114,8 @@ describe('getUrl test', () => { validateObjectExistence: true, } as GetUrlOptions, }); - expect(getPresignedGetObjectUrl).toBeCalledTimes(1); - expect(headObject).toBeCalledTimes(1); + expect(getPresignedGetObjectUrl).toHaveBeenCalledTimes(1); + expect(headObject).toHaveBeenCalledTimes(1); expect(headObject).toHaveBeenCalledWith(config, headObjectOptions); expect(result.url).toEqual({ url: new URL('https://google.com'), @@ -128,20 +128,20 @@ describe('getUrl test', () => { jest.clearAllMocks(); }); it('should return not found error when the object is not found', async () => { - (headObject as jest.Mock).mockImplementation(() => - Object.assign(new Error(), { + (headObject as jest.Mock).mockImplementation(() => { + throw Object.assign(new Error(), { $metadata: { httpStatusCode: 404 }, name: 'NotFound', - }) - ); + }); + }); + expect.assertions(2); try { await getUrl({ key: 'invalid_key', options: { validateObjectExistence: true }, }); - } catch (error) { - expect.assertions(2); - expect(headObject).toBeCalledTimes(1); + } catch (error: any) { + expect(headObject).toHaveBeenCalledTimes(1); expect(error.$metadata?.httpStatusCode).toBe(404); } }); diff --git a/packages/storage/__tests__/providers/s3/apis/list.test.ts b/packages/storage/__tests__/providers/s3/apis/list.test.ts index 2e9d79a8710..6a615a7cd8e 100644 --- a/packages/storage/__tests__/providers/s3/apis/list.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/list.test.ts @@ -148,7 +148,7 @@ describe('list API', () => { { ...listResultItem, key: path ?? '' }, ]); expect(response.nextToken).toEqual(nextToken); - expect(listObjectsV2).toBeCalledTimes(1); + expect(listObjectsV2).toHaveBeenCalledTimes(1); expect(listObjectsV2).toHaveBeenCalledWith(listObjectClientConfig, { Bucket: bucket, MaxKeys: 1000, @@ -186,7 +186,7 @@ describe('list API', () => { { ...listResultItem, key: path ?? '' }, ]); expect(response.nextToken).toEqual(nextToken); - expect(listObjectsV2).toBeCalledTimes(1); + expect(listObjectsV2).toHaveBeenCalledTimes(1); expect(listObjectsV2).toHaveBeenCalledWith(listObjectClientConfig, { Bucket: bucket, Prefix: expectedPath, @@ -283,8 +283,8 @@ describe('list API', () => { expect.assertions(3); try { await list({}); - } catch (error) { - expect(listObjectsV2).toBeCalledTimes(1); + } catch (error: any) { + expect(listObjectsV2).toHaveBeenCalledTimes(1); expect(listObjectsV2).toHaveBeenCalledWith(listObjectClientConfig, { Bucket: bucket, MaxKeys: 1000, diff --git a/packages/storage/__tests__/providers/s3/apis/remove.test.ts b/packages/storage/__tests__/providers/s3/apis/remove.test.ts index b5c1f3902ce..ccfba1e1a19 100644 --- a/packages/storage/__tests__/providers/s3/apis/remove.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/remove.test.ts @@ -88,7 +88,7 @@ describe('remove API', () => { expect( await remove({ key, options: options as StorageOptions }) ).toEqual(removeResult); - expect(deleteObject).toBeCalledTimes(1); + expect(deleteObject).toHaveBeenCalledTimes(1); expect(deleteObject).toHaveBeenCalledWith(deleteObjectClientConfig, { Bucket: bucket, Key: expectedKey, @@ -112,8 +112,8 @@ describe('remove API', () => { const key = 'wrongKey'; try { await remove({ key }); - } catch (error) { - expect(deleteObject).toBeCalledTimes(1); + } catch (error: any) { + expect(deleteObject).toHaveBeenCalledTimes(1); expect(deleteObject).toHaveBeenCalledWith(deleteObjectClientConfig, { Bucket: bucket, Key: `public/${key}`, diff --git a/packages/storage/__tests__/providers/s3/apis/uploadData/index.test.ts b/packages/storage/__tests__/providers/s3/apis/uploadData/index.test.ts index 813d4bfbfdc..95a59ac92e9 100644 --- a/packages/storage/__tests__/providers/s3/apis/uploadData/index.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/uploadData/index.test.ts @@ -38,7 +38,7 @@ describe('uploadData', () => { key: 'key', data: { size: MAX_OBJECT_SIZE + 1 } as any, }) - ).toThrowError( + ).toThrow( expect.objectContaining( validationErrorMap[StorageValidationErrorCode.ObjectIsTooLarge] ) @@ -50,7 +50,7 @@ describe('uploadData', () => { key: 'key', data: {} as any, }); - expect(mockCreateUploadTask).toBeCalled(); + expect(mockCreateUploadTask).toHaveBeenCalled(); }); }); @@ -61,8 +61,8 @@ describe('uploadData', () => { key: 'key', data: smallData, }); - expect(mockPutObjectJob).toBeCalled(); - expect(mockGetMultipartUploadHandlers).not.toBeCalled(); + expect(mockPutObjectJob).toHaveBeenCalled(); + expect(mockGetMultipartUploadHandlers).not.toHaveBeenCalled(); }); it('should use uploadTask', async () => { @@ -73,7 +73,7 @@ describe('uploadData', () => { data: smallData, }); expect(task).toBe('uploadTask'); - expect(mockCreateUploadTask).toBeCalledWith( + expect(mockCreateUploadTask).toHaveBeenCalledWith( expect.objectContaining({ job: 'putObjectJob', onCancel: expect.any(Function), @@ -90,8 +90,8 @@ describe('uploadData', () => { key: 'key', data: biggerData, }); - expect(mockPutObjectJob).not.toBeCalled(); - expect(mockGetMultipartUploadHandlers).toBeCalled(); + expect(mockPutObjectJob).not.toHaveBeenCalled(); + expect(mockGetMultipartUploadHandlers).toHaveBeenCalled(); }); it('should use uploadTask', async () => { @@ -101,7 +101,7 @@ describe('uploadData', () => { data: biggerData, }); expect(task).toBe('uploadTask'); - expect(mockCreateUploadTask).toBeCalledWith( + expect(mockCreateUploadTask).toHaveBeenCalledWith( expect.objectContaining({ job: expect.any(Function), onCancel: expect.any(Function), @@ -117,7 +117,7 @@ describe('uploadData', () => { key: 'key', data: biggerData, }); - expect(mockGetMultipartUploadHandlers).toBeCalled(); + expect(mockGetMultipartUploadHandlers).toHaveBeenCalled(); }); }); }); diff --git a/packages/storage/__tests__/providers/s3/apis/uploadData/multipartHandlers.test.ts b/packages/storage/__tests__/providers/s3/apis/uploadData/multipartHandlers.test.ts index b494b2735d6..d02dc5534e5 100644 --- a/packages/storage/__tests__/providers/s3/apis/uploadData/multipartHandlers.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/uploadData/multipartHandlers.test.ts @@ -189,7 +189,7 @@ describe('getMultipartUploadHandlers', () => { options: options as StorageOptions, }); const result = await multipartUploadJob(); - expect(mockCreateMultipartUpload).toBeCalledWith( + expect(mockCreateMultipartUpload).toHaveBeenCalledWith( expect.objectContaining({ credentials, region, @@ -204,9 +204,9 @@ describe('getMultipartUploadHandlers', () => { expect(result).toEqual( expect.objectContaining({ key: defaultKey, eTag: 'etag' }) ); - expect(mockCreateMultipartUpload).toBeCalledTimes(1); - expect(mockUploadPart).toBeCalledTimes(2); - expect(mockCompleteMultipartUpload).toBeCalledTimes(1); + expect(mockCreateMultipartUpload).toHaveBeenCalledTimes(1); + expect(mockUploadPart).toHaveBeenCalledTimes(2); + expect(mockCompleteMultipartUpload).toHaveBeenCalledTimes(1); } ); }); @@ -217,7 +217,7 @@ describe('getMultipartUploadHandlers', () => { key: defaultKey, data: 1 as any, }); - await expect(multipartUploadJob()).rejects.toThrowError( + await expect(multipartUploadJob()).rejects.toThrow( expect.objectContaining( validationErrorMap[StorageValidationErrorCode.InvalidUploadSource] ) @@ -248,10 +248,10 @@ describe('getMultipartUploadHandlers', () => { file.size ); await multipartUploadJob(); - expect(file.slice).toBeCalledTimes(10_000); // S3 limit of parts count - expect(mockCreateMultipartUpload).toBeCalledTimes(1); - expect(mockUploadPart).toBeCalledTimes(10_000); - expect(mockCompleteMultipartUpload).toBeCalledTimes(1); + expect(file.slice).toHaveBeenCalledTimes(10_000); // S3 limit of parts count + expect(mockCreateMultipartUpload).toHaveBeenCalledTimes(1); + expect(mockUploadPart).toHaveBeenCalledTimes(10_000); + expect(mockCompleteMultipartUpload).toHaveBeenCalledTimes(1); expect(mockUploadPart.mock.calls[0][1].Body.byteLength).toEqual(10 * MB); // The part size should be adjusted from default 5MB to 10MB. }); @@ -273,7 +273,7 @@ describe('getMultipartUploadHandlers', () => { try { await multipartUploadJob(); fail('should throw error'); - } catch (e) { + } catch (e: any) { expect(e.message).toEqual( `Upload failed. Expected object size ${8 * MB}, but got 1.` ); @@ -290,7 +290,7 @@ describe('getMultipartUploadHandlers', () => { key: defaultKey, data: new ArrayBuffer(8 * MB), }); - await expect(multipartUploadJob()).rejects.toThrowError('error'); + await expect(multipartUploadJob()).rejects.toThrow('error'); }); it('should handle error case: finish multipart upload failed', async () => { @@ -303,7 +303,7 @@ describe('getMultipartUploadHandlers', () => { key: defaultKey, data: new ArrayBuffer(8 * MB), }); - await expect(multipartUploadJob()).rejects.toThrowError('error'); + await expect(multipartUploadJob()).rejects.toThrow('error'); }); it('should handle error case: upload a body that splits in two parts but second part fails', async () => { @@ -320,9 +320,9 @@ describe('getMultipartUploadHandlers', () => { key: defaultKey, data: new ArrayBuffer(8 * MB), }); - await expect(multipartUploadJob()).rejects.toThrowError('error'); - expect(mockUploadPart).toBeCalledTimes(2); - expect(mockCompleteMultipartUpload).not.toBeCalled(); + await expect(multipartUploadJob()).rejects.toThrow('error'); + expect(mockUploadPart).toHaveBeenCalledTimes(2); + expect(mockCompleteMultipartUpload).not.toHaveBeenCalled(); }); }); @@ -347,9 +347,9 @@ describe('getMultipartUploadHandlers', () => { ); await multipartUploadJob(); // 1 for caching upload task; 1 for remove cache after upload is completed - expect(mockDefaultStorage.setItem).toBeCalledTimes(2); - expect(mockCreateMultipartUpload).toBeCalledTimes(1); - expect(mockListParts).not.toBeCalled(); + expect(mockDefaultStorage.setItem).toHaveBeenCalledTimes(2); + expect(mockCreateMultipartUpload).toHaveBeenCalledTimes(1); + expect(mockListParts).not.toHaveBeenCalled(); }); it('should send createMultipartUpload request if the upload task is cached but outdated', async () => { @@ -374,10 +374,10 @@ describe('getMultipartUploadHandlers', () => { size ); await multipartUploadJob(); - expect(mockCreateMultipartUpload).toBeCalledTimes(1); - expect(mockListParts).not.toBeCalled(); - expect(mockUploadPart).toBeCalledTimes(2); - expect(mockCompleteMultipartUpload).toBeCalledTimes(1); + expect(mockCreateMultipartUpload).toHaveBeenCalledTimes(1); + expect(mockListParts).not.toHaveBeenCalled(); + expect(mockUploadPart).toHaveBeenCalledTimes(2); + expect(mockCompleteMultipartUpload).toHaveBeenCalledTimes(1); }); it('should cache the upload with file including file lastModified property', async () => { @@ -393,7 +393,7 @@ describe('getMultipartUploadHandlers', () => { ); await multipartUploadJob(); // 1 for caching upload task; 1 for remove cache after upload is completed - expect(mockDefaultStorage.setItem).toBeCalledTimes(2); + expect(mockDefaultStorage.setItem).toHaveBeenCalledTimes(2); const cacheValue = JSON.parse( mockDefaultStorage.setItem.mock.calls[0][1] ); @@ -427,10 +427,10 @@ describe('getMultipartUploadHandlers', () => { size ); await multipartUploadJob(); - expect(mockCreateMultipartUpload).not.toBeCalled(); - expect(mockListParts).toBeCalledTimes(1); - expect(mockUploadPart).toBeCalledTimes(2); - expect(mockCompleteMultipartUpload).toBeCalledTimes(1); + expect(mockCreateMultipartUpload).not.toHaveBeenCalled(); + expect(mockListParts).toHaveBeenCalledTimes(1); + expect(mockUploadPart).toHaveBeenCalledTimes(2); + expect(mockCompleteMultipartUpload).toHaveBeenCalledTimes(1); }); it('should cache upload task if new upload task is created', async () => { @@ -446,7 +446,7 @@ describe('getMultipartUploadHandlers', () => { ); await multipartUploadJob(); // 1 for caching upload task; 1 for remove cache after upload is completed - expect(mockDefaultStorage.setItem).toBeCalledTimes(2); + expect(mockDefaultStorage.setItem).toHaveBeenCalledTimes(2); expect(mockDefaultStorage.setItem.mock.calls[0][0]).toEqual( UPLOADS_STORAGE_KEY ); @@ -473,7 +473,7 @@ describe('getMultipartUploadHandlers', () => { ); await multipartUploadJob(); // 1 for caching upload task; 1 for remove cache after upload is completed - expect(mockDefaultStorage.setItem).toBeCalledTimes(2); + expect(mockDefaultStorage.setItem).toHaveBeenCalledTimes(2); expect(mockDefaultStorage.setItem).toHaveBeenNthCalledWith( 2, UPLOADS_STORAGE_KEY, @@ -496,7 +496,7 @@ describe('getMultipartUploadHandlers', () => { const uploadJobPromise = multipartUploadJob(); await uploadJobPromise; // 1 for caching upload task; 1 for remove cache after upload is completed - expect(mockDefaultStorage.setItem).toBeCalledTimes(2); + expect(mockDefaultStorage.setItem).toHaveBeenCalledTimes(2); expect(mockDefaultStorage.setItem).toHaveBeenNthCalledWith( 2, UPLOADS_STORAGE_KEY, @@ -521,12 +521,12 @@ describe('getMultipartUploadHandlers', () => { try { await multipartUploadJob(); fail('should throw error'); - } catch (error) { + } catch (error: any) { expect(error).toBeInstanceOf(CanceledError); expect(error.message).toBe('Upload is canceled by user'); } - expect(mockAbortMultipartUpload).toBeCalledTimes(1); - expect(mockUploadPart).toBeCalledTimes(2); + expect(mockAbortMultipartUpload).toHaveBeenCalledTimes(1); + expect(mockUploadPart).toHaveBeenCalledTimes(2); expect(mockUploadPart.mock.calls[0][0].abortSignal?.aborted).toBe(true); expect(mockUploadPart.mock.calls[1][0].abortSignal?.aborted).toBe(true); }); @@ -549,7 +549,7 @@ describe('getMultipartUploadHandlers', () => { const uploadPromise = multipartUploadJob(); onResume(); await uploadPromise; - expect(mockUploadPart).toBeCalledTimes(2); + expect(mockUploadPart).toHaveBeenCalledTimes(2); expect(mockUploadPart.mock.calls[0][0].abortSignal?.aborted).toBe(true); expect(mockUploadPart.mock.calls[1][0].abortSignal?.aborted).toBe(true); }); @@ -570,7 +570,7 @@ describe('getMultipartUploadHandlers', () => { 8 * MB ); await multipartUploadJob(); - expect(onProgress).toBeCalledTimes(4); // 2 simulated onProgress events per uploadPart call are all tracked + expect(onProgress).toHaveBeenCalledTimes(4); // 2 simulated onProgress events per uploadPart call are all tracked expect(onProgress).toHaveBeenNthCalledWith(1, { totalBytes: 8388608, transferredBytes: 2621440, @@ -620,7 +620,7 @@ describe('getMultipartUploadHandlers', () => { 8 * MB ); await multipartUploadJob(); - expect(onProgress).toBeCalledTimes(3); + expect(onProgress).toHaveBeenCalledTimes(3); // The first part's 5 MB progress is reported even though no uploadPart call is made. expect(onProgress).toHaveBeenNthCalledWith(1, { totalBytes: 8388608, diff --git a/packages/storage/__tests__/providers/s3/apis/uploadData/putObjectJob.test.ts b/packages/storage/__tests__/providers/s3/apis/uploadData/putObjectJob.test.ts index 9a00c8acb9c..93679f794b1 100644 --- a/packages/storage/__tests__/providers/s3/apis/uploadData/putObjectJob.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/uploadData/putObjectJob.test.ts @@ -89,7 +89,7 @@ describe('putObjectJob', () => { metadata: { key: 'value' }, size: undefined, }); - expect(mockPutObject).toBeCalledWith( + expect(mockPutObject).toHaveBeenCalledWith( { credentials, region: 'region', @@ -127,6 +127,6 @@ describe('putObjectJob', () => { new AbortController().signal ); await job(); - expect(calculateContentMd5).toBeCalledWith('data'); + expect(calculateContentMd5).toHaveBeenCalledWith('data'); }); }); diff --git a/packages/storage/__tests__/providers/s3/apis/utils/resolveS3ConfigAndInput.test.ts b/packages/storage/__tests__/providers/s3/apis/utils/resolveS3ConfigAndInput.test.ts index 524280f3b85..9a15b06e141 100644 --- a/packages/storage/__tests__/providers/s3/apis/utils/resolveS3ConfigAndInput.test.ts +++ b/packages/storage/__tests__/providers/s3/apis/utils/resolveS3ConfigAndInput.test.ts @@ -84,7 +84,7 @@ describe('resolveS3ConfigAndInput', () => { {} ); expect(resolvedBucket).toEqual(bucket); - expect(mockGetConfig).toBeCalled(); + expect(mockGetConfig).toHaveBeenCalled(); }); it('should throw if bucket is not available', async () => { @@ -103,7 +103,7 @@ describe('resolveS3ConfigAndInput', () => { it('should resolve region from S3 config', async () => { const { s3Config } = await resolveS3ConfigAndInput(Amplify, {}); expect(s3Config.region).toEqual(region); - expect(mockGetConfig).toBeCalled(); + expect(mockGetConfig).toHaveBeenCalled(); }); it('should throw if region is not available', async () => { @@ -132,7 +132,7 @@ describe('resolveS3ConfigAndInput', () => { const { s3Config } = await resolveS3ConfigAndInput(Amplify, {}); expect(s3Config.customEndpoint).toEqual('http://localhost:20005'); expect(s3Config.forcePathStyle).toEqual(true); - expect(mockGetConfig).toBeCalled(); + expect(mockGetConfig).toHaveBeenCalled(); }); it('should resolve isObjectLockEnabled from S3 library options', async () => { @@ -150,7 +150,7 @@ describe('resolveS3ConfigAndInput', () => { it('should use default prefix resolver', async () => { mockDefaultResolvePrefix.mockResolvedValueOnce('prefix'); const { keyPrefix } = await resolveS3ConfigAndInput(Amplify, {}); - expect(mockDefaultResolvePrefix).toBeCalled(); + expect(mockDefaultResolvePrefix).toHaveBeenCalled(); expect(keyPrefix).toEqual('prefix'); }); @@ -164,9 +164,9 @@ describe('resolveS3ConfigAndInput', () => { }, }; const { keyPrefix } = await resolveS3ConfigAndInput(Amplify, {}); - expect(customResolvePrefix).toBeCalled(); + expect(customResolvePrefix).toHaveBeenCalled(); expect(keyPrefix).toEqual('prefix'); - expect(mockDefaultResolvePrefix).not.toBeCalled(); + expect(mockDefaultResolvePrefix).not.toHaveBeenCalled(); }); it('should resolve prefix with given access level', async () => { @@ -174,7 +174,7 @@ describe('resolveS3ConfigAndInput', () => { const { keyPrefix } = await resolveS3ConfigAndInput(Amplify, { accessLevel: 'someLevel' as any, }); - expect(mockDefaultResolvePrefix).toBeCalledWith({ + expect(mockDefaultResolvePrefix).toHaveBeenCalledWith({ accessLevel: 'someLevel', targetIdentityId, }); @@ -191,7 +191,7 @@ describe('resolveS3ConfigAndInput', () => { }, }; const { keyPrefix } = await resolveS3ConfigAndInput(Amplify, {}); - expect(mockDefaultResolvePrefix).toBeCalledWith({ + expect(mockDefaultResolvePrefix).toHaveBeenCalledWith({ accessLevel: 'someLevel', targetIdentityId, }); @@ -201,7 +201,7 @@ describe('resolveS3ConfigAndInput', () => { it('should resolve prefix with `guest` access level if no access level is given', async () => { mockDefaultResolvePrefix.mockResolvedValueOnce('prefix'); const { keyPrefix } = await resolveS3ConfigAndInput(Amplify, {}); - expect(mockDefaultResolvePrefix).toBeCalledWith({ + expect(mockDefaultResolvePrefix).toHaveBeenCalledWith({ accessLevel: 'guest', // default access level targetIdentityId, }); diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getObject.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getObject.ts index 60589526075..0506b02d876 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getObject.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/getObject.ts @@ -74,11 +74,6 @@ const getObjectHappyCase: ApiFunctionalTestCase = [ }), method: 'GET', headers: expect.objectContaining({ - authorization: expect.stringContaining('Signature'), - host: 'bucket.s3.us-east-1.amazonaws.com', - 'x-amz-content-sha256': EMPTY_SHA256, - 'x-amz-date': expect.stringMatching(/^\d{8}T\d{6}Z/), - 'x-amz-user-agent': expect.stringContaining('aws-amplify'), Range: 'bytes=1-100', }), }), diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listObjectsV2.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listObjectsV2.ts index 9da8a8f2e19..fed49cd8c3b 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listObjectsV2.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/listObjectsV2.ts @@ -5,7 +5,6 @@ import { listObjectsV2 } from '../../../../../../../src/providers/s3/utils/clien import { ApiFunctionalTestCase } from '../../testUtils/types'; import { defaultConfig, - defaultRequiredRequestHeaders, DEFAULT_RESPONSE_HEADERS, expectedMetadata, } from './shared'; @@ -34,7 +33,6 @@ const listObjectsV2HappyCase: ApiFunctionalTestCase = [ }), method: 'GET', headers: expect.objectContaining({ - ...defaultRequiredRequestHeaders, 'x-amz-request-payer': 'RequestPayer', 'x-amz-expected-bucket-owner': 'ExpectedBucketOwner', }), diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/shared.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/shared.ts index 526113b31db..6a1d8431825 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/cases/shared.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/cases/shared.ts @@ -12,7 +12,6 @@ export const DEFAULT_RESPONSE_HEADERS = { }; export const expectedMetadata = { - attempts: 1, requestId: MOCK_REQUEST_ID, extendedRequestId: MOCK_EXTENDED_REQUEST_ID, httpStatusCode: 200, @@ -25,11 +24,3 @@ export const defaultConfig = { secretAccessKey: 'secret', }, }; - -export const defaultRequiredRequestHeaders = { - authorization: expect.stringContaining('Signature'), - host: 'bucket.s3.us-east-1.amazonaws.com', - 'x-amz-content-sha256': EMPTY_SHA256, - 'x-amz-date': expect.stringMatching(/^\d{8}T\d{6}Z/), - 'x-amz-user-agent': expect.stringContaining('aws-amplify'), -}; diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/functional-apis.test.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/functional-apis.test.ts index c185e6cc3cb..0bcbab879ba 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/functional-apis.test.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/functional-apis.test.ts @@ -2,14 +2,16 @@ // SPDX-License-Identifier: Apache-2.0 import { HttpResponse } from '@aws-amplify/core/internals/aws-client-utils'; -import { fetchTransferHandler } from '@aws-amplify/core/dist/cjs/clients/handlers/fetch'; +import { s3TransferHandler } from '../../../../../../src/providers/s3/utils/client/runtime/s3TransferHandler/fetch'; import cases from './cases'; import { StorageError } from '../../../../../../src/errors/StorageError'; -jest.mock('@aws-amplify/core/dist/cjs/clients/handlers/fetch'); +jest.mock( + '../../../../../../src/providers/s3/utils/client/runtime/s3TransferHandler/fetch' +); -const mockFetchTransferHandler = fetchTransferHandler as jest.Mock; +const mockS3TransferHandler = s3TransferHandler as jest.Mock; const mockBinaryResponse = ({ status, headers, @@ -32,12 +34,12 @@ const mockBinaryResponse = ({ statusCode: status, headers, body: responseBody, - }; + } as any; }; describe('S3 APIs functional test', () => { beforeEach(() => { - mockFetchTransferHandler.mockReset(); + mockS3TransferHandler.mockReset(); }); test.each(cases)( '%s %s', @@ -52,15 +54,14 @@ describe('S3 APIs functional test', () => { outputOrError ) => { expect.assertions(2); - mockFetchTransferHandler.mockResolvedValue( + mockS3TransferHandler.mockResolvedValue( mockBinaryResponse(response as any) ); try { - // @ts-ignore - const output = await handler(config, input); + const output = await handler(config, input as any); if (caseType === 'happy case') { expect(output).toEqual(outputOrError); - expect(fetchTransferHandler).toBeCalledWith( + expect(mockS3TransferHandler).toHaveBeenCalledWith( expectedRequest, expect.anything() ); diff --git a/packages/storage/__tests__/providers/s3/utils/client/S3/getPresignedGetObjectUrl.test.ts b/packages/storage/__tests__/providers/s3/utils/client/S3/getPresignedGetObjectUrl.test.ts index 1c26be2f584..71c50663fc1 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/S3/getPresignedGetObjectUrl.test.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/S3/getPresignedGetObjectUrl.test.ts @@ -61,7 +61,7 @@ describe('serializeGetObjectRequest', () => { } ); - expect(mockPresignUrl).toBeCalledWith( + expect(mockPresignUrl).toHaveBeenCalledWith( expect.anything(), expect.objectContaining({ uriEscapePath: false, diff --git a/packages/storage/__tests__/providers/s3/utils/client/xhrTransferHandler-util.test.ts b/packages/storage/__tests__/providers/s3/utils/client/xhrTransferHandler-util.test.ts index 590cab4686c..58d45fbd2c2 100644 --- a/packages/storage/__tests__/providers/s3/utils/client/xhrTransferHandler-util.test.ts +++ b/packages/storage/__tests__/providers/s3/utils/client/xhrTransferHandler-util.test.ts @@ -80,7 +80,7 @@ describe('xhrTransferHandler', () => { ); mockXhrResponse(mockXhr, mock200Response); await requestPromise; - expect(mockXhr.setRequestHeader).toBeCalledTimes(1); + expect(mockXhr.setRequestHeader).toHaveBeenCalledTimes(1); expect(mockXhr.setRequestHeader).toHaveBeenCalledWith('foo', 'bar'); }); @@ -244,11 +244,11 @@ describe('xhrTransferHandler', () => { downloadEvents: [downloadProgressEvent], }); await requestPromise; - expect(onDownloadProgress).toBeCalledWith({ + expect(onDownloadProgress).toHaveBeenCalledWith({ transferredBytes: downloadProgressEvent.loaded, totalBytes: downloadProgressEvent.total, }); - expect(onUploadProgress).toBeCalledWith({ + expect(onUploadProgress).toHaveBeenCalledWith({ transferredBytes: uploadProgressEvent.loaded, totalBytes: uploadProgressEvent.total, }); @@ -301,7 +301,7 @@ describe('xhrTransferHandler', () => { }); mockXhrResponse(mockXhr, mock200Response); await requestPromise; - expect(mockXhr.getAllResponseHeaders).toBeCalledTimes(1); + expect(mockXhr.getAllResponseHeaders).toHaveBeenCalledTimes(1); }); it('should NOT process response when xhr is cleared', async () => { @@ -312,7 +312,7 @@ describe('xhrTransferHandler', () => { mockXhrResponse(mockXhr, mock200Response); await requestPromise; mockXhrResponse(mockXhr, mock200Response); - expect(mockXhr.getAllResponseHeaders).toBeCalledTimes(1); + expect(mockXhr.getAllResponseHeaders).toHaveBeenCalledTimes(1); }); it('should set Blob response with ResponseBodyMixin when xhr.responseType is blob', async () => { @@ -331,7 +331,7 @@ describe('xhrTransferHandler', () => { await body!.text(); const responseText = await body!.text(); expect(responseText).toBe(mock200Response.body); - expect(FileReader).toBeCalledTimes(1); // validate memoization + expect(FileReader).toHaveBeenCalledTimes(1); // validate memoization await expect(body!.json()).rejects.toThrow( expect.objectContaining({ @@ -362,7 +362,7 @@ describe('xhrTransferHandler', () => { await requestPromise; // Should be no-op if the xhr is already cleared mockXhrResponse(mockXhr, mock200Response); - expect(mockXhr.getAllResponseHeaders).toBeCalledTimes(1); + expect(mockXhr.getAllResponseHeaders).toHaveBeenCalledTimes(1); }); it('should immediately reject with canceled error when signal is already aborted', async () => { @@ -384,8 +384,8 @@ describe('xhrTransferHandler', () => { name: 'ERR_CANCELED', }); } - expect(mockXhr.abort).toBeCalledTimes(1); - expect(mockXhr.send).not.toBeCalled(); + expect(mockXhr.abort).toHaveBeenCalledTimes(1); + expect(mockXhr.send).not.toHaveBeenCalled(); }); it('should reject with canceled error when signal is aborted', async () => { @@ -407,7 +407,7 @@ describe('xhrTransferHandler', () => { name: 'ERR_CANCELED', }); } - expect(mockXhr.abort).toBeCalledTimes(1); - expect(mockXhr.send).toBeCalledTimes(1); + expect(mockXhr.abort).toHaveBeenCalledTimes(1); + expect(mockXhr.send).toHaveBeenCalledTimes(1); }); }); diff --git a/packages/storage/jest.config.js b/packages/storage/jest.config.js new file mode 100644 index 00000000000..06b4ec635ed --- /dev/null +++ b/packages/storage/jest.config.js @@ -0,0 +1,11 @@ +module.exports = { + ...require('../../jest.config'), + coverageThreshold: { + global: { + branches: 75, + functions: 80, + lines: 81, + statements: 91, + }, + }, +}; diff --git a/packages/storage/package.json b/packages/storage/package.json index 2ddd8b070bb..cc24b410a78 100644 --- a/packages/storage/package.json +++ b/packages/storage/package.json @@ -107,58 +107,5 @@ "@rollup/plugin-typescript": "11.1.5", "rollup": "3.29.4", "typescript": "5.0.2" - }, - "jest": { - "globals": { - "ts-jest": { - "diagnostics": { - "pathRegex": "(/__tests__/.*|\\.(test|spec))\\.(tsx?|jsx?)$" - }, - "tsConfig": { - "downlevelIteration": true, - "allowJs": true, - "types": [ - "@types/jest" - ], - "outDir": "./tsconfig.json", - "noEmitOnError": false, - "noImplicitAny": false, - "skipLibCheck": true - } - } - }, - "transform": { - "^.+\\.(js|jsx|ts|tsx)$": "ts-jest" - }, - "testRegex": "(/__tests__/.*|\\.test|spec)\\.(tsx?|jsx?)$", - "testPathIgnorePatterns": [ - "xmlParser-fixture.ts", - "testUtils", - "cases" - ], - "modulePathIgnorePatterns": [ - "dist" - ], - "moduleFileExtensions": [ - "ts", - "tsx", - "js", - "json", - "jsx" - ], - "testEnvironment": "jsdom", - "testURL": "http://localhost/", - "coverageThreshold": { - "global": { - "branches": 0, - "functions": 0, - "lines": 0, - "statements": 0 - } - }, - "coveragePathIgnorePatterns": [ - "/node_modules/", - "dist" - ] } } diff --git a/yarn.lock b/yarn.lock index 51bc5fc63d9..bc07301cf3d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -982,7 +982,7 @@ json5 "^2.1.2" semver "^6.3.0" -"@babel/core@^7.1.0", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.20.0": +"@babel/core@^7.11.6", "@babel/core@^7.12.3", "@babel/core@^7.13.16", "@babel/core@^7.14.0", "@babel/core@^7.20.0": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.23.3.tgz#5ec09c8803b91f51cc887dedc2654a35852849c9" integrity sha512-Jg+msLuNuCJDyBvFv5+OKOUjWMZgd85bKjbICd3zWrKAo+bJ49HJufi7CQE0q0uR8NGyO6xkCACScNqyjHSZew== @@ -1003,7 +1003,7 @@ json5 "^2.2.3" semver "^6.3.1" -"@babel/generator@^7.14.0", "@babel/generator@^7.17.0", "@babel/generator@^7.20.0", "@babel/generator@^7.23.3", "@babel/generator@^7.23.4", "@babel/generator@^7.4.0": +"@babel/generator@^7.14.0", "@babel/generator@^7.17.0", "@babel/generator@^7.20.0", "@babel/generator@^7.23.3", "@babel/generator@^7.23.4", "@babel/generator@^7.7.2": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.23.4.tgz#4a41377d8566ec18f807f42962a7f3551de83d1c" integrity sha512-esuS49Cga3HcThFNebGhlgsrVLkvhqvYDTzgjfFFlHJcIfLe5jFmRRfCQ1KuBfc4Jrtn3ndLgKWAKjBE+IraYQ== @@ -1211,7 +1211,7 @@ chalk "^2.4.2" js-tokens "^4.0.0" -"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.17.0", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.3", "@babel/parser@^7.23.4", "@babel/parser@^7.4.3": +"@babel/parser@^7.1.0", "@babel/parser@^7.13.16", "@babel/parser@^7.14.0", "@babel/parser@^7.14.7", "@babel/parser@^7.17.0", "@babel/parser@^7.20.0", "@babel/parser@^7.20.7", "@babel/parser@^7.22.15", "@babel/parser@^7.23.3", "@babel/parser@^7.23.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.23.4.tgz#409fbe690c333bb70187e2de4021e1e47a026661" integrity sha512-vf3Xna6UEprW+7t6EtOmFpHNAuxw3xqPZghy+brsnusscJRW5BMUzzHZc5ICjULee81WeUV2jjakG09MDglJXQ== @@ -1322,7 +1322,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13": +"@babel/plugin-syntax-bigint@^7.8.3": + version "7.8.3" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== + dependencies: + "@babel/helper-plugin-utils" "^7.8.0" + +"@babel/plugin-syntax-class-properties@^7.0.0", "@babel/plugin-syntax-class-properties@^7.12.13", "@babel/plugin-syntax-class-properties@^7.8.3": version "7.12.13" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz#b5c987274c4a3a82b89714796931a6b53544ae10" integrity sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA== @@ -1378,7 +1385,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-syntax-import-meta@^7.10.4": +"@babel/plugin-syntax-import-meta@^7.10.4", "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g== @@ -1392,14 +1399,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.23.3": +"@babel/plugin-syntax-jsx@^7.0.0", "@babel/plugin-syntax-jsx@^7.23.3", "@babel/plugin-syntax-jsx@^7.7.2": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz#8f2e4f8a9b5f9aa16067e142c1ac9cd9f810f473" integrity sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg== dependencies: "@babel/helper-plugin-utils" "^7.22.5" -"@babel/plugin-syntax-logical-assignment-operators@^7.10.4": +"@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" integrity sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig== @@ -1413,7 +1420,7 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" -"@babel/plugin-syntax-numeric-separator@^7.10.4": +"@babel/plugin-syntax-numeric-separator@^7.10.4", "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz#b9b070b3e33570cd9fd07ba7fa91c0dd37b9af97" integrity sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug== @@ -1448,14 +1455,14 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-top-level-await@^7.14.5": +"@babel/plugin-syntax-top-level-await@^7.14.5", "@babel/plugin-syntax-top-level-await@^7.8.3": version "7.14.5" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz#c1cfdadc35a646240001f06138247b741c34d94c" integrity sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw== dependencies: "@babel/helper-plugin-utils" "^7.14.5" -"@babel/plugin-syntax-typescript@^7.23.3": +"@babel/plugin-syntax-typescript@^7.23.3", "@babel/plugin-syntax-typescript@^7.7.2": version "7.23.3" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz#24f460c85dbbc983cd2b9c4994178bcc01df958f" integrity sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ== @@ -2085,7 +2092,7 @@ dependencies: regenerator-runtime "^0.14.0" -"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.22.15", "@babel/template@^7.4.0": +"@babel/template@^7.0.0", "@babel/template@^7.16.7", "@babel/template@^7.22.15", "@babel/template@^7.3.3": version "7.22.15" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.22.15.tgz#09576efc3830f0430f4548ef971dde1350ef2f38" integrity sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w== @@ -2094,7 +2101,7 @@ "@babel/parser" "^7.22.15" "@babel/types" "^7.22.15" -"@babel/traverse@^7.1.0", "@babel/traverse@^7.14.0", "@babel/traverse@^7.17.0", "@babel/traverse@^7.20.0", "@babel/traverse@^7.23.3", "@babel/traverse@^7.23.4", "@babel/traverse@^7.4.3": +"@babel/traverse@^7.14.0", "@babel/traverse@^7.17.0", "@babel/traverse@^7.20.0", "@babel/traverse@^7.23.3", "@babel/traverse@^7.23.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.23.4.tgz#c2790f7edf106d059a0098770fe70801417f3f85" integrity sha512-IYM8wSUwunWTB6tFC2dkKZhxbIjHoWemdK+3f8/wq8aKhbUscxD5MX72ubd90fxvFknaLPeGw5ycU84V1obHJg== @@ -2110,7 +2117,7 @@ debug "^4.1.0" globals "^11.1.0" -"@babel/types@^7.0.0", "@babel/types@^7.17.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3", "@babel/types@^7.23.4", "@babel/types@^7.4.0", "@babel/types@^7.4.4": +"@babel/types@^7.0.0", "@babel/types@^7.17.0", "@babel/types@^7.20.0", "@babel/types@^7.20.7", "@babel/types@^7.22.15", "@babel/types@^7.22.19", "@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.23.3", "@babel/types@^7.23.4", "@babel/types@^7.3.3", "@babel/types@^7.4.4": version "7.23.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.23.4.tgz#7206a1810fc512a7f7f7d4dace4cb4c1c9dbfb8e" integrity sha512-7uIFwVYpoplT5jp/kVv6EF93VaJ8H+Yn5IczYiaAi98ajzjfoZfslet/e0sLh+wVBjb2qqIut1b0S26VSafsSQ== @@ -2119,13 +2126,10 @@ "@babel/helper-validator-identifier" "^7.22.20" to-fast-properties "^2.0.0" -"@cnakazawa/watch@^1.0.3": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" - integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== - dependencies: - exec-sh "^0.3.2" - minimist "^1.2.0" +"@bcoe/v8-coverage@^0.2.3": + version "0.2.3" + resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@colors/colors@1.5.0": version "1.5.0" @@ -2282,48 +2286,67 @@ resolved "https://registry.yarnpkg.com/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz#291c227e93fd407a96ecd59879a35809120e432b" integrity sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ== -"@jest/console@^24.7.1", "@jest/console@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-24.9.0.tgz#79b1bc06fb74a8cfb01cbdedf945584b1b9707f0" - integrity sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ== +"@istanbuljs/load-nyc-config@^1.0.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: - "@jest/source-map" "^24.9.0" - chalk "^2.0.1" - slash "^2.0.0" + camelcase "^5.3.1" + find-up "^4.1.0" + get-package-type "^0.1.0" + js-yaml "^3.13.1" + resolve-from "^5.0.0" + +"@istanbuljs/schema@^0.1.2": + version "0.1.3" + resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.3.tgz#e45e384e4b8ec16bce2fd903af78450f6bf7ec98" + integrity sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA== + +"@jest/console@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/console/-/console-29.7.0.tgz#cd4822dbdb84529265c5a2bdb529a3c9cc950ffc" + integrity sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg== + dependencies: + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" -"@jest/core@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-24.9.0.tgz#2ceccd0b93181f9c4850e74f2a9ad43d351369c4" - integrity sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A== - dependencies: - "@jest/console" "^24.7.1" - "@jest/reporters" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" +"@jest/core@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/core/-/core-29.7.0.tgz#b6cccc239f30ff36609658c5a5e2291757ce448f" + integrity sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg== + dependencies: + "@jest/console" "^29.7.0" + "@jest/reporters" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + ci-info "^3.2.0" exit "^0.1.2" - graceful-fs "^4.1.15" - jest-changed-files "^24.9.0" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-resolve-dependencies "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - jest-watcher "^24.9.0" - micromatch "^3.1.10" - p-each-series "^1.0.0" - realpath-native "^1.1.0" - rimraf "^2.5.4" - slash "^2.0.0" - strip-ansi "^5.0.0" + graceful-fs "^4.2.9" + jest-changed-files "^29.7.0" + jest-config "^29.7.0" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-resolve-dependencies "^29.7.0" + jest-runner "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + jest-watcher "^29.7.0" + micromatch "^4.0.4" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-ansi "^6.0.0" "@jest/create-cache-key-function@^27.0.1": version "27.5.1" @@ -2339,16 +2362,6 @@ dependencies: "@jest/types" "^29.6.3" -"@jest/environment@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-24.9.0.tgz#21e3afa2d65c0586cbd6cbefe208bafade44ab18" - integrity sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ== - dependencies: - "@jest/fake-timers" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - "@jest/environment@^29.7.0": version "29.7.0" resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-29.7.0.tgz#24d61f54ff1f786f3cd4073b4b94416383baf2a7" @@ -2359,14 +2372,20 @@ "@types/node" "*" jest-mock "^29.7.0" -"@jest/fake-timers@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-24.9.0.tgz#ba3e6bf0eecd09a636049896434d306636540c93" - integrity sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A== +"@jest/expect-utils@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect-utils/-/expect-utils-29.7.0.tgz#023efe5d26a8a70f21677d0a1afc0f0a44e3a1c6" + integrity sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA== + dependencies: + jest-get-type "^29.6.3" + +"@jest/expect@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/expect/-/expect-29.7.0.tgz#76a3edb0cb753b70dfbfe23283510d3d45432bf2" + integrity sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ== dependencies: - "@jest/types" "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" + expect "^29.7.0" + jest-snapshot "^29.7.0" "@jest/fake-timers@^29.7.0": version "29.7.0" @@ -2380,32 +2399,45 @@ jest-mock "^29.7.0" jest-util "^29.7.0" -"@jest/reporters@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-24.9.0.tgz#86660eff8e2b9661d042a8e98a028b8d631a5b43" - integrity sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw== +"@jest/globals@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-29.7.0.tgz#8d9290f9ec47ff772607fa864ca1d5a2efae1d4d" + integrity sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/types" "^29.6.3" + jest-mock "^29.7.0" + +"@jest/reporters@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-29.7.0.tgz#04b262ecb3b8faa83b0b3d321623972393e8f4c7" + integrity sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg== dependencies: - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" + "@bcoe/v8-coverage" "^0.2.3" + "@jest/console" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + "@types/node" "*" + chalk "^4.0.0" + collect-v8-coverage "^1.0.0" exit "^0.1.2" - glob "^7.1.2" - istanbul-lib-coverage "^2.0.2" - istanbul-lib-instrument "^3.0.1" - istanbul-lib-report "^2.0.4" - istanbul-lib-source-maps "^3.0.1" - istanbul-reports "^2.2.6" - jest-haste-map "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - node-notifier "^5.4.2" - slash "^2.0.0" - source-map "^0.6.0" - string-length "^2.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + istanbul-lib-coverage "^3.0.0" + istanbul-lib-instrument "^6.0.0" + istanbul-lib-report "^3.0.0" + istanbul-lib-source-maps "^4.0.0" + istanbul-reports "^3.1.3" + jest-message-util "^29.7.0" + jest-util "^29.7.0" + jest-worker "^29.7.0" + slash "^3.0.0" + string-length "^4.0.1" + strip-ansi "^6.0.0" + v8-to-istanbul "^9.0.1" "@jest/schemas@^29.4.3", "@jest/schemas@^29.6.3": version "29.6.3" @@ -2414,64 +2446,55 @@ dependencies: "@sinclair/typebox" "^0.27.8" -"@jest/source-map@^24.3.0", "@jest/source-map@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-24.9.0.tgz#0e263a94430be4b41da683ccc1e6bffe2a191714" - integrity sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg== +"@jest/source-map@^29.6.3": + version "29.6.3" + resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-29.6.3.tgz#d90ba772095cf37a34a5eb9413f1b562a08554c4" + integrity sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw== dependencies: + "@jridgewell/trace-mapping" "^0.3.18" callsites "^3.0.0" - graceful-fs "^4.1.15" - source-map "^0.6.0" + graceful-fs "^4.2.9" -"@jest/test-result@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-24.9.0.tgz#11796e8aa9dbf88ea025757b3152595ad06ba0ca" - integrity sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA== +"@jest/test-result@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-29.7.0.tgz#8db9a80aa1a097bb2262572686734baed9b1657c" + integrity sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA== dependencies: - "@jest/console" "^24.9.0" - "@jest/types" "^24.9.0" + "@jest/console" "^29.7.0" + "@jest/types" "^29.6.3" "@types/istanbul-lib-coverage" "^2.0.0" + collect-v8-coverage "^1.0.0" -"@jest/test-sequencer@^24.8.0", "@jest/test-sequencer@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz#f8f334f35b625a4f2f355f2fe7e6036dad2e6b31" - integrity sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A== - dependencies: - "@jest/test-result" "^24.9.0" - jest-haste-map "^24.9.0" - jest-runner "^24.9.0" - jest-runtime "^24.9.0" - -"@jest/transform@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-24.9.0.tgz#4ae2768b296553fadab09e9ec119543c90b16c56" - integrity sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/types" "^24.9.0" - babel-plugin-istanbul "^5.1.0" - chalk "^2.0.1" - convert-source-map "^1.4.0" - fast-json-stable-stringify "^2.0.0" - graceful-fs "^4.1.15" - jest-haste-map "^24.9.0" - jest-regex-util "^24.9.0" - jest-util "^24.9.0" - micromatch "^3.1.10" - pirates "^4.0.1" - realpath-native "^1.1.0" - slash "^2.0.0" - source-map "^0.6.1" - write-file-atomic "2.4.1" +"@jest/test-sequencer@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-29.7.0.tgz#6cef977ce1d39834a3aea887a1726628a6f072ce" + integrity sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw== + dependencies: + "@jest/test-result" "^29.7.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + slash "^3.0.0" -"@jest/types@^24.8.0", "@jest/types@^24.9.0": - version "24.9.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-24.9.0.tgz#63cb26cb7500d069e5a389441a7c6ab5e909fc59" - integrity sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw== +"@jest/transform@^29.7.0": + version "29.7.0" + resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-29.7.0.tgz#df2dd9c346c7d7768b8a06639994640c642e284c" + integrity sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw== dependencies: - "@types/istanbul-lib-coverage" "^2.0.0" - "@types/istanbul-reports" "^1.1.1" - "@types/yargs" "^13.0.0" + "@babel/core" "^7.11.6" + "@jest/types" "^29.6.3" + "@jridgewell/trace-mapping" "^0.3.18" + 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.7.0" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + micromatch "^4.0.4" + pirates "^4.0.4" + slash "^3.0.0" + write-file-atomic "^4.0.2" "@jest/types@^26.6.2": version "26.6.2" @@ -2539,7 +2562,7 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== -"@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": +"@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.18", "@jridgewell/trace-mapping@^0.3.9": version "0.3.20" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz#72e45707cf240fa6b081d0366f8265b0cd10197f" integrity sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q== @@ -4509,7 +4532,7 @@ resolved "https://registry.yarnpkg.com/@types/archy/-/archy-0.0.32.tgz#8b572741dad9172dfbf289397af1bb41296d3e40" integrity sha512-5ZZ5+YGmUE01yejiXsKnTcvhakMZ2UllZlMsQni53Doc1JWhe21ia8VntRoRD6fAEWw08JBh/z9qQHJ+//MrIg== -"@types/babel__core@^7.1.0": +"@types/babel__core@^7.1.14": version "7.20.5" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.5.tgz#3df15f27ba85319caa07ba08d0721889bb39c017" integrity sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA== @@ -4591,7 +4614,14 @@ "@types/minimatch" "*" "@types/node" "*" -"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": +"@types/graceful-fs@^4.1.3": + version "4.1.9" + resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.9.tgz#2a06bc0f68a20ab37b3e36aa238be6abdf49e8b4" + integrity sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ== + dependencies: + "@types/node" "*" + +"@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.6" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz#7739c232a1fee9b4d3ce8985f314c0c6d33549d7" integrity sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w== @@ -4603,14 +4633,6 @@ dependencies: "@types/istanbul-lib-coverage" "*" -"@types/istanbul-reports@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" - integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== - dependencies: - "@types/istanbul-lib-coverage" "*" - "@types/istanbul-lib-report" "*" - "@types/istanbul-reports@^3.0.0": version "3.0.4" resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz#0f03e3d2f670fbdac586e34b433783070cc16f54" @@ -4618,18 +4640,28 @@ dependencies: "@types/istanbul-lib-report" "*" -"@types/jest@^24.0.18": - version "24.9.1" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.1.tgz#02baf9573c78f1b9974a5f36778b366aa77bd534" - integrity sha512-Fb38HkXSVA4L8fGKEZ6le5bB8r6MRWlOCZbVuWZcmOMSCd2wCYOwN1ibj8daIoV9naq7aaOZjrLCoCMptKU/4Q== +"@types/jest@^29.5.8": + version "29.5.10" + resolved "https://registry.yarnpkg.com/@types/jest/-/jest-29.5.10.tgz#a10fc5bab9e426081c12b2ef73d24d4f0c9b7f50" + integrity sha512-tE4yxKEphEyxj9s4inideLHktW/x6DwesIwWZ9NN1FKf9zbJYsnhBoA9vrHA/IuIOKwPa5PcFBNV4lpMIOEzyQ== dependencies: - jest-diff "^24.3.0" + expect "^29.0.0" + pretty-format "^29.0.0" "@types/js-cookie@3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@types/js-cookie/-/js-cookie-3.0.2.tgz#451eaeece64c6bdac8b2dde0caab23b085899e0d" integrity sha512-6+0ekgfusHftJNYpihfkMu8BWdeHs9EOJuGcSofErjstGPfPGEu9yTu4t460lTzzAMl2cM5zngQJqPMHbbnvYA== +"@types/jsdom@^20.0.0": + version "20.0.1" + resolved "https://registry.yarnpkg.com/@types/jsdom/-/jsdom-20.0.1.tgz#07c14bc19bd2f918c1929541cdaacae894744808" + integrity sha512-d0r18sZPmMQr1eG35u12FZfhIXNrnsPU/g5wvRKCUf/tOGilKKwYMYGqh33BNR6ba+2gkHw1EUiHoN3mn7E5IQ== + dependencies: + "@types/node" "*" + "@types/tough-cookie" "*" + parse5 "^7.0.0" + "@types/json-schema@*", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" @@ -4752,16 +4784,16 @@ resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.6.tgz#c65b2bfce1bec346582c07724e3f8c1017a20339" integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== -"@types/stack-utils@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" - integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== - "@types/stack-utils@^2.0.0": version "2.0.3" resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-2.0.3.tgz#6209321eb2c1712a7e7466422b8cb1fc0d9dd5d8" integrity sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw== +"@types/tough-cookie@*": + version "4.0.5" + resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-4.0.5.tgz#cb6e2a691b70cb177c6e3ae9c1d2e8b2ea8cd304" + integrity sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA== + "@types/triple-beam@^1.3.2": version "1.3.5" resolved "https://registry.yarnpkg.com/@types/triple-beam/-/triple-beam-1.3.5.tgz#74fef9ffbaa198eb8b588be029f38b00299caa2c" @@ -4791,13 +4823,6 @@ resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-21.0.3.tgz#815e30b786d2e8f0dcd85fd5bcf5e1a04d008f15" integrity sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ== -"@types/yargs@^13.0.0": - version "13.0.12" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-13.0.12.tgz#d895a88c703b78af0465a9de88aa92c61430b092" - integrity sha512-qCxJE1qgz2y0hA4pIxjBR+PelCH0U5CK1XJXFwCNqfmliatKp47UCXXE9Dyk1OXBDLvsCF57TqQEJaeLfDYEOQ== - dependencies: - "@types/yargs-parser" "*" - "@types/yargs@^15.0.0": version "15.0.19" resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.19.tgz#328fb89e46109ecbdb70c295d96ff2f46dfd01b9" @@ -5003,7 +5028,7 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -abab@^2.0.0: +abab@^2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291" integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA== @@ -5038,40 +5063,25 @@ accepts@^1.3.7, accepts@~1.3.5, accepts@~1.3.7: mime-types "~2.1.34" negotiator "0.6.3" -acorn-globals@^4.1.0: - version "4.3.4" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.3.4.tgz#9fa1926addc11c97308c4e66d7add0d40c3272e7" - integrity sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A== +acorn-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-7.0.1.tgz#0dbf05c44fa7c94332914c02066d5beff62c40c3" + integrity sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q== dependencies: - acorn "^6.0.1" - acorn-walk "^6.0.1" + acorn "^8.1.0" + acorn-walk "^8.0.2" acorn-import-assertions@^1.9.0: version "1.9.0" resolved "https://registry.yarnpkg.com/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz#507276249d684797c84e0734ef84860334cfb1ac" integrity sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA== -acorn-walk@^6.0.1: - version "6.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.2.0.tgz#123cb8f3b84c2171f1f7fb252615b1c78a6b1a8c" - integrity sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA== - -acorn-walk@^8.0.0: +acorn-walk@^8.0.0, acorn-walk@^8.0.2: version "8.3.0" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.3.0.tgz#2097665af50fd0cf7a2dfccd2b9368964e66540f" integrity sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA== -acorn@^5.5.3: - version "5.7.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" - integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== - -acorn@^6.0.1: - version "6.4.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" - integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== - -acorn@^8.0.4, acorn@^8.7.1, acorn@^8.8.2: +acorn@^8.0.4, acorn@^8.1.0, acorn@^8.7.1, acorn@^8.8.1, acorn@^8.8.2: version "8.11.2" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.2.tgz#ca0d78b51895be5390a5903c5b3bdcdaf78ae40b" integrity sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w== @@ -5108,7 +5118,7 @@ ajv-keywords@^3.5.2: resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== -ajv@^6.12.3, ajv@^6.12.4, ajv@^6.12.5: +ajv@^6.12.4, ajv@^6.12.5: version "6.12.6" resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== @@ -5133,11 +5143,6 @@ ansi-escapes@^1.1.0: resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" integrity sha512-wiXutNjDUlNEDWHcYH3jtZUhd3c4/VojassD8zHdHCY13xbZy2XbW+NKQwA0tWGBVzDA9qEzYwfoSsWmviidhw== -ansi-escapes@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -5159,12 +5164,7 @@ ansi-regex@^2.0.0: resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" integrity sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA== -ansi-regex@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.1.tgz#123d6479e92ad45ad897d4054e3c7ca7db4944e1" - integrity sha512-+O9Jct8wf++lXxxFc4hc8LsjaSq0HFzzL7cVsw8pRDIPdjKD2mT4ytDZlLuSBZ4cLKZFXIrMGO7DbQCtMJJMKw== - -ansi-regex@^4.0.0, ansi-regex@^4.1.0: +ansi-regex@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.1.tgz#164daac87ab2d6f6db3a29875e2d1766582dabed" integrity sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g== @@ -5208,14 +5208,6 @@ ansi-styles@^6.1.0: resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-6.2.1.tgz#0e62320cf99c21afff3b3012192546aacbfb05c5" integrity sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug== -anymatch@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" - integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== - dependencies: - micromatch "^3.1.4" - normalize-path "^2.1.1" - anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.3" resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" @@ -5285,39 +5277,11 @@ argv@0.0.2: resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" integrity sha512-dEamhpPEwRUBpLNHeuCm/v+g0anFByHahxodVO/BbAarHVBBg2MccCwf9K+o1Pof+2btdnkJelYVUWjW/VrATw== -arr-diff@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" - integrity sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA== - -arr-flatten@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" - integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== - -arr-union@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" - integrity sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q== - -array-buffer-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.0.tgz#fabe8bc193fea865f317fe7807085ee0dee5aead" - integrity sha512-LPuwb2P+NrQw3XhxGc36+XSvuBPopovXYTR9Ew++Du9Yb/bx5AzBfrIsBoj0EZUifjQU+sHL21sseZ3jerWO/A== - dependencies: - call-bind "^1.0.2" - is-array-buffer "^3.0.1" - array-differ@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== -array-equal@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.2.tgz#a8572e64e822358271250b9156d20d96ef5dec04" - integrity sha512-gUHx76KtnhEgB3HOuFYiCm3FIdEs6ocM2asHvNTkfu/Y09qQVrrVVaOKENmS2KkSaGoxgXNqC+ZVtR/n0MOkSA== - array-ify@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" @@ -5328,35 +5292,6 @@ 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== -array-unique@^0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" - integrity sha512-SleRWjh9JUud2wH1hPs9rZBZ33H6T9HOiL0uwGnGx9FpE6wKGyfWugmbkEOIs6qWrZhg0LWeLziLrEwQJhs5mQ== - -array.prototype.reduce@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/array.prototype.reduce/-/array.prototype.reduce-1.0.6.tgz#63149931808c5fc1e1354814923d92d45f7d96d5" - integrity sha512-UW+Mz8LG/sPSU8jRDCjVr6J/ZKAGpHfwrZ6kWTG5qCxIEiXdVshqGnu5vEZA8S1y6X4aCSbQZ0/EEsfvEvBiSg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -arraybuffer.prototype.slice@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.2.tgz#98bd561953e3e74bb34938e77647179dfe6e9f12" - integrity sha512-yMBKppFur/fbHu9/6USUe03bZ4knMYiwFBcyiaXB8Go0qNehwX6inYPzK9U0NeQvGxKthcmHcaR8P5MStSRBAw== - dependencies: - array-buffer-byte-length "^1.0.0" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-array-buffer "^3.0.2" - is-shared-array-buffer "^1.0.2" - arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -5372,23 +5307,6 @@ asap@~2.0.6: resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA== -asn1@~0.2.3: - version "0.2.6" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.6.tgz#0d3a7bb6e64e02a90c0303b31f292868ea09a08d" - integrity sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw== - -assign-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" - integrity sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw== - ast-types@0.15.2: version "0.15.2" resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.15.2.tgz#39ae4809393c4b16df751ee563411423e85fb49d" @@ -5421,21 +5339,6 @@ atob@^2.1.2: resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== -available-typed-arrays@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz#92f95616501069d07d10edb2fc37d3e1c65123b7" - integrity sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw== - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA== - -aws4@^1.8.0: - version "1.12.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" - integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== - axios@^1.0.0: version "1.6.2" resolved "https://registry.yarnpkg.com/axios/-/axios-1.6.2.tgz#de67d42c755b571d3e698df1b6504cde9b0ee9f2" @@ -5450,18 +5353,18 @@ babel-core@^7.0.0-bridge.0: resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-7.0.0-bridge.0.tgz#95a492ddd90f9b4e9a4a1da14eb335b87b634ece" integrity sha512-poPX9mZH/5CSanm50Q+1toVci6pv5KSRv/5TWCwtzQS5XEwn40BcCrgIeMFWP9CKKIniKXNxoIOnOq4VVlGXhg== -babel-jest@^24.8.0, babel-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-24.9.0.tgz#3fc327cb8467b89d14d7bc70e315104a783ccd54" - integrity sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw== +babel-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-29.7.0.tgz#f4369919225b684c56085998ac63dbd05be020d5" + integrity sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg== dependencies: - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/babel__core" "^7.1.0" - babel-plugin-istanbul "^5.1.0" - babel-preset-jest "^24.9.0" - chalk "^2.4.2" - slash "^2.0.0" + "@jest/transform" "^29.7.0" + "@types/babel__core" "^7.1.14" + babel-plugin-istanbul "^6.1.1" + babel-preset-jest "^29.6.3" + chalk "^4.0.0" + graceful-fs "^4.2.9" + slash "^3.0.0" babel-loader@^8.3.0: version "8.3.0" @@ -5473,21 +5376,25 @@ babel-loader@^8.3.0: make-dir "^3.1.0" schema-utils "^2.6.5" -babel-plugin-istanbul@^5.1.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz#df4ade83d897a92df069c4d9a25cf2671293c854" - integrity sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw== +babel-plugin-istanbul@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz#fa88ec59232fd9b4e36dbbc540a8ec9a9b47da73" + integrity sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA== dependencies: "@babel/helper-plugin-utils" "^7.0.0" - find-up "^3.0.0" - istanbul-lib-instrument "^3.3.0" - test-exclude "^5.2.3" + "@istanbuljs/load-nyc-config" "^1.0.0" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-instrument "^5.0.4" + test-exclude "^6.0.0" -babel-plugin-jest-hoist@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz#4f837091eb407e01447c8843cbec546d0002d756" - integrity sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw== +babel-plugin-jest-hoist@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.6.3.tgz#aadbe943464182a8922c3c927c3067ff40d24626" + integrity sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg== 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-module-resolver@^5.0.0: @@ -5537,6 +5444,24 @@ babel-plugin-transform-flow-enums@^0.0.2: dependencies: "@babel/plugin-syntax-flow" "^7.12.1" +babel-preset-current-node-syntax@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz#b4399239b89b2a011f9ddbe3e4f401fc40cff73b" + integrity sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ== + dependencies: + "@babel/plugin-syntax-async-generators" "^7.8.4" + "@babel/plugin-syntax-bigint" "^7.8.3" + "@babel/plugin-syntax-class-properties" "^7.8.3" + "@babel/plugin-syntax-import-meta" "^7.8.3" + "@babel/plugin-syntax-json-strings" "^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators" "^7.8.3" + "@babel/plugin-syntax-nullish-coalescing-operator" "^7.8.3" + "@babel/plugin-syntax-numeric-separator" "^7.8.3" + "@babel/plugin-syntax-object-rest-spread" "^7.8.3" + "@babel/plugin-syntax-optional-catch-binding" "^7.8.3" + "@babel/plugin-syntax-optional-chaining" "^7.8.3" + "@babel/plugin-syntax-top-level-await" "^7.8.3" + babel-preset-fbjs@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/babel-preset-fbjs/-/babel-preset-fbjs-3.4.0.tgz#38a14e5a7a3b285a3f3a86552d650dca5cf6111c" @@ -5570,13 +5495,13 @@ babel-preset-fbjs@^3.4.0: "@babel/plugin-transform-template-literals" "^7.0.0" babel-plugin-syntax-trailing-function-commas "^7.0.0-beta.0" -babel-preset-jest@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz#192b521e2217fb1d1f67cf73f70c336650ad3cdc" - integrity sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg== +babel-preset-jest@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-29.6.3.tgz#fa05fa510e7d493896d7b0dd2033601c840f171c" + integrity sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA== dependencies: - "@babel/plugin-syntax-object-rest-spread" "^7.0.0" - babel-plugin-jest-hoist "^24.9.0" + babel-plugin-jest-hoist "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" balanced-match@^1.0.0: version "1.0.2" @@ -5598,26 +5523,6 @@ base64-js@^1.0.2, base64-js@^1.1.2, base64-js@^1.2.3, base64-js@^1.3.1, base64-j resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== -base@^0.11.1: - version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" - integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== - dependencies: - cache-base "^1.0.1" - class-utils "^0.3.5" - component-emitter "^1.2.1" - define-property "^1.0.0" - isobject "^3.0.1" - mixin-deep "^1.2.0" - pascalcase "^0.1.1" - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w== - dependencies: - tweetnacl "^0.14.3" - before-after-hook@^2.2.0: version "2.2.3" resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c" @@ -5648,13 +5553,6 @@ binary-extensions@^2.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - bl@^4.0.3, bl@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" @@ -5698,22 +5596,6 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" -braces@^2.3.1: - version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" - integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== - dependencies: - arr-flatten "^1.1.0" - array-unique "^0.3.2" - extend-shallow "^2.0.1" - fill-range "^4.0.0" - isobject "^3.0.1" - repeat-element "^1.1.2" - snapdragon "^0.8.1" - snapdragon-node "^2.0.1" - split-string "^3.0.2" - to-regex "^3.0.1" - braces@^3.0.2, braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -5721,18 +5603,6 @@ braces@^3.0.2, braces@~3.0.2: dependencies: fill-range "^7.0.1" -browser-process-hrtime@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" - integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== - -browser-resolve@^1.11.3: - version "1.11.3" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.3.tgz#9b7cbb3d0f510e4cb86bdbd796124d28b5890af6" - integrity sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ== - dependencies: - resolve "1.1.7" - browserslist@^4.14.5, browserslist@^4.21.9, browserslist@^4.22.1: version "4.22.1" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.22.1.tgz#ba91958d1a59b87dab6fed8dfbcb3da5e2e9c619" @@ -5764,7 +5634,7 @@ bser@2.1.1: dependencies: node-int64 "^0.4.0" -buffer-from@1.x, buffer-from@^1.0.0: +buffer-from@^1.0.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== @@ -5904,22 +5774,7 @@ cacache@^17.0.0, cacache@^17.0.4: tar "^6.1.11" unique-filename "^3.0.0" -cache-base@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" - integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== - dependencies: - collection-visit "^1.0.0" - component-emitter "^1.2.1" - get-value "^2.0.6" - has-value "^1.0.0" - isobject "^3.0.1" - set-value "^2.0.0" - to-object-path "^0.3.0" - union-value "^1.0.0" - unset-value "^1.0.0" - -call-bind@^1.0.0, call-bind@^1.0.2, call-bind@^1.0.4, call-bind@^1.0.5: +call-bind@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.5.tgz#6fa2b7845ce0ea49bf4d8b9ef64727a2c2e2e513" integrity sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ== @@ -5966,11 +5821,6 @@ camelcase@^3.0.0: resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" integrity sha512-4nhGqUkc4BqbBBB4Q6zLuD7lzzrHYrjKGeYaEji/3tFR5VdJu9v+LilhGIVe8wxEJPPOeWo7eg8dwY13TZ1BNg== -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha512-FxAv7HpHrXbh3aPo4o2qxHay2lkLY3x5Mw3KeE4KQE8ysVfziWeRZDwcjauvwBSGEC/nXUPzZy8zeh4HokqOnw== - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" @@ -5986,18 +5836,6 @@ caniuse-lite@^1.0.30001406, caniuse-lite@^1.0.30001541: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001563.tgz#aa68a64188903e98f36eb9c56e48fba0c1fe2a32" integrity sha512-na2WUmOxnwIZtwnFI2CZ/3er0wdNzU7hN+cPYz/z2ajHThnkWjNBOpEPP4n+4r2WPM847JaMotaJE3bnfzjyKw== -capture-exit@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" - integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== - dependencies: - rsvp "^4.8.4" - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw== - chalk@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.0.tgz#4e14870a618d9e2edd97dd8345fd9d9dc315646a" @@ -6017,7 +5855,7 @@ chalk@^1.0.0: strip-ansi "^3.0.0" supports-color "^2.0.0" -chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.2: +chalk@^2.3.0, chalk@^2.4.2: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== @@ -6034,6 +5872,11 @@ chalk@^4.0.0, chalk@^4.0.2, chalk@^4.1.0, chalk@^4.1.1, chalk@^4.1.2: ansi-styles "^4.1.0" supports-color "^7.1.0" +char-regex@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== + chardet@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" @@ -6079,15 +5922,10 @@ ci-info@^3.2.0, ci-info@^3.6.1: resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.9.0.tgz#4279a62028a7b1f262f3473fc9605f5e218c59b4" integrity sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ== -class-utils@^0.3.5: - version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" - integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== - dependencies: - arr-union "^3.1.0" - define-property "^0.2.5" - isobject "^3.0.0" - static-extend "^0.1.1" +cjs-module-lexer@^1.0.0: + version "1.2.3" + resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.3.tgz#6c370ab19f8a3394e318fe682686ec0ac684d107" + integrity sha512-0TNiGstbQmCFwt4akjjBg5pLRTSyj/PkWQ1ZoO2zntmg9yLqSRxwEa4iCfQLGjqhiqBfOJa7W/E8wfGrTDmlZQ== classnames@^2.2.6: version "2.3.2" @@ -6247,13 +6085,10 @@ codecov@^3.6.5: teeny-request "7.1.1" urlgrey "1.0.0" -collection-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" - integrity sha512-lNkKvzEeMBBjUGHZ+q6z9pSJla0KWAQPvtzhEV9+iGyQYG+pBpl7xKDhxoNSOZH2hhv0v5k0y2yAM4o4SjoSkw== - dependencies: - map-visit "^1.0.0" - object-visit "^1.0.0" +collect-v8-coverage@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz#c0b29bcd33bcd0779a1344c2136051e6afd3d9e9" + integrity sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q== color-convert@^1.9.0, color-convert@^1.9.3: version "1.9.3" @@ -6331,7 +6166,7 @@ columnify@1.6.0: strip-ansi "^6.0.1" wcwidth "^1.0.0" -combined-stream@^1.0.6, combined-stream@^1.0.8, combined-stream@~1.0.6: +combined-stream@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== @@ -6396,11 +6231,6 @@ compare-func@^2.0.0: array-ify "^1.0.0" dot-prop "^5.1.0" -component-emitter@^1.2.1: - version "1.3.1" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.1.tgz#ef1d5796f7d93f135ee6fb684340b26403c97d17" - integrity sha512-T0+barUSQRTUQASh8bx02dl+DhF54GtIDY13Y3m9oWTklKbb3Wv974meRpeZ3lp1JpLVECWWNHC4vaG2XHXouQ== - compressible@~2.0.16: version "2.0.18" resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.18.tgz#af53cca6b070d4c3c0750fbd77286a6d7cc46fba" @@ -6534,7 +6364,7 @@ conventional-recommended-bump@7.0.1: git-semver-tags "^5.0.0" meow "^8.1.2" -convert-source-map@^1.1.0, convert-source-map@^1.4.0, convert-source-map@^1.7.0: +convert-source-map@^1.1.0, convert-source-map@^1.7.0: version "1.9.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.9.0.tgz#7faae62353fb4213366d0ca98358d22e8368b05f" integrity sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A== @@ -6549,11 +6379,6 @@ cookie@0.5.0: resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.5.0.tgz#d1f5d71adec6558c58f389987c366aa47e994f8b" integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== -copy-descriptor@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" - integrity sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw== - core-js-compat@^3.31.0, core-js-compat@^3.33.1: version "3.33.3" resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.33.3.tgz#ec678b772c5a2d8a7c60a91c3a81869aa704ae01" @@ -6561,16 +6386,6 @@ core-js-compat@^3.31.0, core-js-compat@^3.33.1: dependencies: browserslist "^4.22.1" -core-js@^3.4: - version "3.33.3" - resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.33.3.tgz#3c644a323f0f533a0d360e9191e37f7fc059088d" - integrity sha512-lo0kOocUlLKmm6kv/FswQL8zbkH7mVsLJ/FULClOhv8WRVmKLVcs6XPNQAzstfeJTCHMyButEwG+z1kHxHoDZw== - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ== - core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85" @@ -6596,6 +6411,19 @@ cosmiconfig@^8.2.0: parse-json "^5.2.0" path-type "^4.0.0" +create-jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/create-jest/-/create-jest-29.7.0.tgz#a355c5b3cb1e1af02ba177fe7afd7feee49a5320" + integrity sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + exit "^0.1.2" + graceful-fs "^4.2.9" + jest-config "^29.7.0" + jest-util "^29.7.0" + prompts "^2.0.1" + cross-fetch@^3.0.4: version "3.1.8" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" @@ -6638,17 +6466,22 @@ cssesc@^3.0.0: resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== -cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0": +cssom@^0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.5.0.tgz#d254fa92cd8b6fbd83811b9fbaed34663cc17c36" + integrity sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw== + +cssom@~0.3.6: version "0.3.8" resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== -cssstyle@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.4.0.tgz#9d31328229d3c565c61e586b02041a28fccdccf1" - integrity sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA== +cssstyle@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: - cssom "0.3.x" + cssom "~0.3.6" csstype@^3.0.2: version "3.1.2" @@ -6660,21 +6493,14 @@ dargs@^7.0.0: resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g== - dependencies: - assert-plus "^1.0.0" - -data-urls@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-1.1.0.tgz#15ee0582baa5e22bb59c77140da8f9c76963bbfe" - integrity sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ== +data-urls@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-3.0.2.tgz#9cf24a477ae22bcef5cd5f6f0bfbc1d2d3be9143" + integrity sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ== dependencies: - abab "^2.0.0" - whatwg-mimetype "^2.2.0" - whatwg-url "^7.0.0" + abab "^2.0.6" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" dateformat@^3.0.3: version "3.0.3" @@ -6691,7 +6517,7 @@ debounce@^1.2.1: resolved "https://registry.yarnpkg.com/debounce/-/debounce-1.2.1.tgz#38881d8f4166a5c5848020c11827b834bcb3e0a5" integrity sha512-XRRe6Glud4rd/ZGQfiV1ruXSfbvfJedlV9Y6zOlP+2K04vBYiJEte6stfFkCP03aMnY5tsipamumUjL14fofug== -debug@2.6.9, debug@^2.2.0, debug@^2.3.3: +debug@2.6.9, debug@^2.2.0: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== @@ -6718,6 +6544,11 @@ decamelize@^1.1.0, decamelize@^1.1.1, decamelize@^1.2.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" integrity sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA== +decimal.js@^10.4.2: + version "10.4.3" + resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.4.3.tgz#1044092884d245d1b7f65725fa4ad4c6f781cc23" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + decode-uri-component@^0.2.0: version "0.2.2" resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" @@ -6728,6 +6559,11 @@ dedent@0.7.0: resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" integrity sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA== +dedent@^1.0.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/dedent/-/dedent-1.5.1.tgz#4f3fc94c8b711e9bb2800d185cd6ad20f2a90aff" + integrity sha512-+LxW+KLWxu3HW3M2w2ympwtqPrqYRzU8fqi6Fhd18fBALe15blJPI/I4+UHveMVG6lJqB4JNd4UG0S5cnVHwIg== + deep-equal@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.2.tgz#78a561b7830eef3134c7f6f3a3d6af272a678761" @@ -6740,17 +6576,12 @@ deep-equal@^1.1.1: object-keys "^1.1.1" regexp.prototype.flags "^1.5.1" -deep-is@~0.1.3: - version "0.1.4" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - deepmerge@^3.2.0: version "3.3.0" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-3.3.0.tgz#d3c47fd6f3a93d517b14426b0628a17b0125f5f7" integrity sha512-GRQOafGHwMHpjPx9iCvTgpu9NojZ49q794EEL94JVEw6VaeA8XTUyBKvAkOOjBX9oJNiV6G3P+T+tihFjo2TqA== -deepmerge@^4.3.0: +deepmerge@^4.2.2, deepmerge@^4.3.0: version "4.3.1" resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.3.1.tgz#44b5f2147cd3b00d4b56137685966f26fd25dd4a" integrity sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A== @@ -6776,7 +6607,7 @@ define-lazy-prop@^2.0.0: resolved "https://registry.yarnpkg.com/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz#3f7ae421129bcaaac9bc74905c98a0009ec9ee7f" integrity sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og== -define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: +define-properties@^1.1.3, define-properties@^1.2.0: version "1.2.1" resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== @@ -6785,28 +6616,6 @@ define-properties@^1.1.3, define-properties@^1.1.4, define-properties@^1.2.0: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -define-property@^0.2.5: - version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" - integrity sha512-Rr7ADjQZenceVOAKop6ALkkRAmH1A4Gx9hV/7ZujPUN2rkATqFO0JZLZInbAjpZYoJ1gUx8MRMQVkYemcbMSTA== - dependencies: - is-descriptor "^0.1.0" - -define-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" - integrity sha512-cZTYKFWspt9jZsMscWo8sc/5lbPC9Q0N5nBLgb+Yd915iL3udB1uFgS3B8YCx66UVHq018DAVFoee7x+gxggeA== - dependencies: - is-descriptor "^1.0.0" - -define-property@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" - integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== - dependencies: - is-descriptor "^1.0.2" - isobject "^3.0.1" - del@^6.0.0: version "6.1.1" resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" @@ -6879,10 +6688,10 @@ detect-libc@^2.0.0: resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.2.tgz#8ccf2ba9315350e1241b88d0ac3b0e1fbd99605d" integrity sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw== -detect-newline@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" - integrity sha512-CwffZFvlJffUg9zZA0uqrjQayUTC8ob94pnr5sFwaVv3IOmkfUHcWH+jXaQK3askE51Cqe8/9Ql/0uXNwqZ8Zg== +detect-newline@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== dexie-export-import@1.0.3: version "1.0.3" @@ -6894,11 +6703,6 @@ dexie@3.2.2: resolved "https://registry.yarnpkg.com/dexie/-/dexie-3.2.2.tgz#fa6f2a3c0d6ed0766f8d97a03720056f88fe0e01" integrity sha512-q5dC3HPmir2DERlX+toCBbHQXW5MsyrFqPFcovkH9N2S/UW/H3H5AWAB6iEOExeraAu+j+zRDG+zg/D7YhH0qg== -diff-sequences@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-24.9.0.tgz#5715d6244e2aa65f48bba0bc972db0b0b11e95b5" - integrity sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew== - diff-sequences@^29.6.3: version "29.6.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.6.3.tgz#4deaf894d11407c51efc8418012f9e70b84ea921" @@ -6931,6 +6735,13 @@ domexception@^1.0.1: dependencies: webidl-conversions "^4.0.2" +domexception@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/domexception/-/domexception-4.0.0.tgz#4ad1be56ccadc86fc76d033353999a8037d03673" + integrity sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw== + dependencies: + webidl-conversions "^7.0.0" + dot-prop@^5.1.0: version "5.3.0" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" @@ -6963,14 +6774,6 @@ eastasianwidth@^0.2.0: resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" integrity sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA== -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw== - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -6988,6 +6791,11 @@ electron-to-chromium@^1.4.535: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.590.tgz#85a428fbabb77265a4804040837ed4f2538e3300" integrity sha512-hohItzsQcG7/FBsviCYMtQwUSWvVF7NVqPOnJCErWsAshsP/CR2LAXdmq276RbESNdhxiAq5/vRo1g2pxGXVww== +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@^7.0.1: version "7.0.3" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" @@ -7047,6 +6855,11 @@ enquirer@~2.3.6: dependencies: ansi-colors "^4.1.1" +entities@^4.4.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-4.5.0.tgz#5d268ea5e7113ec74c4d033b79ea5a35a488fb48" + integrity sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw== + env-paths@^2.2.0: version "2.2.1" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.1.tgz#420399d416ce1fbe9bc0a07c62fa68d67fd0f8f2" @@ -7089,79 +6902,11 @@ errorhandler@^1.5.0, errorhandler@^1.5.1: accepts "~1.3.7" escape-html "~1.0.3" -es-abstract@^1.22.1: - version "1.22.3" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.22.3.tgz#48e79f5573198de6dee3589195727f4f74bc4f32" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.12" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz#873f3e84418de4ee19c5be752990b2e44718d09e" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - es-module-lexer@^1.2.1: version "1.4.1" resolved "https://registry.yarnpkg.com/es-module-lexer/-/es-module-lexer-1.4.1.tgz#41ea21b43908fe6a287ffcbe4300f790555331f5" integrity sha512-cXLGjP0c4T3flZJKQSuziYoq7MlT+rnvfZjfp7h+I7K9BNX54kP9nyWvdbwjQ4u1iWbOL4u96fgeZLToQlZC7w== -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz#11f7cc9f63376930a5f20be4915834f4bc74f9c9" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== - dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.1.tgz#e55cd4c9cdc188bcefb03b366c736323fc5c898a" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" @@ -7187,15 +6932,14 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -escodegen@^1.9.1: - version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" - integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== +escodegen@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.1.0.tgz#ba93bbb7a43986d29d6041f99f5262da773e2e17" + integrity sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w== dependencies: esprima "^4.0.1" - estraverse "^4.2.0" + estraverse "^5.2.0" esutils "^2.0.2" - optionator "^0.8.1" optionalDependencies: source-map "~0.6.1" @@ -7219,7 +6963,7 @@ esrecurse@^4.3.0: dependencies: estraverse "^5.2.0" -estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1: version "4.3.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== @@ -7269,11 +7013,6 @@ events@^3.2.0, events@^3.3.0: resolved "https://registry.yarnpkg.com/events/-/events-3.3.0.tgz#31a95ad0a924e2d2c419a813aeb2c4e878ea7400" integrity sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q== -exec-sh@^0.3.2: - version "0.3.6" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.6.tgz#ff264f9e325519a60cb5e273692943483cca63bc" - integrity sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w== - execa@5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/execa/-/execa-5.0.0.tgz#4029b0007998a841fbd1032e5f4de86a3c1e3376" @@ -7332,30 +7071,16 @@ exit@^0.1.2: resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" integrity sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ== -expand-brackets@^2.1.4: - version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" - integrity sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA== - dependencies: - debug "^2.3.3" - define-property "^0.2.5" - extend-shallow "^2.0.1" - posix-character-classes "^0.1.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -expect@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-24.9.0.tgz#b75165b4817074fa4a157794f46fe9f1ba15b6ca" - integrity sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q== - dependencies: - "@jest/types" "^24.9.0" - ansi-styles "^3.2.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-regex-util "^24.9.0" +expect@^29.0.0, expect@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/expect/-/expect-29.7.0.tgz#578874590dcb3214514084c08115d8aee61e11bc" + integrity sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw== + dependencies: + "@jest/expect-utils" "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" expo-file-system@13.1.4: version "13.1.4" @@ -7377,22 +7102,7 @@ exponential-backoff@^3.1.1: resolved "https://registry.yarnpkg.com/exponential-backoff/-/exponential-backoff-3.1.1.tgz#64ac7526fe341ab18a39016cd22c787d01e00bf6" integrity sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw== -extend-shallow@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" - integrity sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug== - dependencies: - is-extendable "^0.1.0" - -extend-shallow@^3.0.0, extend-shallow@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" - integrity sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q== - dependencies: - assign-symbols "^1.0.0" - is-extendable "^1.0.1" - -extend@^3.0.0, extend@~3.0.2: +extend@^3.0.0: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -7415,37 +7125,12 @@ external-editor@^3.0.3: iconv-lite "^0.4.24" tmp "^0.0.33" -extglob@^2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" - integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== - dependencies: - array-unique "^0.3.2" - define-property "^1.0.0" - expand-brackets "^2.1.4" - extend-shallow "^2.0.1" - fragment-cache "^0.2.1" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g== - -extsprintf@^1.2.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.1.tgz#8d172c064867f235c0c84a596806d279bf4bcc07" - integrity sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA== - -fake-indexeddb@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-3.0.0.tgz#1bd0ffce41b0f433409df301d334d8fd7d77da27" - integrity sha512-VrnV9dJWlVWvd8hp9MMR+JS4RLC4ZmToSkuCg91ZwpYE5mSODb3n5VEaV62Hf3AusnbrPfwQhukU+rGZm5W8PQ== +fake-indexeddb@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/fake-indexeddb/-/fake-indexeddb-4.0.2.tgz#e7a884158fa576e00f03e973b9874619947013e4" + integrity sha512-SdTwEhnakbgazc7W3WUXOJfGmhH0YfG4d+dRPOFoYDRTL6U5t8tvrmkf2W/C3W1jk2ylV7Wrnj44RASqpX/lEw== dependencies: - realistic-structured-clone "^2.0.1" - setimmediate "^1.0.5" + realistic-structured-clone "^3.0.0" fast-base64-decode@^1.0.0: version "1.0.0" @@ -7479,16 +7164,11 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" -fast-json-stable-stringify@2.x, 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== -fast-levenshtein@~2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - fast-url-parser@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" @@ -7561,11 +7241,6 @@ figures@^1.3.5: escape-string-regexp "^1.0.5" object-assign "^4.1.0" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - file-url@3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/file-url/-/file-url-3.0.0.tgz#247a586a746ce9f7a8ed05560290968afc262a77" @@ -7578,16 +7253,6 @@ filelist@^1.0.4: dependencies: minimatch "^5.0.1" -fill-range@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" - integrity sha512-VcpLTWqWDiTerugjj8e3+esbg+skS3M9e54UuR3iCeIDMXCLTsAH8hTSzDQU/X6/6t3eYkOKoZSef2PlU6U1XQ== - dependencies: - extend-shallow "^2.0.1" - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range "^2.1.0" - fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -7714,18 +7379,6 @@ follow-redirects@^1.15.0: resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.3.tgz#fe2f3ef2690afce7e82ed0b44db08165b207123a" integrity sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q== -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -for-in@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" - integrity sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ== - foreground-child@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-3.1.1.tgz#1d173e776d75d2772fed08efe4a0de1ea1b12d0d" @@ -7734,11 +7387,6 @@ foreground-child@^3.1.0: cross-spawn "^7.0.0" signal-exit "^4.0.1" -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw== - form-data@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" @@ -7748,22 +7396,6 @@ form-data@^4.0.0: combined-stream "^1.0.8" mime-types "^2.1.12" -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -fragment-cache@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" - integrity sha512-GMBAbW9antB8iZRHLoGw0b3HANt57diZYFO/HL1JGIC1MjKrdmhxvrJbupnVvpys0zsz7yBApXdQyfepKly2kA== - dependencies: - map-cache "^0.2.2" - fresh@0.5.2: version "0.5.2" resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" @@ -7836,14 +7468,6 @@ fs.realpath@^1.0.0: resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@^1.2.7: - version "1.2.13" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.13.tgz#f325cb0455592428bcf11b383370ef70e3bfcc38" - integrity sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw== - dependencies: - bindings "^1.5.0" - nan "^2.12.1" - fsevents@^2.1.2, fsevents@^2.3.2, fsevents@~2.3.2: version "2.3.3" resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" @@ -7854,16 +7478,6 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.6.tgz#cdf315b7d90ee77a4c6ee216c3c3362da07533fd" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - functions-have-names@^1.2.3: version "1.2.3" resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" @@ -7936,7 +7550,7 @@ get-caller-file@^2.0.0, get-caller-file@^2.0.1, get-caller-file@^2.0.5: resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@^1.2.0, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.2.tgz#281b7622971123e1ef4b3c90fd7539306da93f3b" integrity sha512-0gSo4ml/0j98Y3lngkFEot/zhiCeWsbYIlZ+uZOVgzLyLaUw7wxUL+nCTP0XJvJg1AXulJRI3UJi8GsbDuxdGA== @@ -7946,6 +7560,11 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-package-type@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== + get-pkg-repo@^4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" @@ -7978,31 +7597,11 @@ get-stream@^6.0.0: resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== -get-symbol-description@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.0.0.tgz#7fdb81c900101fbd564dd5f1a30af5aadc1e58d6" - integrity sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.1" - -get-value@^2.0.3, get-value@^2.0.6: - version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" - integrity sha512-Ln0UQDlxH1BapMu3GPtf7CuYNwRZf2gwCuPqbyG6pB8WfmFpzqcy4xtAaAMUhnNqjMKTiCPZG2oMT3YSx8U2NA== - getenv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/getenv/-/getenv-1.0.0.tgz#874f2e7544fbca53c7a4738f37de8605c3fcfc31" integrity sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg== -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng== - dependencies: - assert-plus "^1.0.0" - git-raw-commits@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-3.0.0.tgz#5432f053a9744f67e8db03dbc48add81252cfdeb" @@ -8102,7 +7701,7 @@ glob@^10.2.2, glob@^10.3.10: minipass "^5.0.0 || ^6.0.2 || ^7.0.0" path-scurry "^1.10.1" -glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4: +glob@^7.0.0, glob@^7.1.1, glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -8140,13 +7739,6 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.3.tgz#5852882a52b80dc301b0660273e1ed082f0b6ccf" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - globby@11.1.0, globby@^11.0.1, globby@^11.1.0: version "11.1.0" resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" @@ -8190,11 +7782,6 @@ graphql@15.8.0: resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.8.0.tgz#33410e96b012fa3bdb1091cc99a94769db212b38" integrity sha512-5gghUc24tP9HRznNpV2+FIoq3xKkj5dTQqf4v0CpdPbFVwFkWoxOM+o+2OC9ZSvjEMTjfmG9QT+gcvggTwW1zw== -growly@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" - integrity sha512-+xGQY0YyAWCnqy7Cd++hc2JqMYzlm0dG30Jd0beaA64sROr8C4nt8Yc9V5Ro3avlSUDTN0ulqP/VBKi1/lLygw== - gud@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" @@ -8219,19 +7806,6 @@ handlebars@^4.7.6, handlebars@^4.7.7: optionalDependencies: uglify-js "^3.1.4" -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q== - -har-validator@~5.1.3: - version "5.1.5" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd" - integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w== - dependencies: - ajv "^6.12.3" - har-schema "^2.0.0" - hard-rejection@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" @@ -8244,11 +7818,6 @@ has-ansi@^2.0.0: dependencies: ansi-regex "^2.0.0" -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.0.2.tgz#0871bd3e3d51626f6ca0966668ba35d5602d6eaa" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - has-flag@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" @@ -8288,37 +7857,6 @@ has-unicode@2.0.1, has-unicode@^2.0.1: resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -has-value@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" - integrity sha512-gpG936j8/MzaeID5Yif+577c17TxaDmhuyVgSwtnL/q8UUTySg8Mecb+8Cf1otgLoD7DDH75axp86ER7LFsf3Q== - dependencies: - get-value "^2.0.3" - has-values "^0.1.4" - isobject "^2.0.0" - -has-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" - integrity sha512-IBXk4GTsLYdQ7Rvt+GRBrFSVEkmuOUy4re0Xjd9kJSUQpnTrWR4/y9RpfexN9vkAPMFuQoeWKwqzPozRTlasGw== - dependencies: - get-value "^2.0.6" - has-values "^1.0.0" - isobject "^3.0.0" - -has-values@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" - integrity sha512-J8S0cEdWuQbqD9//tlZxiMuMNmxB8PlEwvYwuxsTmR1G5RXUePEX/SJn7aD0GMLieuZYSwNH0cQuJGwnYunXRQ== - -has-values@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" - integrity sha512-ODYZC64uqzmtfGMEAX/FvZiRyWLpAC3vYnNunURUnkGVTS+mI0smVsWaPydRBsE3g+ok7h960jChO8mFcWlHaQ== - dependencies: - is-number "^3.0.0" - kind-of "^4.0.0" - hasown@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.0.tgz#f4c513d454a57b7c7e1650778de226b11700546c" @@ -8388,12 +7926,12 @@ hosted-git-info@^6.0.0, hosted-git-info@^6.1.1: dependencies: lru-cache "^7.5.1" -html-encoding-sniffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8" - integrity sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw== +html-encoding-sniffer@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-3.0.0.tgz#2cb1a8cf0db52414776e5b2a7a04d5dd98158de9" + integrity sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA== dependencies: - whatwg-encoding "^1.0.1" + whatwg-encoding "^2.0.0" html-escaper@^2.0.0, html-escaper@^2.0.2: version "2.0.2" @@ -8434,16 +7972,7 @@ http-proxy-agent@^5.0.0: agent-base "6" debug "4" -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ== - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -https-proxy-agent@^5.0.0: +https-proxy-agent@^5.0.0, https-proxy-agent@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz#c59ef224a04fe8b754f3db0063a25ea30d0005d6" integrity sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA== @@ -8463,20 +7992,20 @@ humanize-ms@^1.2.1: dependencies: ms "^2.0.0" -iconv-lite@0.4.24, iconv-lite@^0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.6.2: +iconv-lite@0.6.3, iconv-lite@^0.6.2: version "0.6.3" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" +iconv-lite@^0.4.24: + version "0.4.24" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== + dependencies: + safer-buffer ">= 2.1.2 < 3" + idb@5.0.6: version "5.0.6" resolved "https://registry.yarnpkg.com/idb/-/idb-5.0.6.tgz#8c94624f5a8a026abe3bef3c7166a5febd1cadc1" @@ -8559,14 +8088,6 @@ import-local@3.1.0, import-local@^3.0.2: pkg-dir "^4.2.0" resolve-cwd "^3.0.0" -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" @@ -8675,15 +8196,6 @@ inquirer@^8.2.4: through "^2.3.6" wrap-ansi "^6.0.1" -internal-slot@^1.0.5: - version "1.0.6" - resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.0.6.tgz#37e756098c4911c5e912b8edbf71ed3aa116f930" - integrity sha512-Xj6dv+PsbtwyPpEflsejS+oIZxmMlV44zAhG479uYu89MsjcYOhCFnNyKrkJrihbsiasQyY0afoCl/9BLR65bg== - dependencies: - get-intrinsic "^1.2.2" - hasown "^2.0.0" - side-channel "^1.0.4" - interpret@^1.0.0: version "1.4.0" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" @@ -8721,13 +8233,6 @@ ip@^2.0.0: resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" integrity sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ== -is-accessor-descriptor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.1.tgz#3223b10628354644b86260db29b3e693f5ceedd4" - integrity sha512-YBUanLI8Yoihw923YeFUS5fs0fF2f5TSFTNiYAAzhhDscDa3lEqYuz1pDOEP5KvX94I9ey3vsqjJcLVFVU+3QA== - dependencies: - hasown "^2.0.0" - is-arguments@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/is-arguments/-/is-arguments-1.1.1.tgz#15b3f88fda01f2a97fec84ca761a560f123efa9b" @@ -8736,15 +8241,6 @@ is-arguments@^1.1.1: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-array-buffer@^3.0.1, is-array-buffer@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.2.tgz#f2653ced8412081638ecb0ebbd0c41c6e0aecbbe" - integrity sha512-y+FyyR/w8vfIRq4eQcM1EYgSTnmHXPqaF+IgzgraytCFq5Xh8lllDVmAZolPJiZttZLeFSINPYMaEJ7/vWUa1w== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.0" - is-typed-array "^1.1.10" - is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" @@ -8755,13 +8251,6 @@ is-arrayish@^0.3.1: resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.0.4.tgz#08147a1875bc2b32005d41ccd8291dffc6691df3" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - is-binary-path@~2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" @@ -8769,24 +8258,11 @@ is-binary-path@~2.1.0: dependencies: binary-extensions "^2.0.0" -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.1.2.tgz#5c6dc200246dd9321ae4b885a114bb1f75f63719" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-buffer@^1.1.5, is-buffer@~1.1.6: +is-buffer@~1.1.6: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - is-ci@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-3.0.1.tgz#db6ecbed1bd659c43dac0f45661e7674103d1867" @@ -8794,13 +8270,6 @@ is-ci@3.0.1: dependencies: ci-info "^3.2.0" -is-ci@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" - integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== - dependencies: - ci-info "^2.0.0" - is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.8.1: version "2.13.1" resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.13.1.tgz#ad0d7532c6fea9da1ebdc82742d74525c6273384" @@ -8808,36 +8277,13 @@ is-core-module@^2.13.0, is-core-module@^2.5.0, is-core-module@^2.8.1: dependencies: hasown "^2.0.0" -is-data-descriptor@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.1.tgz#2109164426166d32ea38c405c1e0945d9e6a4eeb" - integrity sha512-bc4NlCDiCr28U4aEsQ3Qs2491gVq4V8G7MQyws968ImqjKuYtTJXrl7Vq7jsN7Ly/C3xj5KWFrY7sHNeDkAzXw== - dependencies: - hasown "^2.0.0" - -is-date-object@^1.0.1, is-date-object@^1.0.5: +is-date-object@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.5.tgz#0841d5536e724c25597bf6ea62e1bd38298df31f" integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== dependencies: has-tostringtag "^1.0.0" -is-descriptor@^0.1.0: - version "0.1.7" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.7.tgz#2727eb61fd789dcd5bdf0ed4569f551d2fe3be33" - integrity sha512-C3grZTvObeN1xud4cRWl366OMXZTj0+HGyk4hvfpx4ZHt1Pb60ANSXqCK7pdOTeUQpRzECBSTphqvD7U+l22Eg== - dependencies: - is-accessor-descriptor "^1.0.1" - is-data-descriptor "^1.0.1" - -is-descriptor@^1.0.0, is-descriptor@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.3.tgz#92d27cb3cd311c4977a4db47df457234a13cb306" - integrity sha512-JCNNGbwWZEVaSPtS45mdtrneRWJFp07LLmykxeFV5F6oBvNF8vHSfJuJgoT472pSfk+Mf8VnlrspaFBHWM8JAw== - dependencies: - is-accessor-descriptor "^1.0.1" - is-data-descriptor "^1.0.1" - is-directory@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" @@ -8848,18 +8294,6 @@ is-docker@^2.0.0, is-docker@^2.1.1: resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" integrity sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ== -is-extendable@^0.1.0, is-extendable@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" - integrity sha512-5BMULNob1vgFX6EjQw5izWDxrecWK9AM72rugNr0TFldMOi0fj6Jk+zeKIt0xGj4cEfQIJth4w3OKWOJ4f+AFw== - -is-extendable@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" - integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== - dependencies: - is-plain-object "^2.0.4" - is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" @@ -8909,25 +8343,6 @@ is-module@^1.0.0: resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" integrity sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g== -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/is-negative-zero/-/is-negative-zero-2.0.2.tgz#7bf6f03a28003b8b3965de3ac26f664d765f3150" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.0.7.tgz#59d50ada4c45251784e9904f5246c742f07a42fc" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" - integrity sha512-4cboCqIpliH+mAvFNegjZQ4kgKc3ZUhQVr3HvWbSh5q3WH2v82ct+T2Y1hdU5Gdtorx/cLifQjqCbL7bpznLTg== - dependencies: - kind-of "^3.0.2" - is-number@^7.0.0: version "7.0.0" resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" @@ -8958,7 +8373,7 @@ is-plain-obj@^2.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== -is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -8970,6 +8385,11 @@ is-plain-object@^5.0.0: resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== +is-potential-custom-element-name@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5" + integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ== + is-regex@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.1.4.tgz#eef5663cd59fa4c0ae339505323df6854bb15958" @@ -8978,13 +8398,6 @@ is-regex@^1.1.4: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz#8f259c573b60b6a32d4058a1a07430c0a7344c79" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - is-ssh@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.4.0.tgz#4f8220601d2839d8fa624b3106f8e8884f01b8b2" @@ -9007,20 +8420,6 @@ is-stream@^2.0.0: resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.0.7.tgz#0dd12bf2006f255bb58f695110eff7491eebc0fd" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.4.tgz#a6dac93b635b063ca6872236de88910a57af139c" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - is-text-path@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" @@ -9033,18 +8432,6 @@ is-there@^4.3.3: resolved "https://registry.yarnpkg.com/is-there/-/is-there-4.5.1.tgz#ea292e7fad3fc4d70763fe0af40a286c9f5e1e2e" integrity sha512-vIZ7HTXAoRoIwYSsTnxb0sg9L6rth+JOulNcavsbskQkCIWoSM2cjFOWZs4wGziGZER+Xgs/HXiCQZgiL8ppxQ== -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.9: - version "1.1.12" - resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.12.tgz#d0bab5686ef4a76f7a73097b95470ab199c57d4a" - integrity sha512-Z14TF2JNG8Lss5/HMqt0//T9JeHXttXy5pH/DBU4vi98ozO2btxzq9MwYDZYnKwU8nRsz/+GVFVRDq3DkVuSPg== - dependencies: - which-typed-array "^1.1.11" - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA== - is-unicode-supported@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" @@ -9055,18 +8442,6 @@ is-utf8@^0.2.0: resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" integrity sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q== -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.0.2.tgz#9529f383a9338205e89765e0392efc2f100f06f2" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -is-windows@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" - integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== - is-wsl@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" @@ -9089,11 +8464,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.5.tgz#8af1e4c1221244cc62459faf38940d4e644a5723" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -9106,60 +8476,63 @@ isobject@^2.0.0: dependencies: isarray "1.0.0" -isobject@^3.0.0, isobject@^3.0.1: +isobject@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" integrity sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg== -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g== +istanbul-lib-coverage@^3.0.0, istanbul-lib-coverage@^3.2.0: + version "3.2.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz#2d166c4b0644d43a39f04bf6c2edd1e585f31756" + integrity sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg== -istanbul-lib-coverage@^2.0.2, istanbul-lib-coverage@^2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz#675f0ab69503fad4b1d849f736baaca803344f49" - integrity sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA== +istanbul-lib-instrument@^5.0.4: + version "5.2.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz#d10c8885c2125574e1c231cacadf955675e1ce3d" + integrity sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^6.3.0" -istanbul-lib-instrument@^3.0.1, istanbul-lib-instrument@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz#a5f63d91f0bbc0c3e479ef4c5de027335ec6d630" - integrity sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA== - dependencies: - "@babel/generator" "^7.4.0" - "@babel/parser" "^7.4.3" - "@babel/template" "^7.4.0" - "@babel/traverse" "^7.4.3" - "@babel/types" "^7.4.0" - istanbul-lib-coverage "^2.0.5" - semver "^6.0.0" +istanbul-lib-instrument@^6.0.0: + version "6.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.1.tgz#71e87707e8041428732518c6fb5211761753fbdf" + integrity sha512-EAMEJBsYuyyztxMxW3g7ugGPkrZsV57v0Hmv3mm1uQsmB+QnZuepg731CRaIgeUVSdmsTngOkSnauNF8p7FIhA== + dependencies: + "@babel/core" "^7.12.3" + "@babel/parser" "^7.14.7" + "@istanbuljs/schema" "^0.1.2" + istanbul-lib-coverage "^3.2.0" + semver "^7.5.4" -istanbul-lib-report@^2.0.4: - version "2.0.8" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz#5a8113cd746d43c4889eba36ab10e7d50c9b4f33" - integrity sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ== +istanbul-lib-report@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz#908305bac9a5bd175ac6a74489eafd0fc2445a7d" + integrity sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw== dependencies: - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - supports-color "^6.1.0" + istanbul-lib-coverage "^3.0.0" + make-dir "^4.0.0" + supports-color "^7.1.0" -istanbul-lib-source-maps@^3.0.1: - version "3.0.6" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz#284997c48211752ec486253da97e3879defba8c8" - integrity sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw== +istanbul-lib-source-maps@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz#895f3a709fcfba34c6de5a42939022f3e4358551" + integrity sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw== dependencies: debug "^4.1.1" - istanbul-lib-coverage "^2.0.5" - make-dir "^2.1.0" - rimraf "^2.6.3" + istanbul-lib-coverage "^3.0.0" source-map "^0.6.1" -istanbul-reports@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-2.2.7.tgz#5d939f6237d7b48393cc0959eab40cd4fd056931" - integrity sha512-uu1F/L1o5Y6LzPVSVZXNOoD/KXpJue9aeLRd0sM9uMXfZvzomB0WxVamWb5ue8kA2vVWEmW7EG+A5n3f1kqHKg== +istanbul-reports@^3.1.3: + version "3.1.6" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.1.6.tgz#2544bcab4768154281a2f0870471902704ccaa1a" + integrity sha512-TLgnMkKg3iTDsQ9PbPTdpfAK2DzjF9mqUG7RMgcQl8oFjad8ob4laGxv5XV5U9MAfx8D6tSJiUyuAwzLicaxlg== dependencies: html-escaper "^2.0.0" + istanbul-lib-report "^3.0.0" jackspeak@^2.3.5: version "2.3.6" @@ -9180,81 +8553,87 @@ jake@^10.8.5: filelist "^1.0.4" minimatch "^3.1.2" -jest-changed-files@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-24.9.0.tgz#08d8c15eb79a7fa3fc98269bc14b451ee82f8039" - integrity sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg== +jest-changed-files@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-29.7.0.tgz#1c06d07e77c78e1585d020424dedc10d6e17ac3a" + integrity sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w== dependencies: - "@jest/types" "^24.9.0" - execa "^1.0.0" - throat "^4.0.0" + execa "^5.0.0" + jest-util "^29.7.0" + p-limit "^3.1.0" -jest-cli@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-24.9.0.tgz#ad2de62d07472d419c6abc301fc432b98b10d2af" - integrity sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg== +jest-circus@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-circus/-/jest-circus-29.7.0.tgz#b6817a45fcc835d8b16d5962d0c026473ee3668a" + integrity sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/expect" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + co "^4.6.0" + dedent "^1.0.0" + is-generator-fn "^2.0.0" + jest-each "^29.7.0" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-runtime "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + p-limit "^3.1.0" + pretty-format "^29.7.0" + pure-rand "^6.0.0" + slash "^3.0.0" + stack-utils "^2.0.3" + +jest-cli@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-29.7.0.tgz#5592c940798e0cae677eec169264f2d839a37995" + integrity sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg== dependencies: - "@jest/core" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" + "@jest/core" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + chalk "^4.0.0" + create-jest "^29.7.0" exit "^0.1.2" - import-local "^2.0.0" - is-ci "^2.0.0" - jest-config "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - prompts "^2.0.1" - realpath-native "^1.1.0" - yargs "^13.3.0" + import-local "^3.0.2" + jest-config "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + yargs "^17.3.1" -jest-config@24.8.0: - version "24.8.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.8.0.tgz#77db3d265a6f726294687cbbccc36f8a76ee0f4f" - integrity sha512-Czl3Nn2uEzVGsOeaewGWoDPD8GStxCpAe0zOYs2x2l0fZAgPbCr3uwUkgNKV3LwE13VXythM946cd5rdGkkBZw== +jest-config@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-29.7.0.tgz#bcbda8806dbcc01b1e316a46bb74085a84b0245f" + integrity sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ== dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.8.0" - "@jest/types" "^24.8.0" - babel-jest "^24.8.0" - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^24.8.0" - jest-environment-node "^24.8.0" - jest-get-type "^24.8.0" - jest-jasmine2 "^24.8.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.8.0" - jest-util "^24.8.0" - jest-validate "^24.8.0" - micromatch "^3.1.10" - pretty-format "^24.8.0" - realpath-native "^1.1.0" - -jest-config@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-24.9.0.tgz#fb1bbc60c73a46af03590719efa4825e6e4dd1b5" - integrity sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ== - dependencies: - "@babel/core" "^7.1.0" - "@jest/test-sequencer" "^24.9.0" - "@jest/types" "^24.9.0" - babel-jest "^24.9.0" - chalk "^2.0.1" - glob "^7.1.1" - jest-environment-jsdom "^24.9.0" - jest-environment-node "^24.9.0" - jest-get-type "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - micromatch "^3.1.10" - pretty-format "^24.9.0" - realpath-native "^1.1.0" - -"jest-diff@>=29.4.3 < 30": + "@babel/core" "^7.11.6" + "@jest/test-sequencer" "^29.7.0" + "@jest/types" "^29.6.3" + babel-jest "^29.7.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 "^29.7.0" + jest-environment-node "^29.7.0" + jest-get-type "^29.6.3" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-runner "^29.7.0" + jest-util "^29.7.0" + jest-validate "^29.7.0" + micromatch "^4.0.4" + parse-json "^5.2.0" + pretty-format "^29.7.0" + slash "^3.0.0" + strip-json-comments "^3.1.1" + +"jest-diff@>=29.4.3 < 30", jest-diff@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-29.7.0.tgz#017934a66ebb7ecf6f205e84699be10afd70458a" integrity sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw== @@ -9264,58 +8643,39 @@ jest-config@^24.9.0: jest-get-type "^29.6.3" pretty-format "^29.7.0" -jest-diff@^24.3.0, jest-diff@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-24.9.0.tgz#931b7d0d5778a1baf7452cb816e325e3724055da" - integrity sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ== - dependencies: - chalk "^2.0.1" - diff-sequences "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-docblock@^24.3.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-24.9.0.tgz#7970201802ba560e1c4092cc25cbedf5af5a8ce2" - integrity sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA== - dependencies: - detect-newline "^2.1.0" - -jest-each@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-24.9.0.tgz#eb2da602e2a610898dbc5f1f6df3ba86b55f8b05" - integrity sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog== - dependencies: - "@jest/types" "^24.9.0" - chalk "^2.0.1" - jest-get-type "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - -jest-environment-jsdom@^24.8.0, jest-environment-jsdom@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz#4b0806c7fc94f95edb369a69cc2778eec2b7375b" - integrity sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - jsdom "^11.5.1" - -jest-environment-node@^24.8.0, jest-environment-node@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-24.9.0.tgz#333d2d2796f9687f2aeebf0742b519f33c1cbfd3" - integrity sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA== - dependencies: - "@jest/environment" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/types" "^24.9.0" - jest-mock "^24.9.0" - jest-util "^24.9.0" - -jest-environment-node@^29.2.1: +jest-docblock@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-29.7.0.tgz#8fddb6adc3cdc955c93e2a87f61cfd350d5d119a" + integrity sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g== + dependencies: + detect-newline "^3.0.0" + +jest-each@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-29.7.0.tgz#162a9b3f2328bdd991beaabffbb74745e56577d1" + integrity sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ== + dependencies: + "@jest/types" "^29.6.3" + chalk "^4.0.0" + jest-get-type "^29.6.3" + jest-util "^29.7.0" + pretty-format "^29.7.0" + +jest-environment-jsdom@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-29.7.0.tgz#d206fa3551933c3fd519e5dfdb58a0f5139a837f" + integrity sha512-k9iQbsf9OyOfdzWH8HDmrRT0gSIcX+FLNW7IQq94tFX0gynPwqDTW0Ho6iMVNjGz/nb+l/vW3dWM2bbLLpkbXA== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/jsdom" "^20.0.0" + "@types/node" "*" + jest-mock "^29.7.0" + jest-util "^29.7.0" + jsdom "^20.0.0" + +jest-environment-node@^29.2.1, jest-environment-node@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-29.7.0.tgz#0b93e111dda8ec120bc8300e6d1fb9576e164376" integrity sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw== @@ -9335,11 +8695,6 @@ jest-fetch-mock@3.0.3: cross-fetch "^3.0.4" promise-polyfill "^8.1.3" -jest-get-type@^24.8.0, jest-get-type@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-24.9.0.tgz#1684a0c8a50f2e4901b6644ae861f579eed2ef0e" - integrity sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q== - jest-get-type@^26.3.0: version "26.3.0" resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.3.0.tgz#e97dc3c3f53c2b406ca7afaed4493b1d099199e0" @@ -9350,78 +8705,42 @@ jest-get-type@^29.6.3: resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-29.6.3.tgz#36f499fdcea197c1045a127319c0481723908fd1" integrity sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw== -jest-haste-map@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-24.9.0.tgz#b38a5d64274934e21fa417ae9a9fbeb77ceaac7d" - integrity sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ== +jest-haste-map@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-29.7.0.tgz#3c2396524482f5a0506376e6c858c3bbcc17b104" + integrity sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA== dependencies: - "@jest/types" "^24.9.0" - anymatch "^2.0.0" + "@jest/types" "^29.6.3" + "@types/graceful-fs" "^4.1.3" + "@types/node" "*" + anymatch "^3.0.3" fb-watchman "^2.0.0" - graceful-fs "^4.1.15" - invariant "^2.2.4" - jest-serializer "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.9.0" - micromatch "^3.1.10" - sane "^4.0.3" - walker "^1.0.7" + graceful-fs "^4.2.9" + jest-regex-util "^29.6.3" + jest-util "^29.7.0" + jest-worker "^29.7.0" + micromatch "^4.0.4" + walker "^1.0.8" optionalDependencies: - fsevents "^1.2.7" - -jest-jasmine2@^24.8.0, jest-jasmine2@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz#1f7b1bd3242c1774e62acabb3646d96afc3be6a0" - integrity sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw== - dependencies: - "@babel/traverse" "^7.1.0" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - co "^4.6.0" - expect "^24.9.0" - is-generator-fn "^2.0.0" - jest-each "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-runtime "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - pretty-format "^24.9.0" - throat "^4.0.0" - -jest-leak-detector@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz#b665dea7c77100c5c4f7dfcb153b65cf07dcf96a" - integrity sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA== - dependencies: - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-matcher-utils@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz#f5b3661d5e628dffe6dd65251dfdae0e87c3a073" - integrity sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA== - dependencies: - chalk "^2.0.1" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - pretty-format "^24.9.0" - -jest-message-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-24.9.0.tgz#527f54a1e380f5e202a8d1149b0ec872f43119e3" - integrity sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw== + fsevents "^2.3.2" + +jest-leak-detector@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-29.7.0.tgz#5b7ec0dadfdfec0ca383dc9aa016d36b5ea4c728" + integrity sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw== dependencies: - "@babel/code-frame" "^7.0.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/stack-utils" "^1.0.1" - chalk "^2.0.1" - micromatch "^3.1.10" - slash "^2.0.0" - stack-utils "^1.0.1" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" + +jest-matcher-utils@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz#ae8fec79ff249fd592ce80e3ee474e83a6c44f12" + integrity sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g== + dependencies: + chalk "^4.0.0" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + pretty-format "^29.7.0" jest-message-util@^29.7.0: version "29.7.0" @@ -9438,13 +8757,6 @@ jest-message-util@^29.7.0: slash "^3.0.0" stack-utils "^2.0.3" -jest-mock@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-24.9.0.tgz#c22835541ee379b908673ad51087a2185c13f1c6" - integrity sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w== - dependencies: - "@jest/types" "^24.9.0" - jest-mock@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-29.7.0.tgz#4e836cf60e99c6fcfabe9f99d017f3fdd50a6347" @@ -9454,99 +8766,98 @@ jest-mock@^29.7.0: "@types/node" "*" jest-util "^29.7.0" -jest-pnp-resolver@^1.2.1: +jest-pnp-resolver@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz#930b1546164d4ad5937d5540e711d4d38d4cad2e" integrity sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w== -jest-regex-util@^24.3.0, jest-regex-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-24.9.0.tgz#c13fb3380bde22bf6575432c493ea8fe37965636" - integrity sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA== - jest-regex-util@^27.0.6: version "27.5.1" resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-27.5.1.tgz#4da143f7e9fd1e542d4aa69617b38e4a78365b95" integrity sha512-4bfKq2zie+x16okqDXjXn9ql2B0dScQu+vcwe4TvFVhkVyuWLqpZrZtXxLLWoXYgn0E87I6r6GRYHF7wFZBUvg== -jest-resolve-dependencies@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz#ad055198959c4cfba8a4f066c673a3f0786507ab" - integrity sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g== - dependencies: - "@jest/types" "^24.9.0" - jest-regex-util "^24.3.0" - jest-snapshot "^24.9.0" - -jest-resolve@^24.8.0, jest-resolve@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-24.9.0.tgz#dff04c7687af34c4dd7e524892d9cf77e5d17321" - integrity sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ== - dependencies: - "@jest/types" "^24.9.0" - browser-resolve "^1.11.3" - chalk "^2.0.1" - jest-pnp-resolver "^1.2.1" - realpath-native "^1.1.0" - -jest-runner@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-24.9.0.tgz#574fafdbd54455c2b34b4bdf4365a23857fcdf42" - integrity sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - chalk "^2.4.2" - exit "^0.1.2" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-docblock "^24.3.0" - jest-haste-map "^24.9.0" - jest-jasmine2 "^24.9.0" - jest-leak-detector "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - jest-runtime "^24.9.0" - jest-util "^24.9.0" - jest-worker "^24.6.0" - source-map-support "^0.5.6" - throat "^4.0.0" - -jest-runtime@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-24.9.0.tgz#9f14583af6a4f7314a6a9d9f0226e1a781c8e4ac" - integrity sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw== - dependencies: - "@jest/console" "^24.7.1" - "@jest/environment" "^24.9.0" - "@jest/source-map" "^24.3.0" - "@jest/transform" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - chalk "^2.0.1" - exit "^0.1.2" - glob "^7.1.3" - graceful-fs "^4.1.15" - jest-config "^24.9.0" - jest-haste-map "^24.9.0" - jest-message-util "^24.9.0" - jest-mock "^24.9.0" - jest-regex-util "^24.3.0" - jest-resolve "^24.9.0" - jest-snapshot "^24.9.0" - jest-util "^24.9.0" - jest-validate "^24.9.0" - realpath-native "^1.1.0" - slash "^2.0.0" - strip-bom "^3.0.0" - yargs "^13.3.0" +jest-regex-util@^29.6.3: + version "29.6.3" + resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-29.6.3.tgz#4a556d9c776af68e1c5f48194f4d0327d24e8a52" + integrity sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg== + +jest-resolve-dependencies@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-29.7.0.tgz#1b04f2c095f37fc776ff40803dc92921b1e88428" + integrity sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA== + dependencies: + jest-regex-util "^29.6.3" + jest-snapshot "^29.7.0" + +jest-resolve@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-29.7.0.tgz#64d6a8992dd26f635ab0c01e5eef4399c6bcbc30" + integrity sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA== + dependencies: + chalk "^4.0.0" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-pnp-resolver "^1.2.2" + jest-util "^29.7.0" + jest-validate "^29.7.0" + resolve "^1.20.0" + resolve.exports "^2.0.0" + slash "^3.0.0" + +jest-runner@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-29.7.0.tgz#809af072d408a53dcfd2e849a4c976d3132f718e" + integrity sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ== + dependencies: + "@jest/console" "^29.7.0" + "@jest/environment" "^29.7.0" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + emittery "^0.13.1" + graceful-fs "^4.2.9" + jest-docblock "^29.7.0" + jest-environment-node "^29.7.0" + jest-haste-map "^29.7.0" + jest-leak-detector "^29.7.0" + jest-message-util "^29.7.0" + jest-resolve "^29.7.0" + jest-runtime "^29.7.0" + jest-util "^29.7.0" + jest-watcher "^29.7.0" + jest-worker "^29.7.0" + p-limit "^3.1.0" + source-map-support "0.5.13" -jest-serializer@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-24.9.0.tgz#e6d7d7ef96d31e8b9079a714754c5d5c58288e73" - integrity sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ== +jest-runtime@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-29.7.0.tgz#efecb3141cf7d3767a3a0cc8f7c9990587d3d817" + integrity sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ== + dependencies: + "@jest/environment" "^29.7.0" + "@jest/fake-timers" "^29.7.0" + "@jest/globals" "^29.7.0" + "@jest/source-map" "^29.6.3" + "@jest/test-result" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + chalk "^4.0.0" + cjs-module-lexer "^1.0.0" + collect-v8-coverage "^1.0.0" + glob "^7.1.3" + graceful-fs "^4.2.9" + jest-haste-map "^29.7.0" + jest-message-util "^29.7.0" + jest-mock "^29.7.0" + jest-regex-util "^29.6.3" + jest-resolve "^29.7.0" + jest-snapshot "^29.7.0" + jest-util "^29.7.0" + slash "^3.0.0" + strip-bom "^4.0.0" jest-serializer@^27.0.6: version "27.5.1" @@ -9556,42 +8867,31 @@ jest-serializer@^27.0.6: "@types/node" "*" graceful-fs "^4.2.9" -jest-snapshot@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-24.9.0.tgz#ec8e9ca4f2ec0c5c87ae8f925cf97497b0e951ba" - integrity sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew== - dependencies: - "@babel/types" "^7.0.0" - "@jest/types" "^24.9.0" - chalk "^2.0.1" - expect "^24.9.0" - jest-diff "^24.9.0" - jest-get-type "^24.9.0" - jest-matcher-utils "^24.9.0" - jest-message-util "^24.9.0" - jest-resolve "^24.9.0" - mkdirp "^0.5.1" +jest-snapshot@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-29.7.0.tgz#c2c574c3f51865da1bb329036778a69bf88a6be5" + integrity sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw== + 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/types" "^7.3.3" + "@jest/expect-utils" "^29.7.0" + "@jest/transform" "^29.7.0" + "@jest/types" "^29.6.3" + babel-preset-current-node-syntax "^1.0.0" + chalk "^4.0.0" + expect "^29.7.0" + graceful-fs "^4.2.9" + jest-diff "^29.7.0" + jest-get-type "^29.6.3" + jest-matcher-utils "^29.7.0" + jest-message-util "^29.7.0" + jest-util "^29.7.0" natural-compare "^1.4.0" - pretty-format "^24.9.0" - semver "^6.2.0" - -jest-util@^24.8.0, jest-util@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-24.9.0.tgz#7396814e48536d2e85a37de3e4c431d7cb140162" - integrity sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg== - dependencies: - "@jest/console" "^24.9.0" - "@jest/fake-timers" "^24.9.0" - "@jest/source-map" "^24.9.0" - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - callsites "^3.0.0" - chalk "^2.0.1" - graceful-fs "^4.1.15" - is-ci "^2.0.0" - mkdirp "^0.5.1" - slash "^2.0.0" - source-map "^0.6.0" + pretty-format "^29.7.0" + semver "^7.5.3" jest-util@^27.2.0: version "27.5.1" @@ -9605,7 +8905,7 @@ jest-util@^27.2.0: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-util@^29.7.0: +jest-util@^29.0.0, jest-util@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-29.7.0.tgz#23c2b62bfb22be82b44de98055802ff3710fc0bc" integrity sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA== @@ -9617,18 +8917,6 @@ jest-util@^29.7.0: graceful-fs "^4.2.9" picomatch "^2.2.3" -jest-validate@^24.8.0, jest-validate@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-24.9.0.tgz#0775c55360d173cd854e40180756d4ff52def8ab" - integrity sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ== - dependencies: - "@jest/types" "^24.9.0" - camelcase "^5.3.1" - chalk "^2.0.1" - jest-get-type "^24.9.0" - leven "^3.1.0" - pretty-format "^24.9.0" - jest-validate@^26.5.2: version "26.6.2" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.6.2.tgz#23d380971587150467342911c3d7b4ac57ab20ec" @@ -9641,7 +8929,7 @@ jest-validate@^26.5.2: leven "^3.1.0" pretty-format "^26.6.2" -jest-validate@^29.2.1: +jest-validate@^29.2.1, jest-validate@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-29.7.0.tgz#7bf705511c64da591d46b15fce41400d52147d9c" integrity sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw== @@ -9653,26 +8941,19 @@ jest-validate@^29.2.1: leven "^3.1.0" pretty-format "^29.7.0" -jest-watcher@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-24.9.0.tgz#4b56e5d1ceff005f5b88e528dc9afc8dd4ed2b3b" - integrity sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw== - dependencies: - "@jest/test-result" "^24.9.0" - "@jest/types" "^24.9.0" - "@types/yargs" "^13.0.0" - ansi-escapes "^3.0.0" - chalk "^2.0.1" - jest-util "^24.9.0" - string-length "^2.0.0" - -jest-worker@^24.6.0, jest-worker@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-24.9.0.tgz#5dbfdb5b2d322e98567898238a9697bcce67b3e5" - integrity sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw== +jest-watcher@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-29.7.0.tgz#7810d30d619c3a62093223ce6bb359ca1b28a2f2" + integrity sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g== dependencies: - merge-stream "^2.0.0" - supports-color "^6.1.0" + "@jest/test-result" "^29.7.0" + "@jest/types" "^29.6.3" + "@types/node" "*" + ansi-escapes "^4.2.1" + chalk "^4.0.0" + emittery "^0.13.1" + jest-util "^29.7.0" + string-length "^4.0.1" jest-worker@^27.2.0, jest-worker@^27.4.5: version "27.5.1" @@ -9683,13 +8964,25 @@ jest-worker@^27.2.0, jest-worker@^27.4.5: merge-stream "^2.0.0" supports-color "^8.0.0" -jest@^24.x.x: - version "24.9.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-24.9.0.tgz#987d290c05a08b52c56188c1002e368edb007171" - integrity sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw== +jest-worker@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-29.7.0.tgz#acad073acbbaeb7262bd5389e1bcf43e10058d4a" + integrity sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw== + dependencies: + "@types/node" "*" + jest-util "^29.7.0" + merge-stream "^2.0.0" + supports-color "^8.0.0" + +jest@^29.7.0: + version "29.7.0" + resolved "https://registry.yarnpkg.com/jest/-/jest-29.7.0.tgz#994676fc24177f088f1c5e3737f5697204ff2613" + integrity sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw== dependencies: - import-local "^2.0.0" - jest-cli "^24.9.0" + "@jest/core" "^29.7.0" + "@jest/types" "^29.6.3" + import-local "^3.0.2" + jest-cli "^29.7.0" joi@^17.2.1: version "17.11.0" @@ -9734,11 +9027,6 @@ js-yaml@4.1.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg== - jsc-android@^250230.2.1: version "250230.2.1" resolved "https://registry.yarnpkg.com/jsc-android/-/jsc-android-250230.2.1.tgz#3790313a970586a03ab0ad47defbc84df54f1b83" @@ -9779,37 +9067,37 @@ jscodeshift@^0.14.0: temp "^0.8.4" write-file-atomic "^2.3.0" -jsdom@^11.5.1: - version "11.12.0" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8" - integrity sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw== - dependencies: - abab "^2.0.0" - acorn "^5.5.3" - acorn-globals "^4.1.0" - array-equal "^1.0.0" - cssom ">= 0.3.2 < 0.4.0" - cssstyle "^1.0.0" - data-urls "^1.0.0" - domexception "^1.0.1" - escodegen "^1.9.1" - html-encoding-sniffer "^1.0.2" - left-pad "^1.3.0" - nwsapi "^2.0.7" - parse5 "4.0.0" - pn "^1.1.0" - request "^2.87.0" - request-promise-native "^1.0.5" - sax "^1.2.4" - symbol-tree "^3.2.2" - tough-cookie "^2.3.4" - w3c-hr-time "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-encoding "^1.0.3" - whatwg-mimetype "^2.1.0" - whatwg-url "^6.4.1" - ws "^5.2.0" - xml-name-validator "^3.0.0" +jsdom@^20.0.0: + version "20.0.3" + resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-20.0.3.tgz#886a41ba1d4726f67a8858028c99489fed6ad4db" + integrity sha512-SYhBvTh89tTfCD/CRdSOm13mOBa42iTaTyfyEWBdKcGdPxPtLFBXuHR8XHb33YNYaP+lLbmSvBTsnoesCNJEsQ== + dependencies: + abab "^2.0.6" + acorn "^8.8.1" + acorn-globals "^7.0.0" + cssom "^0.5.0" + cssstyle "^2.3.0" + data-urls "^3.0.2" + decimal.js "^10.4.2" + domexception "^4.0.0" + escodegen "^2.0.0" + form-data "^4.0.0" + html-encoding-sniffer "^3.0.0" + http-proxy-agent "^5.0.0" + https-proxy-agent "^5.0.1" + is-potential-custom-element-name "^1.0.1" + nwsapi "^2.2.2" + parse5 "^7.1.1" + saxes "^6.0.0" + symbol-tree "^3.2.4" + tough-cookie "^4.1.2" + w3c-xmlserializer "^4.0.0" + webidl-conversions "^7.0.0" + whatwg-encoding "^2.0.0" + whatwg-mimetype "^3.0.0" + whatwg-url "^11.0.0" + ws "^8.11.0" + xml-name-validator "^4.0.0" jsesc@^2.5.1: version "2.5.2" @@ -9846,26 +9134,16 @@ json-schema-traverse@^0.4.1: resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== -json-schema@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.4.0.tgz#f7de4cf6efab838ebaeb3236474cbba5a1930ab5" - integrity sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA== - json-stringify-nice@^1.1.4: version "1.1.4" resolved "https://registry.yarnpkg.com/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz#2c937962b80181d3f317dd39aa323e14f5a60a67" integrity sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw== -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== -json5@2.x, json5@^2.1.1, json5@^2.1.2, json5@^2.2.2, 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== - json5@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" @@ -9873,6 +9151,11 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.1, json5@^2.1.2, json5@^2.2.2, 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== + jsonc-parser@3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/jsonc-parser/-/jsonc-parser-3.2.0.tgz#31ff3f4c2b9793f89c67212627c51c6394f88e76" @@ -9906,16 +9189,6 @@ jsonparse@^1.2.0, jsonparse@^1.3.1: resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== -jsprim@^1.2.2: - version "1.4.2" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.2.tgz#712c65533a15c878ba59e9ed5f0e26d5b77c5feb" - integrity sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw== - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.4.0" - verror "1.10.0" - just-diff-apply@^5.2.0: version "5.5.0" resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.5.0.tgz#771c2ca9fa69f3d2b54e7c3f5c1dfcbcc47f9f0f" @@ -9931,20 +9204,6 @@ keyboard-key@^1.0.4: resolved "https://registry.yarnpkg.com/keyboard-key/-/keyboard-key-1.1.0.tgz#6f2e8e37fa11475bb1f1d65d5174f1b35653f5b7" integrity sha512-qkBzPTi3rlAKvX7k0/ub44sqOfXeLc/jcnGGmj5c7BJpU8eDrEVPyhCvNYAaoubbsLm9uGWwQJO1ytQK1a9/dQ== -kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" - integrity sha512-NOW9QQXMoZGg/oqnVNoNTTIFEIid1627WCffUBJEdMxYApq7mNE7CpzucIPc+ZQg25Phej7IJSmX3hO+oblOtQ== - dependencies: - is-buffer "^1.1.5" - -kind-of@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" - integrity sha512-24XsCxmEbRwEDbz/qz3stgin8TTzZ1ESR56OMCN0ujYg+vRutNSiOj9bHH9u85DKgXguraugV5sFuvbD4FW/hw== - dependencies: - is-buffer "^1.1.5" - kind-of@^6.0.2, kind-of@^6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" @@ -9974,11 +9233,6 @@ lcid@^1.0.0: dependencies: invert-kv "^1.0.0" -left-pad@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/left-pad/-/left-pad-1.3.0.tgz#5b8a3a7765dfe001261dde915589e782f8c94d1e" - integrity sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA== - lerna@^7.4.2: version "7.4.2" resolved "https://registry.yarnpkg.com/lerna/-/lerna-7.4.2.tgz#03497125d7b7c8d463eebfe17a701b16bde2ad09" @@ -10065,14 +9319,6 @@ leven@^3.1.0: resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== -levn@~0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" - integrity sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA== - dependencies: - prelude-ls "~1.1.2" - type-check "~0.3.2" - libnpmaccess@7.0.2: version "7.0.2" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-7.0.2.tgz#7f056c8c933dd9c8ba771fa6493556b53c5aac52" @@ -10224,17 +9470,12 @@ lodash.memoize@4.x: resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag== -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA== - lodash.throttle@^4.1.1: version "4.1.1" resolved "https://registry.yarnpkg.com/lodash.throttle/-/lodash.throttle-4.1.1.tgz#c23e91b710242ac70c37f1e1cda9274cc39bf2f4" integrity sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ== -lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21, lodash@^4.3.0, lodash@^4.7.0: +lodash@^4.17.15, lodash@^4.17.21, lodash@^4.3.0, lodash@^4.7.0: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -10311,7 +9552,7 @@ magic-string@^0.25.2: dependencies: sourcemap-codec "^1.4.8" -make-dir@4.0.0: +make-dir@4.0.0, make-dir@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-4.0.0.tgz#c3c2307a771277cd9638305f915c29ae741b614e" integrity sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw== @@ -10410,11 +9651,6 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" -map-cache@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" - integrity sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg== - map-obj@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" @@ -10425,13 +9661,6 @@ map-obj@^4.0.0: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.3.0.tgz#9304f906e93faae70880da102a9f1df0ea8bb05a" integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== -map-visit@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" - integrity sha512-4y7uGv8bd2WdM9vpQsiQNo41Ln1NvhvDRuVt0k2JZQ+ezN2uaQes7lZeZ+QQUHOLQAtDaBJ+7wCbi+ab/KFs+w== - dependencies: - object-visit "^1.0.0" - marked@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/marked/-/marked-1.0.0.tgz#d35784245a04871e5988a491e28867362e941693" @@ -11390,25 +10619,6 @@ metro@0.76.8: ws "^7.5.1" yargs "^17.6.2" -micromatch@^3.1.10, micromatch@^3.1.4: - version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" - integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - braces "^2.3.1" - define-property "^2.0.2" - extend-shallow "^3.0.2" - extglob "^2.0.4" - fragment-cache "^0.2.1" - kind-of "^6.0.2" - nanomatch "^1.2.9" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.2" - micromatch@^4.0.0, micromatch@^4.0.4, micromatch@^4.0.5: version "4.0.5" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" @@ -11422,7 +10632,7 @@ mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== -mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.19, mime-types@~2.1.34: +mime-types@^2.1.12, mime-types@^2.1.27, mime-types@~2.1.34: version "2.1.35" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== @@ -11493,7 +10703,7 @@ minimist-options@4.1.0: is-plain-obj "^1.1.0" kind-of "^6.0.3" -minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.5, minimist@^1.2.6: version "1.2.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -11597,15 +10807,7 @@ minizlib@^2.0.0, minizlib@^2.1.1, minizlib@^2.1.2: minipass "^3.0.0" yallist "^4.0.0" -mixin-deep@^1.2.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" - integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== - dependencies: - for-in "^1.0.2" - is-extendable "^1.0.1" - -mkdirp@0.x, mkdirp@^0.5.1: +mkdirp@^0.5.1: version "0.5.6" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== @@ -11668,33 +10870,11 @@ mute-stream@~1.0.0: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-1.0.0.tgz#e31bd9fe62f0aed23520aa4324ea6671531e013e" integrity sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA== -nan@^2.12.1: - version "2.18.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.18.0.tgz#26a6faae7ffbeb293a39660e88a76b82e30b7554" - integrity sha512-W7tfG7vMOGtD30sHoZSSc/JVYiyDPEyQVso/Zz+/uQd0B0L46gtC+pHha5FFMRpil6fm/AoEcRWyOVi4+E/f8w== - nanoid@^3.3.6: version "3.3.7" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.7.tgz#d0c301a691bc8d54efa0a2226ccf3fe2fd656bd8" integrity sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g== -nanomatch@^1.2.9: - version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" - integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== - dependencies: - arr-diff "^4.0.0" - array-unique "^0.3.2" - define-property "^2.0.2" - extend-shallow "^3.0.2" - fragment-cache "^0.2.1" - is-windows "^1.0.2" - kind-of "^6.0.2" - object.pick "^1.3.0" - regex-not "^1.0.0" - snapdragon "^0.8.1" - to-regex "^3.0.1" - nanospinner@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/nanospinner/-/nanospinner-1.1.0.tgz#d17ff621cb1784b0a206b400da88a0ef6db39b97" @@ -11839,17 +11019,6 @@ node-machine-id@1.1.12: resolved "https://registry.yarnpkg.com/node-machine-id/-/node-machine-id-1.1.12.tgz#37904eee1e59b320bb9c5d6c0a59f3b469cb6267" integrity sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ== -node-notifier@^5.4.2: - version "5.4.5" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-5.4.5.tgz#0cbc1a2b0f658493b4025775a13ad938e96091ef" - integrity sha512-tVbHs7DyTLtzOiN78izLA85zRqB9NvEXkAf014Vx3jtSvn/xBl6bR8ZYifj+dFcFrKI21huSQgJZ6ZtL3B4HfQ== - dependencies: - growly "^1.3.0" - is-wsl "^1.1.0" - semver "^5.5.0" - shellwords "^0.1.1" - which "^1.3.0" - node-releases@^2.0.13: version "2.0.13" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.13.tgz#d5ed1627c23e3461e819b02e57b75e4899b1c81d" @@ -11921,13 +11090,6 @@ normalize-path@3, normalize-path@^3.0.0, normalize-path@~3.0.0: resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-path@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" - integrity sha512-3pKJwH184Xo/lnH6oyP1q2pMd7HcypqqmRs91/6/i2CGtWwIKGCkOOMTm/zXbgTEWHw1uNpNi/igc3ePOYHb6w== - dependencies: - remove-trailing-separator "^1.0.1" - npm-bundled@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.2.tgz#944c78789bd739035b70baa2ca5cc32b8d860bc1" @@ -12072,7 +11234,7 @@ number-is-nan@^1.0.0: resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" integrity sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ== -nwsapi@^2.0.7: +nwsapi@^2.2.2: version "2.2.7" resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.7.tgz#738e0707d3128cb750dddcfe90e4610482df0f30" integrity sha512-ub5E4+FBPKwAZx0UwIQOjYWGHTEq5sPqHQNRN8Z9e4A7u3Tj1weLJsL59yH9vmvqEtBHaOmT6cYQKIZOxp35FQ== @@ -12129,11 +11291,6 @@ nx@16.7.0, "nx@>=16.5.1 < 17": "@nx/nx-win32-arm64-msvc" "16.7.0" "@nx/nx-win32-x64-msvc" "16.7.0" -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - ob1@0.72.1: version "0.72.1" resolved "https://registry.yarnpkg.com/ob1/-/ob1-0.72.1.tgz#043943baf35a3fff1c1a436ad29410cfada8b912" @@ -12159,20 +11316,6 @@ object-assign@^4.1.0, object-assign@^4.1.1: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-copy@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" - integrity sha512-79LYn6VAb63zgtmAteVOWo9Vdj71ZVBy3Pbse+VqxDpEP83XuujMrGqHIwAXJ5I/aM0zU7dIyIAhifVTPrNItQ== - dependencies: - copy-descriptor "^0.1.0" - define-property "^0.2.5" - kind-of "^3.0.3" - -object-inspect@^1.13.1, object-inspect@^1.9.0: - version "1.13.1" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== - object-is@^1.1.5: version "1.1.5" resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac" @@ -12186,41 +11329,6 @@ object-keys@^1.1.1: resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== -object-visit@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" - integrity sha512-GBaMwwAVK9qbQN3Scdo0OyvgPW7l3lnaVMj84uTOZlswkX0KpF6fyDBJhtTthf7pymztoN36/KEr1DyhF96zEA== - dependencies: - isobject "^3.0.0" - -object.assign@^4.1.4: - version "4.1.4" - resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.4.tgz#9673c7c7c351ab8c4d0b516f4343ebf4dfb7799f" - integrity sha512-1mxKf0e58bvyjSCtKYY4sRe9itRk3PJpquJOjeIkz885CczcI4IvJJDLPS72oowuSh+pBxUFROpX+TU++hxhZQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.1.4" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.getownpropertydescriptors@^2.1.6: - version "2.1.7" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.1.7.tgz#7a466a356cd7da4ba8b9e94ff6d35c3eeab5d56a" - integrity sha512-PrJz0C2xJ58FNn11XV2lr4Jt5Gzl94qpy9Lu0JlfEj14z88sqbSBJCBEzdlNUCzY2gburhbrwOZ5BHCmuNUy0g== - dependencies: - array.prototype.reduce "^1.0.6" - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - safe-array-concat "^1.0.0" - -object.pick@^1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" - integrity sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ== - dependencies: - isobject "^3.0.1" - on-finished@2.4.1: version "2.4.1" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f" @@ -12287,18 +11395,6 @@ opener@^1.5.2: resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== -optionator@^0.8.1: - version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" - integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== - dependencies: - deep-is "~0.1.3" - fast-levenshtein "~2.0.6" - levn "~0.3.0" - prelude-ls "~1.1.2" - type-check "~0.3.2" - word-wrap "~1.2.3" - ora@^5.4.1: version "5.4.1" resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" @@ -12331,13 +11427,6 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.1, os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== -p-each-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-1.0.0.tgz#930f3d12dd1f50e7434457a22cd6f04ac6ad7f71" - integrity sha512-J/e9xiZZQNrt+958FFzJ+auItsBGq+UrQ7nE89AUP7UOTtjHnkISANXLdayhVzh538UnLMCSlf13lFfRIAKQOA== - dependencies: - p-reduce "^1.0.0" - p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -12357,7 +11446,7 @@ p-limit@^2.0.0, p-limit@^2.2.0: dependencies: p-try "^2.0.0" -p-limit@^3.0.2: +p-limit@^3.0.2, p-limit@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== @@ -12422,11 +11511,6 @@ p-reduce@2.1.0, p-reduce@^2.0.0, p-reduce@^2.1.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha512-3Tx1T3oM1xO/Y8Gj0sWyE78EIJZ+t+aEmXUdvQgvGmSMri7aPTHoovbXEreWKkL5j21Er60XAWLTzKbAKYOujQ== - p-timeout@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" @@ -12547,21 +11631,18 @@ parse-url@^8.1.0: dependencies: parse-path "^7.0.0" -parse5@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608" - integrity sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA== +parse5@^7.0.0, parse5@^7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/parse5/-/parse5-7.1.2.tgz#0736bebbfd77793823240a23b7fc5e010b7f8e32" + integrity sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw== + dependencies: + entities "^4.4.0" parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== -pascalcase@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" - integrity sha512-XHXfu/yOQRy9vYOtUDVMN60OEJjW013GoObG1o+xwQTpB9eYJX/BjXMsdW13ZDPruFhYYn0AG22w0xgQMwl3Nw== - path-exists@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" @@ -12633,11 +11714,6 @@ path-type@^4.0.0: resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow== - picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -12680,7 +11756,7 @@ pinkie@^2.0.0: resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" integrity sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg== -pirates@^4.0.1, pirates@^4.0.5: +pirates@^4.0.4, pirates@^4.0.5: version "4.0.6" resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.6.tgz#3018ae32ecfcff6c29ba2267cbf21166ac1f36b9" integrity sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg== @@ -12715,21 +11791,11 @@ plist@^3.0.5: base64-js "^1.5.1" xmlbuilder "^15.1.1" -pn@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/pn/-/pn-1.1.0.tgz#e2f4cef0e219f463c179ab37463e4e1ecdccbafb" - integrity sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA== - popper.js@^1.14.4: version "1.16.1" resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.16.1.tgz#2a223cb3dc7b6213d740e40372be40de43e65b1b" integrity sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ== -posix-character-classes@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" - integrity sha512-xTgYBc3fuo7Yt7JbiuFxSYGToMoz8fLoE6TC9Wx1P/u+LfeThMOAqmuyECnlBaaJb+u1m9hHiXUEtwW4OzfUJg== - postcss-selector-parser@^6.0.10: version "6.0.13" resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.13.tgz#d05d8d76b1e8e173257ef9d60b706a8e5e99bf1b" @@ -12752,11 +11818,6 @@ pouchdb-collections@^1.0.1: resolved "https://registry.yarnpkg.com/pouchdb-collections/-/pouchdb-collections-1.0.1.tgz#fe63a17da977611abef7cb8026cb1a9553fd8359" integrity sha512-31db6JRg4+4D5Yzc2nqsRqsA2oOkZS8DpFav3jf/qVNBxusKa2ClkEIZ2bJNpaDbMfWtnuSq59p6Bn+CipPMdg== -prelude-ls@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" - integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== - prettier@^3.1.0: version "3.1.0" resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.1.0.tgz#c6d16474a5f764ea1a4a373c593b779697744d5e" @@ -12771,16 +11832,6 @@ pretty-format@29.4.3: ansi-styles "^5.0.0" react-is "^18.0.0" -pretty-format@^24.8.0, pretty-format@^24.9.0: - version "24.9.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-24.9.0.tgz#12fac31b37019a4eea3c11aa9a959eb7628aa7c9" - integrity sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA== - dependencies: - "@jest/types" "^24.9.0" - ansi-regex "^4.0.0" - ansi-styles "^3.2.0" - react-is "^16.8.4" - pretty-format@^26.5.2, pretty-format@^26.6.2: version "26.6.2" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.6.2.tgz#e35c2705f14cb7fe2fe94fa078345b444120fc93" @@ -12791,7 +11842,7 @@ pretty-format@^26.5.2, pretty-format@^26.6.2: ansi-styles "^4.0.0" react-is "^17.0.1" -pretty-format@^29.7.0: +pretty-format@^29.0.0, pretty-format@^29.7.0: version "29.7.0" resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-29.7.0.tgz#ca42c758310f365bfa71a0bda0a807160b776812" integrity sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ== @@ -12889,7 +11940,7 @@ proxy-from-env@^1.1.0: resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== -psl@^1.1.28: +psl@^1.1.33: version "1.9.0" resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== @@ -12917,21 +11968,26 @@ punycode@^2.1.0, punycode@^2.1.1: resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== +pure-rand@^6.0.0: + version "6.0.4" + resolved "https://registry.yarnpkg.com/pure-rand/-/pure-rand-6.0.4.tgz#50b737f6a925468679bff00ad20eade53f37d5c7" + integrity sha512-LA0Y9kxMYv47GIPJy6MI84fqTd2HmYZI83W/kM/SkKfDlajnZYfmXFTxkbY+xSBPkLJxltMa9hIkmdc29eguMA== + q@^1.4.1: version "1.5.1" resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" integrity sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw== -qs@~6.5.2: - version "6.5.3" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" - integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== - querystring@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== +querystringify@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.2.0.tgz#3345941b4153cb9d082d8eee4cda2016a9aef7f6" + integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" @@ -12992,7 +12048,7 @@ react-dom@^16.13.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-is@^16.13.1, react-is@^16.6.3, react-is@^16.8.4, react-is@^16.8.6: +react-is@^16.13.1, react-is@^16.6.3, react-is@^16.8.6: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== @@ -13239,14 +12295,6 @@ read-pkg-up@^3.0.0: find-up "^2.0.0" read-pkg "^3.0.0" -read-pkg-up@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978" - integrity sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA== - dependencies: - find-up "^3.0.0" - read-pkg "^3.0.0" - read-pkg-up@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" @@ -13336,23 +12384,15 @@ readline@^1.3.0: resolved "https://registry.yarnpkg.com/readline/-/readline-1.3.0.tgz#c580d77ef2cfc8752b132498060dc9793a7ac01c" integrity sha512-k2d6ACCkiNYz222Fs/iNze30rRJ1iIicW7JuX/7/cozvih6YCkFZH+J6mAFDVgv0dRBaAyr4jDqC95R2y4IADg== -realistic-structured-clone@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-2.0.4.tgz#7eb4c2319fc3cb72f4c8d3c9e888b11647894b50" - integrity sha512-lItAdBIFHUSe6fgztHPtmmWqKUgs+qhcYLi3wTRUl4OTB3Vb8aBVSjGfQZUvkmJCKoX3K9Wf7kyLp/F/208+7A== +realistic-structured-clone@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/realistic-structured-clone/-/realistic-structured-clone-3.0.0.tgz#7b518049ce2dad41ac32b421cd297075b00e3e35" + integrity sha512-rOjh4nuWkAqf9PWu6JVpOWD4ndI+JHfgiZeMmujYcPi+fvILUu7g6l26TC1K5aBIp34nV+jE1cDO75EKOfHC5Q== dependencies: - core-js "^3.4" domexception "^1.0.1" typeson "^6.1.0" typeson-registry "^1.0.0-alpha.20" -realpath-native@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c" - integrity sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA== - dependencies: - util.promisify "^1.0.0" - recast@^0.21.0: version "0.21.5" resolved "https://registry.yarnpkg.com/recast/-/recast-0.21.5.tgz#e8cd22bb51bcd6130e54f87955d33a2b2e57b495" @@ -13419,14 +12459,6 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regex-not@^1.0.0, regex-not@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" - integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== - dependencies: - extend-shallow "^3.0.2" - safe-regex "^1.1.0" - regexp.prototype.flags@^1.5.1: version "1.5.1" resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz#90ce989138db209f81492edd734183ce99f9677e" @@ -13455,63 +12487,6 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" -remove-trailing-separator@^1.0.1: - version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" - integrity sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw== - -repeat-element@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.4.tgz#be681520847ab58c7568ac75fbfad28ed42d39e9" - integrity sha512-LFiNfRcSu7KK3evMyYOuCzv3L10TW7yC1G2/+StMjK8Y6Vqd2MG7r/Qjw4ghtuCOjFvlnms/iMmLqpvW/ES/WQ== - -repeat-string@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" - integrity sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w== - -request-promise-core@1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f" - integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw== - dependencies: - lodash "^4.17.19" - -request-promise-native@^1.0.5: - version "1.0.9" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28" - integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g== - dependencies: - request-promise-core "1.1.4" - stealthy-require "^1.1.1" - tough-cookie "^2.3.3" - -request@^2.87.0: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -13527,18 +12502,16 @@ require-main-filename@^2.0.0: resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== +requires-port@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== + reselect@^4.1.7: version "4.1.8" resolved "https://registry.yarnpkg.com/reselect/-/reselect-4.1.8.tgz#3f5dc671ea168dccdeb3e141236f69f02eaec524" integrity sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ== -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha512-ccu8zQTrzVr954472aUVPLEcB3YpKSYR3cg/3lo1okzobPBM+1INXBbBZlDbnI/hbEocnf8j0QVo43hQKrbchg== - dependencies: - resolve-from "^3.0.0" - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -13566,12 +12539,12 @@ resolve-url@^0.2.1: resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" integrity sha512-ZuF55hVUQaaczgOIwqWzkEcEidmlD/xl44x1UZnhOXcYuFN2S6+rcxpG+C1N3So0wvNI3DmJICUFfu2SxhBmvg== -resolve@1.1.7: - version "1.1.7" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" - integrity sha512-9znBF0vBcaSN3W2j7wKvdERPwqTxSpCq+if5C0WoTCyV9n24rua28jeuQ2pL/HOf+yUe/Mef+H/5p60K0Id3bg== +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.x, resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.3.2: +resolve@^1.1.6, resolve@^1.10.0, resolve@^1.14.2, resolve@^1.20.0, resolve@^1.22.1, resolve@^1.3.2: version "1.22.8" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.8.tgz#b6c87a9f2aa06dfab52e3d70ac8cde321fa5a48d" integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== @@ -13596,11 +12569,6 @@ restore-cursor@^3.1.0: onetime "^5.1.0" signal-exit "^3.0.2" -ret@~0.1.10: - version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" - integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== - retry@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" @@ -13611,7 +12579,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.2, rimraf@^2.6.3: +rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.2: version "2.7.1" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== @@ -13709,11 +12677,6 @@ rollup@^0.67.4: "@types/estree" "0.0.39" "@types/node" "*" -rsvp@^4.8.4: - version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" - integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== - run-async@^2.2.0, run-async@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" @@ -13738,72 +12701,38 @@ rxjs@^7.5.5, rxjs@^7.8.1: dependencies: tslib "^2.1.0" -safe-array-concat@^1.0.0, safe-array-concat@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.0.1.tgz#91686a63ce3adbea14d61b14c99572a8ff84754c" - integrity sha512-6XbUAseYE2KtOuGueyeobCySj9L4+66Tn6KQMOPQJrAJEowYKW/YR/MGJZl7FdydUdaFu4LYyDZjxf4/Nmo23Q== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - has-symbols "^1.0.3" - isarray "^2.0.5" - safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.2, safe-buffer@~5.2.0: +safe-buffer@^5.1.0, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -safe-regex-test@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.0.0.tgz#793b874d524eb3640d1873aad03596db2d4f2295" - integrity sha512-JBUUzyOgEwXQY1NuPtvcj/qcBDbDmEvWufhlnXZIm75DEHp+afM1r1ujJpJsV/gSM4t59tpDyPi1sd6ZaPFfsA== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.1.3" - is-regex "^1.1.4" - -safe-regex@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" - integrity sha512-aJXcif4xnaNUzvUuC5gcb46oTS7zvg4jpMTnuqtrEPlR3vFr4pxtdTwaF1Qs3Enjn9HK+ZlwQui+a7z0SywIzg== - dependencies: - ret "~0.1.10" - safe-stable-stringify@^2.3.1: version "2.4.3" resolved "https://registry.yarnpkg.com/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz#138c84b6f6edb3db5f8ef3ef7115b8f55ccbf886" integrity sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g== -"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -sane@^4.0.3: - version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" - integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== - dependencies: - "@cnakazawa/watch" "^1.0.3" - anymatch "^2.0.0" - capture-exit "^2.0.0" - exec-sh "^0.3.2" - execa "^1.0.0" - fb-watchman "^2.0.0" - micromatch "^3.1.4" - minimist "^1.1.1" - walker "~1.0.5" - -sax@>=0.6.0, sax@^1.2.4: +sax@>=0.6.0: version "1.3.0" resolved "https://registry.yarnpkg.com/sax/-/sax-1.3.0.tgz#a5dbe77db3be05c9d1ee7785dbd3ea9de51593d0" integrity sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA== +saxes@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/saxes/-/saxes-6.0.0.tgz#fe5b4a4768df4f14a201b1ba6a65c1f3d9988cc5" + integrity sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA== + dependencies: + xmlchars "^2.2.0" + scheduler@0.24.0-canary-efb381bbf-20230505: version "0.24.0-canary-efb381bbf-20230505" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.24.0-canary-efb381bbf-20230505.tgz#5dddc60e29f91cd7f8b983d7ce4a99c2202d178f" @@ -13861,7 +12790,7 @@ semantic-ui-react@^0.88.2: react-popper "^1.3.4" shallowequal "^1.1.0" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5, semver@^5.5.0, semver@^5.6.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.5.0, semver@^5.6.0: version "5.7.2" resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.2.tgz#48d55db737c3287cd4835e17fa13feace1c41ef8" integrity sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g== @@ -13880,7 +12809,7 @@ semver@7.5.3: dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0, semver@^6.3.1: +semver@^6.0.0, semver@^6.3.0, semver@^6.3.1: version "6.3.1" resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== @@ -13957,21 +12886,6 @@ set-function-name@^2.0.0: functions-have-names "^1.2.3" has-property-descriptors "^1.0.0" -set-value@^2.0.0, set-value@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" - integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== - dependencies: - extend-shallow "^2.0.1" - is-extendable "^0.1.1" - is-plain-object "^2.0.3" - split-string "^3.0.1" - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - setprototypeof@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.2.0.tgz#66c9a24a73f9fc28cbe66b09fed3d33dcaf1b424" @@ -14027,20 +12941,6 @@ shelljs@^0.8.4: interpret "^1.0.0" rechoir "^0.6.2" -shellwords@^0.1.1: - version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" - integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== - -side-channel@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" - integrity sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw== - dependencies: - call-bind "^1.0.0" - get-intrinsic "^1.0.2" - object-inspect "^1.9.0" - signal-exit@3.0.7, signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" @@ -14128,36 +13028,6 @@ smart-buffer@^4.2.0: resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.2.0.tgz#6e1d71fa4f18c05f7d0ff216dd16a481d0e8d9ae" integrity sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg== -snapdragon-node@^2.0.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" - integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== - dependencies: - define-property "^1.0.0" - isobject "^3.0.0" - snapdragon-util "^3.0.1" - -snapdragon-util@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" - integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== - dependencies: - kind-of "^3.2.0" - -snapdragon@^0.8.1: - version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" - integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== - dependencies: - base "^0.11.1" - debug "^2.2.0" - define-property "^0.2.5" - extend-shallow "^2.0.1" - map-cache "^0.2.2" - source-map "^0.5.6" - source-map-resolve "^0.5.0" - use "^3.1.0" - socks-proxy-agent@^6.0.0: version "6.2.1" resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz#2687a31f9d7185e38d530bef1944fe1f1496d6ce" @@ -14207,7 +13077,15 @@ source-map-resolve@^0.5.0: source-map-url "^0.4.0" urix "^0.1.0" -source-map-support@^0.5.16, source-map-support@^0.5.6, source-map-support@~0.5.20: +source-map-support@0.5.13: + version "0.5.13" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.13.tgz#31b24a9c2e73c2de85066c0feb7d44767ed52932" + integrity sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map-support@^0.5.16, source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== @@ -14274,13 +13152,6 @@ spdx-license-ids@^3.0.0: resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz#a14f64e0954f6e25cc6587bd4f392522db0d998f" integrity sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw== -split-string@^3.0.1, split-string@^3.0.2: - version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" - integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== - dependencies: - extend-shallow "^3.0.0" - split2@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" @@ -14311,21 +13182,6 @@ sqlite3@^5.0.2: optionalDependencies: node-gyp "8.x" -sshpk@^1.7.0: - version "1.18.0" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.18.0.tgz#1663e55cddf4d688b86a46b77f0d5fe363aba028" - integrity sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - ssri@^10.0.0, ssri@^10.0.1: version "10.0.5" resolved "https://registry.yarnpkg.com/ssri/-/ssri-10.0.5.tgz#e49efcd6e36385196cb515d3a2ad6c3f0265ef8c" @@ -14352,13 +13208,6 @@ stack-trace@0.0.x: resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0" integrity sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg== -stack-utils@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-1.0.5.tgz#a19b0b01947e0029c8e451d5d61a498f5bb1471b" - integrity sha512-KZiTzuV3CnSnSvgMRrARVCj+Ht7rMbauGDK0LdVFRGyenwdylpajAp4Q0i6SX8rEmbTpMMf6ryq2gb8pPq2WgQ== - dependencies: - escape-string-regexp "^2.0.0" - stack-utils@^2.0.3: version "2.0.6" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.6.tgz#aaf0748169c02fc33c8232abccf933f54a1cc34f" @@ -14378,14 +13227,6 @@ stacktrace-parser@^0.1.10, stacktrace-parser@^0.1.3: dependencies: type-fest "^0.7.1" -static-extend@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" - integrity sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g== - dependencies: - define-property "^0.2.5" - object-copy "^0.1.0" - statuses@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63" @@ -14396,11 +13237,6 @@ statuses@~1.5.0: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== -stealthy-require@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" - integrity sha512-ZnWpYnYugiOVEY5GkcuJK1io5V8QmNYChG62gSit9pQVGErXtrKuPC55ITaVSukmMta5qpMU7vqLt2Lnni4f/g== - stream-buffers@2.2.x: version "2.2.0" resolved "https://registry.yarnpkg.com/stream-buffers/-/stream-buffers-2.2.0.tgz#91d5f5130d1cef96dcfa7f726945188741d09ee4" @@ -14418,13 +13254,13 @@ streamsearch@^1.1.0: resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" integrity sha512-Mcc5wHehp9aXz1ax6bZUyY5afg9u2rv5cqQI3mRrYkGC8rW2hM02jWuwjtL++LS5qinSyhj2QfLyNsuc+VsExg== -string-length@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-2.0.0.tgz#d40dbb686a3ace960c1cffca562bf2c45f8363ed" - integrity sha512-Qka42GGrS8Mm3SZ+7cH8UXiIWI867/b/Z/feQSpQx/rbfB8UGknGEZVaUQMOUVj+soY6NpWAxily63HI1OckVQ== +string-length@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.2.tgz#a8a8dc7bd5c1a82b9b3c8b87e125f66871b6e57a" + integrity sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ== dependencies: - astral-regex "^1.0.0" - strip-ansi "^4.0.0" + char-regex "^1.0.2" + strip-ansi "^6.0.0" "string-width-cjs@npm:string-width@^4.2.0", "string-width@^1.0.2 || 2 || 3 || 4", string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.3: version "4.2.3" @@ -14462,33 +13298,6 @@ string-width@^5.0.1, string-width@^5.1.2: emoji-regex "^9.2.2" strip-ansi "^7.0.1" -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz#f9ac6f8af4bd55ddfa8895e6aea92a96395393bd" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz#1bb3afc5008661d73e2dc015cd4853732d6c471e" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz#d4cdb44b83a4737ffbac2d406e405d43d0184298" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - string_decoder@^1.1.1, string_decoder@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.3.0.tgz#42f114594a46cf1a8e30b0a84f56c78c3edac21e" @@ -14517,13 +13326,6 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha512-4XaJ2zQdCzROZDivEVIDPkcQn8LMFSa8kj8Gxb/Lnwzv9A8VctNZ+lfivC/sV3ivW8ElJTERXZoPBRrZKkNKow== - dependencies: - ansi-regex "^3.0.0" - strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" @@ -14572,6 +13374,11 @@ strip-indent@^3.0.0: dependencies: min-indent "^1.0.0" +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + strnum@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/strnum/-/strnum-1.0.5.tgz#5c4e829fe15ad4ff0d20c3db5ac97b73c9b072db" @@ -14615,13 +13422,6 @@ supports-color@^5.3.0: dependencies: has-flag "^3.0.0" -supports-color@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3" - integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ== - dependencies: - has-flag "^3.0.0" - supports-color@^7.1.0: version "7.2.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" @@ -14641,7 +13441,7 @@ supports-preserve-symlinks-flag@^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== -symbol-tree@^3.2.2: +symbol-tree@^3.2.4: version "3.2.4" resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== @@ -14754,15 +13554,14 @@ terser@^5.15.0, terser@^5.16.8: commander "^2.20.0" source-map-support "~0.5.20" -test-exclude@^5.2.3: - version "5.2.3" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-5.2.3.tgz#c3d3e1e311eb7ee405e092dac10aefd09091eac0" - integrity sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g== +test-exclude@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: - glob "^7.1.3" + "@istanbuljs/schema" "^0.1.2" + glob "^7.1.4" minimatch "^3.0.4" - read-pkg-up "^4.0.0" - require-main-filename "^2.0.0" text-extensions@^1.0.0: version "1.9.0" @@ -14774,11 +13573,6 @@ text-hex@1.0.x: resolved "https://registry.yarnpkg.com/text-hex/-/text-hex-1.0.0.tgz#69dc9c1b17446ee79a92bf5b884bb4b9127506f5" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== -throat@^4.0.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-4.1.0.tgz#89037cbc92c56ab18926e6ba4cbb200e15672a6a" - integrity sha512-wCVxLDcFxw7ujDxaeJC6nfl2XfHJNYs8yUYJnvMgtPEFlttP9tHSfRUv2vBe6C4hkVFPWoP1P6ZccbYjmSEkKA== - throat@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" @@ -14833,21 +13627,6 @@ to-fast-properties@^2.0.0: resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog== -to-object-path@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" - integrity sha512-9mWHdnGRuh3onocaHzukyvCZhzvr6tiflAy/JRFXcJX0TjgfWA9pk9t8CMbzmBE4Jfw58pXbkngtBtqYxzNEyg== - dependencies: - kind-of "^3.0.2" - -to-regex-range@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" - integrity sha512-ZZWNfCjUokXXDGXFpZehJIkZqq91BcULFq/Pi7M5i4JnxXdhMKAK682z8bCW3o8Hj1wuuzoKcW3DfVzaP6VuNg== - dependencies: - is-number "^3.0.0" - repeat-string "^1.6.1" - to-regex-range@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" @@ -14855,16 +13634,6 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -to-regex@^3.0.1, to-regex@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" - integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== - dependencies: - define-property "^2.0.2" - extend-shallow "^3.0.2" - regex-not "^1.0.2" - safe-regex "^1.1.0" - toidentifier@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" @@ -14875,20 +13644,15 @@ totalist@^3.0.0: resolved "https://registry.yarnpkg.com/totalist/-/totalist-3.0.1.tgz#ba3a3d600c915b1a97872348f79c127475f6acf8" integrity sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ== -tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== +tough-cookie@^4.1.2: + version "4.1.3" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.1.3.tgz#97b9adb0728b42280aa3d814b6b999b2ff0318bf" + integrity sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw== dependencies: - psl "^1.1.28" + psl "^1.1.33" punycode "^2.1.1" - -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA== - dependencies: - punycode "^2.1.0" + universalify "^0.2.0" + url-parse "^1.5.3" tr46@^2.1.0: version "2.1.0" @@ -14897,6 +13661,13 @@ tr46@^2.1.0: dependencies: punycode "^2.1.1" +tr46@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-3.0.0.tgz#555c4e297a950617e8eeddef633c87d4d9d6cbf9" + integrity sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA== + dependencies: + punycode "^2.1.1" + tr46@~0.0.3: version "0.0.3" resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" @@ -14917,21 +13688,19 @@ triple-beam@^1.3.0: resolved "https://registry.yarnpkg.com/triple-beam/-/triple-beam-1.4.1.tgz#6fde70271dc6e5d73ca0c3b24e2d92afb7441984" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== -ts-jest@^24.x.x: - version "24.3.0" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.3.0.tgz#b97814e3eab359ea840a1ac112deae68aa440869" - integrity sha512-Hb94C/+QRIgjVZlJyiWwouYUF+siNJHJHknyspaOcZ+OQAIdFG/UrdQVXw/0B8Z3No34xkUXZJpOTy9alOWdVQ== +ts-jest@^29.1.1: + version "29.1.1" + resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.1.tgz#f58fe62c63caf7bfcc5cc6472082f79180f0815b" + integrity sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA== dependencies: bs-logger "0.x" - buffer-from "1.x" fast-json-stable-stringify "2.x" - json5 "2.x" + jest-util "^29.0.0" + json5 "^2.2.3" lodash.memoize "4.x" make-error "1.x" - mkdirp "0.x" - resolve "1.x" - semver "^5.5" - yargs-parser "10.x" + semver "^7.5.3" + yargs-parser "^21.0.1" ts-loader@^9.4.3: version "9.5.1" @@ -15051,25 +13820,6 @@ tuf-js@^1.1.7: debug "^4.3.4" make-fetch-happen "^11.1.1" -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w== - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA== - -type-check@~0.3.2: - version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" - integrity sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg== - dependencies: - prelude-ls "~1.1.2" - type-coverage-core@^2.17.2: version "2.26.3" resolved "https://registry.yarnpkg.com/type-coverage-core/-/type-coverage-core-2.26.3.tgz#47e2c8225f582d1ca9551c2bace20836b295c944" @@ -15121,45 +13871,6 @@ type-fest@^0.8.1: resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== -typed-array-buffer@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.0.tgz#18de3e7ed7974b0a729d3feecb94338d1472cd60" - integrity sha512-Y8KTSIglk9OZEr8zywiIHG/kmQ7KWyjseXs1CbSo8vC42w7hg2HgYTxSWwP0+is7bWDc1H+Fo026CpHFwm8tkw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - is-typed-array "^1.1.10" - -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz#d787a24a995711611fb2b87a4052799517b230d0" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz#cbbe89b51fdef9cd6aaf07ad4707340abbc4ea0b" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.4.tgz#89d83785e5c4098bec72e08b319651f0eac9c1bb" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - typed-styles@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/typed-styles/-/typed-styles-0.0.7.tgz#93392a008794c4595119ff62dde6809dbc40a3d9" @@ -15228,10 +13939,10 @@ typescript@5.1.6: resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.3.2.tgz#00d1c7c1c46928c5845c1ee8d0cc2791031d4c43" integrity sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ== -typescript@~3.8.3: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^4.3.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== typeson-registry@^1.0.0-alpha.20: version "1.0.0-alpha.39" @@ -15265,16 +13976,6 @@ ulid@^2.3.0: resolved "https://registry.yarnpkg.com/ulid/-/ulid-2.3.0.tgz#93063522771a9774121a84d126ecd3eb9804071f" integrity sha512-keqHubrlpvT6G2wH0OEfSW4mquYRcbe/J8NMmveoQOjUqmo+hXtO+ORCpWhdbZ7k72UtY61BL7haGxW6enBnjw== -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.0.2.tgz#29032021057d5e6cdbd08c5129c226dff8ed6f9e" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - undici-types@~5.26.4: version "5.26.5" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" @@ -15303,16 +14004,6 @@ unicode-property-aliases-ecmascript@^2.0.0: resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz#43d41e3be698bd493ef911077c9b131f827e8ccd" integrity sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w== -union-value@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" - integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== - dependencies: - arr-union "^3.1.0" - get-value "^2.0.6" - is-extendable "^0.1.1" - set-value "^2.0.1" - unique-filename@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" @@ -15372,6 +14063,11 @@ universalify@^0.1.0: resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== +universalify@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.2.0.tgz#6451760566fa857534745ab1dde952d1b1761be0" + integrity sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg== + universalify@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.1.tgz#168efc2180964e6386d061e094df61afe239b18d" @@ -15382,14 +14078,6 @@ unpipe@~1.0.0: resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== -unset-value@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" - integrity sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ== - dependencies: - has-value "^0.3.1" - isobject "^3.0.0" - untildify@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/untildify/-/untildify-3.0.3.tgz#1e7b42b140bcfd922b22e70ca1265bfe3634c7c9" @@ -15420,6 +14108,14 @@ urix@^0.1.0: resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" integrity sha512-Am1ousAhSLBeB9cG/7k7r2R0zj50uDRlZHPGbazid5s9rlF1F/QKYObEKSIunSjIOkJZqwRRLpvewjEkM7pSqg== +url-parse@^1.5.3: + version "1.5.10" + resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.5.10.tgz#9d3c2f736c1d75dd3bd2be507dcc111f1e2ea9c1" + integrity sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ== + dependencies: + querystringify "^2.1.1" + requires-port "^1.0.0" + url@0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" @@ -15440,29 +14136,11 @@ use-sync-external-store@^1.0.0: resolved "https://registry.yarnpkg.com/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz#7dbefd6ef3fe4e767a0cf5d7287aacfb5846928a" integrity sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA== -use@^3.1.0: - version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" - integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== - util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== -util.promisify@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.1.2.tgz#02b3dbadbb80071eee4c43aed58747afdfc516db" - integrity sha512-PBdZ03m1kBnQ5cjjO0ZvJMJS+QsbyIcFwi4hY4U76OQsCO9JrOYjbCFgIF76ccFg9xnJo7ZHPkqyj1GqmdS7MA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - for-each "^0.3.3" - has-proto "^1.0.1" - has-symbols "^1.0.3" - object.getownpropertydescriptors "^2.1.6" - safe-array-concat "^1.0.0" - utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -15478,7 +14156,7 @@ uuid-validate@^0.0.3: resolved "https://registry.yarnpkg.com/uuid-validate/-/uuid-validate-0.0.3.tgz#e30617f75dc742a0e4f95012a11540faf9d39ab4" integrity sha512-Fykw5U4eZESbq739BeLvEBFRuJODfrlmjx5eJux7W817LjRaq4b7/i4t2zxQmhcX+fAj4nMfRdTzO4tmwLKn0w== -uuid@^3.3.2, uuid@^3.4.0: +uuid@^3.4.0: version "3.4.0" resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== @@ -15503,6 +14181,15 @@ v8-compile-cache@2.3.0: resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee" integrity sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA== +v8-to-istanbul@^9.0.1: + version "9.2.0" + resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-9.2.0.tgz#2ed7644a245cddd83d4e087b9b33b3e62dfd10ad" + integrity sha512-/EH/sDgxU2eGxajKdwLCDmQ4FWq+kpi3uCmBGpw1xJtnAxEjlD8j8PEiGWpCIMIs3ciNAgH0d3TTJiUkYzyZjA== + dependencies: + "@jridgewell/trace-mapping" "^0.3.12" + "@types/istanbul-lib-coverage" "^2.0.1" + convert-source-map "^2.0.0" + validate-npm-package-license@3.0.4, validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" @@ -15530,33 +14217,24 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg== -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw== - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - vlq@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/vlq/-/vlq-1.0.1.tgz#c003f6e7c0b4c1edd623fd6ee50bbc0d6a1de468" integrity sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w== -w3c-hr-time@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" - integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== +w3c-xmlserializer@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz#aebdc84920d806222936e3cdce408e32488a3073" + integrity sha512-d+BFHzbiCx6zGfz0HyQ6Rg69w9k19nviJspaj4yNscGjrHu94sVP+aRm75yEbCh+r2/yR+7q6hux9LVtbuTGBw== dependencies: - browser-process-hrtime "^1.0.0" + xml-name-validator "^4.0.0" walk-up-path@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/walk-up-path/-/walk-up-path-3.0.1.tgz#c8d78d5375b4966c717eb17ada73dbd41490e886" integrity sha512-9YlCL/ynK3CTlrSRrDxZvUauLzAswPCrsaCgilqFevUYpeEW0/3ScEjaa3kbW/T0ghhkEr7mv+fpjqn1Y1YuTA== -walker@^1.0.7, walker@~1.0.5: +walker@^1.0.7, walker@^1.0.8: version "1.0.8" resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.8.tgz#bd498db477afe573dc04185f011d3ab8a8d7653f" integrity sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ== @@ -15605,6 +14283,11 @@ webidl-conversions@^6.1.0: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== +webidl-conversions@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-7.0.0.tgz#256b4e1882be7debbf01d05f0aa2039778ea080a" + integrity sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g== + webpack-bundle-analyzer@^4.7.0: version "4.10.1" resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.10.1.tgz#84b7473b630a7b8c21c741f81d8fe4593208b454" @@ -15687,22 +14370,22 @@ webpack@^5, webpack@^5.75.0, webpack@^5.88.0: watchpack "^2.4.0" webpack-sources "^3.2.3" -whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3: - version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" - integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== +whatwg-encoding@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-2.0.0.tgz#e7635f597fd87020858626805a2729fa7698ac53" + integrity sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg== dependencies: - iconv-lite "0.4.24" + iconv-lite "0.6.3" whatwg-fetch@^3.0.0: version "3.6.19" resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-3.6.19.tgz#caefd92ae630b91c07345537e67f8354db470973" integrity sha512-d67JP4dHSbm2TrpFj8AbO8DnL1JXL5J9u0Kq2xW6d0TFDbCA3Muhdt8orXC22utleTVj7Prqt82baN6RBvnEgw== -whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" - integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== +whatwg-mimetype@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz#5fa1a7623867ff1af6ca3dc72ad6b8a4208beba7" + integrity sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q== whatwg-url-without-unicode@8.0.0-3: version "8.0.0-3" @@ -15713,6 +14396,14 @@ whatwg-url-without-unicode@8.0.0-3: punycode "^2.1.1" webidl-conversions "^5.0.0" +whatwg-url@^11.0.0: + version "11.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-11.0.0.tgz#0a849eebb5faf2119b901bb76fd795c2848d4018" + integrity sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ== + dependencies: + tr46 "^3.0.0" + webidl-conversions "^7.0.0" + whatwg-url@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" @@ -15721,24 +14412,6 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -whatwg-url@^6.4.1: - version "6.5.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-6.5.0.tgz#f2df02bff176fd65070df74ad5ccbb5a199965a8" - integrity sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - whatwg-url@^8.4.0: version "8.7.0" resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" @@ -15748,17 +14421,6 @@ whatwg-url@^8.4.0: tr46 "^2.1.0" webidl-conversions "^6.1.0" -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz#13757bc89b209b049fe5d86430e21cf40a89a8e6" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" @@ -15769,18 +14431,7 @@ which-module@^2.0.0: resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.1.tgz#776b1fe35d90aebe99e8ac15eb24093389a4a409" integrity sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ== -which-typed-array@^1.1.11, which-typed-array@^1.1.13: - version "1.1.13" - resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.13.tgz#870cd5be06ddb616f504e7b039c4c24898184d36" - integrity sha512-P5Nra0qjSncduVPEAr7xhoF5guty49ArDTwzJ/yNuPIbZppyRxFQsRCWrocxIY+CnMVG+qfbU2FmDKyvSGClow== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.4" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.0" - -which@^1.2.9, which@^1.3.0: +which@^1.2.9: version "1.3.1" resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== @@ -15860,11 +14511,6 @@ wml@0.0.83: uuid-js "^0.7.5" yargs "^4.7.1" -word-wrap@~1.2.3: - version "1.2.5" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.5.tgz#d2c45c6dd4fbce621a66f136cbe328afd0410b34" - integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== - wordwrap@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -15919,15 +14565,6 @@ wrappy@1: resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -write-file-atomic@2.4.1: - version "2.4.1" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.1.tgz#d0b05463c188ae804396fd5ab2a370062af87529" - integrity sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - write-file-atomic@5.0.1, write-file-atomic@^5.0.0: version "5.0.1" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-5.0.1.tgz#68df4717c55c6fa4281a7860b4c2ba0a6d2b11e7" @@ -15945,6 +14582,14 @@ write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: imurmurhash "^0.1.4" signal-exit "^3.0.2" +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== + dependencies: + imurmurhash "^0.1.4" + signal-exit "^3.0.7" + write-json-file@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" @@ -15966,13 +14611,6 @@ write-pkg@4.0.0: type-fest "^0.4.1" write-json-file "^3.2.0" -ws@^5.2.0: - version "5.2.3" - resolved "https://registry.yarnpkg.com/ws/-/ws-5.2.3.tgz#05541053414921bc29c63bee14b8b0dd50b07b3d" - integrity sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA== - dependencies: - async-limiter "~1.0.0" - ws@^6.1.4, ws@^6.2.2: version "6.2.2" resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e" @@ -15985,6 +14623,11 @@ ws@^7, ws@^7.3.1, ws@^7.5.1: resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== +ws@^8.11.0: + version "8.14.2" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f" + integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g== + xcode@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/xcode/-/xcode-3.0.1.tgz#3efb62aac641ab2c702458f9a0302696146aa53c" @@ -15993,10 +14636,10 @@ xcode@^3.0.1: simple-plist "^1.1.0" uuid "^7.0.3" -xml-name-validator@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" - integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== +xml-name-validator@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835" + integrity sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw== xml2js@0.4.23: version "0.4.23" @@ -16021,6 +14664,11 @@ xmlbuilder@~11.0.0: resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-11.0.1.tgz#be9bae1c8a046e76b31127726347d0ad7002beb3" integrity sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA== +xmlchars@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== + xtend@~4.0.1: version "4.0.2" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" @@ -16056,19 +14704,12 @@ yaml@^2.2.1: resolved "https://registry.yarnpkg.com/yaml/-/yaml-2.3.4.tgz#53fc1d514be80aabf386dc6001eb29bf3b7523b2" integrity sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA== -yargs-parser@10.x: - version "10.1.0" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8" - integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ== - dependencies: - camelcase "^4.1.0" - yargs-parser@20.2.4: version "20.2.4" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@21.1.1, yargs-parser@^21.1.1: +yargs-parser@21.1.1, yargs-parser@^21.0.1, yargs-parser@^21.1.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== @@ -16148,7 +14789,7 @@ yargs@^15.1.0, yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.2" -yargs@^17.6.2: +yargs@^17.3.1, yargs@^17.6.2: version "17.7.2" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.7.2.tgz#991df39aca675a192b816e1e0363f9d75d2aa269" integrity sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w== From 173808083899826931b88a910fc93c34e5b4a03a Mon Sep 17 00:00:00 2001 From: Venkata Ramyasri Kota <34170013+kvramyasri7@users.noreply.github.com> Date: Wed, 29 Nov 2023 09:25:53 -0800 Subject: [PATCH 07/15] (GH-actions) add `allow-licenses` list in dependency_review #PR2 (#12615) chore: add allow-licenses list in dependency_review --- .../dependecy-review-config.yml | 21 +++++++++++++++++++ .../workflows/callable-dependency-review.yml | 2 ++ 2 files changed, 23 insertions(+) create mode 100644 .github/dependency-review/dependecy-review-config.yml diff --git a/.github/dependency-review/dependecy-review-config.yml b/.github/dependency-review/dependecy-review-config.yml new file mode 100644 index 00000000000..1c0871b714d --- /dev/null +++ b/.github/dependency-review/dependecy-review-config.yml @@ -0,0 +1,21 @@ +allow-licenses: + - 'Apache-2.0' + - 'BSL-1.0' + - 'BSD-1-Clause' + - 'BSD-2-Clause-FreeBSD' + - 'BSD-2-Clause' + - 'BSD-3-Clause-Attribution' + - 'BSD-3-Clause' + - 'CC-BY-3.0' + - 'CC-BY-4.0' + - 'curl' + - 'ISC' + - 'JSON' + - 'MIT' + - 'OpenSSL' + - 'PDDL-1.0' + - 'PostgreSQL' + - 'Python-2.0' + - 'Unlicense' + - 'WTFPL' + - 'Zlib' diff --git a/.github/workflows/callable-dependency-review.yml b/.github/workflows/callable-dependency-review.yml index 67808edbb63..2b3ee6eb805 100644 --- a/.github/workflows/callable-dependency-review.yml +++ b/.github/workflows/callable-dependency-review.yml @@ -17,3 +17,5 @@ jobs: uses: actions/checkout@e2a5a1afd5d7305b13671410c52a31819ab9fad9 # v4.0.0 https://github.com/actions/checkout/commit/e2a5a1afd5d7305b13671410c52a31819ab9fad9 - name: 'Dependency Review' uses: actions/dependency-review-action@7bbfa034e752445ea40215fff1c3bf9597993d3f # v3.1.3 https://github.com/actions/dependency-review-action/commit/7bbfa034e752445ea40215fff1c3bf9597993d3f + with: + config-file: '.github/dependency-review/dependecy-review-config.yml' From 3340588687df5dcfa08ae71e4807d054c9e9f13f Mon Sep 17 00:00:00 2001 From: Caleb Pollman Date: Wed, 29 Nov 2023 15:13:55 -0800 Subject: [PATCH 08/15] fix: update parseAWSExports to return the expected shape of userAttributes (#12654) --- .../__tests__/initSingleton.test.ts | 60 ++++---- .../core/__tests__/parseAWSExports.test.ts | 142 +++++++----------- .../__tests__/singleton/Singleton.test.ts | 36 ++--- packages/core/src/parseAWSExports.ts | 22 ++- packages/core/src/singleton/Auth/types.ts | 3 + 5 files changed, 115 insertions(+), 148 deletions(-) diff --git a/packages/aws-amplify/__tests__/initSingleton.test.ts b/packages/aws-amplify/__tests__/initSingleton.test.ts index ddc523b8e65..39523fe9298 100644 --- a/packages/aws-amplify/__tests__/initSingleton.test.ts +++ b/packages/aws-amplify/__tests__/initSingleton.test.ts @@ -91,41 +91,37 @@ describe('initSingleton (DefaultAmplify)', () => { Amplify.configure(mockLegacyConfig); - expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( - { - Auth: { - Cognito: { - allowGuestAccess: true, - identityPoolId: 'aws_cognito_identity_pool_id', - loginWith: { - email: false, - phone: false, - username: true, - }, - mfa: { - smsEnabled: true, - status: 'off', - totpEnabled: false, - }, - passwordFormat: { - minLength: 8, - requireLowercase: false, - requireNumbers: false, - requireSpecialCharacters: false, - requireUppercase: false, - }, - userAttributes: [ - { - phone_number: { - required: true, - }, - }, - ], - userPoolClientId: 'aws_user_pools_web_client_id', - userPoolId: 'aws_user_pools_id', + const resourcesConfig: ResourcesConfig = { + Auth: { + Cognito: { + allowGuestAccess: true, + identityPoolId: 'aws_cognito_identity_pool_id', + loginWith: { + email: false, + phone: false, + username: true, + }, + mfa: { + smsEnabled: true, + status: 'off', + totpEnabled: false, }, + passwordFormat: { + minLength: 8, + requireLowercase: false, + requireNumbers: false, + requireSpecialCharacters: false, + requireUppercase: false, + }, + userAttributes: { phone_number: { required: true } }, + userPoolClientId: 'aws_user_pools_web_client_id', + userPoolId: 'aws_user_pools_id', }, }, + }; + + expect(mockAmplifySingletonConfigure).toHaveBeenCalledWith( + resourcesConfig, expect.anything() ); }); diff --git a/packages/core/__tests__/parseAWSExports.test.ts b/packages/core/__tests__/parseAWSExports.test.ts index 4dbe05a4221..29ebf893475 100644 --- a/packages/core/__tests__/parseAWSExports.test.ts +++ b/packages/core/__tests__/parseAWSExports.test.ts @@ -1,7 +1,8 @@ import { parseAWSExports } from '../src/parseAWSExports'; +import { ResourcesConfig } from '../src/singleton/types'; // TODO: Add API category tests -describe('Parser', () => { +describe('parseAWSExports', () => { const appId = 'app-id'; const bucket = 'bucket'; const identityPoolId = 'identity-pool-id'; @@ -75,62 +76,8 @@ describe('Parser', () => { const oAuthResponseType = 'code'; it('should parse valid aws-exports.js', () => { - expect( - parseAWSExports({ - aws_cognito_identity_pool_id: identityPoolId, - aws_cognito_sign_up_verification_method: signUpVerificationMethod, - aws_cognito_username_attributes: ['PHONE_NUMBER'], - aws_cognito_signup_attributes: ['PHONE_NUMBER'], - aws_cognito_mfa_configuration: 'OFF', - aws_cognito_mfa_types: ['SMS', 'TOTP'], - aws_cognito_password_protection_settings: { - passwordPolicyMinLength: 8, - passwordPolicyCharacters: [ - 'REQUIRES_SYMBOLS', - 'REQUIRES_UPPERCASE', - 'REQUIRES_NUMBERS', - ], - }, - oauth: { - domain: oAuthDomain, - scope: oAuthScopes, - redirectSignIn: oAuthSigninUrl, - redirectSignOut: oAuthSignoutUrl, - responseType: oAuthResponseType, - }, - aws_cognito_verification_mechanisms: ['EMAIL'], - aws_cognito_social_providers: ['GOOGLE', 'APPLE', 'FACEBOOK', 'AMAZON'], - aws_mandatory_sign_in: 'enable', - aws_mobile_analytics_app_id: appId, - aws_mobile_analytics_app_region: region, - aws_user_files_s3_bucket: bucket, - aws_user_files_s3_bucket_region: region, - aws_user_pools_id: userPoolId, - aws_user_pools_web_client_id: userPoolClientId, - geo: { - amazon_location_service: amazonLocationService, - }, - aws_cloud_logic_custom: [restEndpoint1, restEndpoint2], - aws_appsync_graphqlEndpoint: appsyncEndpoint, - aws_appsync_apiKey: apiKey, - aws_appsync_region: region, - aws_appsync_authenticationType: 'AMAZON_COGNITO_USER_POOLS', - Notifications: { - InAppMessaging: { - AWSPinpoint: { - appId: appId, - region: region, - }, - }, - }, - }) - ).toStrictEqual({ - Analytics: { - Pinpoint: { - appId, - region, - }, - }, + const expected: ResourcesConfig = { + Analytics: { Pinpoint: { appId, region } }, Auth: { Cognito: { identityPoolId, @@ -148,11 +95,7 @@ describe('Parser', () => { phone: true, username: false, }, - mfa: { - smsEnabled: true, - status: 'off', - totpEnabled: true, - }, + mfa: { smsEnabled: true, status: 'off', totpEnabled: true }, passwordFormat: { minLength: 8, requireLowercase: false, @@ -161,18 +104,10 @@ describe('Parser', () => { requireUppercase: true, }, signUpVerificationMethod, - userAttributes: [ - { - email: { - required: true, - }, - }, - { - phone_number: { - required: true, - }, - }, - ], + userAttributes: { + email: { required: true }, + phone_number: { required: true }, + }, userPoolId, userPoolClientId, }, @@ -189,10 +124,7 @@ describe('Parser', () => { }, API: { REST: { - api1: { - endpoint: 'https://api1.com', - region: 'us-east-1', - }, + api1: { endpoint: 'https://api1.com', region: 'us-east-1' }, api2: { endpoint: 'https://api2.com', region: 'us-west-2', @@ -207,14 +139,52 @@ describe('Parser', () => { }, }, Notifications: { - InAppMessaging: { - Pinpoint: { - appId, - region, - }, - }, + InAppMessaging: { Pinpoint: { appId, region } }, }, - }); + }; + expect( + parseAWSExports({ + aws_cognito_identity_pool_id: identityPoolId, + aws_cognito_sign_up_verification_method: signUpVerificationMethod, + aws_cognito_username_attributes: ['PHONE_NUMBER'], + aws_cognito_signup_attributes: ['PHONE_NUMBER'], + aws_cognito_mfa_configuration: 'OFF', + aws_cognito_mfa_types: ['SMS', 'TOTP'], + aws_cognito_password_protection_settings: { + passwordPolicyMinLength: 8, + passwordPolicyCharacters: [ + 'REQUIRES_SYMBOLS', + 'REQUIRES_UPPERCASE', + 'REQUIRES_NUMBERS', + ], + }, + oauth: { + domain: oAuthDomain, + scope: oAuthScopes, + redirectSignIn: oAuthSigninUrl, + redirectSignOut: oAuthSignoutUrl, + responseType: oAuthResponseType, + }, + aws_cognito_verification_mechanisms: ['EMAIL'], + aws_cognito_social_providers: ['GOOGLE', 'APPLE', 'FACEBOOK', 'AMAZON'], + aws_mandatory_sign_in: 'enable', + aws_mobile_analytics_app_id: appId, + aws_mobile_analytics_app_region: region, + aws_user_files_s3_bucket: bucket, + aws_user_files_s3_bucket_region: region, + aws_user_pools_id: userPoolId, + aws_user_pools_web_client_id: userPoolClientId, + geo: { amazon_location_service: amazonLocationService }, + aws_cloud_logic_custom: [restEndpoint1, restEndpoint2], + aws_appsync_graphqlEndpoint: appsyncEndpoint, + aws_appsync_apiKey: apiKey, + aws_appsync_region: region, + aws_appsync_authenticationType: 'AMAZON_COGNITO_USER_POOLS', + Notifications: { + InAppMessaging: { AWSPinpoint: { appId, region } }, + }, + }) + ).toStrictEqual(expected); }); it('should fallback to IAM auth mode if Appsync auth type is invalid', () => { @@ -267,7 +237,7 @@ describe('Parser', () => { mfa: undefined, passwordFormat: undefined, signUpVerificationMethod: undefined, - userAttributes: [], + userAttributes: {}, userPoolClientId: undefined, userPoolId: userPoolId, }, diff --git a/packages/core/__tests__/singleton/Singleton.test.ts b/packages/core/__tests__/singleton/Singleton.test.ts index 7dd8c383b0c..b79f338346e 100644 --- a/packages/core/__tests__/singleton/Singleton.test.ts +++ b/packages/core/__tests__/singleton/Singleton.test.ts @@ -3,7 +3,7 @@ import { AuthClass as Auth } from '../../src/singleton/Auth'; import { decodeJWT } from '../../src/singleton/Auth/utils'; import { CredentialsAndIdentityId } from '../../src/singleton/Auth/types'; import { TextEncoder, TextDecoder } from 'util'; -import { fetchAuthSession } from '../../src'; +import { fetchAuthSession, ResourcesConfig } from '../../src'; Object.assign(global, { TextDecoder, TextEncoder }); type ArgumentTypes = F extends (...args: infer A) => any ? A @@ -16,7 +16,12 @@ const MOCK_AUTH_CONFIG = { }, }, }; -const modelIntrospection = { + +type ModelIntrospection = NonNullable< + NonNullable['GraphQL'] +>['modelIntrospection']; + +const modelIntrospection: ModelIntrospection = { version: 1, models: { Todo: { @@ -107,24 +112,15 @@ describe('Amplify.configure() and Amplify.getConfig()', () => { Amplify.configure(mockLegacyConfig); const result = Amplify.getConfig(); - - expect(result).toEqual({ + const expected: ResourcesConfig = { Auth: { Cognito: { allowGuestAccess: true, identityPoolId: 'aws_cognito_identity_pool_id', userPoolClientId: 'aws_user_pools_web_client_id', userPoolId: 'aws_user_pools_id', - loginWith: { - email: false, - phone: false, - username: true, - }, - mfa: { - smsEnabled: true, - status: 'off', - totpEnabled: false, - }, + loginWith: { email: false, phone: false, username: true }, + mfa: { smsEnabled: true, status: 'off', totpEnabled: false }, passwordFormat: { minLength: 8, requireLowercase: false, @@ -132,13 +128,7 @@ describe('Amplify.configure() and Amplify.getConfig()', () => { requireSpecialCharacters: false, requireUppercase: false, }, - userAttributes: [ - { - phone_number: { - required: true, - }, - }, - ], + userAttributes: { phone_number: { required: true } }, }, }, API: { @@ -150,7 +140,9 @@ describe('Amplify.configure() and Amplify.getConfig()', () => { modelIntrospection, }, }, - }); + }; + + expect(result).toEqual(expected); }); it('should take the v6 shaped config object for configuring and return it from getConfig()', () => { diff --git a/packages/core/src/parseAWSExports.ts b/packages/core/src/parseAWSExports.ts index 061b4dce337..1823cb44275 100644 --- a/packages/core/src/parseAWSExports.ts +++ b/packages/core/src/parseAWSExports.ts @@ -2,8 +2,9 @@ // SPDX-License-Identifier: Apache-2.0 import { ConsoleLogger } from './Logger'; import { - OAuthConfig, AuthConfigUserAttributes, + LegacyUserAttributeKey, + OAuthConfig, OAuthProvider, } from './singleton/Auth/types'; import { ResourcesConfig } from './singleton/types'; @@ -161,17 +162,22 @@ export const parseAWSExports = ( ) ?? false, } : undefined; - const mergedUserAttributes = Array.from( + const mergedUserAttributes: LegacyUserAttributeKey[] = Array.from( new Set([ ...(aws_cognito_verification_mechanisms ?? []), ...(aws_cognito_signup_attributes ?? []), ]) ); - const userAttributesConfig = mergedUserAttributes.map((s: string) => ({ - [s.toLowerCase()]: { - required: true, // All user attributes generated by the CLI will be required - }, - })) as unknown as AuthConfigUserAttributes; + + const userAttributes: AuthConfigUserAttributes = mergedUserAttributes.reduce( + (attributes: AuthConfigUserAttributes, key: LegacyUserAttributeKey) => ({ + ...attributes, + // All user attributes generated by the CLI are required + [key.toLowerCase()]: { required: true }, + }), + {} + ); + const loginWithEmailEnabled = aws_cognito_username_attributes?.includes('EMAIL') ?? false; const loginWithPhoneEnabled = @@ -182,7 +188,7 @@ export const parseAWSExports = ( identityPoolId: aws_cognito_identity_pool_id, allowGuestAccess: aws_mandatory_sign_in !== 'enable', signUpVerificationMethod: aws_cognito_sign_up_verification_method, - userAttributes: userAttributesConfig, + userAttributes, userPoolClientId: aws_user_pools_web_client_id, userPoolId: aws_user_pools_id, mfa: mfaConfig, diff --git a/packages/core/src/singleton/Auth/types.ts b/packages/core/src/singleton/Auth/types.ts index 9ef1f8f26b7..44fac6f0a78 100644 --- a/packages/core/src/singleton/Auth/types.ts +++ b/packages/core/src/singleton/Auth/types.ts @@ -93,6 +93,9 @@ export type AuthStandardAttributeKey = | 'zoneinfo' | AuthVerifiableAttributeKey; +// legacy config user attribute keys are uppercase +export type LegacyUserAttributeKey = Uppercase; + export type AuthVerifiableAttributeKey = 'email' | 'phone_number'; export type AuthConfigUserAttributes = Partial< From 85158edda96de0b6818d13de040cb31124a8b36e Mon Sep 17 00:00:00 2001 From: Venkata Ramyasri Kota <34170013+kvramyasri7@users.noreply.github.com> Date: Thu, 30 Nov 2023 13:26:34 -0800 Subject: [PATCH 09/15] fix: `Build Sample App Tests` and `integ_next_auth_authenticator_and_ssr_page` tests fix (#12655) fix: Build Sample App Tests and integ_next_auth_authenticator_and_ssr_page tests --- .github/canary-config/canary-all.yml | 63 ++++++++----------- .../callable-canary-sampleapp-tests.yml | 2 +- 2 files changed, 28 insertions(+), 37 deletions(-) diff --git a/.github/canary-config/canary-all.yml b/.github/canary-config/canary-all.yml index 47241d613d7..6cb7dc8f928 100644 --- a/.github/canary-config/canary-all.yml +++ b/.github/canary-config/canary-all.yml @@ -1,12 +1,3 @@ -minimal_browser_list: &minimal_browser_list - - chrome - - firefox - -extended_browser_list: &extended_browser_list - - chrome - - firefox - - edge - tests: # DATASTORE - test_name: integ_datastore_auth-owner-based-default @@ -15,56 +6,56 @@ tests: category: datastore sample_name: owner-based-default spec: owner-based-default - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore desc: 'React DataStore' framework: react category: datastore sample_name: [many-to-many] spec: many-to-many - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_multi_auth_one_rule desc: 'React DataStore Multi-Auth - One Rule' framework: react category: datastore sample_name: [multi-auth] spec: multi-auth-one-rule - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_multi_auth_three_plus_rules desc: 'React DataStore Multi-Auth - Three Plus Rules' framework: react category: datastore sample_name: [multi-auth] spec: multi-auth-three-plus-rules - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_subs_disabled desc: 'DataStore - Subs Disabled' framework: react category: datastore sample_name: [subs-disabled] spec: subs-disabled - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_consecutive_saves desc: 'DataStore - Subs Disabled' framework: react category: datastore sample_name: [consecutive-saves] spec: consecutive-saves - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_schema_drift desc: 'DataStore - Schema Drift' framework: react category: datastore sample_name: [schema-drift] spec: schema-drift - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_background_process_manager desc: 'DataStore - Background Process Manager' framework: react category: datastore sample_name: [v2/background-process-manager] spec: background-process-manager - browser: *extended_browser_list + browser: [chrome, edge, firefox] # TODO: remove when updated CPK + related models tests are added # - test_name: integ_react_datastore_related_models # desc: 'DataStore - Related Models' @@ -90,14 +81,14 @@ tests: category: datastore sample_name: [selective-sync-v5] spec: selective-sync-v5 - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_datastore_docs_examples desc: 'DataStore - Docs Examples' framework: react category: datastore sample_name: [v2/amplify-docs-examples] spec: amplify-docs-examples - browser: *minimal_browser_list + browser: [chrome, firefox] timeout_minutes: 45 retry_count: 10 - test_name: integ_react_datastore_websocket_disruption @@ -106,21 +97,21 @@ tests: category: datastore sample_name: [websocket-disruption] spec: websocket-disruption - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_next_datastore_owner_auth desc: 'next owner auth' framework: next category: datastore sample_name: [owner-based-default] spec: next-owner-based-default - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_next_datastore_13_js desc: 'DataStore - Nextjs 13 build with SWC - JS app' framework: next category: datastore sample_name: [next-13-js] spec: nextjs-13 - browser: *minimal_browser_list + browser: [chrome, firefox] timeout_minutes: 45 retry_count: 10 - test_name: integ_rollup_datastore_basic_crud @@ -174,14 +165,14 @@ tests: category: interactions sample_name: [lex-test-component] spec: chatbot-v1 - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_interactions_chatbot_v2 desc: 'Chatbot V2' framework: react category: interactions sample_name: [lex-test-component] spec: chatbot-v2 - browser: *minimal_browser_list + browser: [chrome, firefox] # - test_name: integ_angular_interactions # desc: 'Angular Interactions' # framework: angular @@ -203,7 +194,7 @@ tests: category: predictions sample_name: [multi-user-translation] spec: multiuser-translation - browser: *minimal_browser_list + browser: [chrome, firefox] # PUBSUB - test_name: integ_react_iot_reconnect @@ -230,21 +221,21 @@ tests: category: storage sample_name: [storageApp] spec: storage - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_storage_multipart_progress desc: 'React Storage Multi-Part Upload with Progress' framework: react category: storage sample_name: [multi-part-upload-with-progress] spec: multi-part-upload-with-progress - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_storage_copy desc: 'React Storage Copy' framework: react category: storage sample_name: [multi-part-copy] spec: multi-part-copy - browser: *minimal_browser_list + browser: [chrome, firefox] # API - test_name: integ_react_graphql_api @@ -253,7 +244,7 @@ tests: category: api sample_name: [graphql] spec: graphql - browser: *minimal_browser_list + browser: [chrome, firefox] # AUTH - test_name: integ_react_auth_2_react_credentials_different_region @@ -262,35 +253,35 @@ tests: category: auth sample_name: [credentials-auth] spec: credentials-auth - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_device_tracking desc: 'cognito-device-tracking' framework: react category: auth sample_name: [device-tracking] spec: device-tracking - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_react_delete_user desc: 'delete-user' framework: react category: auth sample_name: [delete-user] spec: delete-user - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_angular_auth_angular_authenticator desc: 'Angular Authenticator' framework: angular category: auth sample_name: [amplify-authenticator] spec: ui-amplify-authenticator - browser: *minimal_browser_list + browser: [chrome, firefox] - test_name: integ_javascript_auth desc: 'JavaScript Auth CDN' framework: javascript category: auth sample_name: [auth-cdn] spec: auth-cdn - browser: *minimal_browser_list + browser: [chrome, firefox] amplifyjs_dir: true - test_name: integ_vue_auth_legacy_vue_authenticator desc: 'Legacy Vue Authenticator' @@ -298,11 +289,11 @@ tests: category: auth sample_name: [amplify-authenticator-legacy] spec: authenticator - browser: *minimal_browser_list + browser:[chrome, firefox] - test_name: integ_next_auth_authenticator_and_ssr_page desc: 'Authenticator and SSR page' framework: next category: auth sample_name: [auth-ssr] spec: auth-ssr - browser: *minimal_browser_list + browser: [chrome, edge] diff --git a/.github/workflows/callable-canary-sampleapp-tests.yml b/.github/workflows/callable-canary-sampleapp-tests.yml index 51ab2e75060..f89746c61b7 100644 --- a/.github/workflows/callable-canary-sampleapp-tests.yml +++ b/.github/workflows/callable-canary-sampleapp-tests.yml @@ -67,7 +67,7 @@ jobs: # Angular - name: Install angular CLI - run: npm install -g @angular/cli + run: npm install -g @angular/cli@16.2.10 - name: Create angular application run: npx -p @angular/cli ng new new-angular-app working-directory: amplify-js-samples-staging/samples/angular/interactions From eb3a0361bf49aa16b6258b149b133f4338a014d1 Mon Sep 17 00:00:00 2001 From: Venkata Ramyasri Kota <34170013+kvramyasri7@users.noreply.github.com> Date: Thu, 30 Nov 2023 14:07:54 -0800 Subject: [PATCH 10/15] Fix: remove `integ_vue_auth_legacy_vue_authenticator` failing canary test (#12657) * chore: remove integ_vue_auth_legacy_vue_authenticator test --- .github/canary-config/canary-all.yml | 7 ------- 1 file changed, 7 deletions(-) diff --git a/.github/canary-config/canary-all.yml b/.github/canary-config/canary-all.yml index 6cb7dc8f928..4efe7781471 100644 --- a/.github/canary-config/canary-all.yml +++ b/.github/canary-config/canary-all.yml @@ -283,13 +283,6 @@ tests: spec: auth-cdn browser: [chrome, firefox] amplifyjs_dir: true - - test_name: integ_vue_auth_legacy_vue_authenticator - desc: 'Legacy Vue Authenticator' - framework: vue - category: auth - sample_name: [amplify-authenticator-legacy] - spec: authenticator - browser:[chrome, firefox] - test_name: integ_next_auth_authenticator_and_ssr_page desc: 'Authenticator and SSR page' framework: next From ef20ad8280421400d3e94ca004c93f4f7b166953 Mon Sep 17 00:00:00 2001 From: Hui Zhao <10602282+HuiSF@users.noreply.github.com> Date: Thu, 30 Nov 2023 17:28:30 -0800 Subject: [PATCH 11/15] fix(core): adapter-core: make SetCookieOptions fields optional (#12658) --- .../src/adapterCore/serverContext/types/cookieStorage.ts | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/core/src/adapterCore/serverContext/types/cookieStorage.ts b/packages/core/src/adapterCore/serverContext/types/cookieStorage.ts index 1c60fa22407..019a69951d1 100644 --- a/packages/core/src/adapterCore/serverContext/types/cookieStorage.ts +++ b/packages/core/src/adapterCore/serverContext/types/cookieStorage.ts @@ -4,9 +4,11 @@ import { CookieSerializeOptions } from 'cookie'; export namespace CookieStorage { - export type SetCookieOptions = Pick< - CookieSerializeOptions, - 'domain' | 'expires' | 'httpOnly' | 'maxAge' | 'sameSite' | 'secure' + export type SetCookieOptions = Partial< + Pick< + CookieSerializeOptions, + 'domain' | 'expires' | 'httpOnly' | 'maxAge' | 'sameSite' | 'secure' + > >; export type Cookie = { From 38282bb8ca85c3c5cc59d40d4fefda1083687b44 Mon Sep 17 00:00:00 2001 From: Hui Zhao <10602282+HuiSF@users.noreply.github.com> Date: Fri, 1 Dec 2023 10:11:02 -0800 Subject: [PATCH 12/15] chore(aws-amplify): add inline docs for Amplify configure and getConfig methods (#12487) * chore(aws-amplify): add inline docs for Amplify configure and getConfig methods * Apply suggestions from code review Co-authored-by: Chris F <5827964+cshfang@users.noreply.github.com> --------- Co-authored-by: Chris F <5827964+cshfang@users.noreply.github.com> --- packages/aws-amplify/src/initSingleton.ts | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/aws-amplify/src/initSingleton.ts b/packages/aws-amplify/src/initSingleton.ts index 7398442ddfb..748012baf14 100644 --- a/packages/aws-amplify/src/initSingleton.ts +++ b/packages/aws-amplify/src/initSingleton.ts @@ -17,10 +17,22 @@ import { } from './auth/cognito'; export const DefaultAmplify = { + /** + * Configures Amplify with the {@link resourceConfig} and {@link libraryOptions}. + * + * @param resourceConfig The {@link ResourcesConfig} object that is typically imported from the + * `amplifyconfiguration.json` file. It can also be an object literal created inline when calling `Amplify.configure`. + * @param libraryOptions The {@link LibraryOptions} additional options for the library. + * + * @example + * import config from './amplifyconfiguration.json'; + * + * Amplify.configure(config); + */ configure( resourceConfig: ResourcesConfig | LegacyConfig, libraryOptions?: LibraryOptions - ) { + ): void { let resolvedResourceConfig: ResourcesConfig; if (Object.keys(resourceConfig).some(key => key.startsWith('aws_'))) { @@ -81,6 +93,12 @@ export const DefaultAmplify = { // configured libraryOptions. Amplify.configure(resolvedResourceConfig); }, + /** + * Returns the {@link ResourcesConfig} object passed in as the `resourceConfig` parameter when calling + * `Amplify.configure`. + * + * @returns An {@link ResourcesConfig} object. + */ getConfig(): ResourcesConfig { return Amplify.getConfig(); }, From 271546de73cbbc8958ccd107a30bd5465ed01740 Mon Sep 17 00:00:00 2001 From: israx <70438514+israx@users.noreply.github.com> Date: Mon, 4 Dec 2023 11:00:11 -0500 Subject: [PATCH 13/15] fix(auth): dispatch signInWithRedirect error (#12653) * fix: dispatch signInWithRedirect failure event * chore: add unit tests * chore: bundle size test * chore: address feedback * chore: remove unknown type --- .../cognito/signInWithRedirect.test.ts | 318 +++++++++++++----- .../cognito/apis/signInWithRedirect.ts | 88 +++-- packages/aws-amplify/package.json | 2 +- packages/core/src/Hub/types/AuthTypes.ts | 11 +- 4 files changed, 293 insertions(+), 126 deletions(-) diff --git a/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts b/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts index 393854f3fee..da55fbc15f8 100644 --- a/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts +++ b/packages/auth/__tests__/providers/cognito/signInWithRedirect.test.ts @@ -2,12 +2,49 @@ // SPDX-License-Identifier: Apache-2.0 import { AuthError } from '../../../src/errors/AuthError'; +import { Hub } from '@aws-amplify/core'; import { INVALID_ORIGIN_EXCEPTION, INVALID_REDIRECT_EXCEPTION, } from '../../../src/errors/constants'; import { getRedirectUrl } from '../../../src/providers/cognito/utils/oauth/getRedirectUrl'; import { getRedirectUrl as getRedirectUrlRN } from '../../../src/providers/cognito/utils/oauth/getRedirectUrl.native'; +import { + parseRedirectURL, + signInWithRedirect, +} from '../../../src/providers/cognito/apis/signInWithRedirect'; +import { openAuthSession } from '../../../src/utils'; +import { AMPLIFY_SYMBOL } from '@aws-amplify/core/internals/utils'; +jest.mock('../../../src/utils/openAuthSession'); +jest.mock('@aws-amplify/core', () => ({ + ...(jest.createMockFromModule('@aws-amplify/core') as object), + Amplify: { + getConfig: jest.fn(() => ({ + Auth: { + Cognito: { + userPoolClientId: '111111-aaaaa-42d8-891d-ee81a1549398', + userPoolId: 'us-west-2_zzzzz', + identityPoolId: 'us-west-2:xxxxxx', + loginWith: { + oauth: { + domain: 'my_cognito_domain', + redirectSignIn: ['http://localhost:3000/'], + redirectSignOut: ['http://localhost:3000/'], + responseType: 'code', + scopes: [ + 'email', + 'openid', + 'profile', + 'aws.cognito.signin.user.admin', + ], + }, + }, + }, + }, + })), + }, + Hub: { dispatch: jest.fn(), listen: jest.fn() }, +})); describe('signInWithRedirect API', () => { it('should pass correct arguments to oauth', () => { @@ -17,110 +54,205 @@ describe('signInWithRedirect API', () => { it('should try to clear oauth data before starting an oauth flow.', async () => { // TODO: ADD Test: previous test was invalid }); -}); -describe('getRedirectUrl on web', () => { - const originalWindowLocation = window.location; - - const currentWindownLocationParamsList: { - origin: string; - pathname: string; - }[] = [ - { origin: 'https://example.com', pathname: '/' }, - { origin: 'https://example.com', pathname: '/app' }, - { origin: 'https://example.com', pathname: '/app/page' }, - { origin: 'http://localhost:3000', pathname: '/' }, - { origin: 'http://localhost:3000', pathname: '/app' }, - ]; - afterEach(() => { - Object.defineProperty(globalThis, 'window', { - value: originalWindowLocation, + describe('signInWithRedirect API error cases', () => { + const oauthErrorMessage = 'an oauth error has occurred'; + const oauthError = new AuthError({ + name: 'OAuthSignInException', + message: oauthErrorMessage, }); - }); - it.each(currentWindownLocationParamsList)( - 'should pick the url that matches the current window', - async windowParams => { - const { origin, pathname } = windowParams; - Object.defineProperty(globalThis, 'window', { - value: { location: { origin, pathname } }, + const invalidStateOauthError = new AuthError({ + name: 'OAuthSignInException', + message: "An error occurred while validating the state", + }); + const mockOpenAuthSession = openAuthSession as jest.Mock; + const mockHubDispatch = Hub.dispatch as jest.Mock; + + afterEach(() => { + mockOpenAuthSession.mockReset(); + }); + + it('should throw and dispatch when an error is returned in the URL in RN', async () => { + mockOpenAuthSession.mockResolvedValueOnce({ + type: 'error', + error: oauthErrorMessage, + }); + + await expect(signInWithRedirect()).rejects.toThrow(oauthError); + expect(Hub.dispatch).toHaveBeenCalledWith( + 'auth', + { + event: 'signInWithRedirect_failure', + data: { error: oauthError }, + }, + 'Auth', + AMPLIFY_SYMBOL + ); + }); + + it('should throw when state is not valid after calling signInWithRedirect', async () => { + mockOpenAuthSession.mockResolvedValueOnce({ + type: 'success', + url: 'http:localhost:3000/oauth2/redirect?state=invalid_state&code=mock_code&scope=openid%20email%20profile&session_state=mock_session_state', + }); + + await expect(signInWithRedirect()).rejects.toThrow(invalidStateOauthError); + expect(mockHubDispatch).toHaveBeenCalledWith( + 'auth', + { + event: 'signInWithRedirect_failure', + data: { error: invalidStateOauthError }, + }, + 'Auth', + AMPLIFY_SYMBOL + ); + + }); + + it('should dispatch the signInWithRedirect_failure event when an error is returned in the URL', async () => { + Object.defineProperty(window, 'location', { + value: { + href: 'http:localhost:3000/oauth2/redirect?error=OAuthSignInException&error_description=an+oauth+error+has+occurred', + }, writable: true, }); - const redirectsFromConfig = [ - 'http://localhost:3000/', - 'https://example.com/', - 'https://example.com/app', - 'https://example.com/app/page', - 'http://localhost:3000/app', - ]; - const redirect = getRedirectUrl(redirectsFromConfig); - expect(redirect).toBe( - redirectsFromConfig.find(redir => redir === redirect) + await expect(parseRedirectURL).not.toThrow(); + expect(mockHubDispatch).toHaveBeenCalledWith( + 'auth', + { + event: 'signInWithRedirect_failure', + data: { error: oauthError }, + }, + 'Auth', + AMPLIFY_SYMBOL ); - } - ); - it('should pick the first url that is comming from a different pathname but same domain', async () => { - Object.defineProperty(globalThis, 'window', { - value: { - location: { - origin: 'https://example.com', - pathname: '/app', - hostname: 'example.com', + }); + + it('should dispatch the signInWithRedirect_failure event when state is not valid', async () => { + Object.defineProperty(window, 'location', { + value: { + href: `http:localhost:3000/oauth2/redirect?state='invalid_state'&code=mock_code&scope=openid%20email%20profile&session_state=mock_session_state`, }, - }, - writable: true, + writable: true, + }); + await expect(parseRedirectURL).not.toThrow(); + expect(mockHubDispatch).toHaveBeenCalledWith( + 'auth', + { + event: 'signInWithRedirect_failure', + data: { error: oauthError }, + }, + 'Auth', + AMPLIFY_SYMBOL + ); }); - const redirect = getRedirectUrl(['https://example.com/another-app']); - expect(redirect).toBe('https://example.com/another-app'); }); - - it('should throw if the url is not comming from the same origin', async () => { - Object.defineProperty(globalThis, 'window', { - value: { - location: { origin: 'https://differentorigin.com', pathname: '/app' }, - }, - writable: true, + + describe('getRedirectUrl on web', () => { + const originalWindowLocation = window.location; + + const currentWindownLocationParamsList: { + origin: string; + pathname: string; + }[] = [ + { origin: 'https://example.com', pathname: '/' }, + { origin: 'https://example.com', pathname: '/app' }, + { origin: 'https://example.com', pathname: '/app/page' }, + { origin: 'http://localhost:3000', pathname: '/' }, + { origin: 'http://localhost:3000', pathname: '/app' }, + ]; + afterEach(() => { + Object.defineProperty(globalThis, 'window', { + value: originalWindowLocation, + }); + }); + it.each(currentWindownLocationParamsList)( + 'should pick the url that matches the current window', + async windowParams => { + const { origin, pathname } = windowParams; + Object.defineProperty(globalThis, 'window', { + value: { location: { origin, pathname } }, + writable: true, + }); + const redirectsFromConfig = [ + 'http://localhost:3000/', + 'https://example.com/', + 'https://example.com/app', + 'https://example.com/app/page', + 'http://localhost:3000/app', + ]; + const redirect = getRedirectUrl(redirectsFromConfig); + expect(redirect).toBe( + redirectsFromConfig.find(redir => redir === redirect) + ); + } + ); + it('should pick the first url that is comming from a different pathname but same domain', async () => { + Object.defineProperty(globalThis, 'window', { + value: { + location: { + origin: 'https://example.com', + pathname: '/app', + hostname: 'example.com', + }, + }, + writable: true, + }); + const redirect = getRedirectUrl(['https://example.com/another-app']); + expect(redirect).toBe('https://example.com/another-app'); + }); + + it('should throw if the url is not comming from the same origin', async () => { + Object.defineProperty(globalThis, 'window', { + value: { + location: { origin: 'https://differentorigin.com', pathname: '/app' }, + }, + writable: true, + }); + + try { + return getRedirectUrl(['http://localhost:3000/', 'https://example.com/']); + } catch (error: any) { + expect(error).toBeInstanceOf(AuthError); + expect(error.name).toBe(INVALID_ORIGIN_EXCEPTION); + } + }); + + it('should throw if the url is not found or invalid', async () => { + Object.defineProperty(globalThis, 'window', { + value: { + location: { origin: 'http://localhost:3000', pathname: '/' }, + }, + writable: true, + }); + + try { + return getRedirectUrl(['novalid']); + } catch (error: any) { + expect(error).toBeInstanceOf(AuthError); + expect(error.name).toBe(INVALID_REDIRECT_EXCEPTION); + } }); - - try { - return getRedirectUrl(['http://localhost:3000/', 'https://example.com/']); - } catch (error: any) { - expect(error).toBeInstanceOf(AuthError); - expect(error.name).toBe(INVALID_ORIGIN_EXCEPTION); - } }); - - it('should throw if the url is not found or invalid', async () => { - Object.defineProperty(globalThis, 'window', { - value: { - location: { origin: 'http://localhost:3000', pathname: '/' }, - }, - writable: true, + + describe('getRedirectUrl on React Native', () => { + it('should pick the first non http or https redirect', async () => { + const redirect = getRedirectUrlRN([ + 'app:custom', + 'https://example.com/', + 'http://localhost:3000/', + ]); + expect(redirect).toBe('app:custom'); + }); + it('should throw if the redirect is invalid or not found', async () => { + try { + return getRedirectUrlRN(['invalid']); + } catch (error: any) { + expect(error).toBeInstanceOf(AuthError); + expect(error.name).toBe(INVALID_REDIRECT_EXCEPTION); + } }); - - try { - return getRedirectUrl(['novalid']); - } catch (error: any) { - expect(error).toBeInstanceOf(AuthError); - expect(error.name).toBe(INVALID_REDIRECT_EXCEPTION); - } }); }); -describe('getRedirectUrl on React Native', () => { - it('should pick the first non http or https redirect', async () => { - const redirect = getRedirectUrlRN([ - 'app:custom', - 'https://example.com/', - 'http://localhost:3000/', - ]); - expect(redirect).toBe('app:custom'); - }); - it('should throw if the redirect is invalid or not found', async () => { - try { - return getRedirectUrlRN(['invalid']); - } catch (error: any) { - expect(error).toBeInstanceOf(AuthError); - expect(error.name).toBe(INVALID_REDIRECT_EXCEPTION); - } - }); -}); + diff --git a/packages/auth/src/providers/cognito/apis/signInWithRedirect.ts b/packages/auth/src/providers/cognito/apis/signInWithRedirect.ts index 76f99752cf1..4794f860632 100644 --- a/packages/auth/src/providers/cognito/apis/signInWithRedirect.ts +++ b/packages/auth/src/providers/cognito/apis/signInWithRedirect.ts @@ -116,6 +116,8 @@ export async function oauthSignIn({ const { type, error, url } = (await openAuthSession(oAuthUrl, redirectSignIn, preferPrivateSession)) ?? {}; + // This code will run in RN applications only as calling signInWithRedirect will + // resolve the promise. if (type === 'success' && url) { // ensure the code exchange completion resolves the signInWithRedirect // returned promise in react-native @@ -129,8 +131,10 @@ export async function oauthSignIn({ preferPrivateSession, }); } + // This code will run in RN applications only as calling signInWithRedirect will + // resolve the promise. if (type === 'error') { - handleFailure(String(error)); + await handleFailure(String(error)); } } @@ -154,11 +158,13 @@ async function handleCodeFlow({ const url = new AmplifyUrl(currentUrl); let validatedState: string; try { - validatedState = await validateStateFromURL(url); + validatedState = await validateState(getStateFromURL(url)); } catch (err) { invokeAndClearPromise(); - // clear temp values - await store.clearOAuthInflightData(); + // validateState method will always throw an AuthError when the state is not valid. The if statement is making TS happy. + if (err instanceof AuthError) { + await handleFailure(err.message); + } return; } const code = url.searchParams.get('code'); @@ -197,6 +203,7 @@ async function handleCodeFlow({ refresh_token, id_token, error, + error_message, token_type, expires_in, } = await ( @@ -212,7 +219,7 @@ async function handleCodeFlow({ if (error) { invokeAndClearPromise(); - handleFailure(error); + await handleFailure(error_message ?? error); } await store.clearOAuthInflightData(); @@ -249,9 +256,15 @@ async function handleImplicitFlow({ const url = new AmplifyUrl(currentUrl); - const { id_token, access_token, state, token_type, expires_in } = ( - url.hash ?? '#' - ) + const { + id_token, + access_token, + state, + token_type, + expires_in, + error_description, + error, + } = (url.hash ?? '#') .substring(1) // Remove # from returned code .split('&') .map(pairings => pairings.split('=')) @@ -261,17 +274,29 @@ async function handleImplicitFlow({ state: undefined, token_type: undefined, expires_in: undefined, + error_description: undefined, + error: undefined, }); + + if (error) { + invokeAndClearPromise(); + await handleFailure(error_description ?? error); + } + if (!access_token) { await store.clearOAuthData(); invokeAndClearPromise(); return; } - + let validatedState; try { - validateState(state); + validatedState = await validateState(state); } catch (error) { invokeAndClearPromise(); + // validateState method will always throw an AuthError when the state is not valid. The if statement is making TS happy. + if (error instanceof AuthError) { + await handleFailure(error.message); + } return; } @@ -286,7 +311,11 @@ async function handleImplicitFlow({ ExpiresIn: expires_in, }); - return completeFlow({ redirectUri, state, preferPrivateSession }); + return completeFlow({ + redirectUri, + state: validatedState, + preferPrivateSession, + }); } async function completeFlow({ @@ -345,7 +374,7 @@ async function handleAuthResponse({ const errorMessage = urlParams.searchParams.get('error_description'); if (error) { - handleFailure(errorMessage); + await handleFailure(errorMessage); } if (responseType === 'code') { @@ -369,36 +398,35 @@ async function handleAuthResponse({ } } -async function validateStateFromURL(urlParams: URL): Promise { - if (!urlParams) { - } - const returnedState = urlParams.searchParams.get('state'); - - validateState(returnedState); - return returnedState; +function getStateFromURL(urlParams: URL): string | null { + return urlParams.searchParams.get('state'); } -function validateState(state?: string | null): asserts state { - let savedState: string | undefined | null; - - store.loadOAuthState().then(resp => { - savedState = resp; - }); +async function validateState(state?: string | null): Promise { + const savedState = await store.loadOAuthState(); // This is because savedState only exists if the flow was initiated by Amplify - if (savedState && state && savedState !== state) { + const validatedState = state === savedState ? savedState : undefined; + if (!validatedState) { throw new AuthError({ name: AuthErrorTypes.OAuthSignInError, message: 'An error occurred while validating the state', recoverySuggestion: 'Try to initiate an OAuth flow from Amplify', }); } + return validatedState; } -function handleFailure(errorMessage: string | null) { +async function handleFailure(errorMessage: string | null) { + const error = new AuthError({ + message: errorMessage ?? 'An error has occurred during the oauth proccess', + name: AuthErrorCodes.OAuthSignInError, + recoverySuggestion: authErrorMessages.oauthSignInError.log, + }); + await store.clearOAuthInflightData(); Hub.dispatch( 'auth', - { event: 'signInWithRedirect_failure' }, + { event: 'signInWithRedirect_failure', data: { error } }, 'Auth', AMPLIFY_SYMBOL ); @@ -409,7 +437,7 @@ function handleFailure(errorMessage: string | null) { }); } -async function parseRedirectURL() { +export async function parseRedirectURL() { const authConfig = Amplify.getConfig().Auth?.Cognito; try { assertTokenProviderConfig(authConfig); @@ -435,7 +463,7 @@ async function parseRedirectURL() { const { loginWith, userPoolClientId } = authConfig; const { domain, redirectSignIn, responseType } = loginWith.oauth; - handleAuthResponse({ + await handleAuthResponse({ currentUrl, clientId: userPoolClientId, domain, diff --git a/packages/aws-amplify/package.json b/packages/aws-amplify/package.json index b1d2a5de93c..6b6cb096b5a 100644 --- a/packages/aws-amplify/package.json +++ b/packages/aws-amplify/package.json @@ -445,7 +445,7 @@ "name": "[Auth] OAuth Auth Flow (Cognito)", "path": "./dist/esm/auth/index.mjs", "import": "{ signInWithRedirect, signOut, fetchAuthSession }", - "limit": "19.61 kB" + "limit": "19.68 kB" }, { "name": "[Storage] copy (S3)", diff --git a/packages/core/src/Hub/types/AuthTypes.ts b/packages/core/src/Hub/types/AuthTypes.ts index eb7533b1e2e..127acaf0f49 100644 --- a/packages/core/src/Hub/types/AuthTypes.ts +++ b/packages/core/src/Hub/types/AuthTypes.ts @@ -5,12 +5,19 @@ type AuthUser = { username: string; userId: string; }; - +type AuthError = { + name: string; + message: string; + recoverySuggestion?: string; +}; export type AuthHubEventData = /** Dispatched when a user signs in with an oauth provider such as Google.*/ | { event: 'signInWithRedirect' } /** Dispatched when there is an error in the oauth flow process.*/ - | { event: 'signInWithRedirect_failure' } + | { + event: 'signInWithRedirect_failure'; + data: { error?: AuthError }; + } /** Dispatched when auth tokens are successfully refreshed.*/ | { event: 'tokenRefresh' } /** Dispatched when there is an error in the refresh of tokens.*/ From e101ceac6a901e240d574e30909ca4409fe91357 Mon Sep 17 00:00:00 2001 From: David McAfee Date: Mon, 4 Dec 2023 08:55:44 -0800 Subject: [PATCH 14/15] fix(data): fix library configuration options headers for subscriptions (#12590) (#12659) --- .../AWSAppSyncRealTimeProvider.test.ts | 28 + .../__tests__/generateClient.test.ts | 863 ++++++++++++++++++ .../api-graphql/__tests__/utils/expects.ts | 35 + packages/api-graphql/src/GraphQLAPI.ts | 2 +- .../AWSAppSyncRealTimeProvider/index.ts | 8 +- .../src/internals/InternalGraphQLAPI.ts | 15 +- packages/api-graphql/src/types/index.ts | 2 +- .../api-rest/src/apis/common/publicApis.ts | 4 +- packages/api/src/internals/InternalAPI.ts | 2 +- packages/core/src/singleton/API/types.ts | 6 +- 10 files changed, 952 insertions(+), 13 deletions(-) diff --git a/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts b/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts index 70156efb52e..4500ce8a566 100644 --- a/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts +++ b/packages/api-graphql/__tests__/AWSAppSyncRealTimeProvider.test.ts @@ -1055,6 +1055,34 @@ describe('AWSAppSyncRealTimeProvider', () => { ); }); + test('authenticating with userPool / custom library options token', async () => { + expect.assertions(1); + + provider + .subscribe({ + appSyncGraphqlEndpoint: 'ws://localhost:8080', + authenticationType: 'userPool', + /** + * When Amplify is configured with a `header` function + * that returns an `Authorization` token, the GraphQL + * API will pass this function as the `libraryConfigHeaders` + * option to the AWSAppSyncRealTimeProvider's `subscribe` + * function. + */ + libraryConfigHeaders: async () => ({ + Authorization: 'test', + }), + }) + .subscribe({ error: () => {} }); + + await fakeWebSocketInterface?.readyForUse; + + expect(loggerSpy).toHaveBeenCalledWith( + 'DEBUG', + 'Authenticating with "userPool"' + ); + }); + test('authenticating with AWS_LAMBDA/custom w/ custom header function', async () => { expect.assertions(1); diff --git a/packages/api-graphql/__tests__/generateClient.test.ts b/packages/api-graphql/__tests__/generateClient.test.ts index efe6ac50b5a..272d765c403 100644 --- a/packages/api-graphql/__tests__/generateClient.test.ts +++ b/packages/api-graphql/__tests__/generateClient.test.ts @@ -7,6 +7,7 @@ import { expectSub, expectSubWithHeaders, expectSubWithHeadersFn, + expectSubWithlibraryConfigHeaders, } from './utils/expects'; import { Observable, from } from 'rxjs'; import * as internals from '../src/internals/'; @@ -4606,6 +4607,868 @@ describe('generateClient', () => { }); }); }); + describe('basic model operations with Amplify configuration options headers', () => { + beforeEach(() => { + jest.clearAllMocks(); + + Amplify.configure(configFixture as any, { + API: { + GraphQL: { + // This is what we're testing: + headers: async () => ({ + Authorization: 'amplify-config-auth-token', + }), + }, + }, + }); + }); + + test('can create() - with library config headers', async () => { + const spy = mockApiResponse({ + data: { + createTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + + const { data } = await client.models.Todo.create({ + name: 'some name', + description: 'something something', + }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('createTodo(input: $input)'), + variables: { + input: { + name: 'some name', + description: 'something something', + }, + }, + }, + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can create() - custom client headers should not overwrite library config headers', async () => { + const spy = mockApiResponse({ + data: { + createTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + + const { data } = await client.models.Todo.create({ + name: 'some name', + description: 'something something', + }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'client-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('createTodo(input: $input)'), + variables: { + input: { + name: 'some name', + description: 'something something', + }, + }, + }, + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can create() - custom request headers should not overwrite library config headers', async () => { + const spy = mockApiResponse({ + data: { + createTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + }); + + const { data } = await client.models.Todo.create( + { + name: 'some name', + description: 'something something', + }, + { + headers: { + 'request-header': 'should exist', + }, + } + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'request-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('createTodo(input: $input)'), + variables: { + input: { + name: 'some name', + description: 'something something', + }, + }, + }, + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can get() - custom client headers should not overwrite library config headers', async () => { + const spy = mockApiResponse({ + data: { + getTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + const { data } = await client.models.Todo.get({ id: 'asdf' }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'client-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('getTodo(id: $id)'), + variables: { + id: 'asdf', + }, + }, + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can get() - custom request headers overwrite client headers, but not library config headers', async () => { + const spy = mockApiResponse({ + data: { + getTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should not exist', + }, + }); + const { data } = await client.models.Todo.get( + { id: 'asdf' }, + { + headers: { + 'request-header': 'should exist', + }, + } + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'request-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('getTodo(id: $id)'), + variables: { + id: 'asdf', + }, + }, + }), + }) + ); + + // Request headers should overwrite client headers: + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.not.objectContaining({ + 'client-header': 'should not exist', + }), + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can list() - custom client headers should not overwrite library config headers', async () => { + const spy = mockApiResponse({ + data: { + listTodos: { + items: [ + { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + ], + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + const { data } = await client.models.Todo.list({ + filter: { name: { contains: 'name' } }, + }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'client-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining( + 'listTodos(filter: $filter, limit: $limit, nextToken: $nextToken)' + ), + variables: { + filter: { + name: { + contains: 'name', + }, + }, + }, + }, + }), + }) + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + body: expect.objectContaining({ + // match nextToken in selection set + query: expect.stringMatching(/^\s*nextToken\s*$/m), + }), + }), + }) + ); + + expect(data.length).toBe(1); + expect(data[0]).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can list() - custom request headers should overwrite client headers but not library config headers', async () => { + const spy = mockApiResponse({ + data: { + listTodos: { + items: [ + { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + ], + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should not exist', + }, + }); + const { data } = await client.models.Todo.list({ + filter: { name: { contains: 'name' } }, + headers: { + 'request-header': 'should exist', + }, + }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'request-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining( + 'listTodos(filter: $filter, limit: $limit, nextToken: $nextToken)' + ), + variables: { + filter: { + name: { + contains: 'name', + }, + }, + }, + }, + }), + }) + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.not.objectContaining({ + 'client-header': 'should not exist', + }), + }), + }) + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + body: expect.objectContaining({ + // match nextToken in selection set + query: expect.stringMatching(/^\s*nextToken\s*$/m), + }), + }), + }) + ); + + expect(data.length).toBe(1); + expect(data[0]).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can update() - custom client headers should not overwrite library config headers', async () => { + const spy = mockApiResponse({ + data: { + updateTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some other name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + const { data } = await client.models.Todo.update({ + id: 'some-id', + name: 'some other name', + }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'client-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('updateTodo(input: $input)'), + variables: { + input: { + id: 'some-id', + name: 'some other name', + }, + }, + }, + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some other name', + description: 'something something', + }) + ); + }); + + test('can update() - custom request headers should overwrite client headers but not library config headers', async () => { + const spy = mockApiResponse({ + data: { + updateTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some other name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + const { data } = await client.models.Todo.update( + { + id: 'some-id', + name: 'some other name', + }, + { + headers: { + 'request-header': 'should exist', + }, + } + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'request-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('updateTodo(input: $input)'), + variables: { + input: { + id: 'some-id', + name: 'some other name', + }, + }, + }, + }), + }) + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.not.objectContaining({ + 'client-header': 'should not exist', + }), + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some other name', + description: 'something something', + }) + ); + }); + + test('can delete() - custom client headers should not overwrite library config headers', async () => { + const spy = mockApiResponse({ + data: { + deleteTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should exist', + }, + }); + const { data } = await client.models.Todo.delete({ + id: 'some-id', + }); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'client-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('deleteTodo(input: $input)'), + variables: { + input: { + id: 'some-id', + }, + }, + }, + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can delete() - custom request headers should overwrite client headers but not library config headers', async () => { + const spy = mockApiResponse({ + data: { + deleteTodo: { + __typename: 'Todo', + ...serverManagedFields, + name: 'some name', + description: 'something something', + }, + }, + }); + + const client = generateClient({ + amplify: Amplify, + headers: { + 'client-header': 'should not exist', + }, + }); + const { data } = await client.models.Todo.delete( + { + id: 'some-id', + }, + { + headers: { + 'request-header': 'should exist', + }, + } + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.objectContaining({ + 'X-Api-Key': 'FAKE-KEY', + 'request-header': 'should exist', + Authorization: 'amplify-config-auth-token', + }), + body: { + query: expect.stringContaining('deleteTodo(input: $input)'), + variables: { + input: { + id: 'some-id', + }, + }, + }, + }), + }) + ); + + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + options: expect.objectContaining({ + headers: expect.not.objectContaining({ + 'client-header': 'should not exist', + }), + }), + }) + ); + + expect(data).toEqual( + expect.objectContaining({ + __typename: 'Todo', + id: 'some-id', + owner: 'wirejobviously', + name: 'some name', + description: 'something something', + }) + ); + }); + + test('can subscribe to onCreate() - with custom headers and library config headers', done => { + const noteToSend = { + __typename: 'Note', + ...serverManagedFields, + body: 'a very good note', + }; + + const graphqlMessage = { + data: { + onCreateNote: noteToSend, + }, + }; + + const graphqlVariables = { + filter: { + body: { contains: 'good note' }, + }, + }; + + const customHeaders = { + 'subscription-header': 'should-exist', + }; + + const client = generateClient({ amplify: Amplify }); + + const spy = jest.fn(() => from([graphqlMessage])); + (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; + + client.models.Note.onCreate({ + filter: graphqlVariables.filter, + headers: customHeaders, + }).subscribe({ + next(value) { + // This util checks for the existence of library config headers: + expectSubWithlibraryConfigHeaders( + spy, + 'onCreateNote', + graphqlVariables, + customHeaders + ); + expect(value).toEqual(expect.objectContaining(noteToSend)); + done(); + }, + error(error) { + expect(error).toBeUndefined(); + done('bad news!'); + }, + }); + }); + + test('can subscribe to onUpdate() - with a custom header and library config headers', done => { + const noteToSend = { + __typename: 'Note', + ...serverManagedFields, + body: 'a very good note', + }; + + const graphqlMessage = { + data: { + onUpdateNote: noteToSend, + }, + }; + + const graphqlVariables = { + filter: { + body: { contains: 'good note' }, + }, + }; + + const customHeaders = { + 'subscription-header': 'should-exist', + }; + + const client = generateClient({ amplify: Amplify }); + + const spy = jest.fn(() => from([graphqlMessage])); + (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; + + client.models.Note.onUpdate({ + filter: graphqlVariables.filter, + headers: customHeaders, + }).subscribe({ + next(value) { + // This util checks for the existence of library config headers: + expectSubWithlibraryConfigHeaders( + spy, + 'onUpdateNote', + graphqlVariables, + customHeaders + ); + expect(value).toEqual(expect.objectContaining(noteToSend)); + done(); + }, + error(error) { + expect(error).toBeUndefined(); + done('bad news!'); + }, + }); + }); + + test('can subscribe to onDelete() - with custom headers and library config headers', done => { + const noteToSend = { + __typename: 'Note', + ...serverManagedFields, + body: 'a very good note', + }; + + const graphqlMessage = { + data: { + onDeleteNote: noteToSend, + }, + }; + + const graphqlVariables = { + filter: { + body: { contains: 'good note' }, + }, + }; + + const customHeaders = { + 'subscription-header': 'should-exist', + }; + + const client = generateClient({ amplify: Amplify }); + + const spy = jest.fn(() => from([graphqlMessage])); + (raw.GraphQLAPI as any).appSyncRealTime = { subscribe: spy }; + + client.models.Note.onDelete({ + filter: graphqlVariables.filter, + headers: customHeaders, + }).subscribe({ + next(value) { + // This util checks for the existence of library config headers: + expectSubWithlibraryConfigHeaders( + spy, + 'onDeleteNote', + graphqlVariables, + customHeaders + ); + expect(value).toEqual(expect.objectContaining(noteToSend)); + done(); + }, + error(error) { + expect(error).toBeUndefined(); + done('bad news!'); + }, + }); + }); + }); describe('observeQuery', () => { beforeEach(() => { diff --git a/packages/api-graphql/__tests__/utils/expects.ts b/packages/api-graphql/__tests__/utils/expects.ts index 2ffc07aa548..6794a82943e 100644 --- a/packages/api-graphql/__tests__/utils/expects.ts +++ b/packages/api-graphql/__tests__/utils/expects.ts @@ -176,3 +176,38 @@ export function expectSubWithHeadersFn( } ); } + +/** + * Performs an `expect()` on a jest spy with some basic nested argument checks + * based on the given subscription `opName` and `item`. + * Used specifically for testing subscriptions with additional headers. + * + * @param spy The jest spy to check. + * @param opName The name of the graphql operation. E.g., `onCreateTodo`. + * @param item The item we expect to have been in the `variables` + * @param libraryConfigHeaders TODO + */ +export function expectSubWithlibraryConfigHeaders( + spy: jest.SpyInstance, + opName: string, + item: Record, + headers?: CustomHeaders +) { + expect(spy).toHaveBeenCalledWith( + expect.objectContaining({ + authenticationType: 'apiKey', + apiKey: 'FAKE-KEY', + appSyncGraphqlEndpoint: 'https://localhost/graphql', + // Code-gen'd queries have an owner param; TypeBeast queries don't: + query: expect.stringContaining(`${opName}(filter: $filter`), + variables: expect.objectContaining(item), + additionalHeaders: expect.objectContaining(headers), + // `headers` that are included in `Amplify.configure` options + libraryConfigHeaders: expect.any(Function), + }), + { + action: '1', + category: 'api', + } + ); +} diff --git a/packages/api-graphql/src/GraphQLAPI.ts b/packages/api-graphql/src/GraphQLAPI.ts index 41f79741bc3..31699d6981b 100644 --- a/packages/api-graphql/src/GraphQLAPI.ts +++ b/packages/api-graphql/src/GraphQLAPI.ts @@ -29,7 +29,7 @@ export class GraphQLAPIClass extends InternalGraphQLAPIClass { * Executes a GraphQL operation * * @param options - GraphQL Options - * @param [additionalHeaders] - headers to merge in after any `graphql_headers` set in the config + * @param [additionalHeaders] - headers to merge in after any `libraryConfigHeaders` set in the config * @returns An Observable if the query is a subscription query, else a promise of the graphql result. */ graphql( diff --git a/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts b/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts index 7b62404c586..a8fb82a05ce 100644 --- a/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts +++ b/packages/api-graphql/src/Providers/AWSAppSyncRealTimeProvider/index.ts @@ -97,7 +97,7 @@ export interface AWSAppSyncRealTimeProviderOptions { variables?: Record; apiKey?: string; region?: string; - graphql_headers?: () => {} | (() => Promise<{}>); + libraryConfigHeaders?: () => {} | (() => Promise<{}>); additionalHeaders?: | Record | (() => Promise>); @@ -203,6 +203,7 @@ export class AWSAppSyncRealTimeProvider { additionalHeaders, apiKey, authToken, + libraryConfigHeaders, } = options || {}; return new Observable(observer => { @@ -235,6 +236,7 @@ export class AWSAppSyncRealTimeProvider { additionalHeaders, apiKey, authToken, + libraryConfigHeaders, }, observer, subscriptionId, @@ -313,7 +315,7 @@ export class AWSAppSyncRealTimeProvider { variables, apiKey, region, - graphql_headers = () => ({}), + libraryConfigHeaders = () => ({}), additionalHeaders = {}, authToken, } = options; @@ -361,7 +363,7 @@ export class AWSAppSyncRealTimeProvider { region, additionalCustomHeaders, })), - ...(await graphql_headers()), + ...(await libraryConfigHeaders()), ...additionalCustomHeaders, [USER_AGENT_HEADER]: getAmplifyUserAgent(customUserAgentDetails), }; diff --git a/packages/api-graphql/src/internals/InternalGraphQLAPI.ts b/packages/api-graphql/src/internals/InternalGraphQLAPI.ts index c473d64c916..31d7223c9a4 100644 --- a/packages/api-graphql/src/internals/InternalGraphQLAPI.ts +++ b/packages/api-graphql/src/internals/InternalGraphQLAPI.ts @@ -149,7 +149,7 @@ export class InternalGraphQLAPIClass { * Executes a GraphQL operation * * @param options - GraphQL Options - * @param [additionalHeaders] - headers to merge in after any `graphql_headers` set in the config + * @param [additionalHeaders] - headers to merge in after any `libraryConfigHeaders` set in the config * @returns An Observable if the query is a subscription query, else a promise of the graphql result. */ graphql( @@ -236,7 +236,7 @@ export class InternalGraphQLAPIClass { endpoint: appSyncGraphqlEndpoint, customEndpoint, customEndpointRegion, - defaultAuthMode + defaultAuthMode, } = resolveConfig(amplify); const authMode = explicitAuthMode || defaultAuthMode || 'iam'; @@ -424,6 +424,16 @@ export class InternalGraphQLAPIClass { ): Observable { const config = resolveConfig(amplify); + /** + * Retrieve library options from Amplify configuration. + * `libraryConfigHeaders` are from the Amplify configuration options, + * and will not be overwritten by other custom headers. These are *not* + * the same as `additionalHeaders`, which are custom headers that are + * either 1)included when configuring the API client or 2) passed along + * with individual requests. + */ + const { headers: libraryConfigHeaders } = resolveLibraryOptions(amplify); + return this.appSyncRealTime.subscribe( { query: print(query as DocumentNode), @@ -434,6 +444,7 @@ export class InternalGraphQLAPIClass { apiKey: config?.apiKey, additionalHeaders, authToken, + libraryConfigHeaders, }, customUserAgentDetails ); diff --git a/packages/api-graphql/src/types/index.ts b/packages/api-graphql/src/types/index.ts index ff4c1a98b95..8703a23ea04 100644 --- a/packages/api-graphql/src/types/index.ts +++ b/packages/api-graphql/src/types/index.ts @@ -175,7 +175,7 @@ export interface AWSAppSyncRealTimeProviderOptions { variables?: Record; apiKey?: string; region?: string; - graphql_headers?: () => {} | (() => Promise<{}>); + libraryConfigHeaders?: () => {} | (() => Promise<{}>); additionalHeaders?: CustomHeaders; } diff --git a/packages/api-rest/src/apis/common/publicApis.ts b/packages/api-rest/src/apis/common/publicApis.ts index 4c82663e2f7..1034f77b811 100644 --- a/packages/api-rest/src/apis/common/publicApis.ts +++ b/packages/api-rest/src/apis/common/publicApis.ts @@ -39,14 +39,14 @@ const publicHandler = ( apiPath, apiOptions?.queryParams ); - const libraryOptionsHeaders = + const libraryConfigHeaders = await amplify.libraryOptions?.API?.REST?.headers?.({ apiName, }); const { headers: invocationHeaders = {} } = apiOptions; const headers = { // custom headers from invocation options should precede library options - ...libraryOptionsHeaders, + ...libraryConfigHeaders, ...invocationHeaders, }; const signingServiceInfo = parseSigningInfo(url, { diff --git a/packages/api/src/internals/InternalAPI.ts b/packages/api/src/internals/InternalAPI.ts index d9d7aa56281..c8c7e6d8f50 100644 --- a/packages/api/src/internals/InternalAPI.ts +++ b/packages/api/src/internals/InternalAPI.ts @@ -62,7 +62,7 @@ export class InternalAPIClass { * Executes a GraphQL operation * * @param options - GraphQL Options - * @param [additionalHeaders] - headers to merge in after any `graphql_headers` set in the config + * @param [additionalHeaders] - headers to merge in after any `libraryConfigHeaders` set in the config * @returns An Observable if queryType is 'subscription', else a promise of the graphql result from the query. */ graphql( diff --git a/packages/core/src/singleton/API/types.ts b/packages/core/src/singleton/API/types.ts index 0a94301c5db..ca0d17b0f9c 100644 --- a/packages/core/src/singleton/API/types.ts +++ b/packages/core/src/singleton/API/types.ts @@ -6,10 +6,10 @@ import { AtLeastOne } from '../types'; export type LibraryAPIOptions = { GraphQL?: { // custom headers for given GraphQL service. Will be applied to all operations. - headers?: (options: { - query: string; + headers?: (options?: { + query?: string; variables?: Record; - }) => Promise; + }) => Promise; withCredentials?: boolean; }; REST?: { From 1c5010cfa02a646f88315464fa1ed8b8dc8cdc72 Mon Sep 17 00:00:00 2001 From: Venkata Ramyasri Kota <34170013+kvramyasri7@users.noreply.github.com> Date: Mon, 4 Dec 2023 12:30:27 -0800 Subject: [PATCH 15/15] chore: comment Integ_next datastore_owner_auth (#12666) --- .github/canary-config/canary-all.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/.github/canary-config/canary-all.yml b/.github/canary-config/canary-all.yml index 4efe7781471..f71c632c4bc 100644 --- a/.github/canary-config/canary-all.yml +++ b/.github/canary-config/canary-all.yml @@ -98,13 +98,14 @@ tests: sample_name: [websocket-disruption] spec: websocket-disruption browser: [chrome, firefox] - - test_name: integ_next_datastore_owner_auth - desc: 'next owner auth' - framework: next - category: datastore - sample_name: [owner-based-default] - spec: next-owner-based-default - browser: [chrome, firefox] + # can un comment when ever fixed + # - test_name: integ_next_datastore_owner_auth + # desc: 'next owner auth' + # framework: next + # category: datastore + # sample_name: [owner-based-default] + # spec: next-owner-based-default + # browser: [chrome, firefox] - test_name: integ_next_datastore_13_js desc: 'DataStore - Nextjs 13 build with SWC - JS app' framework: next