diff --git a/.github/HowToQuestions.md b/.github/HowToQuestions.md index c6b69ff47c..c3b5c83498 100644 --- a/.github/HowToQuestions.md +++ b/.github/HowToQuestions.md @@ -1,5 +1,5 @@ Please feel free to peruse our [samples](https://github.com/Microsoft/BotFramework-WebChat/tree/master/samples), which provide a lot of ideas and foundation for customizing your version of Web Chat. -'How to' questions such as this one are better suited for [Stack Overflow](https://stackoverflow.com/tags/botframework). Please feel free to post other questions you have about developing your own features over there so the community at large may help out. Thank you! +'How to' questions such as this one are better suited for [Stack Overflow](https://stackoverflow.com/tags/botframework). Please feel free to post other questions you have about developing your own features over there so the community at large may help out. If you need help with a Web Chat implementation, you can post a question to the [Web Chat tag](https://stackoverflow.com/questions/tagged/web-chat). Thank you! Please share the link to your Stack Overflow question on this issue. The Web Chat team will close this issue after a week of inactivity or when the Stack Overflow link has been added. diff --git a/CHANGELOG.md b/CHANGELOG.md index 24b81cdcbd..21dabcbb87 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Fix [#1877](https://github.com/Microsoft/BotFramework-WebChat/issues/1877). Add viewport meta tag and fix a few sample links, by [@corinagum](https://github.com/corinagum) in PR [#1919](https://github.com/Microsoft/BotFramework-WebChat/pull/1919) - Fix [#1789](https://github.com/Microsoft/BotFramework-WebChat/issues/1789). Focus send box after message is being sent, by [@corinagum](https://github.com/corinagum) in PR [#1915](https://github.com/Microsoft/BotFramework-WebChat/pull/1915) - Fix [#1920](https://github.com/Microsoft/BotFramework-WebChat/issues/1920). Added disabled property to send button, by [@tdurnford](https://github.com/tdurnford) in PR [#1922](https://github.com/Microsoft/BotFramework-WebChat/pull/1922) +- Fix [#1525](https://github.com/Microsoft/BotFramework-WebChat/issues/1525). Add JavaScript error Offline UI, by [@corinagum](https://github.com/corinagum) in PR [#1927](https://github.com/Microsoft/BotFramework-WebChat/pull/1927) ### Changed - Deployment: Bumps to [`blobxfer@1.7.1`](https://github.com/azure/blobxfer/), by [@compulim](https://github.com/compulim), in PR [#1897](https://github.com/Microsoft/BotFramework-WebChat/pull/1897) diff --git a/README.md b/README.md index 95629663c4..e38c726f69 100644 --- a/README.md +++ b/README.md @@ -280,6 +280,7 @@ There are several properties that you might pass into your Web Chat React Compon | `attachmentMiddleware` | A chain of middleware that allows the developer to add their own custom HTML Elements on attachments. The signature is the following: `options => next => card => next(card)`. | | `attachmentRenderer` | The "flattened" version of `attachmentMiddleware`. | | `cardActionMiddleware` | A chain of middleware that allows the developer to modify card actions, like Adaptive Cards or suggested actions. The middleware signature is the following: `cardActionMiddleware: () => next => ({ cardAction, getSignInUrl }) => next(cardAction)` | +| `createStore` | A chain of middleware that allows the developer to modify the store actions. The middleware signature is the following: `createStore: ({}, ({ dispatch }) => next => action => next(cardAction)` | | `directLine` | Specify the DirectLine object with DirectLine token. | | `disabled` | Disable the UI (i.e. for presentation mode) of Web Chat. | | `grammars` | Specify a grammar list for Speech (Bing Speech or Cognitive Services Speech Services). | diff --git a/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-network-interruption-occurred-reconnecting-status-when-connection-is-interrupted-1-snap.png b/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-network-interruption-occurred-reconnecting-status-when-connection-is-interrupted-1-snap.png index 3ddfe723b3..9df5649f30 100644 Binary files a/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-network-interruption-occurred-reconnecting-status-when-connection-is-interrupted-1-snap.png and b/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-network-interruption-occurred-reconnecting-status-when-connection-is-interrupted-1-snap.png differ diff --git a/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-the-connecting-connectivity-status-when-connecting-for-the-first-time-1-snap.png b/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-the-connecting-connectivity-status-when-connecting-for-the-first-time-1-snap.png index 2299115761..38358560c0 100644 Binary files a/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-the-connecting-connectivity-status-when-connecting-for-the-first-time-1-snap.png and b/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-display-the-connecting-connectivity-status-when-connecting-for-the-first-time-1-snap.png differ diff --git a/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-show-render-error-connectivity-status-when-a-java-script-error-is-present-in-the-code-1-snap.png b/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-show-render-error-connectivity-status-when-a-java-script-error-is-present-in-the-code-1-snap.png new file mode 100644 index 0000000000..89692b2332 Binary files /dev/null and b/__tests__/__image_snapshots__/chrome-docker/offline-ui-js-offline-ui-should-show-render-error-connectivity-status-when-a-java-script-error-is-present-in-the-code-1-snap.png differ diff --git a/__tests__/basic.js b/__tests__/basic.js index 6971d6b9e8..d3836eb935 100644 --- a/__tests__/basic.js +++ b/__tests__/basic.js @@ -13,7 +13,7 @@ test('setup', async () => { const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout carousel'); + await pageObjects.sendMessageViaSendBox('layout carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), 2000); await driver.wait(allImagesLoaded(), 2000); @@ -27,7 +27,7 @@ test('long URLs with break-word', async () => { const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('https://subdomain.domain.com/pathname0/pathname1/pathname2/pathname3/pathname4/') + await pageObjects.sendMessageViaSendBox('https://subdomain.domain.com/pathname0/pathname1/pathname2/pathname3/pathname4/', { waitForSend: true }) await driver.wait(minNumActivitiesShown(2), 2000); await driver.wait(allImagesLoaded(), 2000); @@ -43,7 +43,7 @@ test('long URLs with break-all', async () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('https://subdomain.domain.com/pathname0/pathname1/pathname2/pathname3/pathname4/') + await pageObjects.sendMessageViaSendBox('https://subdomain.domain.com/pathname0/pathname1/pathname2/pathname3/pathname4/', { waitForSend: true }) await driver.wait(minNumActivitiesShown(2), 2000); await driver.wait(allImagesLoaded(), 2000); @@ -58,7 +58,7 @@ test('long URLs with keep-all', async () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS }); - await pageObjects.sendMessageViaSendBox('箸より重いものを持ったことがない箸より重いものを持ったことがない'); + await pageObjects.sendMessageViaSendBox('箸より重いものを持ったことがない箸より重いものを持ったことがない', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), 2000); await driver.wait(allImagesLoaded(), 2000); @@ -72,7 +72,7 @@ test('unknown activities do not render anything in the transcript', async () => const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('unknown activity'); + await pageObjects.sendMessageViaSendBox('unknown activity', { waitForSend: true }); await driver.wait(minNumActivitiesShown(1), 2000); diff --git a/__tests__/cardActionMiddleware.js b/__tests__/cardActionMiddleware.js index 83582ecf8e..df8577ba5f 100644 --- a/__tests__/cardActionMiddleware.js +++ b/__tests__/cardActionMiddleware.js @@ -29,7 +29,7 @@ test('card action "openUrl"', async () => { }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('card-actions'); + await pageObjects.sendMessageViaSendBox('card-actions', { waitForSend: true }); await driver.wait(suggestedActionsShowed(), timeouts.directLine); @@ -65,7 +65,7 @@ test('card action "signin"', async () => { }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('oauth'); + await pageObjects.sendMessageViaSendBox('oauth', { waitForSend: true }); const openUrlButton = await driver.findElement(By.css('[role="log"] ul > li button')); diff --git a/__tests__/carousel.js b/__tests__/carousel.js index 10ce67f954..d9d796b69c 100644 --- a/__tests__/carousel.js +++ b/__tests__/carousel.js @@ -16,7 +16,7 @@ describe('carousel without avatar initials', () => { const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('carousel'); + await pageObjects.sendMessageViaSendBox('carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -40,7 +40,7 @@ describe('carousel without avatar initials', () => { const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout carousel'); + await pageObjects.sendMessageViaSendBox('layout carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -64,7 +64,7 @@ describe('carousel without avatar initials', () => { const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout double'); + await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -76,7 +76,7 @@ describe('carousel without avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ width: 640 }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout double'); + await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -88,7 +88,7 @@ describe('carousel without avatar initials', () => { const { driver, pageObjects } = await setupWebDriver(); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout single carousel'); + await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -100,7 +100,7 @@ describe('carousel without avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ width: 640 }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout single carousel'); + await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -116,7 +116,7 @@ describe('carousel with avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('carousel'); + await pageObjects.sendMessageViaSendBox('carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -140,7 +140,7 @@ describe('carousel with avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout carousel'); + await pageObjects.sendMessageViaSendBox('layout carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -164,7 +164,7 @@ describe('carousel with avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout double'); + await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -176,7 +176,7 @@ describe('carousel with avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS, width: 640 }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout double'); + await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -188,7 +188,7 @@ describe('carousel with avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout single carousel'); + await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); @@ -200,7 +200,7 @@ describe('carousel with avatar initials', () => { const { driver, pageObjects } = await setupWebDriver({ props: WEB_CHAT_PROPS, width: 640 }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('layout single carousel'); + await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await driver.wait(allImagesLoaded(), timeouts.fetch); diff --git a/__tests__/offlineUI.js b/__tests__/offlineUI.js index 83a9575720..101802acd7 100644 --- a/__tests__/offlineUI.js +++ b/__tests__/offlineUI.js @@ -1,6 +1,8 @@ import { By, Condition, Key } from 'selenium-webdriver'; import { imageSnapshotOptions, timeouts } from './constants.json'; +import actionDispatched from './setup/conditions/actionDispatched'; +import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; import staticSpinner from './setup/assets/staticSpinner'; import uiConnected from './setup/conditions/uiConnected'; @@ -19,12 +21,9 @@ const allOutgoingMessagesFailed = new Condition('All outgoing messages to fail s }); describe('offline UI', async () => { - test('should show "taking longer than usual to connect" UI when connection is slow', async () => { - - const WEB_CHAT_PROPS = { spinnerAnimationBackgroundImage: staticSpinner }; + test('should show "Taking longer than usual to connect" UI when connection is slow', async () => { const { driver } = await setupWebDriver({ - props: { WEB_CHAT_PROPS }, createDirectLine: options => { // This part of code is running in the JavaScript VM in Chromium. // This variable must be declared within scope @@ -50,17 +49,25 @@ describe('offline UI', async () => { }; }, pingBotOnLoad: false, - setup: () => new Promise(resolve => { - const scriptElement = document.createElement('script'); + setup: () => + Promise.all([ + window.WebChatTest.loadScript('https://unpkg.com/core-js@2.6.3/client/core.min.js'), + window.WebChatTest.loadScript('https://unpkg.com/lolex@4.0.1/lolex.js'), + ]).then(() => { + window.WebChatTest.clock = lolex.install(); + }) + }); - scriptElement.onload = resolve; - scriptElement.setAttribute('src', 'https://unpkg.com/core-js@2.6.3/client/core.min.js'); + await driver.executeScript(() => { + window.WebChatTest.clock.tick(400); // "Connecting" will be gone after 400ms, turning into "Taking longer than usual to connect" + window.WebChatTest.clock.tick(14600); // Go to t=15s + }); - document.head.appendChild(scriptElement); - }) + await driver.executeScript(() => { + window.WebChatTest.clock.tick(1); // Shortly after 15s, it will show "Taking longer than usual to connect" }); - await driver.sleep(15000); + await driver.wait(actionDispatched('DIRECT_LINE/CONNECT_STILL_PENDING'), timeouts.directLine); const base64PNG = await driver.takeScreenshot(); @@ -186,11 +193,10 @@ describe('offline UI', async () => { }); test('should display the "Connecting..." connectivity status when connecting for the first time', async() => { - const WEB_CHAT_PROPS = { spinnerAnimationBackgroundImage: staticSpinner }; + const WEB_CHAT_PROPS = { styleOptions: { spinnerAnimationBackgroundImage: staticSpinner } }; const { driver } = await setupWebDriver({ - props: WEB_CHAT_PROPS, - createDirectline: options => { + createDirectLine: options => { // This part of code is running in the JavaScript VM in Chromium. // This Direct Line Connection Status variable must be declared within scope const UNINITIALIZED = 0; @@ -215,6 +221,7 @@ describe('offline UI', async () => { }; }, pingBotOnLoad: false, + props: WEB_CHAT_PROPS, setup: () => new Promise(resolve => { const scriptElement = document.createElement('script'); @@ -227,14 +234,14 @@ describe('offline UI', async () => { }); const base64PNG = await driver.takeScreenshot(); + expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions); }); test('should display "Network interruption occurred. Reconnecting…" status when connection is interrupted', async () => { - const WEB_CHAT_PROPS = { spinnerAnimationBackgroundImage: staticSpinner }; + const WEB_CHAT_PROPS = { styleOptions: { spinnerAnimationBackgroundImage: staticSpinner } }; const { driver } = await setupWebDriver({ - props: { WEB_CHAT_PROPS }, createDirectLine: options => { // This part of code is running in the JavaScript VM in Chromium. // These Direct Line Connection Status variables must be declared within scope @@ -263,18 +270,33 @@ describe('offline UI', async () => { }; }, pingBotOnLoad: false, - setup: () => new Promise(resolve => { - const scriptElement = document.createElement('script'); + props: WEB_CHAT_PROPS, + setup: () => + Promise.all([ + window.WebChatTest.loadScript('https://unpkg.com/core-js@2.6.3/client/core.min.js'), + window.WebChatTest.loadScript('https://unpkg.com/lolex@4.0.1/lolex.js') + ]).then(() => { + window.WebChatTest.clock = lolex.install(); + }) + }); - scriptElement.onload = resolve; - scriptElement.setAttribute('src', 'https://unpkg.com/core-js@2.6.3/client/core.min.js'); + await driver.wait(actionDispatched('DIRECT_LINE/CONNECT_PENDING'), timeouts.directLine); + await driver.wait(actionDispatched('DIRECT_LINE/CONNECT_FULFILLED'), timeouts.directLine); + await driver.wait(actionDispatched('DIRECT_LINE/CONNECT_PENDING'), timeouts.directLine); - document.head.appendChild(scriptElement); - }) + await driver.executeScript(() => { + window.WebChatTest.clock.tick(400); // "Connecting" will be gone after 400ms, turning into "Network interruption occured" + window.WebChatTest.clock.tick(200); + }); + + // TODO: [P4] Understand why we need to fire tick() using two cross-VM calls + // When we put everything in a single cross-VM call, the last tick has no effect + await driver.executeScript(() => { + window.WebChatTest.clock.tick(1); // Shortly after 15s, it will show "Network interruption occured." }); - await driver.sleep(600); const base64PNG = await driver.takeScreenshot(); + expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -308,17 +330,51 @@ describe('offline UI', async () => { }; }, pingBotOnLoad: false, - setup: () => new Promise(resolve => { - const scriptElement = document.createElement('script'); + setup: () => + Promise.all([ + window.WebChatTest.loadScript('https://unpkg.com/core-js@2.6.3/client/core.min.js'), + window.WebChatTest.loadScript('https://unpkg.com/lolex@4.0.1/lolex.js') + ]).then(() => { + window.WebChatTest.clock = lolex.install(); + }) + }); - scriptElement.onload = resolve; - scriptElement.setAttribute('src', 'https://unpkg.com/core-js@2.6.3/client/core.min.js'); + await driver.wait(actionDispatched('DIRECT_LINE/RECONNECT_PENDING'), timeouts.directLine); - document.head.appendChild(scriptElement); - }) + await driver.executeScript(() => { + window.WebChatTest.clock.tick(400); // "Connecting" will be gone after 400ms + window.WebChatTest.clock.tick(14600); // Go to t=15s }); - await driver.sleep(17000); + // TODO: [P4] Understand why we need to fire tick() using two cross-VM calls + // When we put everything in a single cross-VM call, the last tick has no effect + await driver.executeScript(() => { + window.WebChatTest.clock.tick(1); // Shortly after 15s, it will show "Taking longer than usual to connect" + }); + + const base64PNG = await driver.takeScreenshot(); + + expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions); + }); + + test('should show "Render error" connectivity status when a JavaScript error is present in the code.', async () => { + const { driver, pageObjects } = await setupWebDriver({ + storeMiddleware: ({ dispatch }) => next => action => { + if (action.type === 'DIRECT_LINE/INCOMING_ACTIVITY' && action.payload.activity && action.payload.activity.text === 'error') { + dispatch({ + type: 'DIRECT_LINE/POST_ACTIVITY', + payload: {} + }); + } + + return next(action); + } + }); + + await driver.wait(uiConnected(), timeouts.directLine); + await pageObjects.sendMessageViaSendBox('error', { waitForSend: false }); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(actionDispatched('WEB_CHAT/SAGA_ERROR'), timeouts.directLine); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/sendBox.js b/__tests__/sendBox.js index 8ad4af1fd2..7100bcc94a 100644 --- a/__tests__/sendBox.js +++ b/__tests__/sendBox.js @@ -32,7 +32,7 @@ test('should focus send box when message is being sent', async () => { }); await driver.wait(uiConnected(), timeouts.directLine); - await pageObjects.sendMessageViaSendBox('Hello, World!'); + await pageObjects.sendMessageViaSendBox('Hello, World!', { waitForSend: true }); await driver.wait(minNumActivitiesShown(1), 2000); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/sendTypingIndicator.js b/__tests__/sendTypingIndicator.js index 01514c3372..f289a1166b 100644 --- a/__tests__/sendTypingIndicator.js +++ b/__tests__/sendTypingIndicator.js @@ -11,7 +11,7 @@ jest.setTimeout(timeouts.test); test('Send typing indicator', async () => { const { driver, pageObjects } = await setupWebDriver({ props: { sendTypingIndicator: true } }); - await pageObjects.sendMessageViaSendBox('echo-typing'); + await pageObjects.sendMessageViaSendBox('echo-typing', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); @@ -27,7 +27,7 @@ test('Send typing indicator', async () => { test('Send typing indicator using deprecated props', async () => { const { driver, pageObjects } = await setupWebDriver({ props: { sendTyping: true } }); - await pageObjects.sendMessageViaSendBox('echo-typing'); + await pageObjects.sendMessageViaSendBox('echo-typing', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); diff --git a/__tests__/setup/assets/staticSpinner.js b/__tests__/setup/assets/staticSpinner.js index a30654ba22..26343da9d9 100644 --- a/__tests__/setup/assets/staticSpinner.js +++ b/__tests__/setup/assets/staticSpinner.js @@ -1,3 +1,3 @@ -export default () => -'url(\'data:image/png;base64,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\')'; +export default + 'url(\'data:image/png;base64,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\')' diff --git a/__tests__/setup/conditions/actionDispatched.js b/__tests__/setup/conditions/actionDispatched.js new file mode 100644 index 0000000000..63617f5191 --- /dev/null +++ b/__tests__/setup/conditions/actionDispatched.js @@ -0,0 +1,7 @@ +import { Condition } from 'selenium-webdriver'; + +export default function (type) { + return new Condition('Action to dispatch', async driver => + await driver.executeScript(type => ~window.WebChatTest.actions.findIndex(({ type: target }) => target === type), type) + ); +} diff --git a/__tests__/setup/pageObjects/sendMessageViaSendBox.js b/__tests__/setup/pageObjects/sendMessageViaSendBox.js index cc8f8d4097..c6f1ce8b4b 100644 --- a/__tests__/setup/pageObjects/sendMessageViaSendBox.js +++ b/__tests__/setup/pageObjects/sendMessageViaSendBox.js @@ -3,9 +3,10 @@ import { By, Key } from 'selenium-webdriver'; import { timeouts } from '../../constants.json'; import allOutgoingActivitiesSent from '../conditions/allOutgoingActivitiesSent'; -export default async function (driver, text) { +export default async function (driver, text, { waitForSend = true }) { const input = await driver.findElement(By.css('input[type="text"]')); await input.sendKeys(text, Key.RETURN); - await driver.wait(allOutgoingActivitiesSent(), timeouts.directLine); + + waitForSend && await driver.wait(allOutgoingActivitiesSent(), timeouts.directLine); } diff --git a/__tests__/setup/web/index.html b/__tests__/setup/web/index.html index 9357ea9a6a..1534d2d74d 100644 --- a/__tests__/setup/web/index.html +++ b/__tests__/setup/web/index.html @@ -53,8 +53,6 @@