From 2c4b4920a4f925000cc9b52a97175bca5a875a06 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 13:18:28 -0700 Subject: [PATCH 1/9] =?UTF-8?q?chore:=20enable=20linting=20on=20tests=20fo?= =?UTF-8?q?r=20more=20packages:=20=E2=A4=B5=EF=B8=8F=201.=20api=202.=20int?= =?UTF-8?q?eractions=203.=20predictions=204.=20pubsub?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .eslintrc.js | 4 ---- 1 file changed, 4 deletions(-) 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: [ From c19a19bdd87629e18f4926579b13b8baf0b8d843 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 13:19:32 -0700 Subject: [PATCH 2/9] chore(api): run yarn lint:fix --- packages/api/__tests__/API.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/api/__tests__/API.test.ts b/packages/api/__tests__/API.test.ts index ab95bf9dcc9..5a8f397bd67 100644 --- a/packages/api/__tests__/API.test.ts +++ b/packages/api/__tests__/API.test.ts @@ -1,7 +1,7 @@ -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 { CONNECTION_STATE_CHANGE, generateClient } from '@aws-amplify/api'; // import { runWithAmplifyServerContext } from 'aws-amplify/internals/adapter-core'; const serverManagedFields = { From bfbd9bddb8f28b6e38a54f39a10712b13eb3e0e3 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 13:21:42 -0700 Subject: [PATCH 3/9] chore(api): manual fix linter errors --- packages/api/__tests__/API.test.ts | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/api/__tests__/API.test.ts b/packages/api/__tests__/API.test.ts index 5a8f397bd67..16e10ac99b8 100644 --- a/packages/api/__tests__/API.test.ts +++ b/packages/api/__tests__/API.test.ts @@ -4,13 +4,6 @@ import { AmplifyClassV6 } from '@aws-amplify/core'; import { CONNECTION_STATE_CHANGE, generateClient } from '@aws-amplify/api'; // import { runWithAmplifyServerContext } from 'aws-amplify/internals/adapter-core'; -const serverManagedFields = { - id: 'some-id', - owner: 'wirejobviously', - createdAt: new Date().toISOString(), - updatedAt: new Date().toISOString(), -}; - describe('API generateClient', () => { afterEach(() => { jest.clearAllMocks(); From da5fa53e6b41939b9385e8b11095f753ebd2d390 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 13:24:29 -0700 Subject: [PATCH 4/9] chore(interactions): run yarn lint:fix --- .../__tests__/lex-v1/AWSLexProvider.test.ts | 18 +++++++--- .../__tests__/lex-v1/apis/onComplete.test.ts | 7 ++-- .../__tests__/lex-v1/apis/send.test.ts | 1 + .../lex-v1/utils/resolveBotConfig.test.ts | 1 + .../__tests__/lex-v2/AWSLexV2Provider.test.ts | 34 ++++++++++++------- .../__tests__/lex-v2/apis/onComplete.test.ts | 7 ++-- .../__tests__/lex-v2/apis/send.test.ts | 1 + .../lex-v2/utils/resolveBotConfig.test.ts | 1 + .../testUtils/randomConfigGeneration.ts | 1 + 9 files changed, 49 insertions(+), 22 deletions(-) diff --git a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts index aaca3c0c1d0..1cef356cbe3 100644 --- a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts +++ b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts @@ -6,9 +6,10 @@ 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'; + jest.mock('@aws-amplify/core'); (global as any).Response = class Response { @@ -58,18 +59,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) { @@ -92,6 +96,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { }, audioStream: createBlob(), }; + return Promise.resolve(result); } else if (status === 'error') { const result = { @@ -99,6 +104,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'Failed', audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -106,6 +112,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'ElicitSlot', audioStream: createBlob(), }; + return Promise.resolve(result); } } else { @@ -119,6 +126,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { }, audioStream: createBlob(), }; + return Promise.resolve(result); } else if (command.input.inputStream === 'error') { const result = { @@ -126,6 +134,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'Failed', audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -133,6 +142,7 @@ LexRuntimeServiceClient.prototype.send = jest.fn((command, callback) => { dialogState: 'ElicitSlot', audioStream: createBlob(), }; + return Promise.resolve(result); } } @@ -339,9 +349,9 @@ describe('Interactions', () => { }); }); - completeFailCallback = jest.fn((err, confirmation) => - expect(err).toEqual(new Error('Bot conversation failed')), - ); + completeFailCallback = jest.fn((err, confirmation) => { + 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..d3ea77ffb46 100644 --- a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v1/apis/onComplete.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 { onComplete } from '../../../src/lex-v1/apis'; import { generateRandomLexV1Config } from '../../testUtils/randomConfigGeneration'; @@ -36,8 +37,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..d716d6c24a5 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,6 +10,7 @@ import { import { gzip, strToU8 } from 'fflate'; import { encode } from 'base-64'; import { v4 as uuid } from 'uuid'; + import { lexProvider } from '../../src/lex-v2/AWSLexV2Provider'; jest.mock('@aws-amplify/core'); @@ -49,12 +49,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); }; @@ -92,6 +93,7 @@ const handleRecognizeTextCommand = command => { }, messages: [{ content: 'echo:' + command.input.text }], }; + return Promise.resolve(result); } else if (command.input.text === 'error') { const result = { @@ -100,6 +102,7 @@ const handleRecognizeTextCommand = command => { }, messages: [{ content: 'echo:' + command.input.text }], }; + return Promise.resolve(result); } else { const result = { @@ -132,6 +135,7 @@ const handleRecognizeUtteranceCommandAudio = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else if (status === 'error') { const result = { @@ -143,6 +147,7 @@ const handleRecognizeUtteranceCommandAudio = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -154,6 +159,7 @@ const handleRecognizeUtteranceCommandAudio = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } }; @@ -172,6 +178,7 @@ const handleRecognizeUtteranceCommandText = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else if (command.input.inputStream === 'error') { const result = { @@ -183,6 +190,7 @@ const handleRecognizeUtteranceCommandText = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } else { const result = { @@ -194,6 +202,7 @@ const handleRecognizeUtteranceCommandText = async command => { ]), audioStream: createBlob(), }; + return Promise.resolve(result); } }; @@ -212,6 +221,7 @@ LexRuntimeV2Client.prototype.send = jest.fn(async (command, callback) => { response = await handleRecognizeUtteranceCommandText(command); } } + return response; }) as any; @@ -393,7 +403,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', @@ -427,9 +437,9 @@ describe('Interactions', () => { }); }); case ACTION_TYPE.ERROR: - return jest.fn((err, confirmation) => - expect(err).toEqual(new Error('Bot conversation failed')), - ); + return jest.fn((err, confirmation) => { + expect(err).toEqual(new Error('Bot conversation failed')); + }); } }; @@ -467,7 +477,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 +494,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 +512,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..ad6f1c28793 100644 --- a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v2/apis/onComplete.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 { onComplete } from '../../../src/lex-v2/apis'; import { generateRandomLexV2Config } from '../../testUtils/randomConfigGeneration'; @@ -36,8 +37,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'; From cc6321fafeafe7e88201b119505987c814b74170 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 13:44:17 -0700 Subject: [PATCH 5/9] chore(interactions): manual fix linter errors --- .../__tests__/lex-v1/AWSLexProvider.test.ts | 43 ++++++++++--------- .../__tests__/lex-v1/apis/onComplete.test.ts | 3 -- .../__tests__/lex-v2/AWSLexV2Provider.test.ts | 43 +++++++++++-------- .../__tests__/lex-v2/apis/onComplete.test.ts | 3 -- 4 files changed, 49 insertions(+), 43 deletions(-) diff --git a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts index 1cef356cbe3..81cb438e617 100644 --- a/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts +++ b/packages/interactions/__tests__/lex-v1/AWSLexProvider.test.ts @@ -9,15 +9,18 @@ import { 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(); @@ -48,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 = { @@ -82,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 @@ -156,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); @@ -276,6 +279,7 @@ describe('Interactions', () => { provider.sendMessage(botConfig.BookTrip, { content: createBlob(), options: { + // @ts-expect-error for testing messageType mismatches content type messageType: 'text', }, }), @@ -284,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', @@ -295,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); @@ -308,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); }); }); @@ -318,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); @@ -349,7 +352,7 @@ describe('Interactions', () => { }); }); - completeFailCallback = jest.fn((err, confirmation) => { + completeFailCallback = jest.fn(err => { expect(err).toEqual(new Error('Bot conversation failed')); }); diff --git a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts b/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts index d3ea77ffb46..72aa31eca4b 100644 --- a/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v1/apis/onComplete.test.ts @@ -1,8 +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'; @@ -28,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); diff --git a/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts b/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts index d716d6c24a5..c3390bf09c6 100644 --- a/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts +++ b/packages/interactions/__tests__/lex-v2/AWSLexV2Provider.test.ts @@ -12,11 +12,14 @@ 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)); } }; @@ -78,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)); } }; @@ -118,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 @@ -207,7 +210,7 @@ const handleRecognizeUtteranceCommandText = async command => { } }; -LexRuntimeV2Client.prototype.send = jest.fn(async (command, callback) => { +LexRuntimeV2Client.prototype.send = jest.fn(async command => { let response; if (command instanceof RecognizeTextCommand) { response = handleRecognizeTextCommand(command); @@ -232,7 +235,7 @@ afterEach(() => { describe('Interactions', () => { // Test 'send' API describe('send API', () => { - let provider; + let provider: AWSLexV2Provider; beforeEach(() => { mockFetchAuthSession.mockReturnValue(credentials); @@ -363,6 +366,7 @@ describe('Interactions', () => { provider.sendMessage(botConfig.BookTrip, { content: createBlob(), options: { + // @ts-expect-error For testing mismatch types messageType: 'text', }, }), @@ -371,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', @@ -382,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); @@ -393,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); }); }); @@ -411,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) => { @@ -437,7 +444,7 @@ describe('Interactions', () => { }); }); case ACTION_TYPE.ERROR: - return jest.fn((err, confirmation) => { + return jest.fn(err => { expect(err).toEqual(new Error('Bot conversation failed')); }); } @@ -458,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; diff --git a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts b/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts index ad6f1c28793..a4fe5b703df 100644 --- a/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts +++ b/packages/interactions/__tests__/lex-v2/apis/onComplete.test.ts @@ -1,8 +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'; @@ -28,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); From 312f04c8a0d4314a74e39aa962db8dd697ebb602 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 13:45:46 -0700 Subject: [PATCH 6/9] chore(predictions): run yarn lint:fix --- .../AWSAIConvertPredictionsProvider.test.ts | 5 ++++- .../AWSAIIdentifyPredictionsProvider.test.ts | 15 +++++++++++++++ .../AWSAIInterpretPredictionsProvider.test.ts | 11 ++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts index 5678c1b079c..f1620e867c4 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, @@ -51,6 +52,7 @@ const resetPollyMock = () => { buffer: 'dummyStream', }, }; + return Promise.resolve(result); } }) as any; @@ -62,6 +64,7 @@ const resetPollyMock = () => { return 'dummyStream'; }, }; + return response; }); @@ -69,7 +72,7 @@ const resetPollyMock = () => { let onCloseCallback; let onErrorCallback; let onMsgCallback; - let connection = { + const connection = { set onmessage(callback) { onMsgCallback = callback; }, diff --git a/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts index 042ca5c7114..ae7ce1085ca 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; @@ -295,6 +302,7 @@ mockGetUrl.mockImplementation(({ key, options }) => { `https://bucket-name.s3.us-west-2.amazonaws.com/${level}/${identityId}/key.png?X-Amz-Algorithm=AWS4-HMAC-SHA256`, ); } + return Promise.resolve({ url }); }); @@ -352,6 +360,7 @@ describe('Predictions identify provider test', () => { DetectedText: '', }); } + return Promise.resolve(plainBlocks); }); // confirm that textract service has been called @@ -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); diff --git a/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts index 60bc46c4c2e..0b43e080f05 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; @@ -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', From 09af5e50a6b9cfbcaacee2c741540283d3c8a32d Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 14:22:19 -0700 Subject: [PATCH 7/9] chore(predictions): manual fix linter errors --- .../AWSAIConvertPredictionsProvider.test.ts | 38 +++++++++---------- .../AWSAIIdentifyPredictionsProvider.test.ts | 29 +++++++------- .../AWSAIInterpretPredictionsProvider.test.ts | 2 +- 3 files changed, 36 insertions(+), 33 deletions(-) diff --git a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts index f1620e867c4..6c6094279b1 100644 --- a/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIConvertPredictionsProvider.test.ts @@ -47,18 +47,18 @@ 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'; @@ -68,21 +68,21 @@ const resetPollyMock = () => { return response; }); -(global as any).WebSocket = jest.fn(url => { - let onCloseCallback; - let onErrorCallback; - let onMsgCallback; +(global as any).WebSocket = jest.fn(() => { + let onCloseCallback: () => void; + let onMsgCallback: (arg0: string) => void; const connection = { - set onmessage(callback) { + /* 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(() => { @@ -149,7 +149,7 @@ const validTextToSpeechInput: TextToSpeechInput = { const validSpeechToTextInput: SpeechToTextInput = { transcription: { source: { - bytes: new Buffer([0, 1, 2]), + bytes: Buffer.from([0, 1, 2]), }, }, }; @@ -208,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'); }); }); @@ -232,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( @@ -273,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'); }); }); @@ -429,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 ae7ce1085ca..7db9f2a3073 100644 --- a/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIIdentifyPredictionsProvider.test.ts @@ -288,18 +288,18 @@ 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`, ); } @@ -307,7 +307,7 @@ mockGetUrl.mockImplementation(({ key, options }) => { }); describe('Predictions identify provider test', () => { - let predictionsProvider; + let predictionsProvider: AmazonAIIdentifyPredictionsProvider; beforeAll(() => { predictionsProvider = new AmazonAIIdentifyPredictionsProvider(); @@ -346,14 +346,14 @@ 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, @@ -361,7 +361,7 @@ describe('Predictions identify provider test', () => { }); } - return Promise.resolve(plainBlocks); + return Promise.resolve(mockPlainBlocks); }); // confirm that textract service has been called const spy = jest.spyOn(TextractClient.prototype, 'send'); @@ -732,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', ); @@ -750,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, @@ -773,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, @@ -791,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, @@ -799,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 0b43e080f05..09a4f37e650 100644 --- a/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts +++ b/packages/predictions/__tests__/providers/AWSAIInterpretPredictionsProvider.test.ts @@ -29,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: [ From e47277e71397f54047fa941bfbe90c06ee36f72b Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 14:23:43 -0700 Subject: [PATCH 8/9] chore(pubsub): run yarn lint:fix --- .../__tests__/ConnectionStateMonitor.tests.ts | 17 ++--- packages/pubsub/__tests__/PubSub.test.ts | 66 ++++++++++++------- packages/pubsub/__tests__/helpers.ts | 26 ++++++-- 3 files changed, 71 insertions(+), 38 deletions(-) diff --git a/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts b/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts index d90c252adb5..1abacc3b3a4 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[]; diff --git a/packages/pubsub/__tests__/PubSub.test.ts b/packages/pubsub/__tests__/PubSub.test.ts index b4b1885b6e8..bae38854dad 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,14 +30,6 @@ 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 mockConnect = jest.fn(options => { @@ -39,7 +41,7 @@ const pahoClientMock = jest.fn().mockImplementation((host, clientId) => { return pahoClientMockCache[clientId]; } - var client = {} as any; + const client = {} as any; client.connect = mockConnect; client.send = jest.fn((topic, message) => { @@ -83,13 +85,15 @@ const testPubSubAsync = ( obs.unsubscribe(); resolve(Promise.resolve()); }, - close: () => console.log('close'), + close: () => { + console.log('close'); + }, error: reject, }); await hubConnectionListener.waitUntilConnectionStateIn([ ConnectionState.Connected, ]); - pubsub.publish({ topics: topic, message: message, options }); + pubsub.publish({ topics: topic, message, options }); }); beforeEach(() => { @@ -145,7 +149,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 +167,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 +239,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', @@ -426,7 +434,7 @@ describe('PubSub', () => { provider: 'MqttOverWSProvider', }); - expect(pubsub['isSSLEnabled']).toBe(false); + expect(pubsub.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', @@ -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([ @@ -542,8 +554,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); + }, }); const subscription2 = pubsub @@ -552,8 +568,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); + }, }); // TODO: we should now when the connection is established to wait for that first diff --git a/packages/pubsub/__tests__/helpers.ts b/packages/pubsub/__tests__/helpers.ts index 5fb25cea201..02f16723795 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(() => { @@ -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, }), }), @@ -306,10 +310,12 @@ class FakeWebSocket implements WebSocket { 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; @@ -319,24 +325,29 @@ class FakeWebSocket implements WebSocket { 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 { 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, @@ -344,6 +355,7 @@ class FakeWebSocket implements WebSocket { ): void { throw new Error('Method not implemented removeEventListener.'); } + dispatchEvent(event: Event): boolean { throw new Error('Method not implemented dispatchEvent.'); } From 5ff4c36103aaa8a8730b8ac953e5a4151981b7a9 Mon Sep 17 00:00:00 2001 From: Hui Zhao Date: Wed, 26 Jun 2024 16:11:22 -0700 Subject: [PATCH 9/9] chore(pubsub): manual fix linter errors --- .../__tests__/ConnectionStateMonitor.tests.ts | 2 +- packages/pubsub/__tests__/PubSub.test.ts | 78 +++++++++---------- packages/pubsub/__tests__/helpers.ts | 52 ++++++------- 3 files changed, 63 insertions(+), 69 deletions(-) diff --git a/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts b/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts index 1abacc3b3a4..14014dc8f91 100644 --- a/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts +++ b/packages/pubsub/__tests__/ConnectionStateMonitor.tests.ts @@ -28,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 bae38854dad..043d5a57b37 100644 --- a/packages/pubsub/__tests__/PubSub.test.ts +++ b/packages/pubsub/__tests__/PubSub.test.ts @@ -30,13 +30,13 @@ jest.mock('@aws-amplify/core', () => ({ }, })); -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]; } @@ -47,12 +47,12 @@ const pahoClientMock = jest.fn().mockImplementation((host, clientId) => { 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; @@ -65,8 +65,7 @@ jest.mock('../src/vendor/paho-mqtt', () => ({ Client: {}, })); -// @ts-ignore -Paho.Client = pahoClientMock; +(Paho as any).Client = pahoClientMock; const testPubSubAsync = ( pubsub, @@ -75,10 +74,11 @@ 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); @@ -90,7 +90,7 @@ const testPubSubAsync = ( }, error: reject, }); - await hubConnectionListener.waitUntilConnectionStateIn([ + await resolvedHubConnectionListener.waitUntilConnectionStateIn([ ConnectionState.Connected, ]); pubsub.publish({ topics: topic, message, options }); @@ -115,7 +115,9 @@ describe('PubSub', () => { describe('constructor test', () => { test('happy case', () => { - const pubsub = new IotPubSub(); + expect(() => { + const _ = new IotPubSub(); + }).not.toThrow(); }); }); @@ -301,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; }), @@ -313,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; }), @@ -330,7 +330,7 @@ describe('PubSub', () => { const sub = pubsub .subscribe({ topics: 'topic', options: { clientId: '123' } }) .subscribe({ - error: () => {}, + error: jest.fn(), }); await hubConnectionListener.waitUntilConnectionStateIn([ @@ -356,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([ @@ -391,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([ @@ -434,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, @@ -484,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( @@ -498,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 () => { @@ -548,19 +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'] }) @@ -578,8 +576,8 @@ describe('PubSub', () => { // 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 02f16723795..51dcd4381b1 100644 --- a/packages/pubsub/__tests__/helpers.ts +++ b/packages/pubsub/__tests__/helpers.ts @@ -34,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 => { @@ -46,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 => { @@ -65,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)); }); } } @@ -98,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); } @@ -233,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({ @@ -257,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(); } @@ -266,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); } }); }); @@ -306,7 +306,7 @@ 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)); } @@ -316,10 +316,10 @@ class FakeWebSocket implements WebSocket { 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, @@ -332,7 +332,7 @@ class FakeWebSocket implements WebSocket { options?: boolean | AddEventListenerOptions, ): void; - addEventListener(type: unknown, listener: unknown, options?: unknown): void { + addEventListener(): void { throw new Error('Method not implemented addEventListener.'); } @@ -348,15 +348,11 @@ class FakeWebSocket implements WebSocket { 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.'); } @@ -370,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, });