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

Show download link and icon based on contentUrl #2868

Merged
merged 10 commits into from
Feb 6, 2020
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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixes [#2822](https://github.com/microsoft/BotFramework-WebChat/issues/2822). Fixed `credentials` should return `authorizationToken` and `subscriptionKey` as string and allow empty LUIS reference grammar ID, by [@compulim](https://github.com/compulim) in PR [#2824](https://github.com/microsoft/BotFramework-WebChat/pull/2824)
- Fixes [#2751](https://github.com/microsoft/BotFramework-WebChat/issues/2751). Move documentation to docs folder, by [@corinagum](https://github.com/corinagum) in PR [#2832](https://github.com/microsoft/BotFramework-WebChat/pull/2832)
- Fixes [#2838](https://github.com/microsoft/BotFramework-WebChat/issues/2838). Fixed `concatMiddleware` should allow any middleware to call its downstream middleware twice, by [@compulim](https://github.com/compulim) in PR [#2839](https://github.com/microsoft/BotFramework-WebChat/pull/2839)
- Fixes [#2864](https://github.com/microsoft/BotFramework-WebChat/issues/2864). Replaced `DownloadAttachment` and `UploadAttachment` with `FileAttachment`, which shows the download link and icon if the attachment contains the `contentUrl`, by [@compulim](https://github.com/compulim) in PR [#2868](https://github.com/microsoft/BotFramework-WebChat/pull/2868)

### Changed

Expand Down
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: 3 additions & 1 deletion __tests__/attachmentMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,9 @@ test('file upload should show thumbnail and file name', async () => {

return next({ activity, attachment });
}
}
},
// TODO: [P3] Offline bot did not reply with a downloadable attachment, we need to use production bot
useProductionBot: true
});

await driver.wait(uiConnected(), timeouts.directLine);
Expand Down
114 changes: 114 additions & 0 deletions __tests__/fileAttachment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { imageSnapshotOptions, timeouts } from './constants.json';

import allImagesLoaded from './setup/conditions/allImagesLoaded';
import minNumActivitiesShown from './setup/conditions/minNumActivitiesShown';
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('show ZIP files with contentUrl', async () => {
const { driver, pageObjects } = await setupWebDriver({
createDirectLine: options => {
const directLine = window.WebChat.createDirectLine(options);
const patchedDirectLine = {
activity$: new Observable(observer => {
const subscription = directLine.activity$.subscribe({
next(activity) {
observer.next(
Object.assign({}, activity, {
attachments: (activity.attachments || []).map(attachment =>
Object.assign({}, attachment, {
contentUrl: 'https://example.org/'
})
)
})
);
}
});

return () => subscription.unsubscribe();
}),

connectionStatus$: directLine.connectionStatus$,
postActivity: directLine.postActivity.bind(directLine),
token: directLine.token
};

return patchedDirectLine;
}
});

await driver.wait(uiConnected(), timeouts.directLine);

await pageObjects.sendFile('empty.zip');
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(allImagesLoaded(), timeouts.fetchImage);

const base64PNG = await driver.takeScreenshot();

expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions);

await expect(
driver.executeScript(() =>
document.querySelector('[role="listitem"]:nth-child(1) a[target="_blank"]').getAttribute('href')
)
).resolves.toEqual('https://example.org/');
await expect(
driver.executeScript(() =>
document.querySelector('[role="listitem"]:nth-child(2) a[target="_blank"]').getAttribute('href')
)
).resolves.toEqual('https://example.org/');
});

test('show ZIP files without contentUrl', async () => {
const { driver, pageObjects } = await setupWebDriver({
createDirectLine: options => {
const directLine = window.WebChat.createDirectLine(options);
const patchedDirectLine = {
activity$: new Observable(observer => {
const subscription = directLine.activity$.subscribe({
next(activity) {
observer.next(
Object.assign({}, activity, {
attachments: (activity.attachments || []).map(attachment =>
Object.assign({}, attachment, {
contentUrl: undefined
})
)
})
);
}
});

return () => subscription.unsubscribe();
}),

connectionStatus$: directLine.connectionStatus$,
postActivity: directLine.postActivity.bind(directLine),
token: directLine.token
};

return patchedDirectLine;
}
});

await driver.wait(uiConnected(), timeouts.directLine);

await pageObjects.sendFile('empty.zip');
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(allImagesLoaded(), timeouts.fetchImage);

const base64PNG = await driver.takeScreenshot();

expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions);

await expect(
driver.executeScript(() => !!document.querySelector('[role="listitem"]:nth-child(1) a'))
).resolves.toBeFalsy();
await expect(
driver.executeScript(() => !!document.querySelector('[role="listitem"]:nth-child(2) a'))
).resolves.toBeFalsy();
});
7 changes: 6 additions & 1 deletion __tests__/hooks/useSendFiles.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { imageSnapshotOptions, timeouts } from '../constants.json';

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

Expand All @@ -9,7 +10,10 @@ import uiConnected from '../setup/conditions/uiConnected';
jest.setTimeout(timeouts.test);

test('calling sendFile should send files', async () => {
const { driver, pageObjects } = await setupWebDriver();
const { driver, pageObjects } = await setupWebDriver({
// TODO: [P3] Offline bot did not reply with a downloadable attachment, we need to use production bot
useProductionBot: true
});

await driver.wait(uiConnected(), timeouts.directLine);

Expand All @@ -24,6 +28,7 @@ test('calling sendFile should send files', async () => {
});

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

const base64PNG = await driver.takeScreenshot();

Expand Down
2 changes: 1 addition & 1 deletion __tests__/hooks/useSendPostBack.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ test('calling sendPostBack should send a post back activity', async () => {

await pageObjects.runHook('useSendPostBack', [], sendPostBack => sendPostBack({ hello: 'World!' }));

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

const base64PNG = await driver.takeScreenshot();

Expand Down
2 changes: 1 addition & 1 deletion __tests__/language.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test('setting language to empty string should not crash', async () => {
await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('echo Hello', { waitForSend: true });

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

const base64PNG = await driver.takeScreenshot();

Expand Down
2 changes: 1 addition & 1 deletion __tests__/markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ test('null renderMarkdown function', async () => {
await pageObjects.sendMessageViaSendBox('echo **This text should be plain text**', { waitForSend: true });

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

const base64PNG = await driver.takeScreenshot();

Expand Down
2 changes: 1 addition & 1 deletion __tests__/sendBox.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ test('should focus send box when message is being sent', async () => {

await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('Hello, World!', { waitForSend: true });
await driver.wait(minNumActivitiesShown(1), timeouts.directLine);
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);

const base64PNG = await driver.takeScreenshot();

Expand Down
2 changes: 1 addition & 1 deletion __tests__/sendTypingIndicator.js
Original file line number Diff line number Diff line change
Expand Up @@ -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), timeouts.directLine);
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);

const base64PNG = await driver.takeScreenshot();
expect(base64PNG).toMatchImageSnapshot(imageSnapshotOptions);
Expand Down
18 changes: 16 additions & 2 deletions __tests__/setup/conditions/minNumActivitiesShown.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,19 @@
import { By, until } from 'selenium-webdriver';
import { Condition } from 'selenium-webdriver';

export default function minNumActivitiesShown(numActivities) {
return until.elementLocated(By.css(`[role="listitem"]:nth-child(${numActivities})`));
return new Condition(`${numActivities} activities is shown`, async driver => {
// To run hooks (WebChatTest.runHook), the code internally create an activity.
// Inside the activity renderer, it call hooks, but return empty visually.
// This activity is invisible and should not count towards "minNumActivitiesShown".

const numActivitiesShown = await driver.executeScript(() =>
[].reduce.call(
document.querySelectorAll('[role="listitem"]'),
(numActivitiesShown, child) => numActivitiesShown + (child.children.length ? 1 : 0),
0
)
);

return numActivitiesShown >= numActivities;
});
}
6 changes: 3 additions & 3 deletions __tests__/speech.selectVoice.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('selecting voice based on language', () => {

await pageObjects.sendMessageViaMicrophone('echo 123');

await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);
await driver.wait(speechSynthesisUtterancePended(), timeouts.ui);

await expect(pageObjects.startSpeechSynthesize()).resolves.toHaveProperty('voice', {
Expand All @@ -42,7 +42,7 @@ describe('selecting voice based on language', () => {

await pageObjects.sendMessageViaMicrophone('echo 123');

await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);
await driver.wait(speechSynthesisUtterancePended(), timeouts.ui);

await expect(pageObjects.startSpeechSynthesize()).resolves.toHaveProperty('voice', {
Expand All @@ -66,7 +66,7 @@ describe('selecting voice based on language', () => {

await pageObjects.sendMessageViaMicrophone('echo 123');

await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);
await driver.wait(speechSynthesisUtterancePended(), timeouts.ui);

await expect(pageObjects.startSpeechSynthesize()).resolves.toHaveProperty('voice', {
Expand Down
4 changes: 2 additions & 2 deletions __tests__/speech.synthesis.js
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ describe('speech synthesis', () => {
await pageObjects.sendMessageViaMicrophone('echo Hello, World!');

await expect(speechRecognitionStartCalled().fn(driver)).resolves.toBeFalsy();
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);

await expect(pageObjects.startSpeechSynthesize()).resolves.toHaveProperty(
'text',
Expand Down Expand Up @@ -140,7 +140,7 @@ describe('speech synthesis', () => {
}
});

await pageObjects.sendMessageViaMicrophone('input hint expected');
await pageObjects.sendMessageViaMicrophone('hint expected');

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

Expand Down
2 changes: 1 addition & 1 deletion __tests__/styleOptions.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ describe('style options', () => {
waitForSend: true
});

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

expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);
});
Expand Down
4 changes: 2 additions & 2 deletions __tests__/suggestedActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe('suggested-actions command', () => {
const imBackButton = buttons[1];

await imBackButton.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();
Expand Down Expand Up @@ -120,7 +120,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();
Expand Down
6 changes: 3 additions & 3 deletions __tests__/timestamp.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ test('update timestamp language on-the-fly', async () => {
await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('echo Hello, World!', { waitForSend: true });

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

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

Expand Down Expand Up @@ -83,7 +83,7 @@ test('prepend text', async () => {
await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('echo Hello, World!', { waitForSend: true });

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

expect(await driver.takeScreenshot()).toMatchImageSnapshot(imageSnapshotOptions);
});
Expand All @@ -94,7 +94,7 @@ test('change timestamp grouping on-the-fly', async () => {
await driver.wait(uiConnected(), timeouts.directLine);
await pageObjects.sendMessageViaSendBox('echo Hello, World!', { waitForSend: true });

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

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

Expand Down
4 changes: 2 additions & 2 deletions __tests__/updateActivity.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ test('should not replace activity without activity ID', async () => {
await pageObjects.sendMessageViaSendBox('echo This message will not be replaced by a carousel.', {
waitForSend: true
});
await driver.wait(minNumActivitiesShown(2), timeouts.directLine);
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);

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

await pageObjects.sendMessageViaSendBox('carousel', { waitForSend: true });
await driver.wait(minNumActivitiesShown(3), timeouts.directLine);
await driver.wait(minNumActivitiesShown(5), timeouts.directLine);
await driver.wait(allImagesLoaded(), timeouts.fetchImage);
await driver.wait(scrollToBottomCompleted(), timeouts.scrollToBottom);

Expand Down
Loading