From f1fb60bf559f61b4b111135667c31f3e49ec74fa Mon Sep 17 00:00:00 2001 From: Evgeniy Semin Date: Fri, 8 Dec 2023 15:05:52 +0300 Subject: [PATCH] =?UTF-8?q?test:=20=D0=A0=D0=B0=D0=B7=D0=B4=D0=B5=D0=BB?= =?UTF-8?q?=D0=B5=D0=BD=D1=8B=20=D1=82=D0=B5=D1=81=D1=82=D1=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...spec.ts => assist.createAssistant.spec.ts} | 32 +-- ...c.ts => assist.createAssistantDev.spec.ts} | 38 ++-- ...c.ts => assist.createAssistantWeb.spec.ts} | 35 ++-- ... => assist.initializeAssistantSDK.spec.ts} | 4 +- ...tion.spec.ts => assist.sendAction.spec.ts} | 27 +-- ...vents.spec.ts => client.appEvents.spec.ts} | 1 + ...g.spec.ts => client.autolistening.spec.ts} | 0 ....spec.ts => client.backgroundApps.spec.ts} | 29 +-- ....spec.ts => client.changeSettings.spec.ts} | 0 ...tion.spec.ts => client.connection.spec.ts} | 13 +- ....spec.ts => client.disableDubbing.spec.ts} | 0 ...dubbing.spec.ts => client.dubbing.spec.ts} | 4 +- ...tings.spec.ts => client.greetings.spec.ts} | 5 +- ...ening.spec.ts => client.listening.spec.ts} | 0 .../{meta.spec.ts => client.meta.spec.ts} | 14 +- ...en.spec.ts => client.refreshToken.spec.ts} | 2 +- .../client.requestPermissions.spec.ts | 186 ++++++++++++++++++ ....ts => client.resolveAudioContext.spec.ts} | 0 ...s.spec.ts => client.subscriptions.spec.ts} | 0 .../integration/requestPermissions.spec.ts | 138 ------------- cypress/support/commands.ts | 8 +- src/createAssistant.ts | 1 - 22 files changed, 307 insertions(+), 230 deletions(-) rename cypress/integration/{createAssistant.spec.ts => assist.createAssistant.spec.ts} (95%) rename cypress/integration/{createAssistantDev.spec.ts => assist.createAssistantDev.spec.ts} (93%) rename cypress/integration/{createAssistantWeb.spec.ts => assist.createAssistantWeb.spec.ts} (63%) rename cypress/integration/{initializeAssistantSDK.spec.ts => assist.initializeAssistantSDK.spec.ts} (96%) rename cypress/integration/{sendAction.spec.ts => assist.sendAction.spec.ts} (86%) rename cypress/integration/{appEvents.spec.ts => client.appEvents.spec.ts} (99%) rename cypress/integration/{autolistening.spec.ts => client.autolistening.spec.ts} (100%) rename cypress/integration/{backgroundApps.spec.ts => client.backgroundApps.spec.ts} (91%) rename cypress/integration/{changeSettings.spec.ts => client.changeSettings.spec.ts} (100%) rename cypress/integration/{connection.spec.ts => client.connection.spec.ts} (97%) rename cypress/integration/{disableDubbing.spec.ts => client.disableDubbing.spec.ts} (100%) rename cypress/integration/{dubbing.spec.ts => client.dubbing.spec.ts} (99%) rename cypress/integration/{greetings.spec.ts => client.greetings.spec.ts} (96%) rename cypress/integration/{listening.spec.ts => client.listening.spec.ts} (100%) rename cypress/integration/{meta.spec.ts => client.meta.spec.ts} (84%) rename cypress/integration/{refreshToken.spec.ts => client.refreshToken.spec.ts} (99%) create mode 100644 cypress/integration/client.requestPermissions.spec.ts rename cypress/integration/{resolveAudioContext.spec.ts => client.resolveAudioContext.spec.ts} (100%) rename cypress/integration/{subscriptions.spec.ts => client.subscriptions.spec.ts} (100%) delete mode 100644 cypress/integration/requestPermissions.spec.ts diff --git a/cypress/integration/createAssistant.spec.ts b/cypress/integration/assist.createAssistant.spec.ts similarity index 95% rename from cypress/integration/createAssistant.spec.ts rename to cypress/integration/assist.createAssistant.spec.ts index 0f8555be84..c4073191f2 100644 --- a/cypress/integration/createAssistant.spec.ts +++ b/cypress/integration/assist.createAssistant.spec.ts @@ -1,10 +1,12 @@ +/* eslint-disable camelcase */ /// + import { createAssistant } from 'lib'; import { Hints, Suggestions } from '@salutejs/scenario'; -import { SystemMessageHeaderByttonsType } from '../../src/index'; +import { SystemMessageHeaderByttonsType, createAssistant as createAssistantT } from '../../src/index'; -/* eslint-disable @typescript-eslint/camelcase */ +declare type createAssistant = typeof createAssistantT; describe('Проверяем createAssistant', () => { beforeEach(() => { @@ -57,16 +59,18 @@ describe('Проверяем createAssistant', () => { expectedName: string | null, ) => new Promise((resolve) => { - window.AssistantHost.sendData = (action: string, name: string | null) => { - expect(action).not.undefined; - expect(action).not.empty; - expect(expectedAction).to.deep.equal(JSON.parse(action)); + window.AssistantHost.sendData = (act: string, name: string | null) => { + expect(act).not.undefined; + expect(act).not.empty; + expect(expectedAction).to.deep.equal(JSON.parse(act)); + if (expectedName) { expect(expectedName).to.equal(name); } else { expect(name).null; // отправляем null, вместо undefined } - resolve(); + + resolve(undefined); }; assistant.sendData({ action: expectedAction, name: expectedName }); @@ -81,17 +85,17 @@ describe('Проверяем createAssistant', () => { new Promise((resolve) => { window.AssistantHost.sendData = cy.stub(); window.AssistantHost.sendDataContainer = (container: string) => { - const { data, message_name, requestId } = JSON.parse(container); + const { data, message_name, requestId: reqId } = JSON.parse(container); expect(expectedAction).to.deep.equal(data); - expect(expectedRequestId).to.equal(requestId); + expect(expectedRequestId).to.equal(reqId); if (expectedName) { expect(expectedName).to.equal(message_name); } else { expect(message_name).empty; // отправляем пустую строку, вместо undefined } - resolve(); + resolve(undefined); }; assistant.sendData({ action: expectedAction, name: expectedName, requestId: expectedRequestId }); @@ -155,8 +159,8 @@ describe('Проверяем createAssistant', () => { // не передаем requestId, ожидаем ответ window.AssistantHost.sendDataContainer = (data) => { - const { requestId } = JSON.parse(data); - setTimeout(() => window.AssistantClient.onData({ ...command, sdk_meta: { requestId } })); + const { requestId: reqId } = JSON.parse(data); + setTimeout(() => window.AssistantClient.onData({ ...command, sdk_meta: { requestId: reqId } })); }; assistant.sendData({ action }, ({ sdk_meta, ...cmd }) => { expect(cmd).to.deep.equal(command); @@ -332,12 +336,12 @@ describe('Проверяем createAssistant', () => { let callbackHadCommand = false; window.AssistantHost.sendDataContainer = (data) => { - const { requestId } = JSON.parse(data); + const { requestId: reqId } = JSON.parse(data); window.setTimeout(() => { window.AssistantClient.onData({ type: 'smart_app_data', - sdk_meta: { requestId }, + sdk_meta: { requestId: reqId }, smart_app_data: testResponse, }); }); diff --git a/cypress/integration/createAssistantDev.spec.ts b/cypress/integration/assist.createAssistantDev.spec.ts similarity index 93% rename from cypress/integration/createAssistantDev.spec.ts rename to cypress/integration/assist.createAssistantDev.spec.ts index a7aaccd3c6..5eafd0b721 100644 --- a/cypress/integration/createAssistantDev.spec.ts +++ b/cypress/integration/assist.createAssistantDev.spec.ts @@ -40,7 +40,7 @@ describe('Проверяем createAssistantDev', () => { let phraseReceived: boolean; let isDone = false; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket); @@ -53,7 +53,7 @@ describe('Проверяем createAssistantDev', () => { if (message.initialSettings) { settingsReceived = message.initialSettings.userChannel === USER_CHANNEL && - message.initialSettings.device.surface === SURFACE && + message.initialSettings.device?.surface === SURFACE && message.initialSettings.device.platformType === 'WEBDBG'; } @@ -87,9 +87,13 @@ describe('Проверяем createAssistantDev', () => { smart_app_data: { type: 'test_command' }, }; const FEATURES = { feature: true }; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; - initProtocol(socket, { initPhrase: INIT_PHRASE, items: [{ command: COMMAND }], systemMessage: { feature_launcher: FEATURES } }); + initProtocol(socket, { + initPhrase: INIT_PHRASE, + items: [{ command: COMMAND }], + systemMessage: { feature_launcher: FEATURES }, + }); }); const assistant = createAssistantDev({ @@ -139,9 +143,13 @@ describe('Проверяем createAssistantDev', () => { smart_app_data: { type: 'test_command' }, }; const FEATURES = { feature: true }; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; - initProtocol(socket, { initPhrase: INIT_PHRASE, items: [{ command: COMMAND }], systemMessage: { feature_launcher: FEATURES } }); + initProtocol(socket, { + initPhrase: INIT_PHRASE, + items: [{ command: COMMAND }], + systemMessage: { feature_launcher: FEATURES }, + }); }); const assistant = createAssistantDev({ @@ -182,7 +190,7 @@ describe('Проверяем createAssistantDev', () => { }); it('Проверяем оповещение подписчиков о старте', (done) => { - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE }); }); @@ -201,7 +209,7 @@ describe('Проверяем createAssistantDev', () => { it('Проверяем вызов send_data - ожидаем мессадж с app_info и стейтом в нем', (done) => { const state = { item_selector: { items: [] }, key: 'TEST' }; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE }); @@ -219,7 +227,8 @@ describe('Проверяем createAssistantDev', () => { expect(server_action).to.ok; expect(message.meta).to.ok; - switch (data.server_action.action_id) { + // @ts-ignore + switch (data.server_action?.action_id) { case 'first': expect(current_app.app_info).to.deep.equal(APP_INFO); expect(current_app.state).to.deep.equal(state); @@ -248,7 +257,7 @@ describe('Проверяем createAssistantDev', () => { it('Проверяем подписку sendAction - ожидаем срабатывание подписки', (done) => { const smartAppData = { type: 'test_data' }; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE }); @@ -258,6 +267,7 @@ describe('Проверяем createAssistantDev', () => { if (message.systemMessage?.data && message.systemMessage?.data !== '{}') { const { server_action }: SystemMessageDataType = JSON.parse(message.systemMessage.data); + // @ts-ignore if (server_action?.type !== 'test_action') { return; } @@ -298,7 +308,7 @@ describe('Проверяем createAssistantDev', () => { const received = { character: false, navigation: false, data: false, insets: false }; let handleStart: () => void; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE, @@ -356,7 +366,7 @@ describe('Проверяем createAssistantDev', () => { const characterId = 'joy'; let handleStart: () => void; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE }); @@ -392,7 +402,7 @@ describe('Проверяем createAssistantDev', () => { it('Проверяем восстановление recoveryState', (done) => { const recoveryState = { type: 'recovery_state', item_selector: { items: [] } }; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE }); }); @@ -431,7 +441,7 @@ describe('Проверяем createAssistantDev', () => { cy.stub(window.history, 'back', historyBack); - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; setTimeout(() => socket.send( diff --git a/cypress/integration/createAssistantWeb.spec.ts b/cypress/integration/assist.createAssistantWeb.spec.ts similarity index 63% rename from cypress/integration/createAssistantWeb.spec.ts rename to cypress/integration/assist.createAssistantWeb.spec.ts index 4caa686cc5..f91e8b75a8 100644 --- a/cypress/integration/createAssistantWeb.spec.ts +++ b/cypress/integration/assist.createAssistantWeb.spec.ts @@ -4,7 +4,7 @@ import { createAssistant } from 'lib'; describe('Проверяем createAssistant на вебе (без сдк)', () => { const state = { type: 'test app state' }; const recoveryState = { type: 'test app recovery state' }; - let expectAfterIt = undefined; + let expectAfterIt: (() => void) | undefined; before(() => { createAssistant({ getState: () => ({}) }); @@ -12,18 +12,20 @@ describe('Проверяем createAssistant на вебе (без сдк)', () onData: cy.stub(), onStart: cy.stub(), onRequestState: cy.stub().returns(state), - onRequestRecoveryState: cy.stub().returns(recoveryState) + onRequestRecoveryState: cy.stub().returns(recoveryState), }; }); beforeEach(() => { expectAfterIt = undefined; - window.top.postMessage = cy.stub(); - }) + if (window.top) { + window.top.postMessage = cy.stub(); + } + }); afterEach(() => { - expectAfterIt && expectAfterIt(); - }) + expectAfterIt?.(); + }); it('appInitialData и AssistantHost установлены', () => { expect(window.appInitialData).to.deep.equals([]); @@ -32,28 +34,31 @@ describe('Проверяем createAssistant на вебе (без сдк)', () it('Проксирование onStart', () => { window.postMessage(JSON.stringify({ type: 'onStart' }), '*'); - cy.wrap(window.AssistantClient.onStart).should(onStart => expect(onStart).to.calledOnce); + cy.wrap(window.AssistantClient?.onStart).should((onStart) => expect(onStart).to.calledOnce); }); it('Проксирование onData', () => { const payload = { type: 'test' }; window.postMessage(JSON.stringify({ type: 'onData', payload }), '*'); - cy.wrap(window.AssistantClient.onData).should(onData => expect(onData).to.calledOnceWith(payload)); + cy.wrap(window.AssistantClient?.onData).should((onData) => expect(onData).to.calledOnceWith(payload)); }); it('Реакция onRequestState', () => { expectAfterIt = () => { - expect(window.AssistantClient.onRequestState).to.calledOnce; - expect(window.top.postMessage).to.calledOnceWith(JSON.stringify({ type: 'state', payload: state }), '*'); + expect(window.AssistantClient?.onRequestState).to.calledOnce; + expect(window.top?.postMessage).to.calledOnceWith(JSON.stringify({ type: 'state', payload: state }), '*'); }; window.postMessage(JSON.stringify({ type: 'onRequestState' }), '*'); }); it('Реакция onRequestRecoveryState', () => { expectAfterIt = () => { - expect(window.AssistantClient.onRequestRecoveryState).to.calledOnce; - expect(window.top.postMessage).to.calledOnceWith(JSON.stringify({ type: 'recoveryState', payload: recoveryState }), '*'); + expect(window.AssistantClient?.onRequestRecoveryState).to.calledOnce; + expect(window.top?.postMessage).to.calledOnceWith( + JSON.stringify({ type: 'recoveryState', payload: recoveryState }), + '*', + ); }; window.postMessage(JSON.stringify({ type: 'onRequestRecoveryState' }), '*'); }); @@ -62,9 +67,11 @@ describe('Проверяем createAssistant на вебе (без сдк)', () window.history.back = cy.stub(); expectAfterIt = () => { expect(window.history.back).to.calledOnce; - cy.wrap(window.top.postMessage, { timeout: 600 }).should(func => expect(func).to.calledOnceWith(JSON.stringify({ type: 'close' }), '*')); + cy.wrap(window.top?.postMessage, { timeout: 600 }).should((func) => + expect(func).to.calledOnceWith(JSON.stringify({ type: 'close' }), '*'), + ); }; window.postMessage(JSON.stringify({ type: 'onBack' }), '*'); }); -}); \ No newline at end of file +}); diff --git a/cypress/integration/initializeAssistantSDK.spec.ts b/cypress/integration/assist.initializeAssistantSDK.spec.ts similarity index 96% rename from cypress/integration/initializeAssistantSDK.spec.ts rename to cypress/integration/assist.initializeAssistantSDK.spec.ts index b4385534bf..4b1e2726f7 100644 --- a/cypress/integration/initializeAssistantSDK.spec.ts +++ b/cypress/integration/assist.initializeAssistantSDK.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ /// import { WebSocket, Server } from 'mock-socket'; @@ -35,7 +36,7 @@ describe('Проверяем', () => { let context: Message; let doneCalled = false; - server.on('connection', (socket) => { + server?.on('connection', (socket) => { socket.binaryType = 'arraybuffer'; initProtocol(socket, { initPhrase: INIT_PHRASE, @@ -53,7 +54,6 @@ describe('Проверяем', () => { } if (action && context && !doneCalled) { - // eslint-disable-next-line @typescript-eslint/camelcase const current_app = JSON.parse(context.meta.current_app); doneCalled = true; diff --git a/cypress/integration/sendAction.spec.ts b/cypress/integration/assist.sendAction.spec.ts similarity index 86% rename from cypress/integration/sendAction.spec.ts rename to cypress/integration/assist.sendAction.spec.ts index 438549cecb..24ad35699c 100644 --- a/cypress/integration/sendAction.spec.ts +++ b/cypress/integration/assist.sendAction.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ /// import { createAssistant } from 'lib'; @@ -32,10 +33,10 @@ describe('Проверяем sendAction', () => { const assistant = initAssistant(); window.AssistantHost.sendDataContainer = (sended) => { - const { data, message_name, requestId } = JSON.parse(sended); + const { data, message_name, requestId: reqId } = JSON.parse(sended); expect(data, 'пришел экшен').to.deep.equal(action); expect(message_name, 'message_name не заполнен').to.empty; - expect(requestId, 'requestId заполнен').to.not.empty; + expect(reqId, 'requestId заполнен').to.not.empty; done(); }; @@ -46,10 +47,10 @@ describe('Проверяем sendAction', () => { const assistant = initAssistant(); window.AssistantHost.sendDataContainer = (sended) => { - const { data, message_name, requestId } = JSON.parse(sended); + const { data, message_name, requestId: reqId } = JSON.parse(sended); expect(data, 'пришел экшен').to.deep.equal(action); expect(message_name, 'message_name передан').to.equal(name); - expect(requestId, 'requestId передан').to.equal(requestId); + expect(reqId, 'requestId передан').to.equal(reqId); done(); }; @@ -62,9 +63,11 @@ describe('Проверяем sendAction', () => { const assistant = initAssistant(); window.AssistantHost.sendDataContainer = (data) => { - const { requestId } = JSON.parse(data); + const { requestId: reqId } = JSON.parse(data); setTimeout(() => - commands.map((command) => window.AssistantClient.onData({ ...command, sdk_meta: { requestId } })), + commands.map((command) => + window.AssistantClient.onData({ ...command, sdk_meta: { requestId: reqId } }), + ), ); }; @@ -93,10 +96,10 @@ describe('Проверяем sendAction', () => { const assistant = initAssistant(); window.AssistantHost.sendDataContainer = (data) => { - const { requestId } = JSON.parse(data); + const { requestId: reqId } = JSON.parse(data); setTimeout(() => commands.map((command, i) => - setTimeout(() => window.AssistantClient.onData({ ...command, sdk_meta: { requestId } }), i), + setTimeout(() => window.AssistantClient.onData({ ...command, sdk_meta: { requestId: reqId } }), i), ), ); }; @@ -118,10 +121,10 @@ describe('Проверяем sendAction', () => { const assistant = initAssistant(); window.AssistantHost.sendDataContainer = (data) => { - const { requestId } = JSON.parse(data); + const { requestId: reqId } = JSON.parse(data); setTimeout(() => commands.map((command, i) => - setTimeout(() => window.AssistantClient.onData({ ...command, sdk_meta: { requestId } }), i), + setTimeout(() => window.AssistantClient.onData({ ...command, sdk_meta: { requestId: reqId } }), i), ), ); }; @@ -153,10 +156,10 @@ describe('Проверяем sendAction', () => { let commandCount = 0; window.AssistantHost.sendDataContainer = (data) => { - const { requestId } = JSON.parse(data); + const { requestId: reqId } = JSON.parse(data); setTimeout(() => { - window.AssistantClient.onData({ ...commands[++dataCount], sdk_meta: { requestId } }); + window.AssistantClient.onData({ ...commands[++dataCount], sdk_meta: { requestId: reqId } }); }, dataCount); }; diff --git a/cypress/integration/appEvents.spec.ts b/cypress/integration/client.appEvents.spec.ts similarity index 99% rename from cypress/integration/appEvents.spec.ts rename to cypress/integration/client.appEvents.spec.ts index 0e2581a73f..6b9ec87a6f 100644 --- a/cypress/integration/appEvents.spec.ts +++ b/cypress/integration/client.appEvents.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ /// import { AppInfo } from '@salutejs/scenario'; diff --git a/cypress/integration/autolistening.spec.ts b/cypress/integration/client.autolistening.spec.ts similarity index 100% rename from cypress/integration/autolistening.spec.ts rename to cypress/integration/client.autolistening.spec.ts diff --git a/cypress/integration/backgroundApps.spec.ts b/cypress/integration/client.backgroundApps.spec.ts similarity index 91% rename from cypress/integration/backgroundApps.spec.ts rename to cypress/integration/client.backgroundApps.spec.ts index 91a0fb0789..f4457fcd62 100644 --- a/cypress/integration/backgroundApps.spec.ts +++ b/cypress/integration/client.backgroundApps.spec.ts @@ -1,4 +1,4 @@ -/* eslint-disable @typescript-eslint/camelcase */ +/* eslint-disable camelcase */ /// import { Server, WebSocket } from 'mock-socket'; @@ -92,12 +92,13 @@ describe('Тест backgroundApps', () => { const app = assistantClient.addBackgroundApp({ appInfo, getState }); return () => { + // @ts-ignore return app.onCommand(({ smart_app_data }) => { - const { appInfo, mustBeReceived, last } = smart_app_data; + const { appInfo: info, mustBeReceived, last } = smart_app_data; - expect(appInfo).deep.eq(APPS[index]); + expect(info).deep.eq(APPS[index]); expect(mustBeReceived).to.be.true; - + if (last) { commandsEnded += 1; } @@ -106,7 +107,7 @@ describe('Тест backgroundApps', () => { done(); } }).clearSubscribers; - } + }; }); onSocketReady((socket) => { @@ -118,16 +119,16 @@ describe('Тест backgroundApps', () => { sendMessage(socket, i, { systemMessageData: { - // eslint-disable-next-line @typescript-eslint/camelcase auto_listening: false, - // eslint-disable-next-line @typescript-eslint/camelcase app_info: appInfo, - items: [{ - command: { - type: 'smart_app_data', - smart_app_data: { appInfo, mustBeReceived, last }, + items: [ + { + command: { + type: 'smart_app_data', + smart_app_data: { appInfo, mustBeReceived, last }, + }, }, - }], + ], }, }); }; @@ -170,13 +171,13 @@ describe('Тест backgroundApps', () => { if (data.server_action) { receivedCount += 1; - + if (data.app_info?.applicationId !== APPS[0].applicationId) { expect(data.server_action).deep.eq(actionToCurrentApp); } else { expect(data.server_action).deep.eq(actionToBackgroundApp); } - + if (receivedCount === 2) { done(); } diff --git a/cypress/integration/changeSettings.spec.ts b/cypress/integration/client.changeSettings.spec.ts similarity index 100% rename from cypress/integration/changeSettings.spec.ts rename to cypress/integration/client.changeSettings.spec.ts diff --git a/cypress/integration/connection.spec.ts b/cypress/integration/client.connection.spec.ts similarity index 97% rename from cypress/integration/connection.spec.ts rename to cypress/integration/client.connection.spec.ts index f3c74cdd81..07fbc96d55 100644 --- a/cypress/integration/connection.spec.ts +++ b/cypress/integration/client.connection.spec.ts @@ -1,6 +1,5 @@ /// -import { createAssistantClient } from '../../src'; import { Message } from '../../src/proto'; import { initAssistantClient } from '../support/helpers/init'; // Собственная реализация необходима, так как пакет mock-socket не эмитит событие сокета close на клиенте @@ -156,12 +155,12 @@ describe('Подключение к сокету', () => { /// и три попытки переподключения assistantClient.on('vps', ({ type }) => { if (type === 'error') { - cy.tick(5000) + cy.tick(5000); expect(attempt).to.be.eq(3); done(); } - }) - }) + }); + }); it('reconnect закроет и откроет соедение если оно открыто (3 попытки)', (done) => { const assistantClient = initAssistantClient(); @@ -171,7 +170,7 @@ describe('Подключение к сокету', () => { attempt++; expect(url).to.be.eq('ws://path'); - + ws = new WebSocketMock(url); ws.readyState = WebSocket.OPEN; cy.stub(ws, 'close'); @@ -200,10 +199,10 @@ describe('Подключение к сокету', () => { /// и три попытки переподключения (+1 в начале) assistantClient.on('vps', ({ type }) => { if (type === 'error') { - cy.tick(5000) + cy.tick(5000); expect(attempt).to.be.eq(4); done(); } - }) + }); }); }); diff --git a/cypress/integration/disableDubbing.spec.ts b/cypress/integration/client.disableDubbing.spec.ts similarity index 100% rename from cypress/integration/disableDubbing.spec.ts rename to cypress/integration/client.disableDubbing.spec.ts diff --git a/cypress/integration/dubbing.spec.ts b/cypress/integration/client.dubbing.spec.ts similarity index 99% rename from cypress/integration/dubbing.spec.ts rename to cypress/integration/client.dubbing.spec.ts index 6eb8a5f6b4..f883889764 100644 --- a/cypress/integration/dubbing.spec.ts +++ b/cypress/integration/client.dubbing.spec.ts @@ -198,7 +198,7 @@ describe('Озвучка', () => { ); socket.send( createMessage({ - messageId: message.messageId+1, + messageId: (message.messageId as number) + 1, messageName: MessageNames.ANSWER_TO_USER, systemMessage: { items: [{ bubble: { text: 'test' } }] }, last: 1, @@ -216,7 +216,7 @@ describe('Озвучка', () => { } }); }); - + assistantClient.on('vps', (event) => { if (event.type === 'outcoming' && event.message.cancel && event.message.messageId === mid) { counter++; diff --git a/cypress/integration/greetings.spec.ts b/cypress/integration/client.greetings.spec.ts similarity index 96% rename from cypress/integration/greetings.spec.ts rename to cypress/integration/client.greetings.spec.ts index 33e5db18bf..342769715e 100644 --- a/cypress/integration/greetings.spec.ts +++ b/cypress/integration/client.greetings.spec.ts @@ -1,3 +1,4 @@ +/* eslint-disable camelcase */ /// import { Server } from 'mock-socket'; @@ -50,7 +51,7 @@ describe('Проверяем приветствие', () => { [{ disableGreetings: false, isFirstSession: true }], ({ messageName, systemMessage, meta }) => { if (messageName === 'OPEN_ASSISTANT') { - const data = JSON.parse(systemMessage.data); + const data = JSON.parse(systemMessage?.data || '{}'); const current_app = JSON.parse(meta.current_app); expect(data.is_first_session, 'Отправлен "is_first_session"').be.true; @@ -68,7 +69,7 @@ describe('Проверяем приветствие', () => { [{ disableGreetings: false, isFirstSession: false }], ({ messageName, systemMessage, meta }) => { if (messageName === 'OPEN_ASSISTANT') { - const data = JSON.parse(systemMessage.data); + const data = JSON.parse(systemMessage?.data || '{}'); const current_app = JSON.parse(meta.current_app); expect(data.is_first_session, 'Не отправлен "is_first_session"').be.eq(undefined); diff --git a/cypress/integration/listening.spec.ts b/cypress/integration/client.listening.spec.ts similarity index 100% rename from cypress/integration/listening.spec.ts rename to cypress/integration/client.listening.spec.ts diff --git a/cypress/integration/meta.spec.ts b/cypress/integration/client.meta.spec.ts similarity index 84% rename from cypress/integration/meta.spec.ts rename to cypress/integration/client.meta.spec.ts index 3a105710ee..0d02a1adc5 100644 --- a/cypress/integration/meta.spec.ts +++ b/cypress/integration/client.meta.spec.ts @@ -5,20 +5,22 @@ import { initAssistantClient } from '../support/helpers/init'; describe('Проверяем заполнение поля meta', () => { it('При подключении отправляется мета', (done) => { - const fieldName = "test_name"; + const fieldName = 'test_name'; const fieldValue = { field: 1 }; const client = initAssistantClient({ getInitialMeta: () => Promise.resolve({ [fieldName]: fieldValue }) }); - cy.mockVps((mes: Message) => { + cy.mockVps((mes: Message) => { if (mes.initialSettings) { assert.isOk('Конфигурационное сообщение'); expect(mes.meta, 'мета содержит поле из getMeta').to.have.ownProperty(fieldName); - expect(mes.meta[fieldName], 'Значение сериализовано и совпадает с исходным').to.be.eq(JSON.stringify(fieldValue)); - + expect(mes.meta[fieldName], 'Значение сериализовано и совпадает с исходным').to.be.eq( + JSON.stringify(fieldValue), + ); + done(); } }).then(() => { client.start(); }); - }); -}); \ No newline at end of file + }); +}); diff --git a/cypress/integration/refreshToken.spec.ts b/cypress/integration/client.refreshToken.spec.ts similarity index 99% rename from cypress/integration/refreshToken.spec.ts rename to cypress/integration/client.refreshToken.spec.ts index 49ea67f609..7c23fa3988 100644 --- a/cypress/integration/refreshToken.spec.ts +++ b/cypress/integration/client.refreshToken.spec.ts @@ -21,7 +21,7 @@ describe('Проверяем обновление токена', () => { server = initServer(); assistantClient = initAssistantClient({ settings: {}, - getToken: () => Promise.resolve(currentToken) + getToken: () => Promise.resolve(currentToken), }); assistantClient.on('status', (status) => { diff --git a/cypress/integration/client.requestPermissions.spec.ts b/cypress/integration/client.requestPermissions.spec.ts new file mode 100644 index 0000000000..39c6a638bf --- /dev/null +++ b/cypress/integration/client.requestPermissions.spec.ts @@ -0,0 +1,186 @@ +/* eslint-disable camelcase */ +/// + +import { Server } from 'mock-socket'; + +import { AppInfo, PermissionType, PermissionStatus } from '../../src'; +import { Message } from '../../src/proto'; +import { sendMessage } from '../support/helpers/socket'; +import { initServer, initAssistantClient } from '../support/helpers/init'; + +describe('Проверяем запросы доступов', () => { + const appInfo: AppInfo = { + projectId: 'test_projectId', + applicationId: 'test_applicationId', + appversionId: 'test_appversionId', + frontendType: 'WEB_APP', + }; + + const currentPosition = { coords: { latitude: 1.1, longitude: 2.2, accuracy: 1.0 }, time: 'test' }; + let getCurrentPosition = (_: (...args: unknown[]) => void, reject: () => void) => { + reject(); + }; + + let server: Server; + + const buildResponseServerAction = ({ + messageId, + permissions = [], + status = 'granted', + }: { + messageId: number; + permissions: PermissionType[]; + status?: PermissionStatus; + }) => ({ + action_id: 'command_response', + request_message_id: messageId, + command_response: { + request_permissions: { + permissions: permissions.map((perm) => ({ type: perm, status })), + }, + }, + }); + + beforeEach(() => { + server = initServer(); + cy.stub(window.navigator.geolocation, 'getCurrentPosition').callsFake((resolve, reject) => { + return getCurrentPosition(resolve, reject); + }); + }); + + afterEach(() => { + server?.stop(); + }); + + it('geo', (done) => { + // 0 - доступ закрыт + // 1 - доступ предоставлен + let phase = 0; + + server.on('connection', (socket) => { + assert.isOk('Соединение после старта'); + + socket.on('message', (data) => { + const message = Message.decode((data as Uint8Array).slice(4)); + + if (message.messageName === 'SERVER_ACTION') { + const d = JSON.parse(message.systemMessage?.data || '{}'); + + expect( + JSON.parse(message.meta?.current_app || '{}').app_info?.systemName, + 'в current_app текущий апп', + ).to.eq('assistant'); + expect(d.app_info, 'в systemMessage appInfo из запроса').to.deep.eq(appInfo); + + switch (phase) { + case 0: // в доступе отказано + expect(message.meta.location, 'location не заполнен в meta').to.be.undefined; + expect(d.server_action, 'Ответ заполнен').to.deep.eq( + buildResponseServerAction({ + messageId: 1, + permissions: ['geo'], + status: 'denied_permanently', + }), + ); + + phase = 1; + getCurrentPosition = (cb) => cb(currentPosition); + assert.isOk('Отправлен запрос геопозиции 2'); + sendMessage(socket, 2, { + systemMessageData: { + app_info: appInfo, + auto_listening: false, + items: [ + { + command: { + type: 'request_permissions', + permissions: ['geo'], + }, + }, + ], + }, + }); + break; + default: // доступ предоставлен + expect(JSON.parse(message.meta?.location || '{}'), 'координаты совпадают').to.deep.eq({ + lat: currentPosition.coords.latitude, + lon: currentPosition.coords.longitude, + accuracy: currentPosition.coords.accuracy, + }); + expect(d.server_action, 'Ответ заполнен').to.deep.eq( + buildResponseServerAction({ messageId: 2, permissions: ['geo'] }), + ); + done(); + break; + } + } + }); + + assert.isOk('Отправлен запрос геопозиции 1'); + sendMessage(socket, 1, { + systemMessageData: { + app_info: appInfo, + auto_listening: false, + items: [ + { + command: { + type: 'request_permissions', + permissions: ['geo'], + }, + }, + ], + }, + }); + }); + + const assistantClient = initAssistantClient({ settings: {} }); + assistantClient.reconnect(); + }); + + (['read_contacts', 'record_audio', 'push'] as PermissionType[]).map((type: PermissionType) => { + it(type, (done) => { + server.on('connection', (socket) => { + assert.isOk('Соединение после старта'); + + socket.on('message', (data) => { + const message = Message.decode((data as Uint8Array).slice(4)); + + if (message.messageName === 'SERVER_ACTION') { + const d = JSON.parse(message.systemMessage?.data || '{}'); + expect( + JSON.parse(message.meta?.current_app || '{}').app_info?.systemName, + 'в current_app текущий апп', + ).to.eq('assistant'); + expect(d.app_info, 'в systemMessage appInfo из запроса').to.deep.eq(appInfo); + expect(d.server_action, 'Ответ заполнен').to.deep.eq( + buildResponseServerAction({ + messageId: 1, + permissions: [type], + status: 'denied_permanently', + }), + ); + done(); + } + }); + + sendMessage(socket, 1, { + systemMessageData: { + app_info: appInfo, + auto_listening: false, + items: [ + { + command: { + type: 'request_permissions', + permissions: [type], + }, + }, + ], + }, + }); + }); + + const assistantClient = initAssistantClient({ settings: {} }); + assistantClient.reconnect(); + }); + }); +}); diff --git a/cypress/integration/resolveAudioContext.spec.ts b/cypress/integration/client.resolveAudioContext.spec.ts similarity index 100% rename from cypress/integration/resolveAudioContext.spec.ts rename to cypress/integration/client.resolveAudioContext.spec.ts diff --git a/cypress/integration/subscriptions.spec.ts b/cypress/integration/client.subscriptions.spec.ts similarity index 100% rename from cypress/integration/subscriptions.spec.ts rename to cypress/integration/client.subscriptions.spec.ts diff --git a/cypress/integration/requestPermissions.spec.ts b/cypress/integration/requestPermissions.spec.ts deleted file mode 100644 index 17d4e659b3..0000000000 --- a/cypress/integration/requestPermissions.spec.ts +++ /dev/null @@ -1,138 +0,0 @@ -/// - -import { Server } from 'mock-socket'; -import { AppInfo, PermissionType, PermissionStatus } from '../../src'; -import { Message } from '../../src/proto'; -import { sendMessage } from '../support/helpers/socket'; -import { initServer, initAssistantClient } from '../support/helpers/init'; - -describe('Проверяем запросы доступов', () => { - const appInfo: AppInfo = { - projectId: 'test_projectId', - applicationId: 'test_applicationId', - appversionId: 'test_appversionId', - frontendType: 'WEB_APP', - } - - const currentPosition = { coords: { latitude: 1.1, longitude: 2.2, accuracy: 1.0 }, time: 'test' }; - let getCurrentPosition = (_, reject) => { reject() }; - - let server: Server; - - const buildResponseServerAction = ({ messageId, permissions = [], status = 'granted' }: { messageId: number, permissions: PermissionType[], status?: PermissionStatus }) => ({ - action_id: 'command_response', - request_message_id: messageId, - command_response: { - request_permissions: { - permissions: permissions.map(perm => ({ type: perm, status })) - } - } - }); - - beforeEach(() => { - server = initServer(); - cy.stub(window.navigator.geolocation, 'getCurrentPosition').callsFake((resolve, reject) => { - return getCurrentPosition(resolve, reject); - }); - }); - - afterEach(() => { - server?.stop(); - }); - - it('geo', (done) => { - // 0 - доступ закрыт - // 1 - доступ предоставлен - let phase = 0; - - server.on('connection', (socket) => { - assert.isOk('Соединение после старта'); - - socket.on('message', (data) => { - const message = Message.decode((data as Uint8Array).slice(4)); - - if (message.messageName === 'SERVER_ACTION') { - const data = JSON.parse(message.systemMessage?.data || '{}'); - - expect(JSON.parse(message.meta?.current_app || '{}').app_info?.systemName, 'в current_app текущий апп').to.eq('assistant'); - expect(data.app_info, 'в systemMessage appInfo из запроса').to.deep.eq(appInfo); - - switch(phase) { - case 0: // в доступе отказано - expect(message.meta.location, 'location не заполнен в meta').to.be.undefined; - expect(data.server_action, 'Ответ заполнен').to.deep.eq(buildResponseServerAction({ messageId: 1, permissions: ['geo'], status: 'denied_permanently' })); - - phase = 1; - getCurrentPosition = (cb) => cb(currentPosition); - assert.isOk('Отправлен запрос геопозиции 2'); - sendMessage(socket, 2, { systemMessageData: { - app_info: appInfo, - auto_listening: false, - items: [{ - command: { - type: 'request_permissions', - permissions: ['geo'], - } - }], - } }); - break; - default: // доступ предоставлен - expect(JSON.parse(message.meta?.location || '{}'), 'координаты совпадают').to.deep.eq({ lat: currentPosition.coords.latitude, lon: currentPosition.coords.longitude, accuracy: currentPosition.coords.accuracy }); - expect(data.server_action, 'Ответ заполнен').to.deep.eq(buildResponseServerAction({ messageId: 2, permissions: ['geo'] })); - done(); - break; - } - } - }); - - assert.isOk('Отправлен запрос геопозиции 1'); - sendMessage(socket, 1, { systemMessageData: { - app_info: appInfo, - auto_listening: false, - items: [{ - command: { - type: 'request_permissions', - permissions: ['geo'], - } - }], - } }); - }) - - const assistantClient = initAssistantClient({ settings: {} }); - assistantClient.reconnect(); - }); - - (['read_contacts', 'record_audio', 'push'] as PermissionType[]).map((type: PermissionType) => { - it(type, (done) => { - server.on('connection', (socket) => { - assert.isOk('Соединение после старта'); - - socket.on('message', (data) => { - const message = Message.decode((data as Uint8Array).slice(4)); - - if (message.messageName === 'SERVER_ACTION') { - const data = JSON.parse(message.systemMessage?.data || '{}'); - expect(JSON.parse(message.meta?.current_app || '{}').app_info?.systemName, 'в current_app текущий апп').to.eq('assistant'); - expect(data.app_info, 'в systemMessage appInfo из запроса').to.deep.eq(appInfo); - expect(data.server_action, 'Ответ заполнен').to.deep.eq(buildResponseServerAction({ messageId: 1, permissions: [type], status: 'denied_permanently' })); - done(); - } - }); - - sendMessage(socket, 1, { systemMessageData: { - app_info: appInfo, - auto_listening: false, - items: [{ - command: { - type: 'request_permissions', - permissions: [type], - } - }], - } }); - }); - - const assistantClient = initAssistantClient({ settings: {} }); - assistantClient.reconnect(); - }); - }); -}); \ No newline at end of file diff --git a/cypress/support/commands.ts b/cypress/support/commands.ts index 8fd86a9691..79c1ebc81a 100644 --- a/cypress/support/commands.ts +++ b/cypress/support/commands.ts @@ -1,9 +1,11 @@ import { Server } from 'mock-socket'; +import { AssistantWindow } from '../../src/typings'; import { Message } from '../../src/proto'; declare global { - // eslint-disable-next-line @typescript-eslint/no-namespace + interface Window extends AssistantWindow {} + namespace Cypress { interface Chainable { mockVps: typeof mockVps; @@ -22,6 +24,6 @@ const mockVps = (onMessage: (message: Message) => void) => { }); return cy.wrap(server); -} +}; -Cypress.Commands.add('mockVps', { prevSubject: false }, mockVps); \ No newline at end of file +Cypress.Commands.add('mockVps', { prevSubject: false }, mockVps); diff --git a/src/createAssistant.ts b/src/createAssistant.ts index 6296463924..c0fd16c347 100644 --- a/src/createAssistant.ts +++ b/src/createAssistant.ts @@ -15,7 +15,6 @@ import { AssistantEvents, AssistantClientCommandEvents, SendDataParams, - AssistantServerAction, } from './typings'; import { createNanoEvents } from './nanoevents'; import { createNanoObservable, ObserverFunc } from './nanoobservable';