Setup initial e2e tests with Spectron.

This commit is contained in:
Tony Anziano 2019-07-18 15:34:15 -07:00
Родитель b345a01b1c
Коммит 6107406bbb
15 изменённых файлов: 6095 добавлений и 418 удалений

1
.gitignore поставляемый
Просмотреть файл

@ -9,3 +9,4 @@ custom-botframework-webchat/dist
coverage
build/
.vscode/*
chrome-driver-log.txt

2
.vscode/launch.json поставляемый
Просмотреть файл

@ -41,7 +41,7 @@
"name": "Jest Current File",
"program": "${workspaceFolder}/node_modules/.bin/jest",
"args": [
"${relativeFile}",
"${fileBasename}",
],
"console": "integratedTerminal",
"internalConsoleOptions": "neverOpen",

Просмотреть файл

@ -6,6 +6,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## Unreleased
## Added
- [main] Added End-to-End tests using Spectron in PR [1696](https://github.com/microsoft/BotFramework-Emulator/pull/1696)
## v4.5.2 - 2019 - 07 - 17
## Fixed
- [client] Fixed some minor styling issues with the JSON inspector in PR [1691](https://github.com/microsoft/BotFramework-Emulator/pull/1691)

1257
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -7,8 +7,9 @@
"rebuild:keytar:electron": "rimraf node_modules/keytar/build && electron-rebuild",
"rebuild:keytar:node": "npm rebuild keytar",
"start": "cd packages\\app\\client && npm run start",
"test": "npm run rebuild:keytar:node && jest --no-cache --runInBand",
"test": "npm run rebuild:keytar:node && jest --no-cache --runInBand --testPathIgnorePatterns=/packages/app/main/e2e/",
"test:coveralls": "jest --runInBand --coverage --coverageReporters=text-lcov | coveralls",
"test:e2e": "npm run rebuild:keytar:electron && jest --no-cache --runInBand --testPathPattern=/e2e/.*\\.spec\\.ts$",
"test:gen-lcov": "npm run test -- --coverage --coverageReporters=lcov --coverageReporters=text",
"uploadcoverage": "cat ./coverage/lcov.info | coveralls"
},

Просмотреть файл

@ -115,6 +115,7 @@ export class BotCreationDialog extends React.Component<{}, BotCreationDialogStat
onChange={this.onInputChange}
label={'Bot name'}
required={true}
name={'create-bot-name'}
/>
<TextField
onChange={this.onInputChange}
@ -123,6 +124,7 @@ export class BotCreationDialog extends React.Component<{}, BotCreationDialogStat
label={'Endpoint URL'}
required={true}
value={this.state.endpoint.endpoint}
name={'create-bot-url'}
/>
{endpointWarning && <span className={styles.endpointWarning}>{endpointWarning}</span>}
<Row className={styles.multiInputRow}>
@ -199,7 +201,12 @@ export class BotCreationDialog extends React.Component<{}, BotCreationDialogStat
<DialogFooter>
<DefaultButton text="Cancel" onClick={this.onCancel} />
<PrimaryButton text="Save and connect" onClick={this.onSaveAndConnect} disabled={!requiredFieldsCompleted} />
<PrimaryButton
text="Save and connect"
onClick={this.onSaveAndConnect}
disabled={!requiredFieldsCompleted}
name={'create-bot-save'}
/>
</DialogFooter>
</Dialog>
);

Просмотреть файл

@ -133,7 +133,7 @@ export class OpenBotDialog extends Component<OpenBotDialogProps, OpenBotDialogSt
return (
<Dialog cancel={this.props.onDialogCancel} className={openBotStyles.themeOverrides} title="Open a bot">
<form onSubmit={this.onSubmit}>
<form id="open-bot-dialog" onSubmit={this.onSubmit}>
<div className={openBotStyles.autoCompleteBar}>
<AutoComplete
autoFocus={true}

Просмотреть файл

@ -0,0 +1,90 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
import { existsSync, unlinkSync } from 'fs';
import { join } from 'path';
import { Application } from 'spectron';
import { appPath, chromeDriverLogPath, electronPath } from './utils';
import { init, setupMock } from './mocks/electronDialog';
describe('Creating a bot', () => {
let app: Application;
beforeEach(async () => {
jest.setTimeout(30000);
app = new Application({
path: electronPath,
args: [appPath],
chromeDriverLogPath,
});
init(app);
await app.start();
});
afterEach(async () => {
if (app && app.isRunning()) {
await app.stop();
}
});
// TODO: could be made more comprehensive by checking that the bot was added to MRU
// on welcome page
it('should create a bot', async () => {
// open the create bot modal
const ctaLinks = await app.client.$$('button[class*="cta-link"]');
const createBotLink = ctaLinks[0];
await app.client.elementIdClick(createBotLink.ELEMENT);
// fill out the bot name and endpoint
await app.client.setValue('input[name="create-bot-name"]', 'e2e-test-bot');
await app.client.setValue('input[name="create-bot-url"]', 'http://localhost:3978/api/messages');
// mock the result from the save dialog
const tempPath = await app.electron.remote.app.getPath('temp');
const testBotPath = join(tempPath, 'e2e-test-bot.bot');
await setupMock(app, { method: 'showSaveDialog', value: testBotPath });
// click save
await app.client.click('button[name="create-bot-save"]');
// wait for Web Chat to show up
await app.client.waitForExist('div[role="log"] + div[role="form"]', 2000);
// verify that the bot was written to disk
expect(existsSync(testBotPath)).toBe(true);
// delete the bot from disk
unlinkSync(testBotPath);
});
});

Просмотреть файл

@ -0,0 +1,59 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import { join } from 'path';
import { Application } from 'spectron';
type ElectronDialogMethod =
| 'showOpenDialog'
| 'showSaveDialog'
| 'showMessageBox'
| 'showErrorBox'
| 'showCertificateTrustDialog';
// make spectron load the preload script first
export function init(app: Application & { args?: string[] }) {
if (app.args && app.args.length) {
// args: [appPath] -> [-r, dialogMock, appPath]
app.args.unshift(join(__dirname, 'electronDialogPreload.js'));
app.args.unshift('-r');
}
}
// setup an electron.dialog mock
export function setupMock(app: Application, options: { method: ElectronDialogMethod; value: any }): Promise<any> {
if (app) {
return app.electron.ipcRenderer.sendSync('SPECTRON/SETUP_DIALOG_MOCK', options);
}
}

Просмотреть файл

@ -0,0 +1,53 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
const { dialog, ipcMain } = require('electron');
// options: { method: string, value: string | string[] }
function mockDialogFunction(options) {
if (options.method && options.value) {
dialog[options.method] = function() {
return new Promise(resolve => {
resolve(options.value);
});
};
} else {
throw new Error('Options missing method or value keys.');
}
}
// register a listener that can be called into from test
ipcMain.on('SPECTRON/SETUP_DIALOG_MOCK', (e, options) => {
mockDialogFunction(options);
e.returnValue = true;
});

Просмотреть файл

@ -0,0 +1,61 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
import { Application } from 'spectron';
import { appPath, chromeDriverLogPath, electronPath } from './utils';
describe('Starting up the Emulator', () => {
let app: Application;
beforeEach(async () => {
jest.setTimeout(30000);
app = new Application({
path: electronPath,
args: [appPath],
chromeDriverLogPath,
});
await app.start();
});
afterEach(async () => {
if (app && app.isRunning()) {
await app.stop();
}
});
it('should show an initial window', async () => {
const count = await app.client.getWindowCount();
expect(count).toBe(1);
expect(await app.browserWindow.getTitle()).toBe('Bot Framework Emulator');
});
});

Просмотреть файл

@ -0,0 +1,43 @@
//
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license.
//
// Microsoft Bot Framework: http://botframework.com
//
// Bot Framework Emulator Github:
// https://github.com/Microsoft/BotFramwork-Emulator
//
// Copyright (c) Microsoft Corporation
// All rights reserved.
//
// MIT License:
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED ""AS IS"", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
import { join } from 'path';
export const electronPath =
process.platform === 'win32'
? join(__dirname, '..', 'node_modules', '.bin', 'electron.cmd')
: join(__dirname, '..', 'node_modules', '.bin', 'electron');
export const appPath = join(__dirname, '..', 'app', 'server', 'main.js');
export const chromeDriverLogPath = join(__dirname, 'chrome-driver-log.txt');

4925
packages/app/main/package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -115,6 +115,7 @@
"ncp": "^2.0.0",
"nodemon": "1.18.11",
"npm-run-all": "^4.1.5",
"spectron": "^6.0.0",
"through2": "^2.0.3",
"typescript": "3.1.1",
"vinyl-buffer": "^1.0.1",

Просмотреть файл

@ -278,7 +278,9 @@ class EmulatorApplication {
this.mainWindow = new Window(this.mainBrowserWindow);
if (process.env.NODE_ENV !== 'test') {
SplashScreen.show(this.mainBrowserWindow);
}
const page =
process.env.ELECTRON_TARGET_URL ||
url.format({