Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add tests for #2331, #2332, and #2399 #2504

Merged
merged 9 commits into from
Oct 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions __tests__/focus.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ describe('type focus sink', () => {
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom);

// For reliability reason, we are scrolling to top before focus
// This will make sure the "New messages" button show up
await pageObjects.scrollToTop();

await driver.executeScript(() => document.querySelector('input[placeholder="Name"]').focus());
await driver
.actions()
Expand Down
21 changes: 21 additions & 0 deletions __tests__/sendBox.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { imageSnapshotOptions, timeouts } from './constants.json';

import actionDispatched from './setup/conditions/actionDispatched';
import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown';
import uiConnected from './setup/conditions/uiConnected';

Expand Down Expand Up @@ -31,3 +32,23 @@ test('should focus send box when message is being sent', async () => {

expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions);
});

test('should trim outgoing message when being sent', async () => {
const { driver, pageObjects } = await setupWebDriver();

await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox(
'\u00A0\u00A0There should be no space before and after this message.\u00A0\u00A0',
{ waitForSend: false }
);
await driver.wait(
actionDispatched(
({ payload: { activity } = {}, type }) =>
type === 'DIRECT_LINE/INCOMING_ACTIVITY' &&
activity.from.role === 'user' &&
activity.text === 'There should be no space before and after this message.'
),
timeouts.directLine
);
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
});
36 changes: 28 additions & 8 deletions __tests__/setup/conditions/actionDispatched.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
import { Condition } from 'selenium-webdriver';

export default function actionDispatched(type) {
return new Condition(
'Action to dispatch',
async driver =>
await driver.executeScript(
type => ~window.WebChatTest.actions.findIndex(({ type: target }) => target === type),
type
export default function actionDispatched(predicateOrType) {
const message =
typeof predicateOrType === 'string' ? `action "${predicateOrType}" to dispatch` : 'action to dispatch';

if (typeof predicateOrType === 'string') {
const expectedType = predicateOrType;

predicateOrType = ({ type }) => type === expectedType;
}

return new Condition(message, async driver => {
const actions = await driver.executeScript(() =>
JSON.parse(
JSON.stringify(
window.WebChatTest.actions.map(action => {
// Filter out payload on DIRECT_LINE/* because some content is not stringifiable

if (/^DIRECT_LINE\//.test(action.type) && action.payload && action.payload.directLine) {
return simpleUpdateIn(action, ['payload', 'directLine'], () => ({}));
}

return action;
})
)
)
);
);

return ~actions.findIndex(action => predicateOrType(action));
});
}
4 changes: 4 additions & 0 deletions __tests__/setup/pageObjects/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@ import isDictating from './isDictating';
import pingBot from './pingBot';
import playMediaToCompletion from './playMediaToCompletion';
import putSpeechRecognitionResult from './putSpeechRecognitionResult';
import scrollToTop from './scrollToTop';
import sendFile from './sendFile';
import sendMessageViaMicrophone from './sendMessageViaMicrophone';
import sendMessageViaSendBox from './sendMessageViaSendBox';
import sendTextToClipboard from './sendTextToClipboard';
import startSpeechSynthesize from './startSpeechSynthesize';
import switchToYouTubeIFRAME from './switchToYouTubeIFRAME';
import typeOnSendBox from './typeOnSendBox';
import updateProps from './updateProps';

Expand Down Expand Up @@ -51,11 +53,13 @@ export default function pageObjects(driver) {
pingBot,
playMediaToCompletion,
putSpeechRecognitionResult,
scrollToTop,
sendFile,
sendMessageViaMicrophone,
sendMessageViaSendBox,
sendTextToClipboard,
startSpeechSynthesize,
switchToYouTubeIFRAME,
typeOnSendBox,
updateProps
},
Expand Down
7 changes: 7 additions & 0 deletions __tests__/setup/pageObjects/scrollToTop.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { timeouts } from '../../constants.json';

export default async function scrollToTop(driver) {
await driver.executeScript(() => {
document.querySelector('[role="log"] > *').scrollTop = 0;
}, timeouts.ui);
}
28 changes: 28 additions & 0 deletions __tests__/setup/pageObjects/switchToYouTubeIFRAME.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { By, Condition, until } from 'selenium-webdriver';
import { timeouts } from '../../constants.json';

function sleep(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}

export default async function switchToYouTubeIFRAME(driver) {
const iframeSelector = By.css('iframe[src^="https://youtube.com/"]');

await driver.wait(until.elementLocated(iframeSelector), timeouts.fetch);

const iframe = await driver.findElement(iframeSelector);

await driver.switchTo().frame(iframe);

// TODO: [P2] Workaround the bug or bump selenium-webdriver
// selenium-webdriver has a bug that frame switching is not complete until 2 seconds later.
// There is currently no workaround other than sleeping.
await sleep(timeouts.fetch);

await driver.wait(
new Condition('until switched to IFRAME', async driver =>
/^https:\/\/www.youtube.com\//.test(await driver.executeScript(() => document.location.href))
),
timeouts.fetch
);
}
1 change: 1 addition & 0 deletions __tests__/setup/web/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
</style>
<script src="https://tdurnford.github.io/BotFramework-Offline-MockBot/index.js"></script>
<script src="https://unpkg.com/[email protected]/dist/event-target-shim.umd.js"></script>
<script src="https://unpkg.com/simple-update-in"></script>
<script src="/createProduceConsumeBroker.js"></script>
<script src="/mockWebSpeech.js"></script>
</head>
Expand Down
18 changes: 18 additions & 0 deletions __tests__/styleOptions.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { imageSnapshotOptions, timeouts } from './constants.json';

import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown';
import scrollToBottomCompleted from './setup/conditions/scrollToBottomCompleted';
import uiConnected from './setup/conditions/uiConnected';

// selenium-webdriver API doc:
Expand Down Expand Up @@ -36,4 +37,21 @@ describe('style options', () => {

expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);
});

test('hide scroll to bottom button', async () => {
const { driver, pageObjects } = await setupWebDriver();

await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('markdown', { waitForSend: true });
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(scrollToBottomCompleted(), timeouts.ui);

await pageObjects.scrollToTop();

expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);

await pageObjects.updateProps({ styleOptions: { hideScrollToEndButton: true } });

expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);
});
});
43 changes: 43 additions & 0 deletions __tests__/video.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { By, until } from 'selenium-webdriver';

import { imageSnapshotOptions, timeouts } from './constants.json';

import allImagesLoaded from './setup/conditions/allImagesLoaded';
import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown.js';

// selenium-webdriver API doc:
// https://seleniumhq.github.io/selenium/docs/api/javascript/module/selenium-webdriver/index_exports_WebDriver.html

jest.setTimeout(timeouts.test);

async function clickButton(driver, locator) {
await driver.wait(until.elementLocated(locator), timeouts.ui);

const pauseButton = await driver.findElement(locator);

await pauseButton.click();
}

test('video', async () => {
const { driver, pageObjects } = await setupWebDriver();

await pageObjects.sendMessageViaSendBox('video youtube', { waitForSend: true });

await driver.wait(allImagesLoaded(), timeouts.fetch);
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);

await pageObjects.switchToYouTubeIFRAME();

await clickButton(driver, By.css('button[aria-label="Play"]'));
await clickButton(driver, By.css('button[aria-label="Pause (k)"]'));

// Hide the spinner animation
await driver.executeScript(() => document.querySelector('.ytp-spinner').remove());

// Wait for YouTube play/pause button animation to complete
await driver.sleep(1000);

const base64PNG = await driver.takeScreenshot();

expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions);
});