Skip to content

Commit

Permalink
Merge 0272212 into 4422c69
Browse files Browse the repository at this point in the history
  • Loading branch information
tonyanziano committed Apr 29, 2019
2 parents 4422c69 + 0272212 commit 008593c
Show file tree
Hide file tree
Showing 5 changed files with 185 additions and 25 deletions.
131 changes: 107 additions & 24 deletions packages/app/client/src/data/sagas/botSagas.spec.ts
Expand Up @@ -31,7 +31,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

import { newNotification, SharedConstants } from '@bfemulator/app-shared';
import { newNotification, SharedConstants, DebugMode } from '@bfemulator/app-shared';
import { BotConfigWithPath, ConversationService } from '@bfemulator/sdk-shared';
import { call, put, select, takeEvery, takeLatest } from 'redux-saga/effects';

Expand All @@ -45,6 +45,7 @@ import {
} from '../action/botActions';
import { beginAdd } from '../action/notificationActions';
import { generateHash } from '../botHelpers';
import { CommandServiceImpl } from '../../platform/commands/commandServiceImpl';

import { botSagas, browseForBot, generateHashForActiveBot, openBotViaFilePath, openBotViaUrl } from './botSagas';
import { refreshConversationMenu } from './sharedSagas';
Expand Down Expand Up @@ -173,32 +174,19 @@ describe('The botSagas', () => {
endpoint: 'http://localhost/api/messages',
})
);
const io = select(() => void 0);
io.SELECT.selector = jasmine.any(Function) as any;
gen.next();
// select serverUrl
expect(gen.next().value).toEqual(io);
// select user
const selectUser = gen.next().value as any;
expect(selectUser).toEqual(io);
gen.next('www.serverurl.com');
// select users
const users = { currentUserId: 'user1', usersById: { user1: {} } };
gen.next(users);
// call ConversationService.startConversation
jest.spyOn(ConversationService, 'startConversation').mockResolvedValue(true);
expect(
gen.next(
selectUser.SELECT.selector({
clientAwareSettings: {
users: {
currentUserId: '1',
usersById: { '1': {} },
},
},
})
).value
).not.toBeNull();
gen.next({ ok: false, statusText: 'oh noes!' });
const errorNotification = beginAdd(
newNotification('An Error occurred opening the bot at http://localhost/api/messages: oh noes!')
);
errorNotification.payload.notification.timestamp = jasmine.any(Number);
errorNotification.payload.notification.id = jasmine.any(String);
(errorNotification as any).payload.notification.timestamp = jasmine.any(Number);
(errorNotification as any).payload.notification.id = jasmine.any(String);
expect(
gen.next({
statusText: 'oh noes!',
Expand All @@ -207,6 +195,101 @@ describe('The botSagas', () => {
).toEqual(put(errorNotification));
});

it('should send the "/INSPECT open" command when in debug mode and opening from url', () => {
const gen = openBotViaUrl(
openBotViaUrlAction({
appPassword: 'password',
appId: '1234abcd',
endpoint: 'http://localhost/api/messages',
})
);
gen.next();
// select serverUrl
gen.next('www.serverurl.com');
// select users
const users = { currentUserId: 'user1', usersById: { user1: {} } };
gen.next(users);
// startConversation
gen.next({ ok: true, json: async () => null });
// select debug mode
gen.next(DebugMode.Sidecar);
// response.json from starting conversation
const postActivityResponse = gen.next({ id: 'someConversationId' }).value;
// posting activity to conversation
const activity = {
type: 'message',
text: '/INSPECT open',
};
expect(postActivityResponse).toEqual(
call(
[CommandServiceImpl, CommandServiceImpl.remoteCall],
SharedConstants.Commands.Emulator.PostActivityToConversation,
'someConversationId',
activity
)
);
// the response from POSTing to the conversation should end the saga
expect(gen.next({ statusCode: 200 }).done).toBe(true);
});

it('should spawn a notification if posting the "/INSPECT open" command fails', () => {
const gen = openBotViaUrl(
openBotViaUrlAction({
appPassword: 'password',
appId: '1234abcd',
endpoint: 'http://localhost/api/messages',
})
);
gen.next();
// select serverUrl
gen.next('www.serverurl.com');
// select users
const users = { currentUserId: 'user1', usersById: { user1: {} } };
gen.next(users);
// startConversation
gen.next({ ok: true, json: async () => null });
// select debug mode
gen.next(DebugMode.Sidecar);
// response.json from starting conversation
gen.next({ id: 'someConversationId' });
// POSTing to the conversation should return a 400
const errorNotification = beginAdd(
newNotification('An error occurred while POSTing "/INSPECT open" command to conversation someConversationId')
);
(errorNotification as any).payload.notification.timestamp = jasmine.any(Number);
(errorNotification as any).payload.notification.id = jasmine.any(String);
expect(gen.next({ statusCode: 400 }).value).toEqual(put(errorNotification));
});

it('should spawn a notification if parsing the conversation id from the response fails', () => {
const gen = openBotViaUrl(
openBotViaUrlAction({
appPassword: 'password',
appId: '1234abcd',
endpoint: 'http://localhost/api/messages',
})
);
gen.next();
// select serverUrl
gen.next('www.serverurl.com');
// select users
const users = { currentUserId: 'user1', usersById: { user1: {} } };
gen.next(users);
// startConversation
gen.next({ ok: true, json: async () => null });
// select debug mode
gen.next(DebugMode.Sidecar);
// response.json from starting conversation
const startConversationResponse = gen.next({ id: undefined }).value;
// POSTing to the conversation should return a 400
const errorNotification = beginAdd(
newNotification('An error occurred while trying to grab conversation ID from new conversation.')
);
(errorNotification as any).payload.notification.timestamp = jasmine.any(Number);
(errorNotification as any).payload.notification.id = jasmine.any(String);
expect(startConversationResponse).toEqual(put(errorNotification));
});

it('should open a bot from a file path', () => {
const gen = openBotViaFilePath(openBotViaFilePathAction('/some/path.bot'));

Expand All @@ -224,8 +307,8 @@ describe('The botSagas', () => {
const errorNotification = beginAdd(
newNotification('An Error occurred opening the bot at /some/path.bot: Error: oh noes!')
);
errorNotification.payload.notification.timestamp = jasmine.any(Number);
errorNotification.payload.notification.id = jasmine.any(String);
(errorNotification as any).payload.notification.timestamp = jasmine.any(Number);
(errorNotification as any).payload.notification.id = jasmine.any(String);
expect(putNotification.value).toEqual(put(errorNotification));
});
});
27 changes: 26 additions & 1 deletion packages/app/client/src/data/sagas/botSagas.ts
Expand Up @@ -31,7 +31,7 @@
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//

import { newNotification, UserSettings } from '@bfemulator/app-shared';
import { DebugMode, newNotification, SharedConstants, UserSettings } from '@bfemulator/app-shared';
import { ConversationService, StartConversationParams } from '@bfemulator/sdk-shared';
import { call, ForkEffect, put, select, takeEvery, takeLatest } from 'redux-saga/effects';

Expand All @@ -40,6 +40,7 @@ import { BotAction, BotActionType, BotConfigWithPathPayload, botHashGenerated }
import { beginAdd } from '../action/notificationActions';
import { generateHash } from '../botHelpers';
import { RootState } from '../store';
import { CommandServiceImpl } from '../../platform/commands/commandServiceImpl';

import { refreshConversationMenu } from './sharedSagas';

Expand Down Expand Up @@ -76,6 +77,30 @@ export function* openBotViaUrl(action: BotAction<Partial<StartConversationParams
if (!response.ok) {
error = `An Error occurred opening the bot at ${action.payload.endpoint}: ${response.statusText}`;
}
const debugMode = yield select((state: RootState) => state.clientAwareSettings.debugMode);
if (debugMode === DebugMode.Sidecar) {
// extract the conversation id from the body
const parsedBody = yield response.json();
const conversationId = parsedBody.id || '';
if (conversationId) {
// post debug init command to conversation
const activity = {
type: 'message',
text: '/INSPECT open',
};
const postActivityResponse = yield call(
[CommandServiceImpl, CommandServiceImpl.remoteCall],
SharedConstants.Commands.Emulator.PostActivityToConversation,
conversationId,
activity
);
if (postActivityResponse.statusCode >= 400) {
throw new Error(`An error occurred while POSTing "/INSPECT open" command to conversation ${conversationId}`);
}
} else {
throw new Error('An error occurred while trying to grab conversation ID from new conversation.');
}
}
} catch (e) {
error = e.message;
}
Expand Down
35 changes: 35 additions & 0 deletions packages/app/main/src/commands/emulatorCommands.spec.ts
Expand Up @@ -111,6 +111,7 @@ const mockEmulator = {
facilities: {
logger: {
logActivity: () => true,
logMessage: () => true,
},
conversations: {
conversationById: () => mockConversation,
Expand All @@ -129,6 +130,7 @@ const mockEmulator = {
mockUsers = users;
},
},
getServiceUrl: () => 'http://localhost:6728',
},
},
},
Expand Down Expand Up @@ -522,4 +524,37 @@ describe('The emulatorCommands', () => {
.handler('chats/myChat.chat');
expect(result).toEqual({ activities: [], fileName: 'myChat.chat' });
});

it('should post an activity to the bot in a conversation', async () => {
mockConversation.botEndpoint = {
fetchWithAuth: async () => ({
status: 200,
}),
} as any;
const postActivitySpy = jest.spyOn(mockConversation, 'postActivityToBot');
const activity = { type: 'message', text: 'I am an activity!', id: 'someId' };
const result = await mockCommandRegistry
.getCommand(SharedConstants.Commands.Emulator.PostActivityToConversation)
.handler(mockConversation.conversationId, activity, false);

expect(result.activityId).toBe('someId');
expect(result.statusCode).toBe(200);
expect(postActivitySpy).toHaveBeenCalled();
});

it('should post an activity to the user in a conversation', async () => {
mockConversation.botEndpoint = {
fetchWithAuth: async () => ({
status: 200,
}),
} as any;
const postActivitySpy = jest.spyOn(mockConversation, 'postActivityToUser');
const activity = { type: 'message', text: 'I am an activity!', id: 'someId', from: {} };
const result = await mockCommandRegistry
.getCommand(SharedConstants.Commands.Emulator.PostActivityToConversation)
.handler(mockConversation.conversationId, activity, true);

expect(result.id).toBe('someId');
expect(postActivitySpy).toHaveBeenCalled();
});
});
16 changes: 16 additions & 0 deletions packages/app/main/src/commands/emulatorCommands.ts
Expand Up @@ -240,4 +240,20 @@ export function registerCommands(commandRegistry: CommandRegistryImpl) {
conversationId
);
});

// ---------------------------------------------------------------------------
// Removes the conversation from the conversation set
commandRegistry.registerCommand(
Commands.PostActivityToConversation,
(conversationId: string, activity: any, toUser: boolean) => {
const conversation = Emulator.getInstance().framework.server.botEmulator.facilities.conversations.conversationById(
conversationId
);
if (toUser) {
return conversation.postActivityToUser(activity, false);
} else {
return conversation.postActivityToBot(activity, false);
}
}
);
}
1 change: 1 addition & 0 deletions packages/app/shared/src/constants/sharedConstants.ts
Expand Up @@ -106,6 +106,7 @@ export const SharedConstants = {
AppendToLog: 'log:append',
SetCurrentUser: 'emulator:set-current-user',
DeleteConversation: 'emulator:delete-conversation',
PostActivityToConversation: 'emulator:post-activity',
},

Extension: {
Expand Down

0 comments on commit 008593c

Please sign in to comment.