Socket
Socket
Sign inDemoInstall

spectron

Package Overview
Dependencies
Maintainers
5
Versions
66
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

spectron - npm Package Compare versions

Comparing version 11.0.0 to 11.1.0

.eslintignore

2

index.js

@@ -1,1 +0,1 @@

exports.Application = require('./lib/application')
exports.Application = require('./lib/application');

@@ -1,61 +0,72 @@

var axsPath = require.resolve('../vendor/axs_testing')
const axsPath = require.resolve('../vendor/axs_testing');
exports.addCommand = function (client, requireName) {
client.addCommand('auditAccessibility', function (options) {
return this.execute(function (axsPath, requireName, options) {
options = options || {}
var ignoreWarnings = options.ignoreWarnings || false
var ignoreRules = Array.isArray(options.ignoreRules) ? options.ignoreRules : []
return this.execute(
function (axsPath, requireName, options) {
options = options || {};
const ignoreWarnings = options.ignoreWarnings || false;
const ignoreRules = Array.isArray(options.ignoreRules)
? options.ignoreRules
: [];
var axs = window[requireName](axsPath)
var audit = axs.Audit.run(new axs.AuditConfiguration({
showUnsupportedRulesWarning: false
}))
const axs = window[requireName](axsPath);
const audit = axs.Audit.run(
new axs.AuditConfiguration({
showUnsupportedRulesWarning: false
})
);
var failures = audit.filter(function (result) {
return result.result === 'FAIL'
})
let failures = audit.filter(function (result) {
return result.result === 'FAIL';
});
if (ignoreWarnings) {
if (ignoreWarnings) {
failures = failures.filter(function (result) {
return result.rule.severity !== 'Warning';
});
}
failures = failures.filter(function (result) {
return result.rule.severity !== 'Warning'
})
}
return ignoreRules.indexOf(result.rule.code) === -1;
});
failures = failures.filter(function (result) {
return ignoreRules.indexOf(result.rule.code) === -1
})
if (failures.length > 0) {
let message = 'Accessibilty audit failed\n\n';
message += failures
.map(function (result) {
return axs.Audit.accessibilityErrorMessage(result);
})
.join('\n\n');
if (failures.length > 0) {
var message = 'Accessibilty audit failed\n\n'
message += failures.map(function (result) {
return axs.Audit.accessibilityErrorMessage(result)
}).join('\n\n')
return {
message: message,
failed: true,
results: failures.map(function (result) {
return {
code: result.rule.code,
elements: result.elements.map(function (element) {
return axs.utils.getQuerySelectorText(element)
}),
message: result.rule.heading,
severity: result.rule.severity,
url: result.rule.url
}
})
return {
message: message,
failed: true,
results: failures.map(function (result) {
return {
code: result.rule.code,
elements: result.elements.map(function (element) {
return axs.utils.getQuerySelectorText(element);
}),
message: result.rule.heading,
severity: result.rule.severity,
url: result.rule.url
};
})
};
} else {
return {
message: 'Accessibilty audit passed',
results: [],
failed: false
};
}
} else {
return {
message: 'Accessibilty audit passed',
results: [],
failed: false
}
}
}, axsPath, requireName, options).then(function (response) {
return response.value
})
})
}
},
axsPath,
requireName,
options
).then(function (response) {
return response;
});
});
};

@@ -1,20 +0,21 @@

var apiCache = {}
const apiCache = {};
function Api (app, requireName) {
this.app = app
this.requireName = requireName
function Api(app, requireName) {
this.app = app;
this.requireName = requireName;
}
Api.prototype.initialize = function () {
return this.load().then(this.addApiCommands.bind(this))
}
const self = this;
return self.load().then(self.addApiCommands.bind(self));
};
Api.prototype.addApiCommands = function (api) {
if (!this.nodeIntegration) return
if (!this.nodeIntegration) return;
this.addRenderProcessApis(api.electron)
this.addMainProcessApis(api.electron.remote)
this.addBrowserWindowApis(api.browserWindow)
this.addWebContentsApis(api.webContents)
this.addProcessApis(api.rendererProcess)
this.addRenderProcessApis(api.electron);
this.addMainProcessApis(api.electron.remote);
this.addBrowserWindowApis(api.browserWindow);
this.addWebContentsApis(api.webContents);
this.addProcessApis(api.rendererProcess);

@@ -26,11 +27,12 @@ this.api = {

webContents: api.webContents
}
};
this.addClientProperties()
}
this.addClientProperties();
};
Api.prototype.load = function () {
var self = this
const self = this;
return this.isNodeIntegrationEnabled().then(function (nodeIntegration) {
self.nodeIntegration = nodeIntegration
self.nodeIntegration = nodeIntegration;
if (!nodeIntegration) {

@@ -42,31 +44,32 @@ return {

rendererProcess: {}
}
};
}
return self.getVersion().then(function (version) {
var api = apiCache[version]
if (api) return api
const api = apiCache[version];
if (api) return api;
return self.loadApi().then(function (api) {
if (version) apiCache[version] = api
return api
})
})
})
}
if (version) apiCache[version] = api;
return api;
});
});
});
};
Api.prototype.isNodeIntegrationEnabled = function () {
return this.app.client.execute(function (requireName) {
return typeof window[requireName] === 'function'
}, this.requireName).then(getResponseValue)
}
const self = this;
return self.app.client.execute(function (requireName) {
return typeof window[requireName] === 'function';
}, self.requireName);
};
Api.prototype.getVersion = function () {
return this.app.client.execute(function (requireName) {
var process = window[requireName]('process')
const process = window[requireName]('process');
if (process != null && process.versions != null) {
return process.versions.electron
return process.versions.electron;
}
}, this.requireName).then(getResponseValue)
}
}, this.requireName);
};

@@ -76,8 +79,10 @@ Api.prototype.loadApi = function () {

if (typeof window[requireName] !== 'function') {
throw new Error('Could not find global require method with name: ' + requireName)
throw new Error(
'Could not find global require method with name: ' + requireName
);
}
var electron = window[requireName]('electron')
var process = window[requireName]('process')
const electron = window[requireName]('electron');
const process = window[requireName]('process');
var api = {
const api = {
browserWindow: {},

@@ -87,5 +92,5 @@ electron: {},

webContents: {}
}
};
function ignoreModule (moduleName) {
function ignoreModule(moduleName) {
switch (moduleName) {

@@ -97,10 +102,10 @@ case 'CallbacksRegistry':

case 'Tray':
return true
return true;
case 'inAppPurchase':
return process.platform !== 'darwin'
return process.platform !== 'darwin';
}
return false
return false;
}
function isRemoteFunction (name) {
function isRemoteFunction(name) {
switch (name) {

@@ -110,52 +115,62 @@ case 'BrowserWindow':

case 'MenuItem':
return false
return false;
}
return typeof electron.remote[name] === 'function'
return typeof electron.remote[name] === 'function';
}
function ignoreApi (apiName) {
function ignoreApi(apiName) {
switch (apiName) {
case 'prototype':
return true
return true;
default:
return apiName[0] === '_'
return apiName[0] === '_';
}
}
function addModule (parent, parentName, name, api) {
api[name] = {}
for (var key in parent[name]) {
if (ignoreApi(key)) continue
api[name][key] = parentName + '.' + name + '.' + key
function addModule(parent, parentName, name, api) {
api[name] = {};
for (const key in parent[name]) {
if (ignoreApi(key)) continue;
api[name][key] = parentName + '.' + name + '.' + key;
}
}
function addRenderProcessModules () {
function addRenderProcessModules() {
Object.getOwnPropertyNames(electron).forEach(function (key) {
if (ignoreModule(key)) return
if (key === 'remote') return
addModule(electron, 'electron', key, api.electron)
})
if (ignoreModule(key)) return;
if (key === 'remote') return;
addModule(electron, 'electron', key, api.electron);
});
}
function addMainProcessModules () {
api.electron.remote = {}
function addMainProcessModules() {
api.electron.remote = {};
Object.getOwnPropertyNames(electron.remote).forEach(function (key) {
if (ignoreModule(key)) return
if (ignoreModule(key)) return;
if (isRemoteFunction(key)) {
api.electron.remote[key] = 'electron.remote.' + key
api.electron.remote[key] = 'electron.remote.' + key;
} else {
addModule(electron.remote, 'electron.remote', key, api.electron.remote)
addModule(
electron.remote,
'electron.remote',
key,
api.electron.remote
);
}
})
addModule(electron.remote, 'electron.remote', 'process', api.electron.remote)
});
addModule(
electron.remote,
'electron.remote',
'process',
api.electron.remote
);
}
function addBrowserWindow () {
var currentWindow = electron.remote.getCurrentWindow()
for (var name in currentWindow) {
if (ignoreApi(name)) continue
var value = currentWindow[name]
function addBrowserWindow() {
const currentWindow = electron.remote.getCurrentWindow();
for (const name in currentWindow) {
if (ignoreApi(name)) continue;
const value = currentWindow[name];
if (typeof value === 'function') {
api.browserWindow[name] = 'browserWindow.' + name
api.browserWindow[name] = 'browserWindow.' + name;
}

@@ -165,9 +180,9 @@ }

function addWebContents () {
var webContents = electron.remote.getCurrentWebContents()
for (var name in webContents) {
if (ignoreApi(name)) continue
var value = webContents[name]
function addWebContents() {
const webContents = electron.remote.getCurrentWebContents();
for (const name in webContents) {
if (ignoreApi(name)) continue;
const value = webContents[name];
if (typeof value === 'function') {
api.webContents[name] = 'webContents.' + name
api.webContents[name] = 'webContents.' + name;
}

@@ -177,172 +192,199 @@ }

function addProcess () {
if (typeof process !== 'object') return
function addProcess() {
if (typeof process !== 'object') return;
for (var name in process) {
if (ignoreApi(name)) continue
api.rendererProcess[name] = 'process.' + name
for (const name in process) {
if (ignoreApi(name)) continue;
api.rendererProcess[name] = 'process.' + name;
}
}
addRenderProcessModules()
addMainProcessModules()
addBrowserWindow()
addWebContents()
addProcess()
addRenderProcessModules();
addMainProcessModules();
addBrowserWindow();
addWebContents();
addProcess();
return api
}, this.requireName).then(getResponseValue)
}
return api;
}, this.requireName);
};
Api.prototype.addClientProperty = function (name) {
var self = this
const self = this;
var clientPrototype = Object.getPrototypeOf(self.app.client)
const clientPrototype = Object.getPrototypeOf(self.app.client);
Object.defineProperty(clientPrototype, name, {
get: function () {
var client = this
const client = this;
return transformObject(self.api[name], {}, function (value) {
return client[value].bind(client)
})
return client[value].bind(client);
});
}
})
}
});
};
Api.prototype.addClientProperties = function () {
this.addClientProperty('electron')
this.addClientProperty('browserWindow')
this.addClientProperty('webContents')
this.addClientProperty('rendererProcess')
this.addClientProperty('electron');
this.addClientProperty('browserWindow');
this.addClientProperty('webContents');
this.addClientProperty('rendererProcess');
Object.defineProperty(Object.getPrototypeOf(this.app.client), 'mainProcess', {
get: function () {
return this.electron.remote.process
return this.electron.remote.process;
}
})
}
});
};
Api.prototype.addRenderProcessApis = function (api) {
var app = this.app
var self = this
var electron = {}
app.electron = electron
const app = this.app;
const self = this;
const electron = {};
app.electron = electron;
Object.keys(api).forEach(function (moduleName) {
if (moduleName === 'remote') return
electron[moduleName] = {}
var moduleApi = api[moduleName]
if (moduleName === 'remote') return;
electron[moduleName] = {};
const moduleApi = api[moduleName];
Object.keys(moduleApi).forEach(function (key) {
var commandName = moduleApi[key]
const commandName = moduleApi[key];
app.client.addCommand(commandName, function () {
var args = Array.prototype.slice.call(arguments)
return this.execute(callRenderApi, moduleName, key, args, self.requireName).then(getResponseValue)
})
const args = Array.prototype.slice.call(arguments);
return this.execute(
callRenderApi,
moduleName,
key,
args,
self.requireName
);
});
electron[moduleName][key] = function () {
return app.client[commandName].apply(app.client, arguments)
}
})
})
}
return app.client[commandName].apply(app.client, arguments);
};
});
});
};
Api.prototype.addMainProcessApis = function (api) {
var app = this.app
var self = this
var remote = {}
app.electron.remote = remote
const app = this.app;
const self = this;
const remote = {};
app.electron.remote = remote;
Object.keys(api).filter(function (propertyName) {
return typeof api[propertyName] === 'string'
}).forEach(function (name) {
var commandName = api[name]
app.client.addCommand(commandName, function () {
var args = Array.prototype.slice.call(arguments)
return this.execute(callMainApi, null, name, args, self.requireName).then(getResponseValue)
Object.keys(api)
.filter(function (propertyName) {
return typeof api[propertyName] === 'string';
})
.forEach(function (name) {
const commandName = api[name];
remote[name] = function () {
return app.client[commandName].apply(app.client, arguments)
}
})
app.client.addCommand(commandName, function () {
const args = Array.prototype.slice.call(arguments);
return this.execute(callMainApi, '', name, args, self.requireName);
});
Object.keys(api).filter(function (moduleName) {
return typeof api[moduleName] === 'object'
}).forEach(function (moduleName) {
remote[moduleName] = {}
var moduleApi = api[moduleName]
remote[name] = function () {
return app.client[commandName].apply(app.client, arguments);
};
});
Object.keys(moduleApi).forEach(function (key) {
var commandName = moduleApi[key]
Object.keys(api)
.filter(function (moduleName) {
return typeof api[moduleName] === 'object';
})
.forEach(function (moduleName) {
remote[moduleName] = {};
const moduleApi = api[moduleName];
app.client.addCommand(commandName, function () {
var args = Array.prototype.slice.call(arguments)
return this.execute(callMainApi, moduleName, key, args, self.requireName).then(getResponseValue)
})
Object.keys(moduleApi).forEach(function (key) {
const commandName = moduleApi[key];
remote[moduleName][key] = function () {
return app.client[commandName].apply(app.client, arguments)
}
})
})
}
app.client.addCommand(commandName, function () {
const args = Array.prototype.slice.call(arguments);
return this.execute(
callMainApi,
moduleName,
key,
args,
self.requireName
);
});
remote[moduleName][key] = function () {
return app.client[commandName].apply(app.client, arguments);
};
});
});
};
Api.prototype.addBrowserWindowApis = function (api) {
var app = this.app
var self = this
app.browserWindow = {}
const app = this.app;
const self = this;
app.browserWindow = {};
const asyncApis = {
'browserWindow.capturePage': true
}
};
Object.keys(api).filter(function (name) {
return !asyncApis.hasOwnProperty(api[name])
}).forEach(function (name) {
var commandName = api[name]
app.client.addCommand(commandName, function () {
var args = Array.prototype.slice.call(arguments)
return this.execute(callBrowserWindowApi, name, args, self.requireName).then(getResponseValue)
Object.keys(api)
.filter(function (name) {
return !Object.prototype.hasOwnProperty.call(asyncApis, api[name]);
})
.forEach(function (name) {
const commandName = api[name];
app.browserWindow[name] = function () {
return app.client[commandName].apply(app.client, arguments)
}
})
app.client.addCommand(commandName, function () {
const args = Array.prototype.slice.call(arguments);
return this.execute(callBrowserWindowApi, name, args, self.requireName);
});
this.addCapturePageSupport()
}
app.browserWindow[name] = function () {
return app.client[commandName].apply(app.client, arguments);
};
});
this.addCapturePageSupport();
};
Api.prototype.addCapturePageSupport = function () {
var app = this.app
var self = this
const app = this.app;
const self = this;
app.client.addCommand('browserWindow.capturePage', function (rect) {
return this.executeAsync(async function (rect, requireName, done) {
var args = []
if (rect != null) args.push(rect)
var browserWindow = window[requireName]('electron').remote.getCurrentWindow()
const image = await browserWindow.capturePage.apply(browserWindow, args)
if (image != null) {
done(image.toPNG().toString('base64'))
} else {
done(image)
}
}, rect, self.requireName).then(getResponseValue).then(function (image) {
return Buffer.from(image, 'base64')
})
})
return this.executeAsync(
async function (rect, requireName, done) {
const args = [];
if (rect != null) args.push(rect);
const browserWindow = window[requireName](
'electron'
).remote.getCurrentWindow();
const image = await browserWindow.capturePage.apply(
browserWindow,
args
);
if (image != null) {
done(image.toPNG().toString('base64'));
} else {
done(image);
}
},
rect,
self.requireName
).then(function (image) {
return Buffer.from(image, 'base64');
});
});
app.browserWindow.capturePage = function () {
return app.client['browserWindow.capturePage'].apply(app.client, arguments)
}
}
return app.client['browserWindow.capturePage'].apply(app.client, arguments);
};
};
Api.prototype.addWebContentsApis = function (api) {
var app = this.app
var self = this
app.webContents = {}
const app = this.app;
const self = this;
app.webContents = {};

@@ -352,166 +394,189 @@ const asyncApis = {

'webContents.executeJavaScript': true
}
};
Object.keys(api).filter(function (name) {
return !asyncApis.hasOwnProperty(api[name])
}).forEach(function (name) {
var commandName = api[name]
app.client.addCommand(commandName, function () {
var args = Array.prototype.slice.call(arguments)
return this.execute(callWebContentsApi, name, args, self.requireName).then(getResponseValue)
Object.keys(api)
.filter(function (name) {
return !Object.prototype.hasOwnProperty.call(asyncApis, api[name]);
})
.forEach(function (name) {
const commandName = api[name];
app.webContents[name] = function () {
return app.client[commandName].apply(app.client, arguments)
}
})
app.client.addCommand(commandName, function () {
const args = Array.prototype.slice.call(arguments);
return this.execute(callWebContentsApi, name, args, self.requireName);
});
this.addSavePageSupport()
this.addExecuteJavaScriptSupport()
}
app.webContents[name] = function () {
return app.client[commandName].apply(app.client, arguments);
};
});
this.addSavePageSupport();
this.addExecuteJavaScriptSupport();
};
Api.prototype.addSavePageSupport = function () {
var app = this.app
var self = this
const app = this.app;
const self = this;
app.client.addCommand('webContents.savePage', function (fullPath, saveType) {
return this.executeAsync(async function (fullPath, saveType, requireName, done) {
var webContents = window[requireName]('electron').remote.getCurrentWebContents()
await webContents.savePage(fullPath, saveType)
done()
}, fullPath, saveType, self.requireName).then(getResponseValue).then(function (rawError) {
return this.executeAsync(
async function (fullPath, saveType, requireName, done) {
const webContents = window[requireName](
'electron'
).remote.getCurrentWebContents();
await webContents.savePage(fullPath, saveType);
done();
},
fullPath,
saveType,
self.requireName
).then(function (rawError) {
if (rawError) {
var error = new Error(rawError.message)
if (rawError.name) error.name = rawError.name
throw error
const error = new Error(rawError.message);
if (rawError.name) error.name = rawError.name;
throw error;
}
})
})
});
});
app.webContents.savePage = function () {
return app.client['webContents.savePage'].apply(app.client, arguments)
}
}
return app.client['webContents.savePage'].apply(app.client, arguments);
};
};
Api.prototype.addExecuteJavaScriptSupport = function () {
const app = this.app
const self = this
const app = this.app;
const self = this;
app.client.addCommand('webContents.executeJavaScript', function (code, useGesture) {
return this.executeAsync(async function (code, useGesture, requireName, done) {
const webContents = window[requireName]('electron').remote.getCurrentWebContents()
const result = await webContents.executeJavaScript(code, useGesture)
done(result)
}, code, useGesture, self.requireName).then(getResponseValue)
})
app.client.addCommand('webContents.executeJavaScript', function (
code,
useGesture
) {
return this.executeAsync(
async function (code, useGesture, requireName, done) {
const webContents = window[requireName](
'electron'
).remote.getCurrentWebContents();
const result = await webContents.executeJavaScript(code, useGesture);
done(result);
},
code,
useGesture,
self.requireName
);
});
app.webContents.executeJavaScript = function () {
return app.client['webContents.executeJavaScript'].apply(app.client, arguments)
}
}
return app.client['webContents.executeJavaScript'].apply(
app.client,
arguments
);
};
};
Api.prototype.addProcessApis = function (api) {
var app = this.app
app.rendererProcess = {}
const app = this.app;
app.rendererProcess = {};
Object.keys(api).forEach(function (name) {
var commandName = api[name]
const commandName = api[name];
app.client.addCommand(commandName, function () {
var args = Array.prototype.slice.call(arguments)
return this.execute(callProcessApi, name, args).then(getResponseValue)
})
const args = Array.prototype.slice.call(arguments);
return this.execute(callProcessApi, name, args);
});
app.rendererProcess[name] = function () {
return app.client[commandName].apply(app.client, arguments)
}
})
return app.client[commandName].apply(app.client, arguments);
};
});
app.mainProcess = app.electron.remote.process
}
app.mainProcess = app.electron.remote.process;
};
Api.prototype.transferPromiseness = function (target, promise) {
this.app.client.transferPromiseness(target, promise)
if (!this.nodeIntegration) return;
if (!this.nodeIntegration) return
const addProperties = function (source, target, moduleName) {
const sourceModule = source[moduleName];
if (!sourceModule) return;
target[moduleName] = transformObject(sourceModule, {}, function (
value,
parent
) {
return value.bind(parent);
});
};
var addProperties = function (source, target, moduleName) {
var sourceModule = source[moduleName]
if (!sourceModule) return
target[moduleName] = transformObject(sourceModule, {}, function (value, parent) {
return value.bind(parent)
})
}
addProperties(promise, target, 'webContents');
addProperties(promise, target, 'browserWindow');
addProperties(promise, target, 'electron');
addProperties(promise, target, 'mainProcess');
addProperties(promise, target, 'rendererProcess');
};
addProperties(promise, target, 'webContents')
addProperties(promise, target, 'browserWindow')
addProperties(promise, target, 'electron')
addProperties(promise, target, 'mainProcess')
addProperties(promise, target, 'rendererProcess')
}
Api.prototype.logApi = function () {
var fs = require('fs')
var path = require('path')
var json = JSON.stringify(this.api, null, 2)
fs.writeFileSync(path.join(__dirname, 'api.json'), json)
}
const fs = require('fs');
const path = require('path');
const json = JSON.stringify(this.api, null, 2);
fs.writeFileSync(path.join(__dirname, 'api.json'), json);
};
function transformObject (input, output, callback) {
function transformObject(input, output, callback) {
Object.keys(input).forEach(function (name) {
var value = input[name]
const value = input[name];
if (typeof value === 'object') {
output[name] = {}
transformObject(value, output[name], callback)
output[name] = {};
transformObject(value, output[name], callback);
} else {
output[name] = callback(value, input)
output[name] = callback(value, input);
}
})
return output
});
return output;
}
function callRenderApi (moduleName, api, args, requireName) {
var module = window[requireName]('electron')[moduleName]
function callRenderApi(moduleName, api, args, requireName) {
const module = window[requireName]('electron')[moduleName];
if (typeof module[api] === 'function') {
return module[api].apply(module, args)
return module[api].apply(module, args);
} else {
return module[api]
return module[api];
}
}
function callMainApi (moduleName, api, args, requireName) {
var module = window[requireName]('electron').remote
function callMainApi(moduleName, api, args, requireName) {
let module = window[requireName]('electron').remote;
if (moduleName) {
module = module[moduleName]
module = module[moduleName];
}
if (typeof module[api] === 'function') {
return module[api].apply(module, args)
return module[api].apply(module, args);
} else {
return module[api]
return module[api];
}
}
function callWebContentsApi (name, args, requireName) {
var webContents = window[requireName]('electron').remote.getCurrentWebContents()
return webContents[name].apply(webContents, args)
function callWebContentsApi(name, args, requireName) {
const webContents = window[requireName](
'electron'
).remote.getCurrentWebContents();
return webContents[name].apply(webContents, args);
}
function callBrowserWindowApi (name, args, requireName) {
var browserWindow = window[requireName]('electron').remote.getCurrentWindow()
return browserWindow[name].apply(browserWindow, args)
function callBrowserWindowApi(name, args, requireName) {
const browserWindow = window[requireName](
'electron'
).remote.getCurrentWindow();
return browserWindow[name].apply(browserWindow, args);
}
function callProcessApi (name, args) {
function callProcessApi(name, args) {
if (typeof process[name] === 'function') {
return process[name].apply(process, args)
return process[name].apply(process, args);
} else {
return process[name]
return process[name];
}
}
function getResponseValue (response) {
return response.value
}
module.exports = Api
module.exports = Api;

@@ -1,92 +0,113 @@

var Accessibility = require('./accessibility')
var Api = require('./api')
var ChromeDriver = require('./chrome-driver')
var DevNull = require('dev-null')
var fs = require('fs')
var path = require('path')
var WebDriver = require('webdriverio')
const Accessibility = require('./accessibility');
const Api = require('./api');
const ChromeDriver = require('./chrome-driver');
const DevNull = require('dev-null');
const fs = require('fs');
const path = require('path');
const WebDriver = require('webdriverio');
function Application (options) {
options = options || {}
this.host = options.host || '127.0.0.1'
this.port = parseInt(options.port, 10) || 9515
function Application(options) {
options = options || {};
this.host = options.host || '127.0.0.1';
this.port = parseInt(options.port, 10) || 9515;
this.quitTimeout = parseInt(options.quitTimeout, 10) || 1000
this.startTimeout = parseInt(options.startTimeout, 10) || 5000
this.waitTimeout = parseInt(options.waitTimeout, 10) || 5000
this.quitTimeout = parseInt(options.quitTimeout, 10) || 1000;
this.startTimeout = parseInt(options.startTimeout, 10) || 5000;
this.waitTimeout = parseInt(options.waitTimeout, 10) || 5000;
this.connectionRetryCount = parseInt(options.connectionRetryCount, 10) || 10
this.connectionRetryTimeout = parseInt(options.connectionRetryTimeout, 10) || 30000
this.connectionRetryCount = parseInt(options.connectionRetryCount, 10) || 10;
this.connectionRetryTimeout =
parseInt(options.connectionRetryTimeout, 10) || 30000;
this.nodePath = options.nodePath || process.execPath
this.path = options.path
this.nodePath = options.nodePath || process.execPath;
this.path = options.path;
this.args = options.args || []
this.chromeDriverArgs = options.chromeDriverArgs || []
this.env = options.env || {}
this.workingDirectory = options.cwd || process.cwd()
this.debuggerAddress = options.debuggerAddress
this.chromeDriverLogPath = options.chromeDriverLogPath
this.webdriverLogPath = options.webdriverLogPath
this.webdriverOptions = options.webdriverOptions || {}
this.requireName = options.requireName || 'require'
this.args = options.args || [];
this.chromeDriverArgs = options.chromeDriverArgs || [];
this.env = options.env || {};
this.workingDirectory = options.cwd || process.cwd();
this.debuggerAddress = options.debuggerAddress;
this.chromeDriverLogPath = options.chromeDriverLogPath;
this.webdriverLogPath = options.webdriverLogPath;
this.webdriverOptions = options.webdriverOptions || {};
this.requireName = options.requireName || 'require';
this.api = new Api(this, this.requireName)
this.setupPromiseness()
this.api = new Api(this, this.requireName);
this.setupPromiseness();
}
Application.prototype.setupPromiseness = function () {
var self = this
const self = this;
self.transferPromiseness = function (target, promise) {
self.api.transferPromiseness(target, promise)
}
}
self.api.transferPromiseness(target, promise);
};
};
Application.prototype.start = function () {
var self = this
return self.exists()
.then(function () { return self.startChromeDriver() })
.then(function () { return self.createClient() })
.then(function () { return self.api.initialize() })
.then(function () { return self.client.timeouts('script', self.waitTimeout) })
.then(function () { self.running = true })
.then(function () { return self })
}
const self = this;
return self
.exists()
.then(function () {
return self.startChromeDriver();
})
.then(function () {
return self.createClient();
})
.then(function () {
return self.api.initialize();
})
.then(function () {
return self.client.setTimeouts(
self.waitTimeout,
self.waitTimeout,
self.waitTimeout
);
})
.then(function () {
self.running = true;
})
.then(function () {
return self;
});
};
Application.prototype.stop = function () {
var self = this
const self = this;
if (!self.isRunning()) return Promise.reject(Error('Application not running'))
if (!self.isRunning()) {
return Promise.reject(Error('Application not running'));
}
return new Promise(function (resolve, reject) {
var endClient = function () {
const endClient = function () {
setTimeout(function () {
self.client.end().then(function () {
self.chromeDriver.stop()
self.running = false
resolve(self)
}, reject)
}, self.quitTimeout)
}
self.chromeDriver.stop();
self.running = false;
resolve(self);
}, self.quitTimeout);
};
if (self.api.nodeIntegration) {
self.client.windowByIndex(0).electron.remote.app.quit().then(endClient, reject)
self.client.electron.remote.app.quit().then(endClient, reject);
} else {
self.client.windowByIndex(0).execute(function () {
window.close()
}).then(endClient, reject)
self.client
.windowByIndex(0)
.then(function () {
self.client.closeWindow();
})
.then(endClient, reject);
}
})
}
});
};
Application.prototype.restart = function () {
var self = this
const self = this;
return self.stop().then(function () {
return self.start()
})
}
return self.start();
});
};
Application.prototype.isRunning = function () {
return this.running
}
return this.running;
};

@@ -113,54 +134,66 @@ Application.prototype.getSettings = function () {

requireName: this.requireName
}
}
};
};
Application.prototype.exists = function () {
var self = this
const self = this;
return new Promise(function (resolve, reject) {
// Binary path is ignored by ChromeDriver if debuggerAddress is set
if (self.debuggerAddress) return resolve()
if (self.debuggerAddress) return resolve();
if (typeof self.path !== 'string') {
return reject(Error('Application path must be a string'))
return reject(Error('Application path must be a string'));
}
fs.stat(self.path, function (error, stat) {
if (error) return reject(error)
if (stat.isFile()) return resolve()
reject(Error('Application path specified is not a file: ' + self.path))
})
})
}
if (error) return reject(error);
if (stat.isFile()) return resolve();
reject(Error('Application path specified is not a file: ' + self.path));
});
});
};
Application.prototype.startChromeDriver = function () {
this.chromeDriver = new ChromeDriver(this.host, this.port, this.nodePath, this.startTimeout, this.workingDirectory, this.chromeDriverLogPath)
return this.chromeDriver.start()
}
this.chromeDriver = new ChromeDriver(
this.host,
this.port,
this.nodePath,
this.startTimeout,
this.workingDirectory,
this.chromeDriverLogPath
);
return this.chromeDriver.start();
};
Application.prototype.createClient = function () {
var self = this
const self = this;
return new Promise(function (resolve, reject) {
var args = []
args.push('spectron-path=' + self.path)
const args = [];
args.push('spectron-path=' + self.path);
self.args.forEach(function (arg, index) {
args.push('spectron-arg' + index + '=' + arg)
})
args.push('spectron-arg' + index + '=' + arg);
});
for (var name in self.env) {
args.push('spectron-env-' + name + '=' + self.env[name])
for (const name in self.env) {
if (Object.prototype.hasOwnProperty.call(self.env, name)) {
args.push('spectron-env-' + name + '=' + self.env[name]);
}
}
self.chromeDriverArgs.forEach(function (arg) {
args.push(arg)
})
args.push(arg);
});
var isWin = process.platform === 'win32'
var launcherPath = path.join(__dirname, isWin ? 'launcher.bat' : 'launcher.js')
const isWin = process.platform === 'win32';
const launcherPath = path.join(
__dirname,
isWin ? 'launcher.bat' : 'launcher.js'
);
if (process.env.APPVEYOR) {
args.push('no-sandbox')
args.push('no-sandbox');
}
var options = {
host: self.host,
const options = {
hostname: self.host,
port: self.port,

@@ -170,5 +203,5 @@ waitforTimeout: self.waitTimeout,

connectionRetryTimeout: self.connectionRetryTimeout,
desiredCapabilities: {
browserName: 'electron',
chromeOptions: {
logLevel: 'silent',
capabilities: {
'goog:chromeOptions': {
binary: launcherPath,

@@ -181,132 +214,98 @@ args: args,

logOutput: DevNull()
}
};
if (self.webdriverLogPath) {
options.logOutput = self.webdriverLogPath
options.logLevel = 'verbose'
options.outputDir = self.webdriverLogPath;
options.logLevel = 'trace';
}
Object.assign(options, self.webdriverOptions)
Object.assign(options, self.webdriverOptions);
self.client = WebDriver.remote(options)
self.addCommands()
self.initializeClient(resolve, reject)
})
}
self.client = WebDriver.remote(options).then(function (remote) {
self.client = remote;
self.addCommands();
resolve();
}, reject);
});
};
Application.prototype.initializeClient = function (resolve, reject) {
var maxTries = 10
var tries = 0
var self = this
var init = function () {
tries++
self.client.init().then(resolve, function (error) {
if (tries >= maxTries) {
error.message = 'Client initialization failed after ' + tries + ' attempts: '
error.message += error.type + ' ' + error.message
reject(error)
} else {
global.setTimeout(init, 250)
}
})
}
init()
}
Application.prototype.addCommands = function () {
this.client.addCommand('waitUntilTextExists', function (selector, text, timeout) {
return this.waitUntil(function () {
return this.isExisting(selector).then(function (exists) {
if (!exists) return false
return this.getText(selector).then(function (selectorText) {
return Array.isArray(selectorText) ? selectorText.some(s => s.includes(text)) : selectorText.includes(text)
})
})
}, timeout).then(function () { }, function (error) {
error.message = 'waitUntilTextExists ' + error.message
throw error
})
})
this.client.addCommand('waitUntilTextExists', function (
selector,
text,
timeout
) {
const self = this;
return self
.waitUntil(async function () {
const elem = await self.$(selector);
const exists = await elem.isExisting();
if (!exists) {
return false;
}
/**
* Utility from webdriverio v5
* https://github.com/webdriverio/webdriverio/blob/v5.9.4/packages/webdriverio/src/commands/browser/switchWindow.js
*/
this.client.addCommand('switchWindow', async function (urlOrTitleToMatch) {
if (typeof urlOrTitleToMatch !== 'string' && !(urlOrTitleToMatch instanceof RegExp)) {
throw new TypeError('Invalid parameter urlOrTitleToMatch: expected a string or a RegExp')
}
const selectorText = await elem.getText();
return Array.isArray(selectorText)
? selectorText.some((s) => s.includes(text))
: selectorText.includes(text);
}, timeout)
.then(
function () {},
function (error) {
error.message = 'waitUntilTextExists ' + error.message;
throw error;
}
);
});
const tabs = await this.windowHandles().then(getResponseValue)
for (const tab of tabs) {
await this.window(tab)
/**
* check if url matches
*/
const url = await this.getUrl()
if (url.match(urlOrTitleToMatch)) {
return tab
}
/**
* check title
*/
const title = await this.getTitle()
if (title.match(urlOrTitleToMatch)) {
return tab
}
}
throw new Error(`No window found with title or url matching "${urlOrTitleToMatch}"`)
})
this.client.addCommand('waitUntilWindowLoaded', function (timeout) {
return this.waitUntil(function () {
return this.webContents.isLoading().then(function (loading) {
return !loading
})
}, timeout).then(function () { }, function (error) {
error.message = 'waitUntilWindowLoaded ' + error.message
throw error
})
})
const self = this;
return self
.waitUntil(function () {
return self.webContents.isLoading().then(function (loading) {
return !loading;
});
}, timeout)
.then(
function () {},
function (error) {
error.message = 'waitUntilWindowLoaded ' + error.message;
throw error;
}
);
});
this.client.addCommand('getWindowCount', function () {
return this.windowHandles().then(getResponseValue).then(function (handles) {
return handles.length
})
})
return this.getWindowHandles().then(function (handles) {
return handles.length;
});
});
this.client.addCommand('windowByIndex', function (index) {
return this.windowHandles().then(getResponseValue).then(function (handles) {
return this.window(handles[index])
})
})
const self = this;
return self.getWindowHandles().then(function (handles) {
return self.switchToWindow(handles[index]);
});
});
this.client.addCommand('getSelectedText', function () {
return this.execute(function () {
return window.getSelection().toString()
}).then(getResponseValue)
})
return window.getSelection().toString();
});
});
this.client.addCommand('getRenderProcessLogs', function () {
return this.log('browser').then(getResponseValue)
})
return this.getLogs('browser');
});
var self = this
const self = this;
this.client.addCommand('getMainProcessLogs', function () {
var logs = self.chromeDriver.getLogs()
self.chromeDriver.clearLogs()
return logs
})
const logs = self.chromeDriver.getLogs();
self.chromeDriver.clearLogs();
return logs;
});
Accessibility.addCommand(this.client, this.requireName)
}
Accessibility.addCommand(this.client, this.requireName);
};
var getResponseValue = function (response) {
return response.value
}
module.exports = Application
module.exports = Application;

@@ -1,135 +0,145 @@

var ChildProcess = require('child_process')
var path = require('path')
var request = require('request')
var split = require('split')
const ChildProcess = require('child_process');
const path = require('path');
const request = require('request');
const split = require('split');
function ChromeDriver (host, port, nodePath, startTimeout, workingDirectory, chromeDriverLogPath) {
this.host = host
this.port = port
this.nodePath = nodePath
this.startTimeout = startTimeout
this.workingDirectory = workingDirectory
this.chromeDriverLogPath = chromeDriverLogPath
function ChromeDriver(
host,
port,
nodePath,
startTimeout,
workingDirectory,
chromeDriverLogPath
) {
this.host = host;
this.port = port;
this.nodePath = nodePath;
this.startTimeout = startTimeout;
this.workingDirectory = workingDirectory;
this.chromeDriverLogPath = chromeDriverLogPath;
this.path = require.resolve('electron-chromedriver/chromedriver')
this.urlBase = '/wd/hub'
this.statusUrl = 'http://' + this.host + ':' + this.port + this.urlBase + '/status'
this.logLines = []
this.path = require.resolve('electron-chromedriver/chromedriver');
this.urlBase = '/';
this.statusUrl =
'http://' + this.host + ':' + this.port + this.urlBase + 'status';
this.logLines = [];
}
ChromeDriver.prototype.start = function () {
if (this.process) throw new Error('ChromeDriver already started')
if (this.process) throw new Error('ChromeDriver already started');
var args = [
this.path,
'--port=' + this.port,
'--url-base=' + this.urlBase
]
const args = [this.path, '--port=' + this.port, '--url-base=' + this.urlBase];
if (this.chromeDriverLogPath) {
args.push('--verbose')
args.push('--log-path=' + this.chromeDriverLogPath)
args.push('--verbose');
args.push('--log-path=' + this.chromeDriverLogPath);
}
var options = {
const options = {
cwd: this.workingDirectory,
env: this.getEnvironment()
}
this.process = ChildProcess.spawn(this.nodePath, args, options)
};
this.process = ChildProcess.spawn(this.nodePath, args, options);
var self = this
this.exitHandler = function () { self.stop() }
global.process.on('exit', this.exitHandler)
const self = this;
this.exitHandler = function () {
self.stop();
};
global.process.on('exit', this.exitHandler);
this.setupLogs()
return this.waitUntilRunning()
}
this.setupLogs();
return this.waitUntilRunning();
};
ChromeDriver.prototype.waitUntilRunning = function () {
var self = this
const self = this;
return new Promise(function (resolve, reject) {
var startTime = Date.now()
var checkIfRunning = function () {
const startTime = Date.now();
const checkIfRunning = function () {
self.isRunning(function (running) {
if (!self.process) {
return reject(Error('ChromeDriver has been stopped'))
return reject(Error('ChromeDriver has been stopped'));
}
if (running) {
return resolve()
return resolve();
}
var elapsedTime = Date.now() - startTime
const elapsedTime = Date.now() - startTime;
if (elapsedTime > self.startTimeout) {
return reject(Error('ChromeDriver did not start within ' + self.startTimeout + 'ms'))
return reject(
Error(
'ChromeDriver did not start within ' + self.startTimeout + 'ms'
)
);
}
global.setTimeout(checkIfRunning, 100)
})
}
checkIfRunning()
})
}
global.setTimeout(checkIfRunning, 100);
});
};
checkIfRunning();
});
};
ChromeDriver.prototype.setupLogs = function () {
var linesToIgnore = 2 // First two lines are ChromeDriver specific
var lineCount = 0
const linesToIgnore = 2; // First two lines are ChromeDriver specific
let lineCount = 0;
this.logLines = []
this.logLines = [];
var self = this
const self = this;
this.process.stdout.pipe(split()).on('data', function (line) {
if (lineCount < linesToIgnore) {
lineCount++
return
lineCount++;
return;
}
self.logLines.push(line)
})
}
self.logLines.push(line);
});
};
ChromeDriver.prototype.getEnvironment = function () {
var env = {}
const env = {};
Object.keys(process.env).forEach(function (key) {
env[key] = process.env[key]
})
env[key] = process.env[key];
});
if (process.platform === 'win32') {
env.SPECTRON_NODE_PATH = process.execPath
env.SPECTRON_LAUNCHER_PATH = path.join(__dirname, 'launcher.js')
env.SPECTRON_NODE_PATH = process.execPath;
env.SPECTRON_LAUNCHER_PATH = path.join(__dirname, 'launcher.js');
}
return env
}
return env;
};
ChromeDriver.prototype.stop = function () {
if (this.exitHandler) global.process.removeListener('exit', this.exitHandler)
this.exitHandler = null
if (this.exitHandler) global.process.removeListener('exit', this.exitHandler);
this.exitHandler = null;
if (this.process) this.process.kill()
this.process = null
if (this.process) this.process.kill();
this.process = null;
this.clearLogs()
}
this.clearLogs();
};
ChromeDriver.prototype.isRunning = function (callback) {
const cb = false
var requestOptions = {
const cb = false;
const requestOptions = {
uri: this.statusUrl,
json: true,
followAllRedirects: true
}
};
request(requestOptions, function (error, response, body) {
if (error) return callback(cb)
if (response.statusCode !== 200) return callback(cb)
callback(body && body.value.ready)
})
}
if (error) return callback(cb);
if (response.statusCode !== 200) return callback(cb);
callback(body && body.value.ready);
});
};
ChromeDriver.prototype.getLogs = function () {
return this.logLines.slice()
}
return this.logLines.slice();
};
ChromeDriver.prototype.clearLogs = function () {
this.logLines = []
}
this.logLines = [];
};
module.exports = ChromeDriver
module.exports = ChromeDriver;
#!/usr/bin/env node
var ChildProcess = require('child_process')
const ChildProcess = require('child_process');
var executablePath = null
var appArgs = []
var chromeArgs = []
let executablePath = null;
const appArgs = [];
const chromeArgs = [];
process.argv.slice(2).forEach(function (arg) {
var indexOfEqualSign = arg.indexOf('=')
const indexOfEqualSign = arg.indexOf('=');
if (indexOfEqualSign === -1) {
chromeArgs.push(arg)
return
chromeArgs.push(arg);
return;
}
var name = arg.substring(0, indexOfEqualSign)
var value = arg.substring(indexOfEqualSign + 1)
const name = arg.substring(0, indexOfEqualSign);
const value = arg.substring(indexOfEqualSign + 1);
if (name === '--spectron-path') {
executablePath = value
executablePath = value;
} else if (name.indexOf('--spectron-arg') === 0) {
appArgs[Number(name.substring(14))] = value
appArgs[Number(name.substring(14))] = value;
} else if (name.indexOf('--spectron-env') === 0) {
process.env[name.substring(15)] = value
process.env[name.substring(15)] = value;
} else if (name.indexOf('--spectron-') !== 0) {
chromeArgs.push(arg)
chromeArgs.push(arg);
}
})
});
var args = appArgs.concat(chromeArgs)
var appProcess = ChildProcess.spawn(executablePath, args)
appProcess.on('exit', function (code) { process.exit(code) })
appProcess.stderr.pipe(process.stdout)
appProcess.stdout.pipe(process.stdout)
appProcess.stdin.pipe(process.stdin)
const args = appArgs.concat(chromeArgs);
const appProcess = ChildProcess.spawn(executablePath, args);
appProcess.on('exit', function (code) {
process.exit(code);
});
appProcess.stderr.pipe(process.stdout);
appProcess.stdout.pipe(process.stdout);
appProcess.stdin.pipe(process.stdin);

@@ -1,13 +0,24 @@

if (process.platform !== 'darwin') process.exit(0)
if (process.platform !== 'darwin') process.exit(0);
const cp = require('child_process')
const path = require('path')
const cp = require('child_process');
const path = require('path');
const pathToChromedriver = require.resolve('electron-chromedriver/chromedriver')
const pathToChromedriverBin = path.resolve(pathToChromedriver, '..', 'bin', 'chromedriver')
const pathToChromedriver = require.resolve(
'electron-chromedriver/chromedriver'
);
const pathToChromedriverBin = path.resolve(
pathToChromedriver,
'..',
'bin',
'chromedriver'
);
const result = cp.spawnSync('install_name_tool', ['-add_rpath', '@executable_path/.', pathToChromedriverBin], {})
const result = cp.spawnSync(
'install_name_tool',
['-add_rpath', '@executable_path/.', pathToChromedriverBin],
{}
);
if (result.status !== 0) {
if (result.stderr.includes('file already has LC_RPATH')) process.exit(0)
process.exit(result.status)
if (result.stderr.includes('file already has LC_RPATH')) process.exit(0);
process.exit(result.status);
}

@@ -7,303 +7,315 @@ // Type definitions for spectron v3.6.0

declare module "spectron" {
import * as Electron from "electron";
import * as WebdriverIO from "webdriverio";
declare module 'spectron' {
import * as Electron from 'electron';
import * as WebdriverIO from 'webdriverio';
interface AccessibilityAuditOptions {
/**
* true to ignore failures with a severity of 'Warning' and only
* include failures with a severity of 'Severe'. Defaults to false.
*/
ignoreWarnings?:boolean;
/**
* Rule code values such as AX_COLOR_01 to ignore failures for.
*/
ignoreRules?:string[];
}
interface AccessibilityAuditOptions {
/**
* true to ignore failures with a severity of 'Warning' and only
* include failures with a severity of 'Severe'. Defaults to false.
*/
ignoreWarnings?: boolean;
interface AccessibilityAuditResult {
/**
* False when the audit has failures
*/
failed:boolean;
/**
* A detailed message about the results
*/
message:string;
/**
* An array of detail objects for each failed rule
*/
results:{
/**
* A unique accessibility rule identifier
*/
code:string;
/**
* Selector path of each HTML element that failed the rule
*/
elements:string[];
/**
* A String message about the failed rule
*/
message:string;
/**
* 'Warning' or 'Severe'
*/
severity:'Warning' | 'Severe';
/**
* URL providing more details about the failed rule
*/
url:string;
}[];
}
export interface SpectronClient extends WebdriverIO.Client<void> {
/**
* Focus a window using its title or URL.
* <webview> tags can also be focused as a separate window.
*/
switchWindow(urlOrTitleToMatch:string):Promise<void>;
/**
* Rule code values such as AX_COLOR_01 to ignore failures for.
*/
ignoreRules?: string[];
}
/**
* Wait until the window is no longer loading.
* Takes an optional timeout in milliseconds that defaults to 5000.
*/
waitUntilWindowLoaded(timeout?:number):Promise<void>;
interface AccessibilityAuditResult {
/**
* False when the audit has failures
*/
failed: boolean;
/**
* Wait until the element matching the given selector contains the given text.
* Takes an optional timeout in milliseconds that defaults to 5000.
*/
waitUntilTextExists(selector:string, text:string, timeout?:number):Promise<void>;
/**
* A detailed message about the results
*/
message: string;
/**
* Gets the number of open windows. <webview> tags are also counted as separate windows.
*/
getWindowCount():Promise<number>;
/**
* Focus a window using its index from the windowHandles() array.
* <webview> tags can also be focused as a separate window.
*/
windowByIndex(index:number):Promise<void>;
/**
* Get the selected text in the current window.
*/
getSelectedText():Promise<string>;
/**
* Gets the console log output from the render process.
* The logs are cleared after they are returned.
*/
getRenderProcessLogs():Promise<WebdriverIO.LogEntry[]>;
/**
* Gets the console log output from the main process.
* The logs are cleared after they are returned.
*/
getMainProcessLogs():Promise<string[]>;
/**
* Run an accessibility audit in the focused window with the specified options.
*/
auditAccessibility(options?:AccessibilityAuditOptions):Promise<AccessibilityAuditResult>;
}
/**
* An array of detail objects for each failed rule
*/
results: {
/**
* A unique accessibility rule identifier
*/
code: string;
export interface SpectronWindow extends Electron.BrowserWindow {
capturePage():Promise<Electron.NativeImage>;
}
/**
* Selector path of each HTML element that failed the rule
*/
elements: string[];
export interface SpectronWebContents extends Electron.WebContents {
savePage(
fullPath:string,
saveType:"HTMLOnly" | "HTMLComplete" | "MHTML",
callback?:(eror:Error) => void
):boolean;
savePage(fullPath:string, saveType:"HTMLOnly" | "HTMLComplete" | "MHTML"):Promise<void>;
savePage(fullPath:string, saveType:"HTMLOnly" | "HTMLComplete" | "MHTML"):any;
executeJavaScript(code:string, userGesture?:boolean):Promise<any>;
}
/**
* A String message about the failed rule
*/
message: string;
type BasicAppSettings = {
/**
* String host name of the launched chromedriver process. Defaults to 'localhost'.
*/
host?:string,
/**
* Number port of the launched chromedriver process. Defaults to 9515.
*/
port?:number,
/**
* Number in milliseconds to wait for application quitting.
* Defaults to 1000 milliseconds.
*/
quitTimeout?:number,
/**
* Number in milliseconds to wait for ChromeDriver to start.
* Defaults to 5000 milliseconds.
*/
startTimeout?:number,
/**
* Number in milliseconds to wait for calls like waitUntilTextExists and
* waitUntilWindowLoaded to complete.
* Defaults to 5000 milliseconds.
*/
waitTimeout?:number,
/**
* Number of retry attempts to make when connecting to ChromeDriver.
* Defaults to 10 attempts.
*/
connectionRetryCount?:number,
/**
* Number in milliseconds to wait for connections to ChromeDriver to be made.
* Defaults to 30000 milliseconds.
*/
connectionRetryTimeout?:number,
/**
* String path to a node executable to launch ChromeDriver with.
* Defaults to process.execPath.
*/
nodePath?:string,
/** String path to the Electron application executable to launch.
* Note: If you want to invoke electron directly with your app's main script then you should
* specify path as electron via electron-prebuilt and specify your app's main script path as
* the first argument in the args array.
*/
path:string,
/**
* Array of arguments to pass to the Electron application.
*/
args?:string[],
/**
* Array of arguments to pass to ChromeDriver.
* See here (https://sites.google.com/a/chromium.org/chromedriver/capabilities) for details
* on the Chrome arguments.
*/
chromeDriverArgs?:string[],
/**
* Object of additional environment variables to set in the launched application.
*/
env?:object,
/**
* String address of a Chrome debugger server to connect to.
*/
debuggerAddress?:string,
/**
* String path to file to store ChromeDriver logs in.
* Setting this option enables --verbose logging when starting ChromeDriver.
*/
chromeDriverLogPath?:string,
/**
* String path to a directory where Webdriver will write logs to.
* Setting this option enables verbose logging from Webdriver.
*/
webdriverLogPath?:string,
/**
* Extra Webdriver options
*/
webdriverOptions?:object,
/**
* Custom property name to use when requiring modules.
* Defaults to require.
* This should only be used if your application deletes the main window.require function
* and assigns it to another property name on window.
*/
requireName?:string
};
type AppConstructorOptions = BasicAppSettings & {
/**
* String path to the working directory to use for the launched application.
* Defaults to process.cwd().
*/
cwd?:string,
};
export type ApplicationSettings = BasicAppSettings & {
/**
* String path to the working directory to use for the launched application.
* Defaults to process.cwd().
*/
workingDirectory?:string,
};
/**
* 'Warning' or 'Severe'
*/
severity: 'Warning' | 'Severe';
/**
* URL providing more details about the failed rule
*/
url: string;
}[];
}
export interface SpectronClient extends WebdriverIO.BrowserObject {
/**
* Start and stop your Electron application.
* Focus a window using its title or URL.
* <webview> tags can also be focused as a separate window.
*/
export class Application {
/**
* Spectron uses WebdriverIO and exposes the managed client property on the created
* Application instances.
* The full client API provided by WebdriverIO can be found here
* http://webdriver.io/api.html
* Several additional commands are provided specific to Electron.
*/
client:SpectronClient;
/**
* The electron property is your gateway to accessing the full Electron API.
* Each Electron module is exposed as a property on the electron property so you can
* think of it as an alias for require('electron') from within your app.
*/
electron:Electron.AllElectron;
/**
* The browserWindow property is an alias for require('electron').remote.getCurrentWindow().
* It provides you access to the current BrowserWindow and contains all the APIs.
* https://electron.atom.io/docs/api/browser-window/
*/
browserWindow:SpectronWindow;
/**
* The webContents property is an alias for
* require('electron').remote.getCurrentWebContents().
* It provides you access to the WebContents for the current window
* and contains all the APIs.
* https://electron.atom.io/docs/api/web-contents/
*/
webContents:SpectronWebContents;
/**
* The mainProcess property is an alias for require('electron').remote.process.
* It provides you access to the main process's process global.
* https://nodejs.org/api/process.html
*/
mainProcess:NodeJS.Process;
/**
*The rendererProcess property is an alias for global.process.
* It provides you access to the main process's process global.
* https://nodejs.org/api/process.html
*/
rendererProcess:NodeJS.Process;
switchWindow(urlOrTitleToMatch: string): Promise<void>;
constructor(options:AppConstructorOptions);
/**
* Wait until the window is no longer loading.
* Takes an optional timeout in milliseconds that defaults to 5000.
*/
waitUntilWindowLoaded(timeout?: number): Promise<void>;
/**
* Starts the application.
* Returns a Promise that will be resolved when the application is ready to use.
* You should always wait for start to complete before running any commands.
*/
start():Promise<Application>;
/**
* Wait until the element matching the given selector contains the given text.
* Takes an optional timeout in milliseconds that defaults to 5000.
*/
waitUntilTextExists(
selector: string,
text: string,
timeout?: number
): Promise<void>;
/**
* Stops the application.
* Returns a Promise that will be resolved once the application has stopped.
*/
stop():Promise<Application>;
/**
* Gets the number of open windows. <webview> tags are also counted as separate windows.
*/
getWindowCount(): Promise<number>;
/**
* Focus a window using its index from the windowHandles() array.
* <webview> tags can also be focused as a separate window.
*/
windowByIndex(index: number): Promise<void>;
/**
* Get the selected text in the current window.
*/
getSelectedText(): Promise<string>;
/**
* Gets the console log output from the render process.
* The logs are cleared after they are returned.
*/
getRenderProcessLogs(): Promise<object[]>;
/**
* Gets the console log output from the main process.
* The logs are cleared after they are returned.
*/
getMainProcessLogs(): Promise<string[]>;
/**
* Stops the application and then starts it.
* Returns a Promise that will be resolved once the application has started again.
*/
restart():Promise<Application>;
/**
* Run an accessibility audit in the focused window with the specified options.
*/
auditAccessibility(
options?: AccessibilityAuditOptions
): Promise<AccessibilityAuditResult>;
}
/**
* Checks to determine if the application is running or not.
*/
isRunning():boolean;
export interface SpectronWindow extends Electron.BrowserWindow {
capturePage(): Promise<Electron.NativeImage>;
}
/**
* Get all the configured options passed to the new Application() constructor.
* This will include the default options values currently being used.
*/
getSettings():ApplicationSettings;
}
export interface SpectronWebContents extends Electron.WebContents {
savePage(
fullPath: string,
saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML',
callback?: (eror: Error) => void
): boolean;
savePage(
fullPath: string,
saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML'
): Promise<void>;
savePage(
fullPath: string,
saveType: 'HTMLOnly' | 'HTMLComplete' | 'MHTML'
): any;
executeJavaScript(code: string, userGesture?: boolean): Promise<any>;
}
type BasicAppSettings = {
/**
* String host name of the launched chromedriver process. Defaults to 'localhost'.
*/
host?: string;
/**
* Number port of the launched chromedriver process. Defaults to 9515.
*/
port?: number;
/**
* Number in milliseconds to wait for application quitting.
* Defaults to 1000 milliseconds.
*/
quitTimeout?: number;
/**
* Number in milliseconds to wait for ChromeDriver to start.
* Defaults to 5000 milliseconds.
*/
startTimeout?: number;
/**
* Number in milliseconds to wait for calls like waitUntilTextExists and
* waitUntilWindowLoaded to complete.
* Defaults to 5000 milliseconds.
*/
waitTimeout?: number;
/**
* Number of retry attempts to make when connecting to ChromeDriver.
* Defaults to 10 attempts.
*/
connectionRetryCount?: number;
/**
* Number in milliseconds to wait for connections to ChromeDriver to be made.
* Defaults to 30000 milliseconds.
*/
connectionRetryTimeout?: number;
/**
* String path to a node executable to launch ChromeDriver with.
* Defaults to process.execPath.
*/
nodePath?: string;
/** String path to the Electron application executable to launch.
* Note: If you want to invoke electron directly with your app's main script then you should
* specify path as electron via electron-prebuilt and specify your app's main script path as
* the first argument in the args array.
*/
path: string;
/**
* Array of arguments to pass to the Electron application.
*/
args?: string[];
/**
* Array of arguments to pass to ChromeDriver.
* See here (https://sites.google.com/a/chromium.org/chromedriver/capabilities) for details
* on the Chrome arguments.
*/
chromeDriverArgs?: string[];
/**
* Object of additional environment variables to set in the launched application.
*/
env?: object;
/**
* String address of a Chrome debugger server to connect to.
*/
debuggerAddress?: string;
/**
* String path to file to store ChromeDriver logs in.
* Setting this option enables --verbose logging when starting ChromeDriver.
*/
chromeDriverLogPath?: string;
/**
* String path to a directory where Webdriver will write logs to.
* Setting this option enables verbose logging from Webdriver.
*/
webdriverLogPath?: string;
/**
* Extra Webdriver options
*/
webdriverOptions?: object;
/**
* Custom property name to use when requiring modules.
* Defaults to require.
* This should only be used if your application deletes the main window.require function
* and assigns it to another property name on window.
*/
requireName?: string;
};
type AppConstructorOptions = BasicAppSettings & {
/**
* String path to the working directory to use for the launched application.
* Defaults to process.cwd().
*/
cwd?: string;
};
export type ApplicationSettings = BasicAppSettings & {
/**
* String path to the working directory to use for the launched application.
* Defaults to process.cwd().
*/
workingDirectory?: string;
};
/**
* Start and stop your Electron application.
*/
export class Application {
/**
* Spectron uses WebdriverIO and exposes the managed client property on the created
* Application instances.
* The full client API provided by WebdriverIO can be found here
* http://webdriver.io/api.html
* Several additional commands are provided specific to Electron.
*/
client: SpectronClient;
/**
* The electron property is your gateway to accessing the full Electron API.
* Each Electron module is exposed as a property on the electron property so you can
* think of it as an alias for require('electron') from within your app.
*/
electron: Electron.AllElectron;
/**
* The browserWindow property is an alias for require('electron').remote.getCurrentWindow().
* It provides you access to the current BrowserWindow and contains all the APIs.
* https://electron.atom.io/docs/api/browser-window/
*/
browserWindow: SpectronWindow;
/**
* The webContents property is an alias for
* require('electron').remote.getCurrentWebContents().
* It provides you access to the WebContents for the current window
* and contains all the APIs.
* https://electron.atom.io/docs/api/web-contents/
*/
webContents: SpectronWebContents;
/**
* The mainProcess property is an alias for require('electron').remote.process.
* It provides you access to the main process's process global.
* https://nodejs.org/api/process.html
*/
mainProcess: NodeJS.Process;
/**
*The rendererProcess property is an alias for global.process.
* It provides you access to the main process's process global.
* https://nodejs.org/api/process.html
*/
rendererProcess: NodeJS.Process;
constructor(options: AppConstructorOptions);
/**
* Starts the application.
* Returns a Promise that will be resolved when the application is ready to use.
* You should always wait for start to complete before running any commands.
*/
start(): Promise<Application>;
/**
* Stops the application.
* Returns a Promise that will be resolved once the application has stopped.
*/
stop(): Promise<Application>;
/**
* Stops the application and then starts it.
* Returns a Promise that will be resolved once the application has started again.
*/
restart(): Promise<Application>;
/**
* Checks to determine if the application is running or not.
*/
isRunning(): boolean;
/**
* Get all the configured options passed to the new Application() constructor.
* This will include the default options values currently being used.
*/
getSettings(): ApplicationSettings;
}
}
{
"name": "spectron",
"version": "11.0.0",
"version": "11.1.0",
"description": "Easily test your Electron apps using ChromeDriver and WebdriverIO.",

@@ -8,7 +8,8 @@ "main": "index.js",

"scripts": {
"lint": "standard",
"lint": "eslint \"**/*.js\" \"**/*.ts\" && prettier --check \"**/*.js\" \"**/*.ts\"",
"prettier:write": "prettier --write \"**/*.js\" \"**/*.ts\"",
"prepack": "check-for-leaks",
"prepush": "check-for-leaks",
"pretest": "tslint lib/spectron.d.ts && tsc lib/spectron.d.ts",
"test": "xvfb-maybe mocha && standard",
"pretest": "tsc lib/spectron.d.ts",
"test": "npm run lint && xvfb-maybe mocha",
"postinstall": "node lib/rpath-fix.js"

@@ -29,3 +30,2 @@ },

"dependencies": {
"@types/webdriverio": "^4.8.0",
"dev-null": "^0.1.1",

@@ -35,5 +35,7 @@ "electron-chromedriver": "^9.0.0",

"split": "^1.0.0",
"webdriverio": "^4.13.0"
"webdriverio": "^6.1.20"
},
"devDependencies": {
"@typescript-eslint/eslint-plugin": "^3.4.0",
"@typescript-eslint/parser": "^3.4.0",
"chai": "^4.2.0",

@@ -44,4 +46,11 @@ "chai-as-promised": "^7.1.1",

"electron": "^9.0.0",
"eslint": "^7.3.1",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"husky": "^4.2.1",
"mocha": "^7.1.2",
"prettier": "^2.0.5",
"standard": "^12.0.1",

@@ -48,0 +57,0 @@ "temp": "^0.9.0",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc