Merge branch 'master' into publish-prebuilt

This commit is contained in:
Vanessa Yuen 2017-08-02 14:57:28 -04:00
commit c8e2e37146
30 changed files with 201 additions and 67 deletions

2
.gitignore vendored
View file

@ -14,6 +14,7 @@
*.vcxproj.filters
*.vcxproj.user
*.xcodeproj
node_modules/
/.idea/
/brightray/brightray.opensdf
/brightray/brightray.sdf
@ -25,7 +26,6 @@
/build/
/dist/
/external_binaries/
node_modules
/out/
/vendor/.gclient
/vendor/debian_jessie_amd64-sysroot/

View file

@ -3,6 +3,9 @@ git:
notifications:
email: false
before_install:
- export BOTO_CONFIG=/dev/null
language: node_js
node_js:
- "4"

View file

@ -57,6 +57,23 @@ void AutoUpdater::OnError(const std::string& message) {
message);
}
void AutoUpdater::OnError(const std::string& message,
const int code, const std::string& domain) {
v8::Locker locker(isolate());
v8::HandleScope handle_scope(isolate());
auto error = v8::Exception::Error(mate::StringToV8(isolate(), message));
auto errorObject = error->ToObject(
isolate()->GetCurrentContext()).ToLocalChecked();
// add two new params for better error handling
errorObject->Set(mate::StringToV8(isolate(), "code"),
v8::Integer::New(isolate(), code));
errorObject->Set(mate::StringToV8(isolate(), "domain"),
mate::StringToV8(isolate(), domain));
mate::EmitEvent(isolate(), GetWrapper(), "error", errorObject, message);
}
void AutoUpdater::OnCheckingForUpdate() {
Emit("checking-for-update");
}

View file

@ -32,6 +32,8 @@ class AutoUpdater : public mate::EventEmitter<AutoUpdater>,
// Delegate implementations.
void OnError(const std::string& error) override;
void OnError(const std::string& message, const int code,
const std::string& domain);
void OnCheckingForUpdate() override;
void OnUpdateAvailable() override;
void OnUpdateNotAvailable() override;

View file

@ -152,7 +152,8 @@ void Initialize(v8::Local<v8::Object> exports,
mate::Dictionary browser_view(
isolate, BrowserView::GetConstructor(isolate)->GetFunction());
browser_view.SetMethod("fromId",
&mate::TrackableObject<BrowserView>::FromWeakMapID);
mate::Dictionary dict(isolate, exports);
dict.Set("BrowserView", browser_view);
}

View file

@ -22,6 +22,9 @@ class Delegate {
// An error happened.
virtual void OnError(const std::string& error) {}
virtual void OnError(const std::string& error, const int code,
const std::string& domain) {}
// Checking to see if there is an update
virtual void OnCheckingForUpdate() {}

View file

@ -104,7 +104,7 @@ void AutoUpdater::CheckForUpdates() {
delegate->OnUpdateNotAvailable();
}
} error:^(NSError *error) {
NSMutableString* failureString =
NSMutableString *failureString =
[NSMutableString stringWithString:error.localizedDescription];
if (error.localizedFailureReason) {
[failureString appendString:@": "];
@ -116,7 +116,8 @@ void AutoUpdater::CheckForUpdates() {
[failureString appendString:@" "];
[failureString appendString:error.localizedRecoverySuggestion];
}
delegate->OnError(base::SysNSStringToUTF8(failureString));
delegate->OnError(base::SysNSStringToUTF8(failureString), error.code,
base::SysNSStringToUTF8(error.domain));
}];
}
@ -125,7 +126,8 @@ void AutoUpdater::QuitAndInstall() {
if (g_update_available) {
[[g_updater relaunchToInstallUpdate] subscribeError:^(NSError* error) {
if (delegate)
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription));
delegate->OnError(base::SysNSStringToUTF8(error.localizedDescription),
error.code, base::SysNSStringToUTF8(error.domain));
}];
} else {
if (delegate)

View file

@ -15,6 +15,7 @@
#include "base/strings/string_util.h"
#include "base/synchronization/lock.h"
#include "base/task_runner.h"
#include "base/threading/thread_task_runner_handle.h"
#include "net/base/file_stream.h"
#include "net/base/filename_util.h"
#include "net/base/io_buffer.h"
@ -119,8 +120,11 @@ void URLRequestAsarJob::Start() {
weak_ptr_factory_.GetWeakPtr(),
base::Owned(meta_info)));
} else {
NotifyStartError(net::URLRequestStatus(net::URLRequestStatus::FAILED,
net::ERR_FILE_NOT_FOUND));
base::ThreadTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::Bind(&URLRequestAsarJob::DidOpen,
weak_ptr_factory_.GetWeakPtr(),
net::ERR_FILE_NOT_FOUND));
}
}

View file

@ -89,7 +89,6 @@ class URLRequestAsarJob : public net::URLRequestJob {
// Callback after fetching file info on a background thread.
void DidFetchMetaInfo(const FileMetaInfo* meta_info);
// Callback after opening file on a background thread.
void DidOpen(int result);

View file

@ -165,6 +165,18 @@ void SetMenuItemID(DbusmenuMenuitem* item, int id) {
g_object_set_data(G_OBJECT(item), "menu-id", GINT_TO_POINTER(id + 1));
}
std::string GetMenuModelStatus(AtomMenuModel* model) {
std::string ret;
for (int i = 0; i < model->GetItemCount(); ++i) {
int status = model->GetTypeAt(i) | (model->IsVisibleAt(i) << 3)
| (model->IsEnabledAt(i) << 4)
| (model->IsItemCheckedAt(i) << 5);
ret += base::StringPrintf(
"%s-%X\n", base::UTF16ToUTF8(model->GetLabelAt(i)).c_str(), status);
}
return ret;
}
} // namespace
GlobalMenuBarX11::GlobalMenuBarX11(NativeWindowViews* window)
@ -309,6 +321,16 @@ void GlobalMenuBarX11::OnSubMenuShow(DbusmenuMenuitem* item) {
if (!model || !GetMenuItemID(item, &id))
return;
// Do not update menu if the submenu has not been changed.
std::string status = GetMenuModelStatus(model);
char* old = static_cast<char*>(g_object_get_data(G_OBJECT(item), "status"));
if (old && status == old)
return;
// Save the new status.
g_object_set_data_full(G_OBJECT(item), "status", g_strdup(status.c_str()),
g_free);
// Clear children.
GList *children = menuitem_take_children(item);
g_list_foreach(children, reinterpret_cast<GFunc>(g_object_unref), NULL);

View file

@ -268,11 +268,10 @@ v8::Local<v8::Value> NativeImage::ToPNG(mate::Arguments* args) {
const SkBitmap bitmap =
image_.AsImageSkia().GetRepresentation(scale_factor).sk_bitmap();
std::unique_ptr<std::vector<unsigned char>> encoded(
new std::vector<unsigned char>());
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, encoded.get());
const char* data = reinterpret_cast<char*>(encoded->data());
size_t size = encoded->size();
std::vector<unsigned char> encoded;
gfx::PNGCodec::EncodeBGRASkBitmap(bitmap, false, &encoded);
const char* data = reinterpret_cast<char*>(encoded.data());
size_t size = encoded.size();
return node::Buffer::Copy(args->isolate(), data, size).ToLocalChecked();
}
@ -292,6 +291,8 @@ v8::Local<v8::Value> NativeImage::ToBitmap(mate::Arguments* args) {
v8::Local<v8::Value> NativeImage::ToJPEG(v8::Isolate* isolate, int quality) {
std::vector<unsigned char> output;
gfx::JPEG1xEncodedDataFromImage(image_, quality, &output);
if (output.empty())
return node::Buffer::New(isolate, 0).ToLocalChecked();
return node::Buffer::Copy(
isolate,
reinterpret_cast<const char*>(&output.front()),

View file

@ -56,7 +56,8 @@ struct V8FunctionInvoker<v8::Local<v8::Value>(ArgTypes...)> {
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args { ConvertToV8(isolate, raw)... };
v8::Local<v8::Value> ret(holder->Call(holder, args.size(), &args.front()));
v8::Local<v8::Value> ret(holder->Call(
holder, args.size(), args.empty() ? nullptr : &args.front()));
return handle_scope.Escape(ret);
}
};
@ -76,7 +77,8 @@ struct V8FunctionInvoker<void(ArgTypes...)> {
v8::Local<v8::Context> context = holder->CreationContext();
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args { ConvertToV8(isolate, raw)... };
holder->Call(holder, args.size(), &args.front());
holder->Call(
holder, args.size(), args.empty() ? nullptr : &args.front());
}
};
@ -97,8 +99,8 @@ struct V8FunctionInvoker<ReturnType(ArgTypes...)> {
v8::Context::Scope context_scope(context);
std::vector<v8::Local<v8::Value>> args { ConvertToV8(isolate, raw)... };
v8::Local<v8::Value> result;
auto maybe_result =
holder->Call(context, holder, args.size(), &args.front());
auto maybe_result = holder->Call(
context, holder, args.size(), args.empty() ? nullptr : &args.front());
if (maybe_result.ToLocal(&result))
Converter<ReturnType>::FromV8(isolate, result, &ret);
return ret;

View file

@ -132,7 +132,12 @@ void AtomRendererClient::WillReleaseScriptContext(
node_bindings_->set_uv_env(nullptr);
// Destroy the node environment.
node::FreeEnvironment(env);
// This is disabled because pending async tasks may still use the environment
// and would cause crashes later. Node does not seem to clear all async tasks
// when the environment is destroyed.
// node::FreeEnvironment(env);
// AtomBindings is tracking node environments.
atom_bindings_->EnvironmentDestroyed(env);
}

View file

@ -203,12 +203,12 @@
'BasicRuntimeChecks': '3', # 3 = all checks enabled, 0 = off
},
'VCLinkerTool': {
'OptimizeReferences': 2, # /OPT:REF
'OptimizeReferences': 2, # /OPT:REF
'EnableCOMDATFolding': 2, # /OPT:ICF
},
},
'conditions': [
['OS=="linux"', {
['OS=="linux" and target_arch=="x64"', {
'defines': [
'_GLIBCXX_DEBUG',
],

View file

@ -1,4 +1,4 @@
# Class: BrowserView
## Class: BrowserView
> Create and control views.
@ -38,6 +38,14 @@ view.webContents.loadURL('https://electron.atom.io')
* `options` Object (optional)
* `webPreferences` Object (optional) - See [BrowserWindow](browser-window.md).
### Static Methods
#### `BrowserView.fromId(id)`
* `id` Integer
Returns `BrowserView` - The view with the given `id`.
### Instance Properties
Objects created with `new BrowserView` have the following properties:

View file

@ -1,4 +1,5 @@
# Class: Menu
## Class: Menu
> Create native application menus and context menus.

View file

@ -22,12 +22,12 @@ Process: [Main](../tutorial/quick-start.md#main-process)
The following properties are available on instances of `TouchBarScrubber`:
#### `touchBarSegmentedControl.items`
#### `touchBarScrubber.items`
A `ScrubberItem[]` array representing the items in this scrubber. Updating this value immediately
updates the control in the touch bar. Updating deep properties inside this array **does not update the touch bar**.
#### `touchBarSegmentedControl.selectedStyle`
#### `touchBarScrubber.selectedStyle`
A `String` representing the style that selected items in the scrubber should have. Updating this value immediately
updates the control in the touch bar. Possible values:
@ -36,7 +36,7 @@ updates the control in the touch bar. Possible values:
* `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`
* `null` - Actually null, not a string, removes all styles
#### `touchBarSegmentedControl.overlayStyle`
#### `touchBarScrubber.overlayStyle`
A `String` representing the style that selected items in the scrubber should have. This style is overlayed on top
of the scrubber item instead of being placed behind it. Updating this value immediately updates the control in the
@ -46,12 +46,12 @@ touch bar. Possible values:
* `outline` - Maps to `[NSScrubberSelectionStyle outlineOverlayStyle]`
* `null` - Actually null, not a string, removes all styles
#### `touchBarSegmentedControl.showArrowButtons`
#### `touchBarScrubber.showArrowButtons`
A `Boolean` representing whether to show the left / right selection arrows in this scrubber. Updating this value
immediately updates the control in the touch bar.
#### `touchBarSegmentedControl.mode`
#### `touchBarScrubber.mode`
A `String` representing the mode of this scrubber. Updating this value immediately
updates the control in the touch bar. Possible values:
@ -59,7 +59,7 @@ updates the control in the touch bar. Possible values:
* `fixed` - Maps to `NSScrubberModeFixed`
* `free` - Maps to `NSScrubberModeFree`
#### `touchBarSegmentedControl.continuous`
#### `touchBarScrubber.continuous`
A `Boolean` representing whether this scrubber is continuous or not. Updating this value immediately
updates the control in the touch bar.

View file

@ -1,4 +1,4 @@
# Class: TouchBar
## Class: TouchBar
> Create TouchBar layouts for native macOS applications

View file

@ -8,10 +8,10 @@ Follow the guidelines below for building Electron on Linux.
* Python 2.7.x. Some distributions like CentOS 6.x still use Python 2.6.x
so you may need to check your Python version with `python -V`.
* Node.js. There are various ways to install Node. You can download
source code from [Node.js](http://nodejs.org) and compile from source.
source code from [nodejs.org](http://nodejs.org) and compile it.
Doing so permits installing Node on your own home directory as a standard user.
Or try repositories such as [NodeSource](https://nodesource.com/blog/nodejs-v012-iojs-and-the-nodesource-linux-repositories).
* Clang 3.4 or later.
* [clang](https://clang.llvm.org/get_started.html) 3.4 or later.
* Development headers of GTK+ and libnotify.
On Ubuntu, install the following libraries:
@ -48,7 +48,7 @@ managers such as pacman. Or one can compile from source code.
## Getting the Code
```bash
$ git clone https://github.com/electron/electron.git
$ git clone https://github.com/electron/electron
```
## Bootstrapping
@ -60,7 +60,7 @@ Downloading certain files can take a long time. Notice that we are using
```bash
$ cd electron
$ ./script/bootstrap.py -v
$ ./script/bootstrap.py --verbose
```
### Cross compilation
@ -73,7 +73,7 @@ $ sudo apt-get install libc6-dev-armhf-cross linux-libc-dev-armhf-cross \
g++-arm-linux-gnueabihf
```
And to cross compile for `arm` or `ia32` targets, you should pass the
And to cross-compile for `arm` or `ia32` targets, you should pass the
`--target_arch` parameter to the `bootstrap.py` script:
```bash
@ -98,7 +98,7 @@ $ ./script/create-dist.py
```
This will put a working distribution with much smaller file sizes in
the `dist` directory. After running the create-dist.py script, you
the `dist` directory. After running the `create-dist.py` script, you
may want to remove the 1.3+ gigabyte binary which is still in `out/R`.
You can also build the `Debug` target only:
@ -143,17 +143,29 @@ See [Build System Overview: Tests](build-system-overview.md#tests)
## Advanced topics
The default building configuration is targeted for major desktop Linux
distributions, to build for a specific distribution or device, following
distributions. To build for a specific distribution or device, the following
information may help you.
### Building `libchromiumcontent` locally
To avoid using the prebuilt binaries of `libchromiumcontent`, you can pass the
`--build_libchromiumcontent` switch to `bootstrap.py` script:
To avoid using the prebuilt binaries of `libchromiumcontent`, you can build `libchromiumcontent` locally. To do so, follow these steps:
1. Install [depot_tools](https://chromium.googlesource.com/chromium/src/+/master/docs/linux_build_instructions.md#Install)
2. Install [additional build dependencies](https://chromium.googlesource.com/chromium/src/+/master/docs/linux_build_instructions.md#Install-additional-build-dependencies)
3. Fetch the git submodules:
```bash
$ git submodule update --init --recursive
```
4. Copy the .gclient config file
```bash
$ ./script/bootstrap.py -v --build_libchromiumcontent
```
```bash
$ cp vendor/libchromiumcontent/.gclient .
```
5. Pass the `--build_libchromiumcontent` switch to `bootstrap.py` script:
```bash
$ ./script/bootstrap.py -v --build_libchromiumcontent
```
Note that by default the `shared_library` configuration is not built, so you can
only build `Release` version of Electron if you use this mode:
@ -164,10 +176,12 @@ $ ./script/build.py -c R
### Using system `clang` instead of downloaded `clang` binaries
By default Electron is built with prebuilt `clang` binaries provided by Chromium
project. If for some reason you want to build with the `clang` installed in your
system, you can call `bootstrap.py` with `--clang_dir=<path>` switch. By passing
it the build script will assume the `clang` binaries reside in `<path>/bin/`.
By default Electron is built with prebuilt
[`clang`](https://clang.llvm.org/get_started.html) binaries provided by the
Chromium project. If for some reason you want to build with the `clang`
installed in your system, you can call `bootstrap.py` with `--clang_dir=<path>`
switch. By passing it the build script will assume the `clang` binaries reside
in `<path>/bin/`.
For example if you installed `clang` under `/user/local/bin/clang`:
@ -176,7 +190,7 @@ $ ./script/bootstrap.py -v --build_libchromiumcontent --clang_dir /usr/local
$ ./script/build.py -c R
```
### Using other compilers other than `clang`
### Using compilers other than `clang`
To build Electron with compilers like `g++`, you first need to disable `clang`
with `--disable_clang` switch first, and then set `CC` and `CXX` environment
@ -209,4 +223,4 @@ custom the building configurations:
* `LDFLAGS`
The environment variables have to be set when executing the `bootstrap.py`
script, it won't work in the `build.py` script.
script, it won't work in the `build.py` script.

View file

@ -12,11 +12,9 @@ The ASAR format was created primarily to improve performance on Windows... TODO
### Brightray
Brightray is a static library that makes [libchromiumcontent]
easier to use in applications.
Brightray is a low-level dependency of Electron that does not concern the
majority of Electron users.
Brightray [was](https://github.com/electron-archive/brightray) a static library
that made [libchromiumcontent] easier to use in applications. It is now
deprecated and has been merged into Electron's codebase.
### CRT
@ -44,8 +42,10 @@ serialized JSON messages between the [main] and [renderer] processes.
### libchromiumcontent
A single, shared library that includes the Chromium Content module and all its
dependencies (e.g., Blink, [V8], etc.).
A shared library that includes the [Chromium Content module] and all its
dependencies (e.g., Blink, [V8], etc.). Also referred to as "libcc".
- [github.com/electron/libchromiumcontent](https://github.com/electron/libchromiumcontent)
### main process
@ -142,8 +142,17 @@ available in "core".
### V8
V8 is Google's open source JavaScript engine. It is written in C++ and is
used in Google Chrome. V8 can run
standalone, or can be embedded into any C++ application.
used in Google Chrome. V8 can run standalone, or can be embedded into any C++ application.
Electron builds V8 as part of Chromium and then points Node to that V8 when
building it.
V8's version numbers always correspond to those of Google Chrome. Chrome 59
includes V8 5.9, Chrome 58 includes V8 5.8, etc.
- [developers.google.com/v8](https://developers.google.com/v8)
- [nodejs.org/api/v8.html](https://nodejs.org/api/v8.html)
- [docs/development/v8-development.md](development/v8-development.md)
### webview
@ -157,11 +166,12 @@ embedded content.
[addons]: https://nodejs.org/api/addons.html
[asar]: https://github.com/electron/asar
[autoUpdater]: api/auto-updater.md
[Chromium Content module]: https://www.chromium.org/developers/content-module
[electron-builder]: https://github.com/electron-userland/electron-builder
[libchromiumcontent]: #libchromiumcontent
[Mac App Store Submission Guide]: tutorial/mac-app-store-submission-guide.md
[main]: #main-process
[renderer]: #renderer-process
[Using Native Node Modules]: tutorial/using-native-node-modules.md
[userland]: #userland
[Using Native Node Modules]: tutorial/using-native-node-modules.md
[V8]: #v8

View file

@ -292,7 +292,7 @@ TouchBar.TouchBarScrubber = class TouchBarScrubber extends TouchBarItem {
this._addLiveProperty('overlayStyle', overlayStyle || null)
this._addLiveProperty('showArrowButtons', showArrowButtons || false)
this._addLiveProperty('mode', mode || 'free')
this._addLiveProperty('continuous', continuous || true)
this._addLiveProperty('continuous', typeof continuous === 'undefined' ? true : continuous)
if (typeof select === 'function' || typeof highlight === 'function') {
if (select == null) select = () => {}

View file

@ -18,14 +18,20 @@ LINUX_DEPS = [
'libnotify-dev',
'libnss3-dev',
'libxtst-dev',
]
LINUX_DEPS_NO_ARM = [
'gcc-multilib',
'g++-multilib',
]
LINUX_DEPS_ARM = [
'libc6-dev-armhf-cross',
'linux-libc-dev-armhf-cross',
'g++-arm-linux-gnueabihf',
'binutils-aarch64-linux-gnu',
'libc6-dev-armhf-cross',
'linux-libc-dev-armhf-cross',
'g++-arm-linux-gnueabihf',
'g++-4.8-multilib-arm-linux-gnueabihf',
'gcc-4.8-multilib-arm-linux-gnueabihf',
]
@ -53,6 +59,8 @@ def main():
deps = LINUX_DEPS
if target_arch == 'arm':
deps += LINUX_DEPS_ARM
else:
deps += LINUX_DEPS_NO_ARM
execute(['sudo', 'apt-get', 'install'] + deps)
execute(['sh', '-e', '/etc/init.d/xvfb', 'start'])

View file

@ -81,6 +81,14 @@ def parse_args():
help='Run tests in CI mode',
action='store_true',
required=False)
parser.add_argument('-g', '--grep',
help='Only run tests matching <pattern>',
metavar='pattern',
required=False)
parser.add_argument('-i', '--invert',
help='Inverts --grep matches',
action='store_true',
required=False)
parser.add_argument('-v', '--verbose',
action='store_true',
help='Prints the output of the subprocesses')

View file

@ -208,7 +208,7 @@ describe('app module', function () {
})
})
describe('app.importCertificate', function () {
xdescribe('app.importCertificate', function () {
if (process.platform !== 'linux') return
var w = null
@ -405,7 +405,7 @@ describe('app module', function () {
})
})
describe('select-client-certificate event', function () {
xdescribe('select-client-certificate event', function () {
let w = null
beforeEach(function () {

View file

@ -100,4 +100,14 @@ describe('BrowserView module', function () {
assert.ok(!view.webContents.getOwnerBrowserWindow())
})
})
describe('BrowserView.fromId()', function () {
it('returns the view with given id', function () {
view = new BrowserView()
w.setBrowserView(view)
assert.notEqual(view.id, null)
let view2 = BrowserView.fromId(view.id)
assert.equal(view2.webContents.id, view.webContents.id)
})
})
})

View file

@ -1144,13 +1144,16 @@ describe('BrowserWindow module', function () {
w.loadURL('file://' + path.join(fixtures, 'api', 'sandbox.html?window-events'))
})
it('works for web contents events', function (done) {
it('works for stop events', function (done) {
waitForEvents(w.webContents, [
'did-navigate',
'did-fail-load',
'did-stop-loading'
], done)
w.loadURL('file://' + path.join(fixtures, 'api', 'sandbox.html?webcontents-stop'))
})
it('works for web contents events', function (done) {
waitForEvents(w.webContents, [
'did-finish-load',
'did-frame-finish-load',

View file

@ -12,7 +12,7 @@ const {remote} = require('electron')
const {app, BrowserWindow, crashReporter} = remote.require('electron')
describe('crashReporter module', function () {
if (process.mas) {
if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) {
return
}

View file

@ -590,6 +590,12 @@ describe('webContents module', function () {
})
describe('destroy()', () => {
// Destroying webContents in its event listener is going to crash when
// Electron is built in Debug mode.
if (process.platform !== 'darwin') {
return
}
let server
before(function (done) {

View file

@ -62,16 +62,17 @@
if (query.invert) mocha.invert();
// Read all test files.
var walker = require('walkdir').walk(require('path').dirname(__dirname), {
var walker = require('walkdir').walk(path.dirname(__dirname), {
no_recurse: true
});
walker.on('file', function(file) {
if (/-spec\.js$/.test(file))
if (/-spec\.js$/.test(file) && !file.includes('api-crash-reporter-spec.js'))
mocha.addFile(file);
});
walker.on('end', function() {
mocha.addFile(path.resolve(__dirname, '..', 'api-crash-reporter-spec.js'))
var runner = mocha.run(function() {
if (isCi && runner.hasOnly) {
try {

View file

@ -141,6 +141,10 @@ app.on('ready', function () {
})
if (chosen === 0) window.destroy()
})
window.webContents.on('crashed', function () {
console.error('Renderer process crashed')
process.exit(1)
})
// For session's download test, listen 'will-download' event in browser, and
// reply the result to renderer for verifying