Electron 380: add share logs support (#333)

- add capabilities to generate log files
- change the location of share logs menu item
- add spectron tests
- add menu item text for windows
- fix issue reported on windows archiving other files
- fix failing spectron tests
- pin archiver dependency version
This commit is contained in:
Vishwas Shashidhar 2018-04-06 13:42:41 +05:30 committed by GitHub
parent 1d1b90d2ae
commit 2e25c97bec
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 250 additions and 22 deletions

View File

@ -1,7 +1,6 @@
'use strict';
const getCmdLineArg = require('./utils/getCmdLineArg.js');
const { isDevEnv } = require('./utils/misc');
const logLevels = require('./enums/logLevels.js');
const MAX_LOG_QUEUE_LENGTH = 100;
@ -18,7 +17,7 @@ class Logger {
this.logQueue = [];
// Initializes the local logger
if (isDevEnv) {
if (!process.env.ELECTRON_QA) {
initializeLocalLogger();
}
}
@ -35,7 +34,7 @@ class Logger {
return;
}
if (isDevEnv) {
if (!process.env.ELECTRON_QA) {
logLocally(level, details);
}

View File

@ -1,9 +1,11 @@
'use strict';
const electron = require('electron');
const fs = require('fs');
const { updateConfigField, getMultipleConfigField } = require('../config.js');
const AutoLaunch = require('auto-launch');
const { isMac, isWindowsOS } = require('../utils/misc.js');
const archiveHandler = require('../utils/archiveHandler');
const log = require('../log.js');
const logLevels = require('../enums/logLevels.js');
const eventEmitter = require('../eventEmitter');
@ -95,13 +97,6 @@ const template = [{
eventEmitter.emit('setDownloadsDirectory', filePaths[0]);
});
}
},
{
label: 'Open Crashes Directory',
click() {
const crashesDirectory = electron.crashReporter.getCrashesDirectory() + '/completed';
electron.shell.showItemInFolder(crashesDirectory);
}
},
{ type: 'separator' },
buildMenuItem('resetzoom'),
@ -120,11 +115,55 @@ const template = [{
},
{
role: 'help',
submenu: [
submenu:
[
{
label: 'Learn More',
click() { electron.shell.openExternal('https://www.symphony.com'); }
}]
},
{
label: 'Troubleshooting',
submenu: [
{
label: isMac ? 'Show Logs in Finder' : 'Show Logs in Explorer',
click() {
const MAC_LOGS_PATH = '/Library/Logs/Symphony/';
const WINDOWS_LOGS_PATH = '\\AppData\\Roaming\\Symphony\\';
let logsPath = isMac ? MAC_LOGS_PATH : WINDOWS_LOGS_PATH;
let source = electron.app.getPath('home') + logsPath;
if (!fs.existsSync(source)) {
electron.dialog.showErrorBox('Failed!', 'No logs are available to share');
return;
}
let destPath = isMac ? '/logs_symphony_' : '\\logs_symphony_';
let timestamp = new Date().getTime();
let destination = electron.app.getPath('downloads') + destPath + timestamp + '.zip';
archiveHandler.generateArchiveForDirectory(source, destination)
.then(() => {
electron.shell.showItemInFolder(destination);
})
.catch((err) => {
electron.dialog.showErrorBox('Failed!', 'Unable to generate logs due to -> ' + err);
})
}
},
{
label: 'Open Crashes Directory',
click() {
const crashesDirectory = electron.crashReporter.getCrashesDirectory() + '/completed';
electron.shell.showItemInFolder(crashesDirectory);
}
}
]
}
]
}
];

View File

@ -0,0 +1,39 @@
'use strict';
const fs = require('fs');
const path = require('path');
const archiver = require('archiver');
function generateArchiveForDirectory(source, destination) {
return new Promise((resolve, reject) => {
let output = fs.createWriteStream(destination);
let archive = archiver('zip', {zlib: {level: 9}});
output.on('close', function () {
resolve();
});
archive.on('error', function(err){
reject(err);
});
archive.pipe(output);
let files = fs.readdirSync(source);
files.forEach((file) => {
if (path.extname(file) === '.log') {
archive.file(source + '/' + file, { name: 'logs/' + file });
}
});
archive.finalize();
});
}
module.exports = {
generateArchiveForDirectory: generateArchiveForDirectory
};

View File

@ -19,7 +19,7 @@
"prebuild": "npm run rebuild && npm run browserify-preload",
"browserify-preload": "browserify -o js/preload/_preloadMain.js -x electron --insert-global-vars=__filename,__dirname js/preload/preloadMain.js --exclude electron-spellchecker",
"rebuild": "electron-rebuild -f",
"test": "npm run lint && npm rebuild --build-from-source && jest --verbose --testPathPattern test && npm run rebuild",
"test": "npm run lint && npm rebuild --build-from-source && cross-env ELECTRON_QA=true && jest --verbose --testPathPattern test && npm run rebuild",
"spectron-test": "npm rebuild --build-from-source && jest --config tests/spectron/jest_spectron.json --runInBand && npm run rebuild",
"lint": "eslint --ext .js js/",
"rename-exe": "cd dist/win-unpacked && ren Symphony.exe Symphony-Electron.exe"
@ -98,6 +98,7 @@
"eslint-plugin-import": "2.8.0",
"eslint-plugin-jsx-a11y": "4.0.0",
"eslint-plugin-react": "6.10.3",
"glob": "7.1.2",
"jest": "19.0.2",
"ncp": "2.0.0",
"robotjs": "0.4.7",
@ -106,6 +107,7 @@
"dependencies": {
"@paulcbetts/system-idle-time": "1.0.4",
"appdirectory": "0.1.0",
"archiver": "2.1.1",
"async.map": "0.5.2",
"async.mapseries": "0.5.2",
"auto-launch": "5.0.5",

View File

@ -138,9 +138,9 @@ describe('Tests for Always on top', () => {
robot.setMouseDelay(200);
robot.moveMouse(190, 0);
robot.mouseClick();
// Key tap 9 times as "Always on Top" is in the
// 9th position under view menu item
for (let i = 0; i < 9; i++) {
// Key tap 8 times as "Always on Top" is in the
// 8th position under view menu item
for (let i = 0; i < 8; i++) {
robot.keyTap('down');
}
robot.keyTap('enter');

View File

@ -105,9 +105,9 @@ describe('Tests for Full screen', () => {
robot.mouseClick();
robot.setKeyboardDelay(100);
// Key tap 7 times as "Enter Full Screen" is in the
// 7th position under view menu item
for (let i = 0; i < 7; i++) {
// Key tap 6 times as "Enter Full Screen" is in the
// 6th position under view menu item
for (let i = 0; i < 6; i++) {
robot.keyTap('down');
}
robot.keyTap('enter');

View File

@ -119,9 +119,9 @@ describe('Tests for Minimize on Close', () => {
robot.mouseClick();
robot.setKeyboardDelay(100);
// Key tap 10 times as "Minimize on Close" is in the
// 10th position under view menu item
for (let i = 0; i < 10; i++) {
// Key tap 9 times as "Minimize on Close" is in the
// 9th position under view menu item
for (let i = 0; i < 9; i++) {
robot.keyTap('down');
}
robot.keyTap('enter');

View File

@ -0,0 +1,149 @@
const Application = require('./spectronSetup');
const { isMac } = require('../../js/utils/misc');
const robot = require('robotjs');
const fs = require('fs');
const glob = require('glob');
let downloadsPath;
let app = new Application({});
describe('Tests for Generating & Sharing Logs', () => {
let originalTimeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
jasmine.DEFAULT_TIMEOUT_INTERVAL = Application.getTimeOut();
beforeAll((done) => {
return app.startApplication().then((startedApp) => {
app = startedApp;
getDownloadsPath().then((path) => {
downloadsPath = path;
done();
}).catch((err) => {
done.fail(new Error(`Unable to start application error: ${err}`));
});
}).catch((err) => {
done.fail(new Error(`Unable to start application error: ${err}`));
});
});
function getDownloadsPath() {
return new Promise(function (resolve, reject) {
app.client.addCommand('getDownloadsPath', function () {
return this.execute(function () {
return require('electron').remote.app.getPath('downloads');
})
});
app.client.getDownloadsPath().then((downloadsPath) => {
resolve(downloadsPath.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();
}
});
it('should launch the app', (done) => {
return app.client.waitUntilWindowLoaded().then(() => {
return app.client.getWindowCount().then((count) => {
expect(count === 1).toBeTruthy();
done();
}).catch((err) => {
done.fail(new Error(`share-logs failed in getWindowCount with error: ${err}`));
});
}).catch((err) => {
done.fail(new Error(`share-logs failed in waitUntilWindowLoaded with error: ${err}`));
});
});
it('should check window count', (done) => {
return app.client.getWindowCount().then((count) => {
expect(count === 1).toBeTruthy();
done();
}).catch((err) => {
done.fail(new Error(`share-logs failed in waitUntilWindowLoaded with error: ${err}`));
});
});
it('should check browser window visibility', (done) => {
return app.browserWindow.isVisible().then((isVisible) => {
expect(isVisible).toBeTruthy();
done();
}).catch((err) => {
done.fail(new Error(`share-logs failed in isVisible with error: ${err}`));
});
});
it('should bring the app to top', () => {
app.browserWindow.focus();
return app.browserWindow.setAlwaysOnTop(true).then(() => {
return app.browserWindow.isAlwaysOnTop().then((isOnTop) => {
expect(isOnTop).toBeTruthy();
});
});
});
it('should generate logs', (done) => {
robot.setKeyboardDelay(500);
if (isMac) {
const x = 305;
const y = 8;
robot.moveMouseSmooth(x, y);
robot.mouseClick();
robot.keyTap('down');
robot.keyTap('down');
robot.keyTap('right');
robot.keyTap('enter');
console.log(downloadsPath);
glob(downloadsPath + '/logs_symphony*.zip', function (err, files) {
if (err || files.length < 1) {
return done.fail(new Error(`log was not generated / file doesn't exist`));
}
let i = files.length;
files.forEach(function (file) {
fs.unlink(file, function (err) {
i--;
if (err) {
console.log('unable to delete file -> ' + file);
}
if (i <=0 ) {
return done();
}
});
});
});
}
});
});