mirror of
https://github.com/finos/SymphonyElectron.git
synced 2025-02-25 18:55:29 -06:00
Merge branch 'master' into rc-1.53.0
* master: SEARCH-905 - Electron "child_process" promisify issue (#462) AVT-1081 [Spectron][Windows] pop-out chat, inbox (#460) [AVT-1095] - [Spectron][MAC] Show 1 in tray icon when unread message = 1 (#458) Support on MAC (#456) bump up version number to 2.11.0 ELECTRON-600 (Implement Native Encryption for AESGCMEncrypt, AESGCMDecrypt & RSADecrypt) (#452) ELECTRON-670 - Remove setting menu to null for pop-out (#457) AVT-1031 AND AVT-1032: Verify toast notification for IMs, Signal,Room (#448) AVT-1025: Verify toast notification when Persist Notification is ON (#447) ELECTRON-607 (Optimization and bug fix) (#455) AVT-1024 Add test "Pop-up alert play depends on setting" (#454) ELECTRON-652: add new app icons for windows and macOS (#453) ELECTRON-607 (Change native menu bar style - Windows 10) (#451) ELECTRON-661 (Security fix for pop-outs RCE) (#450) AVT-1029 Add test "Verify the production logs exists when clicking on "Show logs in Explorer"" (#445) Add test (#443) ELECTRON-591 - Add logic to close up child windows whenever parent window is navigated or reloaded (#446) AVT-937,AVT-938,AVT-939 : [Spectron][Windows] Close window when 'Minimize on Close' is ON (#437) AVT-914 [Spectron][Windows] Add test "Keep size and position of the windows in previous session" (#430) Removes launchd plist files as there no longer needed (#442)
This commit is contained in:
commit
6dcc8089c7
BIN
build/icon.icns
BIN
build/icon.icns
Binary file not shown.
BIN
build/icon.ico
BIN
build/icon.ico
Binary file not shown.
Before Width: | Height: | Size: 361 KiB After Width: | Height: | Size: 361 KiB |
247
js/cryptoLib.js
Normal file
247
js/cryptoLib.js
Normal file
@ -0,0 +1,247 @@
|
|||||||
|
const electron = require('electron');
|
||||||
|
const app = electron.app;
|
||||||
|
const ffi = require('ffi');
|
||||||
|
const ref = require('ref');
|
||||||
|
const path = require('path');
|
||||||
|
const execPath = path.dirname(app.getPath('exe'));
|
||||||
|
|
||||||
|
const log = require('./log.js');
|
||||||
|
const logLevels = require('./enums/logLevels.js');
|
||||||
|
const { isMac, isDevEnv } = require('../js/utils/misc');
|
||||||
|
|
||||||
|
const TAG_LENGTH = 16;
|
||||||
|
const KEY_LENGTH = 32;
|
||||||
|
const arch = process.arch === 'ia32';
|
||||||
|
const winLibraryPath = isDevEnv ? path.join(__dirname, '..', 'library') : path.join(execPath, 'library');
|
||||||
|
const macLibraryPath = isDevEnv ? path.join(__dirname, '..', 'library') : path.join(execPath, '..', 'library');
|
||||||
|
|
||||||
|
const cryptoLibPath = isMac ?
|
||||||
|
path.join(macLibraryPath, 'cryptoLib.dylib') :
|
||||||
|
(arch ? path.join(winLibraryPath, 'libsymphonysearch-x86.dll') : path.join(winLibraryPath, 'libsymphonysearch-x64.dll'));
|
||||||
|
|
||||||
|
const voidPtr = ref.refType(ref.types.void);
|
||||||
|
const RSAKeyPair = exports.RSAKeyPair = voidPtr;
|
||||||
|
const RSAKeyPairPtr = exports.RSAKeyPairPtr = ref.refType(RSAKeyPair);
|
||||||
|
const RSAPubKey = exports.RSAPubKey = voidPtr;
|
||||||
|
const RSAPubKeyPtr = exports.RSAPubKeyPtr = ref.refType(RSAPubKey);
|
||||||
|
|
||||||
|
const library = new ffi.Library((cryptoLibPath), {
|
||||||
|
|
||||||
|
AESEncryptGCM: [ref.types.int32, [
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.int32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.int32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
]],
|
||||||
|
|
||||||
|
AESDecryptGCM: [ref.types.int32, [
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.int32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.int32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
]],
|
||||||
|
|
||||||
|
encryptRSA: [ref.types.uint32, [
|
||||||
|
RSAPubKeyPtr,
|
||||||
|
ref.types.int32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
]],
|
||||||
|
|
||||||
|
decryptRSA: [ref.types.uint32, [
|
||||||
|
RSAPubKeyPtr,
|
||||||
|
ref.types.int32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
]],
|
||||||
|
|
||||||
|
deserializeRSAPubKey: [RSAPubKey, [
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
]],
|
||||||
|
deserializeRSAKeyPair: [RSAKeyPairPtr, [
|
||||||
|
ref.refType(ref.types.uchar),
|
||||||
|
ref.types.uint32,
|
||||||
|
]],
|
||||||
|
|
||||||
|
getRSAKeySize: [ref.types.uint32, [
|
||||||
|
RSAKeyPairPtr
|
||||||
|
]],
|
||||||
|
|
||||||
|
getVersion: [ref.types.CString, []],
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to decrypt content
|
||||||
|
* @param Base64IV
|
||||||
|
* @param Base64AAD
|
||||||
|
* @param Base64Key
|
||||||
|
* @param Base64In
|
||||||
|
* @return {*}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const AESGCMEncrypt = function(Base64IV, Base64AAD, Base64Key, Base64In) {
|
||||||
|
return EncryptDecrypt('AESGCMEncrypt', Base64IV, Base64AAD, Base64Key, Base64In);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method to decrypt content
|
||||||
|
* @param Base64IV
|
||||||
|
* @param Base64AAD
|
||||||
|
* @param Base64Key
|
||||||
|
* @param Base64In
|
||||||
|
* @return {*}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const AESGCMDecrypt = function(Base64IV, Base64AAD, Base64Key, Base64In) {
|
||||||
|
return EncryptDecrypt('AESGCMDecrypt', Base64IV, Base64AAD, Base64Key, Base64In);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt / Decrypt
|
||||||
|
* @param name {String} - Method name
|
||||||
|
* @param Base64IV {String} base64
|
||||||
|
* @param Base64AAD {String} base64
|
||||||
|
* @param Base64Key {String} base64
|
||||||
|
* @param Base64In {String} base64
|
||||||
|
* @return {*}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const EncryptDecrypt = function(name, Base64IV, Base64AAD, Base64Key, Base64In) {
|
||||||
|
let base64In = Base64In;
|
||||||
|
|
||||||
|
if (!base64In) {
|
||||||
|
base64In = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const IV = Buffer.from(Base64IV, 'base64');
|
||||||
|
const AAD = Buffer.from(Base64AAD, 'base64');
|
||||||
|
const Key = Buffer.from(Base64Key, 'base64');
|
||||||
|
const In = Buffer.from(base64In, 'base64');
|
||||||
|
|
||||||
|
if (name === 'AESGCMEncrypt') {
|
||||||
|
const OutPtr = Buffer.alloc(In.length);
|
||||||
|
const Tag = Buffer.alloc(TAG_LENGTH);
|
||||||
|
|
||||||
|
const resultCode = library.AESEncryptGCM(In, In.length, AAD, AAD.length, Key, IV, IV.length, OutPtr, Tag, TAG_LENGTH);
|
||||||
|
|
||||||
|
if (resultCode < 0) {
|
||||||
|
log.send(logLevels.ERROR, `AESEncryptGCM, Failed to encrypt with exit code ${resultCode}`);
|
||||||
|
}
|
||||||
|
log.send(logLevels.INFO, `Output from AESEncryptGCM ${resultCode}`);
|
||||||
|
const bufferArray = [OutPtr, Tag];
|
||||||
|
return Buffer.concat(bufferArray).toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (name === 'AESGCMDecrypt') {
|
||||||
|
const CipherTextLen = In.length - TAG_LENGTH;
|
||||||
|
const Tag = Buffer.from(In.slice(In.length - 16, In.length));
|
||||||
|
const OutPtr = Buffer.alloc(In.length - TAG_LENGTH);
|
||||||
|
|
||||||
|
const resultCode = library.AESDecryptGCM(In, CipherTextLen, AAD, AAD.length, Tag, TAG_LENGTH, Key, IV, IV.length, OutPtr);
|
||||||
|
|
||||||
|
if (resultCode < 0) {
|
||||||
|
log.send(logLevels.ERROR, `AESDecryptGCM, Failed to decrypt with exit code ${resultCode}`);
|
||||||
|
}
|
||||||
|
log.send(logLevels.INFO, `Output from AESDecryptGCM ${resultCode}`);
|
||||||
|
return OutPtr.toString('base64');
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt RSA
|
||||||
|
* @param pemKey
|
||||||
|
* @param input
|
||||||
|
* @return {*}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const RSADecrypt = function (pemKey, input) {
|
||||||
|
return RSAEncryptDecrypt("RSADecrypt", pemKey, input);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt / Decrypt RSA
|
||||||
|
* @param action
|
||||||
|
* @param pemKey
|
||||||
|
* @param inputStr
|
||||||
|
* @return {String}
|
||||||
|
* @constructor
|
||||||
|
*/
|
||||||
|
const RSAEncryptDecrypt = function (action, pemKey, inputStr) {
|
||||||
|
|
||||||
|
let rsaKey = getRSAKeyFromPEM(pemKey);
|
||||||
|
|
||||||
|
if (!rsaKey) {
|
||||||
|
log.send(logLevels.ERROR, `Failed to parse formatted RSA PEM key`);
|
||||||
|
}
|
||||||
|
|
||||||
|
let input = Buffer.from(inputStr, 'base64');
|
||||||
|
let outLen = library.getRSAKeySize(rsaKey);
|
||||||
|
|
||||||
|
let outPtr = Buffer.alloc(KEY_LENGTH);
|
||||||
|
|
||||||
|
let ret = 0;
|
||||||
|
|
||||||
|
if (action === 'RSAEncrypt') {
|
||||||
|
ret = library.encryptRSA(rsaKey, 0, input, input.length, outPtr, outLen);
|
||||||
|
} else {
|
||||||
|
outLen = library.decryptRSA(rsaKey, 0, input, input.length, outPtr, outLen);
|
||||||
|
|
||||||
|
if (outLen < 0) {
|
||||||
|
ret = outLen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret !== 0) {
|
||||||
|
log.send(logLevels.ERROR, `${action} failed due to -> ${ret}`);
|
||||||
|
}
|
||||||
|
return Buffer.from(outPtr.toString('hex'), 'hex').toString('base64');
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get RSA key from PEM key
|
||||||
|
* @param pemKey
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
const getRSAKeyFromPEM = function (pemKey) {
|
||||||
|
|
||||||
|
let pemKeyBytes = Buffer.from(pemKey, 'utf-8');
|
||||||
|
|
||||||
|
let rsaKey;
|
||||||
|
|
||||||
|
if (pemKey.startsWith("-----BEGIN PUBLIC KEY-----")) {
|
||||||
|
rsaKey = library.deserializeRSAPubKey(pemKeyBytes, pemKey.length);
|
||||||
|
} else {
|
||||||
|
rsaKey = library.deserializeRSAKeyPair(pemKeyBytes, pemKey.length);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rsaKey === 0) {
|
||||||
|
log.send(logLevels.ERROR, 'RSAKey is 0!!');
|
||||||
|
}
|
||||||
|
return rsaKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
AESGCMEncrypt: AESGCMEncrypt,
|
||||||
|
AESGCMDecrypt: AESGCMDecrypt,
|
||||||
|
RSADecrypt: RSADecrypt,
|
||||||
|
};
|
@ -8,5 +8,5 @@ let keyMirror = require('keymirror');
|
|||||||
*/
|
*/
|
||||||
module.exports = keyMirror({
|
module.exports = keyMirror({
|
||||||
CUSTOM: null,
|
CUSTOM: null,
|
||||||
NATIVE_WITH_CUSTOM: null,
|
NATIVE: null,
|
||||||
});
|
});
|
||||||
|
@ -67,6 +67,8 @@ function sanitize(windowName) {
|
|||||||
if (!isMac) {
|
if (!isMac) {
|
||||||
eventEmitter.emit('killScreenSnippet');
|
eventEmitter.emit('killScreenSnippet');
|
||||||
}
|
}
|
||||||
|
// Closes all the child windows
|
||||||
|
windowMgr.cleanUpChildWindows();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,7 +163,8 @@ electron.ipcMain.on(apiName, (event, arg) => {
|
|||||||
break;
|
break;
|
||||||
case apiCmds.setLocale:
|
case apiCmds.setLocale:
|
||||||
if (typeof arg.locale === 'string') {
|
if (typeof arg.locale === 'string') {
|
||||||
eventEmitter.emit('language-changed', { language: arg.locale });
|
let browserWin = electron.BrowserWindow.fromWebContents(event.sender);
|
||||||
|
windowMgr.setLocale(browserWin, { language: arg.locale });
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case apiCmds.keyPress:
|
case apiCmds.keyPress:
|
||||||
|
@ -399,23 +399,39 @@ function getTemplate(app) {
|
|||||||
label: i18n.getMessageFor('Title Bar Style'),
|
label: i18n.getMessageFor('Title Bar Style'),
|
||||||
submenu: [
|
submenu: [
|
||||||
{
|
{
|
||||||
label: i18n.getMessageFor('Native With Custom'),
|
label: i18n.getMessageFor('Native'),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: titleBarStyle === titleBarStyles.NATIVE_WITH_CUSTOM,
|
checked: titleBarStyle === titleBarStyles.NATIVE,
|
||||||
|
enabled: titleBarStyle !== titleBarStyles.NATIVE,
|
||||||
click: function (item) {
|
click: function (item) {
|
||||||
item.menu.items[1].checked = false;
|
const isNativeStyle = titleBarStyle === titleBarStyles.NATIVE;
|
||||||
titleBarStyle = titleBarStyles.NATIVE_WITH_CUSTOM;
|
item.menu.items[1].checked = isNativeStyle;
|
||||||
|
|
||||||
|
// Disable menu item accordingly
|
||||||
|
item.menu.items[0].enabled = isNativeStyle;
|
||||||
|
item.menu.items[1].enabled = !isNativeStyle;
|
||||||
|
|
||||||
|
titleBarStyle = titleBarStyles.NATIVE;
|
||||||
updateConfigField('isCustomTitleBar', false);
|
updateConfigField('isCustomTitleBar', false);
|
||||||
|
titleBarActions(app);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: i18n.getMessageFor('Custom'),
|
label: i18n.getMessageFor('Custom'),
|
||||||
type: 'checkbox',
|
type: 'checkbox',
|
||||||
checked: titleBarStyle === titleBarStyles.CUSTOM,
|
checked: titleBarStyle === titleBarStyles.CUSTOM,
|
||||||
|
enabled: titleBarStyle !== titleBarStyles.CUSTOM,
|
||||||
click: function (item) {
|
click: function (item) {
|
||||||
item.menu.items[0].checked = false;
|
const isCustomStyle = titleBarStyle === titleBarStyles.CUSTOM;
|
||||||
|
item.menu.items[0].checked = isCustomStyle;
|
||||||
|
|
||||||
|
// Disable menu item accordingly
|
||||||
|
item.menu.items[1].enabled = isCustomStyle;
|
||||||
|
item.menu.items[0].enabled = !isCustomStyle;
|
||||||
|
|
||||||
titleBarStyle = titleBarStyles.CUSTOM;
|
titleBarStyle = titleBarStyles.CUSTOM;
|
||||||
updateConfigField('isCustomTitleBar', true);
|
updateConfigField('isCustomTitleBar', true);
|
||||||
|
titleBarActions(app);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -479,7 +495,7 @@ function setCheckboxValues() {
|
|||||||
bringToFront = configData[key];
|
bringToFront = configData[key];
|
||||||
break;
|
break;
|
||||||
case 'isCustomTitleBar':
|
case 'isCustomTitleBar':
|
||||||
titleBarStyle = configData[key] ? titleBarStyles.CUSTOM : titleBarStyles.NATIVE_WITH_CUSTOM;
|
titleBarStyle = configData[key] ? titleBarStyles.CUSTOM : titleBarStyles.NATIVE;
|
||||||
break;
|
break;
|
||||||
case 'memoryRefresh':
|
case 'memoryRefresh':
|
||||||
memoryRefresh = configData[key];
|
memoryRefresh = configData[key];
|
||||||
@ -537,6 +553,28 @@ function getTitleBarStyle() {
|
|||||||
return titleBarStyle;
|
return titleBarStyle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays an option to the user whether
|
||||||
|
* to relaunch application
|
||||||
|
*
|
||||||
|
* @param app
|
||||||
|
*/
|
||||||
|
function titleBarActions(app) {
|
||||||
|
const options = {
|
||||||
|
type: 'question',
|
||||||
|
title: i18n.getMessageFor('Relaunch Application'),
|
||||||
|
message: i18n.getMessageFor('Updating Title bar style requires Symphony to relaunch'),
|
||||||
|
buttons: ['Relaunch', 'Cancel']
|
||||||
|
};
|
||||||
|
|
||||||
|
electron.dialog.showMessageBox(options, function (index) {
|
||||||
|
if (index === 0) {
|
||||||
|
app.relaunch();
|
||||||
|
app.exit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getTemplate: getTemplate,
|
getTemplate: getTemplate,
|
||||||
getMinimizeOnClose: getMinimizeOnClose,
|
getMinimizeOnClose: getMinimizeOnClose,
|
||||||
|
@ -487,7 +487,7 @@ function buildCloseNotification(notificationWindow, notificationObj, getTimeoutI
|
|||||||
|
|
||||||
// safety check to prevent from using an
|
// safety check to prevent from using an
|
||||||
// already destroyed notification window
|
// already destroyed notification window
|
||||||
if (notificationWindow.isDestroyed()) {
|
if (notificationWindow && notificationWindow.isDestroyed()) {
|
||||||
return new Promise(function(exitEarly) { exitEarly() })
|
return new Promise(function(exitEarly) { exitEarly() })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -699,6 +699,7 @@ function getWindow() {
|
|||||||
windowProperties.width = config.width;
|
windowProperties.width = config.width;
|
||||||
windowProperties.height = config.height;
|
windowProperties.height = config.height;
|
||||||
notificationWindow = new BrowserWindow(windowProperties);
|
notificationWindow = new BrowserWindow(windowProperties);
|
||||||
|
notificationWindow.winName = 'notification-window';
|
||||||
notificationWindow.setVisibleOnAllWorkspaces(true);
|
notificationWindow.setVisibleOnAllWorkspaces(true);
|
||||||
notificationWindow.loadURL(getTemplatePath());
|
notificationWindow.loadURL(getTemplatePath());
|
||||||
notificationWindow.webContents.on('did-finish-load', function() {
|
notificationWindow.webContents.on('did-finish-load', function() {
|
||||||
@ -737,13 +738,39 @@ function cleanUpActiveNotification(event) {
|
|||||||
*/
|
*/
|
||||||
function cleanUpInactiveWindow() {
|
function cleanUpInactiveWindow() {
|
||||||
inactiveWindows.forEach(function(window) {
|
inactiveWindows.forEach(function(window) {
|
||||||
if (!window.isDestroyed()) {
|
if (window && !window.isDestroyed()) {
|
||||||
window.close();
|
window.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
inactiveWindows = [];
|
inactiveWindows = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Closes all the notification windows
|
||||||
|
* and cleans up the reference variables
|
||||||
|
*/
|
||||||
|
function closeAll() {
|
||||||
|
resetAnimationQueue();
|
||||||
|
const notificationWin = Object.assign([], activeNotifications);
|
||||||
|
for (let activeNotification of notificationWin) {
|
||||||
|
if (activeNotification && !activeNotification.isDestroyed()) {
|
||||||
|
activeNotification.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nextInsertPos = {};
|
||||||
|
activeNotifications = [];
|
||||||
|
notificationQueue = [];
|
||||||
|
cleanUpInactiveWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the animation queue instance
|
||||||
|
*/
|
||||||
|
function resetAnimationQueue() {
|
||||||
|
animationQueue = new AnimationQueue();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new timer to close the notification
|
* Start a new timer to close the notification
|
||||||
* @param event
|
* @param event
|
||||||
@ -784,3 +811,5 @@ ipc.on('electron-notify-mouseover', onMouseOver);
|
|||||||
module.exports.notify = notify;
|
module.exports.notify = notify;
|
||||||
module.exports.updateConfig = updateConfig;
|
module.exports.updateConfig = updateConfig;
|
||||||
module.exports.reset = setupConfig;
|
module.exports.reset = setupConfig;
|
||||||
|
module.exports.closeAll = closeAll;
|
||||||
|
module.exports.resetAnimationQueue = resetAnimationQueue;
|
||||||
|
@ -26,10 +26,14 @@ const memoryMonitorInterval = 1000 * 60 * 60;
|
|||||||
const SnackBar = require('../snackBar').SnackBar;
|
const SnackBar = require('../snackBar').SnackBar;
|
||||||
const KeyCodes = {
|
const KeyCodes = {
|
||||||
Esc: 27,
|
Esc: 27,
|
||||||
|
Alt: 18,
|
||||||
};
|
};
|
||||||
|
|
||||||
let Search;
|
let Search;
|
||||||
let SearchUtils;
|
let SearchUtils;
|
||||||
|
let CryptoLib;
|
||||||
|
let isAltKey = false;
|
||||||
|
let isMenuOpen = false;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Search = remote.require('swift-search').Search;
|
Search = remote.require('swift-search').Search;
|
||||||
@ -45,6 +49,14 @@ try {
|
|||||||
console.warn("Failed to initialize swift search (Utils). You'll need to include the search dependency. Contact the developers for more details");
|
console.warn("Failed to initialize swift search (Utils). You'll need to include the search dependency. Contact the developers for more details");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
CryptoLib = remote.require('./cryptoLib.js');
|
||||||
|
} catch (e) {
|
||||||
|
CryptoLib = null;
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn("Failed to initialize Crypto Lib. You'll need to include the Crypto library. Contact the developers for more details");
|
||||||
|
}
|
||||||
|
|
||||||
require('../downloadManager');
|
require('../downloadManager');
|
||||||
let snackBar;
|
let snackBar;
|
||||||
|
|
||||||
@ -199,6 +211,11 @@ function createAPI() {
|
|||||||
*/
|
*/
|
||||||
SearchUtils: SearchUtils || null,
|
SearchUtils: SearchUtils || null,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Native encryption and decryption.
|
||||||
|
*/
|
||||||
|
CryptoLib: CryptoLib,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Brings window forward and gives focus.
|
* Brings window forward and gives focus.
|
||||||
* @param {String} windowName Name of window. Note: main window name is 'main'
|
* @param {String} windowName Name of window. Note: main window name is 'main'
|
||||||
@ -470,7 +487,6 @@ function createAPI() {
|
|||||||
* the window enters full screen
|
* the window enters full screen
|
||||||
*/
|
*/
|
||||||
local.ipcRenderer.on('window-enter-full-screen', (event, arg) => {
|
local.ipcRenderer.on('window-enter-full-screen', (event, arg) => {
|
||||||
window.addEventListener('keydown', throttledKeyDown, true);
|
|
||||||
if (snackBar && typeof arg === 'object' && arg.snackBar) {
|
if (snackBar && typeof arg === 'object' && arg.snackBar) {
|
||||||
setTimeout(() => snackBar.showSnackBar(arg.snackBar), 500);
|
setTimeout(() => snackBar.showSnackBar(arg.snackBar), 500);
|
||||||
}
|
}
|
||||||
@ -481,7 +497,6 @@ function createAPI() {
|
|||||||
* the window leave full screen
|
* the window leave full screen
|
||||||
*/
|
*/
|
||||||
local.ipcRenderer.on('window-leave-full-screen', () => {
|
local.ipcRenderer.on('window-leave-full-screen', () => {
|
||||||
window.removeEventListener('keydown', throttledKeyDown, true);
|
|
||||||
if (snackBar) {
|
if (snackBar) {
|
||||||
snackBar.removeSnackBar();
|
snackBar.removeSnackBar();
|
||||||
}
|
}
|
||||||
@ -498,22 +513,46 @@ function createAPI() {
|
|||||||
function sanitize() {
|
function sanitize() {
|
||||||
local.ipcRenderer.send(apiName, {
|
local.ipcRenderer.send(apiName, {
|
||||||
cmd: apiCmds.sanitize,
|
cmd: apiCmds.sanitize,
|
||||||
windowName: window.name
|
windowName: window.name || 'main'
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const throttledKeyDown = throttle(1000, (event) => {
|
// Handle key down events
|
||||||
|
const throttledKeyDown = throttle(500, (event) => {
|
||||||
|
isAltKey = event.keyCode === KeyCodes.Alt;
|
||||||
if (event.keyCode === KeyCodes.Esc) {
|
if (event.keyCode === KeyCodes.Esc) {
|
||||||
local.ipcRenderer.send(apiName, {
|
local.ipcRenderer.send(apiName, {
|
||||||
cmd: apiCmds.keyPress,
|
cmd: apiCmds.keyPress,
|
||||||
keyCode: KeyCodes.Esc
|
keyCode: event.keyCode
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Handle key up events
|
||||||
|
const throttledKeyUp = throttle(500, (event) => {
|
||||||
|
if (isAltKey && (event.keyCode === KeyCodes.Alt || KeyCodes.Esc)) {
|
||||||
|
isMenuOpen = !isMenuOpen;
|
||||||
|
}
|
||||||
|
if (isAltKey && isMenuOpen && event.keyCode === KeyCodes.Alt) {
|
||||||
|
local.ipcRenderer.send(apiName, {
|
||||||
|
cmd: apiCmds.keyPress,
|
||||||
|
keyCode: event.keyCode
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const throttleMouseDown = throttle(500, () => {
|
||||||
|
if (isAltKey && isMenuOpen) {
|
||||||
|
isMenuOpen = !isMenuOpen;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener('offline', updateOnlineStatus, false);
|
window.addEventListener('offline', updateOnlineStatus, false);
|
||||||
window.addEventListener('online', updateOnlineStatus, false);
|
window.addEventListener('online', updateOnlineStatus, false);
|
||||||
window.addEventListener('beforeunload', sanitize, false);
|
window.addEventListener('beforeunload', sanitize, false);
|
||||||
|
window.addEventListener('keyup', throttledKeyUp, true);
|
||||||
|
window.addEventListener('keydown', throttledKeyDown, true);
|
||||||
|
window.addEventListener('mousedown', throttleMouseDown, { capture: true });
|
||||||
|
|
||||||
updateOnlineStatus();
|
updateOnlineStatus();
|
||||||
}
|
}
|
||||||
|
123
js/windowMgr.js
123
js/windowMgr.js
@ -44,9 +44,11 @@ let display;
|
|||||||
let sandboxed = false;
|
let sandboxed = false;
|
||||||
let isAutoReload = false;
|
let isAutoReload = false;
|
||||||
let devToolsEnabled = true;
|
let devToolsEnabled = true;
|
||||||
|
let isCustomTitleBarEnabled = true;
|
||||||
|
|
||||||
const KeyCodes = {
|
const KeyCodes = {
|
||||||
Esc: 27,
|
Esc: 27,
|
||||||
|
Alt: 18,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Application menu
|
// Application menu
|
||||||
@ -132,7 +134,7 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
const config = readConfigFileSync();
|
const config = readConfigFileSync();
|
||||||
|
|
||||||
// condition whether to enable custom Windows 10 title bar
|
// condition whether to enable custom Windows 10 title bar
|
||||||
const isCustomTitleBarEnabled = typeof isCustomTitleBar === 'boolean'
|
isCustomTitleBarEnabled = typeof isCustomTitleBar === 'boolean'
|
||||||
&& isCustomTitleBar
|
&& isCustomTitleBar
|
||||||
&& isWindows10();
|
&& isWindows10();
|
||||||
log.send(logLevels.INFO, `we are configuring a custom title bar for windows -> ${isCustomTitleBarEnabled}`);
|
log.send(logLevels.INFO, `we are configuring a custom title bar for windows -> ${isCustomTitleBarEnabled}`);
|
||||||
@ -215,7 +217,7 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
mainWindow.webContents.send('window-leave-full-screen');
|
mainWindow.webContents.send('window-leave-full-screen');
|
||||||
});
|
});
|
||||||
|
|
||||||
if (initialBounds && !isNodeEnv) {
|
if (initialBounds) {
|
||||||
// maximizes the application if previously maximized
|
// maximizes the application if previously maximized
|
||||||
if (initialBounds.isMaximized) {
|
if (initialBounds.isMaximized) {
|
||||||
mainWindow.maximize();
|
mainWindow.maximize();
|
||||||
@ -240,7 +242,7 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
|
|
||||||
// Event needed to hide native menu bar on Windows 10 as we use custom menu bar
|
// Event needed to hide native menu bar on Windows 10 as we use custom menu bar
|
||||||
mainWindow.webContents.once('did-start-loading', () => {
|
mainWindow.webContents.once('did-start-loading', () => {
|
||||||
if (isWindows10() && mainWindow && !mainWindow.isDestroyed()) {
|
if ((isCustomTitleBarEnabled || isWindows10()) && mainWindow && !mainWindow.isDestroyed()) {
|
||||||
mainWindow.setMenuBarVisibility(false);
|
mainWindow.setMenuBarVisibility(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -256,7 +258,7 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
mainWindow.webContents.send('on-page-load');
|
mainWindow.webContents.send('on-page-load');
|
||||||
// initializes and applies styles required for snack bar
|
// initializes and applies styles required for snack bar
|
||||||
mainWindow.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/snackBar/style.css'), 'utf8').toString());
|
mainWindow.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/snackBar/style.css'), 'utf8').toString());
|
||||||
if (isCustomTitleBarEnabled || isWindows10()) {
|
if (isCustomTitleBarEnabled) {
|
||||||
mainWindow.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/windowsTitleBar/style.css'), 'utf8').toString());
|
mainWindow.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/windowsTitleBar/style.css'), 'utf8').toString());
|
||||||
// This is required to initiate Windows title bar only after insertCSS
|
// This is required to initiate Windows title bar only after insertCSS
|
||||||
const titleBarStyle = getTitleBarStyle();
|
const titleBarStyle = getTitleBarStyle();
|
||||||
@ -320,7 +322,7 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
addWindowKey(key, mainWindow);
|
addWindowKey(key, mainWindow);
|
||||||
mainWindow.loadURL(url);
|
mainWindow.loadURL(url);
|
||||||
|
|
||||||
rebuildMenu(lang);
|
setLocale(mainWindow, { language: lang });
|
||||||
|
|
||||||
mainWindow.on('close', function (e) {
|
mainWindow.on('close', function (e) {
|
||||||
if (willQuitApp) {
|
if (willQuitApp) {
|
||||||
@ -371,13 +373,15 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// open external links in default browser - a tag with href='_blank' or window.open
|
// open external links in default browser - a tag with href='_blank' or window.open
|
||||||
mainWindow.webContents.on('new-window', handleNewWindow);
|
const enforceInheritance = (topWebContents) => {
|
||||||
|
const handleNewWindow = (webContents) => {
|
||||||
if (!isDevEnv) {
|
webContents.on('new-window', (event, newWinUrl, frameName, disposition, newWinOptions) => {
|
||||||
mainWindow.webContents.session.setCertificateVerifyProc(handleCertificateTransparencyChecks);
|
if (!newWinOptions.webPreferences) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
newWinOptions.webPreferences = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleNewWindow(event, newWinUrl, frameName, disposition, newWinOptions) {
|
Object.assign(newWinOptions.webPreferences, topWebContents);
|
||||||
|
|
||||||
let newWinParsedUrl = getParsedUrl(newWinUrl);
|
let newWinParsedUrl = getParsedUrl(newWinUrl);
|
||||||
let mainWinParsedUrl = getParsedUrl(url);
|
let mainWinParsedUrl = getParsedUrl(url);
|
||||||
@ -445,27 +449,22 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
newWinOptions.winKey = newWinKey;
|
newWinOptions.winKey = newWinKey;
|
||||||
/* eslint-enable no-param-reassign */
|
/* eslint-enable no-param-reassign */
|
||||||
|
|
||||||
let webContents = newWinOptions.webContents;
|
let childWebContents = newWinOptions.webContents;
|
||||||
|
|
||||||
// Event needed to hide native menu bar
|
// Event needed to hide native menu bar
|
||||||
webContents.once('did-start-loading', () => {
|
childWebContents.once('did-start-loading', () => {
|
||||||
let browserWin = BrowserWindow.fromWebContents(webContents);
|
let browserWin = BrowserWindow.fromWebContents(childWebContents);
|
||||||
if (isWindowsOS && browserWin && !browserWin.isDestroyed()) {
|
if (isWindowsOS && browserWin && !browserWin.isDestroyed()) {
|
||||||
browserWin.setMenuBarVisibility(false);
|
browserWin.setMenuBarVisibility(false);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
webContents.once('did-finish-load', function () {
|
childWebContents.once('did-finish-load', function () {
|
||||||
let browserWin = BrowserWindow.fromWebContents(webContents);
|
let browserWin = BrowserWindow.fromWebContents(childWebContents);
|
||||||
|
|
||||||
if (browserWin) {
|
if (browserWin) {
|
||||||
log.send(logLevels.INFO, 'loaded pop-out window url: ' + newWinParsedUrl);
|
log.send(logLevels.INFO, 'loaded pop-out window url: ' + newWinParsedUrl);
|
||||||
|
|
||||||
if (!isMac) {
|
|
||||||
// Removes the menu bar from the pop-out window
|
|
||||||
// setMenu is currently only supported on Windows and Linux
|
|
||||||
browserWin.setMenu(null);
|
|
||||||
}
|
|
||||||
browserWin.webContents.send('on-page-load');
|
browserWin.webContents.send('on-page-load');
|
||||||
// applies styles required for snack bar
|
// applies styles required for snack bar
|
||||||
browserWin.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/snackBar/style.css'), 'utf8').toString());
|
browserWin.webContents.insertCSS(fs.readFileSync(path.join(__dirname, '/snackBar/style.css'), 'utf8').toString());
|
||||||
@ -501,7 +500,9 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
// In case we navigate to an external link from inside a pop-out,
|
// In case we navigate to an external link from inside a pop-out,
|
||||||
// we open that link in an external browser rather than creating
|
// we open that link in an external browser rather than creating
|
||||||
// a new window
|
// a new window
|
||||||
browserWin.webContents.on('new-window', handleNewWindow.bind(this));
|
if (browserWin.webContents) {
|
||||||
|
handleNewWindow(browserWin.webContents);
|
||||||
|
}
|
||||||
|
|
||||||
addWindowKey(newWinKey, browserWin);
|
addWindowKey(newWinKey, browserWin);
|
||||||
|
|
||||||
@ -536,7 +537,6 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
browserWin.on('close', () => {
|
browserWin.on('close', () => {
|
||||||
browserWin.webContents.removeListener('new-window', handleNewWindow);
|
|
||||||
browserWin.webContents.removeListener('crashed', handleChildWindowCrashEvent);
|
browserWin.webContents.removeListener('crashed', handleChildWindowCrashEvent);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -559,6 +559,18 @@ function doCreateMainWindow(initialUrl, initialBounds, isCustomTitleBar) {
|
|||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
openUrlInDefaultBrowser(newWinUrl);
|
openUrlInDefaultBrowser(newWinUrl);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
handleNewWindow(topWebContents);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!isDevEnv) {
|
||||||
|
mainWindow.webContents.session.setCertificateVerifyProc(handleCertificateTransparencyChecks);
|
||||||
|
}
|
||||||
|
|
||||||
|
// enforce main window's webPreferences to child windows
|
||||||
|
if (mainWindow.webContents) {
|
||||||
|
enforceInheritance(mainWindow.webContents);
|
||||||
}
|
}
|
||||||
|
|
||||||
// whenever the main window is navigated for ex: window.location.href or url redirect
|
// whenever the main window is navigated for ex: window.location.href or url redirect
|
||||||
@ -955,19 +967,34 @@ eventEmitter.on('notificationSettings', (notificationSettings) => {
|
|||||||
display = notificationSettings.display;
|
display = notificationSettings.display;
|
||||||
});
|
});
|
||||||
|
|
||||||
eventEmitter.on('language-changed', (opts) => {
|
/**
|
||||||
|
* Sets the locale settings
|
||||||
|
*
|
||||||
|
* @param browserWindow {Electron.BrowserWindow}
|
||||||
|
* @param opts {Object}
|
||||||
|
* @param opts.language {String} - locale string ex: en-US
|
||||||
|
*/
|
||||||
|
function setLocale(browserWindow, opts) {
|
||||||
const language = opts && opts.language || app.getLocale();
|
const language = opts && opts.language || app.getLocale();
|
||||||
log.send(logLevels.INFO, `language changed to ${language}. Updating menu and user config`);
|
log.send(logLevels.INFO, `language changed to ${language}. Updating menu and user config`);
|
||||||
rebuildMenu(language);
|
|
||||||
updateConfigField('locale', language);
|
|
||||||
});
|
|
||||||
|
|
||||||
function rebuildMenu(language) {
|
|
||||||
setLanguage(language);
|
setLanguage(language);
|
||||||
|
if (browserWindow && isMainWindow(browserWindow)) {
|
||||||
menu = electron.Menu.buildFromTemplate(getTemplate(app));
|
menu = electron.Menu.buildFromTemplate(getTemplate(app));
|
||||||
electron.Menu.setApplicationMenu(menu);
|
electron.Menu.setApplicationMenu(menu);
|
||||||
|
|
||||||
|
if (isWindows10()) {
|
||||||
|
browserWindow.setMenuBarVisibility(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateConfigField('locale', language);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets language for i18n
|
||||||
|
* @param language {String} - locale string ex: en-US
|
||||||
|
*/
|
||||||
function setLanguage(language) {
|
function setLanguage(language) {
|
||||||
i18n.setLanguage(language);
|
i18n.setLanguage(language);
|
||||||
}
|
}
|
||||||
@ -1097,11 +1124,49 @@ function handleKeyPress(keyCode) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case KeyCodes.Alt:
|
||||||
|
if (isWindows10() && !isCustomTitleBarEnabled) {
|
||||||
|
popupMenu();
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds all the child window and closes it
|
||||||
|
*/
|
||||||
|
function cleanUpChildWindows() {
|
||||||
|
const browserWindows = BrowserWindow.getAllWindows();
|
||||||
|
notify.resetAnimationQueue();
|
||||||
|
if (browserWindows && browserWindows.length) {
|
||||||
|
browserWindows.forEach(browserWindow => {
|
||||||
|
// Closes only child windows
|
||||||
|
if (browserWindow && !browserWindow.isDestroyed() && browserWindow.winName !== 'main') {
|
||||||
|
// clean up notification windows
|
||||||
|
if (browserWindow.winName === 'notification-window') {
|
||||||
|
notify.closeAll();
|
||||||
|
} else {
|
||||||
|
browserWindow.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Method that popup the menu on top of the native title bar
|
||||||
|
* whenever Alt key is pressed
|
||||||
|
*/
|
||||||
|
function popupMenu() {
|
||||||
|
const focusedWindow = BrowserWindow.getFocusedWindow();
|
||||||
|
if (mainWindow && !mainWindow.isDestroyed() && isMainWindow(focusedWindow)) {
|
||||||
|
const popupOpts = { browserWin: mainWindow, x: 10, y: -20 };
|
||||||
|
getMenu().popup(popupOpts);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
createMainWindow: createMainWindow,
|
createMainWindow: createMainWindow,
|
||||||
@ -1115,5 +1180,7 @@ module.exports = {
|
|||||||
verifyDisplays: verifyDisplays,
|
verifyDisplays: verifyDisplays,
|
||||||
getMenu: getMenu,
|
getMenu: getMenu,
|
||||||
setIsAutoReload: setIsAutoReload,
|
setIsAutoReload: setIsAutoReload,
|
||||||
handleKeyPress: handleKeyPress
|
handleKeyPress: handleKeyPress,
|
||||||
|
cleanUpChildWindows: cleanUpChildWindows,
|
||||||
|
setLocale: setLocale,
|
||||||
};
|
};
|
||||||
|
@ -54,7 +54,7 @@ class TitleBar {
|
|||||||
TitleBar.setTitleBarTitle();
|
TitleBar.setTitleBarTitle();
|
||||||
TitleBar.addWindowBorders();
|
TitleBar.addWindowBorders();
|
||||||
break;
|
break;
|
||||||
case titleBarStyles.NATIVE_WITH_CUSTOM:
|
case titleBarStyles.NATIVE:
|
||||||
TitleBar.hideTitleContainer();
|
TitleBar.hideTitleContainer();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -104,7 +104,7 @@ class TitleBar {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Method that hides the title container
|
* Method that hides the title container
|
||||||
* if the title bar style is NATIVE_WITH_CUSTOM
|
* if the title bar style is NATIVE
|
||||||
*/
|
*/
|
||||||
static hideTitleContainer() {
|
static hideTitleContainer() {
|
||||||
const titleContainer = document.getElementById('title-container');
|
const titleContainer = document.getElementById('title-container');
|
||||||
|
@ -15,21 +15,32 @@
|
|||||||
},
|
},
|
||||||
"Bring All to Front": "Bring All to Front",
|
"Bring All to Front": "Bring All to Front",
|
||||||
"Bring to Front on Notifications": "Bring to Front on Notifications",
|
"Bring to Front on Notifications": "Bring to Front on Notifications",
|
||||||
"Flash Notification in Taskbar": "Flash Notification in Taskbar",
|
"Certificate Error": "Certificate Error",
|
||||||
"Title Bar Style": "Title Bar Style",
|
|
||||||
"Native With Custom": "Native With Custom",
|
|
||||||
"Custom": "Custom",
|
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Copy": "Copy",
|
"Copy": "Copy",
|
||||||
|
"Custom": "Custom",
|
||||||
"Cut": "Cut",
|
"Cut": "Cut",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
|
"Dev Tools disabled": "Dev Tools disabled",
|
||||||
|
"Dev Tools has been disabled. Please contact your system administrator": "Dev Tools has been disabled. Please contact your system administrator",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
|
"Error loading configuration": "Error loading configuration",
|
||||||
|
"Error loading URL": "Error loading URL",
|
||||||
|
"Error loading window": "Error loading window",
|
||||||
|
"Error setting AutoLaunch configuration": "Error setting AutoLaunch configuration",
|
||||||
|
"Failed!": "Failed!",
|
||||||
|
"Flash Notification in Taskbar": "Flash Notification in Taskbar",
|
||||||
"Help": "Help",
|
"Help": "Help",
|
||||||
"Hide Others": "Hide Others",
|
"Hide Others": "Hide Others",
|
||||||
"Hide Symphony": "Hide Symphony",
|
"Hide Symphony": "Hide Symphony",
|
||||||
"Learn More": "Learn More",
|
"Learn More": "Learn More",
|
||||||
|
"Loading Error": "Loading Error",
|
||||||
"Minimize": "Minimize",
|
"Minimize": "Minimize",
|
||||||
"Minimize on Close": "Minimize on Close",
|
"Minimize on Close": "Minimize on Close",
|
||||||
|
"Native": "Native",
|
||||||
|
"No crashes available to share": "No crashes available to share",
|
||||||
|
"No logs are available to share": "No logs are available to share",
|
||||||
|
"Not Allowed": "Not Allowed",
|
||||||
"NotificationSettings": {
|
"NotificationSettings": {
|
||||||
"Bottom Left": "Bottom Left",
|
"Bottom Left": "Bottom Left",
|
||||||
"Bottom Right": "Bottom Right",
|
"Bottom Right": "Bottom Right",
|
||||||
@ -43,12 +54,19 @@
|
|||||||
"Top Left": "Top Left",
|
"Top Left": "Top Left",
|
||||||
"Top Right": "Top Right"
|
"Top Right": "Top Right"
|
||||||
},
|
},
|
||||||
|
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
|
||||||
|
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",
|
||||||
"Paste": "Paste",
|
"Paste": "Paste",
|
||||||
"Paste and Match Style": "Paste and Match Style",
|
"Paste and Match Style": "Paste and Match Style",
|
||||||
|
"Permission Denied": "Permission Denied",
|
||||||
|
"Please contact your admin for help": "Please contact your admin for help",
|
||||||
|
"please contact your administrator for more details": "please contact your administrator for more details",
|
||||||
"Quit Symphony": "Quit Symphony",
|
"Quit Symphony": "Quit Symphony",
|
||||||
"Redo": "Redo",
|
"Redo": "Redo",
|
||||||
"Refresh app when idle": "Refresh app when idle",
|
"Refresh app when idle": "Refresh app when idle",
|
||||||
|
"Relaunch Application": "Relaunch Application",
|
||||||
"Reload": "Reload",
|
"Reload": "Reload",
|
||||||
|
"Renderer Process Crashed": "Renderer Process Crashed",
|
||||||
"ScreenPicker": {
|
"ScreenPicker": {
|
||||||
"Applications": "Applications",
|
"Applications": "Applications",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
@ -61,56 +79,40 @@
|
|||||||
"Share": "Share"
|
"Share": "Share"
|
||||||
},
|
},
|
||||||
"ScreenSnippet": {
|
"ScreenSnippet": {
|
||||||
"Pen": "Pen",
|
|
||||||
"Done": "Done",
|
"Done": "Done",
|
||||||
"Snipping Tool": "Snipping Tool",
|
|
||||||
"Erase": "Erase",
|
"Erase": "Erase",
|
||||||
"Highlight": "Highlight"
|
"Highlight": "Highlight",
|
||||||
|
"Pen": "Pen",
|
||||||
|
"Snipping Tool": "Snipping Tool"
|
||||||
},
|
},
|
||||||
"Select All": "Select All",
|
"Select All": "Select All",
|
||||||
"Services": "Services",
|
"Services": "Services",
|
||||||
"Show All": "Show All",
|
"Show All": "Show All",
|
||||||
|
"Show crash dump in Explorer": "Show crash dump in Explorer",
|
||||||
"Show crash dump in Finder": "Show crash dump in Finder",
|
"Show crash dump in Finder": "Show crash dump in Finder",
|
||||||
"Show Logs in Finder": "Show Logs in Finder",
|
|
||||||
"Show Logs in Explorer": "Show Logs in Explorer",
|
"Show Logs in Explorer": "Show Logs in Explorer",
|
||||||
|
"Show Logs in Finder": "Show Logs in Finder",
|
||||||
"SnackBar": {
|
"SnackBar": {
|
||||||
"Press ": "Press ",
|
" to exit full screen": " to exit full screen",
|
||||||
"esc": "esc",
|
"esc": "esc",
|
||||||
" to exit full screen": " to exit full screen"
|
"Press ": "Press "
|
||||||
},
|
},
|
||||||
|
"Sorry, you are not allowed to access this website": "Sorry, you are not allowed to access this website",
|
||||||
"Speech": "Speech",
|
"Speech": "Speech",
|
||||||
"Start Speaking": "Start Speaking",
|
"Start Speaking": "Start Speaking",
|
||||||
"Stop Speaking": "Stop Speaking",
|
"Stop Speaking": "Stop Speaking",
|
||||||
"Symphony Help": "Symphony Help",
|
"Symphony Help": "Symphony Help",
|
||||||
|
"Title Bar Style": "Title Bar Style",
|
||||||
"Toggle Full Screen": "Toggle Full Screen",
|
"Toggle Full Screen": "Toggle Full Screen",
|
||||||
"Troubleshooting": "Troubleshooting",
|
"Troubleshooting": "Troubleshooting",
|
||||||
|
"Unable to generate crash reports due to ": "Unable to generate crash reports due to ",
|
||||||
|
"Unable to generate logs due to ": "Unable to generate logs due to ",
|
||||||
"Undo": "Undo",
|
"Undo": "Undo",
|
||||||
|
"Updating Title bar style requires Symphony to relaunch": "Updating Title bar style requires Symphony to relaunch",
|
||||||
"View": "View",
|
"View": "View",
|
||||||
"Window": "Window",
|
"Window": "Window",
|
||||||
|
"Your administrator has disabled": "Your administrator has disabled",
|
||||||
"Zoom": "Zoom",
|
"Zoom": "Zoom",
|
||||||
"Zoom In": "Zoom In",
|
"Zoom In": "Zoom In",
|
||||||
"Zoom Out": "Zoom Out",
|
"Zoom Out": "Zoom Out"
|
||||||
"Renderer Process Crashed": "Renderer Process Crashed",
|
|
||||||
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
|
|
||||||
"Failed!": "Failed!",
|
|
||||||
"No logs are available to share": "No logs are available to share",
|
|
||||||
"Unable to generate logs due to ": "Unable to generate logs due to ",
|
|
||||||
"Show crash dump in Explorer": "Show crash dump in Explorer",
|
|
||||||
"No crashes available to share": "No crashes available to share",
|
|
||||||
"Unable to generate crash reports due to ": "Unable to generate crash reports due to ",
|
|
||||||
"Error setting AutoLaunch configuration": "Error setting AutoLaunch configuration",
|
|
||||||
"Error loading configuration": "Error loading configuration",
|
|
||||||
"Certificate Error": "Certificate Error",
|
|
||||||
"Error loading URL": "Error loading URL",
|
|
||||||
"Error loading window": "Error loading window",
|
|
||||||
"Loading Error": "Loading Error",
|
|
||||||
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",
|
|
||||||
"Not Allowed": "Not Allowed",
|
|
||||||
"Sorry, you are not allowed to access this website": "Sorry, you are not allowed to access this website",
|
|
||||||
"please contact your administrator for more details": "please contact your administrator for more details",
|
|
||||||
"Your administrator has disabled": "Your administrator has disabled",
|
|
||||||
"Please contact your admin for help": "Please contact your admin for help",
|
|
||||||
"Permission Denied": "Permission Denied",
|
|
||||||
"Dev Tools disabled": "Dev Tools disabled",
|
|
||||||
"Dev Tools has been disabled. Please contact your system administrator": "Dev Tools has been disabled. Please contact your system administrator"
|
|
||||||
}
|
}
|
@ -15,21 +15,30 @@
|
|||||||
},
|
},
|
||||||
"Bring All to Front": "Bring All to Front",
|
"Bring All to Front": "Bring All to Front",
|
||||||
"Bring to Front on Notifications": "Bring to Front on Notifications",
|
"Bring to Front on Notifications": "Bring to Front on Notifications",
|
||||||
"Flash Notification in Taskbar": "Flash Notification in Taskbar",
|
"Certificate Error": "Certificate Error",
|
||||||
"Title Bar Style": "Title Bar Style",
|
|
||||||
"Native With Custom": "Native With Custom",
|
|
||||||
"Custom": "Custom",
|
|
||||||
"Close": "Close",
|
"Close": "Close",
|
||||||
"Copy": "Copy",
|
"Copy": "Copy",
|
||||||
|
"Custom": "Custom",
|
||||||
"Cut": "Cut",
|
"Cut": "Cut",
|
||||||
"Delete": "Delete",
|
"Delete": "Delete",
|
||||||
"Edit": "Edit",
|
"Edit": "Edit",
|
||||||
|
"Error loading configuration": "Error loading configuration",
|
||||||
|
"Error loading URL": "Error loading URL",
|
||||||
|
"Error loading window": "Error loading window",
|
||||||
|
"Error setting AutoLaunch configuration": "Error setting AutoLaunch configuration",
|
||||||
|
"Failed!": "Failed!",
|
||||||
|
"Flash Notification in Taskbar": "Flash Notification in Taskbar",
|
||||||
"Help": "Help",
|
"Help": "Help",
|
||||||
"Hide Others": "Hide Others",
|
"Hide Others": "Hide Others",
|
||||||
"Hide Symphony": "Hide Symphony",
|
"Hide Symphony": "Hide Symphony",
|
||||||
"Learn More": "Learn More",
|
"Learn More": "Learn More",
|
||||||
|
"Loading Error": "Loading Error",
|
||||||
"Minimize": "Minimize",
|
"Minimize": "Minimize",
|
||||||
"Minimize on Close": "Minimize on Close",
|
"Minimize on Close": "Minimize on Close",
|
||||||
|
"Native": "Native",
|
||||||
|
"No crashes available to share": "No crashes available to share",
|
||||||
|
"No logs are available to share": "No logs are available to share",
|
||||||
|
"Not Allowed": "Not Allowed",
|
||||||
"NotificationSettings": {
|
"NotificationSettings": {
|
||||||
"Bottom Left": "Bottom Left",
|
"Bottom Left": "Bottom Left",
|
||||||
"Bottom Right": "Bottom Right",
|
"Bottom Right": "Bottom Right",
|
||||||
@ -43,12 +52,19 @@
|
|||||||
"Top Left": "Top Left",
|
"Top Left": "Top Left",
|
||||||
"Top Right": "Top Right"
|
"Top Right": "Top Right"
|
||||||
},
|
},
|
||||||
|
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
|
||||||
|
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",
|
||||||
"Paste": "Paste",
|
"Paste": "Paste",
|
||||||
"Paste and Match Style": "Paste and Match Style",
|
"Paste and Match Style": "Paste and Match Style",
|
||||||
|
"Permission Denied": "Permission Denied",
|
||||||
|
"Please contact your admin for help": "Please contact your admin for help",
|
||||||
|
"please contact your administrator for more details": "please contact your administrator for more details",
|
||||||
"Quit Symphony": "Quit Symphony",
|
"Quit Symphony": "Quit Symphony",
|
||||||
"Redo": "Redo",
|
"Redo": "Redo",
|
||||||
"Refresh app when idle": "Refresh app when idle",
|
"Refresh app when idle": "Refresh app when idle",
|
||||||
|
"Relaunch Application": "Relaunch Application",
|
||||||
"Reload": "Reload",
|
"Reload": "Reload",
|
||||||
|
"Renderer Process Crashed": "Renderer Process Crashed",
|
||||||
"ScreenPicker": {
|
"ScreenPicker": {
|
||||||
"Applications": "Applications",
|
"Applications": "Applications",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "Cancel",
|
||||||
@ -61,54 +77,40 @@
|
|||||||
"Share": "Share"
|
"Share": "Share"
|
||||||
},
|
},
|
||||||
"ScreenSnippet": {
|
"ScreenSnippet": {
|
||||||
"Pen": "Pen",
|
|
||||||
"Done": "Done",
|
"Done": "Done",
|
||||||
"Snipping Tool": "Snipping Tool",
|
|
||||||
"Erase": "Erase",
|
"Erase": "Erase",
|
||||||
"Highlight": "Highlight"
|
"Highlight": "Highlight",
|
||||||
|
"Pen": "Pen",
|
||||||
|
"Snipping Tool": "Snipping Tool"
|
||||||
},
|
},
|
||||||
"Select All": "Select All",
|
"Select All": "Select All",
|
||||||
"Services": "Services",
|
"Services": "Services",
|
||||||
"Show All": "Show All",
|
"Show All": "Show All",
|
||||||
|
"Show crash dump in Explorer": "Show crash dump in Explorer",
|
||||||
"Show crash dump in Finder": "Show crash dump in Finder",
|
"Show crash dump in Finder": "Show crash dump in Finder",
|
||||||
"Show Logs in Finder": "Show Logs in Finder",
|
|
||||||
"Show Logs in Explorer": "Show Logs in Explorer",
|
"Show Logs in Explorer": "Show Logs in Explorer",
|
||||||
|
"Show Logs in Finder": "Show Logs in Finder",
|
||||||
"SnackBar": {
|
"SnackBar": {
|
||||||
"Press ": "Press ",
|
" to exit full screen": " to exit full screen",
|
||||||
"esc": "esc",
|
"esc": "esc",
|
||||||
" to exit full screen": " to exit full screen"
|
"Press ": "Press "
|
||||||
},
|
},
|
||||||
|
"Sorry, you are not allowed to access this website": "Sorry, you are not allowed to access this website",
|
||||||
"Speech": "Speech",
|
"Speech": "Speech",
|
||||||
"Start Speaking": "Start Speaking",
|
"Start Speaking": "Start Speaking",
|
||||||
"Stop Speaking": "Stop Speaking",
|
"Stop Speaking": "Stop Speaking",
|
||||||
"Symphony Help": "Symphony Help",
|
"Symphony Help": "Symphony Help",
|
||||||
|
"Title Bar Style": "Title Bar Style",
|
||||||
"Toggle Full Screen": "Toggle Full Screen",
|
"Toggle Full Screen": "Toggle Full Screen",
|
||||||
"Troubleshooting": "Troubleshooting",
|
"Troubleshooting": "Troubleshooting",
|
||||||
|
"Unable to generate crash reports due to ": "Unable to generate crash reports due to ",
|
||||||
|
"Unable to generate logs due to ": "Unable to generate logs due to ",
|
||||||
"Undo": "Undo",
|
"Undo": "Undo",
|
||||||
|
"Updating Title bar style requires Symphony to relaunch": "Updating Title bar style requires Symphony to relaunch",
|
||||||
"View": "View",
|
"View": "View",
|
||||||
"Window": "Window",
|
"Window": "Window",
|
||||||
|
"Your administrator has disabled": "Your administrator has disabled",
|
||||||
"Zoom": "Zoom",
|
"Zoom": "Zoom",
|
||||||
"Zoom In": "Zoom In",
|
"Zoom In": "Zoom In",
|
||||||
"Zoom Out": "Zoom Out",
|
"Zoom Out": "Zoom Out"
|
||||||
"Renderer Process Crashed": "Renderer Process Crashed",
|
|
||||||
"Oops! Looks like we have had a crash.": "Oops! Looks like we have had a crash.",
|
|
||||||
"Failed!": "Failed!",
|
|
||||||
"No logs are available to share": "No logs are available to share",
|
|
||||||
"Unable to generate logs due to ": "Unable to generate logs due to ",
|
|
||||||
"Show crash dump in Explorer": "Show crash dump in Explorer",
|
|
||||||
"No crashes available to share": "No crashes available to share",
|
|
||||||
"Unable to generate crash reports due to ": "Unable to generate crash reports due to ",
|
|
||||||
"Error setting AutoLaunch configuration": "Error setting AutoLaunch configuration",
|
|
||||||
"Error loading configuration": "Error loading configuration",
|
|
||||||
"Certificate Error": "Certificate Error",
|
|
||||||
"Error loading URL": "Error loading URL",
|
|
||||||
"Error loading window": "Error loading window",
|
|
||||||
"Loading Error": "Loading Error",
|
|
||||||
"Oops! Looks like we have had a crash. Please reload or close this window.": "Oops! Looks like we have had a crash. Please reload or close this window.",
|
|
||||||
"Not Allowed": "Not Allowed",
|
|
||||||
"Sorry, you are not allowed to access this website": "Sorry, you are not allowed to access this website",
|
|
||||||
"please contact your administrator for more details": "please contact your administrator for more details",
|
|
||||||
"Your administrator has disabled": "Your administrator has disabled",
|
|
||||||
"Please contact your admin for help": "Please contact your admin for help",
|
|
||||||
"Permission Denied": "Permission Denied"
|
|
||||||
}
|
}
|
@ -15,21 +15,32 @@
|
|||||||
},
|
},
|
||||||
"Bring All to Front": "すべて前面に表示",
|
"Bring All to Front": "すべて前面に表示",
|
||||||
"Bring to Front on Notifications": "通知時に前面に表示",
|
"Bring to Front on Notifications": "通知時に前面に表示",
|
||||||
"Flash Notification in Taskbar": "タスクバーの通知を点滅",
|
"Certificate Error": "証明書のエラー",
|
||||||
"Title Bar Style": "タイトルバーのスタイル",
|
|
||||||
"Native With Custom": "Nativeでカスタムを使用",
|
|
||||||
"Custom": "カスタム",
|
|
||||||
"Close": "閉じる",
|
"Close": "閉じる",
|
||||||
"Copy": "コピー",
|
"Copy": "コピー",
|
||||||
|
"Custom": "カスタム",
|
||||||
"Cut": "切り取り",
|
"Cut": "切り取り",
|
||||||
"Delete": "削除",
|
"Delete": "削除",
|
||||||
|
"Dev Tools disabled": "開発ツールを無効にする",
|
||||||
|
"Dev Tools has been disabled. Please contact your system administrator": "Dev Toolsが無効になっています。システム管理者に連絡してください",
|
||||||
"Edit": "編集",
|
"Edit": "編集",
|
||||||
|
"Error loading configuration": "構成の読み込みエラー",
|
||||||
|
"Error loading URL": "URLの読み込みエラー",
|
||||||
|
"Error loading window": "ウィンドウを読み込みエラー",
|
||||||
|
"Error setting AutoLaunch configuration": "自動起動の構成の設定エラー",
|
||||||
|
"Failed!": "問題が起きました!",
|
||||||
|
"Flash Notification in Taskbar": "タスクバーの通知を点滅",
|
||||||
"Help": "ヘルプ",
|
"Help": "ヘルプ",
|
||||||
"Hide Others": "他を隠す",
|
"Hide Others": "他を隠す",
|
||||||
"Hide Symphony": "Symphonyを隠す",
|
"Hide Symphony": "Symphonyを隠す",
|
||||||
"Learn More": "詳細",
|
"Learn More": "詳細",
|
||||||
|
"Loading Error": "読み込みエラー",
|
||||||
"Minimize": "最小化",
|
"Minimize": "最小化",
|
||||||
"Minimize on Close": "閉じるで最小化",
|
"Minimize on Close": "閉じるで最小化",
|
||||||
|
"Native": "Native",
|
||||||
|
"No crashes available to share": "共有できるクラッシュはありません",
|
||||||
|
"No logs are available to share": "共有できるログはありません",
|
||||||
|
"Not Allowed": "許可されていませ。",
|
||||||
"NotificationSettings": {
|
"NotificationSettings": {
|
||||||
"Bottom Left": "左下",
|
"Bottom Left": "左下",
|
||||||
"Bottom Right": "右下",
|
"Bottom Right": "右下",
|
||||||
@ -43,12 +54,19 @@
|
|||||||
"Top Left": "左上",
|
"Top Left": "左上",
|
||||||
"Top Right": "右上"
|
"Top Right": "右上"
|
||||||
},
|
},
|
||||||
|
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
|
||||||
|
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
|
||||||
"Paste": "貼り付け",
|
"Paste": "貼り付け",
|
||||||
"Paste and Match Style": "貼り付けでスタイルを合わせる",
|
"Paste and Match Style": "貼り付けでスタイルを合わせる",
|
||||||
|
"Permission Denied": "アクセス許可が拒否されています",
|
||||||
|
"Please contact your admin for help": "不明な点がある場合は、管理者にお問い合わせください",
|
||||||
|
"please contact your administrator for more details": "詳細は、管理者にお問い合わせください",
|
||||||
"Quit Symphony": "Symphonyを終了",
|
"Quit Symphony": "Symphonyを終了",
|
||||||
"Redo": "やり直し",
|
"Redo": "やり直し",
|
||||||
"Refresh app when idle": "アイドル時にアプリを再表示",
|
"Refresh app when idle": "アイドル時にアプリを再表示",
|
||||||
|
"Relaunch Application": "アプリケーションの再起動",
|
||||||
"Reload": "再読み込み",
|
"Reload": "再読み込み",
|
||||||
|
"Renderer Process Crashed": "レンダラープロセスがクラッシュしました",
|
||||||
"ScreenPicker": {
|
"ScreenPicker": {
|
||||||
"Applications": "アプリケーション",
|
"Applications": "アプリケーション",
|
||||||
"Cancel": "キャンセル",
|
"Cancel": "キャンセル",
|
||||||
@ -61,56 +79,40 @@
|
|||||||
"Share": "共有"
|
"Share": "共有"
|
||||||
},
|
},
|
||||||
"ScreenSnippet": {
|
"ScreenSnippet": {
|
||||||
"Pen": "ペン",
|
|
||||||
"Done": "完了",
|
"Done": "完了",
|
||||||
"Snipping Tool": "切り取りツール",
|
|
||||||
"Erase": "消去",
|
"Erase": "消去",
|
||||||
"Highlight": "強調"
|
"Highlight": "強調",
|
||||||
|
"Pen": "ペン",
|
||||||
|
"Snipping Tool": "切り取りツール"
|
||||||
},
|
},
|
||||||
"Select All": "すべてを選択",
|
"Select All": "すべてを選択",
|
||||||
"Services": "サービス",
|
"Services": "サービス",
|
||||||
"Show All": "すべてを表示",
|
"Show All": "すべてを表示",
|
||||||
|
"Show crash dump in Explorer": "Explorerにクラッシュダンプを表示",
|
||||||
"Show crash dump in Finder": "ファインダーにクラッシュダンプを表示",
|
"Show crash dump in Finder": "ファインダーにクラッシュダンプを表示",
|
||||||
"Show Logs in Finder": "ファインダーにログを表示",
|
|
||||||
"Show Logs in Explorer": "Explorerにログを表示",
|
"Show Logs in Explorer": "Explorerにログを表示",
|
||||||
|
"Show Logs in Finder": "ファインダーにログを表示",
|
||||||
"SnackBar": {
|
"SnackBar": {
|
||||||
"Press ": "全画面表示を終了するには ",
|
" to exit full screen": " を押します",
|
||||||
"esc": "esc",
|
"esc": "esc",
|
||||||
" to exit full screen": " を押します"
|
"Press ": "全画面表示を終了するには "
|
||||||
},
|
},
|
||||||
|
"Sorry, you are not allowed to access this website": "申し訳ありませんが、このウェブサイトへのアクセスは許可されていません",
|
||||||
"Speech": "スピーチ",
|
"Speech": "スピーチ",
|
||||||
"Start Speaking": "スピーチを開始",
|
"Start Speaking": "スピーチを開始",
|
||||||
"Stop Speaking": "スピーチを終了",
|
"Stop Speaking": "スピーチを終了",
|
||||||
"Symphony Help": "Symphonyのヘルプ",
|
"Symphony Help": "Symphonyのヘルプ",
|
||||||
|
"Title Bar Style": "タイトルバーのスタイル",
|
||||||
"Toggle Full Screen": "画面表示を切り替え",
|
"Toggle Full Screen": "画面表示を切り替え",
|
||||||
"Troubleshooting": "トラブルシューティング",
|
"Troubleshooting": "トラブルシューティング",
|
||||||
|
"Unable to generate crash reports due to ": "クラッシュレポートを生成できません。理由: ",
|
||||||
|
"Unable to generate logs due to ": "ログを生成できません。理由:",
|
||||||
"Undo": "元に戻す",
|
"Undo": "元に戻す",
|
||||||
|
"Updating Title bar style requires Symphony to relaunch": "タイトルバーのスタイルを更新するには、Symphonyが再起動する必要があります",
|
||||||
"View": "ビュー",
|
"View": "ビュー",
|
||||||
"Window": "ウインドウ",
|
"Window": "ウインドウ",
|
||||||
|
"Your administrator has disabled": "管理者によて無効にされています",
|
||||||
"Zoom": "ズーム",
|
"Zoom": "ズーム",
|
||||||
"Zoom In": "ズームイン",
|
"Zoom In": "ズームイン",
|
||||||
"Zoom Out": "ズームアウト",
|
"Zoom Out": "ズームアウト"
|
||||||
"Renderer Process Crashed": "レンダラープロセスがクラッシュしました",
|
|
||||||
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
|
|
||||||
"Failed!": "問題が起きました!",
|
|
||||||
"No logs are available to share": "共有できるログはありません",
|
|
||||||
"Unable to generate logs due to ": "ログを生成できません。理由:",
|
|
||||||
"Show crash dump in Explorer": "Explorerにクラッシュダンプを表示",
|
|
||||||
"No crashes available to share": "共有できるクラッシュはありません",
|
|
||||||
"Unable to generate crash reports due to ": "クラッシュレポートを生成できません。理由: ",
|
|
||||||
"Error setting AutoLaunch configuration": "自動起動の構成の設定エラー",
|
|
||||||
"Error loading configuration": "構成の読み込みエラー",
|
|
||||||
"Certificate Error": "証明書のエラー",
|
|
||||||
"Error loading URL": "URLの読み込みエラー",
|
|
||||||
"Error loading window": "ウィンドウを読み込みエラー",
|
|
||||||
"Loading Error": "読み込みエラー",
|
|
||||||
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
|
|
||||||
"Not Allowed": "許可されていませ。",
|
|
||||||
"Sorry, you are not allowed to access this website": "申し訳ありませんが、このウェブサイトへのアクセスは許可されていません",
|
|
||||||
"please contact your administrator for more details": "詳細は、管理者にお問い合わせください",
|
|
||||||
"Your administrator has disabled": "管理者によて無効にされています",
|
|
||||||
"Please contact your admin for help": "不明な点がある場合は、管理者にお問い合わせください",
|
|
||||||
"Permission Denied": "アクセス許可が拒否されています",
|
|
||||||
"Dev Tools disabled": "開発ツールを無効にする",
|
|
||||||
"Dev Tools has been disabled. Please contact your system administrator": "Dev Toolsが無効になっています。システム管理者に連絡してください"
|
|
||||||
}
|
}
|
@ -15,21 +15,30 @@
|
|||||||
},
|
},
|
||||||
"Bring All to Front": "すべて前面に表示",
|
"Bring All to Front": "すべて前面に表示",
|
||||||
"Bring to Front on Notifications": "通知時に前面に表示",
|
"Bring to Front on Notifications": "通知時に前面に表示",
|
||||||
"Flash Notification in Taskbar": "タスクバーの通知を点滅",
|
"Certificate Error": "証明書のエラー",
|
||||||
"Title Bar Style": "タイトルバーのスタイル",
|
|
||||||
"Native With Custom": "Nativeでカスタムを使用",
|
|
||||||
"Custom": "カスタム",
|
|
||||||
"Close": "閉じる",
|
"Close": "閉じる",
|
||||||
"Copy": "コピー",
|
"Copy": "コピー",
|
||||||
|
"Custom": "カスタム",
|
||||||
"Cut": "切り取り",
|
"Cut": "切り取り",
|
||||||
"Delete": "削除",
|
"Delete": "削除",
|
||||||
"Edit": "編集",
|
"Edit": "編集",
|
||||||
|
"Error loading configuration": "構成の読み込みエラー",
|
||||||
|
"Error loading URL": "URLの読み込みエラー",
|
||||||
|
"Error loading window": "ウィンドウを読み込みエラー",
|
||||||
|
"Error setting AutoLaunch configuration": "自動起動の構成の設定エラー",
|
||||||
|
"Failed!": "問題が起きました!",
|
||||||
|
"Flash Notification in Taskbar": "タスクバーの通知を点滅",
|
||||||
"Help": "ヘルプ",
|
"Help": "ヘルプ",
|
||||||
"Hide Others": "他を隠す",
|
"Hide Others": "他を隠す",
|
||||||
"Hide Symphony": "Symphonyを隠す",
|
"Hide Symphony": "Symphonyを隠す",
|
||||||
"Learn More": "詳細",
|
"Learn More": "詳細",
|
||||||
|
"Loading Error": "読み込みエラー",
|
||||||
"Minimize": "最小化",
|
"Minimize": "最小化",
|
||||||
"Minimize on Close": "閉じるで最小化",
|
"Minimize on Close": "閉じるで最小化",
|
||||||
|
"Native": "Native",
|
||||||
|
"No crashes available to share": "共有できるクラッシュはありません",
|
||||||
|
"No logs are available to share": "共有できるログはありません",
|
||||||
|
"Not Allowed": "許可されていませ。",
|
||||||
"NotificationSettings": {
|
"NotificationSettings": {
|
||||||
"Bottom Left": "左下",
|
"Bottom Left": "左下",
|
||||||
"Bottom Right": "右下",
|
"Bottom Right": "右下",
|
||||||
@ -43,12 +52,19 @@
|
|||||||
"Top Left": "左上",
|
"Top Left": "左上",
|
||||||
"Top Right": "右上"
|
"Top Right": "右上"
|
||||||
},
|
},
|
||||||
|
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
|
||||||
|
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
|
||||||
"Paste": "貼り付け",
|
"Paste": "貼り付け",
|
||||||
"Paste and Match Style": "貼り付けでスタイルを合わせる",
|
"Paste and Match Style": "貼り付けでスタイルを合わせる",
|
||||||
|
"Permission Denied": "アクセス許可が拒否されています",
|
||||||
|
"Please contact your admin for help": "不明な点がある場合は、管理者にお問い合わせください",
|
||||||
|
"please contact your administrator for more details": "詳細は、管理者にお問い合わせください",
|
||||||
"Quit Symphony": "Symphonyを終了",
|
"Quit Symphony": "Symphonyを終了",
|
||||||
"Redo": "やり直し",
|
"Redo": "やり直し",
|
||||||
"Refresh app when idle": "アイドル時にアプリを再表示",
|
"Refresh app when idle": "アイドル時にアプリを再表示",
|
||||||
|
"Relaunch Application": "アプリケーションの再起動",
|
||||||
"Reload": "再読み込み",
|
"Reload": "再読み込み",
|
||||||
|
"Renderer Process Crashed": "レンダラープロセスがクラッシュしました",
|
||||||
"ScreenPicker": {
|
"ScreenPicker": {
|
||||||
"Applications": "アプリケーション",
|
"Applications": "アプリケーション",
|
||||||
"Cancel": "キャンセル",
|
"Cancel": "キャンセル",
|
||||||
@ -61,54 +77,40 @@
|
|||||||
"Share": "共有"
|
"Share": "共有"
|
||||||
},
|
},
|
||||||
"ScreenSnippet": {
|
"ScreenSnippet": {
|
||||||
"Pen": "ペン",
|
|
||||||
"Done": "完了",
|
"Done": "完了",
|
||||||
"Snipping Tool": "切り取りツール",
|
|
||||||
"Erase": "消去",
|
"Erase": "消去",
|
||||||
"Highlight": "強調"
|
"Highlight": "強調",
|
||||||
|
"Pen": "ペン",
|
||||||
|
"Snipping Tool": "切り取りツール"
|
||||||
},
|
},
|
||||||
"Select All": "すべてを選択",
|
"Select All": "すべてを選択",
|
||||||
"Services": "サービス",
|
"Services": "サービス",
|
||||||
"Show All": "すべてを表示",
|
"Show All": "すべてを表示",
|
||||||
|
"Show crash dump in Explorer": "Explorerにクラッシュダンプを表示",
|
||||||
"Show crash dump in Finder": "ファインダーにクラッシュダンプを表示",
|
"Show crash dump in Finder": "ファインダーにクラッシュダンプを表示",
|
||||||
"Show Logs in Finder": "ファインダーにログを表示",
|
|
||||||
"Show Logs in Explorer": "Explorerにログを表示",
|
"Show Logs in Explorer": "Explorerにログを表示",
|
||||||
|
"Show Logs in Finder": "ファインダーにログを表示",
|
||||||
"SnackBar": {
|
"SnackBar": {
|
||||||
"Press ": "全画面表示を終了するには ",
|
" to exit full screen": " を押します",
|
||||||
"esc": "esc",
|
"esc": "esc",
|
||||||
" to exit full screen": " を押します"
|
"Press ": "全画面表示を終了するには "
|
||||||
},
|
},
|
||||||
|
"Sorry, you are not allowed to access this website": "申し訳ありませんが、このウェブサイトへのアクセスは許可されていません",
|
||||||
"Speech": "スピーチ",
|
"Speech": "スピーチ",
|
||||||
"Start Speaking": "スピーチを開始",
|
"Start Speaking": "スピーチを開始",
|
||||||
"Stop Speaking": "スピーチを終了",
|
"Stop Speaking": "スピーチを終了",
|
||||||
"Symphony Help": "Symphonyのヘルプ",
|
"Symphony Help": "Symphonyのヘルプ",
|
||||||
|
"Title Bar Style": "タイトルバーのスタイル",
|
||||||
"Toggle Full Screen": "画面表示を切り替え",
|
"Toggle Full Screen": "画面表示を切り替え",
|
||||||
"Troubleshooting": "トラブルシューティング",
|
"Troubleshooting": "トラブルシューティング",
|
||||||
|
"Unable to generate crash reports due to ": "クラッシュレポートを生成できません。理由: ",
|
||||||
|
"Unable to generate logs due to ": "ログを生成できません。理由:",
|
||||||
"Undo": "元に戻す",
|
"Undo": "元に戻す",
|
||||||
|
"Updating Title bar style requires Symphony to relaunch": "タイトルバーのスタイルを更新するには、Symphonyが再起動する必要があります",
|
||||||
"View": "ビュー",
|
"View": "ビュー",
|
||||||
"Window": "ウインドウ",
|
"Window": "ウインドウ",
|
||||||
|
"Your administrator has disabled": "管理者によて無効にされています",
|
||||||
"Zoom": "ズーム",
|
"Zoom": "ズーム",
|
||||||
"Zoom In": "ズームイン",
|
"Zoom In": "ズームイン",
|
||||||
"Zoom Out": "ズームアウト",
|
"Zoom Out": "ズームアウト"
|
||||||
"Renderer Process Crashed": "レンダラープロセスがクラッシュしました",
|
|
||||||
"Oops! Looks like we have had a crash.": "おっと!クラッシュしたようです。",
|
|
||||||
"Failed!": "問題が起きました!",
|
|
||||||
"No logs are available to share": "共有できるログはありません",
|
|
||||||
"Unable to generate logs due to ": "ログを生成できません。理由:",
|
|
||||||
"Show crash dump in Explorer": "Explorerにクラッシュダンプを表示",
|
|
||||||
"No crashes available to share": "共有できるクラッシュはありません",
|
|
||||||
"Unable to generate crash reports due to ": "クラッシュレポートを生成できません。理由: ",
|
|
||||||
"Error setting AutoLaunch configuration": "自動起動の構成の設定エラー",
|
|
||||||
"Error loading configuration": "構成の読み込みエラー",
|
|
||||||
"Certificate Error": "証明書のエラー",
|
|
||||||
"Error loading URL": "URLの読み込みエラー",
|
|
||||||
"Error loading window": "ウィンドウを読み込みエラー",
|
|
||||||
"Loading Error": "読み込みエラー",
|
|
||||||
"Oops! Looks like we have had a crash. Please reload or close this window.": "おっと!クラッシュしたようです。このウィンドウを再度読み込むか閉じてください。",
|
|
||||||
"Not Allowed": "許可されていませ。",
|
|
||||||
"Sorry, you are not allowed to access this website": "申し訳ありませんが、このウェブサイトへのアクセスは許可されていません",
|
|
||||||
"please contact your administrator for more details": "詳細は、管理者にお問い合わせください",
|
|
||||||
"Your administrator has disabled": "管理者によて無効にされています",
|
|
||||||
"Please contact your admin for help": "不明な点がある場合は、管理者にお問い合わせください",
|
|
||||||
"Permission Denied": "アクセス許可が拒否されています"
|
|
||||||
}
|
}
|
16
package.json
16
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "Symphony",
|
"name": "Symphony",
|
||||||
"productName": "Symphony",
|
"productName": "Symphony",
|
||||||
"version": "2.10.0",
|
"version": "2.11.0",
|
||||||
"buildNumber": "0",
|
"buildNumber": "0",
|
||||||
"description": "Symphony desktop app (Foundation ODP)",
|
"description": "Symphony desktop app (Foundation ODP)",
|
||||||
"author": "Symphony",
|
"author": "Symphony",
|
||||||
@ -48,6 +48,7 @@
|
|||||||
"extraFiles": [
|
"extraFiles": [
|
||||||
"config/Symphony.config",
|
"config/Symphony.config",
|
||||||
"library/libsymphonysearch.dylib",
|
"library/libsymphonysearch.dylib",
|
||||||
|
"library/cryptoLib.dylib",
|
||||||
"library/lz4.exec"
|
"library/lz4.exec"
|
||||||
],
|
],
|
||||||
"appId": "com.symphony.electron-desktop",
|
"appId": "com.symphony.electron-desktop",
|
||||||
@ -88,8 +89,9 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"bluebird": "3.5.1",
|
"bluebird": "3.5.1",
|
||||||
"browserify": "16.2.2",
|
"browserify": "16.2.2",
|
||||||
|
"chromedriver": "2.40.0",
|
||||||
"cross-env": "5.2.0",
|
"cross-env": "5.2.0",
|
||||||
"electron": "2.0.4",
|
"electron": "2.0.7",
|
||||||
"electron-builder": "20.16.4",
|
"electron-builder": "20.16.4",
|
||||||
"electron-builder-squirrel-windows": "12.3.0",
|
"electron-builder-squirrel-windows": "12.3.0",
|
||||||
"electron-chromedriver": "2.0.0",
|
"electron-chromedriver": "2.0.0",
|
||||||
@ -105,7 +107,9 @@
|
|||||||
"jest-html-reporter": "2.4.1",
|
"jest-html-reporter": "2.4.1",
|
||||||
"ncp": "2.0.0",
|
"ncp": "2.0.0",
|
||||||
"robotjs": "0.5.1",
|
"robotjs": "0.5.1",
|
||||||
"spectron": "3.8.0"
|
"selenium-webdriver": "3.6.0",
|
||||||
|
"spectron": "3.8.0",
|
||||||
|
"wdio-selenium-standalone-service": "0.0.10"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@paulcbetts/system-idle-time": "1.0.4",
|
"@paulcbetts/system-idle-time": "1.0.4",
|
||||||
@ -124,10 +128,12 @@
|
|||||||
"lodash.omit": "4.5.0",
|
"lodash.omit": "4.5.0",
|
||||||
"lodash.pick": "4.4.0",
|
"lodash.pick": "4.4.0",
|
||||||
"shell-path": "2.1.0",
|
"shell-path": "2.1.0",
|
||||||
"winreg": "1.2.4"
|
"winreg": "1.2.4",
|
||||||
|
"ffi": "2.2.0",
|
||||||
|
"ref": "1.3.5"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"screen-snippet": "git+https://github.com/symphonyoss/ScreenSnippet.git#v1.0.2",
|
"screen-snippet": "git+https://github.com/symphonyoss/ScreenSnippet.git#v1.0.2",
|
||||||
"swift-search": "1.0.4"
|
"swift-search": "1.0.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
tests/spectron/alwaysOnTopWithMultApps.spectron.js
Normal file
69
tests/spectron/alwaysOnTopWithMultApps.spectron.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
const {isMac} = require('../../js/utils/misc');
|
||||||
|
|
||||||
|
let app;
|
||||||
|
let windowActions;
|
||||||
|
let webActions;
|
||||||
|
|
||||||
|
!isMac ? describe('Tests for always on top with mult-apps are opened', () => {
|
||||||
|
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
try {
|
||||||
|
app = await new Application({}).startApplication({alwaysOnTop: false});
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
done();
|
||||||
|
} catch(err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
await Utils.killProcess("notepad.exe");
|
||||||
|
await Utils.killProcess("mspaint.exe");
|
||||||
|
await windowActions.openMenu(["Window","Always on Top"]);
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
await app.stop();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Always on Top options when multiple applications are opened
|
||||||
|
* TC-ID: 2898431
|
||||||
|
* Cover scenarios in AVT-990
|
||||||
|
*/
|
||||||
|
it('Verify Always on Top options when multiple applications are opened', async (done) => {
|
||||||
|
try {
|
||||||
|
await windowActions.openMenu(["Window","Always on Top"]);
|
||||||
|
await webActions.minimizeWindows();
|
||||||
|
await Utils.openAppInMaximize("C:\\Windows\\notepad.exe");
|
||||||
|
await Utils.openAppInMaximize("C:\\Windows\\system32\\mspaint.exe");
|
||||||
|
await windowActions.showWindow();
|
||||||
|
await windowActions.clickOutsideWindow();
|
||||||
|
await windowActions.verifyWindowsOnTop();
|
||||||
|
|
||||||
|
//Close and open app again, make sure it's always on top
|
||||||
|
await app.stop();
|
||||||
|
app = await new Application({}).startApplication();
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
await windowActions.clickOutsideWindow();
|
||||||
|
await windowActions.verifyWindowsOnTop();
|
||||||
|
done();
|
||||||
|
} catch(err) {
|
||||||
|
done.fail(new Error(`Fail to keep Always on Top options when multiple applications are opened with error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}): describe.skip();
|
69
tests/spectron/badgeCount.spectron.js
Normal file
69
tests/spectron/badgeCount.spectron.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WebDriver = require('./spectronWebDriver');
|
||||||
|
const { isMac } = require('../../js/utils/misc.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
let app = new Application({
|
||||||
|
startTimeout: Application.getTimeOut(),
|
||||||
|
waitTimeout: Application.getTimeOut()
|
||||||
|
});
|
||||||
|
let webdriver = new WebDriver({ browser: 'chrome' });
|
||||||
|
const WindowsAction = require('./spectronWindowsActions');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const specconst = require('./spectronConstants.js');
|
||||||
|
|
||||||
|
let webActions, windowAction;
|
||||||
|
|
||||||
|
describe('Test for Badge Count on MAC', () => {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
try {
|
||||||
|
app = await new Application({}).startApplication({ testedHost: specconst.TESTED_HOST, alwaysOnTop: true });
|
||||||
|
windowAction = await new WindowsAction(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
await app.stop();
|
||||||
|
await webdriver.quit();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Show 1 in tray icon when unread message = 1
|
||||||
|
* TC-ID: 2906586
|
||||||
|
* Cover scenarios in AVT-1095
|
||||||
|
*/
|
||||||
|
it('Show 1 in tray icon when unread message = 1', async (done) => {
|
||||||
|
try {
|
||||||
|
if (isMac) {
|
||||||
|
let message = await Utils.randomString();
|
||||||
|
await webdriver.startDriver();
|
||||||
|
await webdriver.login(specconst.USER_A);
|
||||||
|
await webdriver.createIM(specconst.USER_B.username);
|
||||||
|
await webActions.login(specconst.USER_B);
|
||||||
|
await webActions.clickLeftNavItem(specconst.USER_A.name);
|
||||||
|
await webActions.openAlertsSettings();
|
||||||
|
let currentBadgeCount = await windowAction.getBadgeCount();
|
||||||
|
await webdriver.sendMessage(message);
|
||||||
|
await windowAction.verifyCurrentBadgeCount(currentBadgeCount + 1);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Show 1 in tray icon with error: ${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
})
|
90
tests/spectron/closePopOutsOnReload.spectron.js
Normal file
90
tests/spectron/closePopOutsOnReload.spectron.js
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
let app = new Application({});
|
||||||
|
|
||||||
|
describe('Tests for pop outs reload scenario', () => {
|
||||||
|
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
|
||||||
|
beforeAll((done) => {
|
||||||
|
return app.startApplication().then((startedApp) => {
|
||||||
|
app = startedApp;
|
||||||
|
done();
|
||||||
|
}).catch((err) => {
|
||||||
|
console.error(`Unable to start application: ${err}`);
|
||||||
|
expect(err).toBeNull();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll((done) => {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
app.stop().then(() => {
|
||||||
|
done();
|
||||||
|
}).catch((err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should launch the app', (done) => {
|
||||||
|
return app.client.waitUntilWindowLoaded().then(() => {
|
||||||
|
return app.client.getWindowCount().then((count) => {
|
||||||
|
expect(count === 1).toBeTruthy();
|
||||||
|
done();
|
||||||
|
}).catch((err) => {
|
||||||
|
expect(err).toBeNull();
|
||||||
|
});
|
||||||
|
}).catch((err) => {
|
||||||
|
expect(err).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should load the demo page', () => {
|
||||||
|
return app.client.url('file:///' + path.join(__dirname, '..', '..', 'demo/index.html'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open a new window and verify', function (done) {
|
||||||
|
app.client.waitForExist('#open-win', 2000);
|
||||||
|
app.client.moveToObject('#open-win', 10, 10);
|
||||||
|
app.client.leftClick('#open-win', 10, 10);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
app.client.getWindowCount().then((count) => {
|
||||||
|
expect(count === 2).toBeTruthy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should open a child window from pop-out and verify', function (done) {
|
||||||
|
return app.client.windowByIndex(1).then(() => {
|
||||||
|
app.client.waitForExist('#open-win', 2000);
|
||||||
|
app.client.moveToObject('#open-win', 10, 10);
|
||||||
|
app.client.leftClick('#open-win', 10, 10);
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
app.client.getWindowCount().then((count) => {
|
||||||
|
expect(count === 3).toBeTruthy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should close pop-out window when main window is reloaded', function (done) {
|
||||||
|
return app.client.windowByIndex(0).then(() => {
|
||||||
|
app.browserWindow.reload();
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
app.client.getWindowCount().then((count) => {
|
||||||
|
expect(count === 1).toBeTruthy();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
52
tests/spectron/electronProductionLogging.spectron.js
Normal file
52
tests/spectron/electronProductionLogging.spectron.js
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
const { isMac } = require('../../js/utils/misc.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
|
||||||
|
let app;
|
||||||
|
let windowActions;
|
||||||
|
|
||||||
|
!isMac ? describe('Tests for Electron Production Logging', () => {
|
||||||
|
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
try {
|
||||||
|
app = await new Application({}).startApplication();
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
|
await windowActions.deleteAllLogFiles();
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
await app.stop();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify the production logs exists when clicking on "Show logs in Explorer"
|
||||||
|
* TC-ID: 3935260
|
||||||
|
* Cover scenarios in AVT-1029
|
||||||
|
*/
|
||||||
|
it('Verify the production logs exists when clicking on Show logs in Explorer', async (done) => {
|
||||||
|
try {
|
||||||
|
await windowActions.openMenu(["Help", "Troubleshooting", "Show Logs in Explorer"]);
|
||||||
|
Utils.sleep(2000) //sleep for creating log
|
||||||
|
await windowActions.verifyLogExported();
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Fail to export production logs with error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}) : describe.skip();
|
@ -123,8 +123,8 @@ describe('Tests for Full screen', () => {
|
|||||||
robot.setMouseDelay(100);
|
robot.setMouseDelay(100);
|
||||||
let x = bounds.x + 200;
|
let x = bounds.x + 200;
|
||||||
let y = bounds.y + 200;
|
let y = bounds.y + 200;
|
||||||
robot.moveMouseSmooth(x, y);
|
robot.moveMouse(x, y);
|
||||||
robot.mouseClick();
|
robot.mouseClick("left");
|
||||||
|
|
||||||
robot.keyTap('f11');
|
robot.keyTap('f11');
|
||||||
|
|
||||||
|
154
tests/spectron/minimize-on-close-icon.spectron.js
Normal file
154
tests/spectron/minimize-on-close-icon.spectron.js
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const { isMac } = require('../../js/utils/misc');
|
||||||
|
const WindowsAction = require('./spectronWindowsActions');
|
||||||
|
const WebAction = require('./spectronWebActions');
|
||||||
|
var app = new Application({
|
||||||
|
startTimeout: Application.getTimeOut(),
|
||||||
|
waitTimeout: Application.getTimeOut()
|
||||||
|
});
|
||||||
|
let wActions;
|
||||||
|
let webActions;
|
||||||
|
|
||||||
|
!isMac ?describe('Add Test To Verify Minimize on Close', () => {
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
await app.startApplication().then(async(startedApp) => {
|
||||||
|
app.app = await startedApp;
|
||||||
|
wActions = await new WindowsAction(app.app);
|
||||||
|
webActions = await new WebAction(app.app);
|
||||||
|
}).then((async() =>{
|
||||||
|
await getConfigPath(app.app).then((config) => {
|
||||||
|
app.pathApp = config;
|
||||||
|
}).catch((err) => {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
}));
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
function getConfigPath(app) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
app.client.addCommand('getUserDataPath', function () {
|
||||||
|
return app.client.execute(function () {
|
||||||
|
return require('electron').remote.app.getPath('userData');
|
||||||
|
})
|
||||||
|
});
|
||||||
|
app.client.getUserDataPath().then((userConfigPath) => {
|
||||||
|
resolve(userConfigPath.value)
|
||||||
|
}).catch((err) => {
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
afterAll((done) => {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
app.client.getWindowCount().then((count) => {
|
||||||
|
if (count > 0) {
|
||||||
|
app.stop().then(() => {
|
||||||
|
done();
|
||||||
|
}).catch((err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Minimize on Close option once the application is installed
|
||||||
|
* TC-ID: 3084609
|
||||||
|
* Cover scenarios in AVT-939
|
||||||
|
*/
|
||||||
|
it('Verify Minimize on Close option once the application is installed', async(done) => {
|
||||||
|
await Application.readConfig(app.pathApp).then(async (userConfig) => {
|
||||||
|
|
||||||
|
//When app un-ticked on Minimize On Close Menu Item
|
||||||
|
//Select 1 times to perform for ticking Menu
|
||||||
|
await wActions.openMenu(["Window","Minimize on Close"]);
|
||||||
|
|
||||||
|
if (userConfig.minimizeOnClose != false) {
|
||||||
|
//When app ticked on Minimize On Close Menu Item
|
||||||
|
//Select 2 times to perform for ticking Menu
|
||||||
|
await wActions.openMenu(["Window","Minimize on Close"]);
|
||||||
|
|
||||||
|
}
|
||||||
|
await wActions.openMenu(["Window","Close"]);
|
||||||
|
await wActions.verifyMinimizeWindows();
|
||||||
|
done();
|
||||||
|
|
||||||
|
}).catch((err) => {
|
||||||
|
done.fail(new Error(`minimize-on-close failed in readConfig with error: ${err}`));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close window when 'Minimize on Close' is ON
|
||||||
|
* TC-ID: 2911252
|
||||||
|
* Cover scenarios in AVT-937
|
||||||
|
*/
|
||||||
|
it('Close window when "Minimize on Close" is ON', async (done) => {
|
||||||
|
|
||||||
|
Application.readConfig(app.pathApp).then(async (userConfig) => {
|
||||||
|
|
||||||
|
//When app un-ticked on Minimize On Close Menu Item
|
||||||
|
//Select 1 times to perform for ticking Menu
|
||||||
|
await wActions.focusWindow();
|
||||||
|
await wActions.openMenu(["Window","Minimize on Close"]);
|
||||||
|
if (userConfig.minimizeOnClose != false) {
|
||||||
|
await wActions.openMenu(["Window","Minimize on Close"]);
|
||||||
|
}
|
||||||
|
//When app ticked on Minimize On Close Menu Item
|
||||||
|
//Select 2 times to perform for ticking Menu
|
||||||
|
|
||||||
|
await wActions.openMenu(["Window","Close"])
|
||||||
|
await wActions.verifyMinimizeWindows();
|
||||||
|
|
||||||
|
await wActions.focusWindow();
|
||||||
|
await wActions.pressCtrlW();
|
||||||
|
await wActions.verifyMinimizeWindows();
|
||||||
|
|
||||||
|
await wActions.focusWindow();
|
||||||
|
await wActions.openMenu(["Window","Close"])
|
||||||
|
await wActions.verifyMinimizeWindows();
|
||||||
|
done();
|
||||||
|
|
||||||
|
}).catch((err) => {
|
||||||
|
done.fail(new Error(`minimize-on-close failed in readConfig with error: ${err}`));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Verify by deselecting Minimize on Close option once the application is launched
|
||||||
|
* TC-ID: 3084612
|
||||||
|
* Cover scenarios in AVT-938
|
||||||
|
*/
|
||||||
|
it('Verify by deselecting Minimize on Close option once the application is launched', async (done) => {
|
||||||
|
await Application.readConfig(app.pathApp).then(async (userConfig) => {
|
||||||
|
|
||||||
|
await wActions.focusWindow();
|
||||||
|
await wActions.openMenu(["Window","Minimize on Close"]).then(async ()=>
|
||||||
|
{
|
||||||
|
if (userConfig.minimizeOnClose == false) {
|
||||||
|
//When app does not tick on Minimize On Close Menu Item
|
||||||
|
//Select 2 times to perform for un-ticking Menu
|
||||||
|
await wActions.openMenu(["Window","Minimize on Close"]);
|
||||||
|
|
||||||
|
}
|
||||||
|
await wActions.openMenu(["Window","Close"])
|
||||||
|
await wActions.verifyMinimizeWindows();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}).catch((err) => {
|
||||||
|
done.fail(new Error(`minimize-on-close failed in readConfig with error: ${err}`));
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}) : describe.skip();
|
84
tests/spectron/pop-Outs.spectron.js
Normal file
84
tests/spectron/pop-Outs.spectron.js
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
const { isMac } = require('../../js/utils/misc.js');
|
||||||
|
const constants = require('./spectronConstants.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
|
||||||
|
let app, webActions, windowsActions;
|
||||||
|
|
||||||
|
describe('Tests for Pop-Outs', () => {
|
||||||
|
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = constants.TIMEOUT_TEST_SUITE;
|
||||||
|
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
try {
|
||||||
|
app = await new Application({}).startApplication({testedHost: constants.TESTED_HOST});
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
windowsActions = await new WindowsActions(app);
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
await windowsActions.closeAllPopOutWindow();
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
await app.stop();
|
||||||
|
await webDriver.quit();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify pop-out chat, inbox
|
||||||
|
* TC-ID: 2897209
|
||||||
|
* Cover scenarios in AVT-1081
|
||||||
|
*/
|
||||||
|
it('Verify pop-out chat, inbox', async (done) => {
|
||||||
|
try {
|
||||||
|
if (isMac) {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
await webActions.login(constants.USER_A);
|
||||||
|
await windowsActions.closeAllPopOutWindow();
|
||||||
|
await windowsActions.bringToFront("Symphony");
|
||||||
|
|
||||||
|
await webActions.createIM(constants.USER_B.name);
|
||||||
|
await webActions.clickPopOutIcon();
|
||||||
|
await windowsActions.verifyPopOutWindowAppear(constants.USER_B.name);
|
||||||
|
await webActions.verifyPopInIconDisplay(constants.USER_B.name);
|
||||||
|
|
||||||
|
await webActions.clickInboxIcon();
|
||||||
|
await webActions.clickInboxPopOutIcon();
|
||||||
|
await windowsActions.verifyPopOutWindowAppear("Inbox");
|
||||||
|
await webActions.verifyPopInIconDisplay("Inbox");
|
||||||
|
|
||||||
|
await windowsActions.bringToFront("Symphony");
|
||||||
|
await webActions.clickInboxIcon();
|
||||||
|
await windowsActions.verifyWindowFocus("Inbox");
|
||||||
|
|
||||||
|
await windowsActions.bringToFront("Symphony");
|
||||||
|
await webActions.clickLeftNavItem(constants.USER_B.name);
|
||||||
|
await Utils.sleep(1); //wait for popout overlaying completely
|
||||||
|
await windowsActions.verifyWindowFocus(constants.USER_B.name);
|
||||||
|
|
||||||
|
await windowsActions.bringToFront("Symphony");
|
||||||
|
await webActions.logout();
|
||||||
|
await webActions.login(constants.USER_A);
|
||||||
|
await windowsActions.verifyPopOutWindowAppear(constants.USER_B.name);
|
||||||
|
await windowsActions.verifyPopOutWindowAppear("Inbox");
|
||||||
|
|
||||||
|
await windowsActions.closeAllPopOutWindow();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Fail to verify pop-out chat, inbox: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
@ -1,44 +1,35 @@
|
|||||||
const Application = require('./spectronSetup');
|
const Application = require('./spectronSetup');
|
||||||
const robot = require('robotjs');
|
|
||||||
const {isMac} = require('../../js/utils/misc');
|
const {isMac} = require('../../js/utils/misc');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
|
||||||
let app = new Application({});
|
let app = new Application({});
|
||||||
let defaultWidth;
|
let windowActions;
|
||||||
let defaultHeight;
|
|
||||||
|
|
||||||
!isMac ? describe('Tests for Resizing windows', () => {
|
describe('Tests for Resizing windows', () => {
|
||||||
|
|
||||||
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
|
||||||
beforeAll((done) => {
|
beforeAll(async (done) => {
|
||||||
return app.startApplication().then((startedApp) => {
|
try {
|
||||||
app = startedApp;
|
app = await new Application({}).startApplication();
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
done();
|
done();
|
||||||
}).catch((err) => {
|
} catch(err) {
|
||||||
done.fail(new Error(`Unable to start application error: ${err}`));
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
});
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll((done) => {
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
if (app && app.isRunning()) {
|
if (app && app.isRunning()) {
|
||||||
// resize to default size
|
|
||||||
app.browserWindow.getBounds().then((bounds) => {
|
|
||||||
let x = bounds.x - (defaultWidth - bounds.width);
|
|
||||||
let y = bounds.y - (defaultHeight - bounds.height);
|
|
||||||
robot.moveMouse(bounds.x, bounds.y);
|
|
||||||
robot.mouseToggle("down");
|
|
||||||
robot.dragMouse(x, y);
|
|
||||||
robot.mouseToggle("up");
|
|
||||||
})
|
|
||||||
//close app
|
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
app.stop().then(() => {
|
await app.stop();
|
||||||
done();
|
done();
|
||||||
}).catch((err) => {
|
|
||||||
done();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,24 +37,13 @@ let defaultHeight;
|
|||||||
* TC-ID: 3028239
|
* TC-ID: 3028239
|
||||||
* Cover scenarios in AVT-768
|
* Cover scenarios in AVT-768
|
||||||
*/
|
*/
|
||||||
it('should be minimized up to 300px', (done) => {
|
it('Should be minimized up to 300px', async (done) => {
|
||||||
app.browserWindow.getBounds().then((bounds) => {
|
try {
|
||||||
defaultHeight = bounds.height;
|
await windowActions.resizeWindows(0, 0);
|
||||||
defaultWidth = bounds.width;
|
expect([ 300, 300 ]).toEqual(await windowActions.getCurrentSize());
|
||||||
let x = bounds.x + bounds.width;
|
|
||||||
let y = bounds.y + bounds.height;
|
|
||||||
robot.setMouseDelay(500);
|
|
||||||
robot.moveMouse(bounds.x, bounds.y);
|
|
||||||
robot.mouseToggle("down");
|
|
||||||
robot.dragMouse(x, y);
|
|
||||||
robot.mouseToggle("up");
|
|
||||||
return app.browserWindow.getBounds().then((bounds) => {
|
|
||||||
const data = {x: bounds.width, y: bounds.height};
|
|
||||||
expect(data).toEqual({x: 300, y: 300});
|
|
||||||
done();
|
done();
|
||||||
}).catch((err) => {
|
} catch (err) {
|
||||||
done.fail(new Error(`failed to minimize window to 300 px with error: ${err}`));
|
done.fail(new Error(`failed to minimize window to 300 px with error: ${err}`));
|
||||||
})
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}) : describe.skip();
|
|
75
tests/spectron/saveLayout.spectron.js
Normal file
75
tests/spectron/saveLayout.spectron.js
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const { isMac } = require('../../js/utils/misc');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
|
||||||
|
let app;
|
||||||
|
let windowActions;
|
||||||
|
let webActions;
|
||||||
|
|
||||||
|
!isMac ? describe('Tests for saved layout', () => {
|
||||||
|
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
|
||||||
|
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
try {
|
||||||
|
app = await new Application({}).startApplication();
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
|
done();
|
||||||
|
} catch(err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
await app.stop();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep size and position of the windows in previous session
|
||||||
|
* TC-ID: 2915948
|
||||||
|
* Cover scenarios in AVT-914
|
||||||
|
*/
|
||||||
|
it('Keep size and position of the windows in previous session', async (done) => {
|
||||||
|
try {
|
||||||
|
var defaultPosition = await windowActions.getCurrentPosition();
|
||||||
|
var defaultSize = await windowActions.getCurrentSize();
|
||||||
|
|
||||||
|
// Size and position of previos session keep after resizing and dragging
|
||||||
|
await windowActions.setPosition(defaultPosition[0], 20);
|
||||||
|
await windowActions.setSize(defaultSize[0] - 100, defaultSize[0] - 100);
|
||||||
|
await Utils.sleep(1); // Sleep 1s after resizing
|
||||||
|
var previousPosition = await windowActions.getCurrentPosition();
|
||||||
|
var previousSize = await windowActions.getCurrentSize();
|
||||||
|
await app.stop();
|
||||||
|
app = await new Application({}).startApplication({defaultSize: false, defaultPosition: false});
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
expect(previousPosition).toEqual(await windowActions.getCurrentPosition());
|
||||||
|
expect(previousSize).toEqual(await windowActions.getCurrentSize());
|
||||||
|
|
||||||
|
// Size and position of previous session keep after maximizing
|
||||||
|
await webActions.maximizeWindows();
|
||||||
|
await Utils.sleep(1); // Sleep 1s after resizing
|
||||||
|
previousSize = await windowActions.getCurrentSize();
|
||||||
|
await app.stop();
|
||||||
|
app = await new Application({}).startApplication({defaultSize: false, defaultPosition: false});
|
||||||
|
windowActions = await new WindowsActions(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
expect(previousSize).toEqual(await windowActions.getCurrentSize());
|
||||||
|
done();
|
||||||
|
} catch(err) {
|
||||||
|
done.fail(new Error(`Fail to keep size and position of the windows in previous session with error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}) : describe.skip();
|
@ -7,4 +7,24 @@ module.exports = {
|
|||||||
|
|
||||||
SEARCH_LIBRARY_PATH_MAC: "node_modules/electron/dist/Electron.app/Contents/library",
|
SEARCH_LIBRARY_PATH_MAC: "node_modules/electron/dist/Electron.app/Contents/library",
|
||||||
SEARCH_LIBRARY_PATH_WIN: "node_modules/electron/dist/library",
|
SEARCH_LIBRARY_PATH_WIN: "node_modules/electron/dist/library",
|
||||||
|
MENU: {
|
||||||
|
"root": {
|
||||||
|
name: "menu", step: 0, items: [
|
||||||
|
{ name: "Edit", step: 0, items: [{ name: "Undo", step: 0 }, { name: "Redo", step: 1 }, { name: "Cut", step: 2 }, { name: "Copy", step: 3 }, { name: "Paste", step: 4 }, { name: "Paste and Match Style", step: 5 }, { name: "Delete", step: 6 }, { name: "Select All", step: 7 }] },
|
||||||
|
{ name: "View", step: 1, items: [{ name: "Reload", step: 0 }, { name: "Actual Size", step: 1 }, { name: "Zoom In", step: 2 }, { name: "Zoom Out", step: 3 }, { name: "Toogle Full Screen", step: 4 }] },
|
||||||
|
{ name: "Window", step: 2, items: [{ name: "Minimize", step: 0 }, { name: "Close", step: 1 }, { name: "Auto Launch On Startup", step: 2 }, { name: "Always on Top", step: 3 }, { name: "Minimize on Close", step: 4 }] },
|
||||||
|
{ name: "Help", step: 3, items: [{ name: "Symphony Help", step: 0 }, { name: "Learn More", step: 1 }, { name: "Troubleshooting", step: 2, items: [{ name: "Show Logs in Explorer", step: 0 }] }, { name: "About Symphony", step: 3 }] }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
LOG_FILENAME_PREFIX: "logs_symphony_",
|
||||||
|
USER_A: { username: process.env.USER_A, password: process.env.PASSWORD, name: process.env.USER_A_NAME },
|
||||||
|
USER_B: { username: process.env.USER_B, password: process.env.PASSWORD, name: process.env.USER_B_NAME },
|
||||||
|
USER_C: { username: process.env.USER_C, password: process.env.PASSWORD, name: process.env.USER_C_NAME },
|
||||||
|
TESTED_HOST: process.env.TESTED_HOST,
|
||||||
|
TYPE_ROOM: { private: "PRIVATE", public: "PUBLIC" },
|
||||||
|
TIMEOUT_TEST_SUITE: 600000,
|
||||||
|
TIMEOUT_PAGE_LOAD: 120000,
|
||||||
|
TIMEOUT_WAIT_ELEMENT: 10000
|
||||||
};
|
};
|
69
tests/spectron/spectronInterfaces.js
Normal file
69
tests/spectron/spectronInterfaces.js
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
module.exports= {
|
||||||
|
// Title bar
|
||||||
|
TITLE_BAR: "#title-bar",
|
||||||
|
MAXIMIZE_BTN: "#title-bar-maximize-button",
|
||||||
|
CLOSE_BUTTON: "button#title-bar-close-button",
|
||||||
|
MAIN_MENU_ITEM: "#hamburger-menu-button",
|
||||||
|
SYM_LOGO: "#logo",
|
||||||
|
|
||||||
|
//Sign In
|
||||||
|
SIGN_IN_BUTTON: "//button[@name='signin-submit']",
|
||||||
|
SIGN_IN_EMAIL: "//input[@name='signin-email']",
|
||||||
|
SIGN_IN_PASSWORD: "//input[@name='signin-password']",
|
||||||
|
NAV_PROFILE: "//div[@id='nav-profile']",
|
||||||
|
PLUS_BTN: "//div[@class='nav-profile__plus-btn-icon']",
|
||||||
|
IM_TAB: "//div[contains(@class,'modal-box modal-box--nfs')]//li[contains(text(),'Direct Chat')]",
|
||||||
|
CHATROOM_TAB: "//div[contains(@class, 'modal-box modal-box--nfs')]//li[contains(text(),'Chat Room')]",
|
||||||
|
CREATE_IM: "//form[@class='create-im']",
|
||||||
|
CREATE_BUTTON: "//button[text()='Create']",
|
||||||
|
ADD_PARTICIPANT_TEXT: "//div[@id='react-modal']//input[contains(@class,'react-autosuggest__input')]",
|
||||||
|
USERS_SUGGESTION_LIST: "//li[@id='react-autowhatever-1-section-0-item-0']",
|
||||||
|
CHATROOM_NAME_TEXT: "//form[@class='create-chatroom']//input[@name='name']",
|
||||||
|
CHATROOM_DESCR_TEXT: "//form[@class='create-chatroom']//input[@name='description']",
|
||||||
|
PRIVATE_ROOM_RADIO_BTN: "//form[@class='create-chatroom']//input[@value='PRIVATE']",
|
||||||
|
PUBLIC_ROOM_RADIO_BTN: "//form[@class='create-chatroom']//input[@value='PUBLIC']",
|
||||||
|
CREATE_IM_DONE_BTN: "//button[contains(@class,tempo-btn--good) and text()='Create']",
|
||||||
|
START_CHAT: "//*[contains(@class, 'sym-menu-tooltip__option')]/*[text()='Start a Chat']",
|
||||||
|
SIGNAL_OPTION: "//div[@class='sym-menu-tooltip__option']/*[text()='Create a Signal']",
|
||||||
|
LEFT_NAV_SINGLE_ITEM: "//div[contains(@class, 'navigation-item-title')]//span[@class='navigation-item-name' and normalize-space()='$$']",
|
||||||
|
CHAT_INPUT_TYPING: "//div[contains(@class,'public-DraftEditor-content')]",
|
||||||
|
SETTTING_BUTTON: "//div[@class='toolbar-settings-text-container']",
|
||||||
|
PERSIS_NOTIFICATION_INPUT_ROOM: "//div[@class='alerts-settings__notification-category']//h5[text()='Rooms:']/..//input[@class='persistent-notification']",
|
||||||
|
PERSIS_NOTIFICATION_INPUT_IM: "//div[@class='alerts-settings__notification-category']//h5[text()='IMs:']/..//input[@class='persistent-notification']",
|
||||||
|
PERSIS_NOTIFICATION_INPUT_SIGNAL: "//div[@class='alerts-settings__notification-category']//h5[text()='Signals:']/..//input[@class='persistent-notification']",
|
||||||
|
ALERT_TAB: "//*[contains(@class,'tempo-tabs__tab tabs-tab') and @data-tab='alerts']",
|
||||||
|
ALERT_OPTION: "//span[@class='sym-menu-tooltip__option-label' and contains(.,'Alerts')]",
|
||||||
|
NAV_ALIAS: "//div[@class='nav-profile__alias']",
|
||||||
|
SIGNAL_HEADER: "//span[@class='navigation-category-name' and contains(.,'Signals')]",
|
||||||
|
WARNING_CLOSE_ICON: "//div[@id='sysMsg']//span[@class='close-icon']",
|
||||||
|
SCROLL_TAB_ACTIVE: "//div[@class='active-tab-container']",
|
||||||
|
SIGNAL_NAME: "//input[@class='react-signal__name']",
|
||||||
|
HASHTAG_NAME: "//div[@class='react-signal__rule-name']//input",
|
||||||
|
LAST_RULE_ROW: "//div[@class='react-signal__rules'][last()]",
|
||||||
|
ENTER_KEYWORD_IN_LAST_INPUT: "//input",
|
||||||
|
HEADER_MODULE: "//header[contains(@class,'module-header gs-draggable')]",
|
||||||
|
MENTION_USER_SUGGESTION: "//span[@class='draftJs__suggestionsEntryText' and text()='$$']",
|
||||||
|
SUGGESTED_ENTITY_DROPDOWN: "//span[@class='draftJs__suggestionsEntryText']",
|
||||||
|
CONFIRM_CREATE_ROOM_BUTTON: "//div[@class='modal-box__footer-buttons']//button[text()='Yes']",
|
||||||
|
MODULE_ON_GRID: "#simple_grid",
|
||||||
|
SPINNER: ".spinner",
|
||||||
|
SIGNOUT: ".sign-out",
|
||||||
|
SIGNOUT_MODAL_BUTTON: "//div[@class='modal-content-buttons buttons']//button[contains(text(), 'Sign Out')]",
|
||||||
|
|
||||||
|
//Popin Popout
|
||||||
|
POPOUT_BUTTON: ".enhanced-pop-out",
|
||||||
|
POPOUT_INBOX_BUTTON: ".add-margin.popout",
|
||||||
|
POPIN_BUTTON: "//*[contains(@class, 'enhanced-pop-in') or contains(@class, 'add-margin popin')]",
|
||||||
|
PIN_CHAT_MOD: ".chat-module .pin-view",
|
||||||
|
|
||||||
|
//Alert Settings
|
||||||
|
MUTE_POPUP_ALERTS_CKB: ".field.field-notifications-on input",
|
||||||
|
|
||||||
|
//Toast Message
|
||||||
|
TOAST_MESSAGE_CONTENT: "#message",
|
||||||
|
|
||||||
|
//Inbox
|
||||||
|
INBOX_BUTTON: ".toolbar-btn-inbox",
|
||||||
|
INBOX_HEADER: ".inbox-header",
|
||||||
|
};
|
||||||
|
|
@ -4,6 +4,7 @@ const fs = require('fs');
|
|||||||
const { isMac, isWindowsOS } = require('../../js/utils/misc');
|
const { isMac, isWindowsOS } = require('../../js/utils/misc');
|
||||||
const ncp = require('ncp').ncp;
|
const ncp = require('ncp').ncp;
|
||||||
const constants = require('./spectronConstants.js');
|
const constants = require('./spectronConstants.js');
|
||||||
|
const ui = require('./spectronInterfaces.js');
|
||||||
|
|
||||||
class App {
|
class App {
|
||||||
|
|
||||||
@ -26,22 +27,34 @@ class App {
|
|||||||
App.copyLibraries(constants.SEARCH_LIBRARY_PATH_WIN);
|
App.copyLibraries(constants.SEARCH_LIBRARY_PATH_WIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.app = new Application(this.options);
|
this.app = new Application(this.options);
|
||||||
}
|
}
|
||||||
|
|
||||||
startApplication(configurations) {
|
async startApplication(configurations) {
|
||||||
return this.app.start().then((app) => {
|
try {
|
||||||
if (configurations)
|
this.app = await this.app.start();
|
||||||
{
|
await this.app.client.waitForVisible(ui.SYM_LOGO, constants.TIMEOUT_PAGE_LOAD);
|
||||||
if (configurations.alwaysOnTop) {
|
if (configurations) {
|
||||||
app.browserWindow.setAlwaysOnTop(true);
|
if (typeof configurations.alwaysOnTop !== "undefined") {
|
||||||
|
await this.app.browserWindow.setAlwaysOnTop(configurations.alwaysOnTop);
|
||||||
|
}
|
||||||
|
if (configurations.testedHost) {
|
||||||
|
await this.app.client.waitUntilWindowLoaded().url(configurations.testedHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return app;
|
|
||||||
}).catch((err) => {
|
if ((typeof configurations === "undefined") || (typeof configurations.defaultSize === "undefined") || (configurations.defaultSize === true)) {
|
||||||
|
await this.app.browserWindow.setSize(900, 900);
|
||||||
|
}
|
||||||
|
if ((typeof configurations === "undefined") || (typeof configurations.defaultPosition === "undefined") || (configurations.defaultPosition === true)) {
|
||||||
|
await this.app.browserWindow.center();
|
||||||
|
}
|
||||||
|
await this.app.browserWindow.minimize();
|
||||||
|
await this.app.browserWindow.restore();
|
||||||
|
return this.app;
|
||||||
|
} catch (err) {
|
||||||
throw new Error("Unable to start application " + err);
|
throw new Error("Unable to start application " + err);
|
||||||
});
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static getAppPath() {
|
static getAppPath() {
|
||||||
@ -53,7 +66,7 @@ class App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static getTimeOut() {
|
static getTimeOut() {
|
||||||
return 90000
|
return 90000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static readConfig(configPath) {
|
static readConfig(configPath) {
|
||||||
|
44
tests/spectron/spectronUtils.js
Normal file
44
tests/spectron/spectronUtils.js
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
const childProcess = require('child_process');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
|
class Utils {
|
||||||
|
static async openAppInMaximize(appPath) {
|
||||||
|
await childProcess.exec('start /MAX ' + appPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async killProcess(processName) {
|
||||||
|
await childProcess.exec('taskkill /f /t /im ' + processName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async sleep(second) {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
setTimeout(resolve, this.toMs(second));
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
static getFolderPath(folderName) {
|
||||||
|
return path.join(require('os').homedir(), folderName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getFiles(path) {
|
||||||
|
return fs.readdirSync(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static toMs(second) {
|
||||||
|
return second * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
static async randomString() {
|
||||||
|
var chars = await "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz";
|
||||||
|
var string_length = await 8;
|
||||||
|
var randomstring = await '';
|
||||||
|
for (var i = 0; i < string_length; i++) {
|
||||||
|
var rnum = await Math.floor(Math.random() * chars.length);
|
||||||
|
randomstring += await chars.substring(rnum, rnum + 1);
|
||||||
|
}
|
||||||
|
return randomstring;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Utils;
|
279
tests/spectron/spectronWebActions.js
Normal file
279
tests/spectron/spectronWebActions.js
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
const ui = require('./spectronInterfaces.js');
|
||||||
|
const constants = require('./spectronConstants.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
|
||||||
|
class WebActions {
|
||||||
|
constructor(app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
async maximizeButtonByClick() {
|
||||||
|
await this.app.client.waitForVisible(ui.MAXIMIZE_BTN, constants.TIMEOUT_WAIT_ELEMENT).click(ui.MAXIMIZE_BTN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async maximizeWindows() {
|
||||||
|
await this.maximizeButtonByClick();
|
||||||
|
await this.app.browserWindow.isMaximized().then(function (maximized) {
|
||||||
|
expect(maximized).toBeTruthy();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickMinimizeButton() {
|
||||||
|
await this.app.client.waitForVisible(ui.MINIMIZE_BTN, 10000).click(ui.MINIMIZE_BTN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async minimizeWindows() {
|
||||||
|
await this.clickMinimizeButton();
|
||||||
|
await this.app.browserWindow.isMinimized().then(function (isMinimized) {
|
||||||
|
expect(isMinimized).toBeTruthy();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async minimizeWindowByClick() {
|
||||||
|
await this.app.client.click(ui.MINIMIZED_BUTTON);
|
||||||
|
}
|
||||||
|
|
||||||
|
async closeWindowByClick() {
|
||||||
|
await this.app.client.click(ui.CLOSE_BUTTON);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async openApplicationMenuByClick() {
|
||||||
|
await this.app.client.click(ui.MAIN_MENU_ITEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getElementByXPath(xpath) {
|
||||||
|
await this.app.client.waitForVisible(xpath, constants.TIMEOUT_WAIT_ELEMENT);
|
||||||
|
var elem = this.app.client.element(xpath);
|
||||||
|
if (elem.isVisible()) {
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
async inputText(el, data) {
|
||||||
|
var obj = await this.getElementByXPath(el);
|
||||||
|
if (obj != null)
|
||||||
|
await this.app.client.setValue(el, data);
|
||||||
|
}
|
||||||
|
async clickAndWaitElementVisible(xpath, elementToVisible, timeOut = constants.TIMEOUT_WAIT_ELEMENT) {
|
||||||
|
await this.app.client.click(xpath).then(async () => {
|
||||||
|
await this.app.client.waitForVisible(elementToVisible, timeOut);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async scrollAndClick(selector, findElement) {
|
||||||
|
var i = 0;
|
||||||
|
var y = 0;
|
||||||
|
await this.app.client.scroll(selector, 0, y);
|
||||||
|
var size = 0;
|
||||||
|
while (i < 10) {
|
||||||
|
size = this.app.client.getElementSize(findElement);
|
||||||
|
if (findElement != null && size == 0) {
|
||||||
|
y += 50;
|
||||||
|
await this.app.client.scroll(selector, 0, y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
await this.app.client.click(findElement);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
async promiseTimeout(ms, promiseFunc) {
|
||||||
|
return new Promise(function (resolve, reject) {
|
||||||
|
// create a timeout to reject promise if not resolved
|
||||||
|
var timer = setTimeout(function () {
|
||||||
|
reject(new Error("promise timeout"));
|
||||||
|
}, ms);
|
||||||
|
promiseFunc
|
||||||
|
.then(function (res) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
resolve(res);
|
||||||
|
})
|
||||||
|
.catch(function (err) {
|
||||||
|
clearTimeout(timer);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
async clickIfElementVisible(selector, timeOut = constants.TIMEOUT_WAIT_ELEMENT) {
|
||||||
|
await this.app.client.waitForVisible(selector, timeOut)
|
||||||
|
.click(selector)
|
||||||
|
}
|
||||||
|
|
||||||
|
async openAlertsSettings() {
|
||||||
|
await this.clickAndWaitElementVisible(ui.SETTTING_BUTTON, ui.ALERT_OPTION);
|
||||||
|
await this.clickAndWaitElementVisible(ui.ALERT_OPTION, ui.ALERT_TAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyToastNotificationShow(message) {
|
||||||
|
let show = false;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
let winCount = await this.app.client.getWindowCount();
|
||||||
|
if (winCount > 1) {
|
||||||
|
for (let j = 1; j < winCount; j++) {
|
||||||
|
await this.app.client.windowByIndex(j);
|
||||||
|
if (await this.app.client.getText(ui.TOAST_MESSAGE_CONTENT) === message) {
|
||||||
|
show = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (show) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Utils.sleep(1);
|
||||||
|
}
|
||||||
|
await expect(show).toBeTruthy();
|
||||||
|
await this.app.client.windowByIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyNoToastNotificationShow(message) {
|
||||||
|
let noShow;
|
||||||
|
for (let i = 0; i < 10; i++) {
|
||||||
|
let winCount = await this.app.client.getWindowCount();
|
||||||
|
if (winCount > 1) {
|
||||||
|
for (let j = 1; j < winCount; j++) {
|
||||||
|
await this.app.client.windowByIndex(j);
|
||||||
|
if (await this.app.client.getText(ui.TOAST_MESSAGE_CONTENT) !== message) {
|
||||||
|
noShow = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
noShow = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (noShow === false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await Utils.sleep(1);
|
||||||
|
}
|
||||||
|
await expect(noShow).toBeTruthy();
|
||||||
|
await this.app.client.windowByIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getElementByXPath(xpath) {
|
||||||
|
let elem = this.app.client.element(xpath);
|
||||||
|
if (elem.isVisible()) {
|
||||||
|
return elem;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async inputText(el, data) {
|
||||||
|
let obj = await this.getElementByXPath(el);
|
||||||
|
if (obj != null)
|
||||||
|
await this.app.client.setValue(el, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickAndWaitElementVisible(xpath, elementToVisible, timeOut = constants.TIMEOUT_WAIT_ELEMENT) {
|
||||||
|
await this.app.client.click(xpath);
|
||||||
|
await this.app.client.waitForVisible(elementToVisible, timeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickIfElementVisible(xpath, timeOut = constants.TIMEOUT_WAIT_ELEMENT) {
|
||||||
|
await this.app.client.waitForVisible(xpath, timeOut)
|
||||||
|
.click(xpath)
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(user) {
|
||||||
|
await this.inputText(ui.SIGN_IN_EMAIL, user.username);
|
||||||
|
await this.inputText(ui.SIGN_IN_PASSWORD, user.password);
|
||||||
|
await this.clickAndWaitElementVisible(ui.SIGN_IN_BUTTON, ui.SETTTING_BUTTON, constants.TIMEOUT_PAGE_LOAD);
|
||||||
|
await this.waitElementNotVisible(ui.SPINNER);
|
||||||
|
}
|
||||||
|
|
||||||
|
async persistToastIM() {
|
||||||
|
await this.clickAndWaitElementVisible(ui.SETTTING_BUTTON, ui.ALERT_OPTION);
|
||||||
|
await this.clickAndWaitElementVisible(ui.ALERT_OPTION, ui.ALERT_TAB);
|
||||||
|
await this.clickAndWaitElementVisible(ui.PERSIS_NOTIFICATION_INPUT_IM, ui.PERSIS_NOTIFICATION_INPUT_IM);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickPlusButton() {
|
||||||
|
await this.clickIfElementVisible(ui.PLUS_BTN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickStartChat() {
|
||||||
|
await this.clickIfElementVisible(ui.START_CHAT);
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectIMTab() {
|
||||||
|
await this.clickIfElementVisible(ui.IM_TAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
async addParticipant(username) {
|
||||||
|
await this.inputText(ui.ADD_PARTICIPANT_TEXT, username);
|
||||||
|
await this.clickIfElementVisible(ui.USERS_SUGGESTION_LIST, 20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickDoneButton() {
|
||||||
|
await this.clickIfElementVisible(ui.CREATE_IM_DONE_BTN);
|
||||||
|
await this.waitElementVisible(ui.HEADER_MODULE);
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitElementNotVisible(locator, timeOut = constants.TIMEOUT_WAIT_ELEMENT) {
|
||||||
|
return await this.app.client.waitForVisible(locator, timeOut, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitElementVisible(locator, timeOut = constants.TIMEOUT_WAIT_ELEMENT) {
|
||||||
|
return await this.app.client.waitForVisible(locator, timeOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
async mouseOver(locator) {
|
||||||
|
await this.app.client.moveToObject(locator);
|
||||||
|
}
|
||||||
|
|
||||||
|
async createIM(username) {
|
||||||
|
await this.clickPlusButton();
|
||||||
|
await this.clickStartChat();
|
||||||
|
await this.selectIMTab();
|
||||||
|
await this.addParticipant(username);
|
||||||
|
await this.clickDoneButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickPopOutIcon() {
|
||||||
|
let windowsActions = await new WindowsActions(this.app);
|
||||||
|
await this.mouseOver(ui.PIN_CHAT_MOD);
|
||||||
|
await Utils.sleep(2); //wait popout button clickable
|
||||||
|
await this.clickIfElementVisible(ui.POPOUT_BUTTON);
|
||||||
|
let index = await windowsActions.getWindowCount() - 1;
|
||||||
|
await windowsActions.windowByIndex(index);
|
||||||
|
await this.waitElementNotVisible(ui.SPINNER, constants.TIMEOUT_PAGE_LOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickInboxPopOutIcon() {
|
||||||
|
let windowsActions = await new WindowsActions(this.app);
|
||||||
|
await this.clickIfElementVisible(ui.POPOUT_INBOX_BUTTON);
|
||||||
|
let index = await windowsActions.getWindowCount() - 1;
|
||||||
|
await windowsActions.windowByIndex(index);
|
||||||
|
await this.waitElementNotVisible(ui.SPINNER, constants.TIMEOUT_PAGE_LOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyPopInIconDisplay(windowTitle){
|
||||||
|
let windowsActions = await new WindowsActions(this.app);
|
||||||
|
let index = await windowsActions.getWindowIndexFromTitle(windowTitle);
|
||||||
|
await windowsActions.windowByIndex(index);
|
||||||
|
await this.waitElementVisible(ui.POPIN_BUTTON, constants.TIMEOUT_WAIT_ELEMENT);
|
||||||
|
await windowsActions.windowByIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickInboxIcon() {
|
||||||
|
await this.clickIfElementVisible(ui.INBOX_BUTTON);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickLeftNavItem(item){
|
||||||
|
let singleItemLocator = ui.LEFT_NAV_SINGLE_ITEM.replace("$$",item);
|
||||||
|
await this.clickIfElementVisible(singleItemLocator);
|
||||||
|
}
|
||||||
|
|
||||||
|
async logout(){
|
||||||
|
await this.openAlertsSettings();
|
||||||
|
await this.clickAndWaitElementVisible(ui.SIGNOUT, ui.SIGNOUT_MODAL_BUTTON);
|
||||||
|
await this.clickAndWaitElementVisible(ui.SIGNOUT_MODAL_BUTTON, ui.SIGN_IN_BUTTON, constants.TIMEOUT_PAGE_LOAD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = WebActions;
|
279
tests/spectron/spectronWebDriver.js
Normal file
279
tests/spectron/spectronWebDriver.js
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
const { Builder, By, Key, until } = require('selenium-webdriver')
|
||||||
|
require('selenium-webdriver/chrome');
|
||||||
|
require('chromedriver');
|
||||||
|
var assert = require('assert');
|
||||||
|
const ui = require('./spectronInterfaces.js');
|
||||||
|
const specconst = require('./spectronConstants.js');
|
||||||
|
|
||||||
|
class WebDriver {
|
||||||
|
constructor(options) {
|
||||||
|
this.options = options;
|
||||||
|
this.d = new Builder().forBrowser(options.browser).build();
|
||||||
|
this.initDriver();
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitElelmentIsNotVisible(xpath) {
|
||||||
|
let result = false;
|
||||||
|
try {
|
||||||
|
const el = await this.driver.wait(
|
||||||
|
until.elementLocated(By.xpath(xpath)),
|
||||||
|
specconst.TIMEOUT_WAIT_ELEMENT
|
||||||
|
)
|
||||||
|
await this.driver.wait(until.elementIsNotVisible(el), specconst.TIMEOUT_WAIT_ELEMENT);
|
||||||
|
if (this.driver.findElements(By.xpath(xpath)).length > 0) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
result = false;
|
||||||
|
}
|
||||||
|
return await assert.equal(result, false);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
await assert.equal(result, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitElelmentIsVisible(xpath,timeout) {
|
||||||
|
try {
|
||||||
|
const el = await this.driver.wait(
|
||||||
|
until.elementLocated(By.xpath(xpath)),
|
||||||
|
specconst.TIMEOUT_WAIT_ELEMENT
|
||||||
|
)
|
||||||
|
await this.driver.wait(until.elementIsVisible(el), timeout);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log("Error:"+err.messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitElementVisibleAndGet(xpath) {
|
||||||
|
const el = await this.driver.wait(
|
||||||
|
until.elementLocated(By.xpath(xpath)),
|
||||||
|
specconst.TIMEOUT_WAIT_ELEMENT
|
||||||
|
)
|
||||||
|
return await this.driver.wait(until.elementIsVisible(el), specconst.TIMEOUT_WAIT_ELEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getElementById(id) {
|
||||||
|
const el = await this.driver.wait(until.elementLocated(By.id(id)), specconst.TIMEOUT_WAIT_ELEMENT)
|
||||||
|
return await this.driver.wait(until.elementIsVisible(el), specconst.TIMEOUT_WAIT_ELEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
async getElementByXPath(xpath) {
|
||||||
|
const el = await this.driver.wait(
|
||||||
|
until.elementLocated(By.xpath(xpath)),
|
||||||
|
specconst.TIMEOUT_WAIT_ELEMENT
|
||||||
|
)
|
||||||
|
return await this.driver.wait(until.elementIsVisible(el), specconst.TIMEOUT_WAIT_ELEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
async inputText(el, data) {
|
||||||
|
var obj = await this.getElementByXPath(el);
|
||||||
|
await obj.sendKeys(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendEnter(el) {
|
||||||
|
var obj = await this.getElementByXPath(el);
|
||||||
|
await obj.sendKeys(Key.ENTER);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessage(message) {
|
||||||
|
await this.inputText(ui.CHAT_INPUT_TYPING, message);
|
||||||
|
await this.sendEnter(ui.CHAT_INPUT_TYPING);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sendMessages(messages) {
|
||||||
|
for (var i = 0; i < messages.length; i++) {
|
||||||
|
await this.sendMessage(messages[i]);
|
||||||
|
await this.sleep(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async login(user) {
|
||||||
|
await this.inputText(ui.SIGN_IN_EMAIL, user.username);
|
||||||
|
await this.inputText(ui.SIGN_IN_PASSWORD, user.password);
|
||||||
|
var singin = await this.getElementByXPath(ui.SIGN_IN_BUTTON);
|
||||||
|
await singin.click();
|
||||||
|
await this.waitElelmentIsVisible(ui.SETTTING_BUTTON,specconst.TIMEOUT_PAGE_LOAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
async mentionUserOnChat(user)
|
||||||
|
{
|
||||||
|
await this.inputText(ui.CHAT_INPUT_TYPING, "@"+user.name);
|
||||||
|
var suggestion = ui.MENTION_USER_SUGGESTION.replace("$$",user.name);
|
||||||
|
var el = await this.getElementByXPath(suggestion);
|
||||||
|
await el.click();
|
||||||
|
await this.sendEnter(ui.CHAT_INPUT_TYPING);
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitSuggestionShowOnlyOneItem(xpath)
|
||||||
|
{
|
||||||
|
if (this.driver.findElements(By.xpath(xpath)).length==1) {
|
||||||
|
return result = true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickShowConversationCreationModal() {
|
||||||
|
var plusButton = await this.getElementByXPath(ui.PLUS_BTN);
|
||||||
|
await plusButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectIMTab() {
|
||||||
|
var imTab = await this.getElementByXPath(ui.IM_TAB);
|
||||||
|
await imTab.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectRoomTab() {
|
||||||
|
var roomTab = await this.getElementByXPath(ui.CHATROOM_TAB);
|
||||||
|
await roomTab.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async addParticipant(username) {
|
||||||
|
await this.inputText(ui.ADD_PARTICIPANT_TEXT, username);
|
||||||
|
await this.sleep(5);
|
||||||
|
var el = await this.waitElementVisibleAndGet(ui.USERS_SUGGESTION_LIST);
|
||||||
|
await el.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickDoneButton() {
|
||||||
|
var el = await this.getElementByXPath(ui.CREATE_IM_DONE_BTN);
|
||||||
|
await el.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickDoneButton() {
|
||||||
|
var el = await this.getElementByXPath(ui.CREATE_IM_DONE_BTN);
|
||||||
|
await el.click();
|
||||||
|
await this.waitElelmentIsNotVisible(ui.CREATE_IM_DONE_BTN);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickConfirmCreateRoom() {
|
||||||
|
var el = await this.getElementByXPath(ui.CONFIRM_CREATE_ROOM_BUTTON);
|
||||||
|
await el.click();
|
||||||
|
await this.waitElelmentIsNotVisible(ui.CONFIRM_CREATE_ROOM_BUTTON);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickStartChat() {
|
||||||
|
var el = await this.getElementByXPath(ui.START_CHAT);
|
||||||
|
await el.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async createIM(username) {
|
||||||
|
await this.clickShowConversationCreationModal();
|
||||||
|
await this.clickStartChat();
|
||||||
|
await this.selectIMTab();
|
||||||
|
await this.addParticipant(username);
|
||||||
|
await this.clickDoneButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
async createMIM(usernames) {
|
||||||
|
await this.clickShowConversationCreationModal();
|
||||||
|
await this.clickStartChat();
|
||||||
|
await this.selectIMTab();
|
||||||
|
for (var i = 0; i < usernames.length; i++) {
|
||||||
|
await this.addParticipant(usernames[i]);
|
||||||
|
}
|
||||||
|
await this.clickDoneButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickCreateSignal() {
|
||||||
|
var el = await this.getElementByXPath(ui.SIGNAL_OPTION);
|
||||||
|
await el.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectPublicRadioButton() {
|
||||||
|
var el = await this.waitElementVisibleAndGet(ui.PUBLIC_ROOM_RADIO_BTN);
|
||||||
|
await el.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectPrivateRadioButton() {
|
||||||
|
var el = await this.waitElementVisibleAndGet(ui.PRIVATE_ROOM_RADIO_BTN);
|
||||||
|
await el.click();
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickLeftNavItem(name) {
|
||||||
|
var xpath = await ui.LEFT_NAV_SINGLE_ITEM.replace("$$", name);
|
||||||
|
var el = await this.getElementByXPath(xpath);
|
||||||
|
await el.click();
|
||||||
|
var eheader = await this.getElementByXPath(ui.HEADER_MODULE);
|
||||||
|
await this.driver.wait(until.elementIsVisible(eheader), specconst.TIMEOUT_WAIT_ELEMENT)
|
||||||
|
}
|
||||||
|
|
||||||
|
async createRoom(usernames, name, description, type) {
|
||||||
|
await this.clickShowConversationCreationModal();
|
||||||
|
await this.clickStartChat();
|
||||||
|
await this.selectRoomTab();
|
||||||
|
await this.inputText(ui.CHATROOM_NAME_TEXT, name);
|
||||||
|
await this.inputText(ui.CHATROOM_DESCR_TEXT, description);
|
||||||
|
if (type === specconst.TYPE_ROOM.private) {
|
||||||
|
await this.selectPrivateRadioButton();
|
||||||
|
}
|
||||||
|
if (type === specconst.TYPE_ROOM.public) {
|
||||||
|
await this.selectPublicRadioButton();
|
||||||
|
}
|
||||||
|
for (var i = 0; i < usernames.length; i++) {
|
||||||
|
await this.addParticipant(usernames[i]);
|
||||||
|
}
|
||||||
|
await this.clickDoneButton();
|
||||||
|
// await this.clickConfirmCreateRoom();
|
||||||
|
}
|
||||||
|
|
||||||
|
async createSignal(signalName, hashTag)
|
||||||
|
{
|
||||||
|
await this.clickShowConversationCreationModal();
|
||||||
|
await this.clickCreateSignal();
|
||||||
|
await this.inputText(ui.SIGNAL_NAME,signalName);
|
||||||
|
await this.inputText(ui.LAST_RULE_ROW+ui.ENTER_KEYWORD_IN_LAST_INPUT,hashTag);
|
||||||
|
await this.clickDoneButton();
|
||||||
|
}
|
||||||
|
|
||||||
|
async initDriver() {
|
||||||
|
return this.d.then(_d => {
|
||||||
|
this.driver = _d
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async startDriver() {
|
||||||
|
await this.driver
|
||||||
|
.manage()
|
||||||
|
.window()
|
||||||
|
.setPosition(0, 0);
|
||||||
|
var size = await await this.driver
|
||||||
|
.manage()
|
||||||
|
.window().getSize();
|
||||||
|
await this.driver.get(specconst.TESTED_HOST);
|
||||||
|
}
|
||||||
|
|
||||||
|
async focusCurrentBrowser() {
|
||||||
|
this.driver.switchTo().window(this.driver.getAllWindowHandles()[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
async sleep(secondSleep) {
|
||||||
|
await this.driver.sleep(secondSleep * 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
async timeOut(secondSleep) {
|
||||||
|
return secondSleep * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
async waitElelmentIsVisible(xpath,timeout) {
|
||||||
|
try {
|
||||||
|
const el = await this.driver.wait(
|
||||||
|
until.elementLocated(By.xpath(xpath)),
|
||||||
|
specconst.TIMEOUT_WAIT_ELEMENT
|
||||||
|
)
|
||||||
|
await this.driver.wait(until.elementIsVisible(el), timeout);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
console.log("Error:"+err.messages);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async quit() {
|
||||||
|
await this.driver.quit();
|
||||||
|
}
|
||||||
|
async close() {
|
||||||
|
await this.driver.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
module.exports = WebDriver;
|
428
tests/spectron/spectronWindowsActions.js
Normal file
428
tests/spectron/spectronWindowsActions.js
Normal file
@ -0,0 +1,428 @@
|
|||||||
|
const robot = require('robotjs');
|
||||||
|
const constants = require('./spectronConstants.js');
|
||||||
|
const Utils = require('./spectronUtils.js');
|
||||||
|
const fs = require('fs');
|
||||||
|
const WebActions = require('./spectronWebActions.js')
|
||||||
|
|
||||||
|
class WindowsActions {
|
||||||
|
constructor(app) {
|
||||||
|
this.app = app;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentSize() {
|
||||||
|
return this.app.browserWindow.getSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
async setSize(width, height) {
|
||||||
|
await this.app.browserWindow.setSize(width, height);
|
||||||
|
}
|
||||||
|
|
||||||
|
async resizeWindows(width, height) {
|
||||||
|
await this.app.browserWindow.getBounds().then((bounds) => {
|
||||||
|
let x = bounds.x + (bounds.width - width);
|
||||||
|
let y = bounds.y + (bounds.height - height);
|
||||||
|
robot.setMouseDelay(500);
|
||||||
|
// Plus 2 pixels to make sure this function works well on MAC
|
||||||
|
robot.moveMouse(bounds.x + 2, bounds.y + 2);
|
||||||
|
robot.mouseToggle("down");
|
||||||
|
robot.dragMouse(x, y);
|
||||||
|
robot.mouseToggle("up");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async getCurrentPosition() {
|
||||||
|
return this.app.browserWindow.getPosition();
|
||||||
|
}
|
||||||
|
|
||||||
|
async setPosition(x, y) {
|
||||||
|
await this.app.browserWindow.setPosition(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
async dragWindows(x, y) {
|
||||||
|
await this.app.browserWindow.getBounds().then((bounds) => {
|
||||||
|
robot.setMouseDelay(500);
|
||||||
|
robot.moveMouse(bounds.x + 200, bounds.y + 10);
|
||||||
|
robot.mouseToggle("down");
|
||||||
|
robot.moveMouse(bounds.x + 205, bounds.y + 10); // Workaround to make this keyword works properly, refer: https://github.com/octalmage/robotjs/issues/389
|
||||||
|
robot.dragMouse(x + 205, y + 10);
|
||||||
|
robot.mouseToggle("up");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async showWindow() {
|
||||||
|
await this.app.browserWindow.restore();
|
||||||
|
await this.app.browserWindow.setAlwaysOnTop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickOutsideWindow() {
|
||||||
|
await this.setPosition(0, 0);
|
||||||
|
let currentSize = await this.getCurrentSize();
|
||||||
|
await robot.moveMouse(currentSize[0] + 20, currentSize[1] + 20);
|
||||||
|
await robot.mouseClick();
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyWindowsOnTop() {
|
||||||
|
await this.app.browserWindow.isAlwaysOnTop().then(function (isAlwaysOnTop) {
|
||||||
|
expect(isAlwaysOnTop).toBeTruthy();
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async menuSearch(element, namevalue) {
|
||||||
|
if (element.name == namevalue) {
|
||||||
|
return await element;
|
||||||
|
}
|
||||||
|
else if (element.items !== undefined) {
|
||||||
|
var result;
|
||||||
|
for (var i = 0; result == null && i < element.items.length; i++) {
|
||||||
|
result = await this.menuSearch(element.items[i], namevalue);
|
||||||
|
result;
|
||||||
|
}
|
||||||
|
return await result;
|
||||||
|
}
|
||||||
|
return await null;
|
||||||
|
}
|
||||||
|
|
||||||
|
async openMenu(arrMenu) {
|
||||||
|
var arrStep = [];
|
||||||
|
for (var i = 0; i < arrMenu.length; i++) {
|
||||||
|
var item = await this.menuSearch(constants.MENU.root, arrMenu[i]);
|
||||||
|
await arrStep.push(item);
|
||||||
|
}
|
||||||
|
await this.actionForMenus(arrStep);
|
||||||
|
return arrStep;
|
||||||
|
}
|
||||||
|
|
||||||
|
async actionForMenus(arrMenu) {
|
||||||
|
let webAction = await new WebActions(this.app);
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(100);
|
||||||
|
let x = bounds.x + 95;
|
||||||
|
let y = bounds.y + 35;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
await robot.mouseClick();
|
||||||
|
await webAction.openApplicationMenuByClick();
|
||||||
|
await robot.setKeyboardDelay(200);
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
for (var i = 0; i < arrMenu.length; i++) {
|
||||||
|
for (var s = 0; s < arrMenu[i].step; s++) {
|
||||||
|
await robot.keyTap('down');
|
||||||
|
}
|
||||||
|
if (arrMenu.length > 1 && i != arrMenu.length - 1) {
|
||||||
|
//handle right keygen
|
||||||
|
await robot.keyTap('right');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyLogExported() {
|
||||||
|
let expected = false;
|
||||||
|
let path = await Utils.getFolderPath('Downloads');
|
||||||
|
let listFiles = Utils.getFiles(path);
|
||||||
|
listFiles.forEach(function (fileName) {
|
||||||
|
if (fileName.indexOf(constants.LOG_FILENAME_PREFIX) > -1) {
|
||||||
|
expected = true;
|
||||||
|
}
|
||||||
|
})
|
||||||
|
await expect(expected).toBeTruthy();
|
||||||
|
}
|
||||||
|
|
||||||
|
async deleteAllLogFiles() {
|
||||||
|
let path = await Utils.getFolderPath('Downloads');
|
||||||
|
let listFiles = Utils.getFiles(path);
|
||||||
|
await listFiles.forEach(function (fileName) {
|
||||||
|
if (fileName.indexOf(constants.LOG_FILENAME_PREFIX) > -1) {
|
||||||
|
fs.unlinkSync(path.concat("\\", fileName));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyMinimizeWindows() {
|
||||||
|
await this.app.browserWindow.isMinimized().then(async function (minimized) {
|
||||||
|
await expect(minimized).toBeTruthy();
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log(err.name);
|
||||||
|
});;
|
||||||
|
}
|
||||||
|
|
||||||
|
async isMinimizedWindows() {
|
||||||
|
let rminimized = -1;
|
||||||
|
|
||||||
|
await this.app.browserWindow.isMinimized().then(async function (minimized) {
|
||||||
|
rminimized = constants.MINIMIZED;
|
||||||
|
}).catch((err) => {
|
||||||
|
rminimized = constants.QUIT;
|
||||||
|
return rminimized;
|
||||||
|
});
|
||||||
|
|
||||||
|
return rminimized;
|
||||||
|
}
|
||||||
|
|
||||||
|
async selectMinimizeOnClose() {
|
||||||
|
let webAction = await new WebActions(this.app);
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(100);
|
||||||
|
let x = bounds.x + 95;
|
||||||
|
let y = bounds.y + 35;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
await robot.mouseClick();
|
||||||
|
await webAction.openApplicationMenuByClick();
|
||||||
|
await robot.setKeyboardDelay(1000);
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
await robot.keyTap('down');
|
||||||
|
await robot.keyTap('down');
|
||||||
|
await robot.keyTap('right');
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
await robot.keyTap('down');
|
||||||
|
}
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async quitApp() {
|
||||||
|
let webAction = await new WebActions(this.app);
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(100);
|
||||||
|
let x = bounds.x + 95;
|
||||||
|
let y = bounds.y + 35;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
await robot.mouseClick();
|
||||||
|
await webAction.openApplicationMenuByClick();
|
||||||
|
await robot.setKeyboardDelay(1000);
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
await robot.keyTap('down');
|
||||||
|
await robot.keyTap('down');
|
||||||
|
await robot.keyTap('right');
|
||||||
|
for (let i = 0; i < 6; i++) {
|
||||||
|
await robot.keyTap('down');
|
||||||
|
}
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async pressCtrlW() {
|
||||||
|
await robot.keyToggle('w', 'down', ['control']);
|
||||||
|
await robot.keyToggle('w', 'up', ['control']);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyMinimizeWindows() {
|
||||||
|
await this.app.browserWindow.isMinimized().then(async function (minimized) {
|
||||||
|
await expect(minimized).toBeTruthy();
|
||||||
|
}).catch((err) => {
|
||||||
|
console.log("error:" + err.name);
|
||||||
|
});;
|
||||||
|
}
|
||||||
|
|
||||||
|
async isMinimizedWindows() {
|
||||||
|
let rminimized = -1;
|
||||||
|
|
||||||
|
await this.app.browserWindow.isMinimized().then(async function (minimized) {
|
||||||
|
rminimized = constants.MINIMIZED;
|
||||||
|
}).catch((err) => {
|
||||||
|
rminimized = constants.QUIT;
|
||||||
|
return rminimized;
|
||||||
|
});
|
||||||
|
|
||||||
|
return rminimized;
|
||||||
|
}
|
||||||
|
|
||||||
|
async pressCtrlM() {
|
||||||
|
await robot.keyToggle('m', 'down', ['control']);
|
||||||
|
await robot.keyToggle('m', 'up', ['control']);
|
||||||
|
}
|
||||||
|
|
||||||
|
async pressCtrlR() {
|
||||||
|
await robot.keyToggle('r', 'down', ['control']);
|
||||||
|
await robot.keyToggle('r', 'up', ['control']);
|
||||||
|
}
|
||||||
|
|
||||||
|
async focusWindow() {
|
||||||
|
this.app.browserWindow.focus();
|
||||||
|
this.app.browserWindow.setAlwaysOnTop(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
async reload() {
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(100);
|
||||||
|
let x = bounds.x + 95;
|
||||||
|
let y = bounds.y + 200;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
await robot.mouseClick('right');
|
||||||
|
await robot.setKeyboardDelay(2000);
|
||||||
|
await robot.keyTap('right');
|
||||||
|
await robot.keyTap('down');
|
||||||
|
await robot.keyTap('enter');
|
||||||
|
}).catch((err1) => {
|
||||||
|
console.log("Message:" + err1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async clickNotification() {
|
||||||
|
let screen = await this.app.electron.screen.getAllDisplays();
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(50);
|
||||||
|
let x = screen[0].bounds.width - 50;
|
||||||
|
let y = screen[0].bounds.height - 100;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
await robot.mouseClick();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async mouseMoveNotification() {
|
||||||
|
let screen = await this.app.electron.screen.getAllDisplays();
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(50);
|
||||||
|
let x = screen[0].bounds.width - 50;
|
||||||
|
let y = screen[0].bounds.height - 100;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async mouseMoveCenter() {
|
||||||
|
let screen = await this.app.electron.screen.getAllDisplays();
|
||||||
|
await this.app.browserWindow.getBounds().then(async (bounds) => {
|
||||||
|
await robot.setMouseDelay(50);
|
||||||
|
let x = screen[0].bounds.width - 500;
|
||||||
|
let y = screen[0].bounds.height - 100;
|
||||||
|
await robot.moveMouseSmooth(x, y);
|
||||||
|
await robot.moveMouse(x, y);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async veriryPersistToastNotification(message) {
|
||||||
|
let i = 0;
|
||||||
|
while (i < 6) {
|
||||||
|
await Utils.sleep(1);
|
||||||
|
await i++;
|
||||||
|
}
|
||||||
|
await this.webAction.verifyToastNotificationShow(message);
|
||||||
|
await this.clickNotification();
|
||||||
|
await this.mouseMoveCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyNotPersistToastNotification(message) {
|
||||||
|
let i = 0;
|
||||||
|
let count = 0;
|
||||||
|
|
||||||
|
while (i < 11) {
|
||||||
|
await Utils.sleep(1);
|
||||||
|
await i++;
|
||||||
|
}
|
||||||
|
await this.webAction.verifyNoToastNotificationShow(message);
|
||||||
|
await this.mouseMoveCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyNotCloseToastWhenMouseOver(message) {
|
||||||
|
await this.mouseMoveNotification();
|
||||||
|
let i = 0;
|
||||||
|
while (i < 8) {
|
||||||
|
await Utils.sleep(1);
|
||||||
|
await i++;
|
||||||
|
}
|
||||||
|
await this.webAction.verifyToastNotificationShow(message);
|
||||||
|
await this.mouseMoveCenter();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBadgeCount() {
|
||||||
|
let count = await this.app.electron.remote.app.getBadgeCount();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
async resetBadgeCount() {
|
||||||
|
await this.app.electron.remote.app.setBadgeCount(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getBadgeCount() {
|
||||||
|
let count = await this.app.electron.remote.app.getBadgeCount();
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyCurrentBadgeCount(number) {
|
||||||
|
let expected = false;
|
||||||
|
let i = 0;
|
||||||
|
let count = await this.getBadgeCount();
|
||||||
|
while (i < 5) {
|
||||||
|
if (count == number) {
|
||||||
|
expected = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await Utils.sleep(1);
|
||||||
|
count = await this.getBadgeCount();
|
||||||
|
await i++;
|
||||||
|
}
|
||||||
|
await expect(expected).toBeTruthy();
|
||||||
|
}
|
||||||
|
|
||||||
|
async getWindowIndexFromTitle(windowTitle) {
|
||||||
|
let winCount = await this.getWindowCount();
|
||||||
|
if (winCount > 1) {
|
||||||
|
for (let j = 1; j < winCount; j++) {
|
||||||
|
await this.windowByIndex(j);
|
||||||
|
|
||||||
|
//wait 120s for title loading
|
||||||
|
let title = await this.app.browserWindow.getTitle();
|
||||||
|
for (let i = 1; i <= 120; i++) {
|
||||||
|
if (title != "Symphony") {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
await Utils.sleep(1);
|
||||||
|
title = await this.app.browserWindow.getTitle();;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (title === windowTitle) {
|
||||||
|
await this.windowByIndex(0);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await this.windowByIndex(0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
async windowByIndex(index) {
|
||||||
|
await this.app.client.windowByIndex(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
async getWindowCount() {
|
||||||
|
return await this.app.client.getWindowCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
async bringToFront(windowTitle) {
|
||||||
|
let index = await this.getWindowIndexFromTitle(windowTitle);
|
||||||
|
await this.windowByIndex(index);
|
||||||
|
await this.app.browserWindow.minimize();
|
||||||
|
await this.app.browserWindow.restore();
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyWindowFocus(windowTitle) {
|
||||||
|
let index = await this.getWindowIndexFromTitle(windowTitle);
|
||||||
|
await this.windowByIndex(index);
|
||||||
|
expect(await this.app.browserWindow.isFocused()).toBeTruthy();
|
||||||
|
await this.windowByIndex(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async verifyPopOutWindowAppear(windowTitle) {
|
||||||
|
let index = await this.getWindowIndexFromTitle(windowTitle);
|
||||||
|
expect(index).toBeGreaterThan(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async closeAllPopOutWindow() {
|
||||||
|
let winCount = await this.getWindowCount();
|
||||||
|
while (winCount > 1) {
|
||||||
|
await this.windowByIndex(winCount - 1);
|
||||||
|
await this.app.browserWindow.close();
|
||||||
|
await Utils.sleep(2);
|
||||||
|
winCount = await this.getWindowCount();
|
||||||
|
}
|
||||||
|
await this.windowByIndex(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = WindowsActions;
|
85
tests/spectron/toastMouseHoveringForIM.spectron.js
Normal file
85
tests/spectron/toastMouseHoveringForIM.spectron.js
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WebDriver = require('./spectronWebDriver');
|
||||||
|
const { isMac } = require('../../js/utils/misc.js');
|
||||||
|
var app = new Application({
|
||||||
|
startTimeout: Application.getTimeOut(),
|
||||||
|
waitTimeout: Application.getTimeOut()
|
||||||
|
});
|
||||||
|
var webdriver = new WebDriver({ browser: 'chrome' });
|
||||||
|
const WindowsAction = require('./spectronWindowsActions');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const specconst = require('./spectronConstants.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
const ifc = require('./spectronInterfaces.js');
|
||||||
|
let webActions, windowAction;
|
||||||
|
|
||||||
|
!isMac? describe('Verify toast notification for IMs', () => {
|
||||||
|
let originalTimeout = specconst.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = specconst.TIMEOUT_TEST_SUITE;
|
||||||
|
|
||||||
|
beforeAll(async(done) => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
app = await new Application({}).startApplication({testedHost:specconst.TESTED_HOST, alwaysOnTop: true});
|
||||||
|
windowAction = await new WindowsAction(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
done();
|
||||||
|
} catch(err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterAll((done) => {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
app.stop().then(() => {
|
||||||
|
webdriver.close();
|
||||||
|
webdriver.quit();
|
||||||
|
done();
|
||||||
|
}).catch((err) => {
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Verify toast notification for IMs
|
||||||
|
* TC-ID: 3395297
|
||||||
|
* Cover scenarios in AVT-1031
|
||||||
|
*/
|
||||||
|
it('Toast notification should not be closed', async () => {
|
||||||
|
|
||||||
|
await webdriver.startDriver();
|
||||||
|
await webdriver.login(specconst.USER_A);
|
||||||
|
await webdriver.createIM(specconst.USER_B.username);
|
||||||
|
await webActions.login(specconst.USER_B);
|
||||||
|
await windowAction.reload();
|
||||||
|
await app.client.waitForVisible(ifc.SETTTING_BUTTON, Utils.toMs(50));
|
||||||
|
await webActions.clickIfElementVisible(ifc.SETTTING_BUTTON);
|
||||||
|
await windowAction.pressCtrlM();
|
||||||
|
await webdriver.clickLeftNavItem(specconst.USER_B.name);
|
||||||
|
var message = await Utils.randomString();
|
||||||
|
await webdriver.sendMessages([message]);
|
||||||
|
await windowAction.verifyNotCloseToastWhenMouseOver(message);
|
||||||
|
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Verify toast notification for signals, mentions and keywords
|
||||||
|
* TC-ID: 3395306
|
||||||
|
* Cover scenarios in AVT-1032
|
||||||
|
*/
|
||||||
|
it('Verify toast notification for signals, mentions and keywords', async () => {
|
||||||
|
var nameSignal = await Utils.randomString();
|
||||||
|
var nameHashTag = await Utils.randomString();
|
||||||
|
var roomName = await Utils.randomString();
|
||||||
|
var description =await Utils.randomString();
|
||||||
|
|
||||||
|
await webdriver.createSignal(nameSignal,nameHashTag);
|
||||||
|
await webdriver.createRoom([specconst.USER_B.username],roomName,description,specconst.TYPE_ROOM.public)
|
||||||
|
await webdriver.clickLeftNavItem(roomName);
|
||||||
|
|
||||||
|
await webdriver.sendMessages(["#"+nameHashTag]);
|
||||||
|
await windowAction.verifyNotCloseToastWhenMouseOver(specconst.USER_A.name+": #"+nameHashTag);
|
||||||
|
await webdriver.mentionUserOnChat(specconst.USER_B);
|
||||||
|
await windowAction.verifyNotCloseToastWhenMouseOver(specconst.USER_A.name+": @"+specconst.USER_B.name);
|
||||||
|
});
|
||||||
|
|
||||||
|
}):describe.skip();
|
77
tests/spectron/toastNotification.spectron.js
Normal file
77
tests/spectron/toastNotification.spectron.js
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const WindowsActions = require('./spectronWindowsActions');
|
||||||
|
const WebDriver = require('./spectronWebDriver');
|
||||||
|
const { isMac } = require('../../js/utils/misc.js');
|
||||||
|
const constants = require('./spectronConstants.js');
|
||||||
|
const ui = require('./spectronInterfaces.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
|
||||||
|
let app, webDriver, webActions, windowsActions;
|
||||||
|
|
||||||
|
describe('Tests for Toast Notification ', () => {
|
||||||
|
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = constants.TIMEOUT_PAGE_LOAD;
|
||||||
|
|
||||||
|
beforeAll(async (done) => {
|
||||||
|
try {
|
||||||
|
webDriver = await new WebDriver({ browser: 'chrome' });
|
||||||
|
app = await new Application({}).startApplication({ testedHost: constants.TESTED_HOST, alwaysOnTop: true });
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
windowsActions = await new WindowsActions(app);
|
||||||
|
done();
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
await app.stop();
|
||||||
|
await webDriver.quit();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verify Pop-up alert play depends on setting
|
||||||
|
* TC-ID: 2916217
|
||||||
|
* Cover scenarios in AVT-1024
|
||||||
|
*/
|
||||||
|
it('Pop-up alert play depends on setting', async (done) => {
|
||||||
|
try {
|
||||||
|
if (isMac) {
|
||||||
|
done();
|
||||||
|
} else {
|
||||||
|
let message1 = await Utils.randomString();
|
||||||
|
let message2 = await Utils.randomString();
|
||||||
|
|
||||||
|
//"Mute pop-up alerts on my desktop"=OFF
|
||||||
|
await webDriver.startDriver();
|
||||||
|
await webActions.login(constants.USER_A);
|
||||||
|
await windowsActions.reload(); //workaround to show topbar menu
|
||||||
|
await webDriver.login(constants.USER_B);
|
||||||
|
await webActions.openAlertsSettings();
|
||||||
|
await webActions.checkBox(ui.MUTE_POPUP_ALERTS_CKB, false);
|
||||||
|
await webDriver.createIM(constants.USER_A);
|
||||||
|
await webDriver.sendMessages([message1]);
|
||||||
|
await webActions.verifyToastNotificationShow(message1);
|
||||||
|
await Utils.sleep(5); //waitting for toast message disappears
|
||||||
|
|
||||||
|
//"Mute pop-up alerts on my desktop"=ON
|
||||||
|
await webActions.checkBox(ui.MUTE_POPUP_ALERTS_CKB, true);
|
||||||
|
await webDriver.sendMessages([message2]);
|
||||||
|
await webActions.verifyNoToastNotificationShow(message2);
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Fail to verify pop-up alert play depends on setting: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
})
|
89
tests/spectron/turnONPersistentToast.spectron.js
Normal file
89
tests/spectron/turnONPersistentToast.spectron.js
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
const Application = require('./spectronSetup');
|
||||||
|
const WebDriver = require('./spectronWebDriver');
|
||||||
|
const { isMac } = require('../../js/utils/misc.js');
|
||||||
|
const Utils = require('./spectronUtils');
|
||||||
|
var app = new Application({
|
||||||
|
startTimeout: Application.getTimeOut(),
|
||||||
|
waitTimeout: Application.getTimeOut()
|
||||||
|
});
|
||||||
|
var webdriver = new WebDriver({ browser: 'chrome' });
|
||||||
|
const WindowsAction = require('./spectronWindowsActions');
|
||||||
|
const WebActions = require('./spectronWebActions');
|
||||||
|
const ifc = require('./spectronInterfaces.js');
|
||||||
|
const specconst = require('./spectronConstants.js');
|
||||||
|
let webActions, windowAction;
|
||||||
|
|
||||||
|
!isMac ? describe('Verify toast notification when Persist Notification is ON', () => {
|
||||||
|
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = specconst.TIMEOUT_TEST_SUITE;
|
||||||
|
|
||||||
|
beforeAll(async(done) => {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
app = await new Application({}).startApplication({testedHost:specconst.TESTED_HOST, alwaysOnTop: true});
|
||||||
|
windowAction = await new WindowsAction(app);
|
||||||
|
webActions = await new WebActions(app);
|
||||||
|
done();
|
||||||
|
} catch(err) {
|
||||||
|
done.fail(new Error(`Unable to start application error: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
afterAll(async (done) => {
|
||||||
|
try {
|
||||||
|
if (app && app.isRunning()) {
|
||||||
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
|
await app.stop();
|
||||||
|
await webdriver.quit();
|
||||||
|
done();
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
done.fail(new Error(`Failed at post-condition: ${err}`));
|
||||||
|
};
|
||||||
|
});
|
||||||
|
/**
|
||||||
|
* Verify toast notification when Persist Notification is ON
|
||||||
|
* TC-ID: 3308790
|
||||||
|
* Cover scenarios in AVT-1025
|
||||||
|
*/
|
||||||
|
it('Toast notification appears on screen and should stay on the screen IM', async () => {
|
||||||
|
|
||||||
|
await webdriver.startDriver();
|
||||||
|
await webdriver.login(specconst.USER_A);
|
||||||
|
await webdriver.createIM(specconst.USER_B.username);
|
||||||
|
await webActions.login(specconst.USER_B);
|
||||||
|
|
||||||
|
await windowAction.reload();
|
||||||
|
await app.client.waitForVisible(ifc.SETTTING_BUTTON, Utils.toMs(50));
|
||||||
|
await webActions.persistToastIM();
|
||||||
|
|
||||||
|
await windowAction.pressCtrlM();
|
||||||
|
var message = await Utils.randomString();
|
||||||
|
await webdriver.sendMessages([message]);
|
||||||
|
await windowAction.veriryPersistToastNotification(message);
|
||||||
|
await webdriver.startDriver();
|
||||||
|
await webdriver.createMIM([specconst.USER_B.username, specconst.USER_C.username]);
|
||||||
|
await webdriver.sendMessages([message]);
|
||||||
|
await windowAction.veriryPersistToastNotification(message);
|
||||||
|
|
||||||
|
})
|
||||||
|
/**
|
||||||
|
* Verify toast notification when Persist Notification is OFF
|
||||||
|
* TC-ID: 46602241
|
||||||
|
* Cover scenarios in AVT-1027
|
||||||
|
*/
|
||||||
|
it('Toast notification appears on screen and should disappear in few seconds IM', async () => {
|
||||||
|
|
||||||
|
await windowAction.showWindow();
|
||||||
|
await app.client.waitForVisible(ifc.SETTTING_BUTTON, Utils.toMs(50));
|
||||||
|
await webActions.persistToastIM();
|
||||||
|
await webdriver.clickLeftNavItem(specconst.USER_B.name);
|
||||||
|
var message = await Utils.randomString();
|
||||||
|
await webdriver.sendMessages([message]);
|
||||||
|
await windowAction.verifyNotPersistToastNotification("Electron");
|
||||||
|
await webdriver.createMIM([specconst.USER_B.username, specconst.USER_C.username]);
|
||||||
|
await webdriver.sendMessages([message]);
|
||||||
|
await windowAction.verifyNotPersistToastNotification("Electron");
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
|
}) : describe.skip();
|
@ -41,6 +41,16 @@ describe('Tests for Zoom in and Zoom out', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
afterAll((done) => {
|
afterAll((done) => {
|
||||||
|
// Get it back normal size
|
||||||
|
if (!isMac) {
|
||||||
|
for (let i = 0; i < 4; i++) {
|
||||||
|
robot.keyToggle('+', 'down', ['control', 'shift']);
|
||||||
|
}
|
||||||
|
robot.keyToggle('+', 'up');
|
||||||
|
robot.keyToggle('control', 'up');
|
||||||
|
robot.keyToggle('shift', 'up');
|
||||||
|
}
|
||||||
|
|
||||||
if (app && app.isRunning()) {
|
if (app && app.isRunning()) {
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = originalTimeout;
|
||||||
app.client.getWindowCount().then((count) => {
|
app.client.getWindowCount().then((count) => {
|
||||||
@ -124,7 +134,7 @@ describe('Tests for Zoom in and Zoom out', () => {
|
|||||||
robot.setMouseDelay(100);
|
robot.setMouseDelay(100);
|
||||||
let x = bounds.x + 200;
|
let x = bounds.x + 200;
|
||||||
let y = bounds.y + 200;
|
let y = bounds.y + 200;
|
||||||
robot.moveMouseSmooth(x, y);
|
robot.moveMouse(x, y);
|
||||||
robot.mouseClick();
|
robot.mouseClick();
|
||||||
|
|
||||||
robot.keyToggle('0', 'down', ['control']);
|
robot.keyToggle('0', 'down', ['control']);
|
||||||
@ -174,7 +184,7 @@ describe('Tests for Zoom in and Zoom out', () => {
|
|||||||
robot.setMouseDelay(100);
|
robot.setMouseDelay(100);
|
||||||
let x = bounds.x + 200;
|
let x = bounds.x + 200;
|
||||||
let y = bounds.y + 200;
|
let y = bounds.y + 200;
|
||||||
robot.moveMouseSmooth(x, y);
|
robot.moveMouse(x, y);
|
||||||
robot.mouseClick();
|
robot.mouseClick();
|
||||||
|
|
||||||
robot.keyToggle('0', 'down', ['control']);
|
robot.keyToggle('0', 'down', ['control']);
|
||||||
|
Loading…
Reference in New Issue
Block a user