[MM-38875] Migrate E2E testing to Playwright, re-enable tests (#1800)

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* [MM-38875] Migrate E2E testing to Playwright, re-enable tests

* Add functionality to map view names to Playwright windows

* Added search box test

* Added robot.js for automating key presses

* Add test using key strokes to navigate menu

* Reload test and added webcontentsid to test helper

* Check Ctrl+Shift+R as well

* oops

* Reorganize

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
This commit is contained in:
Devin Binnie 2021-10-28 13:17:10 -04:00 committed by GitHub
parent bd0d9df7e3
commit c53e897bfd
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 1854 additions and 3477 deletions

View file

@ -65,7 +65,7 @@ commands:
default: ""
steps:
- run: wget -qO - https://download.opensuse.org/repositories/Emulators:/Wine:/Debian/xUbuntu_18.04/Release.key | apt-key add -
- run: apt-get update || true && apt-get install ca-certificates && apt-get update && apt-get -y install << parameters.apt_opts >>
- run: apt-get update || true && apt-get install -y ca-certificates libxtst-dev libpng++-dev && apt-get update && apt-get -y install << parameters.apt_opts >>
update_image:
description: "Update image"
@ -76,7 +76,7 @@ commands:
steps:
- update_base_image:
apt_opts: << parameters.apt_opts >>
- run: npm ci
- run: PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm ci
win_make:
description: "Run mattermost's makefile.ps1 on ./scripts/"

2975
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -28,6 +28,7 @@
"build:main": "webpack-cli --bail --config webpack.config.main.js",
"build:renderer": "webpack-cli --bail --config webpack.config.renderer.js",
"build-prod": "npm-run-all build:*",
"build-robotjs": "npm rebuild --runtime=electron --target=14.1.0 --disturl=https://atom.io/download/atom-shell --abi=83",
"start": "electron dist/ --disable-dev-mode",
"restart": "npm run build && npm run start",
"storybook": "start-storybook -p 9001 -c src/.storybook",
@ -38,7 +39,8 @@
"watch:main": "node scripts/watch_main_and_preload.js",
"watch:renderer": "webpack-dev-server --config webpack.config.renderer.js",
"test": "npm-run-all lint:js test:unit test:e2e",
"test:e2e": "cross-env NODE_ENV=test npm-run-all build test:e2e:build test:e2e:run",
"test:e2e": "cross-env NODE_ENV=test npm-run-all build build-robotjs test:e2e:build test:e2e:run",
"test:e2e:nobuild": "cross-env NODE_ENV=test npm-run-all test:e2e:build test:e2e:run",
"test:e2e:build": "webpack-cli --bail --config webpack.config.test.js",
"test:e2e:run": "electron-mocha -r @babel/register --reporter mocha-circleci-reporter dist/tests/e2e_bundle.js",
"test:unit": "npm-run-all test:unit:build test:unit:run",
@ -111,9 +113,10 @@
"mocha": "^5.2.0",
"mocha-circleci-reporter": "0.0.3",
"npm-run-all": "^4.1.5",
"playwright": "^1.15.2",
"robotjs": "^0.6.0",
"sass-loader": "^10.2.0",
"shebang-loader": "^0.0.1",
"spectron": "^15.0.0",
"style-loader": "^2.0.0",
"typescript": "^4.3.4",
"url-loader": "^1.1.2",

View file

@ -100,3 +100,6 @@ export const BROWSER_HISTORY_PUSH = 'browser-history-push';
export const APP_LOGGED_IN = 'app-logged-in';
export const GET_AVAILABLE_SPELL_CHECKER_LANGUAGES = 'get-available-spell-checker-languages';
export const GET_VIEW_NAME = 'get-view-name';
export const GET_VIEW_WEBCONTENTS_ID = 'get-view-webcontents-id';

View file

@ -51,6 +51,7 @@ export function displayMention(title: string, body: string, channel: {id: string
});
mention.on('click', () => {
log.info('notification click', serverName, mention);
if (serverName) {
windowManager.switchTab(serverName, TAB_MESSAGING);
webcontents.send('notification-clicked', {channel, teamId, url});

View file

@ -6,7 +6,7 @@
/* eslint-disable no-magic-numbers */
import {ipcRenderer, webFrame} from 'electron';
import {contextBridge, ipcRenderer, webFrame} from 'electron';
// I've filed an issue in electron-log https://github.com/megahertz/electron-log/issues/267
// we'll be able to use it again if there is a workaround for the 'os' import
@ -23,6 +23,8 @@ import {
CLOSE_TEAMS_DROPDOWN,
BROWSER_HISTORY_PUSH,
APP_LOGGED_IN,
GET_VIEW_NAME,
GET_VIEW_WEBCONTENTS_ID,
} from 'common/communication';
const UNREAD_COUNT_INTERVAL = 1000;
@ -36,6 +38,13 @@ let shouldSendNotifications;
console.log('Preload initialized');
if (process.env.NODE_ENV === 'test') {
contextBridge.exposeInMainWorld('testHelper', {
getViewName: () => ipcRenderer.invoke(GET_VIEW_NAME),
getWebContentsId: () => ipcRenderer.invoke(GET_VIEW_WEBCONTENTS_ID),
});
}
ipcRenderer.invoke('get-app-version').then(({name, version}) => {
appVersion = version;
appName = name;

View file

@ -77,13 +77,11 @@ export class MattermostView extends EventEmitter {
this.options = Object.assign({}, options);
this.options.webPreferences = {
nativeWindowOpen: true,
contextIsolation: process.env.NODE_ENV !== 'test',
preload,
additionalArguments: [
`version=${app.getVersion()}`,
`appName=${app.name}`,
],
nodeIntegration: process.env.NODE_ENV === 'test',
...options.webPreferences,
};
this.isVisible = false;
@ -273,12 +271,7 @@ export class MattermostView extends EventEmitter {
}
getWebContents = () => {
if (this.status === Status.READY) {
return this.view.webContents;
} else if (this.window) {
return this.window.webContents; // if it's not ready you are looking at the renderer process
}
return WindowManager.getMainWindow()?.webContents;
return this.view.webContents;
}
handleInputEvents = (_: Event, input: Input) => {

View file

@ -32,9 +32,7 @@ export class ModalView<T, T2> {
log.info(`preloading with ${preload}`);
this.view = new BrowserView({webPreferences: {
nativeWindowOpen: true,
contextIsolation: process.env.NODE_ENV !== 'test',
preload,
nodeIntegration: process.env.NODE_ENV === 'test',
// Workaround for this issue: https://github.com/electron/electron/issues/30993
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View file

@ -46,9 +46,7 @@ export default class TeamDropdownView {
const preload = getLocalPreload('dropdown.js');
this.view = new BrowserView({webPreferences: {
nativeWindowOpen: true,
contextIsolation: process.env.NODE_ENV !== 'test',
preload,
nodeIntegration: process.env.NODE_ENV === 'test',
// Workaround for this issue: https://github.com/electron/electron/issues/30993
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View file

@ -295,8 +295,6 @@ export class ViewManager {
const urlView = new BrowserView({
webPreferences: {
nativeWindowOpen: true,
contextIsolation: process.env.NODE_ENV !== 'test',
nodeIntegration: process.env.NODE_ENV === 'test',
// Workaround for this issue: https://github.com/electron/electron/issues/30993
// eslint-disable-next-line @typescript-eslint/ban-ts-comment

View file

@ -169,8 +169,6 @@ const generateNewWindowListener = (getServersFunction: () => TeamWithTabs[], spe
center: true,
webPreferences: {
nativeWindowOpen: true,
nodeIntegration: process.env.NODE_ENV === 'test',
contextIsolation: process.env.NODE_ENV !== 'test',
spellcheck: (typeof spellcheck === 'undefined' ? true : spellcheck),
},
});

View file

@ -80,8 +80,6 @@ function createMainWindow(config: CombinedConfig, options: {linuxAppIcon: string
backgroundColor: '#fff', // prevents blurry text: https://electronjs.org/docs/faq#the-font-looks-blurry-what-is-this-and-what-can-i-do
webPreferences: {
nativeWindowOpen: true,
nodeIntegration: process.env.NODE_ENV === 'test',
contextIsolation: process.env.NODE_ENV !== 'test',
disableBlinkFeatures: 'Auxclick',
preload,
spellcheck,

View file

@ -2,7 +2,7 @@
// See LICENSE.txt for license information.
import path from 'path';
import {app, BrowserWindow, nativeImage, systemPreferences, ipcMain, IpcMainEvent} from 'electron';
import {app, BrowserWindow, nativeImage, systemPreferences, ipcMain, IpcMainEvent, IpcMainInvokeEvent} from 'electron';
import log from 'electron-log';
import {CombinedConfig} from 'types/config';
@ -18,6 +18,8 @@ import {
UPDATE_SHORTCUT_MENU,
BROWSER_HISTORY_PUSH,
APP_LOGGED_IN,
GET_VIEW_NAME,
GET_VIEW_WEBCONTENTS_ID,
} from 'common/communication';
import urlUtils from 'common/utils/url';
@ -54,6 +56,8 @@ ipcMain.on(REACT_APP_INITIALIZED, handleReactAppInitialized);
ipcMain.on(LOADING_SCREEN_ANIMATION_FINISHED, handleLoadingScreenAnimationFinished);
ipcMain.on(BROWSER_HISTORY_PUSH, handleBrowserHistoryPush);
ipcMain.on(APP_LOGGED_IN, handleAppLoggedIn);
ipcMain.handle(GET_VIEW_NAME, handleGetViewName);
ipcMain.handle(GET_VIEW_WEBCONTENTS_ID, handleGetWebContentsId);
export function setConfig(data: CombinedConfig) {
if (data) {
@ -585,3 +589,11 @@ export function getCurrentTeamName() {
function handleAppLoggedIn(event: IpcMainEvent, viewName: string) {
status.viewManager?.reloadViewIfNeeded(viewName);
}
function handleGetViewName(event: IpcMainInvokeEvent) {
return getViewNameByWebContentsId(event.sender.id);
}
function handleGetWebContentsId(event: IpcMainInvokeEvent) {
return event.sender.id;
}

View file

@ -7,11 +7,13 @@ const fs = require('fs');
const path = require('path');
const Application = require('spectron').Application;
const {_electron: electron} = require('playwright');
const chai = require('chai');
const {ipcRenderer} = require('electron');
const {SHOW_SETTINGS_WINDOW} = require('../../src/common/communication');
const {asyncSleep} = require('./utils');
chai.should();
const sourceRootDir = path.join(__dirname, '../..');
@ -47,27 +49,61 @@ module.exports = {
});
},
cleanDataDir() {
try {
fs.rmdirSync(userDataDir, {recursive: true});
} catch (err) {
if (err.code !== 'ENOENT') {
// eslint-disable-next-line no-console
console.error(err);
}
}
},
createTestUserDataDir() {
if (!fs.existsSync(userDataDir)) {
fs.mkdirSync(userDataDir);
}
},
getSpectronApp() {
async getApp() {
const options = {
path: electronBinaryPath,
executablePath: electronBinaryPath,
args: [`${path.join(sourceRootDir, 'dist')}`, `--data-dir=${userDataDir}`, '--disable-dev-mode'],
chromeDriverArgs: [],
};
if (process.env.MM_DEBUG_SETTINGS) {
options.chromeDriverLogPath = './chromedriverlog.txt';
}
if (process.platform === 'darwin' || process.platform === 'linux') {
// on a mac, debbuging port might conflict with other apps
// this changes the default debugging port so chromedriver can run without issues.
options.chromeDriverArgs.push('remote-debugging-port=9222');
}
return new Application(options);
// if (process.env.MM_DEBUG_SETTINGS) {
// options.chromeDriverLogPath = './chromedriverlog.txt';
// }
// if (process.platform === 'darwin' || process.platform === 'linux') {
// // on a mac, debbuging port might conflict with other apps
// // this changes the default debugging port so chromedriver can run without issues.
// options.chromeDriverArgs.push('remote-debugging-port=9222');
//}
return electron.launch(options).then(async (app) => {
// Make sure the app has time to fully load
await asyncSleep(1000);
return app;
});
},
async getServerMap(app) {
const map = {};
await Promise.all(app.windows().map(async (win) => {
return win.evaluate(async () => {
if (!window.testHelper) {
return null;
}
const name = await window.testHelper.getViewName();
const webContentsId = await window.testHelper.getWebContentsId();
return {viewName: name, webContentsId};
}).then((result) => {
if (result) {
map[result.viewName] = {win, webContentsId: result.webContentsId};
}
});
}));
return map;
},
addClientCommands(client) {

View file

@ -2,153 +2,50 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
// TODO: Commenting out until Spectron is upgraded for Electron v14
'use strict';
// 'use strict';
const env = require('../modules/environment');
// const fs = require('fs');
describe('application', function desc() {
this.timeout(30000);
// const env = require('../modules/environment');
beforeEach(async () => {
env.createTestUserDataDir();
env.cleanTestConfig();
this.app = await env.getApp();
});
// describe('application', function desc() {
// this.timeout(30000);
afterEach(async () => {
if (this.app) {
await this.app.close();
}
});
// beforeEach(() => {
// env.createTestUserDataDir();
// env.cleanTestConfig();
// this.app = env.getSpectronApp();
// return this.app.start();
// });
it('should show the new server modal when no servers exist', async () => {
const newServerModal = this.app.windows().find((window) => window.url().includes('newServer'));
const modalTitle = await newServerModal.innerText('#newServerModal .modal-title');
modalTitle.should.equal('Add Server');
});
// afterEach(async () => {
// if (this.app && this.app.isRunning()) {
// await this.app.stop();
// }
// });
it('should show no servers configured in dropdown when no servers exist', async () => {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton');
dropdownButtonText.should.equal('No servers configured');
});
// // it('should show two windows if there is no config file', async () => {
// // await this.app.client.waitUntilWindowLoaded();
// // const count = await this.app.client.getWindowCount();
// // count.should.equal(2);
// // const opened = await this.app.browserWindow.isDevToolsOpened();
// // opened.should.be.false;
it('should be stopped when the app instance already exists', (done) => {
const secondApp = env.getApp();
// // const visible = await this.app.browserWindow.isVisible();
// // visible.should.be.true;
// // });
// if (process.platform === 'darwin') {
// it.skip('should show closed window with cmd+tab', async () => {
// // Unable to utilize Command key press due to: https://bugs.chromium.org/p/chromedriver/issues/detail?id=3023#c2
// await this.app.client.waitUntilWindowLoaded();
// await this.app.client.keys(['Meta', 'w']);
// let visible = await this.app.browserWindow.isVisible();
// visible.should.be.false;
// this.app.client.keys(['Meta', 'Tab']);
// visible = await this.app.browserWindow.isVisible();
// visible.should.be.true;
// });
// }
// it.skip('should restore window bounds', async () => {
// // bounds seems to be incorrectly calculated in some environments
// // - Windows 10: OK
// // - CircleCI: NG
// const expectedBounds = {x: 100, y: 200, width: 300, height: 400};
// fs.writeFileSync(env.boundsInfoPath, JSON.stringify(expectedBounds));
// await this.app.restart();
// const bounds = await this.app.browserWindow.getBounds();
// bounds.should.deep.equal(expectedBounds);
// });
// it('should NOT restore window bounds if the origin is located on outside of viewarea', async () => {
// // bounds seems to be incorrectly calculated in some environments (e.g. CircleCI)
// // - Windows 10: OK
// // - CircleCI: NG
// fs.writeFileSync(env.boundsInfoPath, JSON.stringify({x: -100000, y: 200, width: 300, height: 400}));
// await this.app.restart();
// let bounds = await this.app.browserWindow.getBounds();
// bounds.x.should.satisfy((x) => (x > -10000));
// fs.writeFileSync(env.boundsInfoPath, JSON.stringify({x: 100, y: 200000, width: 300, height: 400}));
// await this.app.restart();
// bounds = await this.app.browserWindow.getBounds();
// bounds.y.should.satisfy((y) => (y < 10000));
// });
// // it('should show settings.html when there is no config file', async () => {
// // await this.app.client.waitUntilWindowLoaded();
// // await this.app.client.pause(1000);
// // const url = await this.app.client.getUrl();
// // url.should.match(/\/settings.html$/);
// // const existing = await this.app.client.isExisting('#newServerModal');
// // existing.should.equal(true);
// // });
// // it('should show index.html when there is config file', async () => {
// // const config = {
// // version: 2,
// // teams: [{
// // name: 'example',
// // url: env.mattermostURL,
// // order: 0,
// // }, {
// // name: 'github',
// // url: 'https://github.com/',
// // order: 1,
// // }],
// // showTrayIcon: false,
// // trayIconTheme: 'light',
// // minimizeToTray: false,
// // notifications: {
// // flashWindow: 0,
// // bounceIcon: false,
// // bounceIconType: 'informational',
// // },
// // showUnreadBadge: true,
// // useSpellChecker: true,
// // enableHardwareAcceleration: true,
// // autostart: true,
// // darkMode: false,
// // };
// // fs.writeFileSync(env.configFilePath, JSON.stringify(config));
// // await this.app.restart();
// // const url = await this.app.client.getUrl();
// // url.should.match(/\/index.html$/);
// // });
// // it('should upgrade v0 config file', async () => {
// // const Config = require('../../src/common/config').default;
// // const newConfig = new Config(env.configFilePath);
// // const oldConfig = {
// // url: env.mattermostURL,
// // };
// // fs.writeFileSync(env.configFilePath, JSON.stringify(oldConfig));
// // await this.app.restart();
// // const url = await this.app.client.getUrl();
// // url.should.match(/\/index.html$/);
// // const str = fs.readFileSync(env.configFilePath, 'utf8');
// // const upgradedConfig = JSON.parse(str);
// // upgradedConfig.version.should.equal(newConfig.defaultData.version);
// // });
// // it.skip('should be stopped when the app instance already exists', (done) => {
// // const secondApp = env.getSpectronApp();
// // // In the correct case, 'start().then' is not called.
// // // So need to use setTimeout in order to finish this test.
// // const timer = setTimeout(() => {
// // done();
// // }, 3000);
// // secondApp.start().then(() => {
// // clearTimeout(timer);
// // return secondApp.stop();
// // }).then(() => {
// // done(new Error('Second app instance exists'));
// // });
// });
// In the correct case, 'start().then' is not called.
// So need to use setTimeout in order to finish this test.
const timer = setTimeout(() => {
done();
}, 3000);
secondApp.then(() => {
clearTimeout(timer);
return secondApp.close();
}).then(() => {
done(new Error('Second app instance exists'));
});
});
});

View file

@ -5,8 +5,10 @@
const fs = require('fs');
const http = require('http');
const path = require('path');
const robot = require('robotjs');
// const http = require('http');
// const path = require('path');
const env = require('../../modules/environment');
const {asyncSleep} = require('../../modules/utils');
@ -15,15 +17,51 @@ describe('renderer/index.html', function desc() {
this.timeout(30000);
const config = {
version: 2,
version: 3,
teams: [{
name: 'example',
url: env.mattermostURL,
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}],
showTrayIcon: false,
trayIconTheme: 'light',
@ -38,178 +76,123 @@ describe('renderer/index.html', function desc() {
enableHardwareAcceleration: true,
autostart: true,
darkMode: false,
lastActiveTeam: 0,
spellCheckerLocales: [],
};
const serverPort = 8181;
before(() => {
function serverCallback(req, res) {
res.writeHead(200, {
'Content-Type': 'text/html',
});
res.end(fs.readFileSync(path.resolve(env.sourceRootDir, 'test/modules/test.html'), 'utf-8'));
}
this.server = http.createServer(serverCallback).listen(serverPort, '127.0.0.1');
});
beforeEach(async () => {
env.createTestUserDataDir();
env.cleanTestConfig();
fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = env.getSpectronApp();
await this.app.start();
this.app = await env.getApp();
});
afterEach(async () => {
if (this.app && this.app.isRunning()) {
await this.app.stop();
if (this.app) {
await this.app.close();
}
});
after((done) => {
this.server.close(done);
it('should set src of browser view from config file', async () => {
const firstServer = this.app.windows().find((window) => window.url() === config.teams[0].url);
const secondServer = this.app.windows().find((window) => window.url() === config.teams[1].url);
firstServer.should.not.be.null;
secondServer.should.not.be.null;
});
// it('should set src of webview from config file', async () => {
// const src0 = await this.app.client.getAttribute('#mattermostView0', 'src');
// src0.should.equal(config.teams[0].url);
it('should set name of menu item from config file', async () => {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown'));
await mainWindow.click('.TeamDropdownButton');
const firstMenuItem = await dropdownView.innerText('.TeamDropdown button.TeamDropdown__button:nth-child(1) span');
const secondMenuItem = await dropdownView.innerText('.TeamDropdown button.TeamDropdown__button:nth-child(2) span');
// const src1 = await this.app.client.getAttribute('#mattermostView1', 'src');
// src1.should.equal(config.teams[1].url);
firstMenuItem.should.equal(config.teams[0].name);
secondMenuItem.should.equal(config.teams[1].name);
});
// const existing = await this.app.client.isExisting('#mattermostView2');
// existing.should.be.false;
// });
it('should only show dropdown when button is clicked', async () => {
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
const mainView = this.app.windows().find((window) => window.url().includes('index'));
// it('should set name of tab from config file', async () => {
// const tabName0 = await this.app.client.getText('#teamTabItem0');
// tabName0.should.equal(config.teams[0].name);
let dropdownHeight = await browserWindow.evaluate((window) => window.getBrowserViews().find((view) => view.webContents.getURL().includes('dropdown')).getBounds().height);
dropdownHeight.should.equal(0);
// const tabName1 = await this.app.client.getText('#teamTabItem1');
// tabName1.should.equal(config.teams[1].name);
// });
await mainView.click('.TeamDropdownButton');
dropdownHeight = await browserWindow.evaluate((window) => window.getBrowserViews().find((view) => view.webContents.getURL().includes('dropdown')).getBounds().height);
dropdownHeight.should.be.greaterThan(0);
// it('should show only the selected team', () => {
// return this.app.client.
// waitForVisible('#mattermostView0', 2000).
// waitForVisible('#mattermostView1', 2000, true).
// click('#teamTabItem1').
// waitForVisible('#mattermostView1', 2000).
// waitForVisible('#mattermostView0', 2000, true);
// });
await mainView.click('.TabBar');
dropdownHeight = await browserWindow.evaluate((window) => window.getBrowserViews().find((view) => view.webContents.getURL().includes('dropdown')).getBounds().height);
dropdownHeight.should.equal(0);
});
// validation now prevents incorrect url's from being used
// it.skip('should show error when using incorrect URL', async () => {
// this.timeout(30000);
// fs.writeFileSync(env.configFilePath, JSON.stringify({
// version: 2,
// teams: [{
// name: 'error_1',
// url: 'http://false',
// order: 0,
// }],
// }));
// await this.app.restart();
// return this.app.client.
// waitForVisible('#mattermostView0-fail', 20000);
// });
it('should show only the selected team', async () => {
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
// it('shouldn\'t set window title by using webview\'s one', async () => {
// fs.writeFileSync(env.configFilePath, JSON.stringify({
// version: 2,
// teams: [{
// name: 'title_test',
// url: `http://localhost:${serverPort}`,
// order: 0,
// }],
// }));
// await this.app.restart();
// await this.app.client.pause(2000);
// const windowTitle = await this.app.browserWindow.getTitle();
// windowTitle.should.equal('Mattermost Desktop App');
// });
let firstViewIsAttached = await browserWindow.evaluate((window, url) => Boolean(window.getBrowserViews().find((view) => view.webContents.getURL() === url)), env.mattermostURL);
firstViewIsAttached.should.be.true;
let secondViewIsAttached = await browserWindow.evaluate((window) => Boolean(window.getBrowserViews().find((view) => view.webContents.getURL() === 'https://github.com/')));
secondViewIsAttached.should.be.false;
// Skip because it's very unstable in CI
// it.skip('should update window title when the activated tab\'s title is updated', async () => {
// fs.writeFileSync(env.configFilePath, JSON.stringify({
// version: 2,
// teams: [{
// name: 'title_test_0',
// url: `http://localhost:${serverPort}`,
// order: 0,
// }, {
// name: 'title_test_1',
// url: `http://localhost:${serverPort}`,
// order: 1,
// }],
// }));
// await this.app.restart();
// await this.app.client.pause(500);
const mainView = this.app.windows().find((window) => window.url().includes('index'));
const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown'));
await mainView.click('.TeamDropdownButton');
await dropdownView.click('.TeamDropdown button.TeamDropdown__button:nth-child(2)');
// // Note: Indices of webview are correct.
// // Somehow they are swapped.
// await this.app.client.
// windowByIndex(2).
// execute(() => {
// document.title = 'Title 0';
// });
// await this.app.client.windowByIndex(0).pause(500);
// let windowTitle = await this.app.browserWindow.getTitle();
// windowTitle.should.equal('Title 0');
firstViewIsAttached = await browserWindow.evaluate((window, url) => Boolean(window.getBrowserViews().find((view) => view.webContents.getURL() === url)), env.mattermostURL);
firstViewIsAttached.should.be.false;
secondViewIsAttached = await browserWindow.evaluate((window) => Boolean(window.getBrowserViews().find((view) => view.webContents.getURL() === 'https://github.com/')));
secondViewIsAttached.should.be.true;
});
// await this.app.client.
// windowByIndex(1).
// execute(() => {
// document.title = 'Title 1';
// });
// await this.app.client.windowByIndex(0).pause(500);
// windowTitle = await this.app.browserWindow.getTitle();
// windowTitle.should.equal('Title 0');
// });
it('should open the new server prompt after clicking the add button', async () => {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown'));
await mainWindow.click('.TeamDropdownButton');
await dropdownView.click('.TeamDropdown__button.addServer');
// Skip because it's very unstable in CI
// it.skip('should update window title when a tab is selected', async () => {
// fs.writeFileSync(env.configFilePath, JSON.stringify({
// version: 2,
// teams: [{
// name: 'title_test_0',
// url: `http://localhost:${serverPort}`,
// order: 0,
// }, {
// name: 'title_test_1',
// url: `http://localhost:${serverPort}`,
// order: 1,
// }],
// }));
// await this.app.restart();
const newServerModal = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('newServer'),
});
const modalTitle = await newServerModal.innerText('#newServerModal .modal-title');
modalTitle.should.equal('Add Server');
});
// // Note: Indices of webview are correct.
// // Somehow they are swapped.
// await this.app.client.pause(500);
it('should switch to servers when keyboard shortcuts are pressed', async () => {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
// await this.app.client.
// windowByIndex(2).
// execute(() => {
// document.title = 'Title 0';
// });
// await this.app.client.
// windowByIndex(1).
// execute(() => {
// document.title = 'Title 1';
// });
// await this.app.client.windowByIndex(0).pause(500);
let dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton');
dropdownButtonText.should.equal('example');
// let windowTitle = await this.app.browserWindow.getTitle();
// windowTitle.should.equal('Title 0');
robot.keyTap('2', ['control', 'shift']);
dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton');
dropdownButtonText.should.equal('github');
// await this.app.client.click('#teamTabItem1').pause(500);
// windowTitle = await this.app.browserWindow.getTitle();
// windowTitle.should.equal('Title 1');
// });
robot.keyTap('1', ['control', 'shift']);
dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton');
dropdownButtonText.should.equal('example');
});
// it('should open the new server prompt after clicking the add button', async () => {
// // See settings_test for specs that cover the actual prompt
// await this.app.client.click('#addServerButton').pause(500);
// const isModalExisting = await this.app.client.isExisting('#newServerModal');
// isModalExisting.should.be.true;
// });
if (process.platform !== 'darwin') {
it('should open the 3 dot menu with Alt', async () => {
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
mainWindow.should.not.be.null;
// Settings window should open if Alt works
robot.keyTap('alt');
robot.keyTap('enter');
robot.keyTap('f');
robot.keyTap('s');
robot.keyTap('enter');
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
settingsWindow.should.not.be.null;
});
}
});

View file

@ -0,0 +1,266 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
const fs = require('fs');
const env = require('../../modules/environment');
const {asyncSleep} = require('../../modules/utils');
describe('modals', function desc() {
this.timeout(30000);
const config = {
version: 3,
teams: [{
name: 'example',
url: env.mattermostURL,
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
darkMode: false,
lastActiveTeam: 0,
spellCheckerLocales: [],
};
beforeEach(async () => {
env.createTestUserDataDir();
env.cleanTestConfig();
fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = await env.getApp();
});
afterEach(async () => {
if (this.app) {
await this.app.close();
}
});
describe('RemoveServerModal', () => {
let removeServerView;
beforeEach(async () => {
const mainView = this.app.windows().find((window) => window.url().includes('index'));
const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown'));
await mainView.click('.TeamDropdownButton');
await dropdownView.hover('.TeamDropdown .TeamDropdown__button:nth-child(1)');
await dropdownView.click('.TeamDropdown .TeamDropdown__button:nth-child(1) button.TeamDropdown__button-remove');
removeServerView = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('removeServer'),
});
});
it('should remove existing team on click Remove', async () => {
await removeServerView.click('button:has-text("Remove")');
await asyncSleep(1000);
const expectedConfig = JSON.parse(JSON.stringify(config.teams.slice(1)));
expectedConfig.forEach((value) => {
value.order--;
});
const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
savedConfig.teams.should.deep.equal(expectedConfig);
});
it('should NOT remove existing team on click Cancel', async () => {
await removeServerView.click('button:has-text("Cancel")');
await asyncSleep(1000);
const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
savedConfig.teams.should.deep.equal(config.teams);
});
it('should disappear on click Close', async () => {
await removeServerView.click('button.close');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('removeServer')));
existing.should.be.false;
});
it('should disappear on click background', async () => {
await removeServerView.click('.modal', {position: {x: 20, y: 20}});
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('removeServer')));
existing.should.be.false;
});
});
describe('NewTeamModal', () => {
let newServerView;
beforeEach(async () => {
const mainView = this.app.windows().find((window) => window.url().includes('index'));
const dropdownView = this.app.windows().find((window) => window.url().includes('dropdown'));
await mainView.click('.TeamDropdownButton');
await dropdownView.click('.TeamDropdown .TeamDropdown__button.addServer');
newServerView = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('newServer'),
});
// wait for autofocus to finish
await asyncSleep(500);
});
it('should open the new server modal', async () => {
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('newServer')));
existing.should.be.true;
});
it('should close the window after clicking cancel', async () => {
await newServerView.click('#cancelNewServerModal');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('newServer')));
existing.should.be.false;
});
it('should not be valid if no team name has been set', async () => {
await newServerView.click('#saveNewServerModal');
const existing = await newServerView.isVisible('#teamNameInput.is-invalid');
existing.should.be.true;
});
it('should not be valid if no server address has been set', async () => {
await newServerView.click('#saveNewServerModal');
const existing = await newServerView.isVisible('#teamUrlInput.is-invalid');
existing.should.be.true;
});
describe('Valid server name', async () => {
beforeEach(async () => {
await newServerView.type('#teamNameInput', 'TestTeam');
await newServerView.click('#saveNewServerModal');
});
it('should not be marked invalid', async () => {
const existing = await newServerView.isVisible('#teamNameInput.is-invalid');
existing.should.be.false;
});
it('should not be possible to click save', async () => {
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
(disabled === '').should.be.true;
});
});
describe('Valid server url', () => {
beforeEach(async () => {
await newServerView.type('#teamUrlInput', 'http://example.org');
await newServerView.click('#saveNewServerModal');
});
it('should be valid', async () => {
const existing = await newServerView.isVisible('#teamUrlInput.is-invalid');
existing.should.be.false;
});
it('should not be possible to click save', async () => {
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
(disabled === '').should.be.true;
});
});
it('should not be valid if an invalid server address has been set', async () => {
await newServerView.type('#teamUrlInput', 'superInvalid url');
await newServerView.click('#saveNewServerModal');
const existing = await newServerView.isVisible('#teamUrlInput.is-invalid');
existing.should.be.true;
});
describe('Valid Team Settings', () => {
beforeEach(async () => {
await newServerView.type('#teamUrlInput', 'http://example.org');
await newServerView.type('#teamNameInput', 'TestTeam');
});
it('should be possible to click add', async () => {
const disabled = await newServerView.getAttribute('#saveNewServerModal', 'disabled');
(disabled === null).should.be.true;
});
it('should add the team to the config file', async () => {
await newServerView.click('#saveNewServerModal');
await asyncSleep(1000);
const existing = Boolean(await this.app.windows().find((window) => window.url().includes('newServer')));
existing.should.be.false;
const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
savedConfig.teams.should.deep.contain({
name: 'TestTeam',
url: 'http://example.org',
order: 2,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
},
],
lastActiveTab: 0,
});
});
});
});
});

View file

@ -4,529 +4,265 @@
// TODO: fix test with new settings window
// 'use strict';
// const fs = require('fs');
// const env = require('../../modules/environment');
// const {asyncSleep} = require('../../modules/utils');
// describe('renderer/settings.html', function desc() {
// this.timeout(30000);
// const config = {
// version: 2,
// teams: [{
// name: 'example',
// url: env.mattermostURL,
// order: 0,
// }, {
// name: 'github',
// url: 'https://github.com/',
// order: 1,
// }],
// showTrayIcon: false,
// trayIconTheme: 'light',
// minimizeToTray: false,
// notifications: {
// flashWindow: 0,
// bounceIcon: false,
// bounceIconType: 'informational',
// },
// showUnreadBadge: true,
// useSpellChecker: true,
// enableHardwareAcceleration: true,
// autostart: true,
// darkMode: false,
// };
// beforeEach(async () => {
// fs.writeFileSync(env.configFilePath, JSON.stringify(config));
// await asyncSleep(1000);
// this.app = env.getSpectronApp();
// await this.app.start();
// });
// afterEach(async () => {
// if (this.app && this.app.isRunning()) {
// await this.app.stop();
// }
// });
// describe('Close button', async () => {
// // it.skip('should show index.html when it\'s clicked', async () => {
// // env.addClientCommands(this.app.client);
// // await this.app.client.
// // loadSettingsPage().
// // click('#btnClose').
// // pause(1000);
// // const url = await this.app.client.getUrl();
// // url.should.match(/\/index.html(\?.+)?$/);
// // });
// it('should be disabled when the number of servers is zero', async () => {
// await this.app.stop();
// env.cleanTestConfig();
// await this.app.start();
// await this.app.client.waitUntilWindowLoaded().
// waitForVisible('#newServerModal', 10000).
// click('#cancelNewServerModal');
// let isCloseButtonEnabled = await this.app.client.isEnabled('#btnClose');
// isCloseButtonEnabled.should.equal(false);
// await this.app.client.
// waitForVisible('#newServerModal', true).
// pause(250).
// click('#addNewServer').
// waitForVisible('#newServerModal').
// setValue('#teamNameInput', 'TestTeam').
// pause(100).
// setValue('#teamUrlInput', 'http://example.org').
// click('#saveNewServerModal').
// waitForVisible('#newServerModal', true).
// waitForVisible('#serversSaveIndicator').
// waitForVisible('#serversSaveIndicator', 10000, true); // at least 2500 ms to disappear
// isCloseButtonEnabled = await this.app.client.isEnabled('#btnClose');
// isCloseButtonEnabled.should.equal(true);
// });
// });
// it('should show NewServerModal after all servers are removed', async () => {
// const modalTitleSelector = '.modal-title=Remove Server';
// env.addClientCommands(this.app.client);
// await this.app.client.
// loadSettingsPage().
// click('=Remove').
// waitForVisible(modalTitleSelector).
// element('.modal-dialog').click('.btn=Remove').
// pause(500).
// click('=Remove').
// waitForVisible(modalTitleSelector).
// element('.modal-dialog').click('.btn=Remove').
// pause(500);
// const isModalExisting = await this.app.client.isExisting('#newServerModal');
// isModalExisting.should.be.true;
// });
// // describe('Server list', () => {
// // it.skip('should open the corresponding tab when a server list item is clicked', async () => {
// // env.addClientCommands(this.app.client);
// // await this.app.client.
// // loadSettingsPage().
// // click('h4=example').
// // pause(1000).
// // waitUntilWindowLoaded();
// // let indexURL = await this.app.client.getUrl();
// // indexURL.should.match(/\/index.html(\?.+)?$/);
// // let isView0Visible = await this.app.client.isVisible('#mattermostView0');
// // isView0Visible.should.be.true;
// // let isView1Visible = await this.app.client.isVisible('#mattermostView1');
// // isView1Visible.should.be.false;
// // await this.app.client.
// // loadSettingsPage().
// // click('h4=github').
// // pause(1000).
// // waitUntilWindowLoaded();
// // indexURL = await this.app.client.getUrl();
// // indexURL.should.match(/\/index.html(\?.+)?$/);
// // isView0Visible = await this.app.client.isVisible('#mattermostView0');
// // isView0Visible.should.be.false;
// // isView1Visible = await this.app.client.isVisible('#mattermostView1');
// // isView1Visible.should.be.true;
// // });
// // });
// describe('Options', () => {
// // describe.skip('Hide Menu Bar', () => {
// // it('should appear on win32 or linux', async () => {
// // const expected = (process.platform === 'win32' || process.platform === 'linux');
// // env.addClientCommands(this.app.client);
// // await this.app.client.loadSettingsPage();
// // const existing = await this.app.client.isExisting('#inputHideMenuBar');
// // existing.should.equal(expected);
// // });
// // [true, false].forEach((v) => {
// // env.shouldTest(it, env.isOneOf(['win32', 'linux']))(`should be saved and loaded: ${v}`, async () => {
// // env.addClientCommands(this.app.client);
// // await this.app.client.
// // loadSettingsPage().
// // scroll('#inputHideMenuBar');
// // const isSelected = await this.app.client.isSelected('#inputHideMenuBar');
// // if (isSelected !== v) {
// // await this.app.client.click('#inputHideMenuBar');
// // }
// // await this.app.client.
// // pause(600).
// // click('#btnClose').
// // pause(1000);
// // const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
// // savedConfig.hideMenuBar.should.equal(v);
// // let autoHide = await this.app.browserWindow.isMenuBarAutoHide();
// // autoHide.should.equal(v);
// // // confirm actual behavior
// // await this.app.restart();
// // env.addClientCommands(this.app.client);
// // autoHide = await this.app.browserWindow.isMenuBarAutoHide();
// // autoHide.should.equal(v);
// // await this.app.loadSettingsPage();
// // autoHide = await this.app.client.isSelected('#inputHideMenuBar');
// // autoHide.should.equal(v);
// // });
// // });
// // });
// describe('Start app on login', () => {
// it('should appear on win32 or linux', async () => {
// const expected = (process.platform === 'win32' || process.platform === 'linux');
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting('#inputAutoStart');
// existing.should.equal(expected);
// });
// });
// describe('Show icon in menu bar / notification area', () => {
// it('should appear on darwin or linux', async () => {
// const expected = (process.platform === 'darwin' || process.platform === 'linux');
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting('#inputShowTrayIcon');
// existing.should.equal(expected);
// });
// describe('Save tray icon setting on mac', () => {
// env.shouldTest(it, env.isOneOf(['darwin', 'linux']))('should be saved when it\'s selected', async () => {
// env.addClientCommands(this.app.client);
// await this.app.browserWindow.setSize(1024, 768); // Resize the window to click the element
// await this.app.client.
// loadSettingsPage().
// click('#inputShowTrayIcon').
// waitForAppOptionsAutoSaved();
// let config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config0.showTrayIcon.should.true;
// await this.app.client.
// click('#inputShowTrayIcon').
// waitForAppOptionsAutoSaved();
// config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config0.showTrayIcon.should.false;
// });
// });
// describe('Save tray icon theme on linux', () => {
// env.shouldTest(it, process.platform === 'linux')('should be saved when it\'s selected', async () => {
// env.addClientCommands(this.app.client);
// await this.app.browserWindow.setSize(1024, 768); // Resize the window to click the element
// await this.app.client.
// loadSettingsPage().
// click('#inputShowTrayIcon').
// click('input[value="dark"]').
// pause(700); // wait auto-save
// const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config0.trayIconTheme.should.equal('dark');
// await this.app.client.
// click('input[value="light"]').
// pause(700); // wait auto-save
// const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config1.trayIconTheme.should.equal('light');
// });
// });
// });
// describe('Leave app running in notification area when application window is closed', () => {
// it('should appear on linux', async () => {
// const expected = (process.platform === 'linux');
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting('#inputMinimizeToTray');
// existing.should.equal(expected);
// });
// });
// // describe.skip('Toggle window visibility when clicking on the tray icon', () => {
// // it('should appear on win32', async () => {
// // const expected = (process.platform === 'win32');
// // env.addClientCommands(this.app.client);
// // await this.app.client.loadSettingsPage();
// // const existing = await this.app.client.isExisting('#inputToggleWindowOnTrayIconClick');
// // existing.should.equal(expected);
// // });
// // });
// describe('Flash app window and taskbar icon when a new message is received', () => {
// it('should appear on win32 and linux', async () => {
// const expected = (process.platform === 'win32' || process.platform === 'linux');
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting('#inputflashWindow');
// existing.should.equal(expected);
// });
// });
// describe('Show red badge on taskbar icon to indicate unread messages', () => {
// it('should appear on darwin or win32', async () => {
// const expected = (process.platform === 'darwin' || process.platform === 'win32');
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting('#inputShowUnreadBadge');
// existing.should.equal(expected);
// });
// });
// describe('Check spelling', () => {
// it('should appear and be selectable', async () => {
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting('#inputSpellChecker');
// existing.should.equal(true);
// const selected = await this.app.client.isSelected('#inputSpellChecker');
// selected.should.equal(true);
// const windowBounds = await this.app.browserWindow.getBounds();
// const inputLocation = await this.app.client.getLocation('#inputSpellChecker');
// const offset = (inputLocation.y - windowBounds.height) + 100;
// await this.app.client.
// scroll(0, offset).
// click('#inputSpellChecker').
// pause(5000);
// const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config1.useSpellChecker.should.equal(false);
// });
// });
// describe('Enable GPU hardware acceleration', () => {
// it('should save selected option', async () => {
// const ID_INPUT_ENABLE_HARDWARE_ACCELERATION = '#inputEnableHardwareAcceleration';
// env.addClientCommands(this.app.client);
// await this.app.client.
// loadSettingsPage().
// waitForExist(ID_INPUT_ENABLE_HARDWARE_ACCELERATION, 5000).
// scroll(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
// const selected = await this.app.client.isSelected(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
// selected.should.equal(true); // default is true
// await this.app.client.click(ID_INPUT_ENABLE_HARDWARE_ACCELERATION).
// waitForVisible('#appOptionsSaveIndicator', 5000).
// waitForVisible('#appOptionsSaveIndicator', 5000, true); // at least 2500 ms to disappear
// const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config0.enableHardwareAcceleration.should.equal(false);
// await this.app.client.click(ID_INPUT_ENABLE_HARDWARE_ACCELERATION).
// waitForVisible('#appOptionsSaveIndicator', 5000).
// waitForVisible('#appOptionsSaveIndicator', 5000, true); // at least 2500 ms to disappear
// const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
// config1.enableHardwareAcceleration.should.equal(true);
// });
// });
// });
// describe('RemoveServerModal', () => {
// const modalTitleSelector = '.modal-title=Remove Server';
// beforeEach(async () => {
// env.addClientCommands(this.app.client);
// await this.app.client.loadSettingsPage();
// const existing = await this.app.client.isExisting(modalTitleSelector);
// existing.should.be.false;
// const visible = await this.app.client.isVisible(modalTitleSelector);
// visible.should.be.false;
// await this.app.client.
// click('=Remove').
// waitForVisible(modalTitleSelector);
// });
// it('should remove existing team on click Remove', async () => {
// await this.app.client.
// element('.modal-dialog').click('.btn=Remove').
// waitForExist(modalTitleSelector, 5000, true);
// await this.app.client.waitForVisible('#serversSaveIndicator', 10000, true);
// const expectedConfig = JSON.parse(JSON.stringify(config.teams.slice(1)));
// expectedConfig.forEach((value) => {
// value.order--;
// });
// const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
// savedConfig.teams.should.deep.equal(expectedConfig);
// });
// it('should NOT remove existing team on click Cancel', async () => {
// await this.app.client.
// element('.modal-dialog').click('.btn=Cancel').
// waitForExist(modalTitleSelector, 5000, true);
// await this.app.client.waitForVisible('#serversSaveIndicator', 10000, true);
// const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
// savedConfig.teams.should.deep.equal(config.teams);
// });
// it('should disappear on click Close', async () => {
// await this.app.client.
// element('.modal-dialog').click('button.close').
// waitForVisible(modalTitleSelector, 10000, true);
// const existing = await this.app.client.isExisting(modalTitleSelector);
// existing.should.be.false;
// });
// it('should disappear on click background', async () => {
// await this.app.browserWindow.setSize(1024, 768); // Resize the window to click the center of <body>
// await this.app.client.
// click('body').
// waitForVisible(modalTitleSelector, 10000, true);
// const existing = await this.app.client.isExisting(modalTitleSelector);
// existing.should.be.false;
// });
// });
// describe('NewTeamModal', () => {
// beforeEach(() => {
// env.addClientCommands(this.app.client);
// return this.app.client.
// loadSettingsPage().
// click('#addNewServer').
// pause(1000);
// });
// it('should open the new server modal', () => {
// return this.app.client.isExisting('#newServerModal').then((existing) => {
// existing.should.be.true;
// });
// });
// it('should close the window after clicking cancel', () => {
// return this.app.client.
// click('#cancelNewServerModal').
// waitForExist('#newServerModal', 10000, true).
// isExisting('#newServerModal').then((existing) => {
// existing.should.be.false;
// });
// });
// it('should not be valid if no team name has been set', () => {
// return this.app.client.
// click('#saveNewServerModal').
// waitForExist('.has-error #teamNameInput', 10000).
// isExisting('.has-error #teamNameInput').then((existing) => {
// existing.should.be.true;
// });
// });
// it('should not be valid if no server address has been set', () => {
// return this.app.client.
// click('#saveNewServerModal').
// waitForExist('.has-error #teamUrlInput', 10000).
// isExisting('.has-error #teamUrlInput').then((existing) => {
// existing.should.be.true;
// });
// });
// describe('Valid server name', () => {
// beforeEach(() => {
// return this.app.client.
// setValue('#teamNameInput', 'TestTeam').
// click('#saveNewServerModal');
// });
// it('should not be marked invalid', () => {
// return this.app.client.
// isExisting('.has-error #teamNameInput').then((existing) => {
// existing.should.be.false;
// });
// });
// it('should not be possible to click save', () => {
// return this.app.client.
// getAttribute('#saveNewServerModal', 'disabled').then((disabled) => {
// disabled.should.equal('true');
// });
// });
// });
// describe('Valid server url', () => {
// beforeEach(() => {
// return this.app.client.
// setValue('#teamUrlInput', 'http://example.org').
// click('#saveNewServerModal');
// });
// it('should be valid', () => {
// return this.app.client.
// isExisting('.has-error #teamUrlInput').then((existing) => {
// existing.should.be.false;
// });
// });
// it('should not be possible to click save', () => {
// return this.app.client.
// getAttribute('#saveNewServerModal', 'disabled').then((disabled) => {
// disabled.should.equal('true');
// });
// });
// });
// it('should not be valid if an invalid server address has been set', () => {
// return this.app.client.
// setValue('#teamUrlInput', 'superInvalid url').
// click('#saveNewServerModal').
// pause(500).
// isExisting('.has-error #teamUrlInput').then((existing) => {
// existing.should.be.true;
// });
// });
// describe('Valid Team Settings', () => {
// beforeEach(() => {
// return this.app.client.
// setValue('#teamUrlInput', 'http://example.org').
// setValue('#teamNameInput', 'TestTeam');
// });
// it('should be possible to click add', () => {
// return this.app.client.
// getAttribute('#saveNewServerModal', 'disabled').then((disabled) => {
// (disabled === null).should.be.true;
// });
// });
// it('should add the team to the config file', async () => {
// await this.app.client.
// click('#saveNewServerModal').
// waitForVisible('#newServerModal', 10000, true).
// waitForVisible('#serversSaveIndicator', 10000).
// waitForVisible('#serversSaveIndicator', 10000, true). // at least 2500 ms to disappear
// waitUntilWindowLoaded();
// const savedConfig = JSON.parse(fs.readFileSync(env.configFilePath, 'utf8'));
// savedConfig.teams.should.deep.contain({
// name: 'TestTeam',
// url: 'http://example.org',
// order: 2,
// });
// });
// });
// });
// });
'use strict';
const fs = require('fs');
const {SHOW_SETTINGS_WINDOW} = require('../../../src/common/communication');
const env = require('../../modules/environment');
const {asyncSleep} = require('../../modules/utils');
describe('renderer/settings.html', function desc() {
this.timeout(30000);
const config = {
version: 3,
teams: [{
name: 'example',
url: env.mattermostURL,
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
darkMode: false,
lastActiveTeam: 0,
spellCheckerLocales: [],
};
beforeEach(async () => {
env.createTestUserDataDir();
env.cleanTestConfig();
fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = await env.getApp();
});
afterEach(async () => {
if (this.app) {
await this.app.close();
}
});
describe('Options', () => {
describe('Start app on login', () => {
it('should appear on win32 or linux', async () => {
const expected = (process.platform === 'win32' || process.platform === 'linux');
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const existing = await settingsWindow.isVisible('#inputAutoStart');
existing.should.equal(expected);
});
});
describe('Show icon in menu bar / notification area', () => {
it('should appear on darwin or linux', async () => {
const expected = (process.platform === 'darwin' || process.platform === 'linux');
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const existing = await settingsWindow.isVisible('#inputShowTrayIcon');
existing.should.equal(expected);
});
describe('Save tray icon setting on mac', () => {
env.shouldTest(it, env.isOneOf(['darwin', 'linux']))('should be saved when it\'s selected', async () => {
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
await settingsWindow.click('#inputShowTrayIcon');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
let config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.showTrayIcon.should.true;
await settingsWindow.click('#inputShowTrayIcon');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.showTrayIcon.should.false;
});
});
describe('Save tray icon theme on linux', () => {
env.shouldTest(it, process.platform === 'linux')('should be saved when it\'s selected', async () => {
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
await settingsWindow.click('#inputShowTrayIcon');
await settingsWindow.click('input[value="dark"]');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.trayIconTheme.should.equal('dark');
await settingsWindow.click('input[value="light"]');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.trayIconTheme.should.equal('light');
});
});
});
describe('Leave app running in notification area when application window is closed', () => {
it('should appear on linux', async () => {
const expected = (process.platform === 'linux');
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const existing = await settingsWindow.isVisible('#inputMinimizeToTray');
existing.should.equal(expected);
});
});
describe('Flash app window and taskbar icon when a new message is received', () => {
it('should appear on win32 and linux', async () => {
const expected = (process.platform === 'win32' || process.platform === 'linux');
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const existing = await settingsWindow.isVisible('#inputflashWindow');
existing.should.equal(expected);
});
});
describe('Show red badge on taskbar icon to indicate unread messages', () => {
it('should appear on darwin or win32', async () => {
const expected = (process.platform === 'darwin' || process.platform === 'win32');
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const existing = await settingsWindow.isVisible('#inputShowUnreadBadge');
existing.should.equal(expected);
});
});
describe('Check spelling', () => {
it('should appear and be selectable', async () => {
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const existing = await settingsWindow.isVisible('#inputSpellChecker');
existing.should.equal(true);
const selected = await settingsWindow.isChecked('#inputSpellChecker');
selected.should.equal(true);
await settingsWindow.click('#inputSpellChecker');
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.useSpellChecker.should.equal(false);
});
});
describe('Enable GPU hardware acceleration', () => {
it('should save selected option', async () => {
const ID_INPUT_ENABLE_HARDWARE_ACCELERATION = '#inputEnableHardwareAcceleration';
this.app.evaluate(({ipcMain}, showWindow) => {
ipcMain.emit(showWindow);
}, SHOW_SETTINGS_WINDOW);
const settingsWindow = await this.app.waitForEvent('window', {
predicate: (window) => window.url().includes('settings'),
});
await settingsWindow.waitForSelector('.settingsPage.container');
const selected = await settingsWindow.isChecked(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
selected.should.equal(true); // default is true
await settingsWindow.click(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
const config0 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config0.enableHardwareAcceleration.should.equal(false);
await settingsWindow.click(ID_INPUT_ENABLE_HARDWARE_ACCELERATION);
await settingsWindow.waitForSelector('.IndicatorContainer :text("Saved")');
const config1 = JSON.parse(fs.readFileSync(env.configFilePath, 'utf-8'));
config1.enableHardwareAcceleration.should.equal(true);
});
});
});
});

116
test/specs/config_test.js Normal file
View file

@ -0,0 +1,116 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
const fs = require('fs');
const env = require('../modules/environment');
describe('config', function desc() {
this.timeout(30000);
beforeEach(async () => {
env.createTestUserDataDir();
env.cleanTestConfig();
});
afterEach(async () => {
if (this.app) {
try {
await this.app.close();
// eslint-disable-next-line no-empty
} catch (err) {}
}
});
it('should show servers in dropdown when there is config file', async () => {
const config = {
version: 3,
teams: [{
name: 'example',
url: env.mattermostURL,
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: true,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: true,
},
],
lastActiveTab: 0,
}],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
darkMode: false,
lastActiveTeam: 0,
spellCheckerLocales: [],
};
fs.writeFileSync(env.configFilePath, JSON.stringify(config));
this.app = await env.getApp();
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton');
dropdownButtonText.should.equal('example');
await this.app.close();
});
it('should upgrade v0 config file', async () => {
const Config = require('../../src/common/config').default;
const newConfig = new Config(env.configFilePath);
const oldConfig = {
url: env.mattermostURL,
};
fs.writeFileSync(env.configFilePath, JSON.stringify(oldConfig));
this.app = await env.getApp();
const mainWindow = this.app.windows().find((window) => window.url().includes('index'));
const dropdownButtonText = await mainWindow.innerText('.TeamDropdownButton:has-text("Primary team")');
dropdownButtonText.should.equal('Primary team');
const str = fs.readFileSync(env.configFilePath, 'utf8');
const upgradedConfig = JSON.parse(str);
upgradedConfig.version.should.equal(newConfig.defaultData.version);
await this.app.close();
});
});

View file

@ -2,9 +2,13 @@
// See LICENSE.txt for license information.
import './app_test.js';
import './security_test.js';
import './spellchecker_test.js';
import './config_test.js';
import './mattermost_test.js';
import './window_test.js';
import './browser/index_test.js';
import './browser/modal_test.js';
import './browser/settings_test.js';
import './main/user_activity_monitor_test.js';
import './utils/util_test.js';

View file

@ -0,0 +1,106 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
const fs = require('fs');
const env = require('../modules/environment');
const {asyncSleep} = require('../modules/utils');
describe('mattermost', function desc() {
this.timeout(30000);
const config = {
version: 3,
teams: [{
name: 'example',
url: env.mattermostURL,
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: false,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: false,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: false,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: false,
},
],
lastActiveTab: 0,
}],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
darkMode: false,
lastActiveTeam: 0,
spellCheckerLocales: [],
};
beforeEach(async () => {
env.cleanDataDir();
env.createTestUserDataDir();
env.cleanTestConfig();
fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = await env.getApp();
this.serverMap = await env.getServerMap(this.app);
});
afterEach(async () => {
if (this.app) {
await this.app.close();
}
});
// TODO: enable when we have a server to test against
it.skip('Control+F should focus the search bar in Mattermost', async () => {
const loadingScreen = this.app.windows().find((window) => window.url().includes('loadingScreen'));
await loadingScreen.waitForSelector('.LoadingScreen', {state: 'hidden'});
const firstServer = this.serverMap[`${config.teams[0].name}___TAB_MESSAGING`].win;
await env.loginToMattermost(firstServer);
await firstServer.waitForSelector('#searchBox');
await firstServer.press('body', process.platform === 'darwin' ? 'Meta+F' : 'Control+F');
const isFocused = await firstServer.$eval('#searchBox', (el) => el === document.activeElement);
isFocused.should.be.true;
const text = await firstServer.inputValue('#searchBox');
text.should.include('in:');
});
});

143
test/specs/menu_test.js Normal file
View file

@ -0,0 +1,143 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
const fs = require('fs');
// const http = require('http');
// const path = require('path');
const robot = require('robotjs');
const env = require('../modules/environment');
const {asyncSleep} = require('../modules/utils');
describe('mattermost', function desc() {
this.timeout(30000);
const config = {
version: 3,
teams: [{
name: 'example',
url: env.mattermostURL,
order: 0,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: false,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: false,
},
],
lastActiveTab: 0,
}, {
name: 'github',
url: 'https://github.com/',
order: 1,
tabs: [
{
name: 'TAB_MESSAGING',
order: 0,
isOpen: true,
},
{
name: 'TAB_FOCALBOARD',
order: 1,
isOpen: false,
},
{
name: 'TAB_PLAYBOOKS',
order: 2,
isOpen: false,
},
],
lastActiveTab: 0,
}],
showTrayIcon: false,
trayIconTheme: 'light',
minimizeToTray: false,
notifications: {
flashWindow: 0,
bounceIcon: false,
bounceIconType: 'informational',
},
showUnreadBadge: true,
useSpellChecker: true,
enableHardwareAcceleration: true,
autostart: true,
darkMode: false,
lastActiveTeam: 0,
spellCheckerLocales: [],
};
beforeEach(async () => {
env.cleanDataDir();
env.createTestUserDataDir();
env.cleanTestConfig();
fs.writeFileSync(env.configFilePath, JSON.stringify(config));
await asyncSleep(1000);
this.app = await env.getApp();
this.serverMap = await env.getServerMap(this.app);
});
afterEach(async () => {
if (this.app) {
await this.app.close();
}
});
it('should reload page when pressing Ctrl+R', async () => {
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
const webContentsId = this.serverMap[`${config.teams[0].name}___TAB_MESSAGING`].webContentsId;
const loadingScreen = this.app.windows().find((window) => window.url().includes('loadingScreen'));
await loadingScreen.waitForSelector('.LoadingScreen', {state: 'hidden'});
const check = browserWindow.evaluate(async (window, id) => {
const promise = new Promise((resolve) => {
const browserView = window.getBrowserViews().find((view) => view.webContents.id === id);
browserView.webContents.on('did-finish-load', () => {
resolve();
});
});
await promise;
return true;
}, webContentsId);
await asyncSleep(500);
robot.keyTap('r', ['control']);
const result = await check;
result.should.be.true;
});
it('should reload page when pressing Ctrl+Shift+R', async () => {
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
const webContentsId = this.serverMap[`${config.teams[0].name}___TAB_MESSAGING`].webContentsId;
const loadingScreen = this.app.windows().find((window) => window.url().includes('loadingScreen'));
await loadingScreen.waitForSelector('.LoadingScreen', {state: 'hidden'});
const check = browserWindow.evaluate(async (window, id) => {
const promise = new Promise((resolve) => {
const browserView = window.getBrowserViews().find((view) => view.webContents.id === id);
browserView.webContents.on('did-finish-load', () => {
resolve();
});
});
await promise;
return true;
}, webContentsId);
await asyncSleep(500);
robot.keyTap('r', ['control', 'shift']);
const result = await check;
result.should.be.true;
});
});

View file

@ -1,126 +0,0 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
// const fs = require('fs');
// const path = require('path');
// const http = require('http');
// const env = require('../modules/environment');
// describe.skip('security', function desc() {
// this.timeout(30000);
// const serverPort = 8181;
// const testURL = `http://localhost:${serverPort}`;
// const config = {
// version: 2,
// teams: [{
// name: 'example_1',
// url: testURL,
// order: 0,
// }, {
// name: 'example_2',
// url: testURL,
// order: 1,
// }],
// };
// before(() => {
// this.server = http.createServer((req, res) => {
// res.writeHead(200, {
// 'Content-Type': 'text/html',
// });
// res.end(fs.readFileSync(path.resolve(env.sourceRootDir, 'test/modules/test.html'), 'utf-8'));
// }).listen(serverPort, '127.0.0.1');
// });
// beforeEach(() => {
// fs.writeFileSync(env.configFilePath, JSON.stringify(config));
// this.app = env.getSpectronApp();
// return this.app.start();
// });
// afterEach(() => {
// if (this.app && this.app.isRunning()) {
// return this.app.stop();
// }
// return true;
// });
// after((done) => {
// this.server.close(done);
// });
// it('should NOT be able to call Node.js API in webview', () => {
// env.addClientCommands(this.app.client);
// // webview is handled as a window by chromedriver.
// return this.app.client.
// windowByIndex(1).isNodeEnabled().then((enabled) => {
// enabled.should.be.false;
// }).
// windowByIndex(2).isNodeEnabled().then((enabled) => {
// enabled.should.be.false;
// }).
// windowByIndex(0).
// getAttribute('webview', 'nodeintegration').then((nodeintegration) => {
// // nodeintegration is an array of string
// nodeintegration.forEach((n) => {
// n.should.equal('false');
// });
// });
// });
// it('should NOT be able to call Node.js API in a new window', () => {
// env.addClientCommands(this.app.client);
// const client = this.app.client;
// return this.app.client.
// windowByIndex(1). // in the first webview
// execute(() => {
// open_window();
// }).
// waitUntil(() => {
// return client.windowHandles().then((handles) => {
// return handles.value.length === 4;
// });
// }, 5000, 'expected a new window').
// windowByIndex(3).isNodeEnabled().then((enabled) => {
// enabled.should.be.false;
// });
// });
// it('should NOT be able to call eval() in any window', () => {
// env.addClientCommands(this.app.client);
// const tryEval = (index) => {
// return this.app.client.
// windowByIndex(index).
// execute(() => {
// return eval('1 + 1');
// }).then((result) => {
// throw new Error(`Promise was unexpectedly fulfilled (result: ${result})`);
// }, (error) => {
// (error !== null).should.be.true;
// });
// };
// const tryEvalInSettingsPage = () => {
// return this.app.client.
// windowByIndex(0).
// loadSettingsPage().
// execute(() => {
// return eval('1 + 1');
// }).then((result) => {
// throw new Error(`Promise was unexpectedly fulfilled (result: ${result})`);
// }, (error) => {
// (error !== null).should.be.true;
// });
// };
// return Promise.all([
// tryEval(0),
// tryEvalInSettingsPage(),
// ]);
// });
// });

View file

@ -1,152 +0,0 @@
// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
//import path from 'path';
// TODO: reenable with the new spellchecker
// describe('main/Spellchecker.js', function() {
// describe('getSpellCheckerLocale()', () => {
// it('should return recognized locale', () => {
// // SpellChecker.getSpellCheckerLocale('en').should.equal('en-US');
// // SpellChecker.getSpellCheckerLocale('en-US').should.equal('en-US');
// // SpellChecker.getSpellCheckerLocale('fr').should.equal('fr-FR');
// // SpellChecker.getSpellCheckerLocale('fr-FR').should.equal('fr-FR');
// // SpellChecker.getSpellCheckerLocale('de').should.equal('de-DE');
// // SpellChecker.getSpellCheckerLocale('de-DE').should.equal('de-DE');
// // SpellChecker.getSpellCheckerLocale('es').should.equal('es-ES');
// // SpellChecker.getSpellCheckerLocale('es-ES').should.equal('es-ES');
// // SpellChecker.getSpellCheckerLocale('nl').should.equal('nl-NL');
// // SpellChecker.getSpellCheckerLocale('nl-NL').should.equal('nl-NL');
// // SpellChecker.getSpellCheckerLocale('pl').should.equal('pl-PL');
// // SpellChecker.getSpellCheckerLocale('pl-PL').should.equal('pl-PL');
// // SpellChecker.getSpellCheckerLocale('pt').should.equal('pt-BR');
// // SpellChecker.getSpellCheckerLocale('pt-BR').should.equal('pt-BR');
// // SpellChecker.getSpellCheckerLocale('ja').should.equal('en-US');
// // SpellChecker.getSpellCheckerLocale('ja-JP').should.equal('en-US');
// // SpellChecker.getSpellCheckerLocale('it').should.equal('it-IT');
// // SpellChecker.getSpellCheckerLocale('it-IT').should.equal('it-IT');
// });
// });
// describe('en-US', function() {
// const spellchecker = null;
// // before(function(done) {
// // // spellchecker = new SpellChecker(
// // // 'en-US',
// // // path.resolve(__dirname, '../../src/node_modules/simple-spellchecker/dict'),
// // // done
// // // );
// // });
// it('should spellcheck', function() {
// // https://github.com/jfmdev/simple-spellchecker/issues/3
// spellchecker.spellCheck('spell').should.equal(true);
// spellchecker.spellCheck('spel').should.equal(false);
// spellchecker.spellCheck('December').should.equal(true);
// spellchecker.spellCheck('december').should.equal(true);
// spellchecker.spellCheck('English').should.equal(true);
// spellchecker.spellCheck('Japan').should.equal(true);
// });
// it('should allow contractions', function() {
// spellchecker.spellCheck("shouldn't").should.equal(true);
// spellchecker.spellCheck('shouldn').should.equal(true);
// });
// it('should allow numerals', function() {
// spellchecker.spellCheck('1').should.equal(true);
// spellchecker.spellCheck('-100').should.equal(true);
// spellchecker.spellCheck('3.14').should.equal(true);
// });
// it('should allow "Mattermost"', function() {
// spellchecker.spellCheck('Mattermost').should.equal(true);
// spellchecker.spellCheck('mattermost').should.equal(true);
// });
// it('should give at most the requested number of suggestions', function() {
// // helllo known to give at least 4 suggestions
// spellchecker.getSuggestions('helllo', 4).length.should.be.equal(4);
// spellchecker.getSuggestions('helllo', 1).length.should.be.equal(1);
// });
// it('should give suggestions which preserve case of first letter', function() {
// let suggestions = spellchecker.getSuggestions('carr', 4);
// suggestions.length.should.not.be.equal(0);
// let i;
// for (i = 0; i < suggestions.length; i++) {
// suggestions[i].charAt(0).should.be.equal('c');
// }
// suggestions = spellchecker.getSuggestions('Carr', 4);
// suggestions.length.should.not.be.equal(0);
// for (i = 0; i < suggestions.length; i++) {
// suggestions[i].charAt(0).should.be.equal('C');
// }
// });
// });
// describe('en-GB', function() {
// const spellchecker = null;
// // before(function(done) {
// // spellchecker = new SpellChecker(
// // 'en-GB',
// // path.resolve(__dirname, '../../src/node_modules/simple-spellchecker/dict'),
// // done
// // );
// // });
// it('should allow contractions', function() {
// spellchecker.spellCheck("shouldn't").should.equal(true);
// spellchecker.spellCheck('shouldn').should.equal(true);
// });
// });
// describe('de-DE', function() {
// const spellchecker = null;
// // before(function(done) {
// // spellchecker = new SpellChecker(
// // 'de-DE',
// // path.resolve(__dirname, '../../src/node_modules/simple-spellchecker/dict'),
// // done
// // );
// // });
// it('should spellcheck', function() {
// spellchecker.spellCheck('Guten').should.equal(true);
// spellchecker.spellCheck('tag').should.equal(true);
// });
// it('should allow numerals', function() {
// spellchecker.spellCheck('1').should.equal(true);
// spellchecker.spellCheck('-100').should.equal(true);
// spellchecker.spellCheck('3.14').should.equal(true);
// });
// it('should give suggestions which preserve case of first letter', function() {
// let suggestions = spellchecker.getSuggestions('gutenn', 4);
// suggestions.length.should.not.be.equal(0);
// let i;
// for (i = 0; i < suggestions.length; i++) {
// suggestions[i].charAt(0).should.be.equal('g');
// }
// suggestions = spellchecker.getSuggestions('Gutenn', 4);
// suggestions.length.should.not.be.equal(0);
// for (i = 0; i < suggestions.length; i++) {
// suggestions[i].charAt(0).should.be.equal('G');
// }
// });
// });
// });

67
test/specs/window_test.js Normal file
View file

@ -0,0 +1,67 @@
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
'use strict';
const fs = require('fs');
const env = require('../modules/environment');
describe('window', function desc() {
this.timeout(30000);
beforeEach(async () => {
env.createTestUserDataDir();
env.cleanTestConfig();
});
afterEach(async () => {
if (this.app) {
try {
await this.app.close();
// eslint-disable-next-line no-empty
} catch (err) {}
}
});
it.skip('should restore window bounds', async () => {
// TODO: Still fails in CircleCI
// bounds seems to be incorrectly calculated in some environments
// - Windows 10: OK
// - CircleCI: NG
const expectedBounds = {x: 100, y: 200, width: 800, height: 400};
fs.writeFileSync(env.boundsInfoPath, JSON.stringify(expectedBounds));
this.app = await env.getApp();
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
const bounds = await browserWindow.evaluate((window) => window.getContentBounds());
bounds.should.deep.equal(expectedBounds);
await this.app.close();
});
it('should NOT restore window bounds if x is located on outside of viewarea', async () => {
// bounds seems to be incorrectly calculated in some environments (e.g. CircleCI)
// - Windows 10: OK
// - CircleCI: NG
fs.writeFileSync(env.boundsInfoPath, JSON.stringify({x: -100000, y: 200, width: 800, height: 400}));
this.app = await env.getApp();
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
const bounds = await browserWindow.evaluate((window) => window.getContentBounds());
bounds.x.should.satisfy((x) => (x > -100000));
await this.app.close();
});
it('should NOT restore window bounds if y is located on outside of viewarea', async () => {
// bounds seems to be incorrectly calculated in some environments (e.g. CircleCI)
// - Windows 10: OK
// - CircleCI: NG
fs.writeFileSync(env.boundsInfoPath, JSON.stringify({x: 100, y: 200000, width: 800, height: 400}));
this.app = await env.getApp();
const mainWindow = await this.app.firstWindow();
const browserWindow = await this.app.browserWindow(mainWindow);
const bounds = await browserWindow.evaluate((window) => window.getContentBounds());
bounds.y.should.satisfy((y) => (y < 200000));
await this.app.close();
});
});

View file

@ -38,7 +38,8 @@ module.exports = merge(base, {
net: 'require("net")',
repl: 'require("repl")',
tls: 'require("tls")',
spectron: 'require("spectron")',
playwright: 'require("playwright")',
robotjs: 'require("robotjs")',
},
node: {
__filename: false,