diff --git a/.eslintrc.js b/.eslintrc.js index 01ea33f2bd3..424e56324d5 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -35,13 +35,9 @@ module.exports = { 'setupTests.ts', 'jest.setup.*', 'jest.config.*', - 'packages/api/__tests__', 'packages/api-graphql/__tests__', 'packages/datastore/__tests__', 'packages/datastore-storage-adapter/__tests__', - 'packages/interactions/__tests__', - 'packages/predictions/__tests__', - 'packages/pubsub/__tests__', ], rules: { camelcase: [ diff --git a/packages/api/__tests__/API.test.ts b/packages/api/__tests__/API.test.ts index ab95bf9dcc9..16e10ac99b8 100644 --- a/packages/api/__tests__/API.test.ts +++ b/packages/api/__tests__/API.test.ts @@ -1,15 +1,8 @@ -import { ResourcesConfig } from 'aws-amplify'; import { InternalGraphQLAPIClass } from '@aws-amplify/api-graphql/internals'; -import { generateClient, CONNECTION_STATE_CHANGE } from '@aws-amplify/api'; import { AmplifyClassV6 } from '@aws-amplify/core'; -// import { runWithAmplifyServerContext } from 'aws-amplify/internals/adapter-core'; -const serverManagedFields = { - id: 'some-id', - owner: 'wirejobviously', - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), -}; +import { CONNECTION_STATE_CHANGE, generateClient } from '@aws-amplify/api'; +// import { runWithAmplifyServerContext } from 'aws-amplify/internals/adapter-core'; describe('API generateClient', () => { afterEach(() => { diff --git a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts index aaca3c0c1d0..81cb438e617 100644 --- a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts +++ b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts @@ -6,17 +6,21 @@ import { PostTextCommand, PostTextCommandOutput, } from '@aws-sdk/client-lex-runtime-service'; -import { lexProvider } from '../../src/lex-v1/AWSLexProvider'; import { fetchAuthSession } from '@aws-amplify/core'; +import { lexProvider } from '../../src/lex-v1/AWSLexProvider'; +import { InteractionsOnCompleteCallback } from '../../src/types/Interactions'; + jest.mock('@aws-amplify/core'); (global as any).Response = class Response { - arrayBuffer(blob: Blob) { + arrayBuffer() { return Promise.resolve(new ArrayBuffer(0)); } }; +type AWSLexProvider = typeof lexProvider; + // mock stream response const createBlob = () => { return new Blob(); @@ -47,7 +51,7 @@ const credentials = { const mockFetchAuthSession = fetchAuthSession as jest.Mock; -LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { +LexRuntimeServiceClient.prototype.send = jest.fn(command => { if (command instanceof PostTextCommand) { if (command.input.inputText === 'done') { const result = { @@ -58,18 +62,21 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { m2: 'done', }, }; + return Promise.resolve(result); } else if (command.input.inputText === 'error') { const result = { message: 'echo:' + command.input.inputText, dialogState: 'Failed', }; + return Promise.resolve(result); } else { const result = { message: 'echo:' + command.input.inputText, dialogState: 'ElicitSlot', }; + return Promise.resolve(result); } } else if (command instanceof PostContentCommand) { @@ -78,7 +85,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { 'audio/x-l16; sample-rate=16000; channel-count=1' ) { const bot = command.input.botName as string; - const [botName, status] = bot.split(':'); + const [_botName, status] = bot.split(':'); if (status === 'done') { // we add the status to the botName @@ -92,6 +99,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { }, audioStream: createBlob(), }; + return Promise.resolve(result); } else if (status === 'error') { const result = { @@ -99,6 +107,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'Failed', audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -106,6 +115,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'ElicitSlot', audioStream: createBlob(), }; + return Promise.resolve(result); } } else { @@ -119,6 +129,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { }, audioStream: createBlob(), }; + return Promise.resolve(result); } else if (command.input.inputStream === 'error') { const result = { @@ -126,6 +137,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'Failed', audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -133,6 +145,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'ElicitSlot', audioStream: createBlob(), }; + return Promise.resolve(result); } } @@ -146,7 +159,7 @@ afterEach(() => { describe('Interactions', () => { // send text and audio message to bot describe('send API', () => { - let provider; + let provider: AWSLexProvider; beforeEach(() => { mockFetchAuthSession.mockReturnValue(credentials); @@ -266,6 +279,7 @@ describe('Interactions', () => { provider.sendMessage(botConfig.BookTrip, { content: createBlob(), options: { + // @ts-expect-error for testing messageType mismatches content type messageType: 'text', }, }), @@ -274,6 +288,7 @@ describe('Interactions', () => { // obj voice in wrong format await expect( provider.sendMessage(botConfig.BookTrip, { + // @ts-expect-error for testing messageType mismatches content type content: 'Hi', options: { messageType: 'voice', @@ -285,8 +300,8 @@ describe('Interactions', () => { // attach 'onComplete' callback to bot describe('onComplete API', () => { - const callback = (err, confirmation) => {}; - let provider; + const callback = jest.fn(); + let provider: AWSLexProvider; beforeEach(() => { mockFetchAuthSession.mockReturnValue(credentials); @@ -298,9 +313,9 @@ describe('Interactions', () => { }); test('Configure onComplete callback for a configured bot successfully', () => { - expect(() => - provider.onComplete(botConfig.BookTrip, callback), - ).not.toThrow(); + expect(() => { + provider.onComplete(botConfig.BookTrip, callback); + }).not.toThrow(); expect.assertions(1); }); }); @@ -308,24 +323,22 @@ describe('Interactions', () => { // test if 'onComplete' callback is fired for different actions describe('reportBotStatus API', () => { jest.useFakeTimers(); - let provider; + let provider: AWSLexProvider; - let inProgressResp; - let completeSuccessResp; - let completeFailResp; + let inProgressResp: PostTextCommandOutput; + let completeSuccessResp: PostTextCommandOutput; + let completeFailResp: PostTextCommandOutput; - let inProgressCallback; - let completeSuccessCallback; - let completeFailCallback; + let inProgressCallback: InteractionsOnCompleteCallback; + let completeSuccessCallback: InteractionsOnCompleteCallback; + let completeFailCallback: InteractionsOnCompleteCallback; beforeEach(async () => { mockFetchAuthSession.mockReturnValue(credentials); provider = lexProvider; // mock callbacks - inProgressCallback = jest.fn((err, confirmation) => - fail(`callback shouldn't be called`), - ); + inProgressCallback = jest.fn(() => fail(`callback shouldn't be called`)); completeSuccessCallback = jest.fn((err, confirmation) => { expect(err).toEqual(undefined); @@ -339,9 +352,9 @@ describe('Interactions', () => { }); }); - completeFailCallback = jest.fn((err, confirmation) => - expect(err).toEqual(new Error('Bot conversation failed')), - ); + completeFailCallback = jest.fn(err => { + expect(err).toEqual(new Error('Bot conversation failed')); + }); // mock responses inProgressResp = (await provider.sendMessage( diff --git a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts b/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts index 29f3ac6cd99..72aa31eca4b 100644 --- a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -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'; @@ -27,7 +26,6 @@ describe('Interactions LexV1 API: onComplete', () => { }); it('invokes provider onComplete API', () => { - const message = uuid(); const mockCallback = jest.fn(); onComplete({ botName: v1BotConfig.name, callback: mockCallback }); expect(mockLexProvider).toHaveBeenCalledTimes(1); @@ -36,8 +34,8 @@ describe('Interactions LexV1 API: onComplete', () => { it('rejects when bot config does not exist', async () => { mockResolveBotConfig.mockReturnValue(undefined); - expect(() => - onComplete({ botName: v1BotConfig.name, callback: jest.fn }), - ).toThrow(InteractionsError); + expect(() => { + onComplete({ botName: v1BotConfig.name, callback: jest.fn }); + }).toThrow(InteractionsError); }); }); diff --git a/packages/interactions/__tests__/lex-v1/apis/send.test.ts b/packages/interactions/__tests__/lex-v1/apis/send.test.ts index 7e05d0538aa..f62daaa8b9d 100644 --- a/packages/interactions/__tests__/lex-v1/apis/send.test.ts +++ b/packages/interactions/__tests__/lex-v1/apis/send.test.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 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'; diff --git a/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts b/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts index 59c648f5d08..d8198e0ff2f 100644 --- a/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts +++ b/packages/interactions/__tests__/lex-v1/utils/resolveBotConfig.test.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; + import { generateRandomLexV1Config, generateRandomLexV2Config, diff --git a/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts b/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts index 486e04541a3..c3390bf09c6 100644 --- a/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts +++ b/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts @@ -2,7 +2,6 @@ // SPDX-License-Identifier: Apache-2.0 import { fetchAuthSession } from '@aws-amplify/core'; import { - IntentState, LexRuntimeV2Client, RecognizeTextCommand, RecognizeTextCommandOutput, @@ -11,12 +10,16 @@ import { import { gzip, strToU8 } from 'fflate'; import { encode } from 'base-64'; import { v4 as uuid } from 'uuid'; + import { lexProvider } from '../../src/lex-v2/AWSLexV2Provider'; +import { InteractionsOnCompleteCallback } from '../../src/types/Interactions'; + +type AWSLexV2Provider = typeof lexProvider; jest.mock('@aws-amplify/core'); (global as any).Response = class Response { - arrayBuffer(blob: Blob) { + arrayBuffer() { return Promise.resolve(new ArrayBuffer(0)); } }; @@ -49,12 +52,13 @@ const credentials = { const mockFetchAuthSession = fetchAuthSession as jest.Mock; const arrayBufferToBase64 = (buffer: Uint8Array) => { - var binary = ''; - var bytes = new Uint8Array(buffer); - var len = bytes.byteLength; - for (var i = 0; i < len; i++) { + let binary = ''; + const bytes = new Uint8Array(buffer); + const len = bytes.byteLength; + for (let i = 0; i < len; i++) { binary += String.fromCharCode(bytes[i]); } + return encode(binary); }; @@ -77,7 +81,7 @@ const gzipBase64Json = async (dataObject: object) => { // 4. arrayBuffer to base64 return arrayBufferToBase64(compressedData); } catch (error) { - return Promise.reject('unable to compress and encode ' + error); + return Promise.reject(new Error('unable to compress and encode ' + error)); } }; @@ -92,6 +96,7 @@ const handleRecognizeTextCommand = command => { }, messages: [{ content: 'echo:' + command.input.text }], }; + return Promise.resolve(result); } else if (command.input.text === 'error') { const result = { @@ -100,6 +105,7 @@ const handleRecognizeTextCommand = command => { }, messages: [{ content: 'echo:' + command.input.text }], }; + return Promise.resolve(result); } else { const result = { @@ -115,7 +121,7 @@ const handleRecognizeTextCommand = command => { const handleRecognizeUtteranceCommandAudio = async command => { const bot = command.input.botId as string; - const [botName, status] = bot.split(':'); + const [_botName, status] = bot.split(':'); if (status === 'done') { // we add the status to the botName @@ -132,6 +138,7 @@ const handleRecognizeUtteranceCommandAudio = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else if (status === 'error') { const result = { @@ -143,6 +150,7 @@ const handleRecognizeUtteranceCommandAudio = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -154,6 +162,7 @@ const handleRecognizeUtteranceCommandAudio = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } }; @@ -172,6 +181,7 @@ const handleRecognizeUtteranceCommandText = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else if (command.input.inputStream === 'error') { const result = { @@ -183,6 +193,7 @@ const handleRecognizeUtteranceCommandText = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -194,11 +205,12 @@ const handleRecognizeUtteranceCommandText = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } }; -LexRuntimeV2Client.prototype.send = jest.fn(async (command, callback) => { +LexRuntimeV2Client.prototype.send = jest.fn(async command => { let response; if (command instanceof RecognizeTextCommand) { response = handleRecognizeTextCommand(command); @@ -212,6 +224,7 @@ LexRuntimeV2Client.prototype.send = jest.fn(async (command, callback) => { response = await handleRecognizeUtteranceCommandText(command); } } + return response; }) as any; @@ -222,7 +235,7 @@ afterEach(() => { describe('Interactions', () => { // Test 'send' API describe('send API', () => { - let provider; + let provider: AWSLexV2Provider; beforeEach(() => { mockFetchAuthSession.mockReturnValue(credentials); @@ -353,6 +366,7 @@ describe('Interactions', () => { provider.sendMessage(botConfig.BookTrip, { content: createBlob(), options: { + // @ts-expect-error For testing mismatch types messageType: 'text', }, }), @@ -361,6 +375,7 @@ describe('Interactions', () => { // obj voice in wrong format await expect( provider.sendMessage(botConfig.BookTrip, { + // @ts-expect-error For testing mismatch types content: 'Hi', options: { messageType: 'voice', @@ -372,8 +387,8 @@ describe('Interactions', () => { // Test 'onComplete' API describe('onComplete API', () => { - const callback = (err, confirmation) => {}; - let provider; + const callback = jest.fn(); + let provider: AWSLexV2Provider; beforeEach(() => { mockFetchAuthSession.mockReturnValue(credentials); @@ -383,9 +398,9 @@ describe('Interactions', () => { afterEach(() => mockFetchAuthSession.mockReset()); test('Configure onComplete callback for a configured bot successfully', () => { - expect(() => - provider.onComplete(botConfig.BookTrip, callback), - ).not.toThrow(); + expect(() => { + provider.onComplete(botConfig.BookTrip, callback); + }).not.toThrow(); expect.assertions(1); }); }); @@ -393,7 +408,7 @@ describe('Interactions', () => { // Test 'reportBotStatus' API describe('reportBotStatus API', () => { jest.useFakeTimers(); - let provider = lexProvider; + const provider = lexProvider; // enum, action types callback function can handle const ACTION_TYPE = Object.freeze({ IN_PROGRESS: 'inProgress', @@ -401,17 +416,19 @@ describe('Interactions', () => { ERROR: 'error', }); - let mockCallbackProvider; - let mockResponseProvider; + let mockCallbackProvider: ( + actionType: (typeof ACTION_TYPE)[keyof typeof ACTION_TYPE], + ) => InteractionsOnCompleteCallback; + let mockResponseProvider: ( + actionType: (typeof ACTION_TYPE)[keyof typeof ACTION_TYPE], + ) => Parameters[0]; beforeEach(async () => { mockFetchAuthSession.mockReturnValue(credentials); mockCallbackProvider = actionType => { switch (actionType) { case ACTION_TYPE.IN_PROGRESS: - return jest.fn((err, confirmation) => - fail(`callback shouldn't be called`), - ); + return jest.fn(() => fail(`callback shouldn't be called`)); case ACTION_TYPE.COMPLETE: return jest.fn((err, confirmation) => { @@ -427,9 +444,9 @@ describe('Interactions', () => { }); }); case ACTION_TYPE.ERROR: - return jest.fn((err, confirmation) => - expect(err).toEqual(new Error('Bot conversation failed')), - ); + return jest.fn(err => { + expect(err).toEqual(new Error('Bot conversation failed')); + }); } }; @@ -448,7 +465,9 @@ describe('Interactions', () => { 'error', )) as RecognizeTextCommandOutput; - mockResponseProvider = actionType => { + mockResponseProvider = ( + actionType: (typeof ACTION_TYPE)[keyof typeof ACTION_TYPE], + ) => { switch (actionType) { case ACTION_TYPE.IN_PROGRESS: return inProgressResp; @@ -467,7 +486,7 @@ describe('Interactions', () => { describe('onComplete callback from `Interactions.onComplete`', () => { test(`In progress, callback shouldn't be called`, async () => { // callback is only called once conversation is completed - let config = { ...botConfig.BookTrip, name: uuid() }; + const config = { ...botConfig.BookTrip, name: uuid() }; const inProgressCallback = mockCallbackProvider( ACTION_TYPE.IN_PROGRESS, ); @@ -484,7 +503,7 @@ describe('Interactions', () => { }); test(`task complete; callback with success resp`, async () => { - let config = { ...botConfig.BookTrip, name: uuid() }; + const config = { ...botConfig.BookTrip, name: uuid() }; const completeSuccessCallback = mockCallbackProvider( ACTION_TYPE.COMPLETE, ); @@ -502,7 +521,7 @@ describe('Interactions', () => { }); test(`task complete; callback with error resp`, async () => { - let config = { ...botConfig.BookTrip, name: uuid() }; + const config = { ...botConfig.BookTrip, name: uuid() }; const completeFailCallback = mockCallbackProvider(ACTION_TYPE.ERROR); provider.onComplete(config, completeFailCallback); diff --git a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts b/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts index dc0b77186d6..a4fe5b703df 100644 --- a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts @@ -1,7 +1,6 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -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'; @@ -27,7 +26,6 @@ describe('Interactions LexV2 API: onComplete', () => { }); it('invokes provider onComplete API', () => { - const message = uuid(); const mockCallback = jest.fn(); onComplete({ botName: v2BotConfig.name, callback: mockCallback }); expect(mockLexProvider).toHaveBeenCalledTimes(1); @@ -36,8 +34,8 @@ describe('Interactions LexV2 API: onComplete', () => { it('rejects when bot config does not exist', async () => { mockResolveBotConfig.mockReturnValue(undefined); - expect(() => - onComplete({ botName: v2BotConfig.name, callback: jest.fn }), - ).toThrow(InteractionsError); + expect(() => { + onComplete({ botName: v2BotConfig.name, callback: jest.fn }); + }).toThrow(InteractionsError); }); }); diff --git a/packages/interactions/__tests__/lex-v2/apis/send.test.ts b/packages/interactions/__tests__/lex-v2/apis/send.test.ts index b1984822db0..56405d3ff07 100644 --- a/packages/interactions/__tests__/lex-v2/apis/send.test.ts +++ b/packages/interactions/__tests__/lex-v2/apis/send.test.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 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'; diff --git a/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts b/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts index ff36b7f6c85..fdaa1097ed6 100644 --- a/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts +++ b/packages/interactions/__tests__/lex-v2/utils/resolveBotConfig.test.ts @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 import { Amplify } from '@aws-amplify/core'; + import { generateRandomLexV1Config, generateRandomLexV2Config, diff --git a/packages/interactions/__tests__/testUtils/randomConfigGeneration.ts b/packages/interactions/__tests__/testUtils/randomConfigGeneration.ts index 5f6fd6f46a8..a0398688734 100644 --- a/packages/interactions/__tests__/testUtils/randomConfigGeneration.ts +++ b/packages/interactions/__tests__/testUtils/randomConfigGeneration.ts @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 import { v4 as uuid } from 'uuid'; + import { AWSLexProviderOption } from '../../src/lex-v1/types'; import { AWSLexV2ProviderOption } from '../../src/lex-v2/types'; diff --git a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts index 5678c1b079c..6c6094279b1 100644 --- a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts @@ -9,6 +9,7 @@ import { TranslateClient, TranslateTextCommand, } from '@aws-sdk/client-translate'; + import { PredictionsValidationErrorCode, validationErrorMap, @@ -46,40 +47,42 @@ const resetTranslateMock = () => { const resetPollyMock = () => { PollyClient.prototype.send = jest.fn(command => { if (command instanceof SynthesizeSpeechCommand) { - const result = { + const mockResult = { AudioStream: { buffer: 'dummyStream', }, }; - return Promise.resolve(result); + + return Promise.resolve(mockResult); } }) as any; }; -(global as any).Response = jest.fn(stream => { +(global as any).Response = jest.fn(() => { const response = { arrayBuffer: () => { return 'dummyStream'; }, }; + return response; }); -(global as any).WebSocket = jest.fn(url => { - let onCloseCallback; - let onErrorCallback; - let onMsgCallback; - let connection = { - set onmessage(callback) { +(global as any).WebSocket = jest.fn(() => { + let onCloseCallback: () => void; + let onMsgCallback: (arg0: string) => void; + const connection = { + /* eslint accessor-pairs: 0 */ + set onmessage(callback: (arg0: string) => void) { onMsgCallback = callback; }, - set onerror(callback) { - onErrorCallback = callback; + set onerror(callback: any) { + // no-op }, - set onclose(callback) { + set onclose(callback: () => void) { onCloseCallback = callback; }, - set onopen(callback) { + set onopen(callback: () => void) { callback(); }, send: jest.fn(() => { @@ -146,7 +149,7 @@ const validTextToSpeechInput: TextToSpeechInput = { const validSpeechToTextInput: SpeechToTextInput = { transcription: { source: { - bytes: new Buffer([0, 1, 2]), + bytes: Buffer.from([0, 1, 2]), }, }, }; @@ -205,11 +208,11 @@ describe('Predictions convert provider test', () => { }); const predictionsProvider = new AmazonAIConvertPredictionsProvider(); jest.spyOn(TranslateClient.prototype, 'send').mockImplementation(() => { - return Promise.reject('error'); + return Promise.reject(new Error('error')); }); expect( predictionsProvider.convert(validTranslateTextInput), - ).rejects.toMatch('error'); + ).rejects.toThrow('error'); }); }); @@ -229,7 +232,7 @@ describe('Predictions convert provider test', () => { }); const predictionsProvider = new AmazonAIConvertPredictionsProvider(); window.URL.createObjectURL = jest.fn(); - jest.spyOn(URL, 'createObjectURL').mockImplementation(blob => { + jest.spyOn(URL, 'createObjectURL').mockImplementation(() => { return 'dummyURL'; }); expect( @@ -270,11 +273,11 @@ describe('Predictions convert provider test', () => { }); const predictionsProvider = new AmazonAIConvertPredictionsProvider(); jest.spyOn(PollyClient.prototype, 'send').mockImplementation(() => { - return Promise.reject('error'); + return Promise.reject(new Error('error')); }); expect( predictionsProvider.convert(validTextToSpeechInput), - ).rejects.toMatch('error'); + ).rejects.toThrow('error'); }); }); @@ -426,7 +429,7 @@ describe('Predictions convert provider test', () => { }); const predictionsProvider = new AmazonAIConvertPredictionsProvider(); window.URL.createObjectURL = jest.fn(); - jest.spyOn(URL, 'createObjectURL').mockImplementation(blob => { + jest.spyOn(URL, 'createObjectURL').mockImplementation(() => { return 'dummyURL'; }); diff --git a/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts index 042ca5c7114..7db9f2a3073 100644 --- a/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts @@ -25,6 +25,7 @@ import { DetectDocumentTextCommand, TextractClient, } from '@aws-sdk/client-textract'; + import { PredictionsValidationErrorCode, validationErrorMap, @@ -72,6 +73,7 @@ RekognitionClient.prototype.send = jest.fn(command => { ], $metadata: {}, }; + return Promise.resolve(detectlabelsResponse); } else if (command instanceof DetectModerationLabelsCommand) { const detectModerationLabelsResponse: DetectModerationLabelsCommandOutput = @@ -79,12 +81,14 @@ RekognitionClient.prototype.send = jest.fn(command => { ModerationLabels: [{ Name: 'test', Confidence: 0.0 }], $metadata: {}, }; + return Promise.resolve(detectModerationLabelsResponse); } else if (command instanceof DetectFacesCommand) { const detectFacesResponse: DetectFacesCommandOutput = { FaceDetails: [{ AgeRange: { High: 0, Low: 0 } }], $metadata: {}, }; + return Promise.resolve(detectFacesResponse); } else if (command instanceof SearchFacesByImageCommand) { const searchFacesByImageResponse: SearchFacesByImageCommandOutput = { @@ -99,6 +103,7 @@ RekognitionClient.prototype.send = jest.fn(command => { ], $metadata: {}, }; + return Promise.resolve(searchFacesByImageResponse); } else if (command instanceof RecognizeCelebritiesCommand) { const recognizeCelebritiesResponse: RecognizeCelebritiesCommandOutput = { @@ -123,6 +128,7 @@ RekognitionClient.prototype.send = jest.fn(command => { ], $metadata: {}, }; + return Promise.resolve(recognizeCelebritiesResponse); } else if (command instanceof DetectTextCommand) { const plainBlocks: DetectTextCommandOutput = { @@ -133,6 +139,7 @@ RekognitionClient.prototype.send = jest.fn(command => { ], $metadata: {}, }; + return Promise.resolve(plainBlocks); } }) as any; @@ -281,25 +288,26 @@ mockGetConfig.mockReturnValue({ identify: options, }, }); -mockGetUrl.mockImplementation(({ key, options }) => { - console.log(key, options); - const level = options?.accessLevel || 'guest'; +mockGetUrl.mockImplementation(({ key, options: optionsParam }) => { + console.log(key, optionsParam); + const level = optionsParam?.accessLevel || 'guest'; let url: URL; if (level === 'guest') { url = new URL( `https://bucket-name.s3.us-west-2.amazonaws.com/public/${key}?X-Amz-Algorithm=AWS4-HMAC-SHA256`, ); } else { - const identityId = options?.targetIdentityId || 'identityId'; + const identityIdFromParam = optionsParam?.targetIdentityId || 'identityId'; url = new URL( - `https://bucket-name.s3.us-west-2.amazonaws.com/${level}/${identityId}/key.png?X-Amz-Algorithm=AWS4-HMAC-SHA256`, + `https://bucket-name.s3.us-west-2.amazonaws.com/${level}/${identityIdFromParam}/key.png?X-Amz-Algorithm=AWS4-HMAC-SHA256`, ); } + return Promise.resolve({ url }); }); describe('Predictions identify provider test', () => { - let predictionsProvider; + let predictionsProvider: AmazonAIIdentifyPredictionsProvider; beforeAll(() => { predictionsProvider = new AmazonAIIdentifyPredictionsProvider(); @@ -338,21 +346,22 @@ describe('Predictions identify provider test', () => { jest .spyOn(RekognitionClient.prototype, 'send') .mockImplementationOnce(() => { - const plainBlocks: DetectTextCommandOutput = { + const mockPlainBlocks: DetectTextCommandOutput = { TextDetections: [ { Type: 'LINE', Id: 1, DetectedText: 'Hello world' }, ], $metadata: {}, }; for (let i = 0; i < 50; ++i) { - plainBlocks.TextDetections!.push({ + mockPlainBlocks.TextDetections!.push({ Type: 'WORD', Id: i + 2, ParentId: 1, DetectedText: '', }); } - return Promise.resolve(plainBlocks); + + return Promise.resolve(mockPlainBlocks); }); // confirm that textract service has been called const spy = jest.spyOn(TextractClient.prototype, 'send'); @@ -623,6 +632,7 @@ describe('Predictions identify provider test', () => { expect( (command as DetectLabelsCommand).input.Image?.S3Object?.Name, ).toMatch('public/key'); + return Promise.resolve(detectlabelsResponse); }); predictionsProvider.identify(detectLabelInput); @@ -638,6 +648,7 @@ describe('Predictions identify provider test', () => { expect( (command as DetectLabelsCommand).input.Image?.S3Object?.Name, ).toMatch('private/identityId/key'); + return {}; }); await predictionsProvider.identify(detectLabelInput); @@ -660,6 +671,7 @@ describe('Predictions identify provider test', () => { expect( (command as DetectLabelsCommand).input.Image?.S3Object?.Name, ).toMatch('protected/identityId/key'); + return Promise.resolve(detectlabelsResponse); }); predictionsProvider.identify(detectLabelInput); @@ -675,6 +687,7 @@ describe('Predictions identify provider test', () => { expect((command as DetectLabelsCommand).input.Image?.Bytes).toMatch( 'bytes', ); + return Promise.resolve(detectlabelsResponse); }); predictionsProvider.identify(detectLabelInput); @@ -691,6 +704,7 @@ describe('Predictions identify provider test', () => { expect( (command as DetectLabelsCommand).input.Image?.Bytes, ).toStrictEqual(fileInput); + return {}; }); await predictionsProvider.identify(detectLabelInput); @@ -708,6 +722,7 @@ describe('Predictions identify provider test', () => { expect( (command as DetectLabelsCommand).input.Image?.Bytes, ).toMatchObject(fileInput); + return {}; }); await predictionsProvider.identify(detectLabelInput); @@ -717,6 +732,7 @@ describe('Predictions identify provider test', () => { const detectLabelInput = { labels: { source: null, type: 'LABELS' }, }; + // @ts-expect-error for testing expect(predictionsProvider.identify(detectLabelInput)).rejects.toThrow( 'not configured correctly', ); @@ -735,7 +751,7 @@ describe('Predictions identify provider test', () => { await predictionsProvider.identify(detectLabelInput); expect( - predictionsProvider.rekognitionClient.config.customUserAgent, + (predictionsProvider as any).rekognitionClient?.config.customUserAgent, ).toEqual( getAmplifyUserAgentObject({ category: Category.Predictions, @@ -758,7 +774,7 @@ describe('Predictions identify provider test', () => { await predictionsProvider.identify(detectFacesInput); expect( - predictionsProvider.rekognitionClient.config.customUserAgent, + (predictionsProvider as any).rekognitionClient?.config.customUserAgent, ).toEqual( getAmplifyUserAgentObject({ category: Category.Predictions, @@ -776,7 +792,7 @@ describe('Predictions identify provider test', () => { await predictionsProvider.identify(detectTextInput); expect( - predictionsProvider.rekognitionClient.config.customUserAgent, + (predictionsProvider as any).rekognitionClient.config.customUserAgent, ).toEqual( getAmplifyUserAgentObject({ category: Category.Predictions, @@ -784,7 +800,9 @@ describe('Predictions identify provider test', () => { }), ); - expect(predictionsProvider.textractClient.config.customUserAgent).toEqual( + expect( + (predictionsProvider as any).textractClient.config.customUserAgent, + ).toEqual( getAmplifyUserAgentObject({ category: Category.Predictions, action: PredictionsAction.Identify, diff --git a/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts index 60bc46c4c2e..09a4f37e650 100644 --- a/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts @@ -13,6 +13,9 @@ import { DetectSyntaxCommand, } from '@aws-sdk/client-comprehend'; +// Mocks before importing provider to avoid race condition with provider instantiation +import { AmazonAIInterpretPredictionsProvider } from '../../src/providers'; + const mockFetchAuthSession = fetchAuthSession as jest.Mock; const mockGetConfig = Amplify.getConfig as jest.Mock; @@ -26,7 +29,7 @@ jest.mock('@aws-amplify/core', () => ({ })), })); -ComprehendClient.prototype.send = jest.fn((command, callback) => { +ComprehendClient.prototype.send = jest.fn(command => { if (command instanceof DetectEntitiesCommand) { const resultDetectEntities = { Entities: [ @@ -39,11 +42,13 @@ ComprehendClient.prototype.send = jest.fn((command, callback) => { }, ], }; + return Promise.resolve(resultDetectEntities); } else if (command instanceof DetectDominantLanguageCommand) { const resultDominantLanguage = { Languages: [{ LanguageCode: 'en-US' }], }; + return Promise.resolve(resultDominantLanguage); } else if (command instanceof DetectSentimentCommand) { const resultDetectSentiment = { @@ -55,6 +60,7 @@ ComprehendClient.prototype.send = jest.fn((command, callback) => { Positive: 0.1282072812318802, }, }; + return Promise.resolve(resultDetectSentiment); } else if (command instanceof DetectSyntaxCommand) { const resultSyntax = { @@ -166,6 +172,7 @@ ComprehendClient.prototype.send = jest.fn((command, callback) => { }, ], }; + return Promise.resolve(resultSyntax); } else if (command instanceof DetectKeyPhrasesCommand) { const resultKeyPhrases = { @@ -190,6 +197,7 @@ ComprehendClient.prototype.send = jest.fn((command, callback) => { }, ], }; + return Promise.resolve(resultKeyPhrases); } }) as any; @@ -205,9 +213,6 @@ const happyConfig = { }, }; -// Mocks before importing provider to avoid race condition with provider instantiation -import { AmazonAIInterpretPredictionsProvider } from '../../src/providers'; - const credentials = { accessKeyId: 'accessKeyId', sessionToken: 'sessionToken', diff --git a/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts b/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts index d90c252adb5..14014dc8f91 100644 --- a/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts +++ b/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts @@ -1,6 +1,15 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import { Observable, Observer, SubscriptionLike as Subscription } from 'rxjs'; +import { Reachability } from '@aws-amplify/core/internals/utils'; + +import { + CONNECTION_CHANGE, + ConnectionStateMonitor, +} from '../src/utils/ConnectionStateMonitor'; +import { ConnectionState as CS } from '../src'; + jest.mock('@aws-amplify/core', () => ({ __esModule: true, ...jest.requireActual('@aws-amplify/core'), @@ -12,14 +21,6 @@ jest.mock('@aws-amplify/core', () => ({ }, })); -import { Observable, Observer, SubscriptionLike as Subscription } from 'rxjs'; -import { Reachability } from '@aws-amplify/core/internals/utils'; -import { - ConnectionStateMonitor, - CONNECTION_CHANGE, -} from '../src/utils/ConnectionStateMonitor'; -import { ConnectionState as CS } from '../src'; - describe('ConnectionStateMonitor', () => { let monitor: ConnectionStateMonitor; let observedStates: CS[]; @@ -27,7 +28,7 @@ describe('ConnectionStateMonitor', () => { let reachabilityObserver: Observer<{ online: boolean }>; beforeEach(() => { - const spyon = jest + jest .spyOn(Reachability.prototype, 'networkMonitor') .mockImplementationOnce(() => { return new Observable(observer => { diff --git a/packages/pubsub/__tests__/PubSub.test.ts b/packages/pubsub/__tests__/PubSub.test.ts index b4b1885b6e8..043d5a57b37 100644 --- a/packages/pubsub/__tests__/PubSub.test.ts +++ b/packages/pubsub/__tests__/PubSub.test.ts @@ -1,3 +1,13 @@ +import { Reachability } from '@aws-amplify/core/internals/utils'; +import { Observable, Observer } from 'rxjs'; + +import * as Paho from '../src/vendor/paho-mqtt'; +import { ConnectionState, PubSub as IotPubSub, mqttTopicMatch } from '../src'; +import { PubSub as MqttPubSub } from '../src/clients/mqtt'; +import * as constants from '../src/Providers/constants'; + +import { HubConnectionListener } from './helpers'; + jest.mock('@aws-amplify/core', () => ({ __esModule: true, ...jest.requireActual('@aws-amplify/core'), @@ -20,37 +30,29 @@ jest.mock('@aws-amplify/core', () => ({ }, })); -import { Reachability } from '@aws-amplify/core/internals/utils'; -import * as Paho from '../src/vendor/paho-mqtt'; -import { ConnectionState, PubSub as IotPubSub, mqttTopicMatch } from '../src'; -import { PubSub as MqttPubSub } from '../src/clients/mqtt'; -import { HubConnectionListener } from './helpers'; -import { Observable, Observer } from 'rxjs'; -import * as constants from '../src/Providers/constants'; - -const pahoClientMockCache = {}; +const pahoClientMockCache: Record = {}; const mockConnect = jest.fn(options => { options.onSuccess(); }); -const pahoClientMock = jest.fn().mockImplementation((host, clientId) => { +const pahoClientMock = jest.fn().mockImplementation((_host, clientId) => { if (pahoClientMockCache[clientId]) { return pahoClientMockCache[clientId]; } - var client = {} as any; + const client = {} as any; client.connect = mockConnect; client.send = jest.fn((topic, message) => { client.onMessageArrived({ destinationName: topic, payloadString: message }); }); - client.subscribe = jest.fn((topics, options) => {}); - client.unsubscribe = jest.fn(() => {}); - client.onMessageArrived = jest.fn(() => {}); + client.subscribe = jest.fn(); + client.unsubscribe = jest.fn(); + client.onMessageArrived = jest.fn(); client.isConnected = jest.fn(() => true); - client.disconnect = jest.fn(() => {}); + client.disconnect = jest.fn(); pahoClientMockCache[clientId] = client; @@ -63,8 +65,7 @@ jest.mock('../src/vendor/paho-mqtt', () => ({ Client: {}, })); -// @ts-ignore -Paho.Client = pahoClientMock; +(Paho as any).Client = pahoClientMock; const testPubSubAsync = ( pubsub, @@ -73,23 +74,26 @@ const testPubSubAsync = ( options?, hubConnectionListener?, ) => + // eslint-disable-next-line no-async-promise-executor new Promise(async (resolve, reject) => { - if (hubConnectionListener === undefined) { - hubConnectionListener = new HubConnectionListener('pubsub'); - } + const resolvedHubConnectionListener = + hubConnectionListener ?? new HubConnectionListener('pubsub'); + const obs = pubsub.subscribe({ topics: topic, options }).subscribe({ next: data => { expect(data).toEqual(message); obs.unsubscribe(); resolve(Promise.resolve()); }, - close: () => console.log('close'), + close: () => { + console.log('close'); + }, error: reject, }); - await hubConnectionListener.waitUntilConnectionStateIn([ + await resolvedHubConnectionListener.waitUntilConnectionStateIn([ ConnectionState.Connected, ]); - pubsub.publish({ topics: topic, message: message, options }); + pubsub.publish({ topics: topic, message, options }); }); beforeEach(() => { @@ -111,7 +115,9 @@ describe('PubSub', () => { describe('constructor test', () => { test('happy case', () => { - const pubsub = new IotPubSub(); + expect(() => { + const _ = new IotPubSub(); + }).not.toThrow(); }); }); @@ -145,7 +151,7 @@ describe('PubSub', () => { test('subscribe and publish to the same topic using AWSIoTProvider', async () => { expect.assertions(1); - let hubConnectionListener = new HubConnectionListener('pubsub'); + const hubConnectionListener = new HubConnectionListener('pubsub'); const config = { PubSub: { @@ -163,8 +169,12 @@ describe('PubSub', () => { next: data => { expect(data).toMatchObject(expectedData); }, - complete: () => console.log('done'), - error: error => console.log('error', error), + complete: () => { + console.log('done'); + }, + error: error => { + console.log('error', error); + }, }); await hubConnectionListener.waitUntilConnectionStateIn([ @@ -231,7 +241,7 @@ describe('PubSub', () => { }); test('trigger reconnection when disconnected', async () => { - let hubConnectionListener = new HubConnectionListener('pubsub'); + const hubConnectionListener = new HubConnectionListener('pubsub'); const pubsub = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', @@ -293,11 +303,10 @@ describe('PubSub', () => { hubConnectionListener = new HubConnectionListener('pubsub'); // Setup a mock of the reachability monitor where the initial value is online. - const spyon = jest + jest .spyOn(Reachability.prototype, 'networkMonitor') .mockImplementationOnce( () => - // @ts-ignore new Observable(observer => { reachabilityObserver = observer; }), @@ -305,7 +314,6 @@ describe('PubSub', () => { // Twice because we subscribe to get the initial state then again to monitor reachability .mockImplementationOnce( () => - // @ts-ignore new Observable(observer => { reachabilityObserver = observer; }), @@ -322,7 +330,7 @@ describe('PubSub', () => { const sub = pubsub .subscribe({ topics: 'topic', options: { clientId: '123' } }) .subscribe({ - error: () => {}, + error: jest.fn(), }); await hubConnectionListener.waitUntilConnectionStateIn([ @@ -348,10 +356,10 @@ describe('PubSub', () => { endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); - const sub = pubsub + pubsub .subscribe({ topics: 'topic', options: { clientId: '123' } }) .subscribe({ - error: () => {}, + error: jest.fn(), }); await hubConnectionListener.waitUntilConnectionStateIn([ @@ -383,10 +391,10 @@ describe('PubSub', () => { endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); - const sub = pubsub + pubsub .subscribe({ topics: 'topic', options: { clientId: '123' } }) .subscribe({ - error: () => {}, + error: jest.fn(), }); await hubConnectionListener.waitUntilConnectionStateIn([ @@ -426,7 +434,7 @@ describe('PubSub', () => { provider: 'MqttOverWSProvider', }); - expect(pubsub['isSSLEnabled']).toBe(false); + expect((pubsub as any).isSSLEnabled).toBe(false); expect(mockConnect).toHaveBeenCalledWith({ useSSL: false, mqttVersion: 3, @@ -448,7 +456,7 @@ describe('PubSub', () => { endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); - let hubConnectionListener = new HubConnectionListener('pubsub'); + const hubConnectionListener = new HubConnectionListener('pubsub'); await testPubSubAsync( iotClient, 'topicA', @@ -476,13 +484,13 @@ describe('PubSub', () => { endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); - const mqttClient = new MqttPubSubTest({ + const _ = new MqttPubSubTest({ region: 'region', endpoint: 'wss://iot.mymockendpoint.org:443/notrealmqtt', }); jest.spyOn(iotClient, 'publish').mockImplementationOnce(() => { - return Promise.reject('Failed to publish'); + return Promise.reject(new Error('Failed to publish')); }); expect( @@ -490,7 +498,7 @@ describe('PubSub', () => { topics: 'topicA', message: { msg: 'my message AWSIoTProvider' }, }), - ).rejects.toMatch('Failed to publish'); + ).rejects.toThrow('Failed to publish'); }); test('On unsubscribe when is the last observer it should disconnect the websocket', async () => { @@ -507,8 +515,12 @@ describe('PubSub', () => { next: _data => { console.log({ _data }); }, - complete: () => console.log('done'), - error: error => console.log('error', error), + complete: () => { + console.log('done'); + }, + error: error => { + console.log('error', error); + }, }); await hubConnectionListener.waitUntilConnectionStateIn([ @@ -536,15 +548,17 @@ describe('PubSub', () => { const spyDisconnect = jest.spyOn(pubsub, 'disconnect'); - const subscription1 = pubsub - .subscribe({ topics: ['topic1', 'topic2'] }) - .subscribe({ - next: _data => { - console.log({ _data }); - }, - complete: () => console.log('done'), - error: error => console.log('error', error), - }); + pubsub.subscribe({ topics: ['topic1', 'topic2'] }).subscribe({ + next: _data => { + console.log({ _data }); + }, + complete: () => { + console.log('done'); + }, + error: error => { + console.log('error', error); + }, + }); const subscription2 = pubsub .subscribe({ topics: ['topic3', 'topic4'] }) @@ -552,14 +566,18 @@ describe('PubSub', () => { next: _data => { console.log({ _data }); }, - complete: () => console.log('done'), - error: error => console.log('error', error), + complete: () => { + console.log('done'); + }, + error: error => { + console.log('error', error); + }, }); // TODO: we should now when the connection is established to wait for that first await (() => { - return new Promise(res => { - setTimeout(res, 100); + return new Promise((resolve, _reject) => { + setTimeout(resolve, 100); }); })(); diff --git a/packages/pubsub/__tests__/helpers.ts b/packages/pubsub/__tests__/helpers.ts index 5fb25cea201..51dcd4381b1 100644 --- a/packages/pubsub/__tests__/helpers.ts +++ b/packages/pubsub/__tests__/helpers.ts @@ -1,8 +1,9 @@ import { Hub } from '@aws-amplify/core'; -import { Observable } from 'rxjs'; -import { ConnectionState as CS, CONNECTION_STATE_CHANGE } from '../src'; +import { Observable, Observer as RxObserver } from 'rxjs'; + +import { CONNECTION_STATE_CHANGE, ConnectionState as CS } from '../src'; import * as constants from '../src/Providers/constants'; -import { Observer as RxObserver } from 'rxjs'; + export function delay(timeout) { return new Promise(resolve => { setTimeout(() => { @@ -33,7 +34,7 @@ export class HubConnectionListener { } /** - * @returns {Observable} - The observable that emits all ConnectionState updates (past and future) + * @returns `Observable` - The observable that emits all ConnectionState updates (past and future) */ allConnectionStateObserver() { return new Observable(observer => { @@ -45,7 +46,7 @@ export class HubConnectionListener { } /** - * @returns {Observable} - The observable that emits ConnectionState updates (past and future) + * @returns `Observable` - The observable that emits ConnectionState updates (past and future) */ connectionStateObserver() { return new Observable(observer => { @@ -64,21 +65,21 @@ export class HubConnectionListener { } async waitForConnectionState(connectionStates: CS[]) { - return new Promise((res, rej) => { + return new Promise((resolve, _reject) => { this.connectionStateObserver().subscribe(value => { if (connectionStates.includes(String(value) as CS)) { - res(undefined); + resolve(undefined); } }); }); } async waitUntilConnectionStateIn(connectionStates: CS[]) { - return new Promise((res, rej) => { + return new Promise((resolve, _reject) => { if (connectionStates.includes(this.currentConnectionState)) { - res(undefined); + resolve(undefined); } - res(this.waitForConnectionState(connectionStates)); + resolve(this.waitForConnectionState(connectionStates)); }); } } @@ -97,12 +98,12 @@ export class FakeWebSocketInterface { } resetWebsocket() { - this.readyForUse = new Promise((res, rej) => { - this.readyResolve = res; + this.readyForUse = new Promise((resolve, _reject) => { + this.readyResolve = resolve; }); let closeResolver: (value: PromiseLike) => void; - this.hasClosed = new Promise((res, rej) => { - closeResolver = res; + this.hasClosed = new Promise((resolve, _reject) => { + closeResolver = resolve; }); this.webSocket = new FakeWebSocket(() => closeResolver); } @@ -182,7 +183,10 @@ export class FakeWebSocketInterface { * @returns A websocket */ newWebSocket() { - setTimeout(() => this.readyResolve(Promise.resolve()), 10); + setTimeout(() => { + this.readyResolve(Promise.resolve()); + }, 10); + return this.webSocket; } @@ -194,7 +198,7 @@ export class FakeWebSocketInterface { new MessageEvent(constants.MESSAGE_TYPES.GQL_CONNECTION_ACK, { data: JSON.stringify({ type: constants.MESSAGE_TYPES.GQL_CONNECTION_ACK, - payload: payload, + payload, }), }), ); @@ -208,7 +212,7 @@ export class FakeWebSocketInterface { new MessageEvent(constants.MESSAGE_TYPES.GQL_CONNECTION_KEEP_ALIVE, { data: JSON.stringify({ type: constants.MESSAGE_TYPES.GQL_CONNECTION_KEEP_ALIVE, - payload: payload, + payload, }), }), ); @@ -219,7 +223,7 @@ export class FakeWebSocketInterface { new MessageEvent(constants.MESSAGE_TYPES.GQL_START_ACK, { data: JSON.stringify({ type: constants.MESSAGE_TYPES.GQL_START_ACK, - payload: payload, + payload, id: this.webSocket.subscriptionId, }), }), @@ -229,7 +233,7 @@ export class FakeWebSocketInterface { /** * Send a data message */ - async sendDataMessage(data: {}) { + async sendDataMessage(data: object) { await this.sendMessage( new MessageEvent('data', { data: JSON.stringify({ @@ -253,7 +257,7 @@ export class FakeWebSocketInterface { /** * Run a command and resolve to allow internal behavior to execute */ - async runAndResolve(fn) { + async runAndResolve(fn: () => Promise | void) { await fn(); await Promise.resolve(); } @@ -262,10 +266,10 @@ export class FakeWebSocketInterface { * DELETE THIS? */ async observesConnectionState(connectionState: CS) { - return new Promise((res, rej) => { + return new Promise((resolve, _reject) => { this.allConnectionStateObserver().subscribe(value => { if (value === connectionState) { - res(undefined); + resolve(undefined); } }); }); @@ -302,49 +306,53 @@ class FakeWebSocket implements WebSocket { protocol!: string; readyState!: number; url!: string; - close(code?: number, reason?: string): void { + close(): void { const closeResolver = this.closeResolverFcn(); if (closeResolver) closeResolver(Promise.resolve(undefined)); } + send(data: string | ArrayBufferLike | Blob | ArrayBufferView): void { const parsedInput = JSON.parse(String(data)); this.subscriptionId = parsedInput.id; } - CONNECTING: 0 = 0; - OPEN: 1 = 1; - CLOSING: 2 = 2; - CLOSED: 3 = 3; + + CONNECTING: 0 = 0 as const; + OPEN: 1 = 1 as const; + CLOSING: 2 = 2 as const; + CLOSED: 3 = 3 as const; addEventListener( type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | AddEventListenerOptions, ): void; + addEventListener( type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions, ): void; - addEventListener(type: unknown, listener: unknown, options?: unknown): void { + + addEventListener(): void { throw new Error('Method not implemented addEventListener.'); } + removeEventListener( type: K, listener: (this: WebSocket, ev: WebSocketEventMap[K]) => any, options?: boolean | EventListenerOptions, ): void; + removeEventListener( type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions, ): void; - removeEventListener( - type: unknown, - listener: unknown, - options?: unknown, - ): void { + + removeEventListener(): void { throw new Error('Method not implemented removeEventListener.'); } - dispatchEvent(event: Event): boolean { + + dispatchEvent(): boolean { throw new Error('Method not implemented dispatchEvent.'); } @@ -358,7 +366,7 @@ export async function replaceConstant( replacementValue: any, testFn: () => Promise, ) { - const initialValue = constants[name]; + const initialValue = (constants as any)[name]; Object.defineProperty(constants, name, { value: replacementValue, });