diff --git a/__tests__/happy.localeOnStartConversation.js b/__tests__/happy.localeOnStartConversation.js new file mode 100644 index 000000000..5f5e9d398 --- /dev/null +++ b/__tests__/happy.localeOnStartConversation.js @@ -0,0 +1,88 @@ +import 'dotenv/config'; + +import onErrorResumeNext from 'on-error-resume-next'; + +import { timeouts } from './constants.json'; +import * as createDirectLine from './setup/createDirectLine'; +import waitForBotToRespond from './setup/waitForBotToRespond'; + +describe('Happy path', () => { + let unsubscribes; + + beforeEach(() => unsubscribes = []); + afterEach(() => unsubscribes.forEach(fn => onErrorResumeNext(fn))); + + describe('should receive the welcome message from bot in English', () => { + let directLine; + + describe('using REST', () => { + beforeEach(() => jest.setTimeout(timeouts.rest)); + + test('without conversation start properties', async () => { + directLine = await createDirectLine.forREST({ token: true }); + }); + + test('without locale in conversation start properties', async () => { + directLine = await createDirectLine.forREST({ token: true }, { conversationStartProperties: {} }); + }); + + test('with locale "en-US" in conversation start properties', async () => { + directLine = await createDirectLine.forREST({ token: true }, { conversationStartProperties: { locale: 'en-US' } }); + }); + }); + + describe('using Web Socket', () => { + beforeEach(() => jest.setTimeout(timeouts.webSocket)); + + test('without conversation start properties', async () => { + directLine = await createDirectLine.forWebSocket({ token: true }); + }); + + test('without locale in conversation start properties', async () => { + directLine = await createDirectLine.forWebSocket({ token: true }, { conversationStartProperties: {} }); + }); + + test('with locale "en-US" in conversation start properties', async () => { + directLine = await createDirectLine.forWebSocket({ token: true }, { conversationStartProperties: { locale: 'en-US' } }); + }); + }); + + afterEach(async () => { + // If directLine object is undefined, that means the test is failing. + if (!directLine) { return; } + + unsubscribes.push(directLine.end.bind(directLine)); + + await waitForBotToRespond(directLine, ({ text }) => text === 'Welcome'); + }); + }); + + describe('should receive the welcome message from bot in Chinese', () => { + let directLine; + + describe('using REST', () => { + beforeEach(() => jest.setTimeout(timeouts.rest)); + + test('with locale "zh-CN" in conversation start properties', async () => { + directLine = await createDirectLine.forREST({ token: true }, { conversationStartProperties: { locale: 'zh-CN' } }); + }); + }); + + describe('using Web Socket', () => { + beforeEach(() => jest.setTimeout(timeouts.webSocket)); + + test('with locale "zh-CN" in conversation start properties', async () => { + directLine = await createDirectLine.forWebSocket({ token: true }, { conversationStartProperties: { locale: 'zh-CN' } }); + }); + }); + + afterEach(async () => { + // If directLine object is undefined, that means the test is failing. + if (!directLine) { return; } + + unsubscribes.push(directLine.end.bind(directLine)); + + await waitForBotToRespond(directLine, ({ text }) => text === '欢迎'); + }); + }); +}); diff --git a/__tests__/happy.receiveAttachmentStreams.js b/__tests__/happy.receiveAttachmentStreams.js index 0cde94354..ce29337b7 100644 --- a/__tests__/happy.receiveAttachmentStreams.js +++ b/__tests__/happy.receiveAttachmentStreams.js @@ -31,8 +31,8 @@ describe('Happy path', () => { unsubscribes.push(directLine.end.bind(directLine)); unsubscribes.push(await waitForConnected(directLine)); - let url1 = 'http://myasebot.azurewebsites.net/177KB.jpg'; - let url2 = 'http://myasebot.azurewebsites.net/100KB.jpg'; + let url1 = 'http://dljstestbot.azurewebsites.net/177KB.jpg'; + let url2 = 'http://dljstestbot.azurewebsites.net/100KB.jpg'; const activityFromUser = { text: 'attach ' + url1 + ' ' + url2, diff --git a/__tests__/happy.uploadAttachmentStreams.js b/__tests__/happy.uploadAttachmentStreams.js index a8240d885..386452d6f 100644 --- a/__tests__/happy.uploadAttachmentStreams.js +++ b/__tests__/happy.uploadAttachmentStreams.js @@ -34,10 +34,10 @@ describe('Happy path', () => { // DirectLine.postActivityWithAttachments support "contentUrl" only but not "content" attachments: [{ contentType: 'image/jpg', - contentUrl: 'http://myasebot.azurewebsites.net/177KB.jpg' + contentUrl: 'http://dljstestbot.azurewebsites.net/177KB.jpg' }, { contentType: 'image/jpg', - contentUrl: 'http://myasebot.azurewebsites.net/100KB.jpg' + contentUrl: 'http://dljstestbot.azurewebsites.net/100KB.jpg' }], text: 'Hello, World!', type: 'message', diff --git a/__tests__/happy.uploadAttachments.js b/__tests__/happy.uploadAttachments.js index f61d44193..9e9ff6c7d 100644 --- a/__tests__/happy.uploadAttachments.js +++ b/__tests__/happy.uploadAttachments.js @@ -53,11 +53,11 @@ describe('Happy path', () => { // DirectLine.postActivityWithAttachments support "contentUrl" only but not "content" attachments: [{ contentType: 'image/jpg', - contentUrl: 'http://myasebot.azurewebsites.net/177KB.jpg', + contentUrl: 'http://dljstestbot.azurewebsites.net/177KB.jpg', thumbnailUrl: 'data:image/png;base64,===177KB.jpg' }, { contentType: 'image/png', - contentUrl: 'http://myasebot.azurewebsites.net/100KB.jpg', + contentUrl: 'http://dljstestbot.azurewebsites.net/100KB.jpg', thumbnailUrl: 'data:image/png;base64,===100KB.jpb' }], text: 'Hello, World!', diff --git a/__tests__/setup/createDirectLine.js b/__tests__/setup/createDirectLine.js index 5812a5f8b..e99bc77a9 100644 --- a/__tests__/setup/createDirectLine.js +++ b/__tests__/setup/createDirectLine.js @@ -6,13 +6,13 @@ import { DirectLineStreaming } from '../../src/directLineStreaming'; const { DIRECT_LINE_SECRET, - STREAMING_EXTENSIONS_DOMAIN = 'https://myasebot.azurewebsites.net/.bot/v3/directline' + STREAMING_EXTENSIONS_DOMAIN = 'https://dljstestbot.azurewebsites.net/.bot/v3/directline' } = process.env; const DEFAULT_DOMAIN = 'https://directline.botframework.com/v3/directline'; async function fetchDirectLineToken() { - const res = await fetch('https://myasebot.azurewebsites.net/token/directline'); + const res = await fetch('https://dljstestbot.azurewebsites.net/token/directline'); if (res.ok) { return await res.json(); @@ -22,7 +22,7 @@ async function fetchDirectLineToken() { } async function fetchDirectLineStreamingExtensionsToken() { - const res = await fetch(`https://myasebot.azurewebsites.net/token/directlinease`); + const res = await fetch(`https://dljstestbot.azurewebsites.net/token/directlinease`); if (res.ok) { return await res.json(); diff --git a/__tests__/unhappy.invalidLocaleOnStartConversation.js b/__tests__/unhappy.invalidLocaleOnStartConversation.js new file mode 100644 index 000000000..d251078c2 --- /dev/null +++ b/__tests__/unhappy.invalidLocaleOnStartConversation.js @@ -0,0 +1,43 @@ +import 'dotenv/config'; + +import onErrorResumeNext from 'on-error-resume-next'; + +import { timeouts } from './constants.json'; +import * as createDirectLine from './setup/createDirectLine'; +import waitForBotToRespond from './setup/waitForBotToRespond'; + +describe('Unhappy path', () => { + let unsubscribes; + + beforeEach(() => unsubscribes = []); + afterEach(() => unsubscribes.forEach(fn => onErrorResumeNext(fn))); + + describe('should receive the welcome message from bot in English', () => { + let directLine; + + describe('using REST', () => { + beforeEach(() => jest.setTimeout(timeouts.rest)); + + test('with invalid locale in conversation start properties', async () => { + directLine = await createDirectLine.forREST({ token: true }, { conversationStartProperties: { locale: { x: 'test' } } }); + }); + }); + + describe('using Web Socket', () => { + beforeEach(() => jest.setTimeout(timeouts.webSocket)); + + test('with invalid locale in conversation start properties', async () => { + directLine = await createDirectLine.forWebSocket({ token: true }, { conversationStartProperties: { locale: { x: 'test' } } }); + }); + }); + + afterEach(async () => { + // If directLine object is undefined, that means the test is failing. + if (!directLine) { return; } + + unsubscribes.push(directLine.end.bind(directLine)); + + await waitForBotToRespond(directLine, ({ text }) => text === 'Welcome'); + }); + }); +}); diff --git a/src/directLine.ts b/src/directLine.ts index b50a29055..5545ab1c1 100644 --- a/src/directLine.ts +++ b/src/directLine.ts @@ -370,7 +370,8 @@ export interface DirectLineOptions { streamUrl?: string, timeout?: number, // Attached to all requests to identify requesting agent. - botAgent?: string + botAgent?: string, + conversationStartProperties?: any } export interface Services { @@ -469,6 +470,8 @@ export class DirectLine implements IBotConnection { private timeout = 20 * 1000; private retries: number; + private localeOnStartConversation: string; + private pollingInterval: number = 1000; //ms private tokenRefreshSubscription: Subscription; @@ -478,6 +481,14 @@ export class DirectLine implements IBotConnection { this.token = options.secret || options.token; this.webSocket = (options.webSocket === undefined ? true : options.webSocket) && typeof WebSocket !== 'undefined' && WebSocket !== undefined; + if (options.conversationStartProperties && options.conversationStartProperties.locale) { + if (Object.prototype.toString.call(options.conversationStartProperties.locale) === '[object String]') { + this.localeOnStartConversation = options.conversationStartProperties.locale; + } else { + console.warn('DirectLineJS: conversationStartProperties.locale was ignored: the locale name may be a BCP 47 language tag'); + } + } + if (options.domain) { this.domain = options.domain; } @@ -616,12 +627,19 @@ export class DirectLine implements IBotConnection { ? `${this.domain}/conversations/${this.conversationId}?watermark=${this.watermark}` : `${this.domain}/conversations`; const method = this.conversationId ? "GET" : "POST"; + const body = this.conversationId + ? undefined + : { + locale: this.localeOnStartConversation + }; return this.services.ajax({ method, url, + body, timeout: this.timeout, headers: { "Accept": "application/json", + "Content-Type": "application/json", ...this.commonHeaders() } })