diff --git a/CHANGELOG.md b/CHANGELOG.md index 53372f87d3..e53ba7c0a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - [`abort-controller`](https://npmjs.com/package/abort-controller) - [`event-target-shim`](https://npmjs.com/package/event-target-shim) - [`p-defer`](https://npmjs.com/package/p-defer) +- Fixes the following issues and improves test reliability, by [@compulim](https://github.com/compulim) in PR [#XXX](https://github.com/microsoft/BotFramework-WebChat/pull/XXX) + - Fixes [#2612](https://github.com/microsoft/BotFramework-WebChat/issues/2612). Wait until language change + - Fixes [#2653](https://github.com/microsoft/BotFramework-WebChat/issues/2653). Scroll-to-bottom check will do 5 consecutive checks to determine stickiness. + - Fixes [#2691](https://github.com/microsoft/BotFramework-WebChat/issues/2691). Wait until button is shown/hid before taking screenshot + - Fixes [#2737](https://github.com/microsoft/BotFramework-WebChat/issues/2737). Use `driver.wait` for conditions + - Fixes [#2776](https://github.com/microsoft/BotFramework-WebChat/issues/2776). Wait until button is shown/hid before taking screenshot + - Use a new timeout `fetchImage` for images ### Changed diff --git a/__tests__/adaptiveCards.js b/__tests__/adaptiveCards.js index eaacb1232f..de08ca5453 100644 --- a/__tests__/adaptiveCards.js +++ b/__tests__/adaptiveCards.js @@ -20,7 +20,7 @@ test('breakfast card', async () => { await pageObjects.sendMessageViaSendBox('card breakfast', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -40,7 +40,7 @@ test('breakfast card with custom host config', async () => { await pageObjects.sendMessageViaSendBox('card breakfast', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -60,7 +60,7 @@ test('breakfast card with custom style options', async () => { await pageObjects.sendMessageViaSendBox('card breakfast', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -74,7 +74,7 @@ test('disable card inputs', async () => { await pageObjects.sendMessageViaSendBox('card inputs', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom); await driver.executeScript(() => { diff --git a/__tests__/basic.js b/__tests__/basic.js index 8ba9e35b3a..9501689296 100644 --- a/__tests__/basic.js +++ b/__tests__/basic.js @@ -16,7 +16,7 @@ test('setup', async () => { await pageObjects.sendMessageViaSendBox('layout carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -33,7 +33,7 @@ test('long URLs with break-word', async () => { ); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -52,7 +52,7 @@ test('long URLs with break-all', async () => { ); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -69,7 +69,7 @@ test('long URLs with keep-all', async () => { }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -96,7 +96,7 @@ test('hero card with a long title and richCardWrapTitle set to true', async () = await pageObjects.sendMessageViaSendBox('herocard long title', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -110,7 +110,7 @@ test('hero card with a long title and richCardWrapTitle set to default value', a await pageObjects.sendMessageViaSendBox('herocard long title', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -124,7 +124,7 @@ test('thumbnail card with a long title and richCardWrapTitle set to true', async await pageObjects.sendMessageViaSendBox('thumbnailcard long title', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -138,7 +138,7 @@ test('thumbnail card with a long title and richCardWrapTitle set to default valu await pageObjects.sendMessageViaSendBox('thumbnailcard long title', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/bubbleBorder.js b/__tests__/bubbleBorder.js index 39bbb64ef6..f28adfaf1e 100644 --- a/__tests__/bubbleBorder.js +++ b/__tests__/bubbleBorder.js @@ -1,6 +1,5 @@ import { imageSnapshotOptions, timeouts } from './constants.json'; -import allImagesLoaded from './setup/conditions/allImagesLoaded'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; import uiConnected from './setup/conditions/uiConnected'; diff --git a/__tests__/bubbleNub.js b/__tests__/bubbleNub.js index 806c8e0c8f..ced8dcbbc5 100644 --- a/__tests__/bubbleNub.js +++ b/__tests__/bubbleNub.js @@ -14,7 +14,7 @@ async function sendMessageAndMatchSnapshot(driver, pageObjects, message) { await pageObjects.sendMessageViaSendBox(message); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/cardActionMiddleware.js b/__tests__/cardActionMiddleware.js index 82cd86e343..a9d62cfbd7 100644 --- a/__tests__/cardActionMiddleware.js +++ b/__tests__/cardActionMiddleware.js @@ -10,6 +10,8 @@ import uiConnected from './setup/conditions/uiConnected'; // selenium-webdriver API doc: // https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html +jest.setTimeout(timeouts.test); + test('card action "openUrl"', async () => { const { driver, pageObjects } = await setupWebDriver({ props: { @@ -42,7 +44,7 @@ test('card action "openUrl"', async () => { const base64PNG = await driver.takeScreenshot(); expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions); -}, 60000); +}); test('card action "signin"', async () => { const { driver, pageObjects } = await setupWebDriver({ @@ -85,4 +87,4 @@ test('card action "signin"', async () => { const base64PNG = await driver.takeScreenshot(); expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions); -}, 60000); +}); diff --git a/__tests__/carousel.js b/__tests__/carousel.js index d9d796b69c..0679c1df8d 100644 --- a/__tests__/carousel.js +++ b/__tests__/carousel.js @@ -19,7 +19,7 @@ describe('carousel without avatar initials', () => { await pageObjects.sendMessageViaSendBox('carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); @@ -43,7 +43,7 @@ describe('carousel without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); @@ -67,7 +67,7 @@ describe('carousel without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -79,7 +79,7 @@ describe('carousel without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -91,7 +91,7 @@ describe('carousel without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -103,7 +103,7 @@ describe('carousel without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -119,7 +119,7 @@ describe('carousel with avatar initials', () => { await pageObjects.sendMessageViaSendBox('carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); @@ -143,7 +143,7 @@ describe('carousel with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); @@ -167,7 +167,7 @@ describe('carousel with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -179,7 +179,7 @@ describe('carousel with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout double', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -191,7 +191,7 @@ describe('carousel with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -203,7 +203,7 @@ describe('carousel with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single carousel', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); diff --git a/__tests__/clockSkew.js b/__tests__/clockSkew.js index 208fa3f31c..4ac3687dbe 100644 --- a/__tests__/clockSkew.js +++ b/__tests__/clockSkew.js @@ -150,7 +150,7 @@ describe('Clock skew', () => { await driver.executeScript(() => window.WebChatTest.releaseActivity(3)); await driver.wait(minNumActivitiesShown(5), timeouts.directLine); await driver.wait(allOutgoingActivitiesSent(), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); diff --git a/__tests__/constants.json b/__tests__/constants.json index 0cadaf0814..3c6f2cc36c 100644 --- a/__tests__/constants.json +++ b/__tests__/constants.json @@ -7,6 +7,7 @@ "timeouts": { "directLine": 15000, "fetch": 2500, + "fetchImage": 5000, "navigation": 10000, "postActivity": 30000, "scrollToBottom": 2000, diff --git a/__tests__/focus.js b/__tests__/focus.js index 3183f2c1bc..513d3abbce 100644 --- a/__tests__/focus.js +++ b/__tests__/focus.js @@ -3,6 +3,7 @@ import { By, Key } from 'selenium-webdriver'; import { imageSnapshotOptions, timeouts } from './constants.json'; import allOutgoingActivitiesSent from './setup/conditions/allOutgoingActivitiesSent'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; +import negationOf from './setup/conditions/negationOf.js'; import scrollToBottomCompleted from './setup/conditions/scrollToBottomCompleted'; import sendBoxTextBoxFocused from './setup/conditions/sendBoxTextBoxFocused'; import suggestedActionsShown from './setup/conditions/suggestedActionsShown'; @@ -22,7 +23,7 @@ test('should not focus send box after clicking on send button', async () => { await pageObjects.typeOnSendBox('echo 123'); await pageObjects.clickSendButton(); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeFalsy(); + await driver.wait(negationOf(sendBoxTextBoxFocused()), timeouts.ui); }); // Verification of fix of #1971, https://github.com/microsoft/BotFramework-WebChat/issues/1971 @@ -36,7 +37,7 @@ test('SHOULD focus send box after clicking on suggested actions', async () => { await pageObjects.clickSuggestedActionButton(0); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeTruthy(); + await driver.wait(sendBoxTextBoxFocused(), timeouts.ui); }); // Verification of fix of #1971, https://github.com/microsoft/BotFramework-WebChat/issues/1971 @@ -47,7 +48,7 @@ test('should focus send box after pressing ENTER to send message', async () => { await pageObjects.typeOnSendBox('echo 123', Key.RETURN); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeTruthy(); + await driver.wait(sendBoxTextBoxFocused(), timeouts.ui); }); describe('type focus sink', () => { @@ -60,7 +61,7 @@ describe('type focus sink', () => { await transcript.click(); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeFalsy(); + await driver.wait(negationOf(sendBoxTextBoxFocused()), timeouts.ui); await driver .actions() @@ -111,14 +112,14 @@ describe('type focus sink', () => { await transcript.click(); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeFalsy(); + await driver.wait(negationOf(sendBoxTextBoxFocused()), timeouts.ui); await driver .actions() .sendKeys(Key.SHIFT) .perform(); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeFalsy(); + await driver.wait(negationOf(sendBoxTextBoxFocused()), timeouts.ui); }); test('should paste into the send box when focus is on the transcript', async () => { @@ -132,7 +133,7 @@ describe('type focus sink', () => { await transcript.click(); - await expect(sendBoxTextBoxFocused().fn(driver)).resolves.toBeFalsy(); + await driver.wait(negationOf(sendBoxTextBoxFocused()), timeouts.ui); await driver .actions() diff --git a/__tests__/hooks/useLanguage.js b/__tests__/hooks/useLanguage.js index 1253b77f7b..ec14eec576 100644 --- a/__tests__/hooks/useLanguage.js +++ b/__tests__/hooks/useLanguage.js @@ -12,17 +12,17 @@ test('getter should return language set in props', async () => { } }); - const [groupTimestamp] = await pageObjects.runHook('useLanguage'); + const [language] = await pageObjects.runHook('useLanguage'); - expect(groupTimestamp).toMatchInlineSnapshot(`"zh-YUE"`); + expect(language).toMatchInlineSnapshot(`"zh-YUE"`); }); test('getter should return default language if not set in props', async () => { const { pageObjects } = await setupWebDriver(); - const [groupTimestamp] = await pageObjects.runHook('useLanguage'); + const [language] = await pageObjects.runHook('useLanguage'); - expect(groupTimestamp).toMatchInlineSnapshot(`"en-US"`); + expect(language).toMatchInlineSnapshot(`"en-US"`); }); test('setter should be undefined', async () => { diff --git a/__tests__/hooks/useSendBoxSpeechInterimsVisible.js b/__tests__/hooks/useSendBoxSpeechInterimsVisible.js index cc1feb4969..5f42b43a35 100644 --- a/__tests__/hooks/useSendBoxSpeechInterimsVisible.js +++ b/__tests__/hooks/useSendBoxSpeechInterimsVisible.js @@ -1,6 +1,6 @@ import { timeouts } from '../constants.json'; -import negate from '../setup/conditions/negate'; +import negationOf from '../setup/conditions/negationOf'; import speechRecognitionStartCalled from '../setup/conditions/speechRecognitionStartCalled'; import speechSynthesisUtterancePended from '../setup/conditions/speechSynthesisUtterancePended'; import uiConnected from '../setup/conditions/uiConnected'; @@ -73,7 +73,7 @@ test('sendBoxSpeechInterimsVisible should return false when synthesizing', async await pageObjects.clickMicrophoneButton(); - await driver.wait(negate(speechSynthesisUtterancePended()), timeouts.ui); + await driver.wait(negationOf(speechSynthesisUtterancePended()), timeouts.ui); await expect( pageObjects.runHook( diff --git a/__tests__/hooks/useTextBox.js b/__tests__/hooks/useTextBox.js index d67fe8d42a..b21210e7f4 100644 --- a/__tests__/hooks/useTextBox.js +++ b/__tests__/hooks/useTextBox.js @@ -1,6 +1,8 @@ import { imageSnapshotOptions, timeouts } from '../constants.json'; import minNumActivitiesShown from '../setup/conditions/minNumActivitiesShown'; +import negationOf from '../setup/conditions/negationOf'; +import scrollToBottomButtonVisible from '../setup/conditions/scrollToBottomButtonVisible'; import scrollToBottomCompleted from '../setup/conditions/scrollToBottomCompleted'; import uiConnected from '../setup/conditions/uiConnected'; @@ -27,6 +29,7 @@ test('calling submit should scroll to end', async () => { document.querySelector('[role="log"] > *').scrollTop = 0; }); + await driver.wait(scrollToBottomButtonVisible(), timeouts.ui); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); await pageObjects.runHook('useTextBoxValue', [], textBoxValue => textBoxValue[1]('Hello, World!')); @@ -35,5 +38,6 @@ test('calling submit should scroll to end', async () => { await driver.wait(minNumActivitiesShown(4), timeouts.directLine); await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom); + await driver.wait(negationOf(scrollToBottomButtonVisible()), timeouts.ui); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); diff --git a/__tests__/inputHint.consecutive.js b/__tests__/inputHint.consecutive.js index 79188a9be5..04e9c4e342 100644 --- a/__tests__/inputHint.consecutive.js +++ b/__tests__/inputHint.consecutive.js @@ -1,7 +1,7 @@ import { timeouts } from './constants.json'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; -import negateCondition from './setup/conditions/negate'; +import negationOf from './setup/conditions/negationOf'; import speechRecognitionStartCalled from './setup/conditions/speechRecognitionStartCalled'; import speechSynthesisUtterancePended from './setup/conditions/speechSynthesisUtterancePended'; import uiConnected from './setup/conditions/uiConnected'; @@ -41,7 +41,7 @@ describe('input hint from consecutive messages', () => { await pageObjects.startSpeechSynthesize(); await pageObjects.endSpeechSynthesize(); - await driver.wait(negateCondition(speechSynthesisUtterancePended()), timeouts.ui); + await driver.wait(negationOf(speechSynthesisUtterancePended()), timeouts.ui); } beforeEach(async () => { diff --git a/__tests__/markdown.js b/__tests__/markdown.js index f1041fcbc4..4a22c5277a 100644 --- a/__tests__/markdown.js +++ b/__tests__/markdown.js @@ -13,7 +13,7 @@ test('hero card', async () => { await pageObjects.sendMessageViaSendBox('herocard', { waitForSend: true }); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); // Wait for transcript to scroll to bottom await driver.sleep(1000); @@ -28,7 +28,7 @@ test('null renderMarkdown function', async () => { await pageObjects.sendMessageViaSendBox('echo **This text should be plain text**', { waitForSend: true }); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/richCards.js b/__tests__/richCards.js index eedfc0cf0b..bf8dba12c1 100644 --- a/__tests__/richCards.js +++ b/__tests__/richCards.js @@ -19,7 +19,7 @@ test('audio card', async () => { await pageObjects.sendMessageViaSendBox('audiocard', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const audioElement = await driver.findElement(By.css('audio')); @@ -38,7 +38,7 @@ test('hero card', async () => { await pageObjects.sendMessageViaSendBox('herocard', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom); const base64PNG = await driver.takeScreenshot(); @@ -53,7 +53,7 @@ test('oauth card', async () => { await pageObjects.sendMessageViaSendBox('oauth', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -67,7 +67,7 @@ test('receipt card', async () => { await pageObjects.sendMessageViaSendBox('receiptcard', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -81,7 +81,7 @@ test('sign-in card', async () => { await pageObjects.sendMessageViaSendBox('signin', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -95,7 +95,7 @@ test('thumbnail card', async () => { await pageObjects.sendMessageViaSendBox('thumbnailcard', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/sendTypingIndicator.js b/__tests__/sendTypingIndicator.js index 8d4567a2ba..a7b5c43305 100644 --- a/__tests__/sendTypingIndicator.js +++ b/__tests__/sendTypingIndicator.js @@ -67,7 +67,7 @@ test('typing indicator should not display after second activity', async () => { }); await pageObjects.sendMessageViaSendBox('typing', { waitForSend: true }); - await driver.wait(minNumActivitiesShown(2), 5000); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); const base64PNG = await driver.takeScreenshot(); expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions); diff --git a/__tests__/setup/conditions/negate.js b/__tests__/setup/conditions/negate.js deleted file mode 100644 index f0fb20dcab..0000000000 --- a/__tests__/setup/conditions/negate.js +++ /dev/null @@ -1,5 +0,0 @@ -import { Condition } from 'selenium-webdriver'; - -export default function negateCondition(condition) { - return new Condition(`Negate of ${condition.name}`, async (...args) => !(await condition.fn(...args))); -} diff --git a/__tests__/setup/conditions/negationOf.js b/__tests__/setup/conditions/negationOf.js new file mode 100644 index 0000000000..fe98c68e76 --- /dev/null +++ b/__tests__/setup/conditions/negationOf.js @@ -0,0 +1,8 @@ +import { Condition } from 'selenium-webdriver'; + +export default function negationOf(condition) { + return new Condition( + `negation of ${condition.name || 'a condition'}`, + async (...args) => !(await condition.fn(...args)) + ); +} diff --git a/__tests__/setup/conditions/scrollToBottomCompleted.js b/__tests__/setup/conditions/scrollToBottomCompleted.js index 57380e0b01..15c3c584cd 100644 --- a/__tests__/setup/conditions/scrollToBottomCompleted.js +++ b/__tests__/setup/conditions/scrollToBottomCompleted.js @@ -1,11 +1,22 @@ import { Condition } from 'selenium-webdriver'; export default function scrollToBottomCompleted() { - return new Condition('for UI to scroll to bottom', driver => - driver.executeScript(() => { - const scrollable = document.querySelector('[role="log"] > *'); + return new Condition('for UI to scroll to bottom', async driver => { + async function completed() { + return await driver.executeScript(() => { + const scrollable = document.querySelector('[role="log"] > *'); - return scrollable && scrollable.offsetHeight + scrollable.scrollTop === scrollable.scrollHeight; - }) - ); + return scrollable && scrollable.offsetHeight + scrollable.scrollTop === scrollable.scrollHeight; + }); + } + + // Browser may keep rendering content. Wait until 5 consecutive completion checks are all truthy. + for (let count = 0; count < 5; count++) { + if (!(await completed())) { + return false; + } + } + + return true; + }); } diff --git a/__tests__/setup/web/index.html b/__tests__/setup/web/index.html index da3b221c8a..dcfd88e555 100644 --- a/__tests__/setup/web/index.html +++ b/__tests__/setup/web/index.html @@ -168,7 +168,7 @@ const hookFn = window.WebChat.hooks[name]; if (!hookFn) { - console.log(`No hooks named "${ name }" were found. Valid hooks are:`, Object.keys(window.WebChat.hooks).sort()); + console.log(`No hooks named "${ name }" were found. Valid hooks are:`, Object.keys(window.WebChat.hooks).sort().map(name => `- ${ name }`).join('\n')); throw new Error(`No hooks named "${ name }" were found.`); } diff --git a/__tests__/speech.recognition.js b/__tests__/speech.recognition.js index 569e1f89b2..cbaab6921d 100644 --- a/__tests__/speech.recognition.js +++ b/__tests__/speech.recognition.js @@ -1,7 +1,7 @@ import { timeouts } from './constants.json'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; -import negateCondition from './setup/conditions/negate'; +import negationOf from './setup/conditions/negationOf'; import speechRecognitionStartCalled from './setup/conditions/speechRecognitionStartCalled'; import speechSynthesisUtterancePended from './setup/conditions/speechSynthesisUtterancePended'; @@ -26,7 +26,7 @@ describe('speech recognition', () => { await pageObjects.startSpeechSynthesize(); await pageObjects.typeOnSendBox('Aloha!'); - await driver.wait(negateCondition(speechSynthesisUtterancePended()), timeouts.ui); + await driver.wait(negationOf(speechSynthesisUtterancePended()), timeouts.ui); await expect(pageObjects.isDictating()).resolves.toBeFalsy(); }); diff --git a/__tests__/speech.synthesis.js b/__tests__/speech.synthesis.js index 8ce634d30e..52fbf582a3 100644 --- a/__tests__/speech.synthesis.js +++ b/__tests__/speech.synthesis.js @@ -1,7 +1,7 @@ import { timeouts } from './constants.json'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; -import negateCondition from './setup/conditions/negate'; +import negationOf from './setup/conditions/negationOf'; import speechRecognitionStartCalled from './setup/conditions/speechRecognitionStartCalled'; import speechSynthesisUtterancePended from './setup/conditions/speechSynthesisUtterancePended'; @@ -122,7 +122,7 @@ describe('speech synthesis', () => { await pageObjects.clickMicrophoneButton(); await expect(speechRecognitionStartCalled().fn(driver)).resolves.toBeTruthy(); - await driver.wait(negateCondition(speechSynthesisUtterancePended()), timeouts.ui); + await driver.wait(negationOf(speechSynthesisUtterancePended()), timeouts.ui); }); describe('without speech synthesis', () => { @@ -145,7 +145,7 @@ describe('speech synthesis', () => { await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await expect(speechRecognitionStartCalled().fn(driver)).resolves.toBeTruthy(); - await driver.wait(negateCondition(speechSynthesisUtterancePended()), timeouts.ui); + await driver.wait(negationOf(speechSynthesisUtterancePended()), timeouts.ui); }); }); }); diff --git a/__tests__/stacked.js b/__tests__/stacked.js index 7bb0090755..78ae9748ae 100644 --- a/__tests__/stacked.js +++ b/__tests__/stacked.js @@ -18,7 +18,7 @@ describe('stacked without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout stacked', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); @@ -31,7 +31,7 @@ describe('stacked without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -43,7 +43,7 @@ describe('stacked without avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -59,7 +59,7 @@ describe('stacked with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout stacked', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -71,7 +71,7 @@ describe('stacked with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); @@ -83,7 +83,7 @@ describe('stacked with avatar initials', () => { await pageObjects.sendMessageViaSendBox('layout single', { waitForSend: true }); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); diff --git a/__tests__/styleOptions.js b/__tests__/styleOptions.js index e2ca6abbc0..74ef198523 100644 --- a/__tests__/styleOptions.js +++ b/__tests__/styleOptions.js @@ -1,6 +1,8 @@ import { imageSnapshotOptions, timeouts } from './constants.json'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; +import negationOf from './setup/conditions/negationOf'; +import scrollToBottomButtonVisible from './setup/conditions/scrollToBottomButtonVisible'; import scrollToBottomCompleted from './setup/conditions/scrollToBottomCompleted'; import uiConnected from './setup/conditions/uiConnected'; @@ -48,10 +50,12 @@ describe('style options', () => { await pageObjects.scrollToTop(); + await driver.wait(scrollToBottomButtonVisible(), timeouts.ui); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); await pageObjects.updateProps({ styleOptions: { hideScrollToEndButton: true } }); + await driver.wait(negationOf(scrollToBottomButtonVisible()), timeouts.ui); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); }); diff --git a/__tests__/suggestedActions.js b/__tests__/suggestedActions.js index 3b67b9fb89..1c04c9a7b7 100644 --- a/__tests__/suggestedActions.js +++ b/__tests__/suggestedActions.js @@ -21,7 +21,7 @@ describe('suggested-actions command', () => { await pageObjects.sendMessageViaSendBox('suggested-actions', { waitForSend: true }); await driver.wait(suggestedActionsShown(), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -37,7 +37,7 @@ describe('suggested-actions command', () => { await pageObjects.sendMessageViaSendBox('suggested-actions', { waitForSend: true }); await driver.wait(suggestedActionsShown(), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -141,7 +141,7 @@ describe('suggested-actions command', () => { const postBackStringButton = buttons[4]; await postBackStringButton.click(); - await driver.wait(minNumActivitiesShown(3), timeouts.directLine); + await driver.wait(minNumActivitiesShown(4), timeouts.directLine); await driver.wait(allOutgoingActivitiesSent(), timeouts.directLine); const base64PNG = await driver.takeScreenshot(); @@ -169,7 +169,7 @@ describe('suggested-actions command', () => { await pageObjects.sendMessageViaSendBox('emptycard', { waitForSend: true }); await driver.wait(suggestedActionsShown(), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -184,7 +184,7 @@ describe('suggested-actions command', () => { await pageObjects.sendMessageViaSendBox('emptycard', { waitForSend: true }); await driver.wait(suggestedActionsShown(), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -203,7 +203,7 @@ describe('suggested-actions command', () => { await pageObjects.sendMessageViaSendBox('emptycard', { waitForSend: true }); await driver.wait(suggestedActionsShown(), timeouts.directLine); - await driver.wait(allImagesLoaded(), 2000); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/timestamp.js b/__tests__/timestamp.js index 984864981f..42e5bebfe2 100644 --- a/__tests__/timestamp.js +++ b/__tests__/timestamp.js @@ -1,6 +1,8 @@ -import { imageSnapshotOptions, timeouts } from './constants.json'; +import { Condition } from 'selenium-webdriver'; +import { imageSnapshotOptions, timeouts } from './constants.json'; import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown'; +import runHook from './setup/pageObjects/runHook'; import uiConnected from './setup/conditions/uiConnected'; // selenium-webdriver API doc: @@ -8,6 +10,14 @@ import uiConnected from './setup/conditions/uiConnected'; jest.setTimeout(timeouts.test); +function expectLanguage(expected) { + return new Condition(`language changed to "${expected}"`, async driver => { + const [language] = await runHook(driver, 'useLanguage'); + + return language === expected; + }); +} + test('update timestamp on-the-fly', async () => { const { driver, pageObjects } = await setupWebDriver(); @@ -19,10 +29,12 @@ test('update timestamp on-the-fly', async () => { expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); await pageObjects.updateProps({ locale: 'zh-HK' }); + await driver.wait(expectLanguage('zh-HK'), timeouts.ui); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); await pageObjects.updateProps({ locale: 'zh-YUE' }); + await driver.wait(expectLanguage('zh-YUE'), timeouts.ui); expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions); }); diff --git a/__tests__/upload.js b/__tests__/upload.js index 516a49e79c..7c7a589c34 100644 --- a/__tests__/upload.js +++ b/__tests__/upload.js @@ -16,8 +16,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -38,8 +38,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -58,8 +58,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -78,8 +78,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -96,8 +96,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -121,8 +121,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -144,8 +144,8 @@ describe('upload a picture', () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('seaofthieves.jpg'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); @@ -160,8 +160,8 @@ test('upload a ZIP file', async () => { await driver.wait(uiConnected(), timeouts.directLine); await pageObjects.sendFile('empty.zip'); - await driver.wait(minNumActivitiesShown(2)); - await driver.wait(allImagesLoaded()); + await driver.wait(minNumActivitiesShown(2), timeouts.directLine); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); const base64PNG = await driver.takeScreenshot(); diff --git a/__tests__/video.js b/__tests__/video.js index 6e81ebad80..fea9b19268 100644 --- a/__tests__/video.js +++ b/__tests__/video.js @@ -23,7 +23,7 @@ test('video', async () => { await pageObjects.sendMessageViaSendBox('video youtube', { waitForSend: true }); - await driver.wait(allImagesLoaded(), timeouts.fetch); + await driver.wait(allImagesLoaded(), timeouts.fetchImage); await driver.wait(minNumActivitiesShown(2), timeouts.directLine); await pageObjects.switchToYouTubeIFRAME();