From 9fecf4b2f73c1f6c78c69846c568bb7d69d3919a Mon Sep 17 00:00:00 2001 From: robbix1206 Date: Sat, 16 Sep 2017 14:03:09 +0200 Subject: [PATCH 001/185] Add npx command for node version 8.2.0 and later --- docs/tutorial/quick-start.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index a641a0d0c75..c4e136c0f8b 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -175,6 +175,12 @@ electron . If you've installed it locally, then run: +### Node v8.2.0 and later + +``` +$ npx electron . +``` + #### macOS / Linux ```bash From 564ca27679dcd5b1da62693026c1e444547a3d89 Mon Sep 17 00:00:00 2001 From: robbix1206 Date: Sat, 16 Sep 2017 14:09:31 +0200 Subject: [PATCH 002/185] Forget a # --- docs/tutorial/quick-start.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index c4e136c0f8b..c958843b2f4 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -175,7 +175,7 @@ electron . If you've installed it locally, then run: -### Node v8.2.0 and later +#### Node v8.2.0 and later ``` $ npx electron . From 0bcc5d37ab5c535230b51e29e8aa6da6313bae47 Mon Sep 17 00:00:00 2001 From: robbix1206 Date: Sat, 16 Sep 2017 15:37:26 +0200 Subject: [PATCH 003/185] Put npx as last option --- docs/tutorial/quick-start.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/tutorial/quick-start.md b/docs/tutorial/quick-start.md index c958843b2f4..835a75a9775 100644 --- a/docs/tutorial/quick-start.md +++ b/docs/tutorial/quick-start.md @@ -175,12 +175,6 @@ electron . If you've installed it locally, then run: -#### Node v8.2.0 and later - -``` -$ npx electron . -``` - #### macOS / Linux ```bash @@ -193,6 +187,12 @@ $ ./node_modules/.bin/electron . $ .\node_modules\.bin\electron . ``` +#### Node v8.2.0 and later + +``` +$ npx electron . +``` + ### Manually Downloaded Electron Binary If you downloaded Electron manually, you can also use the included From 26e6f2c46c672e4fa7bc16a92191f0b5e5190e03 Mon Sep 17 00:00:00 2001 From: Boik Date: Sun, 17 Sep 2017 11:27:03 +0800 Subject: [PATCH 004/185] use textContent instead innerHTML to remediateDOM based XSS vulnerbilities --- lib/renderer/content-scripts-injector.js | 39 ++++++++++++++++++------ 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/lib/renderer/content-scripts-injector.js b/lib/renderer/content-scripts-injector.js index d26802c8a8e..d23311d5ec2 100644 --- a/lib/renderer/content-scripts-injector.js +++ b/lib/renderer/content-scripts-injector.js @@ -5,7 +5,7 @@ const {runInThisContext} = require('vm') // https://developer.chrome.com/extensions/match_patterns const matchesPattern = function (pattern) { if (pattern === '') return true - const regexp = new RegExp('^' + pattern.replace(/\*/g, '.*') + '$') + const regexp = new RegExp(`^${pattern.replace(/\*/g, '.*')}$`) const url = `${location.protocol}//${location.host}${location.pathname}` return url.match(regexp) } @@ -23,12 +23,30 @@ const runContentScript = function (extensionId, url, code) { return compiledWrapper.call(this, context.chrome) } +const runStylesheet = function (url, code) { + const wrapper = `(function (code) { + function init() { + var styleElement = document.createElement('style'); + styleElement.setAttribute('type', 'text/css'); + styleElement.textContent = code; + document.head.append(styleElement); + } + document.addEventListener('DOMContentLoaded', init); + })`; + const compiledWrapper = runInThisContext(wrapper, { + filename: url, + lineOffset: 1, + displayErrors: true, + }); + return compiledWrapper.call(this, code); +} + // Run injected scripts. // https://developer.chrome.com/extensions/content_scripts const injectContentScript = function (extensionId, script) { if (!script.matches.some(matchesPattern)) return - if (script.js) { + if (script.js.length) { for (const {url, code} of script.js) { const fire = runContentScript.bind(window, extensionId, url, code) if (script.runAt === 'document_start') { @@ -41,13 +59,16 @@ const injectContentScript = function (extensionId, script) { } } - if (script.css) { - for (const {code} of script.css) { - process.once('document-end', () => { - var node = document.createElement('style') - node.innerHTML = code - window.document.body.appendChild(node) - }) + if (script.css.length) { + for (const {url, code} of script.css) { + const fire = runStylesheet.bind(window, url, code) + if (script.runAt === 'document_start') { + process.once('document-start', fire) + } else if (script.runAt === 'document_end') { + process.once('document-end', fire) + } else if (script.runAt === 'document_idle') { + document.addEventListener('DOMContentLoaded', fire) + } } } } From d86724f17afab087cedcce1786493d1e526c8ec4 Mon Sep 17 00:00:00 2001 From: Boik Date: Sun, 17 Sep 2017 13:56:22 +0800 Subject: [PATCH 005/185] code improvement --- lib/renderer/content-scripts-injector.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/lib/renderer/content-scripts-injector.js b/lib/renderer/content-scripts-injector.js index d23311d5ec2..5925b941d5e 100644 --- a/lib/renderer/content-scripts-injector.js +++ b/lib/renderer/content-scripts-injector.js @@ -14,7 +14,7 @@ const matchesPattern = function (pattern) { const runContentScript = function (extensionId, url, code) { const context = {} require('./chrome-api').injectTo(extensionId, false, context) - const wrapper = `(function (chrome) {\n ${code}\n })` + const wrapper = `((chrome) => {\n ${code}\n })` const compiledWrapper = runInThisContext(wrapper, { filename: url, lineOffset: 1, @@ -24,10 +24,9 @@ const runContentScript = function (extensionId, url, code) { } const runStylesheet = function (url, code) { - const wrapper = `(function (code) { + const wrapper = `((code) => { function init() { - var styleElement = document.createElement('style'); - styleElement.setAttribute('type', 'text/css'); + const styleElement = document.createElement('style'); styleElement.textContent = code; document.head.append(styleElement); } @@ -46,27 +45,27 @@ const runStylesheet = function (url, code) { const injectContentScript = function (extensionId, script) { if (!script.matches.some(matchesPattern)) return - if (script.js.length) { + if (script.js) { for (const {url, code} of script.js) { const fire = runContentScript.bind(window, extensionId, url, code) if (script.runAt === 'document_start') { process.once('document-start', fire) } else if (script.runAt === 'document_end') { process.once('document-end', fire) - } else if (script.runAt === 'document_idle') { + } else { document.addEventListener('DOMContentLoaded', fire) } } } - if (script.css.length) { + if (script.css) { for (const {url, code} of script.css) { const fire = runStylesheet.bind(window, url, code) if (script.runAt === 'document_start') { process.once('document-start', fire) } else if (script.runAt === 'document_end') { process.once('document-end', fire) - } else if (script.runAt === 'document_idle') { + } else { document.addEventListener('DOMContentLoaded', fire) } } From 16499358b348330f1d9895615a65155b53d8cddc Mon Sep 17 00:00:00 2001 From: Boik Date: Sun, 17 Sep 2017 14:09:12 +0800 Subject: [PATCH 006/185] fix lint --- lib/renderer/content-scripts-injector.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/renderer/content-scripts-injector.js b/lib/renderer/content-scripts-injector.js index 5925b941d5e..5bc41780af9 100644 --- a/lib/renderer/content-scripts-injector.js +++ b/lib/renderer/content-scripts-injector.js @@ -31,13 +31,13 @@ const runStylesheet = function (url, code) { document.head.append(styleElement); } document.addEventListener('DOMContentLoaded', init); - })`; + })` const compiledWrapper = runInThisContext(wrapper, { filename: url, lineOffset: 1, - displayErrors: true, - }); - return compiledWrapper.call(this, code); + displayErrors: true + }) + return compiledWrapper.call(this, code) } // Run injected scripts. From ff978176684d2acf62a619e4d9e4cb0d71f3ccbe Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Mon, 25 Sep 2017 14:02:59 -0700 Subject: [PATCH 007/185] Add `string` to notification doc Tiny fix: The docs suggest `NativeImage` for `icon`, but a string is also allowed. --- docs/api/notification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/notification.md b/docs/api/notification.md index 6dab356bbda..402bbb69db7 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -34,7 +34,7 @@ Returns `Boolean` - Whether or not desktop notifications are supported on the cu * `subtitle` String - (optional) A subtitle for the notification, which will be displayed below the title. _macOS_ * `body` String - The body text of the notification, which will be displayed below the title or subtitle * `silent` Boolean - (optional) Whether or not to emit an OS notification noise when showing the notification - * `icon` [NativeImage](native-image.md) - (optional) An icon to use in the notification + * `icon` (String | [NativeImage](native-image.md)) - (optional) An icon to use in the notification * `hasReply` Boolean - (optional) Whether or not to add an inline reply option to the notification. _macOS_ * `replyPlaceholder` String - (optional) The placeholder to write in the inline reply input field. _macOS_ * `sound` String - (optional) The name of the sound file to play when the notification is shown. _macOS_ From 54563dc94ccb1aea8a29b22739eff309bca21bbc Mon Sep 17 00:00:00 2001 From: John Kleinschmidt Date: Wed, 4 Oct 2017 10:33:27 -0400 Subject: [PATCH 008/185] Add logic to retry github uploads When doing release, sometimes the GitHub upload fails, so try to retry it once before bailing. --- script/upload-to-github.js | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/script/upload-to-github.js b/script/upload-to-github.js index 82374ef49b6..0308b84a43d 100644 --- a/script/upload-to-github.js +++ b/script/upload-to-github.js @@ -13,9 +13,22 @@ let githubOpts = { filePath: filePath, name: fileName } -github.repos.uploadAsset(githubOpts).then(() => { - process.exit() -}).catch((err) => { - console.log(`Error uploading ${fileName} to GitHub:`, err) - process.exitCode = 1 -}) + +let retry = true + +function uploadToGitHub () { + github.repos.uploadAsset(githubOpts).then(() => { + process.exit() + }).catch((err) => { + if (retry) { + console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err) + retry = false + uploadToGitHub() + } else { + console.log(`Error retrying uploading ${fileName} to GitHub:`, err) + process.exitCode = 1 + } + }) +} + +uploadToGitHub() From 0ae12c2b3d4888afd89c49bd9f77a8738d2c967c Mon Sep 17 00:00:00 2001 From: John Kleinschmidt Date: Thu, 5 Oct 2017 16:31:54 -0400 Subject: [PATCH 009/185] Add success message Also increase retries to 5 attempts. --- script/upload-to-github.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/script/upload-to-github.js b/script/upload-to-github.js index 0308b84a43d..45b82a285b2 100644 --- a/script/upload-to-github.js +++ b/script/upload-to-github.js @@ -2,6 +2,10 @@ const GitHub = require('github') const github = new GitHub() github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN}) +if (process.argv.length < 5) { + console.log('Usage: upload-to-github filePath fileName releaseId') + process.exit(1) +} let filePath = process.argv[2] let fileName = process.argv[3] let releaseId = process.argv[4] @@ -14,15 +18,16 @@ let githubOpts = { name: fileName } -let retry = true +let retry = 0 function uploadToGitHub () { github.repos.uploadAsset(githubOpts).then(() => { + console.log(`Successfully uploaded ${fileName} to GitHub.`) process.exit() }).catch((err) => { - if (retry) { + if (retry < 4) { console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err) - retry = false + retry++ uploadToGitHub() } else { console.log(`Error retrying uploading ${fileName} to GitHub:`, err) From 8e1945f76812bb020867e7a370a2f232682bef69 Mon Sep 17 00:00:00 2001 From: Antoine Date: Thu, 5 Oct 2017 14:11:58 -0700 Subject: [PATCH 010/185] :apple: skip tabbing category if macOS < Sierra Previously, the macro was ensuring the` MAC_OS_X_VERSION_10_12` was not defined to decide to compile a `NSWindow` category back porting native tabs or not. This patch ensures to compile the `NSWindow` category only if the min required version is lesser than 1012 (`MAC_OS_X_VERSION_10_12`) --- atom/browser/native_window_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 252df0ebb20..4a6fa9fe2bb 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -465,7 +465,7 @@ bool ScopedDisableResize::disable_resize_ = false; @end -#if !defined(MAC_OS_X_VERSION_10_12) +#if MAC_OS_X_VERSION_MIN_REQUIRED < 1012 // MAC_OS_X_VERSION_10_12 enum { NSWindowTabbingModeDisallowed = 2 From 5e6b683cfb432b02d567eefdb9ee7921fbf4bad0 Mon Sep 17 00:00:00 2001 From: Antoine Date: Thu, 5 Oct 2017 15:57:27 -0700 Subject: [PATCH 011/185] fixed: trying to fix the build --- atom/browser/native_window_mac.mm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/atom/browser/native_window_mac.mm b/atom/browser/native_window_mac.mm index 4a6fa9fe2bb..80554a37a6d 100644 --- a/atom/browser/native_window_mac.mm +++ b/atom/browser/native_window_mac.mm @@ -4,6 +4,7 @@ #include "atom/browser/native_window_mac.h" +#include #include #include @@ -465,7 +466,7 @@ bool ScopedDisableResize::disable_resize_ = false; @end -#if MAC_OS_X_VERSION_MIN_REQUIRED < 1012 // MAC_OS_X_VERSION_10_12 +#if !defined(AVAILABLE_MAC_OS_X_VERSION_10_12_AND_LATER) enum { NSWindowTabbingModeDisallowed = 2 @@ -482,7 +483,7 @@ enum { - (IBAction)toggleTabBar:(id)sender; @end -#endif // MAC_OS_X_VERSION_10_12 +#endif @interface AtomNSWindow : EventDispatchingWindow { @private From e5d4574d3a98bad4161e6f80613145d0bacafe2a Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 7 Oct 2017 14:45:46 +1100 Subject: [PATCH 012/185] Use NSUserNotification identifiers to uniquely find the correct notification from CocoaNotification --- brightray/browser/mac/cocoa_notification.mm | 4 ++++ brightray/browser/mac/notification_presenter_mac.mm | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/brightray/browser/mac/cocoa_notification.mm b/brightray/browser/mac/cocoa_notification.mm index cd7b69ef405..5e51974b3e4 100644 --- a/brightray/browser/mac/cocoa_notification.mm +++ b/brightray/browser/mac/cocoa_notification.mm @@ -13,6 +13,8 @@ namespace brightray { +int g_identifier_ = 1; + CocoaNotification::CocoaNotification(NotificationDelegate* delegate, NotificationPresenter* presenter) : Notification(delegate, presenter) { @@ -29,6 +31,8 @@ void CocoaNotification::Show(const NotificationOptions& options) { [notification_ setTitle:base::SysUTF16ToNSString(options.title)]; [notification_ setSubtitle:base::SysUTF16ToNSString(options.subtitle)]; [notification_ setInformativeText:base::SysUTF16ToNSString(options.msg)]; + [notification_ setIdentifier:[NSString stringWithFormat:@"%s%d", "ElectronNotification", g_identifier_]]; + g_identifier_++; if ([notification_ respondsToSelector:@selector(setContentImage:)] && !options.icon.drawsNothing()) { diff --git a/brightray/browser/mac/notification_presenter_mac.mm b/brightray/browser/mac/notification_presenter_mac.mm index 5afadab7ebb..b8903057346 100644 --- a/brightray/browser/mac/notification_presenter_mac.mm +++ b/brightray/browser/mac/notification_presenter_mac.mm @@ -18,7 +18,8 @@ CocoaNotification* NotificationPresenterMac::GetNotification( NSUserNotification* ns_notification) { for (Notification* notification : notifications()) { auto native_notification = static_cast(notification); - if ([native_notification->notification() isEqual:ns_notification]) + if ([native_notification->notification().identifier + isEqual:ns_notification.identifier]) return native_notification; } return nullptr; From 6326c6727ee8302e957975cfe4a45a88925a4720 Mon Sep 17 00:00:00 2001 From: Yuya Ochiai Date: Sat, 7 Oct 2017 01:31:41 +0900 Subject: [PATCH 013/185] Add did-attach-webview event --- docs/api/web-contents.md | 10 ++++++++++ lib/browser/guest-view-manager.js | 3 ++- .../fixtures/pages/webview-did-attach-event.html | 16 ++++++++++++++++ spec/webview-spec.js | 15 +++++++++++++++ 4 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 spec/fixtures/pages/webview-did-attach-event.html diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index c356e8eac61..07ccefeff8e 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -581,6 +581,16 @@ that can't be set via `` attributes. **Note:** The specified `preload` script option will be appear as `preloadURL` (not `preload`) in the `webPreferences` object emitted with this event. +#### Event: 'did-attach-webview' + +Returns: + +* `event` Event +* `webContents` WebContents - The guest web contents that is used by the + ``. + +Emitted when a `` has been attached to this web contents. + ### Instance Methods #### `contents.loadURL(url[, options])` diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index 731f82838af..0338b776f89 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -76,7 +76,7 @@ const createGuest = function (embedder, params) { watchEmbedder(embedder) // Init guest web view after attached. - guest.on('did-attach', function () { + guest.on('did-attach', function (event) { params = this.attachParams delete this.attachParams @@ -114,6 +114,7 @@ const createGuest = function (embedder, params) { this.loadURL(params.src, opts) } guest.allowPopups = params.allowpopups + embedder.emit('did-attach-webview', event, guest) }) const sendToEmbedder = (channel, ...args) => { diff --git a/spec/fixtures/pages/webview-did-attach-event.html b/spec/fixtures/pages/webview-did-attach-event.html new file mode 100644 index 00000000000..4c6a0b9e500 --- /dev/null +++ b/spec/fixtures/pages/webview-did-attach-event.html @@ -0,0 +1,16 @@ + + + + + + + + + + diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 1d56b430733..656465f034e 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -1183,6 +1183,21 @@ describe(' tag', function () { }) }) + describe('did-attach-webview event', () => { + it('is emitted when a webview has been attached', (done) => { + w = new BrowserWindow({ + show: false + }) + w.webContents.on('did-attach-webview', (event, webContents) => { + ipcMain.once('webview-dom-ready', (event, id) => { + assert.equal(webContents.id, id) + done() + }) + }) + w.loadURL('file://' + fixtures + '/pages/webview-did-attach-event.html') + }) + }) + it('loads devtools extensions registered on the parent window', function (done) { w = new BrowserWindow({ show: false From e027ba9c47fc777c90c7d09adca875ecaa38b07b Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 03:13:40 +1100 Subject: [PATCH 014/185] Add nativeImage.createFromNamedImage API --- atom/common/api/atom_api_native_image.cc | 9 +++++++++ atom/common/api/atom_api_native_image.h | 2 ++ atom/common/api/atom_api_native_image_mac.mm | 20 ++++++++++++++++++++ 3 files changed, 31 insertions(+) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 4d30a88e0d9..419a6c6a61f 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -541,6 +541,14 @@ mate::Handle NativeImage::CreateFromDataURL( return CreateEmpty(isolate); } +#if !defined(OS_MACOSX) +mate::Handle NativeImage::CreateFromNamedImage( + mate::Arguments* args, const std::string& name) { + args->ThrowError("Cannot create NativeImage from a name on non-darwin platforms"); + return CreateEmpty(args->isolate()); +} +#endif + // static void NativeImage::BuildPrototype( v8::Isolate* isolate, v8::Local prototype) { @@ -609,6 +617,7 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("createFromBuffer", &atom::api::NativeImage::CreateFromBuffer); dict.SetMethod("createFromDataURL", &atom::api::NativeImage::CreateFromDataURL); + dict.SetMethod("createFromNamedImage", &atom::api::NativeImage::CreateFromNamedImage); } } // namespace diff --git a/atom/common/api/atom_api_native_image.h b/atom/common/api/atom_api_native_image.h index 6ff7a0e29f3..8bdca3a1a7b 100644 --- a/atom/common/api/atom_api_native_image.h +++ b/atom/common/api/atom_api_native_image.h @@ -53,6 +53,8 @@ class NativeImage : public mate::Wrappable { mate::Arguments* args, v8::Local buffer); static mate::Handle CreateFromDataURL( v8::Isolate* isolate, const GURL& url); + static mate::Handle CreateFromNamedImage( + mate::Arguments* args, const std::string& name); static void BuildPrototype(v8::Isolate* isolate, v8::Local prototype); diff --git a/atom/common/api/atom_api_native_image_mac.mm b/atom/common/api/atom_api_native_image_mac.mm index ad72d4b1492..d19a580dcfb 100644 --- a/atom/common/api/atom_api_native_image_mac.mm +++ b/atom/common/api/atom_api_native_image_mac.mm @@ -6,10 +6,30 @@ #import +#include "base/strings/sys_string_conversions.h" + namespace atom { namespace api { +mate::Handle NativeImage::CreateFromNamedImage( + mate::Arguments* args, const std::string& name) { + @autoreleasepool { + NSImage* image = [NSImage imageNamed:base::SysUTF8ToNSString(name)]; + if (!image.valid) { + args->ThrowError("Cannot create image from name: " + name); + return CreateEmpty(args->isolate()); + } + + CGImageRef ref = [image CGImageForProposedRect:nil context:nil hints:nil]; + NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithCGImage:ref]; + [rep setSize:[image size]]; + NSData* pngData = [rep representationUsingType:NSPNGFileType properties:[[NSDictionary alloc] init]]; + + return CreateFromPNG(args->isolate(), (char *) [pngData bytes], [pngData length]); + } +} + void NativeImage::SetTemplateImage(bool setAsTemplate) { [image_.AsNSImage() setTemplate:setAsTemplate]; } From ec610cd97b639e890543211fd02562a0f266d801 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 03:16:24 +1100 Subject: [PATCH 015/185] Document new nativeImage.createFromNamedImage method --- docs/api/native-image.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 8163c233962..96510eecf7d 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -157,6 +157,16 @@ Returns `NativeImage` Creates a new `NativeImage` instance from `dataURL`. +### `nativeImage.createFromNamedImage(imageName)` _macOS_ + +* `imageName` String + +Returns `NativeImage` + +Creates a new `NativeImage` instance from the NSImage that maps to the +given image name. See [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename?language=objc) +for a list of possible values. + ## Class: NativeImage > Natively wrap images such as tray, dock, and application icons. From 767a178bd1d84d0e94de9626395c600ddd0dc889 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 03:18:44 +1100 Subject: [PATCH 016/185] Do not throw if the named image can not be found --- atom/common/api/atom_api_native_image.cc | 1 - atom/common/api/atom_api_native_image_mac.mm | 1 - 2 files changed, 2 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 419a6c6a61f..79ec0c4b60c 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -544,7 +544,6 @@ mate::Handle NativeImage::CreateFromDataURL( #if !defined(OS_MACOSX) mate::Handle NativeImage::CreateFromNamedImage( mate::Arguments* args, const std::string& name) { - args->ThrowError("Cannot create NativeImage from a name on non-darwin platforms"); return CreateEmpty(args->isolate()); } #endif diff --git a/atom/common/api/atom_api_native_image_mac.mm b/atom/common/api/atom_api_native_image_mac.mm index d19a580dcfb..d9665ceabe1 100644 --- a/atom/common/api/atom_api_native_image_mac.mm +++ b/atom/common/api/atom_api_native_image_mac.mm @@ -17,7 +17,6 @@ mate::Handle NativeImage::CreateFromNamedImage( @autoreleasepool { NSImage* image = [NSImage imageNamed:base::SysUTF8ToNSString(name)]; if (!image.valid) { - args->ThrowError("Cannot create image from name: " + name); return CreateEmpty(args->isolate()); } From b5ba8699f34e14da8afa68e0c10b0263f9085d1b Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 17:05:13 +1100 Subject: [PATCH 017/185] Enable hsl shifting of named images --- atom/common/api/atom_api_native_image_mac.mm | 35 +++++++++++++++++--- docs/api/native-image.md | 20 ++++++++++- 2 files changed, 50 insertions(+), 5 deletions(-) diff --git a/atom/common/api/atom_api_native_image_mac.mm b/atom/common/api/atom_api_native_image_mac.mm index d9665ceabe1..058d5e930da 100644 --- a/atom/common/api/atom_api_native_image_mac.mm +++ b/atom/common/api/atom_api_native_image_mac.mm @@ -7,23 +7,50 @@ #import #include "base/strings/sys_string_conversions.h" +#include "ui/gfx/color_utils.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/image/image_skia_operations.h" namespace atom { namespace api { +NSData* bufferFromNSImage(NSImage* image) { + CGImageRef ref = [image CGImageForProposedRect:nil context:nil hints:nil]; + NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithCGImage:ref]; + [rep setSize:[image size]]; + return [rep representationUsingType:NSPNGFileType properties:[[NSDictionary alloc] init]]; +} + +double safeShift(double in, double def) { + if (in >= 0 || in <= 1 || in == def) return in; + return def; +} + mate::Handle NativeImage::CreateFromNamedImage( mate::Arguments* args, const std::string& name) { @autoreleasepool { + std::vector hsl_shift; NSImage* image = [NSImage imageNamed:base::SysUTF8ToNSString(name)]; if (!image.valid) { return CreateEmpty(args->isolate()); } - CGImageRef ref = [image CGImageForProposedRect:nil context:nil hints:nil]; - NSBitmapImageRep* rep = [[NSBitmapImageRep alloc] initWithCGImage:ref]; - [rep setSize:[image size]]; - NSData* pngData = [rep representationUsingType:NSPNGFileType properties:[[NSDictionary alloc] init]]; + NSData* pngData = bufferFromNSImage(image); + + if (args->GetNext(&hsl_shift) && hsl_shift.size() == 3) { + gfx::Image gfxImage = gfx::Image::CreateFrom1xPNGBytes( + reinterpret_cast((char *) [pngData bytes]), [pngData length]); + color_utils::HSL shift = { + safeShift(hsl_shift[0], -1), + safeShift(hsl_shift[1], 0.5), + safeShift(hsl_shift[2], 0.5) + }; + pngData = bufferFromNSImage(gfx::Image( + gfx::ImageSkiaOperations::CreateHSLShiftedImage( + gfxImage.AsImageSkia(), shift)).CopyNSImage()); + } return CreateFromPNG(args->isolate(), (char *) [pngData bytes], [pngData length]); } diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 96510eecf7d..186df8fb1f9 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -157,9 +157,10 @@ Returns `NativeImage` Creates a new `NativeImage` instance from `dataURL`. -### `nativeImage.createFromNamedImage(imageName)` _macOS_ +### `nativeImage.createFromNamedImage(imageName[, hslShift])` _macOS_ * `imageName` String +* `hslShift` Number[] Returns `NativeImage` @@ -167,6 +168,23 @@ Creates a new `NativeImage` instance from the NSImage that maps to the given image name. See [`NSImageName`](https://developer.apple.com/documentation/appkit/nsimagename?language=objc) for a list of possible values. +The `hslShift` is applied to the image with the following rules +* `hsl_shift[0]` (hue): The absolute hue value for the image - 0 and 1 map + to 0 and 360 on the hue color wheel (red). +* `hsl_shift[1]` (saturation): A saturation shift for the image, with the + following key values: + 0 = remove all color. + 0.5 = leave unchanged. + 1 = fully saturate the image. +* `hsl_shift[2]` (lightness): A lightness shift for the image, with the + following key values: + 0 = remove all lightness (make all pixels black). + 0.5 = leave unchanged. + 1 = full lightness (make all pixels white). + +This means that `[-1, 0, 1]` will make the image completely white and +`[-1, 1, 0]` will make the image completely black. + ## Class: NativeImage > Natively wrap images such as tray, dock, and application icons. From 9308c96f95863c007e29e13422c4dc04ae87f3ef Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 17:17:51 +1100 Subject: [PATCH 018/185] Appease the linting overlords --- atom/common/api/atom_api_native_image.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 79ec0c4b60c..4dfca9ff36b 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -616,7 +616,8 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("createFromBuffer", &atom::api::NativeImage::CreateFromBuffer); dict.SetMethod("createFromDataURL", &atom::api::NativeImage::CreateFromDataURL); - dict.SetMethod("createFromNamedImage", &atom::api::NativeImage::CreateFromNamedImage); + dict.SetMethod("createFromNamedImage" + &atom::api::NativeImage::CreateFromNamedImage); } } // namespace From 2c7787900f434ec16abe8e9f0c09e9bcf7cb9110 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 17:20:55 +1100 Subject: [PATCH 019/185] Follow style guide --- atom/common/api/atom_api_native_image.cc | 2 +- atom/common/api/atom_api_native_image_mac.mm | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/atom/common/api/atom_api_native_image.cc b/atom/common/api/atom_api_native_image.cc index 4dfca9ff36b..469a76fd7f3 100644 --- a/atom/common/api/atom_api_native_image.cc +++ b/atom/common/api/atom_api_native_image.cc @@ -616,7 +616,7 @@ void Initialize(v8::Local exports, v8::Local unused, dict.SetMethod("createFromBuffer", &atom::api::NativeImage::CreateFromBuffer); dict.SetMethod("createFromDataURL", &atom::api::NativeImage::CreateFromDataURL); - dict.SetMethod("createFromNamedImage" + dict.SetMethod("createFromNamedImage", &atom::api::NativeImage::CreateFromNamedImage); } diff --git a/atom/common/api/atom_api_native_image_mac.mm b/atom/common/api/atom_api_native_image_mac.mm index 058d5e930da..110a01efced 100644 --- a/atom/common/api/atom_api_native_image_mac.mm +++ b/atom/common/api/atom_api_native_image_mac.mm @@ -37,22 +37,22 @@ mate::Handle NativeImage::CreateFromNamedImage( return CreateEmpty(args->isolate()); } - NSData* pngData = bufferFromNSImage(image); + NSData* png_data = bufferFromNSImage(image); if (args->GetNext(&hsl_shift) && hsl_shift.size() == 3) { - gfx::Image gfxImage = gfx::Image::CreateFrom1xPNGBytes( - reinterpret_cast((char *) [pngData bytes]), [pngData length]); + gfx::Image gfx_image = gfx::Image::CreateFrom1xPNGBytes( + reinterpret_cast((char *) [png_data bytes]), [png_data length]); color_utils::HSL shift = { safeShift(hsl_shift[0], -1), safeShift(hsl_shift[1], 0.5), safeShift(hsl_shift[2], 0.5) }; - pngData = bufferFromNSImage(gfx::Image( + png_data = bufferFromNSImage(gfx::Image( gfx::ImageSkiaOperations::CreateHSLShiftedImage( - gfxImage.AsImageSkia(), shift)).CopyNSImage()); + gfx_image.AsImageSkia(), shift)).CopyNSImage()); } - return CreateFromPNG(args->isolate(), (char *) [pngData bytes], [pngData length]); + return CreateFromPNG(args->isolate(), (char *) [png_data bytes], [png_data length]); } } From ed25941c650a591469441d9e9a3cbd5d5be22c80 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Tue, 10 Oct 2017 17:30:27 +1100 Subject: [PATCH 020/185] Add basic specs --- spec/api-native-image-spec.js | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/spec/api-native-image-spec.js b/spec/api-native-image-spec.js index 9b8e5c3a2e0..59c204094fb 100644 --- a/spec/api-native-image-spec.js +++ b/spec/api-native-image-spec.js @@ -190,6 +190,34 @@ describe('nativeImage module', () => { }) }) + describe('createFromNamedImage(name)', () => { + it('returns empty for invalid options', () => { + const image = nativeImage.createFromNamedImage('totally_not_real') + assert(image.isEmpty()) + }) + + it('returns empty on non-darwin platforms', () => { + if (process.platform === 'darwin') return + + const image = nativeImage.createFromNamedImage('NSActionTemplate') + assert(image.isEmpty()) + }) + + it('returns a valid image on darwin', () => { + if (process.platform !== 'darwin') return + + const image = nativeImage.createFromNamedImage('NSActionTemplate') + assert(!image.isEmpty()) + }) + + it('returns allows an HSL shift for a valid image on darwin', () => { + if (process.platform !== 'darwin') return + + const image = nativeImage.createFromNamedImage('NSActionTemplate', [0.5, 0.2, 0.8]) + assert(!image.isEmpty()) + }) + }) + describe('resize(options)', () => { it('returns a resized image', () => { const image = nativeImage.createFromPath(path.join(__dirname, 'fixtures', 'assets', 'logo.png')) From 66df065e31d0bc6ebb8c0cbe3b9b662ebed1af07 Mon Sep 17 00:00:00 2001 From: Jonas Zhang <106856363@qq.com> Date: Tue, 10 Oct 2017 21:34:39 +0800 Subject: [PATCH 021/185] Add notification.md file in Chinese Add notification.md file in Chinese --- docs-translations/zh-CN/api/notification.md | 109 ++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 docs-translations/zh-CN/api/notification.md diff --git a/docs-translations/zh-CN/api/notification.md b/docs-translations/zh-CN/api/notification.md new file mode 100644 index 00000000000..ff00ec53e8f --- /dev/null +++ b/docs-translations/zh-CN/api/notification.md @@ -0,0 +1,109 @@ +# 通知 + +> 创建系统桌面通知 + +进程: [Main](../glossary.md#main-process) + +## 在渲染器进程中使用 + +如果你想要从渲染器进程显示通知,则应使用 [HTML5 Notification API](../tutorial/notifications.md) + +## 类: Notification + +> 创建系统桌面通知 + +进程: [Main](../glossary.md#main-process) + +`Notification` 是一个 +[EventEmitter](http://nodejs.org/api/events.html#events_class_events_eventemitter). + +它通过由 `options ` 设置的原生属性创建一个新的 `Notification`. + +### 静态方法 + +`Notification` 类具有以下静态方法: + +#### `Notification.isSupported()` + +返回 `Boolean` - 无论当前系统是否支持桌面通知 + +### `new Notification([options])` _实验性_ + +* `options` 对象 + * `title` 字符串 - 通知的标题,显示在通知窗口的顶部. + * `subtitle` 字符串 - (可选) 通知的副标题,将显示在标题下方. _macOS_ + * `body` 字符串 - 通知的正文,将显示在标题或副标题下方. + * `silent` 布尔 - (可选) 是否在显示通知时发出系统通知提示音. + * `icon` [NativeImage](native-image.md) - (可选) 通知所使用的图标 + * `hasReply` 布尔 - (可选) 是否在通知中添加内联的回复选项. _macOS_ + * `replyPlaceholder` 字符串 - (可选) 在内联输入字段中的提示占位符. _macOS_ + * `sound` 字符串 - (可选) 显示通知时要播放的声音文件的名称. _macOS_ + * `actions` [NotificationAction[]](structures/notification-action.md) - (可选) 添加到通知中的操作. 请阅读 `NotificationAction` 文档中的可用操作和限制. _macOS_ + + +### 实例事件 + +使用 `new Notification` 创建的对象会发出以下事件: + +**注意:** 某些事件仅在特定的操作系统上可用,请参照标签标示。 + +#### 事件: 'show' + +返回: + +* `event` 事件 + +当向用户显示通知时发出. 注意这可以被多次触发, 因为通知可以通过 `show()` 方法多次显示. + +#### 事件: 'click' + +返回: + +* `event` 事件 + +当用户点击通知时发出. + +#### 事件: 'close' + +返回: + +* `event` 事件 + +当用户手动关闭通知时发出. + +在关闭所有通知的情况下,不能保证会发送此事件. + +#### 事件: 'reply' _macOS_ + +返回: + +* `event` 事件 +* `reply` 字符串 - 用户输入到内联回复字段的字符串. + +当用户点击 `hasReply: true` 的通知上的 “回复” 按钮时发出. + +#### Event: 'action' _macOS_ + +返回: + +* `event` 事件 +* `index` Number - The index of the action that was activated + +### 实例方法 + +使用 `new Notification` 创建的对象具有以下实例方法: + +#### `notification.show()` + +立即向用户显示通知. 请注意这不同于 HTML5 Notification 的实现, 简单地实例化一个 `new Notification` 不会立即向用户显示, 你需要在操作系统显示之前调用此方法. + +### 播放声音 + +在 macOS 上, 你可以在显示通知时指定要播放的声音的名称. 除了自定义声音文件, 可以使用任意默认声音 (在 “系统偏好设置” > “声音” 下) . 同时确保声音文件被复制到应用程序包下 (例如`YourApp.app/Contents/Resources`), 或以下位置之一: + +* `~/Library/Sounds` +* `/Library/Sounds` +* `/Network/Library/Sounds` +* `/System/Library/Sounds` + +查看 [`NSSound`](https://developer.apple.com/documentation/appkit/nssound) 文档获取更多信息. From c51ac6048d5ad90690d6c88bbfdc088f4d11afef Mon Sep 17 00:00:00 2001 From: Robin Andersson Date: Tue, 10 Oct 2017 21:33:14 +0200 Subject: [PATCH 022/185] :memo: Updated with link to VS 2015 The previous link pointed to VS 2017 download location. --- docs/development/build-instructions-windows.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development/build-instructions-windows.md b/docs/development/build-instructions-windows.md index 6bfd2425767..e0d9fc28072 100644 --- a/docs/development/build-instructions-windows.md +++ b/docs/development/build-instructions-windows.md @@ -6,7 +6,7 @@ Follow the guidelines below for building Electron on Windows. * Windows 7 / Server 2008 R2 or higher * Visual Studio 2015 Update 3 - [download VS 2015 Community Edition for - free](https://www.visualstudio.com/en-us/products/visual-studio-community-vs.aspx) + free](https://www.visualstudio.com/vs/older-downloads/) * [Python 2.7](http://www.python.org/download/releases/2.7/) * [Node.js](http://nodejs.org/download/) * [Git](http://git-scm.com) From 06d782279ccb2986579e584d0f4b2d029653113b Mon Sep 17 00:00:00 2001 From: Birunthan Mohanathas Date: Tue, 10 Oct 2017 22:55:15 +0300 Subject: [PATCH 023/185] Add systemPreferences.removeUserDefault() This can be used to restore the default or global value of a `key` previously set with `setUserDefault`. --- atom/browser/api/atom_api_system_preferences.cc | 1 + atom/browser/api/atom_api_system_preferences.h | 1 + .../api/atom_api_system_preferences_mac.mm | 5 +++++ docs/api/system-preferences.md | 15 +++++++++++---- spec/api-system-preferences-spec.js | 17 +++++++++++++++++ 5 files changed, 35 insertions(+), 4 deletions(-) diff --git a/atom/browser/api/atom_api_system_preferences.cc b/atom/browser/api/atom_api_system_preferences.cc index 8426c4dbbdf..74d6d03ce7c 100644 --- a/atom/browser/api/atom_api_system_preferences.cc +++ b/atom/browser/api/atom_api_system_preferences.cc @@ -67,6 +67,7 @@ void SystemPreferences::BuildPrototype( &SystemPreferences::UnsubscribeLocalNotification) .SetMethod("getUserDefault", &SystemPreferences::GetUserDefault) .SetMethod("setUserDefault", &SystemPreferences::SetUserDefault) + .SetMethod("removeUserDefault", &SystemPreferences::RemoveUserDefault) .SetMethod("isSwipeTrackingFromScrollEventsEnabled", &SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled) #endif diff --git a/atom/browser/api/atom_api_system_preferences.h b/atom/browser/api/atom_api_system_preferences.h index 895974e9aef..ea5daed94a5 100644 --- a/atom/browser/api/atom_api_system_preferences.h +++ b/atom/browser/api/atom_api_system_preferences.h @@ -76,6 +76,7 @@ class SystemPreferences : public mate::EventEmitter void SetUserDefault(const std::string& name, const std::string& type, mate::Arguments* args); + void RemoveUserDefault(const std::string& name); bool IsSwipeTrackingFromScrollEventsEnabled(); #endif bool IsDarkMode(); diff --git a/atom/browser/api/atom_api_system_preferences_mac.mm b/atom/browser/api/atom_api_system_preferences_mac.mm index 877ad1a1328..58e9b848e25 100644 --- a/atom/browser/api/atom_api_system_preferences_mac.mm +++ b/atom/browser/api/atom_api_system_preferences_mac.mm @@ -229,6 +229,11 @@ void SystemPreferences::SetUserDefault(const std::string& name, } } +void SystemPreferences::RemoveUserDefault(const std::string& name) { + NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults]; + [defaults removeObjectForKey:base::SysUTF8ToNSString(name)]; +} + bool SystemPreferences::IsDarkMode() { NSString* mode = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"]; diff --git a/docs/api/system-preferences.md b/docs/api/system-preferences.md index 54d3ea8d6a2..5ec61224617 100644 --- a/docs/api/system-preferences.md +++ b/docs/api/system-preferences.md @@ -112,9 +112,9 @@ Same as `unsubscribeNotification`, but removes the subscriber from `NSNotificati * `type` String - Can be `string`, `boolean`, `integer`, `float`, `double`, `url`, `array`, `dictionary` -Returns `any` - The value of `key` in system preferences. +Returns `any` - The value of `key` in `NSUserDefaults`. -This API uses `NSUserDefaults` on macOS. Some popular `key` and `type`s are: +Some popular `key` and `type`s are: * `AppleInterfaceStyle`: `string` * `AppleAquaColorVariant`: `integer` @@ -130,15 +130,22 @@ This API uses `NSUserDefaults` on macOS. Some popular `key` and `type`s are: * `type` String - See [`getUserDefault`][#systempreferencesgetuserdefaultkey-type-macos] * `value` String -Set the value of `key` in system preferences. +Set the value of `key` in `NSUserDefaults`. Note that `type` should match actual type of `value`. An exception is thrown if they don't. -This API uses `NSUserDefaults` on macOS. Some popular `key` and `type`s are: +Some popular `key` and `type`s are: * `ApplePressAndHoldEnabled`: `boolean` +### `systemPreferences.removeUserDefault(key)` _macOS_ + +* `key` String + +Removes the `key` in `NSUserDefaults`. This can be used to restore the default +or global value of a `key` previously set with `setUserDefault`. + ### `systemPreferences.isAeroGlassEnabled()` _Windows_ Returns `Boolean` - `true` if [DWM composition][dwm-composition] (Aero Glass) is diff --git a/spec/api-system-preferences-spec.js b/spec/api-system-preferences-spec.js index 1c03d70d986..afcb5d1f9e2 100644 --- a/spec/api-system-preferences-spec.js +++ b/spec/api-system-preferences-spec.js @@ -100,6 +100,23 @@ describe('systemPreferences module', function () { }) }) + describe('systemPreferences.setUserDefault(key, type, value)', () => { + if (process.platform !== 'darwin') { + return + } + + it('removes keys', () => { + const KEY = 'SystemPreferencesTest' + systemPreferences.setUserDefault(KEY, 'string', 'foo') + systemPreferences.removeUserDefault(KEY) + assert.equal(systemPreferences.getUserDefault(KEY, 'string'), '') + }) + + it('does not throw for missing keys', () => { + systemPreferences.removeUserDefault('some-missing-key') + }) + }) + describe('systemPreferences.isInvertedColorScheme()', function () { it('returns a boolean', function () { assert.equal(typeof systemPreferences.isInvertedColorScheme(), 'boolean') From 6fa9249062a001bd159da47cde426420bd52fed0 Mon Sep 17 00:00:00 2001 From: Jonas Zhang <106856363@qq.com> Date: Wed, 11 Oct 2017 09:42:34 +0800 Subject: [PATCH 024/185] Add notification.md file in Chinese Add notification.md file in Chinese --- .../zh-CN/tutorial/notifications.md | 57 +++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 docs-translations/zh-CN/tutorial/notifications.md diff --git a/docs-translations/zh-CN/tutorial/notifications.md b/docs-translations/zh-CN/tutorial/notifications.md new file mode 100644 index 00000000000..41ed77820bc --- /dev/null +++ b/docs-translations/zh-CN/tutorial/notifications.md @@ -0,0 +1,57 @@ +# 通知 (Windows, Linux, macOS) + +所有三个操作系统都提供了应用程序向用户发送通知的手段。Electron允许开发者使用 [HTML5 Notification API](https://notifications.spec.whatwg.org/) 发送通知,并使用当前运行的操作系统的本地通知 API 来显示它。 + +**注意:** 由于这是一个 HTML5 API,它只能在渲染器进程中使用。 如果你想在主进程中显示通知,请查看 [Notification](../api/notification.md) 模块. + +```javascript +let myNotification = new Notification('标题', { + body: '通知正文内容' +}) + +myNotification.onclick = () => { + console.log('通知被点击') +} +``` + +虽然操作系统的代码和用户体验相似,但依然存在微妙的差异。 + +## Windows + +* 在 Windows 10 上, 通知 "仅能运行". +* 在 Windows 8.1 和 Windows 8 上, 你的应用程序的快捷方式,[Application User Model ID][app-user-model-id],必须安装到 “开始” 屏幕。但是请注意,它不需要被固定到开始屏幕。 +* 在 Windows 7 上, 通知通过视觉上类似于较新系统原生的一个自定义的实现来工作。 + +此外,在Windows 8中,通知正文的最大长度为250个字符,Windows团队建议将通知保留为200个字符。 然而,Windows 10中已经删除了这个限制,但是Windows团队要求开发人员合理使用。 尝试将大量文本发送到API(数千个字符)可能会导致不稳定。 + +### 高级通知 + +Windows 的更高版本允许高级通知,自定义模板,图像和其他灵活元素。 要发送这些通知(来自主进程或渲染器进程),请使用用户区模块 [electron-windows-notifications](https://github.com/felixrieseberg/electron-windows-notifications) 来用原生节点附件发送 `ToastNotification` 和 `TileNotification` 对象。 + +虽然包含按钮的通知只能使用 `electron-windows-notifications`,但处理回复则需要使用[`electron-windows-interactive-notifications`](https://github.com/felixrieseberg/electron-windows-interactive-notifications),这有助于注册所需的COM组件,并使用输入的用户数据调用Electron应用程序。 + +### 免打扰模式 / 演示模式 + +要检测是否允许发送通知,请使用用户区模块 [electron-notification-state](https://github.com/felixrieseberg/electron-notification-state)。 + +这样,您可以提前确定 Windows 是否会将通知忽略。 + +## macOS + +macOS上的通知是最直接的,但你应该注意 [苹果关于通知的人机接口指南](https://developer.apple.com/library/mac/documentation/UserExperience/Conceptual/OSXHIGuidelines/NotificationCenter.html). + +请注意,通知的大小限制为256个字节,如果超过该限制,则会被截断。 + +### 高级通知 + +后来的 macOS 版本允许有一个输入字段的通知,允许用户快速回复通知。为了通过输入字段发送通知,请使用用户区模块 [node-mac-notifier](https://github.com/CharlieHess/node-mac-notifier)。 + +### 勿扰 / 会话状态 + +要检测是否允许发送通知,请使用用户区模块 [electron-notification-state](https://github.com/felixrieseberg/electron-notification-state). + +这样可以提前检测是否显示通知。 + +## Linux + +通知使用 `libnotify` 发送,可以在 [Desktop Notifications Specification] [notification-spec] 之后的任何桌面环境中显示通知,包括 Cinnamon, Enlightenment, Unity, GNOME, KDE. From af99e658760045af266e570e126bf0aee2f82799 Mon Sep 17 00:00:00 2001 From: Jonas Zhang <106856363@qq.com> Date: Wed, 11 Oct 2017 09:51:52 +0800 Subject: [PATCH 025/185] Add notification-action.md file in Chinese Add notification-action.md file in Chinese --- .../api/structures/notification-action.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 docs-translations/zh-CN/api/structures/notification-action.md diff --git a/docs-translations/zh-CN/api/structures/notification-action.md b/docs-translations/zh-CN/api/structures/notification-action.md new file mode 100644 index 00000000000..1ceb880acce --- /dev/null +++ b/docs-translations/zh-CN/api/structures/notification-action.md @@ -0,0 +1,19 @@ +# NotificationAction 对象 + +* `type` 字符串 - 动作的类型, 可以是 `button`. +* `text` 字符串 - (可选) 指定动作的标签. + +## 平台 / 动作 支持 + +| 动作类型 | 平台支持 | `text`用法 | 默认 `text` | 限制 | +|-------------|------------------|-----------------|----------------|-------------| +| `button` | macOS | 用作按钮的标签 | "Show" | 最多只有一个按钮,如果仅提供多个,则仅使用最后一个按钮。 此操作也与 `hasReply` 不兼容,如果 `hasReply` 为 `true` ,将被忽略。 | + +### macOS 上的按钮支持 + +为了让额外的通知按钮在 MacOS 上工作,您的应用程序必须符合以下条件。 + +* 应用程序已签名。 +* 在 `info.plist` 中,将应用程序的 `NSUserNotificationAlertStyle` 设为 `alert` 。 + +如果这些要求中的任何一个都不符合,按钮就不会出现。 From 6381f288472a7987c0bf0d653f096862b3525641 Mon Sep 17 00:00:00 2001 From: John Kleinschmidt Date: Wed, 11 Oct 2017 11:38:50 -0400 Subject: [PATCH 026/185] Revert official build Release builds are not currently building with official build --- vendor/libchromiumcontent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/libchromiumcontent b/vendor/libchromiumcontent index d6df80e2074..01de61a555f 160000 --- a/vendor/libchromiumcontent +++ b/vendor/libchromiumcontent @@ -1 +1 @@ -Subproject commit d6df80e20748f35373f15c2bfbd70befb4bb6221 +Subproject commit 01de61a555fb2c3c673eeea88620a873b8ef63c7 From d07529feca8cbe329d282f07aa132bb420bd1338 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Wed, 11 Oct 2017 10:56:40 -0700 Subject: [PATCH 027/185] :wrench: Don't be quiet on default loglevel --- npm/install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/install.js b/npm/install.js index 0419196de2a..dad8ccbbf73 100755 --- a/npm/install.js +++ b/npm/install.js @@ -29,7 +29,7 @@ download({ arch: process.env.npm_config_arch, strictSSL: process.env.npm_config_strict_ssl === 'true', force: process.env.force_no_cache === 'true', - quiet: ['info', 'verbose', 'silly', 'http'].indexOf(process.env.npm_config_loglevel) === -1 + quiet: process.env.npm_config_loglevel === 'silent' }, extractFile) // unzips and makes path.txt point at the correct executable From 2b510d7a06c42122f64d67d235902752cdbf89d9 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Wed, 11 Oct 2017 11:10:38 -0700 Subject: [PATCH 028/185] Update install.js --- npm/install.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/install.js b/npm/install.js index dad8ccbbf73..8cb9ed8815f 100755 --- a/npm/install.js +++ b/npm/install.js @@ -29,7 +29,7 @@ download({ arch: process.env.npm_config_arch, strictSSL: process.env.npm_config_strict_ssl === 'true', force: process.env.force_no_cache === 'true', - quiet: process.env.npm_config_loglevel === 'silent' + quiet: process.env.npm_config_loglevel === 'silent' || process.env.CI }, extractFile) // unzips and makes path.txt point at the correct executable From b79e61db1d8186389e6d56de4179c3e06ab79039 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nuri=20Uzuno=C4=9Flu?= Date: Thu, 12 Oct 2017 09:22:40 +0300 Subject: [PATCH 029/185] [docs] [tr-TR] Update README.md Minor changes. --- docs-translations/tr-TR/project/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs-translations/tr-TR/project/README.md b/docs-translations/tr-TR/project/README.md index f1998ba09bd..ea6ee9f09e8 100644 --- a/docs-translations/tr-TR/project/README.md +++ b/docs-translations/tr-TR/project/README.md @@ -17,23 +17,23 @@ Bu proje katılımcı sözleşmesine bağlıdır. Katılarak, bu kodun sürdürülebilir olduğunu üstlenmeniz beklenmekte. Lütfen uygun olmayan davranışları electron@github.com'a rapor edin. -## Downloads +## İndirme Bağlantıları Electron prebuilt mimarisini yüklemek için, [`npm`](https://docs.npmjs.com/): ```sh -# Development dependency olarak yükleyin +# Geliştirme bağımlılığı olarak yükleyin npm install electron --save-dev # `electron` komutunu global olarak $PATH'a yükleyin npm install electron -g ``` -Prebuilt mimarileri, debug sembolleri, ve fazlası için -[releases page](https://github.com/electron/electron/releases) sayfasını ziyaret edin. +Prebuilt mimarileri, debug sembolleri ve fazlası için +[releases](https://github.com/electron/electron/releases) sayfasını ziyaret edin. -### Mirrors +### Alternatif Bağlantılar - [China](https://npm.taobao.org/mirrors/electron) From cf6e3ca08720780c500a6a1edaa99a44491d34ec Mon Sep 17 00:00:00 2001 From: Jeroen Visser Date: Thu, 12 Oct 2017 14:55:21 +0200 Subject: [PATCH 030/185] Fix link to libnotify spec Link was broken --- docs/tutorial/notifications.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/tutorial/notifications.md b/docs/tutorial/notifications.md index 2ded823f917..d6323726b59 100644 --- a/docs/tutorial/notifications.md +++ b/docs/tutorial/notifications.md @@ -85,3 +85,5 @@ Notifications are sent using `libnotify` which can show notifications on any desktop environment that follows [Desktop Notifications Specification][notification-spec], including Cinnamon, Enlightenment, Unity, GNOME, KDE. + +[notification-spec]: https://developer.gnome.org/notification-spec/ From 7b8dc38e880e891a673f9bbf72c185f701138fd5 Mon Sep 17 00:00:00 2001 From: Yongmin Hong Date: Fri, 13 Oct 2017 02:58:44 +0900 Subject: [PATCH 031/185] Fix Korean grammatic mistakes Mostly spacing errors. Haven't look at full Korean translation, but will do. Signed-off-by: Yongmin Hong --- docs-translations/ko-KR/README.md | 3 +-- docs-translations/ko-KR/project/CONTRIBUTING.md | 6 +++--- docs-translations/ko-KR/project/README.md | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/docs-translations/ko-KR/README.md b/docs-translations/ko-KR/README.md index f829e22752a..f5361dd360c 100644 --- a/docs-translations/ko-KR/README.md +++ b/docs-translations/ko-KR/README.md @@ -1,8 +1,7 @@ 반드시 사용하는 Electron 버전과 문서 버전을 일치시켜야 합니다. 버전 숫자는 문서 페이지 URL에 포함되어 있습니다. 만약 그렇지 않다면, 아마 개발 브랜치의 문서일 것이며 당신의 Electron 버전과 호환되지 않는 API 변경을 포함할 것 입니다. -이전 버전 문서는 깃허브에서 [태그로 열어] -(https://github.com/electron/electron/tree/v1.4.0) 볼 수 있습니다. +이전 버전 문서는 깃허브에서 [태그로 열어](https://github.com/electron/electron/tree/v1.4.0) 볼 수 있습니다. "branches/tags 변경" 드롭다운을 열고 해당 버전의 태그를 선택하세요. **역자주:** 한국어 번역 문서는 `atom.io`에 반영되어 있지 않습니다. 한국어 번역 diff --git a/docs-translations/ko-KR/project/CONTRIBUTING.md b/docs-translations/ko-KR/project/CONTRIBUTING.md index 8d59d72ad45..7bcd70d00f8 100644 --- a/docs-translations/ko-KR/project/CONTRIBUTING.md +++ b/docs-translations/ko-KR/project/CONTRIBUTING.md @@ -13,7 +13,7 @@ ## 이슈 제출 * [여기](https://github.com/electron/electron/issues/new)에서 새로운 이슈를 만들 수 -있습니다. 하지만 이슈를 작성하기 전에 아래의 항목들을 숙지하고 가능한한 이슈 보고에 +있습니다. 하지만 이슈를 작성하기 전에 아래의 항목들을 숙지하고 가능한 한 이슈 보고에 대해 최대한 많은 정보와 자세한 설명을 포함해야 합니다. 가능하다면 다음 항목을 포함해야 합니다: * 사용하고 있는 Electron의 버전 @@ -28,9 +28,9 @@ ## Pull Request 하기 -* 가능한한 스크린샷과 GIF 애니메이션 이미지를 pull request에 추가 +* 가능한 한 스크린샷과 GIF 애니메이션 이미지를 pull request에 추가 * JavaScript, C++과 Python등 -[참조 문서에 정의된 코딩스타일](/docs-translations/ko-KR/development/coding-style.md)을 +[참조 문서에 정의된 코딩 스타일](/docs-translations/ko-KR/development/coding-style.md)을 준수 * [문서 스타일 가이드](/docs-translations/ko-KR/styleguide.md)에 따라 문서를 [Markdown](https://daringfireball.net/projects/markdown) 형식으로 작성. diff --git a/docs-translations/ko-KR/project/README.md b/docs-translations/ko-KR/project/README.md index 23c233518d6..d9373539dbd 100644 --- a/docs-translations/ko-KR/project/README.md +++ b/docs-translations/ko-KR/project/README.md @@ -42,7 +42,7 @@ npm install electron --save-dev ## 참조 문서 [Docs](https://github.com/electron/electron/tree/master/docs-translations/ko-KR/README.md)에 -개발 지침과 API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는법 +개발 지침과 API 레퍼런스가 있습니다. Electron을 빌드 하는 방법과 프로젝트에 기여하는 법 또한 문서에 포함되어 있으니 참고하시기 바랍니다. ## 참조 문서 (번역) From f57b619097754e5938dc023780f8bed885f76aa4 Mon Sep 17 00:00:00 2001 From: Sam Thomson Date: Sat, 14 Oct 2017 13:11:44 +0100 Subject: [PATCH 032/185] updated docs --- docs/api/shell.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/shell.md b/docs/api/shell.md index ae30de76f8b..85c5e762609 100644 --- a/docs/api/shell.md +++ b/docs/api/shell.md @@ -36,7 +36,7 @@ Open the given file in the desktop's default manner. ### `shell.openExternal(url[, options, callback])` -* `url` String +* `url` String - max 2081 characters on windows, or the function returns false * `options` Object (optional) _macOS_ * `activate` Boolean - `true` to bring the opened application to the foreground. The default is `true`. From 60e614b10ce31bf84b43efd06d77d47991c39bf0 Mon Sep 17 00:00:00 2001 From: Robin Andersson Date: Sun, 15 Oct 2017 21:18:20 +0200 Subject: [PATCH 033/185] cpplint skip to run if dependencies has not been bootstrapped See #10593 for the discussion regarding this --- script/cpplint.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/script/cpplint.py b/script/cpplint.py index e602b3cb1e6..5dfca8f76ec 100755 --- a/script/cpplint.py +++ b/script/cpplint.py @@ -38,6 +38,10 @@ SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def main(): + if not os.path.isfile(cpplint_path()): + print("[INFO] Skipping cpplint, dependencies has not been bootstrapped") + return + os.chdir(SOURCE_ROOT) atom_files = list_files('atom', ['app', 'browser', 'common', 'renderer', 'utility'], @@ -60,9 +64,13 @@ def list_files(parent, directories, filters): def call_cpplint(files): - cpplint = os.path.join(SOURCE_ROOT, 'vendor', 'depot_tools', 'cpplint.py') + cpplint = cpplint_path() execute([sys.executable, cpplint] + files) +def cpplint_path(): + return os.path.join(SOURCE_ROOT, 'vendor', 'depot_tools', 'cpplint.py') + + if __name__ == '__main__': sys.exit(main()) From f40cc5ab54a7a5a9d41a5aabe9d92f25799acc93 Mon Sep 17 00:00:00 2001 From: Boik Date: Mon, 16 Oct 2017 17:17:21 +0800 Subject: [PATCH 034/185] add error code to session.setCertificateVerifyProc --- atom/browser/api/atom_api_session.cc | 1 + atom/browser/net/atom_cert_verifier.cc | 1 + atom/browser/net/atom_cert_verifier.h | 1 + docs/api/session.md | 3 ++- spec/api-session-spec.js | 3 ++- 5 files changed, 7 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_session.cc b/atom/browser/api/atom_api_session.cc index cd149f9cfde..0d1f6a71782 100644 --- a/atom/browser/api/atom_api_session.cc +++ b/atom/browser/api/atom_api_session.cc @@ -212,6 +212,7 @@ struct Converter { dict.Set("hostname", val.hostname); dict.Set("certificate", val.certificate); dict.Set("verificationResult", val.default_result); + dict.Set("errorCode", val.error_code); return dict.GetHandle(); } }; diff --git a/atom/browser/net/atom_cert_verifier.cc b/atom/browser/net/atom_cert_verifier.cc index 2a2229f19d1..9cc4a613261 100644 --- a/atom/browser/net/atom_cert_verifier.cc +++ b/atom/browser/net/atom_cert_verifier.cc @@ -92,6 +92,7 @@ class CertVerifierRequest : public AtomCertVerifier::Request { std::unique_ptr request(new VerifyRequestParams()); request->hostname = params_.hostname(); request->default_result = net::ErrorToString(error); + request->error_code = error; request->certificate = params_.certificate(); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, diff --git a/atom/browser/net/atom_cert_verifier.h b/atom/browser/net/atom_cert_verifier.h index 09fa0f2778e..76382bf4c5d 100644 --- a/atom/browser/net/atom_cert_verifier.h +++ b/atom/browser/net/atom_cert_verifier.h @@ -19,6 +19,7 @@ class CertVerifierRequest; struct VerifyRequestParams { std::string hostname; std::string default_result; + int error_code; scoped_refptr certificate; }; diff --git a/docs/api/session.md b/docs/api/session.md index 34fd8c481d5..25ca1b3a824 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -253,7 +253,8 @@ the original network configuration. * `request` Object * `hostname` String * `certificate` [Certificate](structures/certificate.md) - * `error` String - Verification result from chromium. + * `verificationResult` String - Verification result from chromium. + * `errorCode` Integer - Error code. * `callback` Function * `verificationResult` Integer - Value can be one of certificate error codes from [here](https://code.google.com/p/chromium/codesearch#chromium/src/net/base/net_error_list.h). diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index d361c10d947..51996d448b3 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -572,8 +572,9 @@ describe('session module', function () { }) it('accepts the request when the callback is called with 0', function (done) { - session.defaultSession.setCertificateVerifyProc(function ({hostname, certificate, verificationResult}, callback) { + session.defaultSession.setCertificateVerifyProc(function ({hostname, certificate, verificationResult, errorCode}, callback) { assert(['net::ERR_CERT_AUTHORITY_INVALID', 'net::ERR_CERT_COMMON_NAME_INVALID'].includes(verificationResult), verificationResult) + assert([-202, -200].includes(errorCode), errorCode) callback(0) }) From 3a571bbdb4d625bdc71e9c6bc1b902ab8cd00b62 Mon Sep 17 00:00:00 2001 From: Ales Pergl Date: Mon, 2 Oct 2017 13:58:16 +0000 Subject: [PATCH 035/185] Use real shared library names for symbol files --- tools/posix/generate_breakpad_symbols.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/posix/generate_breakpad_symbols.py b/tools/posix/generate_breakpad_symbols.py index d3f98d4d794..c854a23c9cf 100755 --- a/tools/posix/generate_breakpad_symbols.py +++ b/tools/posix/generate_breakpad_symbols.py @@ -117,7 +117,7 @@ def GetSharedLibraryDependenciesLinux(binary): for line in ldd.splitlines(): m = lib_re.match(line) if m: - result.append(m.group(1)) + result.append(os.path.realpath(m.group(1))) return result From 3208a77bf39023408be344a7f87dbe56e44638da Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 17 Oct 2017 13:37:05 -0400 Subject: [PATCH 036/185] Fix link to version-change-rules --- docs/development/releasing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/development/releasing.md b/docs/development/releasing.md index aafee3291a4..667c3112512 100644 --- a/docs/development/releasing.md +++ b/docs/development/releasing.md @@ -3,7 +3,7 @@ This document describes the process for releasing a new version of Electron. ## Find out what version change is needed -Is this a major, minor, patch, or beta version change? Read the [Version Change Rules](docs/tutorial/electron-versioning.md#version-change-rules) to find out. +Is this a major, minor, patch, or beta version change? Read the [Version Change Rules](../tutorial/electron-versioning.md#version-change-rules) to find out. ## Create a temporary branch From c647b0c65e3267f6fb419f78d3e782d62eda3286 Mon Sep 17 00:00:00 2001 From: 73mp74710n Date: Wed, 18 Oct 2017 02:35:19 +0100 Subject: [PATCH 037/185] update docs to show usage of ipcRenderer.sendTo --- docs/api/ipc-renderer.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index e23f3734e5e..567c02508ef 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -74,6 +74,14 @@ and replies by setting `event.returnValue`. **Note:** Sending a synchronous message will block the whole renderer process, unless you know what you are doing you should never use it. +### `ipcRenderer.sendTo(windowid, channel, [, arg1][, arg2][, ...])` + +* `windowid` Number +* `channel` String +* `...args` any[] + +Sends a message to a window with `windowid` via `channel` + ### `ipcRenderer.sendToHost(channel[, arg1][, arg2][, ...])` * `channel` String From 0a0897ef28067f91ba9ea5ab39c82f16ba194a98 Mon Sep 17 00:00:00 2001 From: 73mp74710n Date: Wed, 18 Oct 2017 02:52:02 +0100 Subject: [PATCH 038/185] Update ipc-renderer.md --- docs/api/ipc-renderer.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/ipc-renderer.md b/docs/api/ipc-renderer.md index 567c02508ef..7fed5a953c4 100644 --- a/docs/api/ipc-renderer.md +++ b/docs/api/ipc-renderer.md @@ -74,9 +74,9 @@ and replies by setting `event.returnValue`. **Note:** Sending a synchronous message will block the whole renderer process, unless you know what you are doing you should never use it. -### `ipcRenderer.sendTo(windowid, channel, [, arg1][, arg2][, ...])` +### `ipcRenderer.sendTo(windowId, channel, [, arg1][, arg2][, ...])` -* `windowid` Number +* `windowId` Number * `channel` String * `...args` any[] From 392e88db34831b47bb2caa307ab5b4d3da397ebd Mon Sep 17 00:00:00 2001 From: Sarthak Tripathi Date: Wed, 18 Oct 2017 16:28:18 +0530 Subject: [PATCH 039/185] Updated online-offline-events.md Added more info, to clarify things. --- docs/tutorial/online-offline-events.md | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/docs/tutorial/online-offline-events.md b/docs/tutorial/online-offline-events.md index bc9f7ecc945..ea80d4d0209 100644 --- a/docs/tutorial/online-offline-events.md +++ b/docs/tutorial/online-offline-events.md @@ -1,7 +1,13 @@ # Online/Offline Event Detection Online and offline event detection can be implemented in the renderer process -using standard HTML5 APIs, as shown in the following example. +using standard HTML5 NavigatorOnLine API. +The navigator.onLine attribute returns `false` if the user agent will not contact the network when the user follows links or when a script requests a remote page (or knows that such an attempt would fail) i.e. definitely offline (disconnected from the network) and must return `true` otherwise. +Since all other conditions return `true`, one has to be mindful of getting false positives, as we cannot assume `true` value necessarily means that Electron can access the internet. Such as in cases where the computer is running a virtualization software that has virtual ethernet adapters that are always “connected.” +Therefore, if you really want to determine the internet access status of Electron, +you should develop additional means for checking. + +Example: _main.js_ @@ -78,13 +84,3 @@ _online-status.html_ ``` - -**NOTE:** If Electron is not able to connect to a local area network (LAN) or -a router, it is considered offline; all other conditions return `true`. -So while you can assume that Electron is offline when `navigator.onLine` -returns a `false` value, you cannot assume that a `true` value necessarily -means that Electron can access the internet. You could be getting false -positives, such as in cases where the computer is running a virtualization -software that has virtual ethernet adapters that are always "connected." -Therefore, if you really want to determine the internet access status of Electron, -you should develop additional means for checking. From 392f4b44f0e209dc54efd20c82ba125fb733fc58 Mon Sep 17 00:00:00 2001 From: Sarthak Tripathi Date: Wed, 18 Oct 2017 19:11:05 +0530 Subject: [PATCH 040/185] Updated online-offline-events.md Added links, removed grammatical error. --- docs/tutorial/online-offline-events.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/tutorial/online-offline-events.md b/docs/tutorial/online-offline-events.md index ea80d4d0209..d5399405f7d 100644 --- a/docs/tutorial/online-offline-events.md +++ b/docs/tutorial/online-offline-events.md @@ -1,7 +1,6 @@ # Online/Offline Event Detection -Online and offline event detection can be implemented in the renderer process -using standard HTML5 NavigatorOnLine API. +[Online and offline event](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) detection can be implemented in the renderer process using [NavigatorOnLine](http://html5index.org/Offline%20-%20NavigatorOnLine.html) attribute, part of standard HTML5 API. The navigator.onLine attribute returns `false` if the user agent will not contact the network when the user follows links or when a script requests a remote page (or knows that such an attempt would fail) i.e. definitely offline (disconnected from the network) and must return `true` otherwise. Since all other conditions return `true`, one has to be mindful of getting false positives, as we cannot assume `true` value necessarily means that Electron can access the internet. Such as in cases where the computer is running a virtualization software that has virtual ethernet adapters that are always “connected.” Therefore, if you really want to determine the internet access status of Electron, From 32f92f7a90070bce3451edc623fc27b7d62b81f8 Mon Sep 17 00:00:00 2001 From: Sarthak Tripathi Date: Wed, 18 Oct 2017 19:26:19 +0530 Subject: [PATCH 041/185] Updated online-offline-events.md Improved readability and simplicity. --- docs/tutorial/online-offline-events.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/tutorial/online-offline-events.md b/docs/tutorial/online-offline-events.md index d5399405f7d..b42b9e3df31 100644 --- a/docs/tutorial/online-offline-events.md +++ b/docs/tutorial/online-offline-events.md @@ -1,7 +1,7 @@ # Online/Offline Event Detection -[Online and offline event](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) detection can be implemented in the renderer process using [NavigatorOnLine](http://html5index.org/Offline%20-%20NavigatorOnLine.html) attribute, part of standard HTML5 API. -The navigator.onLine attribute returns `false` if the user agent will not contact the network when the user follows links or when a script requests a remote page (or knows that such an attempt would fail) i.e. definitely offline (disconnected from the network) and must return `true` otherwise. +[Online and offline event](https://developer.mozilla.org/en-US/docs/Online_and_offline_events) detection can be implemented in the renderer process using the [`navigator.onLine`](http://html5index.org/Offline%20-%20NavigatorOnLine.html) attribute, part of standard HTML5 API. +The `navigator.onLine` attribute returns `false` if any network requests are guaranteed to fail i.e. definitely offline (disconnected from the network). It returns `true` in all other cases. Since all other conditions return `true`, one has to be mindful of getting false positives, as we cannot assume `true` value necessarily means that Electron can access the internet. Such as in cases where the computer is running a virtualization software that has virtual ethernet adapters that are always “connected.” Therefore, if you really want to determine the internet access status of Electron, you should develop additional means for checking. From 7be79613b8a7fa4ce775316d82388f10c82a8a2e Mon Sep 17 00:00:00 2001 From: Boik Date: Thu, 19 Oct 2017 00:56:05 +0800 Subject: [PATCH 042/185] according to https://github.com/electron/electron/pull/10670, update app.md --- docs/api/app.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/app.md b/docs/api/app.md index 6c8bdd1be8c..f7ff23e3a75 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -543,7 +543,7 @@ bar, and on macOS you can visit it from dock menu. Clears the recent documents list. -### `app.setAsDefaultProtocolClient(protocol[, path, args])` _macOS_ _Windows_ +### `app.setAsDefaultProtocolClient(protocol[, path, args])` * `protocol` String - The name of your protocol, without `://`. If you want your app to handle `electron://` links, call this method with `electron` as the From 90e7d7e1127015d85e3b2f93ee24fc041dcd60ee Mon Sep 17 00:00:00 2001 From: John Kleinschmidt Date: Wed, 18 Oct 2017 16:49:32 -0400 Subject: [PATCH 043/185] v1.8.2-beta.1 --- atom/browser/resources/mac/Info.plist | 4 ++-- atom/browser/resources/win/atom.rc | 8 ++++---- atom/common/atom_version.h | 2 +- electron.gyp | 2 +- package.json | 2 +- script/upload-to-github.js | 14 +++++++++++++- 6 files changed, 22 insertions(+), 10 deletions(-) diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 9f8c8173a91..3313eba36bb 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 1.8.1 + 1.8.2 CFBundleShortVersionString - 1.8.1 + 1.8.2 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 38b94f86f9b..0c4e97f97de 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -56,8 +56,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,8,1,0 - PRODUCTVERSION 1,8,1,0 + FILEVERSION 1,8,2,1 + PRODUCTVERSION 1,8,2,1 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -74,12 +74,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "1.8.1" + VALUE "FileVersion", "1.8.2" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "1.8.1" + VALUE "ProductVersion", "1.8.2" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index a7f2f8099e7..c80b709304a 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -7,7 +7,7 @@ #define ATOM_MAJOR_VERSION 1 #define ATOM_MINOR_VERSION 8 -#define ATOM_PATCH_VERSION 1 +#define ATOM_PATCH_VERSION 2 #define ATOM_VERSION_IS_RELEASE 1 diff --git a/electron.gyp b/electron.gyp index ff7ddf6952f..240c50d5bc2 100644 --- a/electron.gyp +++ b/electron.gyp @@ -4,7 +4,7 @@ 'product_name%': 'Electron', 'company_name%': 'GitHub, Inc', 'company_abbr%': 'github', - 'version%': '1.8.1', + 'version%': '1.8.2-beta.1', 'js2c_input_dir': '<(SHARED_INTERMEDIATE_DIR)/js2c', }, 'includes': [ diff --git a/package.json b/package.json index 39d4354f01b..166295ce568 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "1.8.1", + "version": "1.8.2-beta.1", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/script/upload-to-github.js b/script/upload-to-github.js index 45b82a285b2..e6ae78cb9bd 100644 --- a/script/upload-to-github.js +++ b/script/upload-to-github.js @@ -28,7 +28,19 @@ function uploadToGitHub () { if (retry < 4) { console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err) retry++ - uploadToGitHub() + github.repos.getAssets(githubOpts).then(assets => { + let existingAssets = assets.data.filter(asset => asset.name === fileName) + if (existingAssets.length > 0) { + console.log(`${fileName} already exists; will delete before retrying upload.`) + github.repos.deleteAsset({ + owner: 'electron', + repo: 'electron', + id: existingAssets[0].id + }).then(uploadToGitHub).catch(uploadToGitHub) + } else { + uploadToGitHub() + } + }) } else { console.log(`Error retrying uploading ${fileName} to GitHub:`, err) process.exitCode = 1 From 463260b249e3c438ad51d391e9bd2fdce2ffb797 Mon Sep 17 00:00:00 2001 From: Ahmed Mohamed Ali Date: Sat, 21 Oct 2017 22:21:24 +0200 Subject: [PATCH 044/185] Electron crashes if user clicks Dev Tools & Zoom options #10697 --- atom/browser/api/atom_api_web_contents.cc | 18 ++++++++++++------ atom/browser/api/atom_api_web_contents.h | 3 +++ 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 89727cb27d0..0cfc07e65a1 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -286,12 +286,13 @@ WebContents::WebContents(v8::Isolate* isolate, request_id_(0), background_throttling_(true), enable_devtools_(true) { + const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate); if (type == REMOTE) { web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); Init(isolate); AttachAsUserData(web_contents); + InitZoomController(web_contents, options); } else { - const mate::Dictionary options = mate::Dictionary::CreateEmpty(isolate); auto session = Session::CreateFrom(isolate, GetBrowserContext()); session_.Reset(isolate, session.ToV8()); InitWithSessionAndOptions(isolate, web_contents, session, options); @@ -392,6 +393,15 @@ WebContents::WebContents(v8::Isolate* isolate, const mate::Dictionary& options) InitWithSessionAndOptions(isolate, web_contents, session, options); } +void WebContents::InitZoomController(content::WebContents* web_contents, + const mate::Dictionary& options) { + WebContentsZoomController::CreateForWebContents(web_contents); + zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents); + double zoom_factor; + if (options.Get(options::kZoomFactor, &zoom_factor)) + zoom_controller_->SetDefaultZoomFactor(zoom_factor); +} + void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, content::WebContents *web_contents, mate::Handle session, @@ -409,11 +419,7 @@ void WebContents::InitWithSessionAndOptions(v8::Isolate* isolate, // Initialize security state client. SecurityStateTabHelper::CreateForWebContents(web_contents); // Initialize zoom controller. - WebContentsZoomController::CreateForWebContents(web_contents); - zoom_controller_ = WebContentsZoomController::FromWebContents(web_contents); - double zoom_factor; - if (options.Get(options::kZoomFactor, &zoom_factor)) - zoom_controller_->SetDefaultZoomFactor(zoom_factor); + InitZoomController(web_contents, options); web_contents->SetUserAgentOverride(GetBrowserContext()->GetUserAgent()); diff --git a/atom/browser/api/atom_api_web_contents.h b/atom/browser/api/atom_api_web_contents.h index 6aeab4e4c7a..7a63ce3af44 100644 --- a/atom/browser/api/atom_api_web_contents.h +++ b/atom/browser/api/atom_api_web_contents.h @@ -385,6 +385,9 @@ class WebContents : public mate::TrackableObject, // get the zoom level. void OnGetZoomLevel(IPC::Message* reply_msg); + void InitZoomController(content::WebContents* web_contents, + const mate::Dictionary& options); + v8::Global session_; v8::Global devtools_web_contents_; v8::Global debugger_; From 42f51850cc803f4e4164f447e62be9a1ea47d193 Mon Sep 17 00:00:00 2001 From: Toinane Date: Sun, 22 Oct 2017 00:15:30 +0200 Subject: [PATCH 045/185] Update OSR with more details --- docs/glossary.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index d1e2739e745..2e937b044e6 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -91,9 +91,11 @@ free software licenses, and is a widely-used alternative to commercial proprietary products like InstallShield. [electron-builder] supports NSIS as a build target. -## OSR +### OSR -Off-screen rendering. +OSR (Off-screen rendering) can be used for, e.g., loading heavy page in +background and then displaying it after (it will be much more faster). +It allows you to render page without show on screen. ### process From b7ebee985b0292eda5234c4555a13ee59914252a Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sun, 22 Oct 2017 23:51:33 -0400 Subject: [PATCH 046/185] refactor indexOfItemById --- lib/browser/api/menu.js | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 174acd7d919..bacebc702c6 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -10,7 +10,7 @@ var nextGroupId = 0 // Search between separators to find a radio menu item and return its group id, // otherwise generate a group id. -var generateGroupId = function (items, pos) { +function generateGroupId (items, pos) { var i, item, j, k, ref1, ref2, ref3 if (pos > 0) { for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) { @@ -37,19 +37,16 @@ var generateGroupId = function (items, pos) { } // Returns the index of item according to |id|. -var indexOfItemById = function (items, id) { - var i, item, j, len - for (i = j = 0, len = items.length; j < len; i = ++j) { - item = items[i] - if (item.id === id) { - return i - } +function indexOfItemById (items, id) { + for (let idx = 0; idx < items.length; idx += 1) { + const item = items[idx] + if (item.id === id) return idx } return -1 } // Returns the index of where to insert the item according to |position|. -var indexToInsertByPosition = function (items, position) { +function indexToInsertByPosition (items, position) { var insertIndex if (!position) { return items.length From 1cd53768ab93be81821a5130c79177530d1aecc7 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Sun, 22 Oct 2017 23:57:23 -0400 Subject: [PATCH 047/185] clean up indexToInsertByPosition --- lib/browser/api/menu.js | 51 +++++++++++++++++++---------------------- 1 file changed, 24 insertions(+), 27 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index bacebc702c6..f9b4862ed58 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -46,39 +46,36 @@ function indexOfItemById (items, id) { } // Returns the index of where to insert the item according to |position|. -function indexToInsertByPosition (items, position) { - var insertIndex - if (!position) { - return items.length - } - const [query, id] = position.split('=') - insertIndex = indexOfItemById(items, id) - if (insertIndex === -1 && query !== 'endof') { +function indexToInsertByPosition (items, pos) { + if (!pos) return items.length + + const [query, id] = pos.split('=') + let idx = indexOfItemById(items, id) + + if (idx === -1 && query !== 'endof') { console.warn("Item with id '" + id + "' is not found") return items.length } - switch (query) { - case 'after': - insertIndex++ - break - case 'endof': - // If the |id| doesn't exist, then create a new group with the |id|. - if (insertIndex === -1) { - items.push({ - id: id, - type: 'separator' - }) - insertIndex = items.length - 1 - } + if (query === 'after') { + idx += 1 + } else if (query === 'endof') { + // create new group with id if none exists + if (idx === -1) { + items.push({ + id, + type: 'separator' + }) + idx = items.length - 1 + } + idx += 1 - // Find the end of the group. - insertIndex++ - while (insertIndex < items.length && items[insertIndex].type !== 'separator') { - insertIndex++ - } + // search for end of group + while (idx < items.length && items[idx].type !== 'separator') { + idx += 1 + } } - return insertIndex + return idx } const Menu = bindings.Menu From f9c3123f5f6086c06c69731140fff6b94d7745d7 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 00:16:35 -0400 Subject: [PATCH 048/185] clean up menuWillShow --- lib/browser/api/menu.js | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index f9b4862ed58..0ee05a06edd 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -88,15 +88,15 @@ Menu.prototype._init = function () { this.items = [] this.delegate = { isCommandIdChecked: (commandId) => { - var command = this.commandsMap[commandId] + const command = this.commandsMap[commandId] return command != null ? command.checked : undefined }, isCommandIdEnabled: (commandId) => { - var command = this.commandsMap[commandId] + const command = this.commandsMap[commandId] return command != null ? command.enabled : undefined }, isCommandIdVisible: (commandId) => { - var command = this.commandsMap[commandId] + const command = this.commandsMap[commandId] return command != null ? command.visible : undefined }, getAcceleratorForCommandId: (commandId, useDefaultAccelerator) => { @@ -106,7 +106,7 @@ Menu.prototype._init = function () { if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() }, getIconForCommandId: (commandId) => { - var command = this.commandsMap[commandId] + const command = this.commandsMap[commandId] return command != null ? command.icon : undefined }, executeCommand: (event, commandId) => { @@ -115,23 +115,17 @@ Menu.prototype._init = function () { command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) }, menuWillShow: () => { - // Make sure radio groups have at least one menu item seleted. - var checked, group, id, j, len, radioItem, ref1 - ref1 = this.groupsMap - for (id in ref1) { - group = ref1[id] - checked = false - for (j = 0, len = group.length; j < len; j++) { - radioItem = group[j] - if (!radioItem.checked) { - continue - } + // Make sure radio groups have at least one menu item selected + for (let id in this.groupsMap) { + const group = this.groupsMap[id] + const checked = false + for (let idx = 0; idx < group.length; idx++) { + const radioItem = group[idx] + if (!radioItem.checked) continue checked = true break } - if (!checked) { - v8Util.setHiddenValue(group[0], 'checked', true) - } + if (!checked) v8Util.setHiddenValue(group[0], 'checked', true) } } } From 61a93c711cd1ab89cf747ad7f6fc90ee16762eba Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 00:47:02 -0400 Subject: [PATCH 049/185] clean up popup --- lib/browser/api/menu.js | 35 +++++++++++++---------------------- 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 0ee05a06edd..421462671fb 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -132,40 +132,31 @@ Menu.prototype._init = function () { } Menu.prototype.popup = function (window, x, y, positioningItem) { + let [newX, newY, newPositioningItem] = [x, y, positioningItem] let asyncPopup // menu.popup(x, y, positioningItem) - if (window != null && (typeof window !== 'object' || window.constructor !== BrowserWindow)) { - // Shift. - positioningItem = y - y = x - x = window - window = null + if (window != null) { + if (typeof window !== 'object' || window.constructor !== BrowserWindow) { + [newPositioningItem, newY, newX] = [y, x, window] + window = null + } } // menu.popup(window, {}) if (x != null && typeof x === 'object') { - const options = x - x = options.x - y = options.y - positioningItem = options.positioningItem - asyncPopup = options.async + [newX, newY, newPositioningItem] = [x.x, x.y, x.positioningItem] + asyncPopup = x.async } - // Default to showing in focused window. + // set up defaults if (window == null) window = BrowserWindow.getFocusedWindow() - - // Default to showing under mouse location. - if (typeof x !== 'number') x = -1 - if (typeof y !== 'number') y = -1 - - // Default to not highlighting any item. - if (typeof positioningItem !== 'number') positioningItem = -1 - - // Default to synchronous for backwards compatibility. + if (typeof x !== 'number') newX = -1 + if (typeof y !== 'number') newY = -1 + if (typeof positioningItem !== 'number') newPositioningItem = -1 if (typeof asyncPopup !== 'boolean') asyncPopup = false - this.popupAt(window, x, y, positioningItem, asyncPopup) + this.popupAt(window, newX, newY, newPositioningItem, asyncPopup) } Menu.prototype.closePopup = function (window) { From 66846bff975f92dd721d5ca29f332edf3795f1c0 Mon Sep 17 00:00:00 2001 From: John Kleinschmidt Date: Mon, 23 Oct 2017 11:02:50 -0400 Subject: [PATCH 050/185] Automate release (#10827) * Create prepare-release script * Add script to merge release * Cleanup/add logging * Move release process out of upload.py * Add cleanup release branch * Update release doc to reflect new scripts * Fix to allow running with notesOnly Also fixup release name and body when beta release. * Fix issues found during release * Use getRelease instead of getAssets github.repos.getAssets is limited to 30 entries which means we may not get back the file we are looking for. * Documentation corrections --- docs/development/releasing.md | 143 +++++------ package.json | 11 +- script/bump-version.py | 1 + script/merge-release.js | 116 +++++++++ script/prepare-release.js | 173 +++++++++++++ script/prerelease.js | 114 --------- script/publish-to-npm.js | 2 +- script/release.js | 462 ++++++++++++++++++++++++++++++++++ script/upload-to-github.js | 4 +- script/upload.py | 52 +--- 10 files changed, 836 insertions(+), 242 deletions(-) create mode 100755 script/merge-release.js create mode 100755 script/prepare-release.js delete mode 100755 script/prerelease.js create mode 100755 script/release.js diff --git a/docs/development/releasing.md b/docs/development/releasing.md index 667c3112512..a72d7d151fb 100644 --- a/docs/development/releasing.md +++ b/docs/development/releasing.md @@ -2,47 +2,51 @@ This document describes the process for releasing a new version of Electron. -## Find out what version change is needed -Is this a major, minor, patch, or beta version change? Read the [Version Change Rules](../tutorial/electron-versioning.md#version-change-rules) to find out. - -## Create a temporary branch +## Determine which branch to release from - **If releasing beta,** create a new branch from `master`. -- **If releasing a stable version,** create a new branch from the beta branch you're stablizing. +- **If releasing a stable version,** create a new branch from the beta branch you're stabilizing. -Name the new branch `release` or anything you like. +## Find out what version change is needed +Run `npm run prepare-release -- --notesOnly` to view auto generated release +notes. The notes generated should help you determine if this is a major, minor, +patch, or beta version change. Read the +[Version Change Rules](../tutorial/electron-versioning.md#version-change-rules) for more information. +## Run the prepare-release script +The prepare release script will do the following: +1. Check if a release is already in process and if so it will halt. +2. Create a release branch. +3. Bump the version number in several files. See [this bump commit] for an example. +4. Create a draft release on GitHub with auto-generated release notes +5. Push the release branch so that the release builds get built. +Once you have determined which type of version change is needed, run the +`prepare-release` script with arguments according to your need: +- `[major|minor|patch|beta]` to increment one of the version numbers, or +- `--stable` to indicate this is a stable version + +For example: + +### Major version change ```sh -git checkout master -git pull -git checkout -b release +npm run prepare-release -- major ``` - -This branch is created as a precaution to prevent any merged PRs from sneaking into a release between the time the temporary release branch is created and the CI builds are complete. - -## Check for extant drafts - -The upload script [looks for an existing draft release](https://github.com/electron/electron/blob/7961a97d7ddbed657c6c867cc8426e02c236c077/script/upload.py#L173-L181). To prevent your new release -from clobbering an existing draft, check [the releases page] and -make sure there are no drafts. - -## Bump the version - -Run the `bump-version` script with arguments according to your need: -- `--bump=[major|minor|patch|beta]` to increment one of the version numbers, or -- `--stable` to indicate this is a stable version, or -- `--version={version}` to set version number directly. - -**Note**: you can use both `--bump` and `--stable` simultaneously. - -There is also a `dry-run` flag you can use to make sure the version number generated is correct before committing. - +### Minor version change ```sh -npm run bump-version -- --bump=patch --stable -git push origin HEAD +npm run prepare-release -- minor +``` +### Patch version change +```sh +npm run prepare-release -- patch +``` +### Beta version change +```sh +npm run prepare-release -- beta +``` +### Promote beta to stable +```sh +npm run prepare-release -- --stable ``` - -This will bump the version number in several files. See [this bump commit] for an example. ## Wait for builds :hourglass_flowing_sand: @@ -159,65 +163,46 @@ This release is published to [npm](https://www.npmjs.com/package/electron) under 1. Uncheck the `prerelease` checkbox if you're publishing a stable release; leave it checked for beta releases. 1. Click 'Save draft'. **Do not click 'Publish release'!** 1. Wait for all builds to pass before proceeding. +1. You can run `npm run release --validateRelease` to verify that all of the +required files have been created for the release. ## Merge temporary branch +Once the release builds have finished, merge the `release` branch back into +the source release branch using the `merge-release` script. +If the branch cannot be successfully merged back this script will automatically +rebase the `release` branch and push the changes which will trigger the release +builds again, which means you will need to wait for the release builds to run +again before proceeding. -Merge the temporary branch back into master, without creating a merge commit: - +### Merging back into master ```sh -git checkout master -git merge release --no-commit -git push origin master +npm run merge-release -- master ``` -If this fails, rebase with master and rebuild: - +### Merging back into old release branch ```sh -git pull -git checkout release -git rebase master -git push origin HEAD +npm run merge-release -- 1-7-x ``` -## Run local debug build - -Run local debug build to verify that you are actually building the version you want. Sometimes you thought you were doing a release for a new version, but you're actually not. - -```sh -npm run build -npm start -``` - -Verify the window is displaying the current updated version. - -## Set environment variables - -You'll need to set the following environment variables to publish a release. Ask another team member for these credentials. - -- `ELECTRON_S3_BUCKET` -- `ELECTRON_S3_ACCESS_KEY` -- `ELECTRON_S3_SECRET_KEY` -- `ELECTRON_GITHUB_TOKEN` - A personal access token with "repo" scope. - -You will only need to do this once. - ## Publish the release -This script will download the binaries and generate the node headers and the .lib linker used on Windows by node-gyp to build native modules. +Once the merge has finished successfully, run the `release` script +via `npm run release` to finish the release process. This script will do the +following: +1. Build the project to validate that the correct version number is being released. +2. Download the binaries and generate the node headers and the .lib linker used +on Windows by node-gyp to build native modules. +3. Create and upload the SHASUMS files stored on S3 for the node files. +4. Create and upload the SHASUMS256.txt file stored on the GitHub release. +5. Validate that all of the required files are present on GitHub and S3 and have +the correct checksums as specified in the SHASUMS files. +6. Publish the release on GitHub +7. Delete the `release` branch. -```sh -npm run release -``` +## Publish to npm -Note: Many distributions of Python still ship with old HTTPS certificates. You may see a `InsecureRequestWarning`, but it can be disregarded. - -## Delete the temporary branch - -```sh -git checkout master -git branch -D release # delete local branch -git push origin :release # delete remote branch -``` +Once the publish is successful, run `npm run publish-to-npm` to publish to +release to npm. [the releases page]: https://github.com/electron/electron/releases [this bump commit]: https://github.com/electron/electron/commit/78ec1b8f89b3886b856377a1756a51617bc33f5a diff --git a/package.json b/package.json index 166295ce568..e4a1cdc5199 100644 --- a/package.json +++ b/package.json @@ -9,15 +9,18 @@ "check-for-leaks": "^1.0.2", "colors": "^1.1.2", "dotenv-safe": "^4.0.4", + "dugite": "^1.45.0", "electabul": "~0.0.4", "electron-docs-linter": "^2.3.3", "electron-typescript-definitions": "^1.2.7", "github": "^9.2.0", - "heads": "^1.3.0", "husky": "^0.14.3", + "minimist": "^1.2.0", + "nugget": "^2.0.1", "request": "^2.68.0", "standard": "^8.4.0", "standard-markdown": "^4.0.0", + "sumchecker": "^2.0.2", "temp": "^0.8.3" }, "standard": { @@ -49,12 +52,14 @@ "lint-api-docs-js": "standard-markdown docs && standard-markdown docs-translations", "create-api-json": "electron-docs-linter docs --outfile=out/electron-api.json --version=$npm_package_version", "create-typescript-definitions": "npm run create-api-json && electron-typescript-definitions --in=out/electron-api.json --out=out/electron.d.ts", + "merge-release": "node ./script/merge-release.js", "preinstall": "node -e 'process.exit(0)'", "publish-to-npm": "node ./script/publish-to-npm.js", "prepack": "check-for-leaks", "prepush": "check-for-leaks", - "prerelease": "node ./script/prerelease", - "release": "./script/upload.py -p", + "prepare-release": "node ./script/prepare-release.js", + "prerelease": "python ./script/bootstrap.py -v --dev && npm run build", + "release": "node ./script/release.js", "repl": "python ./script/start.py --interactive", "start": "python ./script/start.py", "test": "python ./script/test.py" diff --git a/script/bump-version.py b/script/bump-version.py index 8664736cca3..42d6392baef 100755 --- a/script/bump-version.py +++ b/script/bump-version.py @@ -90,6 +90,7 @@ def main(): update_package_json(version, suffix) tag_version(version, suffix) + print 'Bumped to version: {0}'.format(version + suffix) def increase_version(versions, index): for i in range(index + 1, 4): diff --git a/script/merge-release.js b/script/merge-release.js new file mode 100755 index 00000000000..60ac3acb244 --- /dev/null +++ b/script/merge-release.js @@ -0,0 +1,116 @@ +#!/usr/bin/env node + +require('colors') +const assert = require('assert') +const branchToRelease = process.argv[2] +const fail = '\u2717'.red +const { GitProcess, GitError } = require('dugite') +const pass = '\u2713'.green +const path = require('path') +const pkg = require('../package.json') + +assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment') +if (!branchToRelease) { + console.log(`Usage: merge-release branch`) + process.exit(1) +} +const gitDir = path.resolve(__dirname, '..') + +async function callGit (args, errorMessage, successMessage) { + let gitResult = await GitProcess.exec(args, gitDir) + if (gitResult.exitCode === 0) { + console.log(`${pass} ${successMessage}`) + return true + } else { + console.log(`${fail} ${errorMessage} ${gitResult.stderr}`) + process.exit(1) + } +} + +async function checkoutBranch (branchName) { + console.log(`Checking out ${branchName}.`) + let errorMessage = `Error checking out branch ${branchName}:` + let successMessage = `Successfully checked out branch ${branchName}.` + return await callGit(['checkout', branchName], errorMessage, successMessage) +} + +async function commitMerge () { + console.log(`Committing the merge for v${pkg.version}`) + let errorMessage = `Error committing merge:` + let successMessage = `Successfully committed the merge for v${pkg.version}` + let gitArgs = ['commit', '-m', `v${pkg.version}`] + return await callGit(gitArgs, errorMessage, successMessage) +} + +async function mergeReleaseIntoBranch (branchName) { + console.log(`Merging release branch into ${branchName}.`) + let mergeArgs = ['merge', 'release', '--squash'] + let mergeDetails = await GitProcess.exec(mergeArgs, gitDir) + if (mergeDetails.exitCode === 0) { + return true + } else { + const error = GitProcess.parseError(mergeDetails.stderr) + if (error === GitError.MergeConflicts) { + console.log(`${fail} Could not merge release branch into ${branchName} ` + + `due to merge conflicts.`) + return false + } else { + console.log(`${fail} Could not merge release branch into ${branchName} ` + + `due to an error: ${mergeDetails.stderr}.`) + process.exit(1) + } + } +} + +async function pushBranch (branchName) { + console.log(`Pushing branch ${branchName}.`) + let pushArgs = ['push', 'origin', branchName] + let errorMessage = `Could not push branch ${branchName} due to an error:` + let successMessage = `Successfully pushed branch ${branchName}.` + return await callGit(pushArgs, errorMessage, successMessage) +} + +async function pull () { + console.log(`Performing a git pull`) + let errorMessage = `Could not pull due to an error:` + let successMessage = `Successfully performed a git pull` + return await callGit(['pull'], errorMessage, successMessage) +} + +async function rebase (targetBranch) { + console.log(`Rebasing release branch from ${targetBranch}`) + let errorMessage = `Could not rebase due to an error:` + let successMessage = `Successfully rebased release branch from ` + + `${targetBranch}` + return await callGit(['rebase', targetBranch], errorMessage, successMessage) +} + +async function mergeRelease () { + await checkoutBranch(branchToRelease) + let mergeSuccess = await mergeReleaseIntoBranch(branchToRelease) + if (mergeSuccess) { + console.log(`${pass} Successfully merged release branch into ` + + `${branchToRelease}.`) + await commitMerge() + let pushSuccess = await pushBranch(branchToRelease) + if (pushSuccess) { + console.log(`${pass} Success!!! ${branchToRelease} now has the latest release!`) + } + } else { + console.log(`Trying rebase of ${branchToRelease} into release branch.`) + await pull() + await checkoutBranch('release') + let rebaseResult = await rebase(branchToRelease) + if (rebaseResult) { + let pushResult = pushBranch('HEAD') + if (pushResult) { + console.log(`Rebase of ${branchToRelease} into release branch was ` + + `successful. Let release builds run and then try this step again.`) + } + // Exit as failure so release doesn't continue + process.exit(1) + } + } +} + +mergeRelease() diff --git a/script/prepare-release.js b/script/prepare-release.js new file mode 100755 index 00000000000..708dbffee29 --- /dev/null +++ b/script/prepare-release.js @@ -0,0 +1,173 @@ +#!/usr/bin/env node + +require('colors') +const args = require('minimist')(process.argv.slice(2)) +const assert = require('assert') +const { execSync } = require('child_process') +const fail = '\u2717'.red +const { GitProcess, GitError } = require('dugite') +const GitHub = require('github') +const pass = '\u2713'.green +const path = require('path') +const pkg = require('../package.json') +const versionType = args._[0] + +// TODO (future) automatically determine version based on conventional commits +// via conventional-recommended-bump + +assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment') +if (!versionType && !args.notesOnly) { + console.log(`Usage: prepare-release versionType [major | minor | patch | beta]` + + ` (--stable) (--notesOnly)`) + process.exit(1) +} + +const github = new GitHub() +const gitDir = path.resolve(__dirname, '..') +github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN}) + +async function createReleaseBranch () { + console.log(`Creating release branch.`) + let checkoutDetails = await GitProcess.exec([ 'checkout', '-b', 'release' ], gitDir) + if (checkoutDetails.exitCode === 0) { + console.log(`${pass} Successfully created the release branch.`) + } else { + const error = GitProcess.parseError(checkoutDetails.stderr) + if (error === GitError.BranchAlreadyExists) { + console.log(`${fail} Release branch already exists, aborting prepare ` + + `release process.`) + } else { + console.log(`${fail} Error creating release branch: ` + + `${checkoutDetails.stderr}`) + } + process.exit(1) + } +} + +function getNewVersion () { + console.log(`Bumping for new "${versionType}" version.`) + let bumpScript = path.join(__dirname, 'bump-version.py') + let scriptArgs = [bumpScript, `--bump ${versionType}`] + if (args.stable) { + scriptArgs.push('--stable') + } + try { + let bumpVersion = execSync(scriptArgs.join(' '), {encoding: 'UTF-8'}) + bumpVersion = bumpVersion.substr(bumpVersion.indexOf(':') + 1).trim() + let newVersion = `v${bumpVersion}` + console.log(`${pass} Successfully bumped version to ${newVersion}`) + return newVersion + } catch (err) { + console.log(`${fail} Could not bump version, error was:`, err) + } +} + +async function getCurrentBranch (gitDir) { + console.log(`Determining current git branch`) + let gitArgs = ['rev-parse', '--abbrev-ref', 'HEAD'] + let branchDetails = await GitProcess.exec(gitArgs, gitDir) + if (branchDetails.exitCode === 0) { + let currentBranch = branchDetails.stdout.trim() + console.log(`${pass} Successfully determined current git branch is ` + + `${currentBranch}`) + return currentBranch + } else { + let error = GitProcess.parseError(branchDetails.stderr) + console.log(`${fail} Could not get details for the current branch, + error was ${branchDetails.stderr}`, error) + process.exit(1) + } +} + +async function getReleaseNotes (currentBranch) { + console.log(`Generating release notes for ${currentBranch}.`) + let githubOpts = { + owner: 'electron', + repo: 'electron', + base: `v${pkg.version}`, + head: currentBranch + } + let releaseNotes = '(placeholder)\n' + console.log(`Checking for commits from ${pkg.version} to ${currentBranch}`) + let commitComparison = await github.repos.compareCommits(githubOpts) + .catch(err => { + console.log(`{$fail} Error checking for commits from ${pkg.version} to ` + + `${currentBranch}`, err) + process.exit(1) + }) + + commitComparison.data.commits.forEach(commitEntry => { + let commitMessage = commitEntry.commit.message + if (commitMessage.toLowerCase().indexOf('merge') > -1) { + releaseNotes += `${commitMessage} \n` + } + }) + console.log(`${pass} Done generating release notes for ${currentBranch}.`) + return releaseNotes +} + +async function createRelease (branchToTarget, isBeta) { + let releaseNotes = await getReleaseNotes(branchToTarget) + let newVersion = getNewVersion() + const githubOpts = { + owner: 'electron', + repo: 'electron' + } + console.log(`Checking for existing draft release.`) + let releases = await github.repos.getReleases(githubOpts) + .catch(err => { + console.log('$fail} Could not get releases. Error was', err) + }) + let drafts = releases.data.filter(release => release.draft) + if (drafts.length > 0) { + console.log(`${fail} Aborting because draft release for + ${drafts[0].release.tag_name} already exists.`) + process.exit(1) + } + console.log(`${pass} A draft release does not exist; creating one.`) + githubOpts.body = releaseNotes + githubOpts.draft = true + githubOpts.name = `electron ${newVersion}` + if (isBeta) { + githubOpts.body = `Note: This is a beta release. Please file new issues ` + + `for any bugs you find in it.\n \n This release is published to npm ` + + `under the beta tag and can be installed via npm install electron@beta, ` + + `or npm i electron@${newVersion.substr(1)}.` + githubOpts.name = `${githubOpts.name}` + githubOpts.prerelease = true + } + githubOpts.tag_name = newVersion + githubOpts.target_commitish = branchToTarget + await github.repos.createRelease(githubOpts) + .catch(err => { + console.log(`${fail} Error creating new release: `, err) + process.exit(1) + }) + console.log(`${pass} Draft release for ${newVersion} has been created.`) +} + +async function pushRelease () { + let pushDetails = await GitProcess.exec(['push', 'origin', 'HEAD'], gitDir) + if (pushDetails.exitCode === 0) { + console.log(`${pass} Successfully pushed the release branch. Wait for ` + + `release builds to finish before running "npm run release".`) + } else { + console.log(`${fail} Error pushing the release branch: ` + + `${pushDetails.stderr}`) + process.exit(1) + } +} + +async function prepareRelease (isBeta, notesOnly) { + let currentBranch = await getCurrentBranch(gitDir) + if (notesOnly) { + let releaseNotes = await getReleaseNotes(currentBranch) + console.log(`Draft release notes are: ${releaseNotes}`) + } else { + await createReleaseBranch() + await createRelease(currentBranch, isBeta) + await pushRelease() + } +} + +prepareRelease(!args.stable, args.notesOnly) diff --git a/script/prerelease.js b/script/prerelease.js deleted file mode 100755 index 5dd4be1ff55..00000000000 --- a/script/prerelease.js +++ /dev/null @@ -1,114 +0,0 @@ -#!/usr/bin/env node - -require('colors') -const assert = require('assert') -const GitHub = require('github') -const heads = require('heads') -const pkg = require('../package.json') -const pass = '\u2713'.green -const fail = '\u2717'.red -let failureCount = 0 - -assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment') - -const github = new GitHub() -github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN}) -github.repos.getReleases({owner: 'electron', repo: 'electron'}) - .then(res => { - const releases = res.data - const drafts = releases - .filter(release => release.draft) // comment out for testing - // .filter(release => release.tag_name === 'v1.7.5') // uncomment for testing - - check(drafts.length === 1, 'one draft exists', true) - const draft = drafts[0] - - check(draft.tag_name === `v${pkg.version}`, `draft release version matches local package.json (v${pkg.version})`) - check(draft.body.length > 50 && !draft.body.includes('(placeholder)'), 'draft has release notes') - - const requiredAssets = assetsForVersion(draft.tag_name).sort() - const extantAssets = draft.assets.map(asset => asset.name).sort() - - requiredAssets.forEach(asset => { - check(extantAssets.includes(asset), asset) - }) - - const s3Urls = s3UrlsForVersion(draft.tag_name) - heads(s3Urls) - .then(results => { - results.forEach((result, i) => { - check(result === 200, s3Urls[i]) - }) - - process.exit(failureCount > 0 ? 1 : 0) - }) - .catch(err => { - console.error('Error making HEAD requests for S3 assets') - console.error(err) - process.exit(1) - }) - }) - -function check (condition, statement, exitIfFail = false) { - if (condition) { - console.log(`${pass} ${statement}`) - } else { - failureCount++ - console.log(`${fail} ${statement}`) - if (exitIfFail) process.exit(1) - } -} - -function assetsForVersion (version) { - const patterns = [ - 'electron-{{VERSION}}-darwin-x64-dsym.zip', - 'electron-{{VERSION}}-darwin-x64-symbols.zip', - 'electron-{{VERSION}}-darwin-x64.zip', - 'electron-{{VERSION}}-linux-arm-symbols.zip', - 'electron-{{VERSION}}-linux-arm.zip', - 'electron-{{VERSION}}-linux-arm64-symbols.zip', - 'electron-{{VERSION}}-linux-arm64.zip', - 'electron-{{VERSION}}-linux-armv7l-symbols.zip', - 'electron-{{VERSION}}-linux-armv7l.zip', - 'electron-{{VERSION}}-linux-ia32-symbols.zip', - 'electron-{{VERSION}}-linux-ia32.zip', - 'electron-{{VERSION}}-linux-x64-symbols.zip', - 'electron-{{VERSION}}-linux-x64.zip', - 'electron-{{VERSION}}-mas-x64-dsym.zip', - 'electron-{{VERSION}}-mas-x64-symbols.zip', - 'electron-{{VERSION}}-mas-x64.zip', - 'electron-{{VERSION}}-win32-ia32-pdb.zip', - 'electron-{{VERSION}}-win32-ia32-symbols.zip', - 'electron-{{VERSION}}-win32-ia32.zip', - 'electron-{{VERSION}}-win32-x64-pdb.zip', - 'electron-{{VERSION}}-win32-x64-symbols.zip', - 'electron-{{VERSION}}-win32-x64.zip', - 'electron-api.json', - 'electron.d.ts', - 'ffmpeg-{{VERSION}}-darwin-x64.zip', - 'ffmpeg-{{VERSION}}-linux-arm.zip', - 'ffmpeg-{{VERSION}}-linux-arm64.zip', - 'ffmpeg-{{VERSION}}-linux-armv7l.zip', - 'ffmpeg-{{VERSION}}-linux-ia32.zip', - 'ffmpeg-{{VERSION}}-linux-x64.zip', - 'ffmpeg-{{VERSION}}-mas-x64.zip', - 'ffmpeg-{{VERSION}}-win32-ia32.zip', - 'ffmpeg-{{VERSION}}-win32-x64.zip' - ] - return patterns.map(pattern => pattern.replace(/{{VERSION}}/g, version)) -} - -function s3UrlsForVersion (version) { - const bucket = 'https://gh-contractor-zcbenz.s3.amazonaws.com/' - const patterns = [ - 'atom-shell/dist/{{VERSION}}/iojs-{{VERSION}}-headers.tar.gz', - 'atom-shell/dist/{{VERSION}}/iojs-{{VERSION}}.tar.gz', - 'atom-shell/dist/{{VERSION}}/node-{{VERSION}}.tar.gz', - 'atom-shell/dist/{{VERSION}}/node.lib', - 'atom-shell/dist/{{VERSION}}/win-x64/iojs.lib', - 'atom-shell/dist/{{VERSION}}/win-x86/iojs.lib', - 'atom-shell/dist/{{VERSION}}/x64/node.lib', - 'atom-shell/dist/index.json' - ] - return patterns.map(pattern => bucket + pattern.replace(/{{VERSION}}/g, version)) -} diff --git a/script/publish-to-npm.js b/script/publish-to-npm.js index 21960455cfe..aaf93f33cd9 100644 --- a/script/publish-to-npm.js +++ b/script/publish-to-npm.js @@ -114,7 +114,7 @@ new Promise((resolve, reject) => { cwd: tempDir }) const checkVersion = childProcess.execSync(`${path.join(tempDir, 'node_modules', '.bin', 'electron')} -v`) - assert.strictEqual(checkVersion.toString().trim(), `v${rootPackageJson.version}`) + assert.ok((`v${rootPackageJson.version}`.indexOf(checkVersion.toString().trim()) === 0), `Version is correct`) resolve(tarballPath) }) }) diff --git a/script/release.js b/script/release.js new file mode 100755 index 00000000000..42c55b5cee3 --- /dev/null +++ b/script/release.js @@ -0,0 +1,462 @@ +#!/usr/bin/env node + +require('colors') +const args = require('minimist')(process.argv.slice(2)) +const assert = require('assert') +const fs = require('fs') +const { execSync } = require('child_process') +const GitHub = require('github') +const { GitProcess } = require('dugite') +const nugget = require('nugget') +const pkg = require('../package.json') +const pkgVersion = `v${pkg.version}` +const pass = '\u2713'.green +const path = require('path') +const fail = '\u2717'.red +const sumchecker = require('sumchecker') +const temp = require('temp').track() +const { URL } = require('url') +let failureCount = 0 + +assert(process.env.ELECTRON_GITHUB_TOKEN, 'ELECTRON_GITHUB_TOKEN not found in environment') + +const github = new GitHub({ + followRedirects: false +}) +github.authenticate({type: 'token', token: process.env.ELECTRON_GITHUB_TOKEN}) +const gitDir = path.resolve(__dirname, '..') + +async function getDraftRelease (version, skipValidation) { + let releaseInfo = await github.repos.getReleases({owner: 'electron', repo: 'electron'}) + let drafts + let versionToCheck + if (version) { + drafts = releaseInfo.data + .filter(release => release.tag_name === version) + versionToCheck = version + } else { + drafts = releaseInfo.data + .filter(release => release.draft) + versionToCheck = pkgVersion + } + + const draft = drafts[0] + if (!skipValidation) { + failureCount = 0 + check(drafts.length === 1, 'one draft exists', true) + check(draft.tag_name === versionToCheck, `draft release version matches local package.json (${versionToCheck})`) + if (versionToCheck.indexOf('beta')) { + check(draft.prerelease, 'draft is a prerelease') + } + check(draft.body.length > 50 && !draft.body.includes('(placeholder)'), 'draft has release notes') + check((failureCount === 0), `Draft release looks good to go.`, true) + } + return draft +} + +async function validateReleaseAssets (release) { + const requiredAssets = assetsForVersion(release.tag_name).sort() + const extantAssets = release.assets.map(asset => asset.name).sort() + const downloadUrls = release.assets.map(asset => asset.browser_download_url).sort() + + failureCount = 0 + requiredAssets.forEach(asset => { + check(extantAssets.includes(asset), asset) + }) + check((failureCount === 0), `All required GitHub assets exist for release`, true) + + if (release.draft) { + await verifyAssets(release) + } else { + await verifyShasums(downloadUrls) + .catch(err => { + console.log(`${fail} error verifyingShasums`, err) + }) + } + const s3Urls = s3UrlsForVersion(release.tag_name) + await verifyShasums(s3Urls, true) +} + +function check (condition, statement, exitIfFail = false) { + if (condition) { + console.log(`${pass} ${statement}`) + } else { + failureCount++ + console.log(`${fail} ${statement}`) + if (exitIfFail) process.exit(1) + } +} + +function assetsForVersion (version) { + const patterns = [ + `electron-${version}-darwin-x64-dsym.zip`, + `electron-${version}-darwin-x64-symbols.zip`, + `electron-${version}-darwin-x64.zip`, + `electron-${version}-linux-arm-symbols.zip`, + `electron-${version}-linux-arm.zip`, + `electron-${version}-linux-arm64-symbols.zip`, + `electron-${version}-linux-arm64.zip`, + `electron-${version}-linux-armv7l-symbols.zip`, + `electron-${version}-linux-armv7l.zip`, + `electron-${version}-linux-ia32-symbols.zip`, + `electron-${version}-linux-ia32.zip`, + `electron-${version}-linux-x64-symbols.zip`, + `electron-${version}-linux-x64.zip`, + `electron-${version}-mas-x64-dsym.zip`, + `electron-${version}-mas-x64-symbols.zip`, + `electron-${version}-mas-x64.zip`, + `electron-${version}-win32-ia32-pdb.zip`, + `electron-${version}-win32-ia32-symbols.zip`, + `electron-${version}-win32-ia32.zip`, + `electron-${version}-win32-x64-pdb.zip`, + `electron-${version}-win32-x64-symbols.zip`, + `electron-${version}-win32-x64.zip`, + `electron-api.json`, + `electron.d.ts`, + `ffmpeg-${version}-darwin-x64.zip`, + `ffmpeg-${version}-linux-arm.zip`, + `ffmpeg-${version}-linux-arm64.zip`, + `ffmpeg-${version}-linux-armv7l.zip`, + `ffmpeg-${version}-linux-ia32.zip`, + `ffmpeg-${version}-linux-x64.zip`, + `ffmpeg-${version}-mas-x64.zip`, + `ffmpeg-${version}-win32-ia32.zip`, + `ffmpeg-${version}-win32-x64.zip`, + `SHASUMS256.txt` + ] + return patterns +} + +function s3UrlsForVersion (version) { + const bucket = `https://gh-contractor-zcbenz.s3.amazonaws.com/` + const patterns = [ + `${bucket}atom-shell/dist/${version}/iojs-${version}-headers.tar.gz`, + `${bucket}atom-shell/dist/${version}/iojs-${version}.tar.gz`, + `${bucket}atom-shell/dist/${version}/node-${version}.tar.gz`, + `${bucket}atom-shell/dist/${version}/node.lib`, + `${bucket}atom-shell/dist/${version}/win-x64/iojs.lib`, + `${bucket}atom-shell/dist/${version}/win-x86/iojs.lib`, + `${bucket}atom-shell/dist/${version}/x64/node.lib`, + `${bucket}atom-shell/dist/${version}/SHASUMS.txt`, + `${bucket}atom-shell/dist/${version}/SHASUMS256.txt`, + `${bucket}atom-shell/dist/index.json` + ] + return patterns +} + +function checkVersion () { + console.log(`Verifying that app version matches package version ${pkgVersion}.`) + let startScript = path.join(__dirname, 'start.py') + let appVersion = runScript(startScript, ['--version']).trim() + check((pkgVersion.indexOf(appVersion) === 0), `App version ${appVersion} matches ` + + `package version ${pkgVersion}.`, true) +} + +function runScript (scriptName, scriptArgs, cwd) { + let scriptCommand = `${scriptName} ${scriptArgs.join(' ')}` + let scriptOptions = { + encoding: 'UTF-8' + } + if (cwd) { + scriptOptions.cwd = cwd + } + try { + return execSync(scriptCommand, scriptOptions) + } catch (err) { + console.log(`${fail} Error running ${scriptName}`, err) + process.exit(1) + } +} + +function uploadNodeShasums () { + console.log('Uploading Node SHASUMS file to S3.') + let scriptPath = path.join(__dirname, 'upload-node-checksums.py') + runScript(scriptPath, ['-v', pkgVersion]) + console.log(`${pass} Done uploading Node SHASUMS file to S3.`) +} + +function uploadIndexJson () { + console.log('Uploading index.json to S3.') + let scriptPath = path.join(__dirname, 'upload-index-json.py') + runScript(scriptPath, []) + console.log(`${pass} Done uploading index.json to S3.`) +} + +async function createReleaseShasums (release) { + let fileName = 'SHASUMS256.txt' + let existingAssets = release.assets.filter(asset => asset.name === fileName) + if (existingAssets.length > 0) { + console.log(`${fileName} already exists on GitHub; deleting before creating new file.`) + await github.repos.deleteAsset({ + owner: 'electron', + repo: 'electron', + id: existingAssets[0].id + }).catch(err => { + console.log(`${fail} Error deleting ${fileName} on GitHub:`, err) + }) + } + console.log(`Creating and uploading the release ${fileName}.`) + let scriptPath = path.join(__dirname, 'merge-electron-checksums.py') + let checksums = runScript(scriptPath, ['-v', pkgVersion]) + console.log(`${pass} Generated release SHASUMS.`) + let filePath = await saveShaSumFile(checksums, fileName) + console.log(`${pass} Created ${fileName} file.`) + await uploadShasumFile(filePath, fileName, release) + console.log(`${pass} Successfully uploaded ${fileName} to GitHub.`) +} + +async function uploadShasumFile (filePath, fileName, release) { + let githubOpts = { + owner: 'electron', + repo: 'electron', + id: release.id, + filePath, + name: fileName + } + return await github.repos.uploadAsset(githubOpts) + .catch(err => { + console.log(`${fail} Error uploading ${filePath} to GitHub:`, err) + process.exit(1) + }) +} + +function saveShaSumFile (checksums, fileName) { + return new Promise((resolve, reject) => { + temp.open(fileName, (err, info) => { + if (err) { + console.log(`${fail} Could not create ${fileName} file`) + process.exit(1) + } else { + fs.writeFileSync(info.fd, checksums) + fs.close(info.fd, (err) => { + if (err) { + console.log(`${fail} Could close ${fileName} file`) + process.exit(1) + } + resolve(info.path) + }) + } + }) + }) +} + +async function publishRelease (release) { + let githubOpts = { + owner: 'electron', + repo: 'electron', + id: release.id, + tag_name: release.tag_name, + draft: false + } + return await github.repos.editRelease(githubOpts) + .catch(err => { + console.log(`${fail} Error publishing release:`, err) + process.exit(1) + }) +} + +async function makeRelease (releaseToValidate) { + if (releaseToValidate) { + console.log(`Validating release ${args.validateRelease}`) + let release = await getDraftRelease(args.validateRelease) + await validateReleaseAssets(release) + } else { + checkVersion() + let draftRelease = await getDraftRelease() + uploadNodeShasums() + uploadIndexJson() + await createReleaseShasums(draftRelease) + // Fetch latest version of release before verifying + draftRelease = await getDraftRelease(pkgVersion, true) + await validateReleaseAssets(draftRelease) + await publishRelease(draftRelease) + await cleanupReleaseBranch() + console.log(`${pass} SUCCESS!!! Release has been published. Please run ` + + `"npm run publish-to-npm" to publish release to npm.`) + } +} + +async function makeTempDir () { + return new Promise((resolve, reject) => { + temp.mkdir('electron-publish', (err, dirPath) => { + if (err) { + reject(err) + } else { + resolve(dirPath) + } + }) + }) +} + +async function verifyAssets (release) { + let downloadDir = await makeTempDir() + let githubOpts = { + owner: 'electron', + repo: 'electron', + headers: { + Accept: 'application/octet-stream' + } + } + console.log(`Downloading files from GitHub to verify shasums`) + let shaSumFile = 'SHASUMS256.txt' + let filesToCheck = await Promise.all(release.assets.map(async (asset) => { + githubOpts.id = asset.id + let assetDetails = await github.repos.getAsset(githubOpts) + await downloadFiles(assetDetails.meta.location, downloadDir, false, asset.name) + return asset.name + })).catch(err => { + console.log(`${fail} Error downloading files from GitHub`, err) + process.exit(1) + }) + filesToCheck = filesToCheck.filter(fileName => fileName !== shaSumFile) + let checkerOpts + await validateChecksums({ + algorithm: 'sha256', + filesToCheck, + fileDirectory: downloadDir, + shaSumFile, + checkerOpts, + fileSource: 'GitHub' + }) +} + +function downloadFiles (urls, directory, quiet, targetName) { + return new Promise((resolve, reject) => { + let nuggetOpts = { + dir: directory + } + if (quiet) { + nuggetOpts.quiet = quiet + } + if (targetName) { + nuggetOpts.target = targetName + } + nugget(urls, nuggetOpts, (err) => { + if (err) { + reject(err) + } else { + resolve() + } + }) + }) +} + +async function verifyShasums (urls, isS3) { + let fileSource = isS3 ? 'S3' : 'GitHub' + console.log(`Downloading files from ${fileSource} to verify shasums`) + let downloadDir = await makeTempDir() + let filesToCheck = [] + try { + if (!isS3) { + await downloadFiles(urls, downloadDir) + filesToCheck = urls.map(url => { + let currentUrl = new URL(url) + return path.basename(currentUrl.pathname) + }).filter(file => file.indexOf('SHASUMS') === -1) + } else { + const s3VersionPath = `/atom-shell/dist/${pkgVersion}/` + await Promise.all(urls.map(async (url) => { + let currentUrl = new URL(url) + let dirname = path.dirname(currentUrl.pathname) + let filename = path.basename(currentUrl.pathname) + let s3VersionPathIdx = dirname.indexOf(s3VersionPath) + if (s3VersionPathIdx === -1 || dirname === s3VersionPath) { + if (s3VersionPathIdx !== -1 && filename.indexof('SHASUMS') === -1) { + filesToCheck.push(filename) + } + await downloadFiles(url, downloadDir, true) + } else { + let subDirectory = dirname.substr(s3VersionPathIdx + s3VersionPath.length) + let fileDirectory = path.join(downloadDir, subDirectory) + try { + fs.statSync(fileDirectory) + } catch (err) { + fs.mkdirSync(fileDirectory) + } + filesToCheck.push(path.join(subDirectory, filename)) + await downloadFiles(url, fileDirectory, true) + } + })) + } + } catch (err) { + console.log(`${fail} Error downloading files from ${fileSource}`, err) + process.exit(1) + } + console.log(`${pass} Successfully downloaded the files from ${fileSource}.`) + let checkerOpts + if (isS3) { + checkerOpts = { defaultTextEncoding: 'binary' } + } + + await validateChecksums({ + algorithm: 'sha256', + filesToCheck, + fileDirectory: downloadDir, + shaSumFile: 'SHASUMS256.txt', + checkerOpts, + fileSource + }) + + if (isS3) { + await validateChecksums({ + algorithm: 'sha1', + filesToCheck, + fileDirectory: downloadDir, + shaSumFile: 'SHASUMS.txt', + checkerOpts, + fileSource + }) + } +} + +async function validateChecksums (validationArgs) { + console.log(`Validating checksums for files from ${validationArgs.fileSource} ` + + `against ${validationArgs.shaSumFile}.`) + let shaSumFilePath = path.join(validationArgs.fileDirectory, validationArgs.shaSumFile) + let checker = new sumchecker.ChecksumValidator(validationArgs.algorithm, + shaSumFilePath, validationArgs.checkerOpts) + await checker.validate(validationArgs.fileDirectory, validationArgs.filesToCheck) + .catch(err => { + if (err instanceof sumchecker.ChecksumMismatchError) { + console.error(`${fail} The checksum of ${err.filename} from ` + + `${validationArgs.fileSource} did not match the shasum in ` + + `${validationArgs.shaSumFile}`) + } else if (err instanceof sumchecker.ChecksumParseError) { + console.error(`${fail} The checksum file ${validationArgs.shaSumFile} ` + + `from ${validationArgs.fileSource} could not be parsed.`, err) + } else if (err instanceof sumchecker.NoChecksumFoundError) { + console.error(`${fail} The file ${err.filename} from ` + + `${validationArgs.fileSource} was not in the shasum file ` + + `${validationArgs.shaSumFile}.`) + } else { + console.error(`${fail} Error matching files from ` + + `${validationArgs.fileSource} shasums in ${validationArgs.shaSumFile}.`, err) + } + process.exit(1) + }) + console.log(`${pass} All files from ${validationArgs.fileSource} match ` + + `shasums defined in ${validationArgs.shaSumFile}.`) +} + +async function cleanupReleaseBranch () { + console.log(`Cleaning up release branch.`) + let errorMessage = `Could not delete local release branch.` + let successMessage = `Successfully deleted local release branch.` + await callGit(['branch', '-D', 'release'], errorMessage, successMessage) + errorMessage = `Could not delete remote release branch.` + successMessage = `Successfully deleted remote release branch.` + return await callGit(['push', 'origin', ':release'], errorMessage, successMessage) +} + +async function callGit (args, errorMessage, successMessage) { + let gitResult = await GitProcess.exec(args, gitDir) + if (gitResult.exitCode === 0) { + console.log(`${pass} ${successMessage}`) + return true + } else { + console.log(`${fail} ${errorMessage} ${gitResult.stderr}`) + process.exit(1) + } +} + +makeRelease(args.validateRelease) diff --git a/script/upload-to-github.js b/script/upload-to-github.js index e6ae78cb9bd..7c3f8d9c11c 100644 --- a/script/upload-to-github.js +++ b/script/upload-to-github.js @@ -28,8 +28,8 @@ function uploadToGitHub () { if (retry < 4) { console.log(`Error uploading ${fileName} to GitHub, will retry. Error was:`, err) retry++ - github.repos.getAssets(githubOpts).then(assets => { - let existingAssets = assets.data.filter(asset => asset.name === fileName) + github.repos.getRelease(githubOpts).then(release => { + let existingAssets = release.data.assets.filter(asset => asset.name === fileName) if (existingAssets.length > 0) { console.log(`${fileName} already exists; will delete before retrying upload.`) github.repos.deleteAsset({ diff --git a/script/upload.py b/script/upload.py index cc1dd8e5d07..586a6be1eb2 100755 --- a/script/upload.py +++ b/script/upload.py @@ -36,17 +36,16 @@ PDB_NAME = get_zip_name(PROJECT_NAME, ELECTRON_VERSION, 'pdb') def main(): args = parse_args() - if not args.publish_release: - if not dist_newer_than_head(): - run_python_script('create-dist.py') + if not dist_newer_than_head(): + run_python_script('create-dist.py') - build_version = get_electron_build_version() - if not ELECTRON_VERSION.startswith(build_version): - error = 'Tag name ({0}) should match build version ({1})\n'.format( - ELECTRON_VERSION, build_version) - sys.stderr.write(error) - sys.stderr.flush() - return 1 + build_version = get_electron_build_version() + if not ELECTRON_VERSION.startswith(build_version): + error = 'Tag name ({0}) should match build version ({1})\n'.format( + ELECTRON_VERSION, build_version) + sys.stderr.write(error) + sys.stderr.flush() + return 1 github = GitHub(auth_token()) releases = github.repos(ELECTRON_REPO).releases.get() @@ -64,24 +63,6 @@ def main(): release = create_or_get_release_draft(github, releases, args.version, tag_exists) - if args.publish_release: - # Upload the Node SHASUMS*.txt. - run_python_script('upload-node-checksums.py', '-v', ELECTRON_VERSION) - - # Upload the index.json. - run_python_script('upload-index-json.py') - - # Create and upload the Electron SHASUMS*.txt - release_electron_checksums(release) - - # Press the publish button. - publish_release(github, release['id']) - - # TODO: run publish-to-npm script here - - # Do not upload other files when passed "-p". - return - # Upload Electron with GitHub Releases API. upload_electron(github, release, os.path.join(DIST_DIR, DIST_NAME)) upload_electron(github, release, os.path.join(DIST_DIR, SYMBOLS_NAME)) @@ -206,16 +187,6 @@ def create_release_draft(github, tag): return r -def release_electron_checksums(release): - checksums = run_python_script('merge-electron-checksums.py', - '-v', ELECTRON_VERSION) - filename = 'SHASUMS256.txt' - filepath = os.path.join(SOURCE_ROOT, filename) - with open(filepath, 'w') as sha_file: - sha_file.write(checksums.decode('utf-8')) - upload_io_to_github(release, filename, filepath) - - def upload_electron(github, release, file_path): # Delete the original file before uploading in CI. filename = os.path.basename(file_path) @@ -263,11 +234,6 @@ def upload_sha256_checksum(version, file_path): 'atom-shell/tmp/{0}'.format(version), [checksum_path]) -def publish_release(github, release_id): - data = dict(draft=False) - github.repos(ELECTRON_REPO).releases(release_id).patch(data=data) - - def auth_token(): token = get_env_var('GITHUB_TOKEN') message = ('Error: Please set the $ELECTRON_GITHUB_TOKEN ' From 87802b2c17cadb98412e0ea68e2d56f2135de794 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 12:11:59 -0400 Subject: [PATCH 051/185] initial port of things into a Menu class --- lib/browser/api/menu.js | 465 +++++++++++++++++++--------------------- 1 file changed, 223 insertions(+), 242 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 421462671fb..bfe6eb82fd9 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -6,10 +6,231 @@ const v8Util = process.atomBinding('v8_util') const bindings = process.atomBinding('menu') // Automatically generated radio menu item's group id. -var nextGroupId = 0 +let nextGroupId = 0 +let applicationMenu = null + +const Menu = bindings.Menu + +class Menu extends EventEmitter { + constructor () { + this.commandsMap = {} + this.groupsMap = {} + this.items = [] + this.delegate = { + isCommandIdChecked: (commandId) => { + const command = this.commandsMap[commandId] + return command != null ? command.checked : undefined + }, + isCommandIdEnabled: (commandId) => { + const command = this.commandsMap[commandId] + return command != null ? command.enabled : undefined + }, + isCommandIdVisible: (commandId) => { + const command = this.commandsMap[commandId] + return command != null ? command.visible : undefined + }, + getAcceleratorForCommandId: (commandId, useDefaultAccelerator) => { + const command = this.commandsMap[commandId] + if (command == null) return + if (command.accelerator != null) return command.accelerator + if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() + }, + getIconForCommandId: (commandId) => { + const command = this.commandsMap[commandId] + return command != null ? command.icon : undefined + }, + executeCommand: (event, commandId) => { + const command = this.commandsMap[commandId] + if (command == null) return + command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) + }, + menuWillShow: () => { + // Make sure radio groups have at least one menu item selected + for (let id in this.groupsMap) { + const group = this.groupsMap[id] + const checked = false + for (let idx = 0; idx < group.length; idx++) { + const radioItem = group[idx] + if (!radioItem.checked) continue + checked = true + break + } + if (!checked) v8Util.setHiddenValue(group[0], 'checked', true) + } + } + } + popup (window, x, y, positioningItem) { + let [newX, newY, newPositioningItem] = [x, y, positioningItem] + let asyncPopup + + // menu.popup(x, y, positioningItem) + if (window != null) { + if (typeof window !== 'object' || window.constructor !== BrowserWindow) { + [newPositioningItem, newY, newX] = [y, x, window] + window = null + } + } + + // menu.popup(window, {}) + if (x != null && typeof x === 'object') { + [newX, newY, newPositioningItem] = [x.x, x.y, x.positioningItem] + asyncPopup = x.async + } + + // set up defaults + if (window == null) window = BrowserWindow.getFocusedWindow() + if (typeof x !== 'number') newX = -1 + if (typeof y !== 'number') newY = -1 + if (typeof positioningItem !== 'number') newPositioningItem = -1 + if (typeof asyncPopup !== 'boolean') asyncPopup = false + + this.popupAt(window, newX, newY, newPositioningItem, asyncPopup) + } + closePopup (window) { + if (window == null || window.constructor !== BrowserWindow) { + window = BrowserWindow.getFocusedWindow() + } + + if (window != null) this.closePopupAt(window.id) + } + getMenuItemById (id) { + const items = this.items + + let found = items.find(item => item.id === id) || null + for (let i = 0, length = items.length; !found && i < length; i++) { + if (items[i].submenu) { + found = items[i].submenu.getMenuItemById(id) + } + } + return found + } + append (item) { + return this.insert(this.getItemCount(), item) + } + insert (pos, item) { + var base, name + if ((item != null ? item.constructor : void 0) !== MenuItem) { + throw new TypeError('Invalid item') + } + switch (item.type) { + case 'normal': + this.insertItem(pos, item.commandId, item.label) + break + case 'checkbox': + this.insertCheckItem(pos, item.commandId, item.label) + break + case 'separator': + this.insertSeparator(pos) + break + case 'submenu': + this.insertSubMenu(pos, item.commandId, item.label, item.submenu) + break + case 'radio': + // Grouping radio menu items. + item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) + if ((base = this.groupsMap)[name = item.groupId] == null) { + base[name] = [] + } + this.groupsMap[item.groupId].push(item) + + // Setting a radio menu item should flip other items in the group. + v8Util.setHiddenValue(item, 'checked', item.checked) + Object.defineProperty(item, 'checked', { + enumerable: true, + get: function () { + return v8Util.getHiddenValue(item, 'checked') + }, + set: () => { + var j, len, otherItem, ref1 + ref1 = this.groupsMap[item.groupId] + for (j = 0, len = ref1.length; j < len; j++) { + otherItem = ref1[j] + if (otherItem !== item) { + v8Util.setHiddenValue(otherItem, 'checked', false) + } + } + return v8Util.setHiddenValue(item, 'checked', true) + } + }) + this.insertRadioItem(pos, item.commandId, item.label, item.groupId) + } + if (item.sublabel != null) { + this.setSublabel(pos, item.sublabel) + } + if (item.icon != null) { + this.setIcon(pos, item.icon) + } + if (item.role != null) { + this.setRole(pos, item.role) + } + + // Make menu accessable to items. + item.overrideReadOnlyProperty('menu', this) + + // Remember the items. + this.items.splice(pos, 0, item) + this.commandsMap[item.commandId] = item + } + _callMenuWillShow () { + if (this.delegate != null) { + this.delegate.menuWillShow() + } + this.items.forEach(function (item) { + if (item.submenu != null) { + item.submenu._callMenuWillShow() + } + }) + } + static setApplicationMenu (menu) { + if (!(menu === null || menu.constructor === Menu)) { + throw new TypeError('Invalid menu') + } + + // Keep a reference. + applicationMenu = menu + if (process.platform === 'darwin') { + if (menu === null) { + return + } + menu._callMenuWillShow() + bindings.setApplicationMenu(menu) + } else { + BrowserWindow.getAllWindows().forEach(function (window) { + window.setMenu(menu) + }) + } + } + static getApplicationMenu () { + return applicationMenu + } + static buildFromTemplate (template) { + if (!Array.isArray(template)) throw new TypeError('Invalid template for Menu') + + const menu = new Menu() + let positioned = [] + let idx = 0 + + template.forEach((item) => { + idx = (item.position) ? indexToInsertByPosition(positioned, item.position) : idx += 1 + positioned.splice(idx, 0, item) + }) + + positioned.forEach((item) => { + if (typeof item !== 'object') { + throw new TypeError('Invalid template for MenuItem') + } + menu.append(new MenuItem(item)) + }) + + return menu + } +} + +Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder + +/* HELPER METHODS */ // Search between separators to find a radio menu item and return its group id, -// otherwise generate a group id. function generateGroupId (items, pos) { var i, item, j, k, ref1, ref2, ref3 if (pos > 0) { @@ -78,244 +299,4 @@ function indexToInsertByPosition (items, pos) { return idx } -const Menu = bindings.Menu - -Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype) - -Menu.prototype._init = function () { - this.commandsMap = {} - this.groupsMap = {} - this.items = [] - this.delegate = { - isCommandIdChecked: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.checked : undefined - }, - isCommandIdEnabled: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.enabled : undefined - }, - isCommandIdVisible: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.visible : undefined - }, - getAcceleratorForCommandId: (commandId, useDefaultAccelerator) => { - const command = this.commandsMap[commandId] - if (command == null) return - if (command.accelerator != null) return command.accelerator - if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() - }, - getIconForCommandId: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.icon : undefined - }, - executeCommand: (event, commandId) => { - const command = this.commandsMap[commandId] - if (command == null) return - command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) - }, - menuWillShow: () => { - // Make sure radio groups have at least one menu item selected - for (let id in this.groupsMap) { - const group = this.groupsMap[id] - const checked = false - for (let idx = 0; idx < group.length; idx++) { - const radioItem = group[idx] - if (!radioItem.checked) continue - checked = true - break - } - if (!checked) v8Util.setHiddenValue(group[0], 'checked', true) - } - } - } -} - -Menu.prototype.popup = function (window, x, y, positioningItem) { - let [newX, newY, newPositioningItem] = [x, y, positioningItem] - let asyncPopup - - // menu.popup(x, y, positioningItem) - if (window != null) { - if (typeof window !== 'object' || window.constructor !== BrowserWindow) { - [newPositioningItem, newY, newX] = [y, x, window] - window = null - } - } - - // menu.popup(window, {}) - if (x != null && typeof x === 'object') { - [newX, newY, newPositioningItem] = [x.x, x.y, x.positioningItem] - asyncPopup = x.async - } - - // set up defaults - if (window == null) window = BrowserWindow.getFocusedWindow() - if (typeof x !== 'number') newX = -1 - if (typeof y !== 'number') newY = -1 - if (typeof positioningItem !== 'number') newPositioningItem = -1 - if (typeof asyncPopup !== 'boolean') asyncPopup = false - - this.popupAt(window, newX, newY, newPositioningItem, asyncPopup) -} - -Menu.prototype.closePopup = function (window) { - if (window == null || window.constructor !== BrowserWindow) { - window = BrowserWindow.getFocusedWindow() - } - if (window != null) { - this.closePopupAt(window.id) - } -} - -Menu.prototype.getMenuItemById = function (id) { - const items = this.items - - let found = items.find(item => item.id === id) || null - for (let i = 0, length = items.length; !found && i < length; i++) { - if (items[i].submenu) { - found = items[i].submenu.getMenuItemById(id) - } - } - return found -} - -Menu.prototype.append = function (item) { - return this.insert(this.getItemCount(), item) -} - -Menu.prototype.insert = function (pos, item) { - var base, name - if ((item != null ? item.constructor : void 0) !== MenuItem) { - throw new TypeError('Invalid item') - } - switch (item.type) { - case 'normal': - this.insertItem(pos, item.commandId, item.label) - break - case 'checkbox': - this.insertCheckItem(pos, item.commandId, item.label) - break - case 'separator': - this.insertSeparator(pos) - break - case 'submenu': - this.insertSubMenu(pos, item.commandId, item.label, item.submenu) - break - case 'radio': - // Grouping radio menu items. - item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) - if ((base = this.groupsMap)[name = item.groupId] == null) { - base[name] = [] - } - this.groupsMap[item.groupId].push(item) - - // Setting a radio menu item should flip other items in the group. - v8Util.setHiddenValue(item, 'checked', item.checked) - Object.defineProperty(item, 'checked', { - enumerable: true, - get: function () { - return v8Util.getHiddenValue(item, 'checked') - }, - set: () => { - var j, len, otherItem, ref1 - ref1 = this.groupsMap[item.groupId] - for (j = 0, len = ref1.length; j < len; j++) { - otherItem = ref1[j] - if (otherItem !== item) { - v8Util.setHiddenValue(otherItem, 'checked', false) - } - } - return v8Util.setHiddenValue(item, 'checked', true) - } - }) - this.insertRadioItem(pos, item.commandId, item.label, item.groupId) - } - if (item.sublabel != null) { - this.setSublabel(pos, item.sublabel) - } - if (item.icon != null) { - this.setIcon(pos, item.icon) - } - if (item.role != null) { - this.setRole(pos, item.role) - } - - // Make menu accessable to items. - item.overrideReadOnlyProperty('menu', this) - - // Remember the items. - this.items.splice(pos, 0, item) - this.commandsMap[item.commandId] = item -} - -// Force menuWillShow to be called -Menu.prototype._callMenuWillShow = function () { - if (this.delegate != null) { - this.delegate.menuWillShow() - } - this.items.forEach(function (item) { - if (item.submenu != null) { - item.submenu._callMenuWillShow() - } - }) -} - -var applicationMenu = null - -Menu.setApplicationMenu = function (menu) { - if (!(menu === null || menu.constructor === Menu)) { - throw new TypeError('Invalid menu') - } - - // Keep a reference. - applicationMenu = menu - if (process.platform === 'darwin') { - if (menu === null) { - return - } - menu._callMenuWillShow() - bindings.setApplicationMenu(menu) - } else { - BrowserWindow.getAllWindows().forEach(function (window) { - window.setMenu(menu) - }) - } -} - -Menu.getApplicationMenu = function () { - return applicationMenu -} - -Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder - -Menu.buildFromTemplate = function (template) { - var insertIndex, item, j, k, len, len1, menu, menuItem, positionedTemplate - if (!Array.isArray(template)) { - throw new TypeError('Invalid template for Menu') - } - positionedTemplate = [] - insertIndex = 0 - for (j = 0, len = template.length; j < len; j++) { - item = template[j] - if (item.position) { - insertIndex = indexToInsertByPosition(positionedTemplate, item.position) - } else { - // If no |position| is specified, insert after last item. - insertIndex++ - } - positionedTemplate.splice(insertIndex, 0, item) - } - menu = new Menu() - for (k = 0, len1 = positionedTemplate.length; k < len1; k++) { - item = positionedTemplate[k] - if (typeof item !== 'object') { - throw new TypeError('Invalid template for MenuItem') - } - menuItem = new MenuItem(item) - menu.append(menuItem) - } - return menu -} - module.exports = Menu From db5a429948d70df6bceb98f6f8113c20a799c2b6 Mon Sep 17 00:00:00 2001 From: Toinane Date: Mon, 23 Oct 2017 18:36:52 +0200 Subject: [PATCH 052/185] fixe grammar --- docs/glossary.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/glossary.md b/docs/glossary.md index 2e937b044e6..ee6e07883eb 100644 --- a/docs/glossary.md +++ b/docs/glossary.md @@ -93,9 +93,9 @@ as a build target. ### OSR -OSR (Off-screen rendering) can be used for, e.g., loading heavy page in -background and then displaying it after (it will be much more faster). -It allows you to render page without show on screen. +OSR (Off-screen rendering) can be used for loading heavy page in +background and then displaying it after (it will be much faster). +It allows you to render page without showing it on screen. ### process From 577c0042b0fe3c0f1498f015392ed91986b7eb6d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 14:47:47 -0400 Subject: [PATCH 053/185] update to ES6 --- lib/browser/api/menu.js | 491 ++++++++++++++++++---------------------- 1 file changed, 218 insertions(+), 273 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index bfe6eb82fd9..75b5a31e3b0 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -1,302 +1,247 @@ -'use strict' +const {BrowserWindow, MenuItem} = require('electron') +const {EventEmitter} = require('events') +//const _ = require('lodash') -const {BrowserWindow, MenuItem, webContents} = require('electron') -const EventEmitter = require('events').EventEmitter const v8Util = process.atomBinding('v8_util') const bindings = process.atomBinding('menu') // Automatically generated radio menu item's group id. let nextGroupId = 0 -let applicationMenu = null -const Menu = bindings.Menu - -class Menu extends EventEmitter { - constructor () { - this.commandsMap = {} - this.groupsMap = {} - this.items = [] - this.delegate = { - isCommandIdChecked: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.checked : undefined - }, - isCommandIdEnabled: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.enabled : undefined - }, - isCommandIdVisible: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.visible : undefined - }, - getAcceleratorForCommandId: (commandId, useDefaultAccelerator) => { - const command = this.commandsMap[commandId] - if (command == null) return - if (command.accelerator != null) return command.accelerator - if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() - }, - getIconForCommandId: (commandId) => { - const command = this.commandsMap[commandId] - return command != null ? command.icon : undefined - }, - executeCommand: (event, commandId) => { - const command = this.commandsMap[commandId] - if (command == null) return - command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) - }, - menuWillShow: () => { - // Make sure radio groups have at least one menu item selected - for (let id in this.groupsMap) { - const group = this.groupsMap[id] - const checked = false - for (let idx = 0; idx < group.length; idx++) { - const radioItem = group[idx] - if (!radioItem.checked) continue - checked = true - break - } - if (!checked) v8Util.setHiddenValue(group[0], 'checked', true) - } - } - } - popup (window, x, y, positioningItem) { - let [newX, newY, newPositioningItem] = [x, y, positioningItem] - let asyncPopup - - // menu.popup(x, y, positioningItem) - if (window != null) { - if (typeof window !== 'object' || window.constructor !== BrowserWindow) { - [newPositioningItem, newY, newX] = [y, x, window] - window = null - } - } - - // menu.popup(window, {}) - if (x != null && typeof x === 'object') { - [newX, newY, newPositioningItem] = [x.x, x.y, x.positioningItem] - asyncPopup = x.async - } - - // set up defaults - if (window == null) window = BrowserWindow.getFocusedWindow() - if (typeof x !== 'number') newX = -1 - if (typeof y !== 'number') newY = -1 - if (typeof positioningItem !== 'number') newPositioningItem = -1 - if (typeof asyncPopup !== 'boolean') asyncPopup = false - - this.popupAt(window, newX, newY, newPositioningItem, asyncPopup) - } - closePopup (window) { - if (window == null || window.constructor !== BrowserWindow) { - window = BrowserWindow.getFocusedWindow() - } - - if (window != null) this.closePopupAt(window.id) - } - getMenuItemById (id) { - const items = this.items - - let found = items.find(item => item.id === id) || null - for (let i = 0, length = items.length; !found && i < length; i++) { - if (items[i].submenu) { - found = items[i].submenu.getMenuItemById(id) - } - } - return found - } - append (item) { - return this.insert(this.getItemCount(), item) - } - insert (pos, item) { - var base, name - if ((item != null ? item.constructor : void 0) !== MenuItem) { - throw new TypeError('Invalid item') - } - switch (item.type) { - case 'normal': - this.insertItem(pos, item.commandId, item.label) - break - case 'checkbox': - this.insertCheckItem(pos, item.commandId, item.label) - break - case 'separator': - this.insertSeparator(pos) - break - case 'submenu': - this.insertSubMenu(pos, item.commandId, item.label, item.submenu) - break - case 'radio': - // Grouping radio menu items. - item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) - if ((base = this.groupsMap)[name = item.groupId] == null) { - base[name] = [] - } - this.groupsMap[item.groupId].push(item) - - // Setting a radio menu item should flip other items in the group. - v8Util.setHiddenValue(item, 'checked', item.checked) - Object.defineProperty(item, 'checked', { - enumerable: true, - get: function () { - return v8Util.getHiddenValue(item, 'checked') - }, - set: () => { - var j, len, otherItem, ref1 - ref1 = this.groupsMap[item.groupId] - for (j = 0, len = ref1.length; j < len; j++) { - otherItem = ref1[j] - if (otherItem !== item) { - v8Util.setHiddenValue(otherItem, 'checked', false) - } - } - return v8Util.setHiddenValue(item, 'checked', true) - } - }) - this.insertRadioItem(pos, item.commandId, item.label, item.groupId) - } - if (item.sublabel != null) { - this.setSublabel(pos, item.sublabel) - } - if (item.icon != null) { - this.setIcon(pos, item.icon) - } - if (item.role != null) { - this.setRole(pos, item.role) - } - - // Make menu accessable to items. - item.overrideReadOnlyProperty('menu', this) - - // Remember the items. - this.items.splice(pos, 0, item) - this.commandsMap[item.commandId] = item - } - _callMenuWillShow () { - if (this.delegate != null) { - this.delegate.menuWillShow() - } - this.items.forEach(function (item) { - if (item.submenu != null) { - item.submenu._callMenuWillShow() - } - }) - } - static setApplicationMenu (menu) { - if (!(menu === null || menu.constructor === Menu)) { - throw new TypeError('Invalid menu') - } - - // Keep a reference. - applicationMenu = menu - if (process.platform === 'darwin') { - if (menu === null) { - return - } - menu._callMenuWillShow() - bindings.setApplicationMenu(menu) - } else { - BrowserWindow.getAllWindows().forEach(function (window) { - window.setMenu(menu) - }) - } - } - static getApplicationMenu () { - return applicationMenu - } - static buildFromTemplate (template) { - if (!Array.isArray(template)) throw new TypeError('Invalid template for Menu') - - const menu = new Menu() - let positioned = [] - let idx = 0 - - template.forEach((item) => { - idx = (item.position) ? indexToInsertByPosition(positioned, item.position) : idx += 1 - positioned.splice(idx, 0, item) - }) - - positioned.forEach((item) => { - if (typeof item !== 'object') { - throw new TypeError('Invalid template for MenuItem') - } - menu.append(new MenuItem(item)) - }) - - return menu - } -} - -Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder - -/* HELPER METHODS */ - -// Search between separators to find a radio menu item and return its group id, -function generateGroupId (items, pos) { - var i, item, j, k, ref1, ref2, ref3 +/* Search between seperators to find a radio menu item and return its group id */ +const generateGroupId = function(items, pos) { + let i, item if (pos > 0) { - for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) { + let asc, start + for (start = pos - 1, i = start, asc = start <= 0; asc ? i <= 0 : i >= 0; asc ? i++ : i--) { item = items[i] - if (item.type === 'radio') { - return item.groupId - } - if (item.type === 'separator') { - break - } + if (item.type === 'radio') { return item.groupId } + if (item.type === 'separator') { break } } } else if (pos < items.length) { - for (i = k = ref2 = pos, ref3 = items.length - 1; ref2 <= ref3 ? k <= ref3 : k >= ref3; i = ref2 <= ref3 ? ++k : --k) { + let asc1, end + for (i = pos, end = items.length - 1, asc1 = pos <= end; asc1 ? i <= end : i >= end; asc1 ? i++ : i--) { item = items[i] - if (item.type === 'radio') { - return item.groupId - } - if (item.type === 'separator') { - break - } + if (item.type === 'radio') { return item.groupId } + if (item.type === 'separator') { break } } } return ++nextGroupId } -// Returns the index of item according to |id|. -function indexOfItemById (items, id) { - for (let idx = 0; idx < items.length; idx += 1) { - const item = items[idx] - if (item.id === id) return idx +/* Returns the index of item according to |id|. */ +const indexOfItemById = function(items, id) { + for (let i = 0; i < items.length; i++) { + const item = items[i] + if (item.id === id) return i } return -1 } -// Returns the index of where to insert the item according to |position|. -function indexToInsertByPosition (items, pos) { - if (!pos) return items.length +/* Returns the index of where to insert the item according to |position|. */ +const indexToInsertByPosition = function(items, position) { + if (!position) { return items.length } - const [query, id] = pos.split('=') - let idx = indexOfItemById(items, id) - - if (idx === -1 && query !== 'endof') { - console.warn("Item with id '" + id + "' is not found") + const [query, id] = Array.from(position.split('=')) + let insertIndex = indexOfItemById(items, id) + if ((insertIndex === -1) && (query !== 'endof')) { + console.warn(`Item with id '${id}' is not found`) return items.length } - if (query === 'after') { - idx += 1 - } else if (query === 'endof') { - // create new group with id if none exists - if (idx === -1) { - items.push({ - id, - type: 'separator' - }) - idx = items.length - 1 - } - idx += 1 + switch (query) { + case 'after': + insertIndex++ + break + case 'endof': + /* If the |id| doesn't exist, then create a new group with the |id|. */ + if (insertIndex === -1) { + items.push({id, type: 'separator'}) + insertIndex = items.length - 1 + } - // search for end of group - while (idx < items.length && items[idx].type !== 'separator') { - idx += 1 - } + /* Find the end of the group. */ + insertIndex++ + while ((insertIndex < items.length) && (items[insertIndex].type !== 'separator')) { + insertIndex++ + } + break } - return idx + + return insertIndex } -module.exports = Menu +const { Menu } = bindings + +Menu.prototype.__proto__ = EventEmitter.prototype + +Menu.prototype._init = function() { + this.commandsMap = {} + this.groupsMap = {} + this.items = [] + return this.delegate = { + isCommandIdChecked: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].checked : undefined), + isCommandIdEnabled: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].enabled : undefined), + isCommandIdVisible: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].visible : undefined), + getAcceleratorForCommandId: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].accelerator : undefined), + getIconForCommandId: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].icon : undefined), + executeCommand: commandId => { + return (this.commandsMap[commandId] != null ? this.commandsMap[commandId].click(BrowserWindow.getFocusedWindow()) : undefined) + }, + menuWillShow: () => { + for (let id in this.groupsMap) { + const group = this.groupsMap[id] + let checked = false + for (let radioItem in group) { + if (radioItem.checked) { + checked = true + break + } + } + if (!checked) v8Util.setHiddenValue(group[0], 'checked', true) + } + } + } +} + +Menu.prototype.popup = function(window, x, y) { + if ((window != null ? window.constructor : undefined) !== BrowserWindow) { + /* Shift. */ + y = x + x = window + window = BrowserWindow.getFocusedWindow() + } + if (x !== null && y !== null) { + return this._popupAt(window, x, y) + } else { + return this._popup(window) + } +} + +Menu.prototype.append = function(item) { + return this.insert(this.getItemCount(), item) +} + +Menu.prototype.insert = function(pos, item) { + if ((item != null ? item.constructor : undefined) !== MenuItem) { + throw new TypeError('Invalid item') + } + + switch (item.type) { + case 'normal': + this.insertItem(pos, item.commandId, item.label) + break + case 'checkbox': + this.insertCheckItem(pos, item.commandId, item.label) + break + case 'separator': + this.insertSeparator(pos) + break + case 'submenu': + this.insertSubMenu(pos, item.commandId, item.label, item.submenu) + break + case 'radio': + /* Grouping radio menu items. */ + item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) + if (this.groupsMap[item.groupId] == null) this.groupsMap[item.groupId] = [] + this.groupsMap[item.groupId].push(item) + + /* Setting a radio menu item should flip other items in the group. */ + v8Util.setHiddenValue(item, 'checked', item.checked) + Object.defineProperty(item, 'checked', { + enumerable: true, + get() { return v8Util.getHiddenValue(item, 'checked') }, + set: val => { + for (let otherItem in this.groupsMap[item.groupId]) { + if (otherItem !== item) v8Util.setHiddenValue(otherItem, 'checked', false) + } + return v8Util.setHiddenValue(item, 'checked', true) + } + }) + + this.insertRadioItem(pos, item.commandId, item.label, item.groupId) + break + } + + if (item.sublabel != null) this.setSublabel(pos, item.sublabel) + if (item.icon != null) this.setIcon(pos, item.icon) + if (item.role != null) this.setRole(pos, item.role) + + /* Make menu accessable to items. */ + item.overrideReadOnlyProperty('menu', this) + + /* Remember the items. */ + this.items.splice(pos, 0, item) + return this.commandsMap[item.commandId] = item +} + +/* Force menuWillShow to be called */ +Menu.prototype._callMenuWillShow = function() { + if (this.delegate != null) this.delegate.menuWillShow() + + return (() => { + const result = [] + for (let item of Array.from(this.items)) { + if (item.submenu != null) { + result.push(item.submenu._callMenuWillShow()) + } + } + return result + })() +} + +let applicationMenu = null +Menu.setApplicationMenu = function(menu) { + if ((menu !== null) && (menu.constructor !== Menu)) { throw new TypeError('Invalid menu') } + /* Keep a reference. */ + applicationMenu = menu + + if (process.platform === 'darwin') { + if (menu === null) { return } + menu._callMenuWillShow() + return bindings.setApplicationMenu(menu) + } else { + const windows = BrowserWindow.getAllWindows() + return Array.from(windows).map((w) => w.setMenu(menu)) + } +} + +Menu.getApplicationMenu = () => applicationMenu + +Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder + +Menu.buildFromTemplate = function(template) { + if (!Array.isArray(template)) { throw new TypeError('Invalid template for Menu') } + + const positionedTemplate = [] + let insertIndex = 0 + + for (var item of Array.from(template)) { + if (item.position) { + insertIndex = indexToInsertByPosition(positionedTemplate, item.position) + } else { + /* If no |position| is specified, insert after last item. */ + insertIndex++ + } + positionedTemplate.splice(insertIndex, 0, item) + } + + const menu = new Menu + + for (item of Array.from(positionedTemplate)) { + if (typeof item !== 'object') { throw new TypeError('Invalid template for MenuItem') } + + const menuItem = new MenuItem(item) + for (let key in item) { + const value = item[key] + if (menuItem[key] == null) { + menuItem[key] = value + } + } + menu.append(menuItem) + } + + return menu +} + +module.exports = Menu \ No newline at end of file From 3fc5d51a96557974db9349565ae18fd20e75b371 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 18:35:16 -0400 Subject: [PATCH 054/185] clean up delegate --- lib/browser/api/menu.js | 272 ++++++++++++++++++++++------------------ 1 file changed, 147 insertions(+), 125 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 75b5a31e3b0..71ac7f5241d 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -5,88 +5,23 @@ const {EventEmitter} = require('events') const v8Util = process.atomBinding('v8_util') const bindings = process.atomBinding('menu') -// Automatically generated radio menu item's group id. -let nextGroupId = 0 - -/* Search between seperators to find a radio menu item and return its group id */ -const generateGroupId = function(items, pos) { - let i, item - if (pos > 0) { - let asc, start - for (start = pos - 1, i = start, asc = start <= 0; asc ? i <= 0 : i >= 0; asc ? i++ : i--) { - item = items[i] - if (item.type === 'radio') { return item.groupId } - if (item.type === 'separator') { break } - } - } else if (pos < items.length) { - let asc1, end - for (i = pos, end = items.length - 1, asc1 = pos <= end; asc1 ? i <= end : i >= end; asc1 ? i++ : i--) { - item = items[i] - if (item.type === 'radio') { return item.groupId } - if (item.type === 'separator') { break } - } - } - return ++nextGroupId -} - -/* Returns the index of item according to |id|. */ -const indexOfItemById = function(items, id) { - for (let i = 0; i < items.length; i++) { - const item = items[i] - if (item.id === id) return i - } - return -1 -} - -/* Returns the index of where to insert the item according to |position|. */ -const indexToInsertByPosition = function(items, position) { - if (!position) { return items.length } - - const [query, id] = Array.from(position.split('=')) - let insertIndex = indexOfItemById(items, id) - if ((insertIndex === -1) && (query !== 'endof')) { - console.warn(`Item with id '${id}' is not found`) - return items.length - } - - switch (query) { - case 'after': - insertIndex++ - break - case 'endof': - /* If the |id| doesn't exist, then create a new group with the |id|. */ - if (insertIndex === -1) { - items.push({id, type: 'separator'}) - insertIndex = items.length - 1 - } - - /* Find the end of the group. */ - insertIndex++ - while ((insertIndex < items.length) && (items[insertIndex].type !== 'separator')) { - insertIndex++ - } - break - } - - return insertIndex -} - const { Menu } = bindings Menu.prototype.__proto__ = EventEmitter.prototype -Menu.prototype._init = function() { +Menu.prototype._init = function () { this.commandsMap = {} this.groupsMap = {} this.items = [] return this.delegate = { - isCommandIdChecked: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].checked : undefined), - isCommandIdEnabled: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].enabled : undefined), - isCommandIdVisible: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].visible : undefined), - getAcceleratorForCommandId: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].accelerator : undefined), - getIconForCommandId: commandId => (this.commandsMap[commandId] != null ? this.commandsMap[commandId].icon : undefined), - executeCommand: commandId => { - return (this.commandsMap[commandId] != null ? this.commandsMap[commandId].click(BrowserWindow.getFocusedWindow()) : undefined) + isCommandIdChecked: id => (this.commandsMap[id] ? this.commandsMap[id].checked : undefined), + isCommandIdEnabled: id => (this.commandsMap[id] ? this.commandsMap[id].enabled : undefined), + isCommandIdVisible: id => (this.commandsMap[id] ? this.commandsMap[id].visible : undefined), + getAcceleratorForCommandId: id => (this.commandsMap[id] ? this.commandsMap[id].accelerator : undefined), + getIconForCommandId: id => (this.commandsMap[id] ? this.commandsMap[id].icon : undefined), + executeCommand: (id) => { + const command = this.commandsMap[id] + return command ? this.commandsMap[id].click(BrowserWindow.getFocusedWindow()) : undefined }, menuWillShow: () => { for (let id in this.groupsMap) { @@ -104,25 +39,41 @@ Menu.prototype._init = function() { } } -Menu.prototype.popup = function(window, x, y) { - if ((window != null ? window.constructor : undefined) !== BrowserWindow) { - /* Shift. */ +Menu.prototype.popup = function (window, x, y, positioningItem) { + let asyncPopup + + // menu.popup(x, y, positioningItem) + if (window != null && (typeof window !== 'object' || window.constructor !== BrowserWindow)) { + // Shift. + positioningItem = y y = x x = window - window = BrowserWindow.getFocusedWindow() + window = null } - if (x !== null && y !== null) { - return this._popupAt(window, x, y) - } else { - return this._popup(window) + + // menu.popup(window, {}) + if (x != null && typeof x === 'object') { + const options = x + x = options.x + y = options.y + positioningItem = options.positioningItem + asyncPopup = options.async } + + if (window == null) window = BrowserWindow.getFocusedWindow() + if (typeof x !== 'number') x = -1 + if (typeof y !== 'number') y = -1 + if (typeof positioningItem !== 'number') positioningItem = -1 + if (typeof asyncPopup !== 'boolean') asyncPopup = false + + this.popupAt(window, x, y, positioningItem, asyncPopup) } -Menu.prototype.append = function(item) { +Menu.prototype.append = function (item) { return this.insert(this.getItemCount(), item) } -Menu.prototype.insert = function(pos, item) { +Menu.prototype.insert = function (pos, item) { if ((item != null ? item.constructor : undefined) !== MenuItem) { throw new TypeError('Invalid item') } @@ -176,33 +127,39 @@ Menu.prototype.insert = function(pos, item) { } /* Force menuWillShow to be called */ -Menu.prototype._callMenuWillShow = function() { +Menu.prototype._callMenuWillShow = function () { if (this.delegate != null) this.delegate.menuWillShow() - return (() => { - const result = [] - for (let item of Array.from(this.items)) { - if (item.submenu != null) { - result.push(item.submenu._callMenuWillShow()) - } - } - return result - })() + this.items.forEach(item => { + if (item.submenu != null) item.submenu._callMenuWillShow() + }) } -let applicationMenu = null -Menu.setApplicationMenu = function(menu) { - if ((menu !== null) && (menu.constructor !== Menu)) { throw new TypeError('Invalid menu') } - /* Keep a reference. */ - applicationMenu = menu +Menu.prototype.getMenuItemById = function (id) { + const items = this.items + let found = items.find(item => item.id === id) || null + for (let i = 0, length = items.length; !found && i < length; i++) { + if (items[i].submenu) { + found = items[i].submenu.getMenuItemById(id) + } + } + return found +} + +Menu.setApplicationMenu = function (menu) { + if (menu !== null && menu.constructor !== Menu) { + throw new TypeError('Invalid menu') + } + + applicationMenu = menu if (process.platform === 'darwin') { - if (menu === null) { return } + if (menu === null) return menu._callMenuWillShow() return bindings.setApplicationMenu(menu) } else { const windows = BrowserWindow.getAllWindows() - return Array.from(windows).map((w) => w.setMenu(menu)) + return windows.map((w) => w.setMenu(menu)) } } @@ -210,38 +167,103 @@ Menu.getApplicationMenu = () => applicationMenu Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder -Menu.buildFromTemplate = function(template) { - if (!Array.isArray(template)) { throw new TypeError('Invalid template for Menu') } - - const positionedTemplate = [] - let insertIndex = 0 - - for (var item of Array.from(template)) { - if (item.position) { - insertIndex = indexToInsertByPosition(positionedTemplate, item.position) - } else { - /* If no |position| is specified, insert after last item. */ - insertIndex++ - } - positionedTemplate.splice(insertIndex, 0, item) +// build menu from a template +Menu.buildFromTemplate = function (template) { + if (!(template instanceof Array)) { + throw new TypeError('Invalid template for Menu') } const menu = new Menu + const positioned = [] + let idx = 0 - for (item of Array.from(positionedTemplate)) { - if (typeof item !== 'object') { throw new TypeError('Invalid template for MenuItem') } + template.forEach(item => { + idx = (item.position) ? indexToInsertByPosition(positioned, item.position) : idx++ + positioned.splice(idx, 0, item) + }) - const menuItem = new MenuItem(item) - for (let key in item) { - const value = item[key] - if (menuItem[key] == null) { - menuItem[key] = value - } + positioned.forEach((item) => { + if (typeof item !== 'object') { + throw new TypeError('Invalid template for MenuItem') } - menu.append(menuItem) - } + menu.append(new MenuItem(item)) + }) return menu } +// Automatically generated radio menu item's group id. +let nextGroupId = 0 +let applicationMenu = null + +/* Search between seperators to find a radio menu item and return its group id */ +const generateGroupId = function(items, pos) { + let i, item + if (pos > 0) { + let asc, start + for (start = pos - 1, i = start, asc = start <= 0; asc ? i <= 0 : i >= 0; asc ? i++ : i--) { + item = items[i] + if (item.type === 'radio') { return item.groupId } + if (item.type === 'separator') { break } + } + } else if (pos < items.length) { + let asc1, end + for (i = pos, end = items.length - 1, asc1 = pos <= end; asc1 ? i <= end : i >= end; asc1 ? i++ : i--) { + item = items[i] + if (item.type === 'radio') { return item.groupId } + if (item.type === 'separator') { break } + } + } + return ++nextGroupId +} + +/* Returns the index of item according to |id|. */ +const indexOfItemById = function (items, id) { + for (let i = 0; i < items.length; i++) { + const item = items[i] + if (item.id === id) return i + } + return -1 +} + +/* Returns the index of where to insert the item according to |position|. */ +function indexToInsertByPosition (items, position) { + if (!position) return items.length + const [query, id] = position.split('=') + let idx = indexOfItemById(items, id) + + if (idx === -1 && query !== 'endof') { + console.warn(`Item with id '${id}' is not found`) + return items.length + } + + const queries = { + 'after': () => idx++, + 'endof': () => { + if (idx === -1) { + items.push({id, type: 'separator'}) + idx = items.length - 1 + } + + idx++ + while (idx < items.length && items[idx].type !== 'separator') { + idx++ + } + } + } + + queries[query]() + return idx +} + +// WIP, need to figure out how to pass current menu group to this method +function isOuterSeparator (current, item) { + current.filter(item => { !item.visible }) + const idx = current.indexof(item) + if (idx === 0 || idx === current.length) { + return true + } + return false +} + module.exports = Menu \ No newline at end of file From 9038987e1ddc6991306b78f7e7dab8798a9f8960 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 20:04:22 -0400 Subject: [PATCH 055/185] significant cleanup; all tests still passing --- lib/browser/api/menu.js | 319 +++++++++++++++++++++++----------------- 1 file changed, 186 insertions(+), 133 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 71ac7f5241d..fbafd1d22d1 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -1,39 +1,66 @@ -const {BrowserWindow, MenuItem} = require('electron') -const {EventEmitter} = require('events') -//const _ = require('lodash') +'use strict' +const {BrowserWindow, MenuItem, webContents} = require('electron') +const EventEmitter = require('events').EventEmitter const v8Util = process.atomBinding('v8_util') const bindings = process.atomBinding('menu') -const { Menu } = bindings +const {Menu} = bindings +let applicationMenu = null +let nextGroupId = 0 -Menu.prototype.__proto__ = EventEmitter.prototype +Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype) Menu.prototype._init = function () { this.commandsMap = {} this.groupsMap = {} this.items = [] - return this.delegate = { - isCommandIdChecked: id => (this.commandsMap[id] ? this.commandsMap[id].checked : undefined), - isCommandIdEnabled: id => (this.commandsMap[id] ? this.commandsMap[id].enabled : undefined), - isCommandIdVisible: id => (this.commandsMap[id] ? this.commandsMap[id].visible : undefined), - getAcceleratorForCommandId: id => (this.commandsMap[id] ? this.commandsMap[id].accelerator : undefined), - getIconForCommandId: id => (this.commandsMap[id] ? this.commandsMap[id].icon : undefined), - executeCommand: (id) => { - const command = this.commandsMap[id] - return command ? this.commandsMap[id].click(BrowserWindow.getFocusedWindow()) : undefined + this.delegate = { + isCommandIdChecked: (commandId) => { + var command = this.commandsMap[commandId] + return command != null ? command.checked : undefined + }, + isCommandIdEnabled: (commandId) => { + var command = this.commandsMap[commandId] + return command != null ? command.enabled : undefined + }, + isCommandIdVisible: (commandId) => { + var command = this.commandsMap[commandId] + return command != null ? command.visible : undefined + }, + getAcceleratorForCommandId: (commandId, useDefaultAccelerator) => { + const command = this.commandsMap[commandId] + if (command == null) return + if (command.accelerator != null) return command.accelerator + if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() + }, + getIconForCommandId: (commandId) => { + var command = this.commandsMap[commandId] + return command != null ? command.icon : undefined + }, + executeCommand: (event, commandId) => { + const command = this.commandsMap[commandId] + if (command == null) return + command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) }, menuWillShow: () => { - for (let id in this.groupsMap) { - const group = this.groupsMap[id] - let checked = false - for (let radioItem in group) { - if (radioItem.checked) { - checked = true - break + // Make sure radio groups have at least one menu item seleted. + var checked, group, id, j, len, radioItem, ref1 + ref1 = this.groupsMap + for (id in ref1) { + group = ref1[id] + checked = false + for (j = 0, len = group.length; j < len; j++) { + radioItem = group[j] + if (!radioItem.checked) { + continue } + checked = true + break + } + if (!checked) { + v8Util.setHiddenValue(group[0], 'checked', true) } - if (!checked) v8Util.setHiddenValue(group[0], 'checked', true) } } } @@ -60,79 +87,29 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { asyncPopup = options.async } + // Default to showing in focused window. if (window == null) window = BrowserWindow.getFocusedWindow() + + // Default to showing under mouse location. if (typeof x !== 'number') x = -1 if (typeof y !== 'number') y = -1 + + // Default to not highlighting any item. if (typeof positioningItem !== 'number') positioningItem = -1 + + // Default to synchronous for backwards compatibility. if (typeof asyncPopup !== 'boolean') asyncPopup = false this.popupAt(window, x, y, positioningItem, asyncPopup) } -Menu.prototype.append = function (item) { - return this.insert(this.getItemCount(), item) -} - -Menu.prototype.insert = function (pos, item) { - if ((item != null ? item.constructor : undefined) !== MenuItem) { - throw new TypeError('Invalid item') +Menu.prototype.closePopup = function (window) { + if (window == null || window.constructor !== BrowserWindow) { + window = BrowserWindow.getFocusedWindow() } - - switch (item.type) { - case 'normal': - this.insertItem(pos, item.commandId, item.label) - break - case 'checkbox': - this.insertCheckItem(pos, item.commandId, item.label) - break - case 'separator': - this.insertSeparator(pos) - break - case 'submenu': - this.insertSubMenu(pos, item.commandId, item.label, item.submenu) - break - case 'radio': - /* Grouping radio menu items. */ - item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) - if (this.groupsMap[item.groupId] == null) this.groupsMap[item.groupId] = [] - this.groupsMap[item.groupId].push(item) - - /* Setting a radio menu item should flip other items in the group. */ - v8Util.setHiddenValue(item, 'checked', item.checked) - Object.defineProperty(item, 'checked', { - enumerable: true, - get() { return v8Util.getHiddenValue(item, 'checked') }, - set: val => { - for (let otherItem in this.groupsMap[item.groupId]) { - if (otherItem !== item) v8Util.setHiddenValue(otherItem, 'checked', false) - } - return v8Util.setHiddenValue(item, 'checked', true) - } - }) - - this.insertRadioItem(pos, item.commandId, item.label, item.groupId) - break + if (window != null) { + this.closePopupAt(window.id) } - - if (item.sublabel != null) this.setSublabel(pos, item.sublabel) - if (item.icon != null) this.setIcon(pos, item.icon) - if (item.role != null) this.setRole(pos, item.role) - - /* Make menu accessable to items. */ - item.overrideReadOnlyProperty('menu', this) - - /* Remember the items. */ - this.items.splice(pos, 0, item) - return this.commandsMap[item.commandId] = item -} - -/* Force menuWillShow to be called */ -Menu.prototype._callMenuWillShow = function () { - if (this.delegate != null) this.delegate.menuWillShow() - - this.items.forEach(item => { - if (item.submenu != null) item.submenu._callMenuWillShow() - }) } Menu.prototype.getMenuItemById = function (id) { @@ -147,8 +124,83 @@ Menu.prototype.getMenuItemById = function (id) { return found } +//cleaned up +Menu.prototype.append = function (item) { + return this.insert(this.getItemCount(), item) +} + +Menu.prototype.insert = function (pos, item) { + var base, name + if ((item != null ? item.constructor : void 0) !== MenuItem) { + throw new TypeError('Invalid item') + } + switch (item.type) { + case 'normal': + this.insertItem(pos, item.commandId, item.label) + break + case 'checkbox': + this.insertCheckItem(pos, item.commandId, item.label) + break + case 'separator': + this.insertSeparator(pos) + break + case 'submenu': + this.insertSubMenu(pos, item.commandId, item.label, item.submenu) + break + case 'radio': + // Grouping radio menu items. + item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) + if ((base = this.groupsMap)[name = item.groupId] == null) { + base[name] = [] + } + this.groupsMap[item.groupId].push(item) + + // Setting a radio menu item should flip other items in the group. + v8Util.setHiddenValue(item, 'checked', item.checked) + Object.defineProperty(item, 'checked', { + enumerable: true, + get: function () { + return v8Util.getHiddenValue(item, 'checked') + }, + set: () => { + var j, len, otherItem, ref1 + ref1 = this.groupsMap[item.groupId] + for (j = 0, len = ref1.length; j < len; j++) { + otherItem = ref1[j] + if (otherItem !== item) { + v8Util.setHiddenValue(otherItem, 'checked', false) + } + } + return v8Util.setHiddenValue(item, 'checked', true) + } + }) + this.insertRadioItem(pos, item.commandId, item.label, item.groupId) + } + + if (item.sublabel != null) this.setSublabel(pos, item.sublabel) + if (item.icon != null) this.setIcon(pos, item.icon) + if (item.role != null) this.setRole(pos, item.role) + + // Make menu accessable to items. + item.overrideReadOnlyProperty('menu', this) + + // Remember the items. + this.items.splice(pos, 0, item) + this.commandsMap[item.commandId] = item +} + +// Force menuWillShow to be called +// cleaned up +Menu.prototype._callMenuWillShow = function () { + if (this.delegate != null) this.delegate.menuWillShow() + this.items.forEach(item => { + if (item.submenu != null) item.submenu._callMenuWillShow() + }) +} + +// cleaned up Menu.setApplicationMenu = function (menu) { - if (menu !== null && menu.constructor !== Menu) { + if (!(menu === null || menu.constructor === Menu)) { throw new TypeError('Invalid menu') } @@ -156,32 +208,35 @@ Menu.setApplicationMenu = function (menu) { if (process.platform === 'darwin') { if (menu === null) return menu._callMenuWillShow() - return bindings.setApplicationMenu(menu) + bindings.setApplicationMenu(menu) } else { const windows = BrowserWindow.getAllWindows() - return windows.map((w) => w.setMenu(menu)) + return windows.map(w => w.setMenu(menu)) } } +// cleaned up Menu.getApplicationMenu = () => applicationMenu Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder -// build menu from a template +// cleaned up Menu.buildFromTemplate = function (template) { if (!(template instanceof Array)) { throw new TypeError('Invalid template for Menu') } - const menu = new Menu + const menu = new Menu() const positioned = [] let idx = 0 + // sort template by position template.forEach(item => { - idx = (item.position) ? indexToInsertByPosition(positioned, item.position) : idx++ + idx = (item.position) ? indexToInsertByPosition(positioned, item.position) : idx += 1 positioned.splice(idx, 0, item) }) + // add each item from positioned menu to application menu positioned.forEach((item) => { if (typeof item !== 'object') { throw new TypeError('Invalid template for MenuItem') @@ -192,78 +247,76 @@ Menu.buildFromTemplate = function (template) { return menu } -// Automatically generated radio menu item's group id. -let nextGroupId = 0 -let applicationMenu = null +/* Helper Methods */ -/* Search between seperators to find a radio menu item and return its group id */ -const generateGroupId = function(items, pos) { - let i, item +// Search between separators to find a radio menu item and return its group id, +function generateGroupId (items, pos) { + var i, item, j, k, ref1, ref2, ref3 if (pos > 0) { - let asc, start - for (start = pos - 1, i = start, asc = start <= 0; asc ? i <= 0 : i >= 0; asc ? i++ : i--) { + for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) { item = items[i] - if (item.type === 'radio') { return item.groupId } - if (item.type === 'separator') { break } + if (item.type === 'radio') { + return item.groupId + } + if (item.type === 'separator') { + break + } } } else if (pos < items.length) { - let asc1, end - for (i = pos, end = items.length - 1, asc1 = pos <= end; asc1 ? i <= end : i >= end; asc1 ? i++ : i--) { + for (i = k = ref2 = pos, ref3 = items.length - 1; ref2 <= ref3 ? k <= ref3 : k >= ref3; i = ref2 <= ref3 ? ++k : --k) { item = items[i] - if (item.type === 'radio') { return item.groupId } - if (item.type === 'separator') { break } + if (item.type === 'radio') { + return item.groupId + } + if (item.type === 'separator') { + break + } } } return ++nextGroupId } -/* Returns the index of item according to |id|. */ -const indexOfItemById = function (items, id) { - for (let i = 0; i < items.length; i++) { - const item = items[i] - if (item.id === id) return i - } - return -1 +// Returns the index of item according to |id|. +// cleaned up +function indexOfItemById (items, id) { + const foundItem = items.find(item => item.id === id) || null + return items.indexOf(foundItem) } -/* Returns the index of where to insert the item according to |position|. */ +// Returns the index of where to insert the item according to |position| function indexToInsertByPosition (items, position) { if (!position) return items.length - const [query, id] = position.split('=') - let idx = indexOfItemById(items, id) + const [query, id] = position.split('=') // parse query and id from position + const idx = indexOfItemById(items, id) // calculate initial index of item + + // warn if query doesn't exist if (idx === -1 && query !== 'endof') { - console.warn(`Item with id '${id}' is not found`) + console.warn("Item with id '" + id + "' is not found") return items.length } + // compute new index based on query const queries = { - 'after': () => idx++, - 'endof': () => { - if (idx === -1) { + 'after': (index) => index += 1, + 'endof': (index) => { + if (index === -1) { items.push({id, type: 'separator'}) - idx = items.length - 1 + index = items.length - 1 } - idx++ - while (idx < items.length && items[idx].type !== 'separator') { - idx++ - } + index += 1 + while (index < items.length && items[index].type !== 'separator') index += 1 + return index } } - queries[query]() - return idx + // return new index if needed, or original indexOfItemById + return (query in queries) ? queries[query](idx) : idx } -// WIP, need to figure out how to pass current menu group to this method -function isOuterSeparator (current, item) { - current.filter(item => { !item.visible }) - const idx = current.indexof(item) - if (idx === 0 || idx === current.length) { - return true - } - return false +function computeNewIndexOnQuery(idx, query) { + } module.exports = Menu \ No newline at end of file From 9b364d5be30c24e998bc2acb22f1812838f1ac06 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 22:22:39 -0400 Subject: [PATCH 056/185] refactor menuWillShow --- lib/browser/api/menu.js | 54 ++++++++++++----------------------------- 1 file changed, 16 insertions(+), 38 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index fbafd1d22d1..9877d81bb9b 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -7,7 +7,7 @@ const bindings = process.atomBinding('menu') const {Menu} = bindings let applicationMenu = null -let nextGroupId = 0 +let groupIdIndex = 0 Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype) @@ -44,23 +44,10 @@ Menu.prototype._init = function () { command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) }, menuWillShow: () => { - // Make sure radio groups have at least one menu item seleted. - var checked, group, id, j, len, radioItem, ref1 - ref1 = this.groupsMap - for (id in ref1) { - group = ref1[id] - checked = false - for (j = 0, len = group.length; j < len; j++) { - radioItem = group[j] - if (!radioItem.checked) { - continue - } - checked = true - break - } - if (!checked) { - v8Util.setHiddenValue(group[0], 'checked', true) - } + // Ensure radio groups have at least one menu item seleted + for (let id in this.groupsMap) { + let found = this.groupsMap[id].find(item => item.checked) || null + if (!found) v8Util.setHiddenValue(this.groupsMap[id][0], 'checked', true) } } } @@ -251,29 +238,23 @@ Menu.buildFromTemplate = function (template) { // Search between separators to find a radio menu item and return its group id, function generateGroupId (items, pos) { - var i, item, j, k, ref1, ref2, ref3 + let i, item if (pos > 0) { - for (i = j = ref1 = pos - 1; ref1 <= 0 ? j <= 0 : j >= 0; i = ref1 <= 0 ? ++j : --j) { + let asc, start + for (start = pos - 1, i = start, asc = start <= 0; asc ? i <= 0 : i >= 0; asc ? i++ : i--) { item = items[i] - if (item.type === 'radio') { - return item.groupId - } - if (item.type === 'separator') { - break - } + if (item.type === 'radio') { return item.groupId } + if (item.type === 'separator') { break } } } else if (pos < items.length) { - for (i = k = ref2 = pos, ref3 = items.length - 1; ref2 <= ref3 ? k <= ref3 : k >= ref3; i = ref2 <= ref3 ? ++k : --k) { + let asc1, end + for (i = pos, end = items.length - 1, asc1 = pos <= end; asc1 ? i <= end : i >= end; asc1 ? i++ : i--) { item = items[i] - if (item.type === 'radio') { - return item.groupId - } - if (item.type === 'separator') { - break - } + if (item.type === 'radio') { return item.groupId } + if (item.type === 'separator') { break } } } - return ++nextGroupId + return ++groupIdIndex } // Returns the index of item according to |id|. @@ -284,6 +265,7 @@ function indexOfItemById (items, id) { } // Returns the index of where to insert the item according to |position| +// cleaned up function indexToInsertByPosition (items, position) { if (!position) return items.length @@ -315,8 +297,4 @@ function indexToInsertByPosition (items, position) { return (query in queries) ? queries[query](idx) : idx } -function computeNewIndexOnQuery(idx, query) { - -} - module.exports = Menu \ No newline at end of file From 508b6147694ff2706fb6f016a2a064971f46d3b6 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 22:33:23 -0400 Subject: [PATCH 057/185] remove excess code in delegate --- lib/browser/api/menu.js | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 9877d81bb9b..b123c8e46bb 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -16,31 +16,19 @@ Menu.prototype._init = function () { this.groupsMap = {} this.items = [] this.delegate = { - isCommandIdChecked: (commandId) => { - var command = this.commandsMap[commandId] - return command != null ? command.checked : undefined - }, - isCommandIdEnabled: (commandId) => { - var command = this.commandsMap[commandId] - return command != null ? command.enabled : undefined - }, - isCommandIdVisible: (commandId) => { - var command = this.commandsMap[commandId] - return command != null ? command.visible : undefined - }, - getAcceleratorForCommandId: (commandId, useDefaultAccelerator) => { - const command = this.commandsMap[commandId] - if (command == null) return - if (command.accelerator != null) return command.accelerator + isCommandIdChecked: id => this.commandsMap[id].checked, + isCommandIdEnabled: id => this.commandsMap[id].enabled, + isCommandIdVisible: id => this.commandsMap[id].visible, + getAcceleratorForCommandId: (id, useDefaultAccelerator) => { + const command = this.commandsMap[id] + if (command === null) return + if (command.accelerator !== null) return command.accelerator if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() }, - getIconForCommandId: (commandId) => { - var command = this.commandsMap[commandId] - return command != null ? command.icon : undefined - }, - executeCommand: (event, commandId) => { - const command = this.commandsMap[commandId] - if (command == null) return + getIconForCommandId: id => this.commandsMap[id].icon, + executeCommand: (event, id) => { + const command = this.commandsMap[id] + if (command === null) return command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) }, menuWillShow: () => { From 7c0f7329d90583b2f743fd05240bfed90d5583c4 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 22:35:42 -0400 Subject: [PATCH 058/185] appease the linter overlords --- lib/browser/api/menu.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index b123c8e46bb..bd89ca319b9 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -99,7 +99,6 @@ Menu.prototype.getMenuItemById = function (id) { return found } -//cleaned up Menu.prototype.append = function (item) { return this.insert(this.getItemCount(), item) } @@ -268,7 +267,10 @@ function indexToInsertByPosition (items, position) { // compute new index based on query const queries = { - 'after': (index) => index += 1, + 'after': (index) => { + index += 1 + return index + }, 'endof': (index) => { if (index === -1) { items.push({id, type: 'separator'}) @@ -285,4 +287,4 @@ function indexToInsertByPosition (items, position) { return (query in queries) ? queries[query](idx) : idx } -module.exports = Menu \ No newline at end of file +module.exports = Menu From b1e707d53534474e73b446e731ad8dfc17518664 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 23 Oct 2017 23:46:39 -0400 Subject: [PATCH 059/185] abstract out switch case from Menu.prototype.insert --- lib/browser/api/menu.js | 108 ++++++++++++++++++++-------------------- 1 file changed, 53 insertions(+), 55 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index bd89ca319b9..77d881b5d30 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -11,6 +11,7 @@ let groupIdIndex = 0 Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype) +// cleaned up Menu.prototype._init = function () { this.commandsMap = {} this.groupsMap = {} @@ -41,6 +42,7 @@ Menu.prototype._init = function () { } } +// create and show a popup Menu.prototype.popup = function (window, x, y, positioningItem) { let asyncPopup @@ -78,6 +80,7 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { this.popupAt(window, x, y, positioningItem, asyncPopup) } +// close an existing popup Menu.prototype.closePopup = function (window) { if (window == null || window.constructor !== BrowserWindow) { window = BrowserWindow.getFocusedWindow() @@ -87,11 +90,12 @@ Menu.prototype.closePopup = function (window) { } } +// return a MenuItem with the specified id Menu.prototype.getMenuItemById = function (id) { const items = this.items let found = items.find(item => item.id === id) || null - for (let i = 0, length = items.length; !found && i < length; i++) { + for (let i = 0; !found && i < items.length; i++) { if (items[i].submenu) { found = items[i].submenu.getMenuItemById(id) } @@ -99,58 +103,21 @@ Menu.prototype.getMenuItemById = function (id) { return found } +// append a new MenuItem to an existing Menu Menu.prototype.append = function (item) { return this.insert(this.getItemCount(), item) } +// insert a new menu item at a specified location Menu.prototype.insert = function (pos, item) { - var base, name if ((item != null ? item.constructor : void 0) !== MenuItem) { throw new TypeError('Invalid item') } - switch (item.type) { - case 'normal': - this.insertItem(pos, item.commandId, item.label) - break - case 'checkbox': - this.insertCheckItem(pos, item.commandId, item.label) - break - case 'separator': - this.insertSeparator(pos) - break - case 'submenu': - this.insertSubMenu(pos, item.commandId, item.label, item.submenu) - break - case 'radio': - // Grouping radio menu items. - item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) - if ((base = this.groupsMap)[name = item.groupId] == null) { - base[name] = [] - } - this.groupsMap[item.groupId].push(item) - // Setting a radio menu item should flip other items in the group. - v8Util.setHiddenValue(item, 'checked', item.checked) - Object.defineProperty(item, 'checked', { - enumerable: true, - get: function () { - return v8Util.getHiddenValue(item, 'checked') - }, - set: () => { - var j, len, otherItem, ref1 - ref1 = this.groupsMap[item.groupId] - for (j = 0, len = ref1.length; j < len; j++) { - otherItem = ref1[j] - if (otherItem !== item) { - v8Util.setHiddenValue(otherItem, 'checked', false) - } - } - return v8Util.setHiddenValue(item, 'checked', true) - } - }) - this.insertRadioItem(pos, item.commandId, item.label, item.groupId) - } + // insert item depending on its type + insertItemByType.call(this, item, pos) + // set item properties if (item.sublabel != null) this.setSublabel(pos, item.sublabel) if (item.icon != null) this.setIcon(pos, item.icon) if (item.role != null) this.setRole(pos, item.role) @@ -164,7 +131,6 @@ Menu.prototype.insert = function (pos, item) { } // Force menuWillShow to be called -// cleaned up Menu.prototype._callMenuWillShow = function () { if (this.delegate != null) this.delegate.menuWillShow() this.items.forEach(item => { @@ -172,7 +138,12 @@ Menu.prototype._callMenuWillShow = function () { }) } -// cleaned up +// return application menu +Menu.getApplicationMenu = () => applicationMenu + +Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder + +// set application menu with a preexisting menu Menu.setApplicationMenu = function (menu) { if (!(menu === null || menu.constructor === Menu)) { throw new TypeError('Invalid menu') @@ -189,12 +160,7 @@ Menu.setApplicationMenu = function (menu) { } } -// cleaned up -Menu.getApplicationMenu = () => applicationMenu - -Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder - -// cleaned up +// build a menu by passing in a template Menu.buildFromTemplate = function (template) { if (!(template instanceof Array)) { throw new TypeError('Invalid template for Menu') @@ -223,7 +189,7 @@ Menu.buildFromTemplate = function (template) { /* Helper Methods */ -// Search between separators to find a radio menu item and return its group id, +// Search between separators to find a radio menu item and return its group id function generateGroupId (items, pos) { let i, item if (pos > 0) { @@ -241,18 +207,17 @@ function generateGroupId (items, pos) { if (item.type === 'separator') { break } } } - return ++groupIdIndex + groupIdIndex += 1 + return groupIdIndex } // Returns the index of item according to |id|. -// cleaned up function indexOfItemById (items, id) { const foundItem = items.find(item => item.id === id) || null return items.indexOf(foundItem) } // Returns the index of where to insert the item according to |position| -// cleaned up function indexToInsertByPosition (items, position) { if (!position) return items.length @@ -287,4 +252,37 @@ function indexToInsertByPosition (items, position) { return (query in queries) ? queries[query](idx) : idx } +// insert a new MenuItem depending on its type +function insertItemByType(item, pos) { + const types = { + 'normal': () => this.insertItem(pos, item.commandId, item.label), + 'checkbox': () => this.insertCheckItem(pos, item.commandId, item.label), + 'separator':() => this.insertSeparator(pos), + 'submenu': () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu), + 'radio': () => { + // Grouping radio menu items + item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) + if (this.groupsMap[item.groupId] == null) { + this.groupsMap[item.groupId] = [] + } + this.groupsMap[item.groupId].push(item) + + // Setting a radio menu item should flip other items in the group. + v8Util.setHiddenValue(item, 'checked', item.checked) + Object.defineProperty(item, 'checked', { + enumerable: true, + get: () => v8Util.getHiddenValue(item, 'checked'), + set: () => { + this.groupsMap[item.groupId].forEach(other => { + if (other !== item) v8Util.setHiddenValue(other, 'checked', false) + }) + v8Util.setHiddenValue(item, 'checked', true) + } + }) + this.insertRadioItem(pos, item.commandId, item.label, item.groupId) + } + } + types[item.type]() +} + module.exports = Menu From f93121b226d824c20fa5af0015afff9231cc73db Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 00:07:39 -0400 Subject: [PATCH 060/185] don't reassign parameters in Menu.prototype.popup --- lib/browser/api/menu.js | 53 +++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 28 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 77d881b5d30..82ecb08dab0 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -11,7 +11,8 @@ let groupIdIndex = 0 Object.setPrototypeOf(Menu.prototype, EventEmitter.prototype) -// cleaned up +/* Instance Methods */ + Menu.prototype._init = function () { this.commandsMap = {} this.groupsMap = {} @@ -45,39 +46,33 @@ Menu.prototype._init = function () { // create and show a popup Menu.prototype.popup = function (window, x, y, positioningItem) { let asyncPopup + let [newX, newY, newPosition, newWindow] = [x, y, positioningItem, window] // menu.popup(x, y, positioningItem) - if (window != null && (typeof window !== 'object' || window.constructor !== BrowserWindow)) { - // Shift. - positioningItem = y - y = x - x = window - window = null + if (window !== null) { + // shift over values + if (typeof window !== 'object' || window.constructor !== BrowserWindow) { + [newPosition, newY, newX, newWindow] = [y, x, window, null] + } } // menu.popup(window, {}) - if (x != null && typeof x === 'object') { - const options = x - x = options.x - y = options.y - positioningItem = options.positioningItem - asyncPopup = options.async + if (x !== null && typeof x === 'object') { + const opts = x + newX = opts.x + newY = opts.y + newPosition = opts.positioningItem + asyncPopup = opts.async } - // Default to showing in focused window. - if (window == null) window = BrowserWindow.getFocusedWindow() - - // Default to showing under mouse location. - if (typeof x !== 'number') x = -1 - if (typeof y !== 'number') y = -1 - - // Default to not highlighting any item. - if (typeof positioningItem !== 'number') positioningItem = -1 - - // Default to synchronous for backwards compatibility. + // set defaults + if (typeof x !== 'number') newX = -1 + if (typeof y !== 'number') newY = -1 + if (typeof positioningItem !== 'number') newPosition = -1 + if (window === null) newWindow = BrowserWindow.getFocusedWindow() if (typeof asyncPopup !== 'boolean') asyncPopup = false - this.popupAt(window, x, y, positioningItem, asyncPopup) + this.popupAt(newWindow, newX, newY, newPosition, asyncPopup) } // close an existing popup @@ -138,6 +133,8 @@ Menu.prototype._callMenuWillShow = function () { }) } +/* Static Methods */ + // return application menu Menu.getApplicationMenu = () => applicationMenu @@ -187,7 +184,7 @@ Menu.buildFromTemplate = function (template) { return menu } -/* Helper Methods */ +/* Helper Functions */ // Search between separators to find a radio menu item and return its group id function generateGroupId (items, pos) { @@ -253,11 +250,11 @@ function indexToInsertByPosition (items, position) { } // insert a new MenuItem depending on its type -function insertItemByType(item, pos) { +function insertItemByType (item, pos) { const types = { 'normal': () => this.insertItem(pos, item.commandId, item.label), 'checkbox': () => this.insertCheckItem(pos, item.commandId, item.label), - 'separator':() => this.insertSeparator(pos), + 'separator': () => this.insertSeparator(pos), 'submenu': () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu), 'radio': () => { // Grouping radio menu items From 75f32afcd513c94baececeb2d6414b43c27ed93b Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 00:24:57 -0400 Subject: [PATCH 061/185] clean up excess code from generateGroupId --- lib/browser/api/menu.js | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 82ecb08dab0..1effc3ff761 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -188,20 +188,15 @@ Menu.buildFromTemplate = function (template) { // Search between separators to find a radio menu item and return its group id function generateGroupId (items, pos) { - let i, item if (pos > 0) { - let asc, start - for (start = pos - 1, i = start, asc = start <= 0; asc ? i <= 0 : i >= 0; asc ? i++ : i--) { - item = items[i] - if (item.type === 'radio') { return item.groupId } - if (item.type === 'separator') { break } + for (let idx = pos - 1; idx >= 0; idx--) { + if (items[idx].type === 'radio') return items[idx].groupId + if (items[idx].type === 'separator') break } } else if (pos < items.length) { - let asc1, end - for (i = pos, end = items.length - 1, asc1 = pos <= end; asc1 ? i <= end : i >= end; asc1 ? i++ : i--) { - item = items[i] - if (item.type === 'radio') { return item.groupId } - if (item.type === 'separator') { break } + for (let idx = pos; idx <= items.length - 1; idx++) { + if (items[idx].type === 'radio') return items[idx].groupId + if (items[idx].type === 'separator') break } } groupIdIndex += 1 From e7649a800a66c7cc420bd499aff00ae74afeacf5 Mon Sep 17 00:00:00 2001 From: Jonas Zhang <106856363@qq.com> Date: Tue, 24 Oct 2017 14:02:07 +0800 Subject: [PATCH 062/185] Add a little translation for zh-CN Add a little translation for zh-CN --- docs-translations/zh-CN/styleguide.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs-translations/zh-CN/styleguide.md b/docs-translations/zh-CN/styleguide.md index 74f888ace01..660776d505f 100644 --- a/docs-translations/zh-CN/styleguide.md +++ b/docs-translations/zh-CN/styleguide.md @@ -173,7 +173,7 @@ required[, optional] 如果参数或方法对某些平台是唯一的,那么这些平台将使用数据类型后面的空格分隔的斜体列表来表示。 值可以是 `macOS`,`Windows` 或 `Linux` ```markdown -* `animate` Boolean (optional) _macOS_ _Windows_ - Animate the thing. +* `animate` Boolean (optional) _macOS_ _Windows_ - 进行动画处理的事情. ``` `Array` 类型的参数, 必须在指定数组下面的描述中描述可能包含的元素. From c1cad655c87a124db267d5eb4a2a3b6862d52f43 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 24 Oct 2017 11:46:14 +0200 Subject: [PATCH 063/185] Fixed typo `thrid-party` => `third-party` --- docs/tutorial/accessibility.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/tutorial/accessibility.md b/docs/tutorial/accessibility.md index d2b6099bba5..b003d794e3a 100644 --- a/docs/tutorial/accessibility.md +++ b/docs/tutorial/accessibility.md @@ -44,7 +44,7 @@ By using [`app.setAccessibilitySupportEnabled(enabled)`](https://electron.atom.i Electron application will enable accessibility automatically when it detects assistive technology (Windows) or VoiceOver (macOS). See Chrome's [accessibility documentation](https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology) for more details. -On macOS, thrid-party assistive technology can switch accessibility inside Electron applications by setting the attribute `AXManualAccessibility` programmatically: +On macOS, third-party assistive technology can switch accessibility inside Electron applications by setting the attribute `AXManualAccessibility` programmatically: ```objc CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility"); From 43e118fe45c357c1aea60015196888a5a379081f Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 12:01:51 -0400 Subject: [PATCH 064/185] update desktop capturer and remove unnessary vars --- lib/renderer/api/desktop-capturer.js | 40 ++++++++++++---------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index e998c786a59..3b9e5a6505b 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -1,46 +1,40 @@ -const ipcRenderer = require('electron').ipcRenderer -const nativeImage = require('electron').nativeImage +const {ipcRenderer, nativeImage} = require('electron') -var nextId = 0 -var includes = [].includes +const includes = [].includes +let currentId = 0 -var getNextId = function () { - return ++nextId -} +const incrementId = () => currentId += 1 // |options.type| can not be empty and has to include 'window' or 'screen'. -var isValid = function (options) { - return ((options != null ? options.types : void 0) != null) && Array.isArray(options.types) +function isValid (options) { + const types = (options != null) ? options.types : undefined + return (types != null) && Array.isArray(options.types) } exports.getSources = function (options, callback) { - var captureScreen, captureWindow, id - if (!isValid(options)) { - return callback(new Error('Invalid options')) - } - captureWindow = includes.call(options.types, 'window') - captureScreen = includes.call(options.types, 'screen') + if (!isValid(options)) return callback(new Error('Invalid options')) + const captureWindow = includes.call(options.types, 'window') + const captureScreen = includes.call(options.types, 'screen') + if (options.thumbnailSize == null) { options.thumbnailSize = { width: 150, height: 150 } } - id = getNextId() + + const id = incrementId() ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id) - return ipcRenderer.once('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + id, function (event, sources) { - var source - callback(null, (function () { - var i, len, results + return ipcRenderer.once(`ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`, (event, sources) => { + callback(null, (() => { results = [] - for (i = 0, len = sources.length; i < len; i++) { - source = sources[i] + sources.forEach(source => { results.push({ id: source.id, name: source.name, thumbnail: nativeImage.createFromDataURL(source.thumbnail) }) - } + }) return results })()) }) From b58ceae69cec41e3d31230a1117a965aa8379ac2 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 12:28:15 -0400 Subject: [PATCH 065/185] appease linter gods --- lib/renderer/api/desktop-capturer.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index 3b9e5a6505b..ff47dfd8e98 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -3,7 +3,10 @@ const {ipcRenderer, nativeImage} = require('electron') const includes = [].includes let currentId = 0 -const incrementId = () => currentId += 1 +const incrementId = () => { + currentId += 1 + return currentId +} // |options.type| can not be empty and has to include 'window' or 'screen'. function isValid (options) { @@ -27,7 +30,7 @@ exports.getSources = function (options, callback) { ipcRenderer.send('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', captureWindow, captureScreen, options.thumbnailSize, id) return ipcRenderer.once(`ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}`, (event, sources) => { callback(null, (() => { - results = [] + const results = [] sources.forEach(source => { results.push({ id: source.id, From aaa8aec946c0c1ecc964ae806642442e96210493 Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 24 Oct 2017 12:42:45 -0400 Subject: [PATCH 066/185] trying out parameterized builds in circle --- .circleci/config.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index a43cb917fab..5841bb39318 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,6 +19,10 @@ jobs: case ${MESSAGE} in Bump* ) echo 'export ELECTRON_RELEASE=1' >> $BASH_ENV esac + if [ -n "${RUN_RELEASE_BUILD}" ]; then + echo 'release build triggered from api' + echo 'export ELECTRON_RELEASE=1' >> $BASH_ENV + fi - run: name: Bootstrap command: | @@ -63,7 +67,7 @@ jobs: - image: electronbuilds/electron:0.0.3 environment: TARGET_ARCH: arm64 - resource_class: xlarge + resource_class: xlarge steps: - checkout - run: From 491a00fd84ac6db719666a9fe38e0e0b35b7fa46 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 12:49:37 -0400 Subject: [PATCH 067/185] clean main process desktop_capturer --- lib/browser/desktop-capturer.js | 66 +++++++++++++++++---------------- 1 file changed, 34 insertions(+), 32 deletions(-) diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index da1d481c605..bd264bab845 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -1,23 +1,23 @@ 'use strict' -const ipcMain = require('electron').ipcMain -const desktopCapturer = process.atomBinding('desktop_capturer').desktopCapturer +const {ipcMain} = require('electron') +const {desktopCapturer} = process.atomBinding('desktop_capturer') -var deepEqual = function (opt1, opt2) { - return JSON.stringify(opt1) === JSON.stringify(opt2) -} +const deepEqual = (a, b) => JSON.stringify(a) === JSON.stringify(b) // A queue for holding all requests from renderer process. -var requestsQueue = [] +let requestsQueue = [] -ipcMain.on('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, captureWindow, captureScreen, thumbnailSize, id) { - var request - request = { - id: id, +const electronSources = 'ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES' +const capturerResult = (id) => `ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_${id}` + +ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, id) => { + const request = { + id, options: { - captureWindow: captureWindow, - captureScreen: captureScreen, - thumbnailSize: thumbnailSize + captureWindow, + captureScreen, + thumbnailSize }, webContents: event.sender } @@ -28,45 +28,47 @@ ipcMain.on('ELECTRON_BROWSER_DESKTOP_CAPTURER_GET_SOURCES', function (event, cap // If the WebContents is destroyed before receiving result, just remove the // reference from requestsQueue to make the module not send the result to it. - event.sender.once('destroyed', function () { + event.sender.once('destroyed', () => { request.webContents = null + return }) }) -desktopCapturer.emit = function (event, name, sources) { +desktopCapturer.emit = (event, name, sources) => { // Receiving sources result from main process, now send them back to renderer. - var handledRequest, i, len, ref, ref1, request, result, source, unhandledRequestsQueue - handledRequest = requestsQueue.shift(0) - result = (function () { - var i, len, results - results = [] - for (i = 0, len = sources.length; i < len; i++) { - source = sources[i] + const handledRequest = requestsQueue.shift(0) + const handledWebContents = handledRequest.webContents + const unhandledRequestsQueue = [] + + const result = () => { + const results = [] + sources.forEach(source => { results.push({ id: source.id, name: source.name, thumbnail: source.thumbnail.toDataURL() }) - } + }) return results - })() - if ((ref = handledRequest.webContents) != null) { - ref.send('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + handledRequest.id, result) + } + + if (handledWebContents != null) { + handledWebContents.send(capturerResult(handledRequest.id), result()) } // Check the queue to see whether there is other same request. If has, handle // it for reducing redunplicated `desktopCaptuer.startHandling` calls. - unhandledRequestsQueue = [] - for (i = 0, len = requestsQueue.length; i < len; i++) { - request = requestsQueue[i] + + requestsQueue.forEach(request => { + const webContents = request.webContents if (deepEqual(handledRequest.options, request.options)) { - if ((ref1 = request.webContents) != null) { - ref1.send('ELECTRON_RENDERER_DESKTOP_CAPTURER_RESULT_' + request.id, result) + if (webContents != null) { + webContents.send(capturerResult(request.id), result()) } } else { unhandledRequestsQueue.push(request) } - } + }) requestsQueue = unhandledRequestsQueue // If the requestsQueue is not empty, start a new request handling. From 98df1537507eb230ad2bd54ac479baa0f4d5dd7e Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 15:47:09 -0400 Subject: [PATCH 068/185] convert to map and remove shift param --- lib/browser/desktop-capturer.js | 24 ++++++++++-------------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index bd264bab845..74acb828544 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -36,24 +36,20 @@ ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, desktopCapturer.emit = (event, name, sources) => { // Receiving sources result from main process, now send them back to renderer. - const handledRequest = requestsQueue.shift(0) + const handledRequest = requestsQueue.shift() const handledWebContents = handledRequest.webContents const unhandledRequestsQueue = [] - const result = () => { - const results = [] - sources.forEach(source => { - results.push({ - id: source.id, - name: source.name, - thumbnail: source.thumbnail.toDataURL() - }) - }) - return results - } + const result = sources.map(source => { + return { + id: source.id, + name: source.name, + thumbnail: source.thumbnail.toDataURL() + } + }) if (handledWebContents != null) { - handledWebContents.send(capturerResult(handledRequest.id), result()) + handledWebContents.send(capturerResult(handledRequest.id), result) } // Check the queue to see whether there is other same request. If has, handle @@ -63,7 +59,7 @@ desktopCapturer.emit = (event, name, sources) => { const webContents = request.webContents if (deepEqual(handledRequest.options, request.options)) { if (webContents != null) { - webContents.send(capturerResult(request.id), result()) + webContents.send(capturerResult(request.id), result) } } else { unhandledRequestsQueue.push(request) From 7e1adfcab7d44409549c071173e2e646b2e4567e Mon Sep 17 00:00:00 2001 From: John Kleinschmidt Date: Tue, 24 Oct 2017 16:28:05 -0400 Subject: [PATCH 069/185] Apply escape analysis patch --- vendor/libchromiumcontent | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/libchromiumcontent b/vendor/libchromiumcontent index 01de61a555f..1aaa5c36280 160000 --- a/vendor/libchromiumcontent +++ b/vendor/libchromiumcontent @@ -1 +1 @@ -Subproject commit 01de61a555fb2c3c673eeea88620a873b8ef63c7 +Subproject commit 1aaa5c3628084035d5e349bdc9cef6dbeb87bcc8 From e8935232b1898ef6cb0c7e7a002d4f231e6fb032 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 18:52:12 -0400 Subject: [PATCH 070/185] clean falsy statements --- lib/browser/api/menu.js | 46 ++++++++++++++++++++--------------------- 1 file changed, 22 insertions(+), 24 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 1effc3ff761..9864e189b26 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -18,19 +18,19 @@ Menu.prototype._init = function () { this.groupsMap = {} this.items = [] this.delegate = { - isCommandIdChecked: id => this.commandsMap[id].checked, - isCommandIdEnabled: id => this.commandsMap[id].enabled, - isCommandIdVisible: id => this.commandsMap[id].visible, + isCommandIdChecked: id => this.commandsMap[id] ? this.commandsMap[id].checked : undefined, + isCommandIdEnabled: id => this.commandsMap[id] ? this.commandsMap[id].enabled : undefined, + isCommandIdVisible: id => this.commandsMap[id] ? this.commandsMap[id].visible : undefined, getAcceleratorForCommandId: (id, useDefaultAccelerator) => { const command = this.commandsMap[id] - if (command === null) return - if (command.accelerator !== null) return command.accelerator + if (!command) return + if (command.accelerator) return command.accelerator if (useDefaultAccelerator) return command.getDefaultRoleAccelerator() }, - getIconForCommandId: id => this.commandsMap[id].icon, + getIconForCommandId: id => this.commandsMap[id] ? this.commandsMap[id].icon : undefined, executeCommand: (event, id) => { const command = this.commandsMap[id] - if (command === null) return + if (!command) return command.click(event, BrowserWindow.getFocusedWindow(), webContents.getFocusedWebContents()) }, menuWillShow: () => { @@ -49,7 +49,7 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { let [newX, newY, newPosition, newWindow] = [x, y, positioningItem, window] // menu.popup(x, y, positioningItem) - if (window !== null) { + if (!window) { // shift over values if (typeof window !== 'object' || window.constructor !== BrowserWindow) { [newPosition, newY, newX, newWindow] = [y, x, window, null] @@ -57,7 +57,7 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { } // menu.popup(window, {}) - if (x !== null && typeof x === 'object') { + if (x && typeof x === 'object') { const opts = x newX = opts.x newY = opts.y @@ -69,7 +69,7 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { if (typeof x !== 'number') newX = -1 if (typeof y !== 'number') newY = -1 if (typeof positioningItem !== 'number') newPosition = -1 - if (window === null) newWindow = BrowserWindow.getFocusedWindow() + if (!window) newWindow = BrowserWindow.getFocusedWindow() if (typeof asyncPopup !== 'boolean') asyncPopup = false this.popupAt(newWindow, newX, newY, newPosition, asyncPopup) @@ -77,12 +77,10 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { // close an existing popup Menu.prototype.closePopup = function (window) { - if (window == null || window.constructor !== BrowserWindow) { + if (!window || window.constructor !== BrowserWindow) { window = BrowserWindow.getFocusedWindow() } - if (window != null) { - this.closePopupAt(window.id) - } + if (window) this.closePopupAt(window.id) } // return a MenuItem with the specified id @@ -105,7 +103,7 @@ Menu.prototype.append = function (item) { // insert a new menu item at a specified location Menu.prototype.insert = function (pos, item) { - if ((item != null ? item.constructor : void 0) !== MenuItem) { + if ((item ? item.constructor : void 0) !== MenuItem) { throw new TypeError('Invalid item') } @@ -113,9 +111,9 @@ Menu.prototype.insert = function (pos, item) { insertItemByType.call(this, item, pos) // set item properties - if (item.sublabel != null) this.setSublabel(pos, item.sublabel) - if (item.icon != null) this.setIcon(pos, item.icon) - if (item.role != null) this.setRole(pos, item.role) + if (item.sublabel) this.setSublabel(pos, item.sublabel) + if (item.icon) this.setIcon(pos, item.icon) + if (item.role) this.setRole(pos, item.role) // Make menu accessable to items. item.overrideReadOnlyProperty('menu', this) @@ -127,9 +125,9 @@ Menu.prototype.insert = function (pos, item) { // Force menuWillShow to be called Menu.prototype._callMenuWillShow = function () { - if (this.delegate != null) this.delegate.menuWillShow() + if (this.delegate) this.delegate.menuWillShow() this.items.forEach(item => { - if (item.submenu != null) item.submenu._callMenuWillShow() + if (item.submenu) item.submenu._callMenuWillShow() }) } @@ -142,13 +140,13 @@ Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder // set application menu with a preexisting menu Menu.setApplicationMenu = function (menu) { - if (!(menu === null || menu.constructor === Menu)) { + if (!(menu || menu.constructor === Menu)) { throw new TypeError('Invalid menu') } applicationMenu = menu if (process.platform === 'darwin') { - if (menu === null) return + if (!menu) return menu._callMenuWillShow() bindings.setApplicationMenu(menu) } else { @@ -205,7 +203,7 @@ function generateGroupId (items, pos) { // Returns the index of item according to |id|. function indexOfItemById (items, id) { - const foundItem = items.find(item => item.id === id) || null + const foundItem = items.find(item => item.id === id) || -1 return items.indexOf(foundItem) } @@ -218,7 +216,7 @@ function indexToInsertByPosition (items, position) { // warn if query doesn't exist if (idx === -1 && query !== 'endof') { - console.warn("Item with id '" + id + "' is not found") + console.warn(`Item with id ${id} is not found`) return items.length } From 7593bec6876cb3427d0e669f4198ce5f850b554a Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 19:36:06 -0400 Subject: [PATCH 071/185] update reviewed items --- lib/browser/desktop-capturer.js | 11 +++-------- lib/renderer/api/desktop-capturer.js | 6 +++--- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/lib/browser/desktop-capturer.js b/lib/browser/desktop-capturer.js index 74acb828544..48a7a2ad691 100644 --- a/lib/browser/desktop-capturer.js +++ b/lib/browser/desktop-capturer.js @@ -30,7 +30,6 @@ ipcMain.on(electronSources, (event, captureWindow, captureScreen, thumbnailSize, // reference from requestsQueue to make the module not send the result to it. event.sender.once('destroyed', () => { request.webContents = null - return }) }) @@ -48,19 +47,15 @@ desktopCapturer.emit = (event, name, sources) => { } }) - if (handledWebContents != null) { + if (handledWebContents) { handledWebContents.send(capturerResult(handledRequest.id), result) } - // Check the queue to see whether there is other same request. If has, handle - // it for reducing redunplicated `desktopCaptuer.startHandling` calls. - + // Check the queue to see whether there is another identical request & handle requestsQueue.forEach(request => { const webContents = request.webContents if (deepEqual(handledRequest.options, request.options)) { - if (webContents != null) { - webContents.send(capturerResult(request.id), result) - } + if (webContents) webContents.send(capturerResult(request.id), result) } else { unhandledRequestsQueue.push(request) } diff --git a/lib/renderer/api/desktop-capturer.js b/lib/renderer/api/desktop-capturer.js index ff47dfd8e98..b9320c893fc 100644 --- a/lib/renderer/api/desktop-capturer.js +++ b/lib/renderer/api/desktop-capturer.js @@ -8,10 +8,10 @@ const incrementId = () => { return currentId } -// |options.type| can not be empty and has to include 'window' or 'screen'. +// |options.types| can't be empty and must be an array function isValid (options) { - const types = (options != null) ? options.types : undefined - return (types != null) && Array.isArray(options.types) + const types = options ? options.types : undefined + return Array.isArray(types) } exports.getSources = function (options, callback) { From c38f66cc1bbcff7b013f973ad3f157618176e9f1 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Tue, 24 Oct 2017 17:00:42 -0700 Subject: [PATCH 072/185] =?UTF-8?q?:wrench:=20Ensure=20that=20-r=20isn?= =?UTF-8?q?=E2=80=99t=20considered=20interactive?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- default_app/main.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/default_app/main.js b/default_app/main.js index 3085d4c52bf..9cd225f60f4 100644 --- a/default_app/main.js +++ b/default_app/main.js @@ -27,8 +27,7 @@ for (let i = 0; i < argv.length; i++) { } else if (argv[i] === '--default' || argv[i] === '-d') { option.default = true break - } else if (argv[i] === '--interactive' || argv[i] === '-i' || - argv[i] === '-repl' || argv[i] === '-r') { + } else if (argv[i] === '--interactive' || argv[i] === '-i' || argv[i] === '-repl') { option.interactive = true } else if (argv[i] === '--test-type=webdriver') { option.webdriver = true From 0e6100ae1729b9ff6aaa7056e8c88db1db3afa2d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 20:27:26 -0400 Subject: [PATCH 073/185] upgrade menu spec to ES6 --- spec/api-menu-spec.js | 155 ++++++++++++++++++++---------------------- 1 file changed, 74 insertions(+), 81 deletions(-) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index 4389f9d50db..baba221a6a1 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -4,10 +4,10 @@ const {ipcRenderer, remote} = require('electron') const {BrowserWindow, Menu, MenuItem} = remote const {closeWindow} = require('./window-helpers') -describe('menu module', function () { +describe.only('menu module', function () { describe('Menu.buildFromTemplate', function () { it('should be able to attach extra fields', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: 'text', extra: 'field' @@ -17,7 +17,7 @@ describe('menu module', function () { }) it('does not modify the specified template', function () { - var template = ipcRenderer.sendSync('eval', "var template = [{label: 'text', submenu: [{label: 'sub'}]}];\nrequire('electron').Menu.buildFromTemplate(template);\ntemplate;") + const template = ipcRenderer.sendSync('eval', "var template = [{label: 'text', submenu: [{label: 'sub'}]}];\nrequire('electron').Menu.buildFromTemplate(template);\ntemplate;") assert.deepStrictEqual(template, [ { label: 'text', @@ -47,7 +47,7 @@ describe('menu module', function () { describe('Menu.buildFromTemplate should reorder based on item position specifiers', function () { it('should position before existing item', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: '2', id: '2' @@ -66,7 +66,7 @@ describe('menu module', function () { }) it('should position after existing item', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: '1', id: '1' @@ -85,7 +85,7 @@ describe('menu module', function () { }) it('should position at endof existing separator groups', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { type: 'separator', id: 'numbers' @@ -129,7 +129,7 @@ describe('menu module', function () { }) it('should create separator group if endof does not reference existing separator group', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: 'a', id: 'a', @@ -167,7 +167,7 @@ describe('menu module', function () { }) it('should continue inserting items at next index when no specifier is present', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: '4', id: '4' @@ -197,7 +197,7 @@ describe('menu module', function () { describe('Menu.getMenuItemById', function () { it('should return the item with the given id', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: 'View', submenu: [ @@ -220,7 +220,7 @@ describe('menu module', function () { describe('Menu.insert', function () { it('should store item in @items by its index', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: '1' }, { @@ -229,9 +229,8 @@ describe('menu module', function () { label: '3' } ]) - var item = new MenuItem({ - label: 'inserted' - }) + const item = new MenuItem({ label: 'inserted' }) + menu.insert(1, item) assert.equal(menu.items[0].label, '1') assert.equal(menu.items[1].label, 'inserted') @@ -242,23 +241,27 @@ describe('menu module', function () { describe('Menu.popup', function () { let w = null + let menu - afterEach(function () { + beforeEach(() => { + w = new BrowserWindow({show: false, width: 200, height: 200}) + menu = Menu.buildFromTemplate([ + { + label: '1' + }, { + label: '2' + }, { + label: '3' + } + ]) + }) + + afterEach(() => { return closeWindow(w).then(function () { w = null }) }) describe('when called with async: true', function () { it('returns immediately', function () { - w = new BrowserWindow({show: false, width: 200, height: 200}) - const menu = Menu.buildFromTemplate([ - { - label: '1' - }, { - label: '2' - }, { - label: '3' - } - ]) menu.popup(w, {x: 100, y: 100, async: true}) menu.closePopup(w) }) @@ -266,7 +269,7 @@ describe('menu module', function () { }) describe('MenuItem.click', function () { it('should be called with the item object passed', function (done) { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: 'text', click: function (item) { @@ -282,7 +285,7 @@ describe('menu module', function () { describe('MenuItem with checked property', function () { it('clicking an checkbox item should flip the checked property', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: 'text', type: 'checkbox' @@ -294,7 +297,7 @@ describe('menu module', function () { }) it('clicking an radio item should always make checked property true', function () { - var menu = Menu.buildFromTemplate([ + const menu = Menu.buildFromTemplate([ { label: 'text', type: 'radio' @@ -307,99 +310,91 @@ describe('menu module', function () { }) it('at least have one item checked in each group', function () { - var i, j, k, menu, template - template = [] - for (i = j = 0; j <= 10; i = ++j) { + const template = [] + for (let i = 0; i <= 10; i++) { template.push({ - label: '' + i, + label: `${i}`, type: 'radio' }) } - template.push({ - type: 'separator' - }) - for (i = k = 12; k <= 20; i = ++k) { + template.push({type: 'separator'}) + for (let i = 12; i <= 20; i++) { template.push({ - label: '' + i, + label: `${i}`, type: 'radio' }) } - menu = Menu.buildFromTemplate(template) + const menu = Menu.buildFromTemplate(template) menu.delegate.menuWillShow() assert.equal(menu.items[0].checked, true) assert.equal(menu.items[12].checked, true) }) it('should assign groupId automatically', function () { - var groupId, i, j, k, l, m, menu, template - template = [] - for (i = j = 0; j <= 10; i = ++j) { + const template = [] + for (let i = 0; i <= 10; i++) { template.push({ - label: '' + i, + label: `${i}`, type: 'radio' }) } - template.push({ - type: 'separator' - }) - for (i = k = 12; k <= 20; i = ++k) { + template.push({type: 'separator'}) + for (let i = 12; i <= 20; i++) { template.push({ - label: '' + i, + label: `${i}`, type: 'radio' }) } - menu = Menu.buildFromTemplate(template) - groupId = menu.items[0].groupId - for (i = l = 0; l <= 10; i = ++l) { + const menu = Menu.buildFromTemplate(template) + const groupId = menu.items[0].groupId + for (let i = 0; i <= 10; i++) { assert.equal(menu.items[i].groupId, groupId) } - for (i = m = 12; m <= 20; i = ++m) { + for (let i = 12; i <= 20; i++) { assert.equal(menu.items[i].groupId, groupId + 1) } }) it("setting 'checked' should flip other items' 'checked' property", function () { - var i, j, k, l, m, menu, n, o, p, q, template - template = [] - for (i = j = 0; j <= 10; i = ++j) { + const template = [] + for (let i = 0; i <= 10; i++) { template.push({ - label: '' + i, + label: `${i}`, type: 'radio' }) } - template.push({ - type: 'separator' - }) - for (i = k = 12; k <= 20; i = ++k) { + template.push({type: 'separator'}) + for (let i = 12; i <= 20; i++) { template.push({ - label: '' + i, + label: `${i}`, type: 'radio' }) } - menu = Menu.buildFromTemplate(template) - for (i = l = 0; l <= 10; i = ++l) { + + const menu = Menu.buildFromTemplate(template) + for (let i = 0; i <= 10; i++) { assert.equal(menu.items[i].checked, false) } menu.items[0].checked = true assert.equal(menu.items[0].checked, true) - for (i = m = 1; m <= 10; i = ++m) { + for (let i = 1; i <= 10; i++) { assert.equal(menu.items[i].checked, false) } menu.items[10].checked = true assert.equal(menu.items[10].checked, true) - for (i = n = 0; n <= 9; i = ++n) { + for (let i = 0; i <= 9; i++) { assert.equal(menu.items[i].checked, false) } - for (i = o = 12; o <= 20; i = ++o) { + for (let i = 12; i <= 20; i++) { assert.equal(menu.items[i].checked, false) } menu.items[12].checked = true assert.equal(menu.items[10].checked, true) - for (i = p = 0; p <= 9; i = ++p) { + for (let i = 0; i <= 9; i++) { assert.equal(menu.items[i].checked, false) } assert.equal(menu.items[12].checked, true) - for (i = q = 13; q <= 20; i = ++q) { + for (let i = 13; i <= 20; i++) { assert.equal(menu.items[i].checked, false) } }) @@ -407,20 +402,18 @@ describe('menu module', function () { describe('MenuItem command id', function () { it('cannot be overwritten', function () { - var item = new MenuItem({ - label: 'item' - }) + const item = new MenuItem({label: 'item'}) - var commandId = item.commandId - assert(commandId != null) - item.commandId = '' + commandId + '-modified' + const commandId = item.commandId + assert(commandId) + item.commandId = `${commandId}-modified` assert.equal(item.commandId, commandId) }) }) describe('MenuItem with invalid type', function () { it('throws an exception', function () { - assert.throws(function () { + assert.throws(() => { Menu.buildFromTemplate([ { label: 'text', @@ -433,7 +426,7 @@ describe('menu module', function () { describe('MenuItem with submenu type and missing submenu', function () { it('throws an exception', function () { - assert.throws(function () { + assert.throws(() => { Menu.buildFromTemplate([ { label: 'text', @@ -446,7 +439,7 @@ describe('menu module', function () { describe('MenuItem role', function () { it('includes a default label and accelerator', function () { - var item = new MenuItem({role: 'close'}) + let item = new MenuItem({role: 'close'}) assert.equal(item.label, process.platform === 'darwin' ? 'Close Window' : 'Close') assert.equal(item.accelerator, undefined) assert.equal(item.getDefaultRoleAccelerator(), 'CommandOrControl+W') @@ -480,7 +473,7 @@ describe('menu module', function () { describe('MenuItem editMenu', function () { it('includes a default submenu layout when submenu is empty', function () { - var item = new MenuItem({role: 'editMenu'}) + const item = new MenuItem({role: 'editMenu'}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'undo') assert.equal(item.submenu.items[1].role, 'redo') @@ -503,7 +496,7 @@ describe('menu module', function () { }) it('overrides default layout when submenu is specified', function () { - var item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) + const item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'close') }) @@ -511,7 +504,7 @@ describe('menu module', function () { describe('MenuItem windowMenu', function () { it('includes a default submenu layout when submenu is empty', function () { - var item = new MenuItem({role: 'windowMenu'}) + const item = new MenuItem({role: 'windowMenu'}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'minimize') assert.equal(item.submenu.items[1].role, 'close') @@ -523,7 +516,7 @@ describe('menu module', function () { }) it('overrides default layout when submenu is specified', function () { - var item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) + const item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'copy') }) @@ -531,13 +524,13 @@ describe('menu module', function () { describe('MenuItem with custom properties in constructor', function () { it('preserves the custom properties', function () { - var template = [{ + const template = [{ label: 'menu 1', customProp: 'foo', submenu: [] }] - var menu = Menu.buildFromTemplate(template) + const menu = Menu.buildFromTemplate(template) menu.items[0].submenu.append(new MenuItem({ label: 'item 1', customProp: 'bar', From d54148de4e89c581afc5ad9fe61914fc004fad4f Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 20:31:02 -0400 Subject: [PATCH 074/185] remove from spec --- spec/api-menu-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index baba221a6a1..fa389fe5f7d 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -4,7 +4,7 @@ const {ipcRenderer, remote} = require('electron') const {BrowserWindow, Menu, MenuItem} = remote const {closeWindow} = require('./window-helpers') -describe.only('menu module', function () { +describe('menu module', function () { describe('Menu.buildFromTemplate', function () { it('should be able to attach extra fields', function () { const menu = Menu.buildFromTemplate([ From 424f9aeae6323d32fe55e3c4a3909e0565a4085c Mon Sep 17 00:00:00 2001 From: Matt Lyons Date: Tue, 24 Oct 2017 19:36:23 -0700 Subject: [PATCH 075/185] :penguin: Don't wait for xdg-open to exit Waiting for xdg-open to return freezes Electron application. Some file managers (ex: Nemo) don't return until some time after they are closed, this freezes the Electron application until the process returns. The same is true about any application that can potentially be opened with OpenItem --- atom/common/platform_util_linux.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/common/platform_util_linux.cc b/atom/common/platform_util_linux.cc index 18e37558514..76cdfaf45a8 100644 --- a/atom/common/platform_util_linux.cc +++ b/atom/common/platform_util_linux.cc @@ -75,11 +75,11 @@ bool ShowItemInFolder(const base::FilePath& full_path) { if (!base::DirectoryExists(dir)) return false; - return XDGOpen(dir.value(), true); + return XDGOpen(dir.value(), false); } bool OpenItem(const base::FilePath& full_path) { - return XDGOpen(full_path.value(), true); + return XDGOpen(full_path.value(), false); } bool OpenExternal(const GURL& url, bool activate) { From f7bc5481f386db241ba9f3dfac5bb0c63e7a183e Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 22:40:31 -0400 Subject: [PATCH 076/185] add a few more tests to api_menu_spec --- spec/api-menu-spec.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index fa389fe5f7d..ad2ddafeb73 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -4,7 +4,7 @@ const {ipcRenderer, remote} = require('electron') const {BrowserWindow, Menu, MenuItem} = remote const {closeWindow} = require('./window-helpers') -describe('menu module', function () { +describe.only('menu module', function () { describe('Menu.buildFromTemplate', function () { it('should be able to attach extra fields', function () { const menu = Menu.buildFromTemplate([ @@ -229,6 +229,7 @@ describe('menu module', function () { label: '3' } ]) + const item = new MenuItem({ label: 'inserted' }) menu.insert(1, item) @@ -239,6 +240,27 @@ describe('menu module', function () { }) }) + describe('Menu.append', function () { + it('should add the item to the end of the menu', function () { + const menu = Menu.buildFromTemplate([ + { + label: '1' + }, { + label: '2' + }, { + label: '3' + } + ]) + const item = new MenuItem({ label: 'inserted' }) + + menu.append(item) + assert.equal(menu.items[0].label, '1') + assert.equal(menu.items[1].label, '2') + assert.equal(menu.items[2].label, '3') + assert.equal(menu.items[3].label, 'inserted') + }) + }) + describe('Menu.popup', function () { let w = null let menu @@ -267,6 +289,19 @@ describe('menu module', function () { }) }) }) + + describe('Menu.setApplicationMenu', function () { + const menu = Menu.buildFromTemplate([ + { + label: '1' + }, { + label: '2' + } + ]) + Menu.setApplicationMenu(menu) + assert.notEqual(Menu.getApplicationMenu(), null) + }) + describe('MenuItem.click', function () { it('should be called with the item object passed', function (done) { const menu = Menu.buildFromTemplate([ From 135454342d9a5e636386f02195c77b5bff27a09a Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 24 Oct 2017 22:41:28 -0400 Subject: [PATCH 077/185] remove .only from spec --- spec/api-menu-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index ad2ddafeb73..2c422b340dc 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -4,7 +4,7 @@ const {ipcRenderer, remote} = require('electron') const {BrowserWindow, Menu, MenuItem} = remote const {closeWindow} = require('./window-helpers') -describe.only('menu module', function () { +describe('menu module', function () { describe('Menu.buildFromTemplate', function () { it('should be able to attach extra fields', function () { const menu = Menu.buildFromTemplate([ From f129622446a6cd819e8c1c73c9762825847b382d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 09:51:21 -0400 Subject: [PATCH 078/185] clean up remote --- lib/renderer/api/remote.js | 198 ++++++++++++++++++------------------- 1 file changed, 94 insertions(+), 104 deletions(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index fdc95cdb5cd..d48a1fc22d6 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -9,14 +9,30 @@ const {ipcRenderer, isPromise, CallbacksRegistry} = require('electron') const resolvePromise = Promise.resolve.bind(Promise) const callbacksRegistry = new CallbacksRegistry() - const remoteObjectCache = v8Util.createIDWeakMap() +// lookup for ipc renderer send calls +const ipcs = { + 'b_mem_con': 'ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', + 'b_mem_call': 'ELECTRON_BROWSER_MEMBER_CALL', + 'b_mem_get': 'ELECTRON_BROWSER_MEMBER_GET', + 'b_mem_set': 'ELECTRON_BROWSER_MEMBER_SET', + 'b_con': 'ELECTRON_BROWSER_CONSTRUCTOR', + 'b_func_call': 'ELECTRON_BROWSER_FUNCTION_CALL', + 'rend_call': 'ELECTRON_RENDERER_CALLBACK', + 'rend_rel_call': 'ELECTRON_RENDERER_RELEASE_CALLBACK', + 'b_con_rel': 'ELECTRON_BROWSER_CONTEXT_RELEASE' + 'b_req': 'ELECTRON_BROWSER_REQUIRE', + 'b_get_built': 'ELECTRON_BROWSER_GET_BUILTIN', + 'b_curr_win': 'ELECTRON_BROWSER_CURRENT_WINDOW', + 'b_curr_web_con': 'ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', + 'b_glob': 'ELECTRON_BROWSER_GLOBAL', + 'b_guest_web_con': 'ELECTRON_BROWSER_GUEST_WEB_CONTENTS' +} + // Convert the arguments object into an array of meta data. -const wrapArgs = function (args, visited) { - if (visited == null) { - visited = new Set() - } +function wrapArgs (args, visited) { + if (visited) visited = new Set() const valueToMeta = function (value) { // Check for circular reference. @@ -45,7 +61,7 @@ const wrapArgs = function (args, visited) { type: 'date', value: value.getTime() } - } else if ((value != null) && typeof value === 'object') { + } else if (value && typeof value === 'object') { if (isPromise(value)) { return { type: 'promise', @@ -62,7 +78,7 @@ const wrapArgs = function (args, visited) { let meta = { type: 'object', - name: value.constructor != null ? value.constructor.name : '', + name: (value.constructor) ? value.constructor.name : '', members: [] } visited.add(value) @@ -99,7 +115,7 @@ const wrapArgs = function (args, visited) { // Populate object's members from descriptors. // The |ref| will be kept referenced by |members|. // This matches |getObjectMemebers| in rpc-server. -const setObjectMembers = function (ref, object, metaId, members) { +function setObjectMembers (ref, object, metaId, members) { if (!Array.isArray(members)) return for (let member of members) { @@ -110,11 +126,11 @@ const setObjectMembers = function (ref, object, metaId, members) { const remoteMemberFunction = function (...args) { if (this && this.constructor === remoteMemberFunction) { // Constructor call. - let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args)) + const ret = ipcRenderer.sendSync(ipcs['b_mem_con'], metaId, member.name, wrapArgs(args)) return metaToValue(ret) } else { // Call member function. - let ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args)) + const ret = ipcRenderer.sendSync(ipcs['b_mem_call'], metaId, member.name, wrapArgs(args)) return metaToValue(ret) } } @@ -133,19 +149,17 @@ const setObjectMembers = function (ref, object, metaId, members) { descriptor.configurable = true } else if (member.type === 'get') { descriptor.get = function () { - return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_GET', metaId, member.name)) + return metaToValue(ipcRenderer.sendSync(ipcs['b_mem_get'], metaId, member.name)) } // Only set setter when it is writable. if (member.writable) { descriptor.set = function (value) { const args = wrapArgs([value]) - const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, args) + const meta = ipcRenderer.sendSync(ipcs['b_mem_set'], metaId, member.name, args) // Meta will be non-null when a setter error occurred so parse it // to a value so it gets re-thrown. - if (meta != null) { - metaToValue(meta) - } + if (meta) metaToValue(meta) return value } } @@ -157,8 +171,8 @@ const setObjectMembers = function (ref, object, metaId, members) { // Populate object's prototype from descriptor. // This matches |getObjectPrototype| in rpc-server. -const setObjectPrototype = function (ref, object, metaId, descriptor) { - if (descriptor === null) return +function setObjectPrototype (ref, object, metaId, descriptor) { + if (!descriptor) return let proto = {} setObjectMembers(ref, proto, metaId, descriptor.members) setObjectPrototype(ref, proto, metaId, descriptor.proto) @@ -166,14 +180,14 @@ const setObjectPrototype = function (ref, object, metaId, descriptor) { } // Wrap function in Proxy for accessing remote properties -const proxyFunctionProperties = function (remoteMemberFunction, metaId, name) { +function proxyFunctionProperties (remoteMemberFunction, metaId, name) { let loaded = false // Lazily load function properties const loadRemoteProperties = () => { if (loaded) return loaded = true - const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_GET', metaId, name) + const meta = ipcRenderer.sendSync(ipcs['b_mem_get'], metaId, name) setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members) } @@ -201,7 +215,7 @@ const proxyFunctionProperties = function (remoteMemberFunction, metaId, name) { }, getOwnPropertyDescriptor: (target, property) => { let descriptor = Object.getOwnPropertyDescriptor(target, property) - if (descriptor != null) return descriptor + if (descriptor) return descriptor loadRemoteProperties() return Object.getOwnPropertyDescriptor(target, property) } @@ -209,128 +223,106 @@ const proxyFunctionProperties = function (remoteMemberFunction, metaId, name) { } // Convert meta data from browser into real value. -const metaToValue = function (meta) { - var el, i, len, ref1, results, ret - switch (meta.type) { - case 'value': - return meta.value - case 'array': - ref1 = meta.members - results = [] - for (i = 0, len = ref1.length; i < len; i++) { - el = ref1[i] - results.push(metaToValue(el)) - } - return results - case 'buffer': - return Buffer.from(meta.value) - case 'promise': - return resolvePromise({then: metaToValue(meta.then)}) - case 'error': - return metaToPlainObject(meta) - case 'date': - return new Date(meta.value) - case 'exception': - throw new Error(meta.message + '\n' + meta.stack) - default: - if (remoteObjectCache.has(meta.id)) return remoteObjectCache.get(meta.id) +function metaToValue (meta) { + const types = { + 'value': () => meta.value, + 'array': () => { + const members = meta.members + return members.map((member) => metaToValue(member)) + }, + 'buffer': () => Buffer.from(meta.value), + 'promise': () => resolvePromise({then: metaToValue(meta.then)}) + 'error': () => metaToPlainObject(meta), + 'date': () => new Date(meta.value), + 'exception': () => new Error(`${meta.message}\n${meta.stack}`) + } - if (meta.type === 'function') { - // A shadow class to represent the remote function object. - let remoteFunction = function (...args) { - if (this && this.constructor === remoteFunction) { - // Constructor call. - let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(args)) - // Returning object in constructor will replace constructed object - // with the returned object. - // http://stackoverflow.com/questions/1978049/what-values-can-a-constructor-return-to-avoid-returning-this - return metaToValue(obj) - } else { - // Function call. - let obj = ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(args)) - return metaToValue(obj) - } + if (meta.type in types) { + types[meta.type]() + } else { + let ret + if (remoteObjectCache.has(meta.id)) return remoteObjectCache.get(meta.id) + + // A shadow class to represent the remote function object. + if (meta.type === 'function') { + let remoteFunction = function (...args) { + if (this && this.constructor === remoteFunction) { + return metaToValue(ipcRenderer.sendSync( + ipcs['b_con'], meta.id, wrapArgs(args) + ) + } else { + return metaToValue(ipcRenderer.sendSync( + ipcs['b_func_call'], meta.id, wrapArgs(args) + ) } - ret = remoteFunction - } else { - ret = {} } + ret = remoteFunction + } else { + ret = {} + } - // Populate delegate members. - setObjectMembers(ret, ret, meta.id, meta.members) - // Populate delegate prototype. - setObjectPrototype(ret, ret, meta.id, meta.proto) + setObjectMembers(ret, ret, meta.id, meta.members) + setObjectPrototype(ret, ret, meta.id, meta.proto) - // Set constructor.name to object's name. - Object.defineProperty(ret.constructor, 'name', { value: meta.name }) + // Set constructor.name to object's name. + Object.defineProperty(ret.constructor, 'name', { value: meta.name }) - // Track delegate object's life time, and tell the browser to clean up - // when the object is GCed. - v8Util.setRemoteObjectFreer(ret, meta.id) - - // Remember object's id. - v8Util.setHiddenValue(ret, 'atomId', meta.id) - remoteObjectCache.set(meta.id, ret) - return ret + // Track delegate obj's lifetime & tell browser to clean up when object is GCed. + v8Util.setRemoteObjectFreer(ret, meta.id) + v8Util.setHiddenValue(ret, 'atomId', meta.id) + remoteObjectCache.set(meta.id, ret) + return ret } } // Construct a plain object from the meta. -const metaToPlainObject = function (meta) { - var i, len, obj, ref1 - obj = (function () { - switch (meta.type) { - case 'error': - return new Error() - default: - return {} - } - })() - ref1 = meta.members - for (i = 0, len = ref1.length; i < len; i++) { - let {name, value} = ref1[i] - obj[name] = value - } +function metaToPlainObject (meta) { + if (meta.type === 'error') return new Error() + + const obj = {} + const members = meta.members + + members.forEach((key, val) => { obj[key] = val }) return obj } // Browser calls a callback in renderer. -ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', function (event, id, args) { +ipcRenderer.on(ipcs['rend_call'], (event, id, args) => { callbacksRegistry.apply(id, metaToValue(args)) }) // A callback in browser is released. -ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', function (event, id) { +ipcRenderer.on(ipcs['rend_rel_call'], (event, id) => { callbacksRegistry.remove(id) }) process.on('exit', () => { - ipcRenderer.sendSync('ELECTRON_BROWSER_CONTEXT_RELEASE') + ipcRenderer.sendSync(ipcs['b_con_rel']) }) // Get remote module. exports.require = function (module) { - return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_REQUIRE', module)) + return metaToValue(ipcRenderer.sendSync(ipcs['b_req'], module)) } // Alias to remote.require('electron').xxx. exports.getBuiltin = function (module) { - return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GET_BUILTIN', module)) + return metaToValue(ipcRenderer.sendSync(ipcs['b_get_built'], module)) } // Get current BrowserWindow. exports.getCurrentWindow = function () { - return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WINDOW')) + return metaToValue(ipcRenderer.sendSync(ipcs['b_curr_win'])) } // Get current WebContents object. exports.getCurrentWebContents = function () { - return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS')) + return metaToValue(ipcRenderer.sendSync(ipcs['b_curr_web_cont'])) } // Get a global object in browser. exports.getGlobal = function (name) { - return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GLOBAL', name)) + return metaToValue(ipcRenderer.sendSync(ipcs['b_glob'], name)) } // Get the process object in browser. @@ -340,16 +332,14 @@ exports.__defineGetter__('process', function () { // Create a funtion that will return the specifed value when called in browser. exports.createFunctionWithReturnValue = function (returnValue) { - const func = function () { - return returnValue - } + const func = () => returnValue v8Util.setHiddenValue(func, 'returnValue', true) return func } // Get the guest WebContents from guestInstanceId. exports.getGuestWebContents = function (guestInstanceId) { - const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId) + const meta = ipcRenderer.sendSync(ipcs['b_guest_web_con'], guestInstanceId) return metaToValue(meta) } From c0f2a7b44a690962adda77fe9e182f7416ad8c83 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 09:56:02 -0400 Subject: [PATCH 079/185] fix standard issues --- lib/renderer/api/remote.js | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index d48a1fc22d6..ecbc7f7f4b8 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -21,7 +21,7 @@ const ipcs = { 'b_func_call': 'ELECTRON_BROWSER_FUNCTION_CALL', 'rend_call': 'ELECTRON_RENDERER_CALLBACK', 'rend_rel_call': 'ELECTRON_RENDERER_RELEASE_CALLBACK', - 'b_con_rel': 'ELECTRON_BROWSER_CONTEXT_RELEASE' + 'b_con_rel': 'ELECTRON_BROWSER_CONTEXT_RELEASE', 'b_req': 'ELECTRON_BROWSER_REQUIRE', 'b_get_built': 'ELECTRON_BROWSER_GET_BUILTIN', 'b_curr_win': 'ELECTRON_BROWSER_CURRENT_WINDOW', @@ -231,7 +231,7 @@ function metaToValue (meta) { return members.map((member) => metaToValue(member)) }, 'buffer': () => Buffer.from(meta.value), - 'promise': () => resolvePromise({then: metaToValue(meta.then)}) + 'promise': () => resolvePromise({then: metaToValue(meta.then)}), 'error': () => metaToPlainObject(meta), 'date': () => new Date(meta.value), 'exception': () => new Error(`${meta.message}\n${meta.stack}`) @@ -247,13 +247,9 @@ function metaToValue (meta) { if (meta.type === 'function') { let remoteFunction = function (...args) { if (this && this.constructor === remoteFunction) { - return metaToValue(ipcRenderer.sendSync( - ipcs['b_con'], meta.id, wrapArgs(args) - ) + return metaToValue(ipcRenderer.sendSync(ipcs['b_con'], meta.id, wrapArgs(args))) } else { - return metaToValue(ipcRenderer.sendSync( - ipcs['b_func_call'], meta.id, wrapArgs(args) - ) + return metaToValue(ipcRenderer.sendSync(ipcs['b_func_call'], meta.id, wrapArgs(args))) } } ret = remoteFunction From ffd43c18866eb33cf3d70f03a3ffd6d27a29e0e7 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 10:17:41 -0400 Subject: [PATCH 080/185] remove quotes and const replaces --- lib/browser/api/menu.js | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 9864e189b26..3e56bea04b6 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -35,8 +35,8 @@ Menu.prototype._init = function () { }, menuWillShow: () => { // Ensure radio groups have at least one menu item seleted - for (let id in this.groupsMap) { - let found = this.groupsMap[id].find(item => item.checked) || null + for (const id in this.groupsMap) { + const found = this.groupsMap[id].find(item => item.checked) || null if (!found) v8Util.setHiddenValue(this.groupsMap[id][0], 'checked', true) } } @@ -222,11 +222,11 @@ function indexToInsertByPosition (items, position) { // compute new index based on query const queries = { - 'after': (index) => { + after: (index) => { index += 1 return index }, - 'endof': (index) => { + endof: (index) => { if (index === -1) { items.push({id, type: 'separator'}) index = items.length - 1 @@ -245,11 +245,11 @@ function indexToInsertByPosition (items, position) { // insert a new MenuItem depending on its type function insertItemByType (item, pos) { const types = { - 'normal': () => this.insertItem(pos, item.commandId, item.label), - 'checkbox': () => this.insertCheckItem(pos, item.commandId, item.label), - 'separator': () => this.insertSeparator(pos), - 'submenu': () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu), - 'radio': () => { + normal: () => this.insertItem(pos, item.commandId, item.label), + checkbox: () => this.insertCheckItem(pos, item.commandId, item.label), + separator: () => this.insertSeparator(pos), + submenu: () => this.insertSubMenu(pos, item.commandId, item.label, item.submenu), + radio: () => { // Grouping radio menu items item.overrideReadOnlyProperty('groupId', generateGroupId(this.items, pos)) if (this.groupsMap[item.groupId] == null) { From 1e8bdc15e20ad9ad179ec2efff9c4927234d73dc Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 10:40:38 -0400 Subject: [PATCH 081/185] use _wgetenv to get windows env variables --- brightray/browser/browser_main_parts.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index e5406e519a6..6b7c47f5c7e 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -168,7 +168,9 @@ BrowserMainParts::~BrowserMainParts() { void OverrideAppLogsPath() { #if defined(OS_WIN) std::wstring app_name = base::UTF8ToWide(GetApplicationName()); - std::wstring log_path = L"%HOMEDRIVE%%HOMEPATH%\\AppData\\Roaming\\"; + std::wstring drive = _wgetenv(L"HOMEDRIVE")); + std::wstring path = _wgetenv(L"HOMEPATH")); + std::wstring log_path = drive + "\\" + path + L"\\AppData\\Roaming\\"; std::wstring app_log_path = log_path + app_name + L"\\logs"; #else std::string app_name = GetApplicationName(); From 3c1c5a409919234a6402299132885a214a518991 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 11:46:51 -0400 Subject: [PATCH 082/185] combine homepath and homedrive into single line --- brightray/browser/browser_main_parts.cc | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index 6b7c47f5c7e..c5ee689c100 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -168,9 +168,8 @@ BrowserMainParts::~BrowserMainParts() { void OverrideAppLogsPath() { #if defined(OS_WIN) std::wstring app_name = base::UTF8ToWide(GetApplicationName()); - std::wstring drive = _wgetenv(L"HOMEDRIVE")); - std::wstring path = _wgetenv(L"HOMEPATH")); - std::wstring log_path = drive + "\\" + path + L"\\AppData\\Roaming\\"; + std::wstring home = _wgetenv(L"HOMEDRIVE") + "\\" +_wgetenv(L"HOMEPATH"); + std::wstring log_path = home + L"\\AppData\\Roaming\\"; std::wstring app_log_path = log_path + app_name + L"\\logs"; #else std::string app_name = GetApplicationName(); From 06811cc557e1621fb24addfb593c975f54a33a4f Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 12:02:50 -0400 Subject: [PATCH 083/185] appropriately cast pointers to strings --- brightray/browser/browser_main_parts.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index c5ee689c100..fe9cc7073b4 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -168,8 +168,9 @@ BrowserMainParts::~BrowserMainParts() { void OverrideAppLogsPath() { #if defined(OS_WIN) std::wstring app_name = base::UTF8ToWide(GetApplicationName()); - std::wstring home = _wgetenv(L"HOMEDRIVE") + "\\" +_wgetenv(L"HOMEPATH"); - std::wstring log_path = home + L"\\AppData\\Roaming\\"; + std::wstring home = std::wstring(_wgetenv(L"HOMEDRIVE")); + std::wstring drive = std::wstring(_wgetenv(L"HOMEPATH")); + std::wstring log_path = home + L"\\" + drive + L"\\AppData\\Roaming\\"; std::wstring app_log_path = log_path + app_name + L"\\logs"; #else std::string app_name = GetApplicationName(); From bccaf562000aa2c2cf04bf73d498d00bb6c0327f Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 12:23:41 -0400 Subject: [PATCH 084/185] remove common sense comments --- lib/browser/api/menu.js | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/lib/browser/api/menu.js b/lib/browser/api/menu.js index 3e56bea04b6..caa65afbbf0 100644 --- a/lib/browser/api/menu.js +++ b/lib/browser/api/menu.js @@ -43,7 +43,6 @@ Menu.prototype._init = function () { } } -// create and show a popup Menu.prototype.popup = function (window, x, y, positioningItem) { let asyncPopup let [newX, newY, newPosition, newWindow] = [x, y, positioningItem, window] @@ -75,7 +74,6 @@ Menu.prototype.popup = function (window, x, y, positioningItem) { this.popupAt(newWindow, newX, newY, newPosition, asyncPopup) } -// close an existing popup Menu.prototype.closePopup = function (window) { if (!window || window.constructor !== BrowserWindow) { window = BrowserWindow.getFocusedWindow() @@ -83,7 +81,6 @@ Menu.prototype.closePopup = function (window) { if (window) this.closePopupAt(window.id) } -// return a MenuItem with the specified id Menu.prototype.getMenuItemById = function (id) { const items = this.items @@ -96,12 +93,10 @@ Menu.prototype.getMenuItemById = function (id) { return found } -// append a new MenuItem to an existing Menu Menu.prototype.append = function (item) { return this.insert(this.getItemCount(), item) } -// insert a new menu item at a specified location Menu.prototype.insert = function (pos, item) { if ((item ? item.constructor : void 0) !== MenuItem) { throw new TypeError('Invalid item') @@ -123,7 +118,6 @@ Menu.prototype.insert = function (pos, item) { this.commandsMap[item.commandId] = item } -// Force menuWillShow to be called Menu.prototype._callMenuWillShow = function () { if (this.delegate) this.delegate.menuWillShow() this.items.forEach(item => { @@ -133,7 +127,6 @@ Menu.prototype._callMenuWillShow = function () { /* Static Methods */ -// return application menu Menu.getApplicationMenu = () => applicationMenu Menu.sendActionToFirstResponder = bindings.sendActionToFirstResponder @@ -155,7 +148,6 @@ Menu.setApplicationMenu = function (menu) { } } -// build a menu by passing in a template Menu.buildFromTemplate = function (template) { if (!(template instanceof Array)) { throw new TypeError('Invalid template for Menu') @@ -201,13 +193,11 @@ function generateGroupId (items, pos) { return groupIdIndex } -// Returns the index of item according to |id|. function indexOfItemById (items, id) { const foundItem = items.find(item => item.id === id) || -1 return items.indexOf(foundItem) } -// Returns the index of where to insert the item according to |position| function indexToInsertByPosition (items, position) { if (!position) return items.length @@ -242,7 +232,6 @@ function indexToInsertByPosition (items, position) { return (query in queries) ? queries[query](idx) : idx } -// insert a new MenuItem depending on its type function insertItemByType (item, pos) { const types = { normal: () => this.insertItem(pos, item.commandId, item.label), From d4880b135a0148dd70dcf0e9d33d146e6305bdae Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 15:36:16 -0400 Subject: [PATCH 085/185] revert ipc lookup table --- lib/renderer/api/remote.js | 51 ++++++++++++-------------------------- 1 file changed, 16 insertions(+), 35 deletions(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index ecbc7f7f4b8..f115215f311 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -11,25 +11,6 @@ const resolvePromise = Promise.resolve.bind(Promise) const callbacksRegistry = new CallbacksRegistry() const remoteObjectCache = v8Util.createIDWeakMap() -// lookup for ipc renderer send calls -const ipcs = { - 'b_mem_con': 'ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', - 'b_mem_call': 'ELECTRON_BROWSER_MEMBER_CALL', - 'b_mem_get': 'ELECTRON_BROWSER_MEMBER_GET', - 'b_mem_set': 'ELECTRON_BROWSER_MEMBER_SET', - 'b_con': 'ELECTRON_BROWSER_CONSTRUCTOR', - 'b_func_call': 'ELECTRON_BROWSER_FUNCTION_CALL', - 'rend_call': 'ELECTRON_RENDERER_CALLBACK', - 'rend_rel_call': 'ELECTRON_RENDERER_RELEASE_CALLBACK', - 'b_con_rel': 'ELECTRON_BROWSER_CONTEXT_RELEASE', - 'b_req': 'ELECTRON_BROWSER_REQUIRE', - 'b_get_built': 'ELECTRON_BROWSER_GET_BUILTIN', - 'b_curr_win': 'ELECTRON_BROWSER_CURRENT_WINDOW', - 'b_curr_web_con': 'ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', - 'b_glob': 'ELECTRON_BROWSER_GLOBAL', - 'b_guest_web_con': 'ELECTRON_BROWSER_GUEST_WEB_CONTENTS' -} - // Convert the arguments object into an array of meta data. function wrapArgs (args, visited) { if (visited) visited = new Set() @@ -126,11 +107,11 @@ function setObjectMembers (ref, object, metaId, members) { const remoteMemberFunction = function (...args) { if (this && this.constructor === remoteMemberFunction) { // Constructor call. - const ret = ipcRenderer.sendSync(ipcs['b_mem_con'], metaId, member.name, wrapArgs(args)) + const ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', metaId, member.name, wrapArgs(args)) return metaToValue(ret) } else { // Call member function. - const ret = ipcRenderer.sendSync(ipcs['b_mem_call'], metaId, member.name, wrapArgs(args)) + const ret = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_CALL', metaId, member.name, wrapArgs(args)) return metaToValue(ret) } } @@ -149,14 +130,14 @@ function setObjectMembers (ref, object, metaId, members) { descriptor.configurable = true } else if (member.type === 'get') { descriptor.get = function () { - return metaToValue(ipcRenderer.sendSync(ipcs['b_mem_get'], metaId, member.name)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_GET', metaId, member.name)) } // Only set setter when it is writable. if (member.writable) { descriptor.set = function (value) { const args = wrapArgs([value]) - const meta = ipcRenderer.sendSync(ipcs['b_mem_set'], metaId, member.name, args) + const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, args) // Meta will be non-null when a setter error occurred so parse it // to a value so it gets re-thrown. if (meta) metaToValue(meta) @@ -187,7 +168,7 @@ function proxyFunctionProperties (remoteMemberFunction, metaId, name) { const loadRemoteProperties = () => { if (loaded) return loaded = true - const meta = ipcRenderer.sendSync(ipcs['b_mem_get'], metaId, name) + const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_GET', metaId, name) setObjectMembers(remoteMemberFunction, remoteMemberFunction, meta.id, meta.members) } @@ -247,9 +228,9 @@ function metaToValue (meta) { if (meta.type === 'function') { let remoteFunction = function (...args) { if (this && this.constructor === remoteFunction) { - return metaToValue(ipcRenderer.sendSync(ipcs['b_con'], meta.id, wrapArgs(args))) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CONSTRUCTOR', meta.id, wrapArgs(args))) } else { - return metaToValue(ipcRenderer.sendSync(ipcs['b_func_call'], meta.id, wrapArgs(args))) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_FUNCTION_CALL', meta.id, wrapArgs(args))) } } ret = remoteFunction @@ -283,42 +264,42 @@ function metaToPlainObject (meta) { } // Browser calls a callback in renderer. -ipcRenderer.on(ipcs['rend_call'], (event, id, args) => { +ipcRenderer.on('ELECTRON_RENDERER_CALLBACK', (event, id, args) => { callbacksRegistry.apply(id, metaToValue(args)) }) // A callback in browser is released. -ipcRenderer.on(ipcs['rend_rel_call'], (event, id) => { +ipcRenderer.on('ELECTRON_RENDERER_RELEASE_CALLBACK', (event, id) => { callbacksRegistry.remove(id) }) process.on('exit', () => { - ipcRenderer.sendSync(ipcs['b_con_rel']) + ipcRenderer.sendSync('ELECTRON_BROWSER_CONTEXT_RELEASE') }) // Get remote module. exports.require = function (module) { - return metaToValue(ipcRenderer.sendSync(ipcs['b_req'], module)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_REQUIRE', module)) } // Alias to remote.require('electron').xxx. exports.getBuiltin = function (module) { - return metaToValue(ipcRenderer.sendSync(ipcs['b_get_built'], module)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GET_BUILTIN', module)) } // Get current BrowserWindow. exports.getCurrentWindow = function () { - return metaToValue(ipcRenderer.sendSync(ipcs['b_curr_win'])) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WINDOW')) } // Get current WebContents object. exports.getCurrentWebContents = function () { - return metaToValue(ipcRenderer.sendSync(ipcs['b_curr_web_cont'])) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS')) } // Get a global object in browser. exports.getGlobal = function (name) { - return metaToValue(ipcRenderer.sendSync(ipcs['b_glob'], name)) + return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GLOBAL', name)) } // Get the process object in browser. @@ -335,7 +316,7 @@ exports.createFunctionWithReturnValue = function (returnValue) { // Get the guest WebContents from guestInstanceId. exports.getGuestWebContents = function (guestInstanceId) { - const meta = ipcRenderer.sendSync(ipcs['b_guest_web_con'], guestInstanceId) + const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId) return metaToValue(meta) } From c2d9e082cb144e506a7e6e9e85a15e714da1cd4e Mon Sep 17 00:00:00 2001 From: Paul Frazee Date: Wed, 25 Oct 2017 21:01:53 -0500 Subject: [PATCH 086/185] Fix crash in custom protocols caused by bad callback exec --- atom/browser/net/url_request_fetch_job.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/atom/browser/net/url_request_fetch_job.cc b/atom/browser/net/url_request_fetch_job.cc index ff426dd08c8..04d0ddd1e6a 100644 --- a/atom/browser/net/url_request_fetch_job.cc +++ b/atom/browser/net/url_request_fetch_job.cc @@ -258,7 +258,9 @@ void URLRequestFetchJob::OnURLFetchComplete(const net::URLFetcher* source) { HeadersCompleted(); return; } - ReadRawDataComplete(0); + if (request_->status().is_io_pending()) { + ReadRawDataComplete(0); + } } else { NotifyStartError(fetcher_->GetStatus()); } From 5f6f117bad369c59e9109b58af25ad0a678d06a8 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 25 Oct 2017 23:41:11 -0400 Subject: [PATCH 087/185] changes from review --- lib/renderer/api/remote.js | 37 +++++++++++++++---------------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/lib/renderer/api/remote.js b/lib/renderer/api/remote.js index f115215f311..e38c531c90a 100644 --- a/lib/renderer/api/remote.js +++ b/lib/renderer/api/remote.js @@ -12,10 +12,8 @@ const callbacksRegistry = new CallbacksRegistry() const remoteObjectCache = v8Util.createIDWeakMap() // Convert the arguments object into an array of meta data. -function wrapArgs (args, visited) { - if (visited) visited = new Set() - - const valueToMeta = function (value) { +function wrapArgs (args, visited = new Set()) { + const valueToMeta = (value) => { // Check for circular reference. if (visited.has(value)) { return { @@ -59,7 +57,7 @@ function wrapArgs (args, visited) { let meta = { type: 'object', - name: (value.constructor) ? value.constructor.name : '', + name: value.constructor ? value.constructor.name : '', members: [] } visited.add(value) @@ -140,7 +138,7 @@ function setObjectMembers (ref, object, metaId, members) { const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_MEMBER_SET', metaId, member.name, args) // Meta will be non-null when a setter error occurred so parse it // to a value so it gets re-thrown. - if (meta) metaToValue(meta) + if (meta != null) metaToValue(meta) return value } } @@ -207,10 +205,7 @@ function proxyFunctionProperties (remoteMemberFunction, metaId, name) { function metaToValue (meta) { const types = { 'value': () => meta.value, - 'array': () => { - const members = meta.members - return members.map((member) => metaToValue(member)) - }, + 'array': () => meta.members.map((member) => metaToValue(member)), 'buffer': () => Buffer.from(meta.value), 'promise': () => resolvePromise({then: metaToValue(meta.then)}), 'error': () => metaToPlainObject(meta), @@ -219,7 +214,7 @@ function metaToValue (meta) { } if (meta.type in types) { - types[meta.type]() + return types[meta.type] } else { let ret if (remoteObjectCache.has(meta.id)) return remoteObjectCache.get(meta.id) @@ -278,44 +273,42 @@ process.on('exit', () => { }) // Get remote module. -exports.require = function (module) { +exports.require = (module) => { return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_REQUIRE', module)) } // Alias to remote.require('electron').xxx. -exports.getBuiltin = function (module) { +exports.getBuiltin = (module) => { return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GET_BUILTIN', module)) } // Get current BrowserWindow. -exports.getCurrentWindow = function () { +exports.getCurrentWindow = () => { return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WINDOW')) } // Get current WebContents object. -exports.getCurrentWebContents = function () { +exports.getCurrentWebContents = () => { return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS')) } // Get a global object in browser. -exports.getGlobal = function (name) { +exports.getGlobal = (name) => { return metaToValue(ipcRenderer.sendSync('ELECTRON_BROWSER_GLOBAL', name)) } // Get the process object in browser. -exports.__defineGetter__('process', function () { - return exports.getGlobal('process') -}) +exports.__defineGetter__('process', () => exports.getGlobal('process')) -// Create a funtion that will return the specifed value when called in browser. -exports.createFunctionWithReturnValue = function (returnValue) { +// Create a function that will return the specified value when called in browser. +exports.createFunctionWithReturnValue = (returnValue) => { const func = () => returnValue v8Util.setHiddenValue(func, 'returnValue', true) return func } // Get the guest WebContents from guestInstanceId. -exports.getGuestWebContents = function (guestInstanceId) { +exports.getGuestWebContents = (guestInstanceId) => { const meta = ipcRenderer.sendSync('ELECTRON_BROWSER_GUEST_WEB_CONTENTS', guestInstanceId) return metaToValue(meta) } From 246c808222c99c8406b379fbd27001d3da0c0b60 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 00:18:55 -0400 Subject: [PATCH 088/185] move away from wstring --- brightray/browser/browser_main_parts.cc | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index fe9cc7073b4..ec08763038f 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -166,18 +166,17 @@ BrowserMainParts::~BrowserMainParts() { #if defined(OS_WIN) || defined(OS_LINUX) void OverrideAppLogsPath() { + base::FilePath path; + bool success = PathService::Get(brightray::DIR_APP_DATA, &path); + if (success) { + path = path.Append(base::UTF8ToWide(GetApplicationName())); #if defined(OS_WIN) - std::wstring app_name = base::UTF8ToWide(GetApplicationName()); - std::wstring home = std::wstring(_wgetenv(L"HOMEDRIVE")); - std::wstring drive = std::wstring(_wgetenv(L"HOMEPATH")); - std::wstring log_path = home + L"\\" + drive + L"\\AppData\\Roaming\\"; - std::wstring app_log_path = log_path + app_name + L"\\logs"; + path = path.Append(L"logs"); #else - std::string app_name = GetApplicationName(); - std::string home_path = std::string(getenv("HOME")); - std::string app_log_path = home_path + "/.config/" + app_name + "/logs"; + path = path.Append("logs"); #endif - PathService::Override(DIR_APP_LOGS, base::FilePath(app_log_path)); + PathService::Override(DIR_APP_LOGS, base::FilePath(path)); + } } #endif From c9dca6b8ad9aeddd5fbab4ca01daa2a481ed575c Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 00:21:52 -0400 Subject: [PATCH 089/185] remove unnecessary boolean --- brightray/browser/browser_main_parts.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index ec08763038f..74008dd23dd 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -167,8 +167,7 @@ BrowserMainParts::~BrowserMainParts() { #if defined(OS_WIN) || defined(OS_LINUX) void OverrideAppLogsPath() { base::FilePath path; - bool success = PathService::Get(brightray::DIR_APP_DATA, &path); - if (success) { + if (PathService::Get(brightray::DIR_APP_DATA, &path)) { path = path.Append(base::UTF8ToWide(GetApplicationName())); #if defined(OS_WIN) path = path.Append(L"logs"); From fc920ffd06210875653dee854d94e91a26ff41c3 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 00:27:27 -0400 Subject: [PATCH 090/185] base::UTF8ToWide --> base::FromUTF8Unsafe --- brightray/browser/browser_main_parts.cc | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/brightray/browser/browser_main_parts.cc b/brightray/browser/browser_main_parts.cc index 74008dd23dd..f3ab093af06 100644 --- a/brightray/browser/browser_main_parts.cc +++ b/brightray/browser/browser_main_parts.cc @@ -168,13 +168,9 @@ BrowserMainParts::~BrowserMainParts() { void OverrideAppLogsPath() { base::FilePath path; if (PathService::Get(brightray::DIR_APP_DATA, &path)) { - path = path.Append(base::UTF8ToWide(GetApplicationName())); -#if defined(OS_WIN) - path = path.Append(L"logs"); -#else - path = path.Append("logs"); -#endif - PathService::Override(DIR_APP_LOGS, base::FilePath(path)); + path = path.Append(base::FilePath::FromUTF8Unsafe(GetApplicationName())); + path = path.Append(base::FilePath::FromUTF8Unsafe("logs")); + PathService::Override(DIR_APP_LOGS, path); } } #endif From 0c9e106502018a03d25c76a068d8741463a24fed Mon Sep 17 00:00:00 2001 From: Selwyn Date: Thu, 26 Oct 2017 14:17:34 +0200 Subject: [PATCH 091/185] Update electron-download to version 4.1.0 Respects the OS cache location and be able to set he cache location by setting the environment variable `ELECTRON_CACHE`. --- npm/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/npm/package.json b/npm/package.json index f6221e54580..d2967f01cfe 100644 --- a/npm/package.json +++ b/npm/package.json @@ -12,7 +12,7 @@ "types": "electron.d.ts", "dependencies": { "@types/node": "^8.0.24", - "electron-download": "^3.0.1", + "electron-download": "^4.1.0", "extract-zip": "^1.0.3" }, "devDependencies": { From 08845c990370a250a7747703a1abcb6f92b22a93 Mon Sep 17 00:00:00 2001 From: Robin Andersson Date: Thu, 26 Oct 2017 20:21:09 +0200 Subject: [PATCH 092/185] Removed incorrect optional labels from tray.displayBalloon(options) docs --- docs/api/tray.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/api/tray.md b/docs/api/tray.md index 53efaa71201..52147bcc292 100644 --- a/docs/api/tray.md +++ b/docs/api/tray.md @@ -245,8 +245,8 @@ win.on('hide', () => { * `options` Object * `icon` ([NativeImage](native-image.md) | String) - (optional) - * `title` String - (optional) - * `content` String - (optional) + * `title` String + * `content` String Displays a tray balloon. From 17f4e53d6babf7ca04d3b9f305180d4a06801fe5 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 16:30:07 -0400 Subject: [PATCH 093/185] match earlier tests to ES6 later ones --- spec/api-protocol-spec.js | 776 ++++++++++++++------------------------ 1 file changed, 292 insertions(+), 484 deletions(-) diff --git a/spec/api-protocol-spec.js b/spec/api-protocol-spec.js index 2d457cb5511..a79bb3b1bca 100644 --- a/spec/api-protocol-spec.js +++ b/spec/api-protocol-spec.js @@ -3,42 +3,38 @@ const http = require('http') const path = require('path') const qs = require('querystring') const {closeWindow} = require('./window-helpers') -const remote = require('electron').remote +const {remote} = require('electron') const {BrowserWindow, ipcMain, protocol, session, webContents} = remote -describe('protocol module', function () { - var protocolName = 'sp' - var text = 'valar morghulis' - var postData = { +describe('protocol module', () => { + const protocolName = 'sp' + const text = 'valar morghulis' + const postData = { name: 'post test', type: 'string' } - afterEach(function (done) { - protocol.unregisterProtocol(protocolName, function () { - protocol.uninterceptProtocol('http', function () { - done() - }) + afterEach((done) => { + protocol.unregisterProtocol(protocolName, () => { + protocol.uninterceptProtocol('http', () => done()) }) }) - describe('protocol.register(Any)Protocol', function () { - var emptyHandler = function (request, callback) { - callback() - } + describe('protocol.register(Any)Protocol', () => { + const emptyHandler = (request, callback) => callback() - it('throws error when scheme is already registered', function (done) { - protocol.registerStringProtocol(protocolName, emptyHandler, function (error) { + it('throws error when scheme is already registered', (done) => { + protocol.registerStringProtocol(protocolName, emptyHandler, (error) => { assert.equal(error, null) - protocol.registerBufferProtocol(protocolName, emptyHandler, function (error) { + protocol.registerBufferProtocol(protocolName, emptyHandler, (error) => { assert.notEqual(error, null) done() }) }) }) - it('does not crash when handler is called twice', function (done) { - var doubleHandler = function (request, callback) { + it('does not crash when handler is called twice', (done) => { + const doubleHandler = (request, callback) => { try { callback(text) callback() @@ -46,36 +42,29 @@ describe('protocol module', function () { // Ignore error } } - protocol.registerStringProtocol(protocolName, doubleHandler, function (error) { - if (error) { - return done(error) - } + protocol.registerStringProtocol(protocolName, doubleHandler, (error) => { + if (error) return done(error) + $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sends error when callback is called with nothing', function (done) { - protocol.registerBufferProtocol(protocolName, emptyHandler, function (error) { - if (error) { - return done(error) - } + it('sends error when callback is called with nothing', (done) => { + protocol.registerBufferProtocol(protocolName, emptyHandler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { - return done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') return done() } @@ -83,126 +72,98 @@ describe('protocol module', function () { }) }) - it('does not crash when callback is called in next tick', function (done) { - var handler = function (request, callback) { - setImmediate(function () { - callback(text) - }) + it('does not crash when callback is called in next tick', (done) => { + const handler = (request, callback) => { + setImmediate(() => callback(text)) } - protocol.registerStringProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + protocol.registerStringProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) }) - describe('protocol.unregisterProtocol', function () { - it('returns error when scheme does not exist', function (done) { - protocol.unregisterProtocol('not-exist', function (error) { + describe('protocol.unregisterProtocol', () => { + it('returns error when scheme does not exist', (done) => { + protocol.unregisterProtocol('not-exist', (error) => { assert.notEqual(error, null) done() }) }) }) - describe('protocol.registerStringProtocol', function () { - it('sends string as response', function (done) { - var handler = function (request, callback) { - callback(text) - } - protocol.registerStringProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + describe('protocol.registerStringProtocol', () => { + it('sends string as response', (done) => { + const handler = (request, callback) => callback(text) + protocol.registerStringProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sets Access-Control-Allow-Origin', function (done) { - var handler = function (request, callback) { - callback(text) - } - protocol.registerStringProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('sets Access-Control-Allow-Origin', (done) => { + const handler = (request, callback) => callback(text) + protocol.registerStringProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data, status, request) { + success: (data, status, request) => { assert.equal(data, text) assert.equal(request.getResponseHeader('Access-Control-Allow-Origin'), '*') done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sends object as response', function (done) { - var handler = function (request, callback) { + it('sends object as response', (done) => { + const handler = (request, callback) => { callback({ data: text, mimeType: 'text/html' }) } - protocol.registerStringProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + protocol.registerStringProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('fails when sending object other than string', function (done) { - var handler = function (request, callback) { - callback(new Date()) - } - protocol.registerBufferProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('fails when sending object other than string', (done) => { + const handler = (request, callback) => callback(new Date()) + protocol.registerBufferProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { - done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -211,95 +172,71 @@ describe('protocol module', function () { }) }) - describe('protocol.registerBufferProtocol', function () { - var buffer = new Buffer(text) - - it('sends Buffer as response', function (done) { - var handler = function (request, callback) { - callback(buffer) - } - protocol.registerBufferProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + describe('protocol.registerBufferProtocol', () => { + const buffer = new Buffer(text) + it('sends Buffer as response', (done) => { + const handler = (request, callback) => callback(buffer) + protocol.registerBufferProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sets Access-Control-Allow-Origin', function (done) { - var handler = function (request, callback) { - callback(buffer) - } - - protocol.registerBufferProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('sets Access-Control-Allow-Origin', (done) => { + const handler = (request, callback) => callback(buffer) + protocol.registerBufferProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data, status, request) { + success: (data, status, request) => { assert.equal(data, text) assert.equal(request.getResponseHeader('Access-Control-Allow-Origin'), '*') done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sends object as response', function (done) { - var handler = function (request, callback) { + it('sends object as response', (done) => { + const handler = (request, callback) => { callback({ data: buffer, mimeType: 'text/html' }) } - protocol.registerBufferProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + protocol.registerBufferProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('fails when sending string', function (done) { - var handler = function (request, callback) { - callback(text) - } - protocol.registerBufferProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('fails when sending string', (done) => { + const handler = (request, callback) => callback(text) + protocol.registerBufferProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { - done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -308,120 +245,89 @@ describe('protocol module', function () { }) }) - describe('protocol.registerFileProtocol', function () { - var filePath = path.join(__dirname, 'fixtures', 'asar', 'a.asar', 'file1') - var fileContent = require('fs').readFileSync(filePath) - var normalPath = path.join(__dirname, 'fixtures', 'pages', 'a.html') - var normalContent = require('fs').readFileSync(normalPath) + describe('protocol.registerFileProtocol', () => { + const filePath = path.join(__dirname, 'fixtures', 'asar', 'a.asar', 'file1') + const fileContent = require('fs').readFileSync(filePath) + const normalPath = path.join(__dirname, 'fixtures', 'pages', 'a.html') + const normalContent = require('fs').readFileSync(normalPath) - it('sends file path as response', function (done) { - var handler = function (request, callback) { - callback(filePath) - } - protocol.registerFileProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('sends file path as response', (done) => { + const handler = (request, callback) => callback(filePath) + protocol.registerFileProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, String(fileContent)) return done() }, - error: function (xhr, errorType, error) { - return done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sets Access-Control-Allow-Origin', function (done) { - var handler = function (request, callback) { - callback(filePath) - } - protocol.registerFileProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('sets Access-Control-Allow-Origin', (done) => { + const handler = (request, callback) => callback(filePath) + protocol.registerFileProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data, status, request) { + success: (data, status, request) => { assert.equal(data, String(fileContent)) assert.equal(request.getResponseHeader('Access-Control-Allow-Origin'), '*') done() }, - error: function (xhr, errorType, error) { + error: (xhr, errorType, error) => { done(error) } }) }) }) - it('sends object as response', function (done) { - var handler = function (request, callback) { - callback({ - path: filePath - }) - } - protocol.registerFileProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('sends object as response', (done) => { + const handler = (request, callback) => callback({ path: filePath }) + protocol.registerFileProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, String(fileContent)) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('can send normal file', function (done) { - var handler = function (request, callback) { - callback(normalPath) - } - - protocol.registerFileProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('can send normal file', (done) => { + const handler = (request, callback) => callback(normalPath) + protocol.registerFileProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, String(normalContent)) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('fails when sending unexist-file', function (done) { - var fakeFilePath = path.join(__dirname, 'fixtures', 'asar', 'a.asar', 'not-exist') - var handler = function (request, callback) { - callback(fakeFilePath) - } - protocol.registerFileProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('fails when sending unexist-file', (done) => { + const fakeFilePath = path.join(__dirname, 'fixtures', 'asar', 'a.asar', 'not-exist') + const handler = (request, callback) => callback(fakeFilePath) + protocol.registerFileProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { - done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -429,21 +335,15 @@ describe('protocol module', function () { }) }) - it('fails when sending unsupported content', function (done) { - var handler = function (request, callback) { - callback(new Date()) - } - protocol.registerFileProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('fails when sending unsupported content', (done) => { + const handler = (request, callback) => callback(new Date()) + protocol.registerFileProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { - done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -452,57 +352,41 @@ describe('protocol module', function () { }) }) - describe('protocol.registerHttpProtocol', function () { - it('sends url as response', function (done) { - var server = http.createServer(function (req, res) { + describe('protocol.registerHttpProtocol', () => { + it('sends url as response', (done) => { + const server = http.createServer((req, res) => { assert.notEqual(req.headers.accept, '') res.end(text) server.close() }) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - var url = 'http://127.0.0.1:' + port - var handler = function (request, callback) { - callback({ - url: url - }) - } - protocol.registerHttpProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + const url = 'http://127.0.0.1:' + port + const handler = (request, callback) => callback({url}) + protocol.registerHttpProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) }) - it('fails when sending invalid url', function (done) { - var handler = function (request, callback) { - callback({ - url: 'url' - }) - } - protocol.registerHttpProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('fails when sending invalid url', (done) => { + const handler = (request, callback) => callback({url: 'url'}) + protocol.registerHttpProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { - done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -510,21 +394,17 @@ describe('protocol module', function () { }) }) - it('fails when sending unsupported content', function (done) { - var handler = function (request, callback) { - callback(new Date()) - } - protocol.registerHttpProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + it('fails when sending unsupported content', (done) => { + const handler = (request, callback) => callback(new Date()) + protocol.registerHttpProtocol(protocolName, handler, (error) => { + if (error) return done(error) $.ajax({ url: protocolName + '://fake-host', cache: false, - success: function () { + success: () => { done('request succeeded but it should not') }, - error: function (xhr, errorType) { + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -532,32 +412,26 @@ describe('protocol module', function () { }) }) - it('works when target URL redirects', function (done) { - var contents = null - var server = http.createServer(function (req, res) { + it('works when target URL redirects', (done) => { + let contents = null + const server = http.createServer((req, res) => { if (req.url === '/serverRedirect') { res.statusCode = 301 - res.setHeader('Location', 'http://' + req.rawHeaders[1]) + res.setHeader('Location', `http://${req.rawHeaders[1]}`) res.end() } else { res.end(text) } }) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - var url = `${protocolName}://fake-host` - var redirectURL = `http://127.0.0.1:${port}/serverRedirect` - var handler = function (request, callback) { - callback({ - url: redirectURL - }) - } - protocol.registerHttpProtocol(protocolName, handler, function (error) { - if (error) { - return done(error) - } + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + const url = `${protocolName}://fake-host` + const redirectURL = `http://127.0.0.1:${port}/serverRedirect` + const handler = (request, callback) => callback({url: redirectURL}) + protocol.registerHttpProtocol(protocolName, handler, (error) => { + if (error) return done(error) contents = webContents.create({}) - contents.on('did-finish-load', function () { + contents.on('did-finish-load', () => { assert.equal(contents.getURL(), url) server.close() contents.destroy() @@ -569,62 +443,58 @@ describe('protocol module', function () { }) }) - describe('protocol.isProtocolHandled', function () { - it('returns true for about:', function (done) { - protocol.isProtocolHandled('about', function (result) { + describe('protocol.isProtocolHandled', () => { + it('returns true for about:', (done) => { + protocol.isProtocolHandled('about', (result) => { assert.equal(result, true) done() }) }) - it('returns true for file:', function (done) { - protocol.isProtocolHandled('file', function (result) { + it('returns true for file:', (done) => { + protocol.isProtocolHandled('file', (result) => { assert.equal(result, true) done() }) }) - it('returns true for http:', function (done) { - protocol.isProtocolHandled('http', function (result) { + it('returns true for http:', (done) => { + protocol.isProtocolHandled('http', (result) => { assert.equal(result, true) done() }) }) - it('returns true for https:', function (done) { - protocol.isProtocolHandled('https', function (result) { + it('returns true for https:', (done) => { + protocol.isProtocolHandled('https', (result) => { assert.equal(result, true) done() }) }) - it('returns false when scheme is not registered', function (done) { - protocol.isProtocolHandled('no-exist', function (result) { + it('returns false when scheme is not registered', (done) => { + protocol.isProtocolHandled('no-exist', (result) => { assert.equal(result, false) done() }) }) - it('returns true for custom protocol', function (done) { - var emptyHandler = function (request, callback) { - callback() - } - protocol.registerStringProtocol(protocolName, emptyHandler, function (error) { + it('returns true for custom protocol', (done) => { + const emptyHandler = (request, callback) => callback() + protocol.registerStringProtocol(protocolName, emptyHandler, (error) => { assert.equal(error, null) - protocol.isProtocolHandled(protocolName, function (result) { + protocol.isProtocolHandled(protocolName, (result) => { assert.equal(result, true) done() }) }) }) - it('returns true for intercepted protocol', function (done) { - var emptyHandler = function (request, callback) { - callback() - } - protocol.interceptStringProtocol('http', emptyHandler, function (error) { + it('returns true for intercepted protocol', (done) => { + const emptyHandler = (request, callback) => callback() + protocol.interceptStringProtocol('http', emptyHandler, (error) => { assert.equal(error, null) - protocol.isProtocolHandled('http', function (result) { + protocol.isProtocolHandled('http', (result) => { assert.equal(result, true) done() }) @@ -632,23 +502,20 @@ describe('protocol module', function () { }) }) - describe('protocol.intercept(Any)Protocol', function () { - var emptyHandler = function (request, callback) { - callback() - } - - it('throws error when scheme is already intercepted', function (done) { - protocol.interceptStringProtocol('http', emptyHandler, function (error) { + describe('protocol.intercept(Any)Protocol', () => { + const emptyHandler = (request, callback) => callback() + it('throws error when scheme is already intercepted', (done) => { + protocol.interceptStringProtocol('http', emptyHandler, (error) => { assert.equal(error, null) - protocol.interceptBufferProtocol('http', emptyHandler, function (error) { + protocol.interceptBufferProtocol('http', emptyHandler, (error) => { assert.notEqual(error, null) done() }) }) }) - it('does not crash when handler is called twice', function (done) { - var doubleHandler = function (request, callback) { + it('does not crash when handler is called twice', (done) => { + var doubleHandler = (request, callback) => { try { callback(text) callback() @@ -656,39 +523,29 @@ describe('protocol module', function () { // Ignore error } } - protocol.interceptStringProtocol('http', doubleHandler, function (error) { - if (error) { - return done(error) - } + protocol.interceptStringProtocol('http', doubleHandler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('sends error when callback is called with nothing', function (done) { - if (process.env.TRAVIS === 'true') { - return done() - } - protocol.interceptBufferProtocol('http', emptyHandler, function (error) { - if (error) { - return done(error) - } + it('sends error when callback is called with nothing', (done) => { + if (process.env.TRAVIS === 'true') return done() + protocol.interceptBufferProtocol('http', emptyHandler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, - success: function () { - done('request succeeded but it should not') - }, - error: function (xhr, errorType) { + success: () => done('request succeeded but it should not'), + error: (xhr, errorType) => { assert.equal(errorType, 'error') done() } @@ -697,149 +554,123 @@ describe('protocol module', function () { }) }) - describe('protocol.interceptStringProtocol', function () { - it('can intercept http protocol', function (done) { - var handler = function (request, callback) { - callback(text) - } - protocol.interceptStringProtocol('http', handler, function (error) { - if (error) { - return done(error) - } + describe('protocol.interceptStringProtocol', () => { + it('can intercept http protocol', (done) => { + const handler = (request, callback) => callback(text) + protocol.interceptStringProtocol('http', handler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('can set content-type', function (done) { - var handler = function (request, callback) { + it('can set content-type', (done) => { + const handler = (request, callback) => { callback({ mimeType: 'application/json', data: '{"value": 1}' }) } - protocol.interceptStringProtocol('http', handler, function (error) { - if (error) { - return done(error) - } + protocol.interceptStringProtocol('http', handler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(typeof data, 'object') assert.equal(data.value, 1) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('can receive post data', function (done) { - var handler = function (request, callback) { - var uploadData = request.uploadData[0].bytes.toString() - callback({ - data: uploadData - }) + it('can receive post data', (done) => { + const handler = (request, callback) => { + const uploadData = request.uploadData[0].bytes.toString() + callback({data: uploadData}) } - protocol.interceptStringProtocol('http', handler, function (error) { - if (error) { - return done(error) - } + protocol.interceptStringProtocol('http', handler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, type: 'POST', data: postData, - success: function (data) { + success: (data) => { assert.deepEqual(qs.parse(data), postData) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) }) - describe('protocol.interceptBufferProtocol', function () { - it('can intercept http protocol', function (done) { - var handler = function (request, callback) { - callback(new Buffer(text)) - } - protocol.interceptBufferProtocol('http', handler, function (error) { - if (error) { - return done(error) - } + describe('protocol.interceptBufferProtocol', () => { + it('can intercept http protocol', (done) => { + const handler = (request, callback) => callback(new Buffer(text)) + protocol.interceptBufferProtocol('http', handler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, - success: function (data) { + success: (data) => { assert.equal(data, text) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) - it('can receive post data', function (done) { - var handler = function (request, callback) { - var uploadData = request.uploadData[0].bytes + it('can receive post data', (done) => { + const handler = (request, callback) => { + const uploadData = request.uploadData[0].bytes callback(uploadData) } - protocol.interceptBufferProtocol('http', handler, function (error) { - if (error) { - return done(error) - } + protocol.interceptBufferProtocol('http', handler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, type: 'POST', data: postData, - success: function (data) { + success: (data) => { assert.equal(data, $.param(postData)) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) }) - describe('protocol.interceptHttpProtocol', function () { - it('can send POST request', function (done) { - var server = http.createServer(function (req, res) { - var body = '' - req.on('data', function (chunk) { + describe('protocol.interceptHttpProtocol', () => { + it('can send POST request', (done) => { + const server = http.createServer((req, res) => { + let body = '' + req.on('data', (chunk) => { body += chunk }) - req.on('end', function () { + req.on('end', () => { res.end(body) }) server.close() }) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - var url = 'http://127.0.0.1:' + port - var handler = function (request, callback) { - var data = { + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + const url = `http://127.0.0.1:${port}` + const handler = (request, callback) => { + const data = { url: url, method: 'POST', uploadData: { @@ -850,48 +681,40 @@ describe('protocol module', function () { } callback(data) } - protocol.interceptHttpProtocol('http', handler, function (error) { - if (error) { - return done(error) - } + protocol.interceptHttpProtocol('http', handler, (error) => { + if (error) return done(error) $.ajax({ url: 'http://fake-host', cache: false, type: 'POST', data: postData, - success: function (data) { + success: (data) => { assert.deepEqual(qs.parse(data), postData) done() }, - error: function (xhr, errorType, error) { - done(error) - } + error: (xhr, errorType, error) => done(error) }) }) }) }) - it('can use custom session', function (done) { - const customSession = session.fromPartition('custom-ses', { - cache: false - }) - customSession.webRequest.onBeforeRequest(function (details, callback) { + it('can use custom session', (done) => { + const customSession = session.fromPartition('custom-ses', {cache: false}) + customSession.webRequest.onBeforeRequest((details, callback) => { assert.equal(details.url, 'http://fake-host/') callback({cancel: true}) }) - const handler = function (request, callback) { + const handler = (request, callback) => { callback({ url: request.url, session: customSession }) } - protocol.interceptHttpProtocol('http', handler, function (error) { - if (error) { - return done(error) - } - fetch('http://fake-host').then(function () { + protocol.interceptHttpProtocol('http', handler, (error) => { + if (error) return done(error) + fetch('http://fake-host').then(() => { done('request succeeded but it should not') - }).catch(function () { + }).catch(() => { customSession.webRequest.onBeforeRequest(null) done() }) @@ -899,47 +722,47 @@ describe('protocol module', function () { }) }) - describe('protocol.uninterceptProtocol', function () { - it('returns error when scheme does not exist', function (done) { - protocol.uninterceptProtocol('not-exist', function (error) { + describe('protocol.uninterceptProtocol', () => { + it('returns error when scheme does not exist', (done) => { + protocol.uninterceptProtocol('not-exist', (error) => { assert.notEqual(error, null) done() }) }) - it('returns error when scheme is not intercepted', function (done) { - protocol.uninterceptProtocol('http', function (error) { + it('returns error when scheme is not intercepted', (done) => { + protocol.uninterceptProtocol('http', (error) => { assert.notEqual(error, null) done() }) }) }) - describe('protocol.registerStandardSchemes', function () { + describe('protocol.registerStandardSchemes', () => { const standardScheme = remote.getGlobal('standardScheme') - const origin = standardScheme + '://fake-host' - const imageURL = origin + '/test.png' + const origin = `${standardScheme}://fake-host` + const imageURL = `${origin}/test.png` const filePath = path.join(__dirname, 'fixtures', 'pages', 'b.html') const fileContent = '' - var w = null - var success = null + let w = null + let success = null - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({show: false}) success = false }) - afterEach(function (done) { - protocol.unregisterProtocol(standardScheme, function () { - closeWindow(w).then(function () { + afterEach((done) => { + protocol.unregisterProtocol(standardScheme, () => { + closeWindow(w).then(() => { w = null done() }) }) }) - it('resolves relative resources', function (done) { - var handler = function (request, callback) { + it('resolves relative resources', (done) => { + const handler = (request, callback) => { if (request.url === imageURL) { success = true callback() @@ -947,11 +770,9 @@ describe('protocol module', function () { callback(filePath) } } - protocol.registerFileProtocol(standardScheme, handler, function (error) { - if (error) { - return done(error) - } - w.webContents.on('did-finish-load', function () { + protocol.registerFileProtocol(standardScheme, handler, (error) => { + if (error) return done(error) + w.webContents.on('did-finish-load', () => { assert(success) done() }) @@ -959,8 +780,8 @@ describe('protocol module', function () { }) }) - it('resolves absolute resources', function (done) { - var handler = function (request, callback) { + it('resolves absolute resources', (done) => { + const handler = (request, callback) => { if (request.url === imageURL) { success = true callback() @@ -971,11 +792,9 @@ describe('protocol module', function () { }) } } - protocol.registerStringProtocol(standardScheme, handler, function (error) { - if (error) { - return done(error) - } - w.webContents.on('did-finish-load', function () { + protocol.registerStringProtocol(standardScheme, handler, (error) => { + if (error) return done(error) + w.webContents.on('did-finish-load', () => { assert(success) done() }) @@ -983,29 +802,21 @@ describe('protocol module', function () { }) }) - it('can have fetch working in it', function (done) { + it('can have fetch working in it', (done) => { const content = '' - const handler = function (request, callback) { - callback({data: content, mimeType: 'text/html'}) - } - protocol.registerStringProtocol(standardScheme, handler, function (error) { + const handler = (request, callback) => callback({data: content, mimeType: 'text/html'}) + protocol.registerStringProtocol(standardScheme, handler, (error) => { if (error) return done(error) - w.webContents.on('crashed', function () { - done('WebContents crashed') - }) - w.webContents.on('did-finish-load', function () { - done() - }) + w.webContents.on('crashed', () => done('WebContents crashed')) + w.webContents.on('did-finish-load', () => done()) w.loadURL(origin) }) }) - it('can access files through the FileSystem API', function (done) { + it('can access files through the FileSystem API', (done) => { let filePath = path.join(__dirname, 'fixtures', 'pages', 'filesystem.html') - const handler = function (request, callback) { - callback({path: filePath}) - } - protocol.registerFileProtocol(standardScheme, handler, function (error) { + const handler = (request, callback) => callback({path: filePath}) + protocol.registerFileProtocol(standardScheme, handler, (error) => { if (error) return done(error) w.loadURL(origin) }) @@ -1013,15 +824,12 @@ describe('protocol module', function () { ipcMain.once('file-system-write-end', () => done()) }) - it('registers secure, when {secure: true}', function (done) { - // the CacheStorage API will only work if secure == true + it('registers secure, when {secure: true}', (done) => { let filePath = path.join(__dirname, 'fixtures', 'pages', 'cache-storage.html') - const handler = function (request, callback) { - callback({path: filePath}) - } + const handler = (request, callback) => callback({path: filePath}) ipcMain.once('success', () => done()) ipcMain.once('failure', (event, err) => done(err)) - protocol.registerFileProtocol(standardScheme, handler, function (error) { + protocol.registerFileProtocol(standardScheme, handler, (error) => { if (error) return done(error) w.loadURL(origin) }) From b53e41af4236bb7f100ffba2a1d2143844d6b14e Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:05:15 -0400 Subject: [PATCH 094/185] migrate api-browser-view-spec to ES6 --- spec/api-browser-view-spec.js | 52 +++++++++++++++++------------------ 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js index 11cf582b002..8de4186eafc 100644 --- a/spec/api-browser-view-spec.js +++ b/spec/api-browser-view-spec.js @@ -6,11 +6,11 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {BrowserView, BrowserWindow} = remote -describe('BrowserView module', function () { - var w = null - var view = null +describe.only('BrowserView module', () => { + let w = null + let view = null - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({ show: false, width: 400, @@ -21,68 +21,68 @@ describe('BrowserView module', function () { }) }) - afterEach(function () { + afterEach(() => { if (view) { view.destroy() view = null } - return closeWindow(w).then(function () { w = null }) + return closeWindow(w).then(() => { w = null }) }) - describe('BrowserView.setBackgroundColor()', function () { - it('does not throw for valid args', function () { + describe('BrowserView.setBackgroundColor()', () => { + it('does not throw for valid args', () => { view = new BrowserView() view.setBackgroundColor('#000') }) - it('throws for invalid args', function () { + it('throws for invalid args', () => { view = new BrowserView() - assert.throws(function () { + assert.throws(() => { view.setBackgroundColor(null) }, /conversion failure/) }) }) - describe('BrowserView.setAutoResize()', function () { - it('does not throw for valid args', function () { + describe('BrowserView.setAutoResize()', () => { + it('does not throw for valid args', () => { view = new BrowserView() view.setAutoResize({}) view.setAutoResize({ width: true, height: false }) }) - it('throws for invalid args', function () { + it('throws for invalid args', () => { view = new BrowserView() - assert.throws(function () { + assert.throws(() => { view.setAutoResize(null) }, /conversion failure/) }) }) - describe('BrowserView.setBounds()', function () { - it('does not throw for valid args', function () { + describe('BrowserView.setBounds()', () => { + it('does not throw for valid args', () => { view = new BrowserView() view.setBounds({ x: 0, y: 0, width: 1, height: 1 }) }) - it('throws for invalid args', function () { + it('throws for invalid args', () => { view = new BrowserView() - assert.throws(function () { + assert.throws(() => { view.setBounds(null) }, /conversion failure/) - assert.throws(function () { + assert.throws(() => { view.setBounds({}) }, /conversion failure/) }) }) - describe('BrowserWindow.setBrowserView()', function () { - it('does not throw for valid args', function () { + describe('BrowserWindow.setBrowserView()', () => { + it('does not throw for valid args', () => { view = new BrowserView() w.setBrowserView(view) }) - it('does not throw if called multiple times with same view', function () { + it('does not throw if called multiple times with same view', () => { view = new BrowserView() w.setBrowserView(view) w.setBrowserView(view) @@ -90,8 +90,8 @@ describe('BrowserView module', function () { }) }) - describe('BrowserView.webContents.getOwnerBrowserWindow()', function () { - it('points to owning window', function () { + describe('BrowserView.webContents.getOwnerBrowserWindow()', () => { + it('points to owning window', () => { view = new BrowserView() assert.ok(!view.webContents.getOwnerBrowserWindow()) w.setBrowserView(view) @@ -101,8 +101,8 @@ describe('BrowserView module', function () { }) }) - describe('BrowserView.fromId()', function () { - it('returns the view with given id', function () { + describe('BrowserView.fromId()', () => { + it('returns the view with given id', () => { view = new BrowserView() w.setBrowserView(view) assert.notEqual(view.id, null) From 68314dbc05ef667e23c7f5a47780920dbef93105 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:11:12 -0400 Subject: [PATCH 095/185] remove stray only --- spec/api-browser-view-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js index 8de4186eafc..9e2078ff727 100644 --- a/spec/api-browser-view-spec.js +++ b/spec/api-browser-view-spec.js @@ -6,7 +6,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {BrowserView, BrowserWindow} = remote -describe.only('BrowserView module', () => { +describe('BrowserView module', () => { let w = null let view = null From 56979804ec6d440b64cd49b0412e70127ef0b1c2 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:12:51 -0400 Subject: [PATCH 096/185] update clipboard spec --- spec/api-clipboard-spec.js | 60 +++++++++++++++++++------------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/spec/api-clipboard-spec.js b/spec/api-clipboard-spec.js index 84a4de742ea..2c50ef3821f 100644 --- a/spec/api-clipboard-spec.js +++ b/spec/api-clipboard-spec.js @@ -4,45 +4,45 @@ const {Buffer} = require('buffer') const {clipboard, nativeImage} = require('electron') -describe('clipboard module', function () { - var fixtures = path.resolve(__dirname, 'fixtures') +describe('clipboard module', () => { + const fixtures = path.resolve(__dirname, 'fixtures') - describe('clipboard.readImage()', function () { - it('returns NativeImage intance', function () { - var p = path.join(fixtures, 'assets', 'logo.png') - var i = nativeImage.createFromPath(p) + describe('clipboard.readImage()', () => { + it('returns NativeImage intance', () => { + const p = path.join(fixtures, 'assets', 'logo.png') + const i = nativeImage.createFromPath(p) clipboard.writeImage(p) assert.equal(clipboard.readImage().toDataURL(), i.toDataURL()) }) }) - describe('clipboard.readText()', function () { - it('returns unicode string correctly', function () { - var text = '千江有水千江月,万里无云万里天' + describe('clipboard.readText()', () => { + it('returns unicode string correctly', () => { + const text = '千江有水千江月,万里无云万里天' clipboard.writeText(text) assert.equal(clipboard.readText(), text) }) }) - describe('clipboard.readHTML()', function () { - it('returns markup correctly', function () { - var text = 'Hi' - var markup = process.platform === 'darwin' ? "Hi" : process.platform === 'linux' ? 'Hi' : 'Hi' + describe('clipboard.readHTML()', () => { + it('returns markup correctly', () => { + const text = 'Hi' + const markup = process.platform === 'darwin' ? "Hi" : process.platform === 'linux' ? 'Hi' : 'Hi' clipboard.writeHTML(text) assert.equal(clipboard.readHTML(), markup) }) }) - describe('clipboard.readRTF', function () { - it('returns rtf text correctly', function () { - var rtf = '{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}' + describe('clipboard.readRTF', () => { + it('returns rtf text correctly', () => { + const rtf = '{\\rtf1\\ansi{\\fonttbl\\f0\\fswiss Helvetica;}\\f0\\pard\nThis is some {\\b bold} text.\\par\n}' clipboard.writeRTF(rtf) assert.equal(clipboard.readRTF(), rtf) }) }) - describe('clipboard.readBookmark', function () { - it('returns title and url', function () { + describe('clipboard.readBookmark', () => { + it('returns title and url', () => { if (process.platform === 'linux') return clipboard.writeBookmark('a title', 'https://electron.atom.io') @@ -59,14 +59,14 @@ describe('clipboard module', function () { }) }) - describe('clipboard.write()', function () { - it('returns data correctly', function () { - var text = 'test' - var rtf = '{\\rtf1\\utf8 text}' - var p = path.join(fixtures, 'assets', 'logo.png') - var i = nativeImage.createFromPath(p) - var markup = process.platform === 'darwin' ? "Hi" : process.platform === 'linux' ? 'Hi' : 'Hi' - var bookmark = {title: 'a title', url: 'test'} + describe('clipboard.write()', () => { + it('returns data correctly', () => { + const text = 'test' + const rtf = '{\\rtf1\\utf8 text}' + const p = path.join(fixtures, 'assets', 'logo.png') + const i = nativeImage.createFromPath(p) + const markup = process.platform === 'darwin' ? "Hi" : process.platform === 'linux' ? 'Hi' : 'Hi' + const bookmark = {title: 'a title', url: 'test'} clipboard.write({ text: 'test', html: 'Hi', @@ -85,8 +85,8 @@ describe('clipboard module', function () { }) }) - describe('clipboard.read/writeFindText(text)', function () { - it('reads and write text to the find pasteboard', function () { + describe('clipboard.read/writeFindText(text)', () => { + it('reads and write text to the find pasteboard', () => { if (process.platform !== 'darwin') return clipboard.writeFindText('find this') @@ -110,8 +110,8 @@ describe('clipboard module', function () { }) }) - describe('clipboard.readBuffer(format)', function () { - it('returns a Buffer of the content for the specified format', function () { + describe('clipboard.readBuffer(format)', () => { + it('returns a Buffer of the content for the specified format', () => { if (process.platform !== 'darwin') return const buffer = Buffer.from('this is binary', 'utf8') From d4350079c90136842ee81e6028a0a5250f35813d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:21:36 -0400 Subject: [PATCH 097/185] update crash reporter spec --- spec/api-crash-reporter-spec.js | 83 ++++++++++++++------------------- 1 file changed, 34 insertions(+), 49 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index b7a50f7c108..0598677fea2 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,46 +11,42 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe('crashReporter module', function () { - if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) { - return - } +describe('crashReporter module', () => { + if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return - var originalTempDirectory = null - var tempDirectory = null + let originalTempDirectory = null + let tempDirectory = null - before(function () { + before(() => { tempDirectory = temp.mkdirSync('electronCrashReporterSpec-') originalTempDirectory = app.getPath('temp') app.setPath('temp', tempDirectory) }) - after(function () { + after(() => { app.setPath('temp', originalTempDirectory) }) - var fixtures = path.resolve(__dirname, 'fixtures') + const fixtures = path.resolve(__dirname, 'fixtures') const generateSpecs = (description, browserWindowOpts) => { - describe(description, function () { - var w = null - var stopServer = null + describe(description, () => { + let w = null + let stopServer = null - beforeEach(function () { + beforeEach(() => { stopServer = null w = new BrowserWindow(Object.assign({ show: false }, browserWindowOpts)) }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - afterEach(function () { + afterEach(() => { stopCrashService() }) - afterEach(function (done) { + afterEach((done) => { if (stopServer != null) { stopServer(done) } else { @@ -123,12 +119,8 @@ describe('crashReporter module', function () { crashReporter.setUploadToServer(false) } const testDone = (uploaded) => { - if (uploaded) { - return done(new Error('Uploaded crash report')) - } - if (process.platform === 'darwin') { - crashReporter.setUploadToServer(true) - } + if (uploaded) return done(new Error('Uploaded crash report')) + if (process.platform === 'darwin') crashReporter.setUploadToServer(true) assert(fs.existsSync(dumpFile)) done() } @@ -136,13 +128,10 @@ describe('crashReporter module', function () { let pollInterval const pollDumpFile = () => { fs.readdir(crashesDir, (err, files) => { - if (err) { - return - } + if (err) return const dumps = files.filter((file) => /\.dmp$/.test(file) && !existingDumpFiles.has(file)) - if (!dumps.length) { - return - } + if (!dumps.length) return + assert.equal(1, dumps.length) dumpFile = path.join(crashesDir, dumps[0]) clearInterval(pollInterval) @@ -210,22 +199,18 @@ describe('crashReporter module', function () { } }) - describe('.start(options)', function () { - it('requires that the companyName and submitURL options be specified', function () { - assert.throws(function () { - crashReporter.start({ - companyName: 'Missing submitURL' - }) + describe('.start(options)', () => { + it('requires that the companyName and submitURL options be specified', () => { + assert.throws(() => { + crashReporter.start({companyName: 'Missing submitURL'}) }, /submitURL is a required option to crashReporter\.start/) - assert.throws(function () { - crashReporter.start({ - submitURL: 'Missing companyName' - }) + assert.throws(() => { + crashReporter.start({submitURL: 'Missing companyName'}) }, /companyName is a required option to crashReporter\.start/) }) - it('can be called multiple times', function () { - assert.doesNotThrow(function () { + it('can be called multiple times', () => { + assert.doesNotThrow(() => { crashReporter.start({ companyName: 'Umbrella Corporation', submitURL: 'http://127.0.0.1/crashes' @@ -239,12 +224,12 @@ describe('crashReporter module', function () { }) }) - describe('.get/setUploadToServer', function () { - it('throws an error when called from the renderer process', function () { + describe('.get/setUploadToServer', () => { + it('throws an error when called from the renderer process', () => { assert.throws(() => require('electron').crashReporter.getUploadToServer()) }) - it('can be read/set from the main process', function () { + it('can be read/set from the main process', () => { if (process.platform === 'darwin') { crashReporter.start({ companyName: 'Umbrella Corporation', @@ -279,9 +264,9 @@ const waitForCrashReport = () => { } const startServer = ({callback, processType, done}) => { - var called = false - var server = http.createServer((req, res) => { - var form = new multiparty.Form() + let called = false + let server = http.createServer((req, res) => { + const form = new multiparty.Form() form.parse(req, (error, fields) => { if (error) throw error if (called) return @@ -335,7 +320,7 @@ const startServer = ({callback, processType, done}) => { for (const connection of activeConnections) { connection.destroy() } - server.close(function () { + server.close(() => { done() }) } From 83a290a411d4c31ffc22ccf47fa7449df85dd1f6 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:32:04 -0400 Subject: [PATCH 098/185] update debugger spec --- spec/api-debugger-spec.js | 58 +++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 30 deletions(-) diff --git a/spec/api-debugger-spec.js b/spec/api-debugger-spec.js index 83b114f7238..40d9feca27d 100644 --- a/spec/api-debugger-spec.js +++ b/spec/api-debugger-spec.js @@ -4,11 +4,11 @@ const path = require('path') const {closeWindow} = require('./window-helpers') const BrowserWindow = require('electron').remote.BrowserWindow -describe('debugger module', function () { - var fixtures = path.resolve(__dirname, 'fixtures') - var w = null +describe.only('debugger module', () => { + const fixtures = path.resolve(__dirname, 'fixtures') + let w = null - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({ show: false, width: 400, @@ -16,13 +16,11 @@ describe('debugger module', function () { }) }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - describe('debugger.attach', function () { - it('fails when devtools is already open', function (done) { - w.webContents.on('did-finish-load', function () { + describe('debugger.attach', () => { + it('fails when devtools is already open', (done) => { + w.webContents.on('did-finish-load', () => { w.webContents.openDevTools() try { w.webContents.debugger.attach() @@ -31,10 +29,10 @@ describe('debugger module', function () { done() } }) - w.webContents.loadURL('file://' + path.join(fixtures, 'pages', 'a.html')) + w.webContents.loadURL(`file://${path.join(fixtures, 'pages', 'a.html')}`) }) - it('fails when protocol version is not supported', function (done) { + it('fails when protocol version is not supported', (done) => { try { w.webContents.debugger.attach('2.0') } catch (err) { @@ -43,20 +41,20 @@ describe('debugger module', function () { } }) - it('attaches when no protocol version is specified', function (done) { + it('attaches when no protocol version is specified', (done) => { try { w.webContents.debugger.attach() } catch (err) { - done('unexpected error : ' + err) + done(`unexpected error : ${err}`) } assert(w.webContents.debugger.isAttached()) done() }) }) - describe('debugger.detach', function () { - it('fires detach event', function (done) { - w.webContents.debugger.on('detach', function (e, reason) { + describe('debugger.detach', () => { + it('fires detach event', (done) => { + w.webContents.debugger.on('detach', (e, reason) => { assert.equal(reason, 'target closed') assert(!w.webContents.debugger.isAttached()) done() @@ -64,23 +62,23 @@ describe('debugger module', function () { try { w.webContents.debugger.attach() } catch (err) { - done('unexpected error : ' + err) + done(`unexpected error : ${err}`) } w.webContents.debugger.detach() }) }) - describe('debugger.sendCommand', function () { + describe('debugger.sendCommand', () => { let server - afterEach(function () { + afterEach(() => { if (server != null) { server.close() server = null } }) - it('retuns response', function (done) { + it('retuns response', (done) => { w.webContents.loadURL('about:blank') try { w.webContents.debugger.attach() @@ -100,9 +98,9 @@ describe('debugger module', function () { w.webContents.debugger.sendCommand('Runtime.evaluate', params, callback) }) - it('fires message event', function (done) { - var url = process.platform !== 'win32' - ? 'file://' + path.join(fixtures, 'pages', 'a.html') + it('fires message event', (done) => { + const url = process.platform !== 'win32' + ? `file://${path.join(fixtures, 'pages', 'a.html')}` : 'file:///' + path.join(fixtures, 'pages', 'a.html').replace(/\\/g, '/') w.webContents.loadURL(url) try { @@ -110,7 +108,7 @@ describe('debugger module', function () { } catch (err) { done('unexpected error : ' + err) } - w.webContents.debugger.on('message', function (e, method, params) { + w.webContents.debugger.on('message', (e, method, params) => { if (method === 'Console.messageAdded') { assert.equal(params.message.level, 'log') assert.equal(params.message.url, url) @@ -122,25 +120,25 @@ describe('debugger module', function () { w.webContents.debugger.sendCommand('Console.enable') }) - it('returns error message when command fails', function (done) { + it('returns error message when command fails', (done) => { w.webContents.loadURL('about:blank') try { w.webContents.debugger.attach() } catch (err) { - done('unexpected error : ' + err) + done(`unexpected error : ${err}`) } - w.webContents.debugger.sendCommand('Test', function (err) { + w.webContents.debugger.sendCommand('Test', (err) => { assert.equal(err.message, "'Test' wasn't found") w.webContents.debugger.detach() done() }) }) - it('handles invalid unicode characters in message', function (done) { + it('handles invalid unicode characters in message', (done) => { try { w.webContents.debugger.attach() } catch (err) { - done('unexpected error : ' + err) + done(`unexpected error : ${err}`) } w.webContents.debugger.on('message', (event, method, params) => { From 6cd308f9ad7fb01086a305f4ea18678a14ea8507 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:35:33 -0400 Subject: [PATCH 099/185] update deprecations spec --- spec/api-debugger-spec.js | 2 +- spec/api-deprecations-spec.js | 21 ++++++++++----------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/spec/api-debugger-spec.js b/spec/api-debugger-spec.js index 40d9feca27d..5902a5b0027 100644 --- a/spec/api-debugger-spec.js +++ b/spec/api-debugger-spec.js @@ -4,7 +4,7 @@ const path = require('path') const {closeWindow} = require('./window-helpers') const BrowserWindow = require('electron').remote.BrowserWindow -describe.only('debugger module', () => { +describe('debugger module', () => { const fixtures = path.resolve(__dirname, 'fixtures') let w = null diff --git a/spec/api-deprecations-spec.js b/spec/api-deprecations-spec.js index 5b618ac9016..00815b284cb 100644 --- a/spec/api-deprecations-spec.js +++ b/spec/api-deprecations-spec.js @@ -1,27 +1,26 @@ const assert = require('assert') -const deprecations = require('electron').deprecations +const {deprecations, deprecate} = require('electron') -describe('deprecations', function () { - beforeEach(function () { +describe('deprecations', () => { + beforeEach(() => { deprecations.setHandler(null) process.throwDeprecation = true }) - it('allows a deprecation handler function to be specified', function () { - var messages = [] + it('allows a deprecation handler function to be specified', () => { + const messages = [] - deprecations.setHandler(function (message) { + deprecations.setHandler((message) => { messages.push(message) }) - require('electron').deprecate.log('this is deprecated') - + deprecate.log('this is deprecated') assert.deepEqual(messages, ['this is deprecated']) }) - it('throws an exception if no deprecation handler is specified', function () { - assert.throws(function () { - require('electron').deprecate.log('this is deprecated') + it('throws an exception if no deprecation handler is specified', () => { + assert.throws(() => { + deprecate.log('this is deprecated') }, /this is deprecated/) }) }) From 6feff1d6e8d91e3b5cb66d6c7531893cbbbbe8c4 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:44:06 -0400 Subject: [PATCH 100/185] update desktop capturer spec --- spec/api-desktop-capturer-spec.js | 30 ++++++++++++++---------------- 1 file changed, 14 insertions(+), 16 deletions(-) diff --git a/spec/api-desktop-capturer-spec.js b/spec/api-desktop-capturer-spec.js index 3dce618de00..ae4af2375e9 100644 --- a/spec/api-desktop-capturer-spec.js +++ b/spec/api-desktop-capturer-spec.js @@ -1,33 +1,31 @@ const assert = require('assert') -const desktopCapturer = require('electron').desktopCapturer +const {desktopCapturer, remote} = require('electron') -const isCI = require('electron').remote.getGlobal('isCi') +const isCI = remote.getGlobal('isCi') -describe('desktopCapturer', function () { - if (isCI && process.platform === 'win32') { - return - } +describe('desktopCapturer', () => { + if (isCI && process.platform === 'win32') return - it('should return a non-empty array of sources', function (done) { + it('should return a non-empty array of sources', (done) => { desktopCapturer.getSources({ types: ['window', 'screen'] - }, function (error, sources) { + }, (error, sources) => { assert.equal(error, null) assert.notEqual(sources.length, 0) done() }) }) - it('throws an error for invalid options', function (done) { - desktopCapturer.getSources(['window', 'screen'], function (error) { + it('throws an error for invalid options', (done) => { + desktopCapturer.getSources(['window', 'screen'], (error) => { assert.equal(error.message, 'Invalid options') done() }) }) - it('does not throw an error when called more than once (regression)', function (done) { - var callCount = 0 - var callback = function (error, sources) { + it('does not throw an error when called more than once (regression)', (done) => { + let callCount = 0 + const callback = (error, sources) => { callCount++ assert.equal(error, null) assert.notEqual(sources.length, 0) @@ -38,9 +36,9 @@ describe('desktopCapturer', function () { desktopCapturer.getSources({types: ['window', 'screen']}, callback) }) - it('responds to subsequest calls of different options', function (done) { - var callCount = 0 - var callback = function (error, sources) { + it('responds to subsequest calls of different options', (done) => { + let callCount = 0 + const callback = (error, sources) => { callCount++ assert.equal(error, null) if (callCount === 2) done() From 13fc080213db58aa1bb6c014cd008303d6939bf4 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:49:21 -0400 Subject: [PATCH 101/185] small tweaks to global shortcut spec --- spec/api-global-shortcut-spec.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/spec/api-global-shortcut-spec.js b/spec/api-global-shortcut-spec.js index 2031d4556fa..3d200d6ad85 100644 --- a/spec/api-global-shortcut-spec.js +++ b/spec/api-global-shortcut-spec.js @@ -1,12 +1,10 @@ -const {globalShortcut} = require('electron').remote +const {globalShortcut, remote} = require('electron') const assert = require('assert') -const isCI = require('electron').remote.getGlobal('isCi') +const isCI = remote.getGlobal('isCi') describe('globalShortcut module', () => { - if (isCI && process.platform === 'win32') { - return - } + if (isCI && process.platform === 'win32') return beforeEach(() => { globalShortcut.unregisterAll() From e64e9995b69e2b98923b0e217b1418ffe825bff0 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:53:47 -0400 Subject: [PATCH 102/185] small tweak to process spec --- spec/api-process-spec.js | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/spec/api-process-spec.js b/spec/api-process-spec.js index 5f4ad1730bc..954b75eeb2b 100644 --- a/spec/api-process-spec.js +++ b/spec/api-process-spec.js @@ -1,19 +1,18 @@ const assert = require('assert') -describe('process module', function () { - describe('process.getCPUUsage()', function () { - it('returns a cpu usage object', function () { +describe('process module', () => { + describe('process.getCPUUsage()', () => { + it('returns a cpu usage object', () => { const cpuUsage = process.getCPUUsage() assert.equal(typeof cpuUsage.percentCPUUsage, 'number') assert.equal(typeof cpuUsage.idleWakeupsPerSecond, 'number') }) }) - describe('process.getIOCounters()', function () { - it('returns an io counters object', function () { - if (process.platform === 'darwin') { - return - } + describe('process.getIOCounters()', () => { + it('returns an io counters object', () => { + if (process.platform === 'darwin') return + const ioCounters = process.getIOCounters() assert.equal(typeof ioCounters.readOperationCount, 'number') assert.equal(typeof ioCounters.writeOperationCount, 'number') From d8f2183b3d6c5cff8e7c9a99793b8eb4b95c8864 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:55:07 -0400 Subject: [PATCH 103/185] upgrade screen spec --- spec/api-screen-spec.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/spec/api-screen-spec.js b/spec/api-screen-spec.js index 93d048acf49..b69a836ec31 100644 --- a/spec/api-screen-spec.js +++ b/spec/api-screen-spec.js @@ -1,31 +1,29 @@ const assert = require('assert') -const screen = require('electron').screen +const {screen} = require('electron') -describe('screen module', function () { - describe('screen.getCursorScreenPoint()', function () { - it('returns a point object', function () { - var point = screen.getCursorScreenPoint() +describe('screen module', () => { + describe('screen.getCursorScreenPoint()', () => { + it('returns a point object', () => { + const point = screen.getCursorScreenPoint() assert.equal(typeof point.x, 'number') assert.equal(typeof point.y, 'number') }) }) - describe('screen.getPrimaryDisplay()', function () { - it('returns a display object', function () { - var display = screen.getPrimaryDisplay() + describe('screen.getPrimaryDisplay()', () => { + it('returns a display object', () => { + const display = screen.getPrimaryDisplay() assert.equal(typeof display.scaleFactor, 'number') assert(display.size.width > 0) assert(display.size.height > 0) }) }) - describe('screen.getMenuBarHeight()', function () { - if (process.platform !== 'darwin') { - return - } + describe('screen.getMenuBarHeight()', () => { + if (process.platform !== 'darwin') return - it('returns an integer', function () { - var screenHeight = screen.getMenuBarHeight() + it('returns an integer', () => { + const screenHeight = screen.getMenuBarHeight() assert.equal(typeof screenHeight, 'number') }) }) From 1130ccf69b48ec6a57e66cde4a9a6dfd24b73f8a Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 20:58:48 -0400 Subject: [PATCH 104/185] upgrade system pref spec --- spec/api-system-preferences-spec.js | 41 +++++++++++------------------ 1 file changed, 16 insertions(+), 25 deletions(-) diff --git a/spec/api-system-preferences-spec.js b/spec/api-system-preferences-spec.js index afcb5d1f9e2..020d6ad5c01 100644 --- a/spec/api-system-preferences-spec.js +++ b/spec/api-system-preferences-spec.js @@ -2,41 +2,37 @@ const assert = require('assert') const {remote} = require('electron') const {systemPreferences} = remote -describe('systemPreferences module', function () { - describe('systemPreferences.getAccentColor', function () { - if (process.platform !== 'win32') { - return - } +describe('systemPreferences module', () => { + describe('systemPreferences.getAccentColor', () => { + if (process.platform !== 'win32') return - it('should return a non-empty string', function () { + it('should return a non-empty string', () => { let accentColor = systemPreferences.getAccentColor() assert.notEqual(accentColor, null) assert(accentColor.length > 0) }) }) - describe('systemPreferences.getColor(id)', function () { - if (process.platform !== 'win32') { - return - } + describe('systemPreferences.getColor(id)', () => { + if (process.platform !== 'win32') return - it('throws an error when the id is invalid', function () { - assert.throws(function () { + it('throws an error when the id is invalid', () => { + assert.throws(() => { systemPreferences.getColor('not-a-color') }, /Unknown color: not-a-color/) }) - it('returns a hex RGB color string', function () { + it('returns a hex RGB color string', () => { assert.equal(/^#[0-9A-F]{6}$/i.test(systemPreferences.getColor('window')), true) }) }) - describe('systemPreferences.getUserDefault(key, type)', function () { + describe('systemPreferences.getUserDefault(key, type)', () => { if (process.platform !== 'darwin') { return } - it('returns values for known user defaults', function () { + it('returns values for known user defaults', () => { const locale = systemPreferences.getUserDefault('AppleLocale', 'string') assert.equal(typeof locale, 'string') assert(locale.length > 0) @@ -46,7 +42,7 @@ describe('systemPreferences module', function () { assert(languages.length > 0) }) - it('returns values for unknown user defaults', function () { + it('returns values for unknown user defaults', () => { assert.equal(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'boolean'), false) assert.equal(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'integer'), 0) assert.equal(systemPreferences.getUserDefault('UserDefaultDoesNotExist', 'float'), 0) @@ -60,12 +56,9 @@ describe('systemPreferences module', function () { }) describe('systemPreferences.setUserDefault(key, type, value)', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return const KEY = 'SystemPreferencesTest' - const TEST_CASES = [ ['string', 'abc'], ['boolean', true], @@ -101,9 +94,7 @@ describe('systemPreferences module', function () { }) describe('systemPreferences.setUserDefault(key, type, value)', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return it('removes keys', () => { const KEY = 'SystemPreferencesTest' @@ -117,8 +108,8 @@ describe('systemPreferences module', function () { }) }) - describe('systemPreferences.isInvertedColorScheme()', function () { - it('returns a boolean', function () { + describe('systemPreferences.isInvertedColorScheme()', () => { + it('returns a boolean', () => { assert.equal(typeof systemPreferences.isInvertedColorScheme(), 'boolean') }) }) From 0317189213d24cd663732d2ea5f683b7be1896ff Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 21:08:47 -0400 Subject: [PATCH 105/185] update touch bar spec --- spec/api-touch-bar-spec.js | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/spec/api-touch-bar-spec.js b/spec/api-touch-bar-spec.js index 6177e3cb85f..18dd414f688 100644 --- a/spec/api-touch-bar-spec.js +++ b/spec/api-touch-bar-spec.js @@ -6,22 +6,22 @@ const {closeWindow} = require('./window-helpers') const {TouchBarButton, TouchBarColorPicker, TouchBarGroup} = TouchBar const {TouchBarLabel, TouchBarPopover, TouchBarScrubber, TouchBarSegmentedControl, TouchBarSlider, TouchBarSpacer} = TouchBar -describe('TouchBar module', function () { - it('throws an error when created without an options object', function () { +describe('TouchBar module', () => { + it('throws an error when created without an options object', () => { assert.throws(() => { const touchBar = new TouchBar() touchBar.toString() }, /Must specify options object as first argument/) }) - it('throws an error when created with invalid items', function () { + it('throws an error when created with invalid items', () => { assert.throws(() => { const touchBar = new TouchBar({items: [1, true, {}, []]}) touchBar.toString() }, /Each item must be an instance of TouchBarItem/) }) - it('throws an error when an invalid escape item is set', function () { + it('throws an error when an invalid escape item is set', () => { assert.throws(() => { const touchBar = new TouchBar({items: [], escapeItem: 'esc'}) touchBar.toString() @@ -33,19 +33,19 @@ describe('TouchBar module', function () { }, /Escape item must be an instance of TouchBarItem/) }) - describe('BrowserWindow behavior', function () { + describe('BrowserWindow behavior', () => { let window - beforeEach(function () { + beforeEach(() => { window = new BrowserWindow() }) - afterEach(function () { + afterEach(() => { window.setTouchBar(null) - return closeWindow(window).then(function () { window = null }) + return closeWindow(window).then(() => { window = null }) }) - it('can be added to and removed from a window', function () { + it('can be added to and removed from a window', () => { const label = new TouchBarLabel({label: 'bar'}) const touchBar = new TouchBar([ new TouchBarButton({label: 'foo', backgroundColor: '#F00', click: () => {}}), @@ -73,9 +73,7 @@ describe('TouchBar module', function () { showArrowButtons: true }) ]) - const escapeButton = new TouchBarButton({ - label: 'foo' - }) + const escapeButton = new TouchBarButton({label: 'foo'}) window.setTouchBar(touchBar) touchBar.escapeItem = escapeButton label.label = 'baz' @@ -85,7 +83,7 @@ describe('TouchBar module', function () { touchBar.escapeItem = null }) - it('calls the callback on the items when a window interaction event fires', function (done) { + it('calls the callback on the items when a window interaction event fires', (done) => { const button = new TouchBarButton({ label: 'bar', click: () => { @@ -97,7 +95,7 @@ describe('TouchBar module', function () { window.emit('-touch-bar-interaction', {}, button.id) }) - it('calls the callback on the escape item when a window interaction event fires', function (done) { + it('calls the callback on the escape item when a window interaction event fires', (done) => { const button = new TouchBarButton({ label: 'bar', click: () => { From abecde05724e5cbde413f14864659d6923988e75 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 21:41:06 -0400 Subject: [PATCH 106/185] fix shortcut spec error --- spec/api-global-shortcut-spec.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/api-global-shortcut-spec.js b/spec/api-global-shortcut-spec.js index 3d200d6ad85..b89890903f4 100644 --- a/spec/api-global-shortcut-spec.js +++ b/spec/api-global-shortcut-spec.js @@ -1,9 +1,9 @@ -const {globalShortcut, remote} = require('electron') +const {globalShortcut} = require('electron').remote + const assert = require('assert') +const isCI = require('electron').remote.getGlobal('isCi') -const isCI = remote.getGlobal('isCi') - -describe('globalShortcut module', () => { +describe.only('globalShortcut module', () => { if (isCI && process.platform === 'win32') return beforeEach(() => { From 7a3efd1543c63868ccf3cf9946045a31e5b47dc0 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 21:41:29 -0400 Subject: [PATCH 107/185] stop leaving onlys there --- spec/api-global-shortcut-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-global-shortcut-spec.js b/spec/api-global-shortcut-spec.js index b89890903f4..d6204ace109 100644 --- a/spec/api-global-shortcut-spec.js +++ b/spec/api-global-shortcut-spec.js @@ -3,7 +3,7 @@ const {globalShortcut} = require('electron').remote const assert = require('assert') const isCI = require('electron').remote.getGlobal('isCi') -describe.only('globalShortcut module', () => { +describe('globalShortcut module', () => { if (isCI && process.platform === 'win32') return beforeEach(() => { From eed54a18c48928332466a455021aece4bffbc906 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 26 Oct 2017 22:09:38 -0400 Subject: [PATCH 108/185] fix comment typo --- spec/api-clipboard-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-clipboard-spec.js b/spec/api-clipboard-spec.js index 2c50ef3821f..e9a5c58fee9 100644 --- a/spec/api-clipboard-spec.js +++ b/spec/api-clipboard-spec.js @@ -8,7 +8,7 @@ describe('clipboard module', () => { const fixtures = path.resolve(__dirname, 'fixtures') describe('clipboard.readImage()', () => { - it('returns NativeImage intance', () => { + it('returns NativeImage instance', () => { const p = path.join(fixtures, 'assets', 'logo.png') const i = nativeImage.createFromPath(p) clipboard.writeImage(p) From 85ef4c6d91a24e1d0c9bfe9a69837668781bf904 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Fri, 27 Oct 2017 16:08:15 +1300 Subject: [PATCH 109/185] Ensure the click event is only dispatched on ContentsClicked activation type --- brightray/browser/mac/notification_center_delegate.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/brightray/browser/mac/notification_center_delegate.mm b/brightray/browser/mac/notification_center_delegate.mm index 834b9e5ee43..d8a8c901834 100644 --- a/brightray/browser/mac/notification_center_delegate.mm +++ b/brightray/browser/mac/notification_center_delegate.mm @@ -33,7 +33,7 @@ notification->NotificationReplied([notif.response.string UTF8String]); } else if (notif.activationType == NSUserNotificationActivationTypeActionButtonClicked) { notification->NotificationButtonClicked(); - } else { + } else if (notif.activationType == NSUserNotificationActivationTypeContentsClicked) { notification->NotificationClicked(); } } From fe9069c02806fc7dabc8a9b599f4f725b3a755eb Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Fri, 27 Oct 2017 16:22:21 +1300 Subject: [PATCH 110/185] Close the previous notification on multiple calls to show --- atom/browser/api/atom_api_notification.cc | 9 +++++++++ docs/api/notification.md | 4 ++++ 2 files changed, 13 insertions(+) diff --git a/atom/browser/api/atom_api_notification.cc b/atom/browser/api/atom_api_notification.cc index ef5b9ce1296..d7da05a1fe8 100644 --- a/atom/browser/api/atom_api_notification.cc +++ b/atom/browser/api/atom_api_notification.cc @@ -175,8 +175,16 @@ void Notification::NotificationDestroyed() { void Notification::NotificationClosed() { } +void Notification::Close() { + if (notification_) { + notification_->Dismiss(); + notification_.reset(); + } +} + // Showing notifications void Notification::Show() { + Close(); if (presenter_) { notification_ = presenter_->CreateNotification(this); if (notification_) { @@ -207,6 +215,7 @@ void Notification::BuildPrototype(v8::Isolate* isolate, mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) .MakeDestroyable() .SetMethod("show", &Notification::Show) + .SetMethod("close", &Notification::Close) .SetProperty("title", &Notification::GetTitle, &Notification::SetTitle) .SetProperty("subtitle", &Notification::GetSubtitle, &Notification::SetSubtitle) diff --git a/docs/api/notification.md b/docs/api/notification.md index 402bbb69db7..f0b39e7b6b5 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -104,6 +104,10 @@ HTML5 Notification implementation, simply instantiating a `new Notification` doe not immediately show it to the user, you need to call this method before the OS will display it. +#### `notification.close()` + +Dismisses the notification + ### Playing Sounds On macOS, you can specify the name of the sound you'd like to play when the From 8719e9f09813755a6395ab7ec0959baec68de9a8 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Fri, 27 Oct 2017 16:27:37 +1300 Subject: [PATCH 111/185] Definitely didn't forget to push the header file --- atom/browser/api/atom_api_notification.h | 1 + 1 file changed, 1 insertion(+) diff --git a/atom/browser/api/atom_api_notification.h b/atom/browser/api/atom_api_notification.h index d4679e7c2c9..50197350bc5 100644 --- a/atom/browser/api/atom_api_notification.h +++ b/atom/browser/api/atom_api_notification.h @@ -45,6 +45,7 @@ class Notification : public mate::TrackableObject, ~Notification() override; void Show(); + void Close(); // Prop Getters base::string16 GetTitle() const; From ca8f45a5019432fbe76f03390eae6b969e603bd2 Mon Sep 17 00:00:00 2001 From: Matt Crocker Date: Mon, 23 Oct 2017 22:37:03 -0700 Subject: [PATCH 112/185] Notifications should emit close on close, not eventual GC --- atom/browser/api/atom_api_notification.cc | 2 +- docs/api/notification.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/atom_api_notification.cc b/atom/browser/api/atom_api_notification.cc index ef5b9ce1296..7db7dbf38ac 100644 --- a/atom/browser/api/atom_api_notification.cc +++ b/atom/browser/api/atom_api_notification.cc @@ -169,10 +169,10 @@ void Notification::NotificationDisplayed() { } void Notification::NotificationDestroyed() { - Emit("close"); } void Notification::NotificationClosed() { + Emit("close"); } // Showing notifications diff --git a/docs/api/notification.md b/docs/api/notification.md index 402bbb69db7..9c041a76cef 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -74,7 +74,7 @@ Returns: Emitted when the notification is closed by manual intervention from the user. -This event is not guarunteed to be emitted in all cases where the notification +This event is not guaranteed to be emitted in all cases where the notification is closed. #### Event: 'reply' _macOS_ From c5914516c851b3d3948c4d98c88c3b3f289b1bed Mon Sep 17 00:00:00 2001 From: Matt Crocker Date: Mon, 23 Oct 2017 22:38:55 -0700 Subject: [PATCH 113/185] Upstream good ideas from Muon --- atom/browser/api/event_emitter.h | 7 +++++-- atom/browser/api/trackable_object.h | 5 ++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/atom/browser/api/event_emitter.h b/atom/browser/api/event_emitter.h index ead3beddaac..cf580cc53be 100644 --- a/atom/browser/api/event_emitter.h +++ b/atom/browser/api/event_emitter.h @@ -79,8 +79,11 @@ class EventEmitter : public Wrappable { const Args&... args) { v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); - v8::Local event = internal::CreateJSEvent( - isolate(), GetWrapper(), sender, message); + v8::Local wrapper = GetWrapper(); + if (wrapper.IsEmpty()) + return false; + v8::Local event = internal::CreateJSEvent( + isolate(), wrapper, sender, message); return EmitWithEvent(name, event, args...); } diff --git a/atom/browser/api/trackable_object.h b/atom/browser/api/trackable_object.h index e632f52b84c..f9225924d05 100644 --- a/atom/browser/api/trackable_object.h +++ b/atom/browser/api/trackable_object.h @@ -62,7 +62,10 @@ class TrackableObject : public TrackableObjectBase, public: // Mark the JS object as destroyed. void MarkDestroyed() { - Wrappable::GetWrapper()->SetAlignedPointerInInternalField(0, nullptr); + v8::Local wrapper = Wrappable::GetWrapper(); + if (!wrapper.IsEmpty()) { + Wrappable::GetWrapper()->SetAlignedPointerInInternalField(0, nullptr); + } } bool IsDestroyed() { From 77a26882a30a3dbd20987b5fc98ec34575c618d2 Mon Sep 17 00:00:00 2001 From: Matt Crocker Date: Mon, 23 Oct 2017 22:58:43 -0700 Subject: [PATCH 114/185] Make linter happy --- atom/browser/api/event_emitter.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/atom/browser/api/event_emitter.h b/atom/browser/api/event_emitter.h index cf580cc53be..f5a8025e860 100644 --- a/atom/browser/api/event_emitter.h +++ b/atom/browser/api/event_emitter.h @@ -80,9 +80,10 @@ class EventEmitter : public Wrappable { v8::Locker locker(isolate()); v8::HandleScope handle_scope(isolate()); v8::Local wrapper = GetWrapper(); - if (wrapper.IsEmpty()) + if (wrapper.IsEmpty()) { return false; - v8::Local event = internal::CreateJSEvent( + } + v8::Local event = internal::CreateJSEvent( isolate(), wrapper, sender, message); return EmitWithEvent(name, event, args...); } From b6fb016a9a720d633cb312f5801e326f0a0565ca Mon Sep 17 00:00:00 2001 From: Matt Crocker Date: Fri, 27 Oct 2017 00:07:54 -0700 Subject: [PATCH 115/185] Cleanup per review comment --- atom/browser/api/trackable_object.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/api/trackable_object.h b/atom/browser/api/trackable_object.h index f9225924d05..6fcde898a67 100644 --- a/atom/browser/api/trackable_object.h +++ b/atom/browser/api/trackable_object.h @@ -64,7 +64,7 @@ class TrackableObject : public TrackableObjectBase, void MarkDestroyed() { v8::Local wrapper = Wrappable::GetWrapper(); if (!wrapper.IsEmpty()) { - Wrappable::GetWrapper()->SetAlignedPointerInInternalField(0, nullptr); + wrapper->SetAlignedPointerInInternalField(0, nullptr); } } From 42da83f8ca0d15d57e3c3a9b8aaa6a932560f55e Mon Sep 17 00:00:00 2001 From: Matt Crocker Date: Fri, 27 Oct 2017 00:11:16 -0700 Subject: [PATCH 116/185] Update native-mate to pick up related changes --- vendor/native_mate | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vendor/native_mate b/vendor/native_mate index f047bb61bbd..bf92fa88b73 160000 --- a/vendor/native_mate +++ b/vendor/native_mate @@ -1 +1 @@ -Subproject commit f047bb61bbd985079dd93e7ed322999550efed1d +Subproject commit bf92fa88b735b8c9ff951e6ef78a531bd10e8778 From 541b36917559bd2639c16746c9e010184e494b40 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Fri, 27 Oct 2017 11:44:41 -0700 Subject: [PATCH 117/185] :construction_worker: Add a spec --- spec/api-browser-view-spec.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js index 9e2078ff727..6debec2a768 100644 --- a/spec/api-browser-view-spec.js +++ b/spec/api-browser-view-spec.js @@ -90,6 +90,21 @@ describe('BrowserView module', () => { }) }) + describe('BrowserWindow.getBrowserView()', () => { + it('returns the set view', () => { + view = new BrowserView() + w.setBrowserView(view) + assert.notEqual(view.id, null) + let view2 = w.getBrowserView() + assert.equal(view2.webContents.id, view.webContents.id) + }) + + it('returns null if none is set', () => { + let view = w.getBrowserView() + assert.equal(null, view) + }) + }) + describe('BrowserView.webContents.getOwnerBrowserWindow()', () => { it('points to owning window', () => { view = new BrowserView() From 29a85bc928a0c2e9b3523d6bae2131f0a74db0fa Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Fri, 27 Oct 2017 11:44:48 -0700 Subject: [PATCH 118/185] :memo: Document it --- docs/api/browser-window.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index e2b7c3f048d..8d61d518f76 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1443,6 +1443,10 @@ removed in future Electron releases. * `browserView` [BrowserView](browser-view.md) +#### `win.getBrowserView()` _Experimental_ + +Returns `BrowserView` - an attached BrowserView. Returns `null` if none is attached. + **Note:** The BrowserView API is currently experimental and may change or be removed in future Electron releases. From 7bad679a69f558270ba366aadee89a87a1effb9a Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Fri, 27 Oct 2017 12:14:09 -0700 Subject: [PATCH 119/185] :memo: Correct types --- docs/api/browser-window.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 8d61d518f76..acd141695ac 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -1445,7 +1445,7 @@ removed in future Electron releases. #### `win.getBrowserView()` _Experimental_ -Returns `BrowserView` - an attached BrowserView. Returns `null` if none is attached. +Returns `BrowserView | null` - an attached BrowserView. Returns `null` if none is attached. **Note:** The BrowserView API is currently experimental and may change or be removed in future Electron releases. From 2e487adf8aaf56f1cbccefd47a35877d8ec652e5 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Fri, 27 Oct 2017 12:17:30 -0700 Subject: [PATCH 120/185] :memo: Add a line to the docs --- docs/api/notification.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/api/notification.md b/docs/api/notification.md index f0b39e7b6b5..c73678d7984 100644 --- a/docs/api/notification.md +++ b/docs/api/notification.md @@ -104,9 +104,12 @@ HTML5 Notification implementation, simply instantiating a `new Notification` doe not immediately show it to the user, you need to call this method before the OS will display it. +If the notification has been shown before, this method will dismiss the previously +shown notification and create a new one with identical properties. + #### `notification.close()` -Dismisses the notification +Dismisses the notification. ### Playing Sounds From e4214a6cbe084f6e038d955ae0a61df9394cd486 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Fri, 27 Oct 2017 16:45:58 -0400 Subject: [PATCH 121/185] [WIP] Upgrade more specs (#10945) Finish upgrading specs to ES6 --- spec/api-app-spec.js | 255 +++++------ spec/api-ipc-spec.js | 232 +++++----- spec/api-menu-spec.js | 92 ++-- spec/api-net-spec.js | 539 +++++++++++----------- spec/api-session-spec.js | 406 ++++++++--------- spec/api-web-contents-spec.js | 128 +++--- spec/api-web-request-spec.js | 301 +++++------- spec/chromium-spec.js | 589 +++++++++++------------- spec/modules-spec.js | 72 ++- spec/node-spec.js | 210 +++++---- spec/webview-spec.js | 833 ++++++++++++++++------------------ 11 files changed, 1712 insertions(+), 1945 deletions(-) diff --git a/spec/api-app-spec.js b/spec/api-app-spec.js index 58925deca48..5624c319bf3 100644 --- a/spec/api-app-spec.js +++ b/spec/api-app-spec.js @@ -11,17 +11,17 @@ const {app, BrowserWindow, ipcMain} = remote const isCI = remote.getGlobal('isCi') -describe('electron module', function () { - it('does not expose internal modules to require', function () { - assert.throws(function () { +describe('electron module', () => { + it('does not expose internal modules to require', () => { + assert.throws(() => { require('clipboard') }, /Cannot find module 'clipboard'/) }) - describe('require("electron")', function () { + describe('require("electron")', () => { let window = null - beforeEach(function () { + beforeEach(() => { window = new BrowserWindow({ show: false, width: 400, @@ -29,24 +29,22 @@ describe('electron module', function () { }) }) - afterEach(function () { - return closeWindow(window).then(function () { window = null }) + afterEach(() => { + return closeWindow(window).then(() => { window = null }) }) - it('always returns the internal electron module', function (done) { - ipcMain.once('answer', function () { - done() - }) - window.loadURL('file://' + path.join(__dirname, 'fixtures', 'api', 'electron-module-app', 'index.html')) + it('always returns the internal electron module', (done) => { + ipcMain.once('answer', () => done()) + window.loadURL(`file://${path.join(__dirname, 'fixtures', 'api', 'electron-module-app', 'index.html')}`) }) }) }) -describe('app module', function () { +describe('app module', () => { let server, secureUrl const certPath = path.join(__dirname, 'fixtures', 'certificates') - before(function () { + before(() => { const options = { key: fs.readFileSync(path.join(certPath, 'server.key')), cert: fs.readFileSync(path.join(certPath, 'server.pem')), @@ -58,7 +56,7 @@ describe('app module', function () { rejectUnauthorized: false } - server = https.createServer(options, function (req, res) { + server = https.createServer(options, (req, res) => { if (req.client.authorized) { res.writeHead(200) res.end('authorized') @@ -68,24 +66,24 @@ describe('app module', function () { } }) - server.listen(0, '127.0.0.1', function () { + server.listen(0, '127.0.0.1', () => { const port = server.address().port secureUrl = `https://127.0.0.1:${port}` }) }) - after(function () { + after(() => { server.close() }) - describe('app.getVersion()', function () { - it('returns the version field of package.json', function () { + describe('app.getVersion()', () => { + it('returns the version field of package.json', () => { assert.equal(app.getVersion(), '0.1.0') }) }) - describe('app.setVersion(version)', function () { - it('overrides the version', function () { + describe('app.setVersion(version)', () => { + it('overrides the version', () => { assert.equal(app.getVersion(), '0.1.0') app.setVersion('test-version') assert.equal(app.getVersion(), 'test-version') @@ -93,14 +91,14 @@ describe('app module', function () { }) }) - describe('app.getName()', function () { - it('returns the name field of package.json', function () { + describe('app.getName()', () => { + it('returns the name field of package.json', () => { assert.equal(app.getName(), 'Electron Test') }) }) - describe('app.setName(name)', function () { - it('overrides the name', function () { + describe('app.setName(name)', () => { + it('overrides the name', () => { assert.equal(app.getName(), 'Electron Test') app.setName('test-name') assert.equal(app.getName(), 'test-name') @@ -108,36 +106,35 @@ describe('app module', function () { }) }) - describe('app.getLocale()', function () { - it('should not be empty', function () { + describe('app.getLocale()', () => { + it('should not be empty', () => { assert.notEqual(app.getLocale(), '') }) }) - describe('app.isInApplicationsFolder()', function () { - it('should be false during tests', function () { + describe('app.isInApplicationsFolder()', () => { + it('should be false during tests', () => { if (process.platform !== 'darwin') return - assert.equal(app.isInApplicationsFolder(), false) }) }) - describe('app.exit(exitCode)', function () { - var appProcess = null + describe('app.exit(exitCode)', () => { + let appProcess = null - afterEach(function () { + afterEach(() => { if (appProcess != null) appProcess.kill() }) - it('emits a process exit event with the code', function (done) { - var appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app') - var electronPath = remote.getGlobal('process').execPath - var output = '' + it('emits a process exit event with the code', (done) => { + const appPath = path.join(__dirname, 'fixtures', 'api', 'quit-app') + const electronPath = remote.getGlobal('process').execPath + let output = '' appProcess = ChildProcess.spawn(electronPath, [appPath]) - appProcess.stdout.on('data', function (data) { + appProcess.stdout.on('data', (data) => { output += data }) - appProcess.on('close', function (code) { + appProcess.on('close', (code) => { if (process.platform !== 'win32') { assert.notEqual(output.indexOf('Exit event with code: 123'), -1) } @@ -146,7 +143,7 @@ describe('app module', function () { }) }) - it('closes all windows', function (done) { + it('closes all windows', (done) => { var appPath = path.join(__dirname, 'fixtures', 'api', 'exit-closes-all-windows-app') var electronPath = remote.getGlobal('process').execPath appProcess = ChildProcess.spawn(electronPath, [appPath]) @@ -157,7 +154,7 @@ describe('app module', function () { }) }) - describe('app.makeSingleInstance', function () { + describe('app.makeSingleInstance', () => { it('prevents the second launch of app', function (done) { this.timeout(120000) const appPath = path.join(__dirname, 'fixtures', 'api', 'singleton') @@ -178,11 +175,11 @@ describe('app module', function () { }) }) - describe('app.relaunch', function () { + describe('app.relaunch', () => { let server = null const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-app-relaunch' : '/tmp/electron-app-relaunch' - beforeEach(function (done) { + beforeEach((done) => { fs.unlink(socketPath, () => { server = net.createServer() server.listen(socketPath) @@ -190,14 +187,12 @@ describe('app module', function () { }) }) - afterEach(function (done) { + afterEach((done) => { server.close(() => { if (process.platform === 'win32') { done() } else { - fs.unlink(socketPath, () => { - done() - }) + fs.unlink(socketPath, () => done()) } }) }) @@ -206,11 +201,9 @@ describe('app module', function () { this.timeout(120000) let state = 'none' - server.once('error', (error) => { - done(error) - }) + server.once('error', (error) => done(error)) server.on('connection', (client) => { - client.once('data', function (data) { + client.once('data', (data) => { if (String(data) === 'false' && state === 'none') { state = 'first-launch' } else if (String(data) === 'true' && state === 'first-launch') { @@ -226,42 +219,36 @@ describe('app module', function () { }) }) - describe('app.setUserActivity(type, userInfo)', function () { - if (process.platform !== 'darwin') { - return - } + describe('app.setUserActivity(type, userInfo)', () => { + if (process.platform !== 'darwin') return - it('sets the current activity', function () { + it('sets the current activity', () => { app.setUserActivity('com.electron.testActivity', {testData: '123'}) assert.equal(app.getCurrentActivityType(), 'com.electron.testActivity') }) }) - xdescribe('app.importCertificate', function () { + xdescribe('app.importCertificate', () => { if (process.platform !== 'linux') return var w = null - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - it('can import certificate into platform cert store', function (done) { + it('can import certificate into platform cert store', (done) => { let options = { certificate: path.join(certPath, 'client.p12'), password: 'electron' } - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) - w.webContents.on('did-finish-load', function () { + w.webContents.on('did-finish-load', () => { assert.equal(w.webContents.getTitle(), 'authorized') done() }) - ipcRenderer.once('select-client-certificate', function (event, webContentsId, list) { + ipcRenderer.once('select-client-certificate', (event, webContentsId, list) => { assert.equal(webContentsId, w.webContents.id) assert.equal(list.length, 1) assert.equal(list[0].issuerName, 'Intermediate CA') @@ -271,7 +258,7 @@ describe('app module', function () { event.sender.send('client-certificate-response', list[0]) }) - app.importCertificate(options, function (result) { + app.importCertificate(options, (result) => { assert(!result) ipcRenderer.sendSync('set-client-certificate-option', false) w.loadURL(secureUrl) @@ -279,79 +266,69 @@ describe('app module', function () { }) }) - describe('BrowserWindow events', function () { - var w = null + describe('BrowserWindow events', () => { + let w = null - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - it('should emit browser-window-focus event when window is focused', function (done) { - app.once('browser-window-focus', function (e, window) { + it('should emit browser-window-focus event when window is focused', (done) => { + app.once('browser-window-focus', (e, window) => { assert.equal(w.id, window.id) done() }) - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) w.emit('focus') }) - it('should emit browser-window-blur event when window is blured', function (done) { - app.once('browser-window-blur', function (e, window) { + it('should emit browser-window-blur event when window is blured', (done) => { + app.once('browser-window-blur', (e, window) => { assert.equal(w.id, window.id) done() }) - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) w.emit('blur') }) - it('should emit browser-window-created event when window is created', function (done) { - app.once('browser-window-created', function (e, window) { - setImmediate(function () { + it('should emit browser-window-created event when window is created', (done) => { + app.once('browser-window-created', (e, window) => { + setImmediate(() => { assert.equal(w.id, window.id) done() }) }) - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) }) - it('should emit web-contents-created event when a webContents is created', function (done) { - app.once('web-contents-created', function (e, webContents) { - setImmediate(function () { + it('should emit web-contents-created event when a webContents is created', (done) => { + app.once('web-contents-created', (e, webContents) => { + setImmediate(() => { assert.equal(w.webContents.id, webContents.id) done() }) }) - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) }) }) - describe('app.setBadgeCount API', function () { + describe('app.setBadgeCount API', () => { const shouldFail = process.platform === 'win32' || (process.platform === 'linux' && !app.isUnityRunning()) - afterEach(function () { + afterEach(() => { app.setBadgeCount(0) }) - it('returns false when failed', function () { + it('returns false when failed', () => { assert.equal(app.setBadgeCount(42), !shouldFail) }) - it('should set a badge count', function () { + it('should set a badge count', () => { app.setBadgeCount(42) assert.equal(app.getBadgeCount(), shouldFail ? 0 : 42) }) }) - describe('app.get/setLoginItemSettings API', function () { + describe('app.get/setLoginItemSettings API', () => { if (process.platform === 'linux') return const updateExe = path.resolve(path.dirname(process.execPath), '..', 'Update.exe') @@ -360,17 +337,17 @@ describe('app module', function () { '--process-start-args', `"--hidden"` ] - beforeEach(function () { + beforeEach(() => { app.setLoginItemSettings({openAtLogin: false}) app.setLoginItemSettings({openAtLogin: false, path: updateExe, args: processStartArgs}) }) - afterEach(function () { + afterEach(() => { app.setLoginItemSettings({openAtLogin: false}) app.setLoginItemSettings({openAtLogin: false, path: updateExe, args: processStartArgs}) }) - it('returns the login item status of the app', function () { + it('returns the login item status of the app', () => { app.setLoginItemSettings({openAtLogin: true}) assert.deepEqual(app.getLoginItemSettings(), { openAtLogin: true, @@ -409,35 +386,35 @@ describe('app module', function () { }) }) - describe('isAccessibilitySupportEnabled API', function () { - it('returns whether the Chrome has accessibility APIs enabled', function () { + describe('isAccessibilitySupportEnabled API', () => { + it('returns whether the Chrome has accessibility APIs enabled', () => { assert.equal(typeof app.isAccessibilitySupportEnabled(), 'boolean') }) }) - describe('getPath(name)', function () { - it('returns paths that exist', function () { + describe('getPath(name)', () => { + it('returns paths that exist', () => { assert.equal(fs.existsSync(app.getPath('exe')), true) assert.equal(fs.existsSync(app.getPath('home')), true) assert.equal(fs.existsSync(app.getPath('temp')), true) }) - it('throws an error when the name is invalid', function () { - assert.throws(function () { + it('throws an error when the name is invalid', () => { + assert.throws(() => { app.getPath('does-not-exist') }, /Failed to get 'does-not-exist' path/) }) - it('returns the overridden path', function () { + it('returns the overridden path', () => { app.setPath('music', __dirname) assert.equal(app.getPath('music'), __dirname) }) }) - xdescribe('select-client-certificate event', function () { + xdescribe('select-client-certificate event', () => { let w = null - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({ show: false, webPreferences: { @@ -446,12 +423,10 @@ describe('app module', function () { }) }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - it('can respond with empty certificate list', function (done) { - w.webContents.on('did-finish-load', function () { + it('can respond with empty certificate list', (done) => { + w.webContents.on('did-finish-load', () => { assert.equal(w.webContents.getTitle(), 'denied') server.close() done() @@ -498,7 +473,7 @@ describe('app module', function () { }) }) - describe('getFileIcon() API', function () { + describe('getFileIcon() API', () => { // FIXME Get these specs running on Linux CI if (process.platform === 'linux' && isCI) return @@ -509,16 +484,16 @@ describe('app module', function () { large: process.platform === 'win32' ? 32 : 48 } - it('fetches a non-empty icon', function (done) { - app.getFileIcon(iconPath, function (err, icon) { + it('fetches a non-empty icon', (done) => { + app.getFileIcon(iconPath, (err, icon) => { assert.equal(err, null) assert.equal(icon.isEmpty(), false) done() }) }) - it('fetches normal icon size by default', function (done) { - app.getFileIcon(iconPath, function (err, icon) { + it('fetches normal icon size by default', (done) => { + app.getFileIcon(iconPath, (err, icon) => { const size = icon.getSize() assert.equal(err, null) assert.equal(size.height, sizes.normal) @@ -527,9 +502,9 @@ describe('app module', function () { }) }) - describe('size option', function () { - it('fetches a small icon', function (done) { - app.getFileIcon(iconPath, { size: 'small' }, function (err, icon) { + describe('size option', () => { + it('fetches a small icon', (done) => { + app.getFileIcon(iconPath, { size: 'small' }, (err, icon) => { const size = icon.getSize() assert.equal(err, null) assert.equal(size.height, sizes.small) @@ -538,7 +513,7 @@ describe('app module', function () { }) }) - it('fetches a normal icon', function (done) { + it('fetches a normal icon', (done) => { app.getFileIcon(iconPath, { size: 'normal' }, function (err, icon) { const size = icon.getSize() assert.equal(err, null) @@ -548,7 +523,7 @@ describe('app module', function () { }) }) - it('fetches a large icon', function (done) { + it('fetches a large icon', (done) => { // macOS does not support large icons if (process.platform === 'darwin') return done() @@ -563,8 +538,8 @@ describe('app module', function () { }) }) - describe('getAppMetrics() API', function () { - it('returns memory and cpu stats of all running electron processes', function () { + describe('getAppMetrics() API', () => { + it('returns memory and cpu stats of all running electron processes', () => { const appMetrics = app.getAppMetrics() assert.ok(appMetrics.length > 0, 'App memory info object is not > 0') const types = [] @@ -588,15 +563,15 @@ describe('app module', function () { }) }) - describe('getGPUFeatureStatus() API', function () { - it('returns the graphic features statuses', function () { + describe('getGPUFeatureStatus() API', () => { + it('returns the graphic features statuses', () => { const features = app.getGPUFeatureStatus() assert.equal(typeof features.webgl, 'string') assert.equal(typeof features.gpu_compositing, 'string') }) }) - describe('mixed sandbox option', function () { + describe('mixed sandbox option', () => { // FIXME Get these specs running on Linux if (process.platform === 'linux') return @@ -604,7 +579,7 @@ describe('app module', function () { let server = null const socketPath = process.platform === 'win32' ? '\\\\.\\pipe\\electron-mixed-sandbox' : '/tmp/electron-mixed-sandbox' - beforeEach(function (done) { + beforeEach((done) => { fs.unlink(socketPath, () => { server = net.createServer() server.listen(socketPath) @@ -612,18 +587,14 @@ describe('app module', function () { }) }) - afterEach(function (done) { - if (appProcess != null) { - appProcess.kill() - } + afterEach((done) => { + if (appProcess != null) appProcess.kill() server.close(() => { if (process.platform === 'win32') { done() } else { - fs.unlink(socketPath, () => { - done() - }) + fs.unlink(socketPath, () => done()) } }) }) @@ -680,9 +651,9 @@ describe('app module', function () { }) }) - describe('disableDomainBlockingFor3DAPIs() API', function () { - it('throws when called after app is ready', function () { - assert.throws(function () { + describe('disableDomainBlockingFor3DAPIs() API', () => { + it('throws when called after app is ready', () => { + assert.throws(() => { app.disableDomainBlockingFor3DAPIs() }, /before app is ready/) }) diff --git a/spec/api-ipc-spec.js b/spec/api-ipc-spec.js index fb4278d180f..79f7c092703 100644 --- a/spec/api-ipc-spec.js +++ b/spec/api-ipc-spec.js @@ -8,7 +8,7 @@ const {closeWindow} = require('./window-helpers') const {ipcRenderer, remote} = require('electron') const {ipcMain, webContents, BrowserWindow} = remote -const comparePaths = function (path1, path2) { +const comparePaths = (path1, path2) => { if (process.platform === 'win32') { path1 = path1.toLowerCase() path2 = path2.toLowerCase() @@ -16,29 +16,27 @@ const comparePaths = function (path1, path2) { assert.equal(path1, path2) } -describe('ipc module', function () { - var fixtures = path.join(__dirname, 'fixtures') +describe('ipc module', () => { + const fixtures = path.join(__dirname, 'fixtures') - var w = null + let w = null - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - describe('remote.require', function () { - it('should returns same object for the same module', function () { - var dialog1 = remote.require('electron') - var dialog2 = remote.require('electron') + describe('remote.require', () => { + it('should returns same object for the same module', () => { + const dialog1 = remote.require('electron') + const dialog2 = remote.require('electron') assert.equal(dialog1, dialog2) }) - it('should work when object contains id property', function () { - var a = remote.require(path.join(fixtures, 'module', 'id.js')) + it('should work when object contains id property', () => { + const a = remote.require(path.join(fixtures, 'module', 'id.js')) assert.equal(a.id, 1127) }) - it('should work when object has no prototype', function () { - var a = remote.require(path.join(fixtures, 'module', 'no-prototype.js')) + it('should work when object has no prototype', () => { + const a = remote.require(path.join(fixtures, 'module', 'no-prototype.js')) assert.equal(a.foo.constructor.name, '') assert.equal(a.foo.bar, 'baz') assert.equal(a.foo.baz, false) @@ -48,13 +46,13 @@ describe('ipc module', function () { assert.equal(a.getConstructorName(new (class {})()), '') }) - it('should search module from the user app', function () { + it('should search module from the user app', () => { comparePaths(path.normalize(remote.process.mainModule.filename), path.resolve(__dirname, 'static', 'main.js')) comparePaths(path.normalize(remote.process.mainModule.paths[0]), path.resolve(__dirname, 'static', 'node_modules')) }) - it('should work with function properties', function () { - var a = remote.require(path.join(fixtures, 'module', 'export-function-with-properties.js')) + it('should work with function properties', () => { + let a = remote.require(path.join(fixtures, 'module', 'export-function-with-properties.js')) assert.equal(typeof a, 'function') assert.equal(a.bar, 'baz') @@ -75,36 +73,36 @@ describe('ipc module', function () { assert.equal(a.bar.baz, undefined) }) - it('should work with static class members', function () { - var a = remote.require(path.join(fixtures, 'module', 'remote-static.js')) + it('should work with static class members', () => { + const a = remote.require(path.join(fixtures, 'module', 'remote-static.js')) assert.equal(typeof a.Foo, 'function') assert.equal(a.Foo.foo(), 3) assert.equal(a.Foo.bar, 'baz') - var foo = new a.Foo() + const foo = new a.Foo() assert.equal(foo.baz(), 123) }) - it('includes the length of functions specified as arguments', function () { - var a = remote.require(path.join(fixtures, 'module', 'function-with-args.js')) - assert.equal(a(function (a, b, c, d, f) {}), 5) + it('includes the length of functions specified as arguments', () => { + const a = remote.require(path.join(fixtures, 'module', 'function-with-args.js')) + assert.equal(a((a, b, c, d, f) => {}), 5) assert.equal(a((a) => {}), 1) assert.equal(a((...args) => {}), 0) }) - it('handles circular references in arrays and objects', function () { - var a = remote.require(path.join(fixtures, 'module', 'circular.js')) + it('handles circular references in arrays and objects', () => { + const a = remote.require(path.join(fixtures, 'module', 'circular.js')) - var arrayA = ['foo'] - var arrayB = [arrayA, 'bar'] + let arrayA = ['foo'] + const arrayB = [arrayA, 'bar'] arrayA.push(arrayB) assert.deepEqual(a.returnArgs(arrayA, arrayB), [ ['foo', [null, 'bar']], [['foo', null], 'bar'] ]) - var objectA = {foo: 'bar'} - var objectB = {baz: objectA} + let objectA = {foo: 'bar'} + const objectB = {baz: objectA} objectA.objectB = objectB assert.deepEqual(a.returnArgs(objectA, objectB), [ {foo: 'bar', objectB: {baz: null}}, @@ -145,35 +143,35 @@ describe('ipc module', function () { }) }) - describe('remote.createFunctionWithReturnValue', function () { - it('should be called in browser synchronously', function () { - var buf = new Buffer('test') - var call = remote.require(path.join(fixtures, 'module', 'call.js')) - var result = call.call(remote.createFunctionWithReturnValue(buf)) + describe('remote.createFunctionWithReturnValue', () => { + it('should be called in browser synchronously', () => { + const buf = new Buffer('test') + const call = remote.require(path.join(fixtures, 'module', 'call.js')) + const result = call.call(remote.createFunctionWithReturnValue(buf)) assert.equal(result.constructor.name, 'Buffer') }) }) - describe('remote modules', function () { - it('includes browser process modules as properties', function () { + describe('remote modules', () => { + it('includes browser process modules as properties', () => { assert.equal(typeof remote.app.getPath, 'function') assert.equal(typeof remote.webContents.getFocusedWebContents, 'function') assert.equal(typeof remote.clipboard.readText, 'function') assert.equal(typeof remote.shell.openExternal, 'function') }) - it('returns toString() of original function via toString()', function () { + it('returns toString() of original function via toString()', () => { const {readText} = remote.clipboard assert(readText.toString().startsWith('function')) - var {functionWithToStringProperty} = remote.require(path.join(fixtures, 'module', 'to-string-non-function.js')) + const {functionWithToStringProperty} = remote.require(path.join(fixtures, 'module', 'to-string-non-function.js')) assert.equal(functionWithToStringProperty.toString, 'hello') }) }) - describe('remote object in renderer', function () { - it('can change its properties', function () { - var property = remote.require(path.join(fixtures, 'module', 'property.js')) + describe('remote object in renderer', () => { + it('can change its properties', () => { + const property = remote.require(path.join(fixtures, 'module', 'property.js')) assert.equal(property.property, 1127) property.property = null @@ -188,70 +186,70 @@ describe('ipc module', function () { assert.equal(property.getFunctionProperty(), 'bar-browser') property.func.property = 'foo' // revert back - var property2 = remote.require(path.join(fixtures, 'module', 'property.js')) + const property2 = remote.require(path.join(fixtures, 'module', 'property.js')) assert.equal(property2.property, 1007) property.property = 1127 }) - it('rethrows errors getting/setting properties', function () { + it('rethrows errors getting/setting properties', () => { const foo = remote.require(path.join(fixtures, 'module', 'error-properties.js')) - assert.throws(function () { + assert.throws(() => { foo.bar }, /getting error/) - assert.throws(function () { + assert.throws(() => { foo.bar = 'test' }, /setting error/) }) - it('can set a remote property with a remote object', function () { + it('can set a remote property with a remote object', () => { const foo = remote.require(path.join(fixtures, 'module', 'remote-object-set.js')) - assert.doesNotThrow(function () { + assert.doesNotThrow(() => { foo.bar = remote.getCurrentWindow() }) }) - it('can construct an object from its member', function () { - var call = remote.require(path.join(fixtures, 'module', 'call.js')) - var obj = new call.constructor() + it('can construct an object from its member', () => { + const call = remote.require(path.join(fixtures, 'module', 'call.js')) + const obj = new call.constructor() assert.equal(obj.test, 'test') }) - it('can reassign and delete its member functions', function () { - var remoteFunctions = remote.require(path.join(fixtures, 'module', 'function.js')) + it('can reassign and delete its member functions', () => { + const remoteFunctions = remote.require(path.join(fixtures, 'module', 'function.js')) assert.equal(remoteFunctions.aFunction(), 1127) - remoteFunctions.aFunction = function () { return 1234 } + remoteFunctions.aFunction = () => { return 1234 } assert.equal(remoteFunctions.aFunction(), 1234) assert.equal(delete remoteFunctions.aFunction, true) }) - it('is referenced by its members', function () { + it('is referenced by its members', () => { let stringify = remote.getGlobal('JSON').stringify global.gc() stringify({}) }) }) - describe('remote value in browser', function () { + describe('remote value in browser', () => { const print = path.join(fixtures, 'module', 'print_name.js') const printName = remote.require(print) - it('keeps its constructor name for objects', function () { + it('keeps its constructor name for objects', () => { const buf = new Buffer('test') assert.equal(printName.print(buf), 'Buffer') }) - it('supports instanceof Date', function () { + it('supports instanceof Date', () => { const now = new Date() assert.equal(printName.print(now), 'Date') assert.deepEqual(printName.echo(now), now) }) - it('supports instanceof Buffer', function () { + it('supports instanceof Buffer', () => { const buffer = Buffer.from('test') assert.ok(buffer.equals(printName.echo(buffer))) @@ -262,7 +260,7 @@ describe('ipc module', function () { assert.ok(arrayWithBuffer[2].equals(printName.echo(arrayWithBuffer)[2])) }) - it('supports TypedArray', function () { + it('supports TypedArray', () => { const values = [1, 2, 3, 4] assert.deepEqual(printName.typedArray(values), values) @@ -271,93 +269,93 @@ describe('ipc module', function () { }) }) - describe('remote promise', function () { - it('can be used as promise in each side', function (done) { - var promise = remote.require(path.join(fixtures, 'module', 'promise.js')) - promise.twicePromise(Promise.resolve(1234)).then(function (value) { + describe('remote promise', () => { + it('can be used as promise in each side', (done) => { + const promise = remote.require(path.join(fixtures, 'module', 'promise.js')) + promise.twicePromise(Promise.resolve(1234)).then((value) => { assert.equal(value, 2468) done() }) }) - it('handles rejections via catch(onRejected)', function (done) { - var promise = remote.require(path.join(fixtures, 'module', 'rejected-promise.js')) - promise.reject(Promise.resolve(1234)).catch(function (error) { + it('handles rejections via catch(onRejected)', (done) => { + const promise = remote.require(path.join(fixtures, 'module', 'rejected-promise.js')) + promise.reject(Promise.resolve(1234)).catch((error) => { assert.equal(error.message, 'rejected') done() }) }) - it('handles rejections via then(onFulfilled, onRejected)', function (done) { - var promise = remote.require(path.join(fixtures, 'module', 'rejected-promise.js')) - promise.reject(Promise.resolve(1234)).then(function () {}, function (error) { + it('handles rejections via then(onFulfilled, onRejected)', (done) => { + const promise = remote.require(path.join(fixtures, 'module', 'rejected-promise.js')) + promise.reject(Promise.resolve(1234)).then(() => {}, (error) => { assert.equal(error.message, 'rejected') done() }) }) - it('does not emit unhandled rejection events in the main process', function (done) { + it('does not emit unhandled rejection events in the main process', (done) => { remote.process.once('unhandledRejection', function (reason) { done(reason) }) - var promise = remote.require(path.join(fixtures, 'module', 'unhandled-rejection.js')) - promise.reject().then(function () { + const promise = remote.require(path.join(fixtures, 'module', 'unhandled-rejection.js')) + promise.reject().then(() => { done(new Error('Promise was not rejected')) - }).catch(function (error) { + }).catch((error) => { assert.equal(error.message, 'rejected') done() }) }) - it('emits unhandled rejection events in the renderer process', function (done) { + it('emits unhandled rejection events in the renderer process', (done) => { window.addEventListener('unhandledrejection', function (event) { event.preventDefault() assert.equal(event.reason.message, 'rejected') done() }) - var promise = remote.require(path.join(fixtures, 'module', 'unhandled-rejection.js')) - promise.reject().then(function () { + const promise = remote.require(path.join(fixtures, 'module', 'unhandled-rejection.js')) + promise.reject().then(() => { done(new Error('Promise was not rejected')) }) }) }) - describe('remote webContents', function () { - it('can return same object with different getters', function () { - var contents1 = remote.getCurrentWindow().webContents - var contents2 = remote.getCurrentWebContents() + describe('remote webContents', () => { + it('can return same object with different getters', () => { + const contents1 = remote.getCurrentWindow().webContents + const contents2 = remote.getCurrentWebContents() assert(contents1 === contents2) }) }) - describe('remote class', function () { - let cl = remote.require(path.join(fixtures, 'module', 'class.js')) - let base = cl.base + describe('remote class', () => { + const cl = remote.require(path.join(fixtures, 'module', 'class.js')) + const base = cl.base let derived = cl.derived - it('can get methods', function () { + it('can get methods', () => { assert.equal(base.method(), 'method') }) - it('can get properties', function () { + it('can get properties', () => { assert.equal(base.readonly, 'readonly') }) - it('can change properties', function () { + it('can change properties', () => { assert.equal(base.value, 'old') base.value = 'new' assert.equal(base.value, 'new') base.value = 'old' }) - it('has unenumerable methods', function () { + it('has unenumerable methods', () => { assert(!base.hasOwnProperty('method')) assert(Object.getPrototypeOf(base).hasOwnProperty('method')) }) - it('keeps prototype chain in derived class', function () { + it('keeps prototype chain in derived class', () => { assert.equal(derived.method(), 'method') assert.equal(derived.readonly, 'readonly') assert(!derived.hasOwnProperty('method')) @@ -366,7 +364,7 @@ describe('ipc module', function () { assert(Object.getPrototypeOf(proto).hasOwnProperty('method')) }) - it('is referenced by methods in prototype chain', function () { + it('is referenced by methods in prototype chain', () => { let method = derived.method derived = null global.gc() @@ -374,9 +372,9 @@ describe('ipc module', function () { }) }) - describe('ipc.sender.send', function () { - it('should work when sending an object containing id property', function (done) { - var obj = { + describe('ipc.sender.send', () => { + it('should work when sending an object containing id property', (done) => { + const obj = { id: 1, name: 'ly' } @@ -387,7 +385,7 @@ describe('ipc module', function () { ipcRenderer.send('message', obj) }) - it('can send instances of Date', function (done) { + it('can send instances of Date', (done) => { const currentDate = new Date() ipcRenderer.once('message', function (event, value) { assert.equal(value, currentDate.toISOString()) @@ -396,7 +394,7 @@ describe('ipc module', function () { ipcRenderer.send('message', currentDate) }) - it('can send instances of Buffer', function (done) { + it('can send instances of Buffer', (done) => { const buffer = Buffer.from('hello') ipcRenderer.once('message', function (event, message) { assert.ok(buffer.equals(message)) @@ -405,7 +403,7 @@ describe('ipc module', function () { ipcRenderer.send('message', buffer) }) - it('can send objects with DOM class prototypes', function (done) { + it('can send objects with DOM class prototypes', (done) => { ipcRenderer.once('message', function (event, value) { assert.equal(value.protocol, 'file:') assert.equal(value.hostname, '') @@ -414,7 +412,7 @@ describe('ipc module', function () { ipcRenderer.send('message', document.location) }) - it('can send Electron API objects', function (done) { + it('can send Electron API objects', (done) => { const webContents = remote.getCurrentWebContents() ipcRenderer.once('message', function (event, value) { assert.deepEqual(value.browserWindowOptions, webContents.browserWindowOptions) @@ -423,10 +421,10 @@ describe('ipc module', function () { ipcRenderer.send('message', webContents) }) - it('does not crash on external objects (regression)', function (done) { + it('does not crash on external objects (regression)', (done) => { const request = http.request({port: 5000, hostname: '127.0.0.1', method: 'GET', path: '/'}) const stream = request.agent.sockets['127.0.0.1:5000:'][0]._handle._externalStream - request.on('error', function () {}) + request.on('error', () => {}) ipcRenderer.once('message', function (event, requestValue, externalStreamValue) { assert.equal(requestValue.method, 'GET') assert.equal(requestValue.path, '/') @@ -437,7 +435,7 @@ describe('ipc module', function () { ipcRenderer.send('message', request, stream) }) - it('can send objects that both reference the same object', function (done) { + it('can send objects that both reference the same object', (done) => { const child = {hello: 'world'} const foo = {name: 'foo', child: child} const bar = {name: 'bar', child: child} @@ -453,7 +451,7 @@ describe('ipc module', function () { ipcRenderer.send('message', array, foo, bar, child) }) - it('inserts null for cyclic references', function (done) { + it('inserts null for cyclic references', (done) => { const array = [5] array.push(array) @@ -473,17 +471,17 @@ describe('ipc module', function () { }) }) - describe('ipc.sendSync', function () { - afterEach(function () { + describe('ipc.sendSync', () => { + afterEach(() => { ipcMain.removeAllListeners('send-sync-message') }) - it('can be replied by setting event.returnValue', function () { - var msg = ipcRenderer.sendSync('echo', 'test') + it('can be replied by setting event.returnValue', () => { + const msg = ipcRenderer.sendSync('echo', 'test') assert.equal(msg, 'test') }) - it('does not crash when reply is not sent and browser is destroyed', function (done) { + it('does not crash when reply is not sent and browser is destroyed', (done) => { w = new BrowserWindow({ show: false }) @@ -494,7 +492,7 @@ describe('ipc module', function () { w.loadURL('file://' + path.join(fixtures, 'api', 'send-sync-message.html')) }) - it('does not crash when reply is sent by multiple listeners', function (done) { + it('does not crash when reply is sent by multiple listeners', (done) => { w = new BrowserWindow({ show: false }) @@ -509,36 +507,36 @@ describe('ipc module', function () { }) }) - describe('ipcRenderer.sendTo', function () { + describe('ipcRenderer.sendTo', () => { let contents = null - beforeEach(function () { + beforeEach(() => { contents = webContents.create({}) }) - afterEach(function () { + afterEach(() => { ipcRenderer.removeAllListeners('pong') contents.destroy() contents = null }) - it('sends message to WebContents', function (done) { + it('sends message to WebContents', (done) => { const webContentsId = remote.getCurrentWebContents().id ipcRenderer.once('pong', function (event, id) { assert.equal(webContentsId, id) done() }) - contents.once('did-finish-load', function () { + contents.once('did-finish-load', () => { ipcRenderer.sendTo(contents.id, 'ping', webContentsId) }) contents.loadURL('file://' + path.join(fixtures, 'pages', 'ping-pong.html')) }) }) - describe('remote listeners', function () { - it('can be added and removed correctly', function () { + describe('remote listeners', () => { + it('can be added and removed correctly', () => { w = new BrowserWindow({ show: false }) - var listener = function () {} + const listener = () => {} w.on('test', listener) assert.equal(w.listenerCount('test'), 1) w.removeListener('test', listener) @@ -592,8 +590,8 @@ describe('ipc module', function () { assert.equal(ipcRenderer.listenerCount('test-event'), 0) }) - describe('remote objects registry', function () { - it('does not dereference until the render view is deleted (regression)', function (done) { + describe('remote objects registry', () => { + it('does not dereference until the render view is deleted (regression)', (done) => { w = new BrowserWindow({ show: false }) diff --git a/spec/api-menu-spec.js b/spec/api-menu-spec.js index 2c422b340dc..560af5c05a4 100644 --- a/spec/api-menu-spec.js +++ b/spec/api-menu-spec.js @@ -4,9 +4,9 @@ const {ipcRenderer, remote} = require('electron') const {BrowserWindow, Menu, MenuItem} = remote const {closeWindow} = require('./window-helpers') -describe('menu module', function () { - describe('Menu.buildFromTemplate', function () { - it('should be able to attach extra fields', function () { +describe('Menu module', () => { + describe('Menu.buildFromTemplate', () => { + it('should be able to attach extra fields', () => { const menu = Menu.buildFromTemplate([ { label: 'text', @@ -16,7 +16,7 @@ describe('menu module', function () { assert.equal(menu.items[0].extra, 'field') }) - it('does not modify the specified template', function () { + it('does not modify the specified template', () => { const template = ipcRenderer.sendSync('eval', "var template = [{label: 'text', submenu: [{label: 'sub'}]}];\nrequire('electron').Menu.buildFromTemplate(template);\ntemplate;") assert.deepStrictEqual(template, [ { @@ -30,8 +30,8 @@ describe('menu module', function () { ]) }) - it('does not throw exceptions for undefined/null values', function () { - assert.doesNotThrow(function () { + it('does not throw exceptions for undefined/null values', () => { + assert.doesNotThrow(() => { Menu.buildFromTemplate([ { label: 'text', @@ -45,8 +45,8 @@ describe('menu module', function () { }) }) - describe('Menu.buildFromTemplate should reorder based on item position specifiers', function () { - it('should position before existing item', function () { + describe('Menu.buildFromTemplate should reorder based on item position specifiers', () => { + it('should position before existing item', () => { const menu = Menu.buildFromTemplate([ { label: '2', @@ -65,7 +65,7 @@ describe('menu module', function () { assert.equal(menu.items[2].label, '3') }) - it('should position after existing item', function () { + it('should position after existing item', () => { const menu = Menu.buildFromTemplate([ { label: '1', @@ -84,7 +84,7 @@ describe('menu module', function () { assert.equal(menu.items[2].label, '3') }) - it('should position at endof existing separator groups', function () { + it('should position at endof existing separator groups', () => { const menu = Menu.buildFromTemplate([ { type: 'separator', @@ -128,7 +128,7 @@ describe('menu module', function () { assert.equal(menu.items[7].label, 'c') }) - it('should create separator group if endof does not reference existing separator group', function () { + it('should create separator group if endof does not reference existing separator group', () => { const menu = Menu.buildFromTemplate([ { label: 'a', @@ -166,7 +166,7 @@ describe('menu module', function () { assert.equal(menu.items[7].label, '3') }) - it('should continue inserting items at next index when no specifier is present', function () { + it('should continue inserting items at next index when no specifier is present', () => { const menu = Menu.buildFromTemplate([ { label: '4', @@ -195,8 +195,8 @@ describe('menu module', function () { }) }) - describe('Menu.getMenuItemById', function () { - it('should return the item with the given id', function () { + describe('Menu.getMenuItemById', () => { + it('should return the item with the given id', () => { const menu = Menu.buildFromTemplate([ { label: 'View', @@ -218,8 +218,8 @@ describe('menu module', function () { }) }) - describe('Menu.insert', function () { - it('should store item in @items by its index', function () { + describe('Menu.insert', () => { + it('should store item in @items by its index', () => { const menu = Menu.buildFromTemplate([ { label: '1' @@ -240,8 +240,8 @@ describe('menu module', function () { }) }) - describe('Menu.append', function () { - it('should add the item to the end of the menu', function () { + describe('Menu.append', () => { + it('should add the item to the end of the menu', () => { const menu = Menu.buildFromTemplate([ { label: '1' @@ -261,7 +261,7 @@ describe('menu module', function () { }) }) - describe('Menu.popup', function () { + describe('Menu.popup', () => { let w = null let menu @@ -279,18 +279,18 @@ describe('menu module', function () { }) afterEach(() => { - return closeWindow(w).then(function () { w = null }) + return closeWindow(w).then(() => { w = null }) }) - describe('when called with async: true', function () { - it('returns immediately', function () { + describe('when called with async: true', () => { + it('returns immediately', () => { menu.popup(w, {x: 100, y: 100, async: true}) menu.closePopup(w) }) }) }) - describe('Menu.setApplicationMenu', function () { + describe('Menu.setApplicationMenu', () => { const menu = Menu.buildFromTemplate([ { label: '1' @@ -302,7 +302,7 @@ describe('menu module', function () { assert.notEqual(Menu.getApplicationMenu(), null) }) - describe('MenuItem.click', function () { + describe('MenuItem.click', () => { it('should be called with the item object passed', function (done) { const menu = Menu.buildFromTemplate([ { @@ -318,8 +318,8 @@ describe('menu module', function () { }) }) - describe('MenuItem with checked property', function () { - it('clicking an checkbox item should flip the checked property', function () { + describe('MenuItem with checked property', () => { + it('clicking an checkbox item should flip the checked property', () => { const menu = Menu.buildFromTemplate([ { label: 'text', @@ -331,7 +331,7 @@ describe('menu module', function () { assert.equal(menu.items[0].checked, true) }) - it('clicking an radio item should always make checked property true', function () { + it('clicking an radio item should always make checked property true', () => { const menu = Menu.buildFromTemplate([ { label: 'text', @@ -344,7 +344,7 @@ describe('menu module', function () { assert.equal(menu.items[0].checked, true) }) - it('at least have one item checked in each group', function () { + it('at least have one item checked in each group', () => { const template = [] for (let i = 0; i <= 10; i++) { template.push({ @@ -365,7 +365,7 @@ describe('menu module', function () { assert.equal(menu.items[12].checked, true) }) - it('should assign groupId automatically', function () { + it('should assign groupId automatically', () => { const template = [] for (let i = 0; i <= 10; i++) { template.push({ @@ -390,7 +390,7 @@ describe('menu module', function () { } }) - it("setting 'checked' should flip other items' 'checked' property", function () { + it("setting 'checked' should flip other items' 'checked' property", () => { const template = [] for (let i = 0; i <= 10; i++) { template.push({ @@ -435,8 +435,8 @@ describe('menu module', function () { }) }) - describe('MenuItem command id', function () { - it('cannot be overwritten', function () { + describe('MenuItem command id', () => { + it('cannot be overwritten', () => { const item = new MenuItem({label: 'item'}) const commandId = item.commandId @@ -446,8 +446,8 @@ describe('menu module', function () { }) }) - describe('MenuItem with invalid type', function () { - it('throws an exception', function () { + describe('MenuItem with invalid type', () => { + it('throws an exception', () => { assert.throws(() => { Menu.buildFromTemplate([ { @@ -459,8 +459,8 @@ describe('menu module', function () { }) }) - describe('MenuItem with submenu type and missing submenu', function () { - it('throws an exception', function () { + describe('MenuItem with submenu type and missing submenu', () => { + it('throws an exception', () => { assert.throws(() => { Menu.buildFromTemplate([ { @@ -472,8 +472,8 @@ describe('menu module', function () { }) }) - describe('MenuItem role', function () { - it('includes a default label and accelerator', function () { + describe('MenuItem role', () => { + it('includes a default label and accelerator', () => { let item = new MenuItem({role: 'close'}) assert.equal(item.label, process.platform === 'darwin' ? 'Close Window' : 'Close') assert.equal(item.accelerator, undefined) @@ -506,8 +506,8 @@ describe('menu module', function () { }) }) - describe('MenuItem editMenu', function () { - it('includes a default submenu layout when submenu is empty', function () { + describe('MenuItem editMenu', () => { + it('includes a default submenu layout when submenu is empty', () => { const item = new MenuItem({role: 'editMenu'}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'undo') @@ -530,15 +530,15 @@ describe('menu module', function () { } }) - it('overrides default layout when submenu is specified', function () { + it('overrides default layout when submenu is specified', () => { const item = new MenuItem({role: 'editMenu', submenu: [{role: 'close'}]}) assert.equal(item.label, 'Edit') assert.equal(item.submenu.items[0].role, 'close') }) }) - describe('MenuItem windowMenu', function () { - it('includes a default submenu layout when submenu is empty', function () { + describe('MenuItem windowMenu', () => { + it('includes a default submenu layout when submenu is empty', () => { const item = new MenuItem({role: 'windowMenu'}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'minimize') @@ -550,15 +550,15 @@ describe('menu module', function () { } }) - it('overrides default layout when submenu is specified', function () { + it('overrides default layout when submenu is specified', () => { const item = new MenuItem({role: 'windowMenu', submenu: [{role: 'copy'}]}) assert.equal(item.label, 'Window') assert.equal(item.submenu.items[0].role, 'copy') }) }) - describe('MenuItem with custom properties in constructor', function () { - it('preserves the custom properties', function () { + describe('MenuItem with custom properties in constructor', () => { + it('preserves the custom properties', () => { const template = [{ label: 'menu 1', customProp: 'foo', diff --git a/spec/api-net-spec.js b/spec/api-net-spec.js index 9edfbc4fc5d..69aa1154ee8 100644 --- a/spec/api-net-spec.js +++ b/spec/api-net-spec.js @@ -25,13 +25,13 @@ function randomString (length) { const kOneKiloByte = 1024 const kOneMegaByte = kOneKiloByte * kOneKiloByte -describe('net module', function () { +describe('net module', () => { let server const connections = new Set() - beforeEach(function (done) { + beforeEach((done) => { server = http.createServer() - server.listen(0, '127.0.0.1', function () { + server.listen(0, '127.0.0.1', () => { server.url = `http://127.0.0.1:${server.address().port}` done() }) @@ -43,20 +43,20 @@ describe('net module', function () { }) }) - afterEach(function (done) { + afterEach((done) => { for (const connection of connections) { connection.destroy() } - server.close(function () { + server.close(() => { server = null done() }) }) - describe('HTTP basics', function () { - it('should be able to issue a basic GET request', function (done) { + describe('HTTP basics', () => { + it('should be able to issue a basic GET request', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.method, 'GET') @@ -67,12 +67,12 @@ describe('net module', function () { } }) const urlRequest = net.request(`${server.url}${requestUrl}`) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -80,9 +80,9 @@ describe('net module', function () { urlRequest.end() }) - it('should be able to issue a basic POST request', function (done) { + it('should be able to issue a basic POST request', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.method, 'POST') @@ -96,12 +96,12 @@ describe('net module', function () { method: 'POST', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -109,10 +109,10 @@ describe('net module', function () { urlRequest.end() }) - it('should fetch correct data in a GET request', function (done) { + it('should fetch correct data in a GET request', (done) => { const requestUrl = '/requestUrl' const bodyData = 'Hello World!' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.method, 'GET') @@ -124,14 +124,14 @@ describe('net module', function () { } }) const urlRequest = net.request(`${server.url}${requestUrl}`) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { let expectedBodyData = '' assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { expectedBodyData += chunk.toString() }) - response.on('end', function () { + response.on('end', () => { assert.equal(expectedBodyData, bodyData) done() }) @@ -140,18 +140,18 @@ describe('net module', function () { urlRequest.end() }) - it('should post the correct data in a POST request', function (done) { + it('should post the correct data in a POST request', (done) => { const requestUrl = '/requestUrl' const bodyData = 'Hello World!' - server.on('request', function (request, response) { + server.on('request', (request, response) => { let postedBodyData = '' switch (request.url) { case requestUrl: assert.equal(request.method, 'POST') - request.on('data', function (chunk) { + request.on('data', (chunk) => { postedBodyData += chunk.toString() }) - request.on('end', function () { + request.on('end', () => { assert.equal(postedBodyData, bodyData) response.end() }) @@ -164,12 +164,11 @@ describe('net module', function () { method: 'POST', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { - }) - response.on('end', function () { + response.on('data', (chunk) => {}) + response.on('end', () => { done() }) response.resume() @@ -178,9 +177,9 @@ describe('net module', function () { urlRequest.end() }) - it('should support chunked encoding', function (done) { + it('should support chunked encoding', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: response.statusCode = 200 @@ -189,10 +188,10 @@ describe('net module', function () { assert.equal(request.method, 'POST') assert.equal(request.headers['transfer-encoding'], 'chunked') assert(!request.headers['content-length']) - request.on('data', function (chunk) { + request.on('data', (chunk) => { response.write(chunk) }) - request.on('end', function (chunk) { + request.on('end', (chunk) => { response.end(chunk) }) break @@ -206,16 +205,16 @@ describe('net module', function () { }) let chunkIndex = 0 - let chunkCount = 100 + const chunkCount = 100 let sentChunks = [] let receivedChunks = [] - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { receivedChunks.push(chunk) }) - response.on('end', function () { + response.on('end', () => { let sentData = Buffer.concat(sentChunks) let receivedData = Buffer.concat(receivedChunks) assert.equal(sentData.toString(), receivedData.toString()) @@ -226,8 +225,8 @@ describe('net module', function () { }) urlRequest.chunkedEncoding = true while (chunkIndex < chunkCount) { - ++chunkIndex - let chunk = randomBuffer(kOneKiloByte) + chunkIndex += 1 + const chunk = randomBuffer(kOneKiloByte) sentChunks.push(chunk) assert(urlRequest.write(chunk)) } @@ -235,15 +234,15 @@ describe('net module', function () { }) }) - describe('ClientRequest API', function () { - afterEach(function () { + describe('ClientRequest API', () => { + afterEach(() => { session.defaultSession.webRequest.onBeforeRequest(null) }) - it('request/response objects should emit expected events', function (done) { + it('request/response objects should emit expected events', (done) => { const requestUrl = '/requestUrl' - let bodyData = randomString(kOneMegaByte) - server.on('request', function (request, response) { + const bodyData = randomString(kOneMegaByte) + server.on('request', (request, response) => { switch (request.url) { case requestUrl: response.statusCode = 200 @@ -279,51 +278,51 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { requestResponseEventEmitted = true const statusCode = response.statusCode assert.equal(statusCode, 200) let buffers = [] response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { buffers.push(chunk) responseDataEventEmitted = true }) - response.on('end', function () { + response.on('end', () => { let receivedBodyData = Buffer.concat(buffers) assert(receivedBodyData.toString() === bodyData) responseEndEventEmitted = true maybeDone(done) }) response.resume() - response.on('error', function (error) { + response.on('error', (error) => { assert.ifError(error) }) - response.on('aborted', function () { + response.on('aborted', () => { assert.fail('response aborted') }) }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { requestFinishEventEmitted = true }) - urlRequest.on('error', function (error) { + urlRequest.on('error', (error) => { assert.ifError(error) }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { assert.fail('request aborted') }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true maybeDone(done) }) urlRequest.end() }) - it('should be able to set a custom HTTP request header before first write', function (done) { + it('should be able to set a custom HTTP request header before first write', (done) => { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' const customHeaderValue = 'Some-Customer-Header-Value' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.headers[customHeaderName.toLowerCase()], @@ -340,13 +339,13 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -364,11 +363,11 @@ describe('net module', function () { urlRequest.end() }) - it('should be able to set a non-string object as a header value', function (done) { + it('should be able to set a non-string object as a header value', (done) => { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Integer-Value' const customHeaderValue = 900 - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.headers[customHeaderName.toLowerCase()], @@ -385,11 +384,11 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -407,11 +406,11 @@ describe('net module', function () { urlRequest.end() }) - it('should not be able to set a custom HTTP request header after first write', function (done) { + it('should not be able to set a custom HTTP request header after first write', (done) => { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' const customHeaderValue = 'Some-Customer-Header-Value' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert(!request.headers[customHeaderName.toLowerCase()]) @@ -427,13 +426,13 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -446,11 +445,11 @@ describe('net module', function () { urlRequest.end() }) - it('should be able to remove a custom HTTP request header before first write', function (done) { + it('should be able to remove a custom HTTP request header before first write', (done) => { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' const customHeaderValue = 'Some-Customer-Header-Value' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert(!request.headers[customHeaderName.toLowerCase()]) @@ -466,13 +465,13 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -486,11 +485,11 @@ describe('net module', function () { urlRequest.end() }) - it('should not be able to remove a custom HTTP request header after first write', function (done) { + it('should not be able to remove a custom HTTP request header after first write', (done) => { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' const customHeaderValue = 'Some-Customer-Header-Value' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.headers[customHeaderName.toLowerCase()], @@ -507,13 +506,13 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -522,7 +521,7 @@ describe('net module', function () { assert.equal(urlRequest.getHeader(customHeaderName), customHeaderValue) urlRequest.write('') - assert.throws(function () { + assert.throws(() => { urlRequest.removeHeader(customHeaderName) }) assert.equal(urlRequest.getHeader(customHeaderName), @@ -530,12 +529,12 @@ describe('net module', function () { urlRequest.end() }) - it('should be able to set cookie header line', function (done) { + it('should be able to set cookie header line', (done) => { const requestUrl = '/requestUrl' const cookieHeaderName = 'Cookie' const cookieHeaderValue = 'test=12345' const customSession = session.fromPartition('test-cookie-header') - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.headers[cookieHeaderName.toLowerCase()], @@ -552,22 +551,19 @@ describe('net module', function () { url: `${server.url}`, name: 'test', value: '11111' - }, function (error) { - if (error) { - return done(error) - } + }, (error) => { + if (error) return done(error) const urlRequest = net.request({ method: 'GET', url: `${server.url}${requestUrl}`, session: customSession }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function (chunk) { - }) - response.on('end', function () { + response.on('data', (chunk) => {}) + response.on('end', () => { done() }) response.resume() @@ -579,9 +575,9 @@ describe('net module', function () { }) }) - it('should be able to abort an HTTP request before first write', function (done) { + it('should be able to abort an HTTP request before first write', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { response.end() assert.fail('Unexpected request event') }) @@ -593,19 +589,19 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.fail('Unexpected response event') }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { assert.fail('Unexpected finish event') }) - urlRequest.on('error', function () { + urlRequest.on('error', () => { assert.fail('Unexpected error event') }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { requestAbortEventEmitted = true }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true assert(requestAbortEventEmitted) assert(requestCloseEventEmitted) @@ -616,10 +612,10 @@ describe('net module', function () { urlRequest.end() }) - it('it should be able to abort an HTTP request before request end', function (done) { + it('it should be able to abort an HTTP request before request end', (done) => { const requestUrl = '/requestUrl' let requestReceivedByServer = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: requestReceivedByServer = true @@ -637,19 +633,19 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.fail('Unexpected response event') }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { assert.fail('Unexpected finish event') }) - urlRequest.on('error', function () { + urlRequest.on('error', () => { assert.fail('Unexpected error event') }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { requestAbortEventEmitted = true }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true assert(requestReceivedByServer) assert(requestAbortEventEmitted) @@ -664,10 +660,10 @@ describe('net module', function () { } }) - it('it should be able to abort an HTTP request after request end and before response', function (done) { + it('it should be able to abort an HTTP request after request end and before response', (done) => { const requestUrl = '/requestUrl' let requestReceivedByServer = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: requestReceivedByServer = true @@ -691,19 +687,19 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.fail('Unexpected response event') }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { requestFinishEventEmitted = true }) - urlRequest.on('error', function () { + urlRequest.on('error', () => { assert.fail('Unexpected error event') }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { requestAbortEventEmitted = true }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true assert(requestFinishEventEmitted) assert(requestReceivedByServer) @@ -718,10 +714,10 @@ describe('net module', function () { } }) - it('it should be able to abort an HTTP request after response start', function (done) { + it('it should be able to abort an HTTP request after response start', (done) => { const requestUrl = '/requestUrl' let requestReceivedByServer = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: requestReceivedByServer = true @@ -744,35 +740,35 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { requestResponseEventEmitted = true const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { assert.fail('Unexpected end event') }) response.resume() - response.on('error', function () { + response.on('error', () => { assert.fail('Unexpected error event') }) - response.on('aborted', function () { + response.on('aborted', () => { responseAbortedEventEmitted = true }) urlRequest.abort() }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { requestFinishEventEmitted = true }) - urlRequest.on('error', function () { + urlRequest.on('error', () => { assert.fail('Unexpected error event') }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { requestAbortEventEmitted = true }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true assert(requestFinishEventEmitted, 'request should emit "finish" event') assert(requestReceivedByServer, 'request should be received by the server') @@ -785,10 +781,10 @@ describe('net module', function () { urlRequest.end(randomString(kOneKiloByte)) }) - it('abort event should be emitted at most once', function (done) { + it('abort event should be emitted at most once', (done) => { const requestUrl = '/requestUrl' let requestReceivedByServer = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: requestReceivedByServer = true @@ -807,23 +803,23 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function () { + urlRequest.on('response', () => { assert.fail('Unexpected response event') }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { requestFinishEventEmitted = true }) - urlRequest.on('error', function () { + urlRequest.on('error', () => { assert.fail('Unexpected error event') }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { ++requestAbortEventCount urlRequest.abort() }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true // Let all pending async events to be emitted - setTimeout(function () { + setTimeout(() => { assert(requestFinishEventEmitted) assert(requestReceivedByServer) assert.equal(requestAbortEventCount, 1) @@ -839,11 +835,11 @@ describe('net module', function () { } }) - it('Requests should be intercepted by webRequest module', function (done) { + it('Requests should be intercepted by webRequest module', (done) => { const requestUrl = '/requestUrl' const redirectUrl = '/redirectUrl' let requestIsRedirected = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case redirectUrl: requestIsRedirected = true @@ -856,7 +852,7 @@ describe('net module', function () { let requestIsIntercepted = false session.defaultSession.webRequest.onBeforeRequest( - function (details, callback) { + (details, callback) => { if (details.url === `${server.url}${requestUrl}`) { requestIsIntercepted = true callback({ @@ -871,12 +867,12 @@ describe('net module', function () { const urlRequest = net.request(`${server.url}${requestUrl}`) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { assert(requestIsRedirected, 'The server should receive a request to the forward URL') assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module') done() @@ -886,12 +882,12 @@ describe('net module', function () { urlRequest.end() }) - it('should to able to create and intercept a request using a custom session object', function (done) { + it('should to able to create and intercept a request using a custom session object', (done) => { const requestUrl = '/requestUrl' const redirectUrl = '/redirectUrl' const customPartitionName = 'custom-partition' let requestIsRedirected = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case redirectUrl: requestIsRedirected = true @@ -902,39 +898,35 @@ describe('net module', function () { } }) - session.defaultSession.webRequest.onBeforeRequest( - function (details, callback) { - assert.fail('Request should not be intercepted by the default session') - }) - - let customSession = session.fromPartition(customPartitionName, { - cache: false + session.defaultSession.webRequest.onBeforeRequest((details, callback) => { + assert.fail('Request should not be intercepted by the default session') }) + + let customSession = session.fromPartition(customPartitionName, {cache: false}) let requestIsIntercepted = false - customSession.webRequest.onBeforeRequest( - function (details, callback) { - if (details.url === `${server.url}${requestUrl}`) { - requestIsIntercepted = true - callback({ - redirectURL: `${server.url}${redirectUrl}` - }) - } else { - callback({ - cancel: false - }) - } - }) + customSession.webRequest.onBeforeRequest((details, callback) => { + if (details.url === `${server.url}${requestUrl}`) { + requestIsIntercepted = true + callback({ + redirectURL: `${server.url}${redirectUrl}` + }) + } else { + callback({ + cancel: false + }) + } + }) const urlRequest = net.request({ url: `${server.url}${requestUrl}`, session: customSession }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { assert(requestIsRedirected, 'The server should receive a request to the forward URL') assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module') done() @@ -944,40 +936,40 @@ describe('net module', function () { urlRequest.end() }) - it('should throw if given an invalid redirect mode', function () { + it('should throw if given an invalid redirect mode', () => { const requestUrl = '/requestUrl' const options = { url: `${server.url}${requestUrl}`, redirect: 'custom' } - assert.throws(function () { + assert.throws(() => { net.request(options) }, 'redirect mode should be one of follow, error or manual') }) - it('should throw when calling getHeader without a name', function () { - assert.throws(function () { + it('should throw when calling getHeader without a name', () => { + assert.throws(() => { net.request({url: `${server.url}/requestUrl`}).getHeader() }, /`name` is required for getHeader\(name\)\./) - assert.throws(function () { + assert.throws(() => { net.request({url: `${server.url}/requestUrl`}).getHeader(null) }, /`name` is required for getHeader\(name\)\./) }) - it('should throw when calling removeHeader without a name', function () { - assert.throws(function () { + it('should throw when calling removeHeader without a name', () => { + assert.throws(() => { net.request({url: `${server.url}/requestUrl`}).removeHeader() }, /`name` is required for removeHeader\(name\)\./) - assert.throws(function () { + assert.throws(() => { net.request({url: `${server.url}/requestUrl`}).removeHeader(null) }, /`name` is required for removeHeader\(name\)\./) }) - it('should follow redirect when no redirect mode is provided', function (done) { + it('should follow redirect when no redirect mode is provided', (done) => { const requestUrl = '/301' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case '/301': response.statusCode = '301' @@ -995,16 +987,16 @@ describe('net module', function () { const urlRequest = net.request({ url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) done() }) urlRequest.end() }) - it('should follow redirect chain when no redirect mode is provided', function (done) { + it('should follow redirect chain when no redirect mode is provided', (done) => { const requestUrl = '/redirectChain' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case '/redirectChain': response.statusCode = '301' @@ -1027,16 +1019,16 @@ describe('net module', function () { const urlRequest = net.request({ url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) done() }) urlRequest.end() }) - it('should not follow redirect when mode is error', function (done) { + it('should not follow redirect when mode is error', (done) => { const requestUrl = '/301' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case '/301': response.statusCode = '301' @@ -1055,19 +1047,19 @@ describe('net module', function () { url: `${server.url}${requestUrl}`, redirect: 'error' }) - urlRequest.on('error', function (error) { + urlRequest.on('error', (error) => { assert.equal(error.message, 'Request cannot follow redirect with the current redirect mode') }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { done() }) urlRequest.end() }) - it('should allow follow redirect when mode is manual', function (done) { + it('should allow follow redirect when mode is manual', (done) => { const requestUrl = '/redirectChain' let redirectCount = 0 - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case '/redirectChain': response.statusCode = '301' @@ -1091,12 +1083,12 @@ describe('net module', function () { url: `${server.url}${requestUrl}`, redirect: 'manual' }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) assert.equal(redirectCount, 2) done() }) - urlRequest.on('redirect', function (status, method, url) { + urlRequest.on('redirect', (status, method, url) => { if (url === `${server.url}/301` || url === `${server.url}/200`) { redirectCount += 1 urlRequest.followRedirect() @@ -1105,10 +1097,10 @@ describe('net module', function () { urlRequest.end() }) - it('should allow cancelling redirect when mode is manual', function (done) { + it('should allow cancelling redirect when mode is manual', (done) => { const requestUrl = '/redirectChain' let redirectCount = 0 - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case '/redirectChain': response.statusCode = '301' @@ -1132,21 +1124,21 @@ describe('net module', function () { url: `${server.url}${requestUrl}`, redirect: 'manual' }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { urlRequest.abort() }) response.resume() }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { assert.equal(redirectCount, 1) done() }) - urlRequest.on('redirect', function (status, method, url) { + urlRequest.on('redirect', (status, method, url) => { if (url === `${server.url}/redirect/1`) { redirectCount += 1 urlRequest.followRedirect() @@ -1155,7 +1147,7 @@ describe('net module', function () { urlRequest.end() }) - it('should throw if given an invalid session option', function (done) { + it('should throw if given an invalid session option', (done) => { const requestUrl = '/requestUrl' try { const urlRequest = net.request({ @@ -1168,12 +1160,12 @@ describe('net module', function () { } }) - it('should to able to create and intercept a request using a custom partition name', function (done) { + it('should to able to create and intercept a request using a custom partition name', (done) => { const requestUrl = '/requestUrl' const redirectUrl = '/redirectUrl' const customPartitionName = 'custom-partition' let requestIsRedirected = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case redirectUrl: requestIsRedirected = true @@ -1184,39 +1176,37 @@ describe('net module', function () { } }) - session.defaultSession.webRequest.onBeforeRequest( - function (details, callback) { - assert.fail('Request should not be intercepted by the default session') - }) + session.defaultSession.webRequest.onBeforeRequest((details, callback) => { + assert.fail('Request should not be intercepted by the default session') + }) let customSession = session.fromPartition(customPartitionName, { cache: false }) let requestIsIntercepted = false - customSession.webRequest.onBeforeRequest( - function (details, callback) { - if (details.url === `${server.url}${requestUrl}`) { - requestIsIntercepted = true - callback({ - redirectURL: `${server.url}${redirectUrl}` - }) - } else { - callback({ - cancel: false - }) - } - }) + customSession.webRequest.onBeforeRequest((details, callback) => { + if (details.url === `${server.url}${requestUrl}`) { + requestIsIntercepted = true + callback({ + redirectURL: `${server.url}${redirectUrl}` + }) + } else { + callback({ + cancel: false + }) + } + }) const urlRequest = net.request({ url: `${server.url}${requestUrl}`, partition: customPartitionName }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { assert(requestIsRedirected, 'The server should receive a request to the forward URL') assert(requestIsIntercepted, 'The request should be intercepted by the webRequest module') done() @@ -1226,7 +1216,7 @@ describe('net module', function () { urlRequest.end() }) - it('should throw if given an invalid partition option', function (done) { + it('should throw if given an invalid partition option', (done) => { const requestUrl = '/requestUrl' try { const urlRequest = net.request({ @@ -1239,11 +1229,11 @@ describe('net module', function () { } }) - it('should be able to create a request with options', function (done) { + it('should be able to create a request with options', (done) => { const requestUrl = '/' const customHeaderName = 'Some-Custom-Header-Name' const customHeaderValue = 'Some-Customer-Header-Value' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: assert.equal(request.method, 'GET') @@ -1266,12 +1256,12 @@ describe('net module', function () { } options.headers[customHeaderName] = customHeaderValue const urlRequest = net.request(options) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert.equal(response.statusCode, 200) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -1279,13 +1269,13 @@ describe('net module', function () { urlRequest.end() }) - it('should be able to pipe a readable stream into a net request', function (done) { + it('should be able to pipe a readable stream into a net request', (done) => { const nodeRequestUrl = '/nodeRequestUrl' const netRequestUrl = '/netRequestUrl' const bodyData = randomString(kOneMegaByte) let netRequestReceived = false let netRequestEnded = false - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case nodeRequestUrl: response.write(bodyData) @@ -1294,10 +1284,10 @@ describe('net module', function () { case netRequestUrl: netRequestReceived = true let receivedBodyData = '' - request.on('data', function (chunk) { + request.on('data', (chunk) => { receivedBodyData += chunk.toString() }) - request.on('end', function (chunk) { + request.on('end', (chunk) => { netRequestEnded = true if (chunk) { receivedBodyData += chunk.toString() @@ -1312,14 +1302,13 @@ describe('net module', function () { }) let nodeRequest = http.request(`${server.url}${nodeRequestUrl}`) - nodeRequest.on('response', function (nodeResponse) { + nodeRequest.on('response', (nodeResponse) => { const netRequest = net.request(`${server.url}${netRequestUrl}`) - netRequest.on('response', function (netResponse) { + netRequest.on('response', (netResponse) => { assert.equal(netResponse.statusCode, 200) netResponse.pause() - netResponse.on('data', function (chunk) { - }) - netResponse.on('end', function () { + netResponse.on('data', (chunk) => {}) + netResponse.on('end', () => { assert(netRequestReceived) assert(netRequestEnded) done() @@ -1331,9 +1320,9 @@ describe('net module', function () { nodeRequest.end() }) - it('should emit error event on server socket close', function (done) { + it('should emit error event on server socket close', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: request.socket.destroy() @@ -1344,11 +1333,11 @@ describe('net module', function () { }) let requestErrorEventEmitted = false const urlRequest = net.request(`${server.url}${requestUrl}`) - urlRequest.on('error', function (error) { + urlRequest.on('error', (error) => { assert(error) requestErrorEventEmitted = true }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { assert(requestErrorEventEmitted) done() }) @@ -1356,12 +1345,12 @@ describe('net module', function () { }) }) - describe('IncomingMessage API', function () { - it('response object should implement the IncomingMessage API', function (done) { + describe('IncomingMessage API', () => { + it('response object should implement the IncomingMessage API', (done) => { const requestUrl = '/requestUrl' const customHeaderName = 'Some-Custom-Header-Name' const customHeaderValue = 'Some-Customer-Header-Value' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: response.statusCode = 200 @@ -1377,7 +1366,7 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { const statusCode = response.statusCode assert(typeof statusCode === 'number') assert.equal(statusCode, 200) @@ -1398,9 +1387,9 @@ describe('net module', function () { assert(typeof httpVersionMinor === 'number') assert(httpVersionMinor >= 0) response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { }) - response.on('end', function () { + response.on('end', () => { done() }) response.resume() @@ -1408,11 +1397,11 @@ describe('net module', function () { urlRequest.end() }) - it('should be able to pipe a net response into a writable stream', function (done) { + it('should be able to pipe a net response into a writable stream', (done) => { const nodeRequestUrl = '/nodeRequestUrl' const netRequestUrl = '/netRequestUrl' const bodyData = randomString(kOneMegaByte) - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case netRequestUrl: response.statusCode = 200 @@ -1422,10 +1411,10 @@ describe('net module', function () { break case nodeRequestUrl: let receivedBodyData = '' - request.on('data', function (chunk) { + request.on('data', (chunk) => { receivedBodyData += chunk.toString() }) - request.on('end', function (chunk) { + request.on('end', (chunk) => { if (chunk) { receivedBodyData += chunk.toString() } @@ -1437,7 +1426,7 @@ describe('net module', function () { handleUnexpectedURL(request, response) } }) - ipcRenderer.once('api-net-spec-done', function () { + ipcRenderer.once('api-net-spec-done', () => { done() }) // Execute below code directly within the browser context without @@ -1455,9 +1444,9 @@ describe('net module', function () { } let nodeRequest = http.request(nodeOptions) nodeRequest.on('response', function (nodeResponse) { - nodeResponse.on('data', function (chunk) { + nodeResponse.on('data', (chunk) => { }) - nodeResponse.on('end', function (chunk) { + nodeResponse.on('end', (chunk) => { event.sender.send('api-net-spec-done') }) }) @@ -1467,10 +1456,10 @@ describe('net module', function () { `) }) - it('should not emit any event after close', function (done) { + it('should not emit any event after close', (done) => { const requestUrl = '/requestUrl' let bodyData = randomString(kOneKiloByte) - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: response.statusCode = 200 @@ -1487,36 +1476,36 @@ describe('net module', function () { method: 'GET', url: `${server.url}${requestUrl}` }) - urlRequest.on('response', function (response) { + urlRequest.on('response', (response) => { assert(!requestCloseEventEmitted) const statusCode = response.statusCode assert.equal(statusCode, 200) response.pause() - response.on('data', function () { + response.on('data', () => { }) - response.on('end', function () { + response.on('end', () => { }) response.resume() - response.on('error', function () { + response.on('error', () => { assert(!requestCloseEventEmitted) }) - response.on('aborted', function () { + response.on('aborted', () => { assert(!requestCloseEventEmitted) }) }) - urlRequest.on('finish', function () { + urlRequest.on('finish', () => { assert(!requestCloseEventEmitted) }) - urlRequest.on('error', function () { + urlRequest.on('error', () => { assert(!requestCloseEventEmitted) }) - urlRequest.on('abort', function () { + urlRequest.on('abort', () => { assert(!requestCloseEventEmitted) }) - urlRequest.on('close', function () { + urlRequest.on('close', () => { requestCloseEventEmitted = true // Wait so that all async events get scheduled. - setTimeout(function () { + setTimeout(() => { done() }, 100) }) @@ -1524,16 +1513,16 @@ describe('net module', function () { }) }) - describe('Stability and performance', function (done) { - it('should free unreferenced, never-started request objects without crash', function (done) { + describe('Stability and performance', (done) => { + it('should free unreferenced, never-started request objects without crash', (done) => { const requestUrl = '/requestUrl' - ipcRenderer.once('api-net-spec-done', function () { + ipcRenderer.once('api-net-spec-done', () => { done() }) ipcRenderer.send('eval', ` const {net} = require('electron') const urlRequest = net.request('${server.url}${requestUrl}') - process.nextTick(function () { + process.nextTick(() => { const v8Util = process.atomBinding('v8_util') v8Util.requestGarbageCollectionForTesting() event.sender.send('api-net-spec-done') @@ -1541,15 +1530,15 @@ describe('net module', function () { `) }) - it('should not collect on-going requests without crash', function (done) { + it('should not collect on-going requests without crash', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: response.statusCode = 200 response.statusMessage = 'OK' response.write(randomString(kOneKiloByte)) - ipcRenderer.once('api-net-spec-resume', function () { + ipcRenderer.once('api-net-spec-resume', () => { response.write(randomString(kOneKiloByte)) response.end() }) @@ -1558,7 +1547,7 @@ describe('net module', function () { handleUnexpectedURL(request, response) } }) - ipcRenderer.once('api-net-spec-done', function () { + ipcRenderer.once('api-net-spec-done', () => { done() }) // Execute below code directly within the browser context without @@ -1566,13 +1555,13 @@ describe('net module', function () { ipcRenderer.send('eval', ` const {net} = require('electron') const urlRequest = net.request('${server.url}${requestUrl}') - urlRequest.on('response', function (response) { - response.on('data', function () { + urlRequest.on('response', (response) => { + response.on('data', () => { }) - response.on('end', function () { + response.on('end', () => { event.sender.send('api-net-spec-done') }) - process.nextTick(function () { + process.nextTick(() => { // Trigger a garbage collection. const v8Util = process.atomBinding('v8_util') v8Util.requestGarbageCollectionForTesting() @@ -1583,9 +1572,9 @@ describe('net module', function () { `) }) - it('should collect unreferenced, ended requests without crash', function (done) { + it('should collect unreferenced, ended requests without crash', (done) => { const requestUrl = '/requestUrl' - server.on('request', function (request, response) { + server.on('request', (request, response) => { switch (request.url) { case requestUrl: response.statusCode = 200 @@ -1596,20 +1585,20 @@ describe('net module', function () { handleUnexpectedURL(request, response) } }) - ipcRenderer.once('api-net-spec-done', function () { + ipcRenderer.once('api-net-spec-done', () => { done() }) ipcRenderer.send('eval', ` const {net} = require('electron') const urlRequest = net.request('${server.url}${requestUrl}') - urlRequest.on('response', function (response) { - response.on('data', function () { + urlRequest.on('response', (response) => { + response.on('data', () => { }) - response.on('end', function () { + response.on('end', () => { }) }) - urlRequest.on('close', function () { - process.nextTick(function () { + urlRequest.on('close', () => { + process.nextTick(() => { const v8Util = process.atomBinding('v8_util') v8Util.requestGarbageCollectionForTesting() event.sender.send('api-net-spec-done') diff --git a/spec/api-session-spec.js b/spec/api-session-spec.js index 51996d448b3..91432e39461 100644 --- a/spec/api-session-spec.js +++ b/spec/api-session-spec.js @@ -10,13 +10,13 @@ const {closeWindow} = require('./window-helpers') const {ipcRenderer, remote} = require('electron') const {ipcMain, session, BrowserWindow, net} = remote -describe('session module', function () { - var fixtures = path.resolve(__dirname, 'fixtures') - var w = null - var webview = null - var url = 'http://127.0.0.1' +describe('session module', () => { + let fixtures = path.resolve(__dirname, 'fixtures') + let w = null + let webview = null + const url = 'http://127.0.0.1' - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({ show: false, width: 400, @@ -24,7 +24,7 @@ describe('session module', function () { }) }) - afterEach(function () { + afterEach(() => { if (webview != null) { if (!document.body.contains(webview)) { document.body.appendChild(webview) @@ -32,21 +32,21 @@ describe('session module', function () { webview.remove() } - return closeWindow(w).then(function () { w = null }) + return closeWindow(w).then(() => { w = null }) }) - describe('session.defaultSession', function () { - it('returns the default session', function () { + describe('session.defaultSession', () => { + it('returns the default session', () => { assert.equal(session.defaultSession, session.fromPartition('')) }) }) - describe('session.fromPartition(partition, options)', function () { - it('returns existing session with same partition', function () { + describe('session.fromPartition(partition, options)', () => { + it('returns existing session with same partition', () => { assert.equal(session.fromPartition('test'), session.fromPartition('test')) }) - it('created session is ref-counted', function () { + it('created session is ref-counted', () => { const partition = 'test2' const userAgent = 'test-agent' const ses1 = session.fromPartition(partition) @@ -58,104 +58,83 @@ describe('session module', function () { }) }) - describe('ses.cookies', function () { - it('should get cookies', function (done) { - var server = http.createServer(function (req, res) { + describe('ses.cookies', () => { + it('should get cookies', (done) => { + const server = http.createServer((req, res) => { res.setHeader('Set-Cookie', ['0=0']) res.end('finished') server.close() }) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - w.loadURL(url + ':' + port) - w.webContents.on('did-finish-load', function () { - w.webContents.session.cookies.get({ - url: url - }, function (error, list) { - var cookie, i, len - if (error) { - return done(error) - } - for (i = 0, len = list.length; i < len; i++) { - cookie = list[i] + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + w.loadURL(`${url}:${port}`) + w.webContents.on('did-finish-load', () => { + w.webContents.session.cookies.get({url}, (error, list) => { + if (error) return done(error) + for (let i = 0; i < list.length; i++) { + const cookie = list[i] if (cookie.name === '0') { if (cookie.value === '0') { return done() } else { - return done('cookie value is ' + cookie.value + ' while expecting 0') + return done(`cookie value is ${cookie.value} while expecting 0`) } } } - done('Can not find cookie') + done('Can\'t find cookie') }) }) }) }) - it('calls back with an error when setting a cookie with missing required fields', function (done) { + it('calls back with an error when setting a cookie with missing required fields', (done) => { session.defaultSession.cookies.set({ url: '', name: '1', value: '1' - }, function (error) { + }, (error) => { assert.equal(error.message, 'Setting cookie failed') done() }) }) - it('should over-write the existent cookie', function (done) { + it('should over-write the existent cookie', (done) => { session.defaultSession.cookies.set({ - url: url, + url, name: '1', value: '1' - }, function (error) { - if (error) { - return done(error) - } - session.defaultSession.cookies.get({ - url: url - }, function (error, list) { - var cookie, i, len - if (error) { - return done(error) - } - for (i = 0, len = list.length; i < len; i++) { - cookie = list[i] + }, (error) => { + if (error) return done(error) + session.defaultSession.cookies.get({url}, (error, list) => { + if (error) return done(error) + for (let i = 0; i < list.length; i++) { + const cookie = list[i] if (cookie.name === '1') { if (cookie.value === '1') { return done() } else { - return done('cookie value is ' + cookie.value + ' while expecting 1') + return done(`cookie value is ${cookie.value} while expecting 1`) } } } - done('Can not find cookie') + done('Can\'t find cookie') }) }) }) - it('should remove cookies', function (done) { + it('should remove cookies', (done) => { session.defaultSession.cookies.set({ url: url, name: '2', value: '2' - }, function (error) { - if (error) { - return done(error) - } - session.defaultSession.cookies.remove(url, '2', function () { - session.defaultSession.cookies.get({ - url: url - }, function (error, list) { - var cookie, i, len - if (error) { - return done(error) - } - for (i = 0, len = list.length; i < len; i++) { - cookie = list[i] - if (cookie.name === '2') { - return done('Cookie not deleted') - } + }, (error) => { + if (error) return done(error) + session.defaultSession.cookies.remove(url, '2', () => { + session.defaultSession.cookies.get({url}, (error, list) => { + if (error) return done(error) + for (let i = 0; i < list.length; i++) { + const cookie = list[i] + if (cookie.name === '2') return done('Cookie not deleted') } done() }) @@ -163,23 +142,17 @@ describe('session module', function () { }) }) - it('should set cookie for standard scheme', function (done) { + it('should set cookie for standard scheme', (done) => { const standardScheme = remote.getGlobal('standardScheme') const origin = standardScheme + '://fake-host' session.defaultSession.cookies.set({ url: origin, name: 'custom', value: '1' - }, function (error) { - if (error) { - return done(error) - } - session.defaultSession.cookies.get({ - url: origin - }, function (error, list) { - if (error) { - return done(error) - } + }, (error) => { + if (error) return done(error) + session.defaultSession.cookies.get({url: origin}, (error, list) => { + if (error) return done(error) assert.equal(list.length, 1) assert.equal(list[0].name, 'custom') assert.equal(list[0].value, '1') @@ -189,16 +162,16 @@ describe('session module', function () { }) }) - it('emits a changed event when a cookie is added or removed', function (done) { + it('emits a changed event when a cookie is added or removed', (done) => { const {cookies} = session.fromPartition('cookies-changed') - cookies.once('changed', function (event, cookie, cause, removed) { + cookies.once('changed', (event, cookie, cause, removed) => { assert.equal(cookie.name, 'foo') assert.equal(cookie.value, 'bar') assert.equal(cause, 'explicit') assert.equal(removed, false) - cookies.once('changed', function (event, cookie, cause, removed) { + cookies.once('changed', (event, cookie, cause, removed) => { assert.equal(cookie.name, 'foo') assert.equal(cookie.value, 'bar') assert.equal(cause, 'explicit') @@ -206,7 +179,7 @@ describe('session module', function () { done() }) - cookies.remove(url, 'foo', function (error) { + cookies.remove(url, 'foo', (error) => { if (error) return done(error) }) }) @@ -215,13 +188,13 @@ describe('session module', function () { url: url, name: 'foo', value: 'bar' - }, function (error) { + }, (error) => { if (error) return done(error) }) }) - describe('ses.cookies.flushStore(callback)', function () { - it('flushes the cookies to disk and invokes the callback when done', function (done) { + describe('ses.cookies.flushStore(callback)', () => { + it('flushes the cookies to disk and invokes the callback when done', (done) => { session.defaultSession.cookies.set({ url: url, name: 'foo', @@ -236,30 +209,30 @@ describe('session module', function () { }) }) - describe('ses.clearStorageData(options)', function () { + describe('ses.clearStorageData(options)', () => { fixtures = path.resolve(__dirname, 'fixtures') - it('clears localstorage data', function (done) { - ipcMain.on('count', function (event, count) { + it('clears localstorage data', (done) => { + ipcMain.on('count', (event, count) => { ipcMain.removeAllListeners('count') assert.equal(count, 0) done() }) w.loadURL('file://' + path.join(fixtures, 'api', 'localstorage.html')) - w.webContents.on('did-finish-load', function () { - var options = { + w.webContents.on('did-finish-load', () => { + const options = { origin: 'file://', storages: ['localstorage'], quotas: ['persistent'] } - w.webContents.session.clearStorageData(options, function () { + w.webContents.session.clearStorageData(options, () => { w.webContents.send('getcount') }) }) }) }) - describe('will-download event', function () { - beforeEach(function () { + describe('will-download event', () => { + beforeEach(() => { if (w != null) w.destroy() w = new BrowserWindow({ show: false, @@ -268,10 +241,10 @@ describe('session module', function () { }) }) - it('can cancel default download behavior', function (done) { + it('can cancel default download behavior', (done) => { const mockFile = new Buffer(1024) const contentDisposition = 'inline; filename="mockFile.txt"' - const downloadServer = http.createServer(function (req, res) { + const downloadServer = http.createServer((req, res) => { res.writeHead(200, { 'Content-Length': mockFile.length, 'Content-Type': 'application/plain', @@ -281,13 +254,13 @@ describe('session module', function () { downloadServer.close() }) - downloadServer.listen(0, '127.0.0.1', function () { + downloadServer.listen(0, '127.0.0.1', () => { const port = downloadServer.address().port - const url = 'http://127.0.0.1:' + port + '/' + const url = `http://127.0.0.1:${port}/` ipcRenderer.sendSync('set-download-option', false, true) w.loadURL(url) - ipcRenderer.once('download-error', function (event, downloadUrl, filename, error) { + ipcRenderer.once('download-error', (event, downloadUrl, filename, error) => { assert.equal(downloadUrl, url) assert.equal(filename, 'mockFile.txt') assert.equal(error, 'Object has been destroyed') @@ -297,14 +270,12 @@ describe('session module', function () { }) }) - describe('DownloadItem', function () { - var mockPDF = new Buffer(1024 * 1024 * 5) - var contentDisposition = 'inline; filename="mock.pdf"' - var downloadFilePath = path.join(fixtures, 'mock.pdf') - var downloadServer = http.createServer(function (req, res) { - if (req.url === '/?testFilename') { - contentDisposition = 'inline' - } + describe('DownloadItem', () => { + const mockPDF = new Buffer(1024 * 1024 * 5) + let contentDisposition = 'inline; filename="mock.pdf"' + const downloadFilePath = path.join(fixtures, 'mock.pdf') + const downloadServer = http.createServer((req, res) => { + if (req.url === '/?testFilename') contentDisposition = 'inline' res.writeHead(200, { 'Content-Length': mockPDF.length, 'Content-Type': 'application/pdf', @@ -313,13 +284,13 @@ describe('session module', function () { res.end(mockPDF) downloadServer.close() }) - var assertDownload = function (event, state, url, mimeType, + const assertDownload = (event, state, url, mimeType, receivedBytes, totalBytes, disposition, - filename, port, savePath) { + filename, port, savePath) => { assert.equal(state, 'completed') assert.equal(filename, 'mock.pdf') assert.equal(savePath, path.join(__dirname, 'fixtures', 'mock.pdf')) - assert.equal(url, 'http://127.0.0.1:' + port + '/') + assert.equal(url, `http://127.0.0.1:${port}/`) assert.equal(mimeType, 'application/pdf') assert.equal(receivedBytes, mockPDF.length) assert.equal(totalBytes, mockPDF.length) @@ -328,15 +299,15 @@ describe('session module', function () { fs.unlinkSync(downloadFilePath) } - it('can download using WebContents.downloadURL', function (done) { - downloadServer.listen(0, '127.0.0.1', function () { - var port = downloadServer.address().port + it('can download using WebContents.downloadURL', (done) => { + downloadServer.listen(0, '127.0.0.1', () => { + const port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', false, false) - w.webContents.downloadURL(url + ':' + port) - ipcRenderer.once('download-done', function (event, state, url, + w.webContents.downloadURL(`${url}:${port}`) + ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, - filename, savePath) { + filename, savePath) => { assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath) done() @@ -344,19 +315,19 @@ describe('session module', function () { }) }) - it('can download using WebView.downloadURL', function (done) { - downloadServer.listen(0, '127.0.0.1', function () { - var port = downloadServer.address().port + it('can download using WebView.downloadURL', (done) => { + downloadServer.listen(0, '127.0.0.1', () => { + const port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', false, false) webview = new WebView() - webview.src = 'file://' + fixtures + '/api/blank.html' - webview.addEventListener('did-finish-load', function () { - webview.downloadURL(url + ':' + port + '/') + webview.src = `file://${fixtures}/api/blank.html` + webview.addEventListener('did-finish-load', () => { + webview.downloadURL(`${url}:${port}/`) }) - ipcRenderer.once('download-done', function (event, state, url, + ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, - filename, savePath) { + filename, savePath) => { assertDownload(event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, port, savePath) document.body.removeChild(webview) @@ -366,15 +337,15 @@ describe('session module', function () { }) }) - it('can cancel download', function (done) { - downloadServer.listen(0, '127.0.0.1', function () { - var port = downloadServer.address().port + it('can cancel download', (done) => { + downloadServer.listen(0, '127.0.0.1', () => { + const port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', true, false) - w.webContents.downloadURL(url + ':' + port + '/') - ipcRenderer.once('download-done', function (event, state, url, + w.webContents.downloadURL(`${url}:${port}/`) + ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, - filename) { + filename) => { assert.equal(state, 'cancelled') assert.equal(filename, 'mock.pdf') assert.equal(mimeType, 'application/pdf') @@ -386,18 +357,17 @@ describe('session module', function () { }) }) - it('can generate a default filename', function (done) { - // Somehow this test always fail on appveyor. + it('can generate a default filename', (done) => { if (process.env.APPVEYOR === 'True') return done() - downloadServer.listen(0, '127.0.0.1', function () { - var port = downloadServer.address().port + downloadServer.listen(0, '127.0.0.1', () => { + const port = downloadServer.address().port ipcRenderer.sendSync('set-download-option', true, false) - w.webContents.downloadURL(url + ':' + port + '/?testFilename') - ipcRenderer.once('download-done', function (event, state, url, + w.webContents.downloadURL(`${url}:${port}/?testFilename`) + ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, - filename) { + filename) => { assert.equal(state, 'cancelled') assert.equal(filename, 'download.pdf') assert.equal(mimeType, 'application/pdf') @@ -409,28 +379,28 @@ describe('session module', function () { }) }) - describe('when a save path is specified and the URL is unavailable', function () { - it('does not display a save dialog and reports the done state as interrupted', function (done) { + describe('when a save path is specified and the URL is unavailable', () => { + it('does not display a save dialog and reports the done state as interrupted', (done) => { ipcRenderer.sendSync('set-download-option', false, false) ipcRenderer.once('download-done', (event, state) => { assert.equal(state, 'interrupted') done() }) - w.webContents.downloadURL('file://' + path.join(__dirname, 'does-not-exist.txt')) + w.webContents.downloadURL(`file://${path.join(__dirname, 'does-not-exist.txt')}`) }) }) }) - describe('ses.protocol', function () { + describe('ses.protocol', () => { const partitionName = 'temp' const protocolName = 'sp' const partitionProtocol = session.fromPartition(partitionName).protocol const protocol = session.defaultSession.protocol - const handler = function (ignoredError, callback) { + const handler = (ignoredError, callback) => { callback({data: 'test', mimeType: 'text/html'}) } - beforeEach(function (done) { + beforeEach((done) => { if (w != null) w.destroy() w = new BrowserWindow({ show: false, @@ -438,53 +408,49 @@ describe('session module', function () { partition: partitionName } }) - partitionProtocol.registerStringProtocol(protocolName, handler, function (error) { + partitionProtocol.registerStringProtocol(protocolName, handler, (error) => { done(error != null ? error : undefined) }) }) - afterEach(function (done) { + afterEach((done) => { partitionProtocol.unregisterProtocol(protocolName, () => done()) }) - it('does not affect defaultSession', function (done) { - protocol.isProtocolHandled(protocolName, function (result) { + it('does not affect defaultSession', (done) => { + protocol.isProtocolHandled(protocolName, (result) => { assert.equal(result, false) - partitionProtocol.isProtocolHandled(protocolName, function (result) { + partitionProtocol.isProtocolHandled(protocolName, (result) => { assert.equal(result, true) done() }) }) }) - xit('handles requests from partition', function (done) { - w.webContents.on('did-finish-load', function () { - done() - }) + xit('handles requests from partition', (done) => { + w.webContents.on('did-finish-load', () => done()) w.loadURL(`${protocolName}://fake-host`) }) }) - describe('ses.setProxy(options, callback)', function () { - it('allows configuring proxy settings', function (done) { - const config = { - proxyRules: 'http=myproxy:80' - } - session.defaultSession.setProxy(config, function () { - session.defaultSession.resolveProxy('http://localhost', function (proxy) { + describe('ses.setProxy(options, callback)', () => { + it('allows configuring proxy settings', (done) => { + const config = {proxyRules: 'http=myproxy:80'} + session.defaultSession.setProxy(config, () => { + session.defaultSession.resolveProxy('http://localhost', (proxy) => { assert.equal(proxy, 'PROXY myproxy:80') done() }) }) }) - it('allows bypassing proxy settings', function (done) { + it('allows bypassing proxy settings', (done) => { const config = { proxyRules: 'http=myproxy:80', proxyBypassRules: '' } - session.defaultSession.setProxy(config, function () { - session.defaultSession.resolveProxy('http://localhost', function (proxy) { + session.defaultSession.setProxy(config, () => { + session.defaultSession.resolveProxy('http://localhost', (proxy) => { assert.equal(proxy, 'DIRECT') done() }) @@ -492,17 +458,17 @@ describe('session module', function () { }) }) - describe('ses.getBlobData(identifier, callback)', function () { - it('returns blob data for uuid', function (done) { + describe('ses.getBlobData(identifier, callback)', () => { + it('returns blob data for uuid', (done) => { const scheme = 'temp' const protocol = session.defaultSession.protocol - const url = scheme + '://host' - before(function () { + const url = `${scheme}://host` + before(() => { if (w != null) w.destroy() w = new BrowserWindow({show: false}) }) - after(function (done) { + after((done) => { protocol.unregisterProtocol(scheme, () => { closeWindow(w).then(() => { w = null @@ -525,30 +491,30 @@ describe('session module', function () { ` - protocol.registerStringProtocol(scheme, function (request, callback) { + protocol.registerStringProtocol(scheme, (request, callback) => { if (request.method === 'GET') { callback({data: content, mimeType: 'text/html'}) } else if (request.method === 'POST') { let uuid = request.uploadData[1].blobUUID assert(uuid) - session.defaultSession.getBlobData(uuid, function (result) { + session.defaultSession.getBlobData(uuid, (result) => { assert.equal(result.toString(), postData) done() }) } - }, function (error) { + }, (error) => { if (error) return done(error) w.loadURL(url) }) }) }) - describe('ses.setCertificateVerifyProc(callback)', function () { - var server = null + describe('ses.setCertificateVerifyProc(callback)', () => { + let server = null - beforeEach(function (done) { - var certPath = path.join(__dirname, 'fixtures', 'certificates') - var options = { + beforeEach((done) => { + const certPath = path.join(__dirname, 'fixtures', 'certificates') + const options = { key: fs.readFileSync(path.join(certPath, 'server.key')), cert: fs.readFileSync(path.join(certPath, 'server.pem')), ca: [ @@ -559,54 +525,54 @@ describe('session module', function () { rejectUnauthorized: false } - server = https.createServer(options, function (req, res) { + server = https.createServer(options, (req, res) => { res.writeHead(200) res.end('hello') }) server.listen(0, '127.0.0.1', done) }) - afterEach(function () { + afterEach(() => { session.defaultSession.setCertificateVerifyProc(null) server.close() }) - it('accepts the request when the callback is called with 0', function (done) { - session.defaultSession.setCertificateVerifyProc(function ({hostname, certificate, verificationResult, errorCode}, callback) { + it('accepts the request when the callback is called with 0', (done) => { + session.defaultSession.setCertificateVerifyProc(({hostname, certificate, verificationResult, errorCode}, callback) => { assert(['net::ERR_CERT_AUTHORITY_INVALID', 'net::ERR_CERT_COMMON_NAME_INVALID'].includes(verificationResult), verificationResult) assert([-202, -200].includes(errorCode), errorCode) callback(0) }) - w.webContents.once('did-finish-load', function () { + w.webContents.once('did-finish-load', () => { assert.equal(w.webContents.getTitle(), 'hello') done() }) w.loadURL(`https://127.0.0.1:${server.address().port}`) }) - describe('deprecated function signature', function () { - it('supports accepting the request', function (done) { - session.defaultSession.setCertificateVerifyProc(function (hostname, certificate, callback) { + describe('deprecated function signature', () => { + it('supports accepting the request', (done) => { + session.defaultSession.setCertificateVerifyProc((hostname, certificate, callback) => { assert.equal(hostname, '127.0.0.1') callback(true) }) - w.webContents.once('did-finish-load', function () { + w.webContents.once('did-finish-load', () => { assert.equal(w.webContents.getTitle(), 'hello') done() }) w.loadURL(`https://127.0.0.1:${server.address().port}`) }) - it('supports rejecting the request', function (done) { - session.defaultSession.setCertificateVerifyProc(function (hostname, certificate, callback) { + it('supports rejecting the request', (done) => { + session.defaultSession.setCertificateVerifyProc((hostname, certificate, callback) => { assert.equal(hostname, '127.0.0.1') callback(false) }) - var url = `https://127.0.0.1:${server.address().port}` - w.webContents.once('did-finish-load', function () { + const url = `https://127.0.0.1:${server.address().port}` + w.webContents.once('did-finish-load', () => { assert.equal(w.webContents.getTitle(), url) done() }) @@ -614,8 +580,8 @@ describe('session module', function () { }) }) - it('rejects the request when the callback is called with -2', function (done) { - session.defaultSession.setCertificateVerifyProc(function ({hostname, certificate, verificationResult}, callback) { + it('rejects the request when the callback is called with -2', (done) => { + session.defaultSession.setCertificateVerifyProc(({hostname, certificate, verificationResult}, callback) => { assert.equal(hostname, '127.0.0.1') assert.equal(certificate.issuerName, 'Intermediate CA') assert.equal(certificate.subjectName, 'localhost') @@ -630,8 +596,8 @@ describe('session module', function () { callback(-2) }) - var url = `https://127.0.0.1:${server.address().port}` - w.webContents.once('did-finish-load', function () { + const url = `https://127.0.0.1:${server.address().port}` + w.webContents.once('did-finish-load', () => { assert.equal(w.webContents.getTitle(), url) done() }) @@ -639,8 +605,8 @@ describe('session module', function () { }) }) - describe('ses.createInterruptedDownload(options)', function () { - it('can create an interrupted download item', function (done) { + describe('ses.createInterruptedDownload(options)', () => { + it('can create an interrupted download item', (done) => { ipcRenderer.sendSync('set-download-option', true, false) const filePath = path.join(__dirname, 'fixtures', 'mock.pdf') const options = { @@ -651,10 +617,10 @@ describe('session module', function () { length: 5242880 } w.webContents.session.createInterruptedDownload(options) - ipcRenderer.once('download-created', function (event, state, urlChain, + ipcRenderer.once('download-created', (event, state, urlChain, mimeType, receivedBytes, totalBytes, filename, - savePath) { + savePath) => { assert.equal(state, 'interrupted') assert.deepEqual(urlChain, ['http://127.0.0.1/']) assert.equal(mimeType, 'application/pdf') @@ -665,26 +631,22 @@ describe('session module', function () { }) }) - it('can be resumed', function (done) { + it('can be resumed', (done) => { const fixtures = path.join(__dirname, 'fixtures') const downloadFilePath = path.join(fixtures, 'logo.png') - const rangeServer = http.createServer(function (req, res) { - let options = { - root: fixtures - } + const rangeServer = http.createServer((req, res) => { + let options = { root: fixtures } send(req, req.url, options) - .on('error', function (error) { - done(error) - }).pipe(res) + .on('error', (error) => { done(error) }).pipe(res) }) ipcRenderer.sendSync('set-download-option', true, false, downloadFilePath) - rangeServer.listen(0, '127.0.0.1', function () { + rangeServer.listen(0, '127.0.0.1', () => { const port = rangeServer.address().port const downloadUrl = `http://127.0.0.1:${port}/assets/logo.png` - const callback = function (event, state, url, mimeType, + const callback = (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename, savePath, urlChain, - lastModifiedTime, eTag) { + lastModifiedTime, eTag) => { if (state === 'cancelled') { const options = { path: savePath, @@ -718,11 +680,11 @@ describe('session module', function () { }) }) - describe('ses.clearAuthCache(options[, callback])', function () { - it('can clear http auth info from cache', function (done) { + describe('ses.clearAuthCache(options[, callback])', () => { + it('can clear http auth info from cache', (done) => { const ses = session.fromPartition('auth-cache') - const server = http.createServer(function (req, res) { - var credentials = auth(req) + const server = http.createServer((req, res) => { + const credentials = auth(req) if (!credentials || credentials.name !== 'test' || credentials.pass !== 'test') { res.statusCode = 401 res.setHeader('WWW-Authenticate', 'Basic realm="Restricted"') @@ -731,7 +693,7 @@ describe('session module', function () { res.end('authenticated') } }) - server.listen(0, '127.0.0.1', function () { + server.listen(0, '127.0.0.1', () => { const port = server.address().port function issueLoginRequest (attempt = 1) { if (attempt > 2) { @@ -742,27 +704,25 @@ describe('session module', function () { url: `http://127.0.0.1:${port}`, session: ses }) - request.on('login', function (info, callback) { - attempt++ + request.on('login', (info, callback) => { + attempt += 1 assert.equal(info.scheme, 'basic') assert.equal(info.realm, 'Restricted') callback('test', 'test') }) - request.on('response', function (response) { + request.on('response', (response) => { let data = '' response.pause() - response.on('data', function (chunk) { + response.on('data', (chunk) => { data += chunk }) - response.on('end', function () { + response.on('end', () => { assert.equal(data, 'authenticated') - ses.clearAuthCache({type: 'password'}, function () { + ses.clearAuthCache({type: 'password'}, () => { issueLoginRequest(attempt) }) }) - response.on('error', function (error) { - done(error) - }) + response.on('error', (error) => { done(error) }) response.resume() }) // Internal api to bypass cache for testing. @@ -782,12 +742,12 @@ describe('session module', function () { }) webview = new WebView() - webview.addEventListener('ipc-message', function (e) { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'message') assert.deepEqual(e.args, ['SecurityError']) done() }) - webview.src = 'file://' + fixtures + '/pages/permissions/midi-sysex.html' + webview.src = `file://${fixtures}/pages/permissions/midi-sysex.html` webview.partition = 'permissionTest' webview.setAttribute('nodeintegration', 'on') document.body.appendChild(webview) diff --git a/spec/api-web-contents-spec.js b/spec/api-web-contents-spec.js index e94dc9eb2ac..f4093dd43a4 100644 --- a/spec/api-web-contents-spec.js +++ b/spec/api-web-contents-spec.js @@ -10,11 +10,11 @@ const {BrowserWindow, webContents, ipcMain, session} = remote const isCi = remote.getGlobal('isCi') -describe('webContents module', function () { +describe('webContents module', () => { const fixtures = path.resolve(__dirname, 'fixtures') let w - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({ show: false, width: 400, @@ -25,14 +25,12 @@ describe('webContents module', function () { }) }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - describe('getAllWebContents() API', function () { - it('returns an array of web contents', function (done) { - w.webContents.on('devtools-opened', function () { - const all = webContents.getAllWebContents().sort(function (a, b) { + describe('getAllWebContents() API', () => { + it('returns an array of web contents', (done) => { + w.webContents.on('devtools-opened', () => { + const all = webContents.getAllWebContents().sort((a, b) => { return a.getId() - b.getId() }) @@ -44,24 +42,24 @@ describe('webContents module', function () { done() }) - w.loadURL('file://' + path.join(fixtures, 'pages', 'webview-zoom-factor.html')) + w.loadURL(`file://${path.join(fixtures, 'pages', 'webview-zoom-factor.html')}`) w.webContents.openDevTools() }) }) - describe('getFocusedWebContents() API', function () { - it('returns the focused web contents', function (done) { + describe('getFocusedWebContents() API', () => { + it('returns the focused web contents', (done) => { if (isCi) return done() const specWebContents = remote.getCurrentWebContents() assert.equal(specWebContents.getId(), webContents.getFocusedWebContents().getId()) - specWebContents.once('devtools-opened', function () { + specWebContents.once('devtools-opened', () => { assert.equal(specWebContents.devToolsWebContents.getId(), webContents.getFocusedWebContents().getId()) specWebContents.closeDevTools() }) - specWebContents.once('devtools-closed', function () { + specWebContents.once('devtools-closed', () => { assert.equal(specWebContents.getId(), webContents.getFocusedWebContents().getId()) done() }) @@ -69,18 +67,18 @@ describe('webContents module', function () { specWebContents.openDevTools() }) - it('does not crash when called on a detached dev tools window', function (done) { + it('does not crash when called on a detached dev tools window', (done) => { const specWebContents = w.webContents - specWebContents.once('devtools-opened', function () { - assert.doesNotThrow(function () { + specWebContents.once('devtools-opened', () => { + assert.doesNotThrow(() => { webContents.getFocusedWebContents() }) specWebContents.closeDevTools() }) - specWebContents.once('devtools-closed', function () { - assert.doesNotThrow(function () { + specWebContents.once('devtools-closed', () => { + assert.doesNotThrow(() => { webContents.getFocusedWebContents() }) done() @@ -91,9 +89,9 @@ describe('webContents module', function () { }) }) - describe('isFocused() API', function () { - it('returns false when the window is hidden', function () { - BrowserWindow.getAllWindows().forEach(function (window) { + describe('isFocused() API', () => { + it('returns false when the window is hidden', () => { + BrowserWindow.getAllWindows().forEach((window) => { assert.equal(!window.isVisible() && window.webContents.isFocused(), false) }) }) @@ -101,7 +99,7 @@ describe('webContents module', function () { describe('before-input-event event', () => { it('can prevent document keyboard events', (done) => { - w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html')) + w.loadURL(`file://${path.join(__dirname, 'fixtures', 'pages', 'key-events.html')}`) w.webContents.once('did-finish-load', () => { ipcMain.once('keydown', (event, key) => { assert.equal(key, 'b') @@ -115,7 +113,7 @@ describe('webContents module', function () { }) it('has the correct properties', (done) => { - w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'base-page.html')) + w.loadURL(`file://${path.join(__dirname, 'fixtures', 'pages', 'base-page.html')}`) w.webContents.once('did-finish-load', () => { const testBeforeInput = (opts) => { return new Promise((resolve, reject) => { @@ -199,16 +197,14 @@ describe('webContents module', function () { }) }) - describe('sendInputEvent(event)', function () { - beforeEach(function (done) { - w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'key-events.html')) - w.webContents.once('did-finish-load', function () { - done() - }) + describe('sendInputEvent(event)', () => { + beforeEach((done) => { + w.loadURL(`file://${path.join(__dirname, 'fixtures', 'pages', 'key-events.html')}`) + w.webContents.once('did-finish-load', () => done()) }) - it('can send keydown events', function (done) { - ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + it('can send keydown events', (done) => { + ipcMain.once('keydown', (event, key, code, keyCode, shiftKey, ctrlKey, altKey) => { assert.equal(key, 'a') assert.equal(code, 'KeyA') assert.equal(keyCode, 65) @@ -220,8 +216,8 @@ describe('webContents module', function () { w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'A'}) }) - it('can send keydown events with modifiers', function (done) { - ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + it('can send keydown events with modifiers', (done) => { + ipcMain.once('keydown', (event, key, code, keyCode, shiftKey, ctrlKey, altKey) => { assert.equal(key, 'Z') assert.equal(code, 'KeyZ') assert.equal(keyCode, 90) @@ -233,8 +229,8 @@ describe('webContents module', function () { w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Z', modifiers: ['shift', 'ctrl']}) }) - it('can send keydown events with special keys', function (done) { - ipcMain.once('keydown', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + it('can send keydown events with special keys', (done) => { + ipcMain.once('keydown', (event, key, code, keyCode, shiftKey, ctrlKey, altKey) => { assert.equal(key, 'Tab') assert.equal(code, 'Tab') assert.equal(keyCode, 9) @@ -246,8 +242,8 @@ describe('webContents module', function () { w.webContents.sendInputEvent({type: 'keyDown', keyCode: 'Tab', modifiers: ['alt']}) }) - it('can send char events', function (done) { - ipcMain.once('keypress', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + it('can send char events', (done) => { + ipcMain.once('keypress', (event, key, code, keyCode, shiftKey, ctrlKey, altKey) => { assert.equal(key, 'a') assert.equal(code, 'KeyA') assert.equal(keyCode, 65) @@ -260,8 +256,8 @@ describe('webContents module', function () { w.webContents.sendInputEvent({type: 'char', keyCode: 'A'}) }) - it('can send char events with modifiers', function (done) { - ipcMain.once('keypress', function (event, key, code, keyCode, shiftKey, ctrlKey, altKey) { + it('can send char events with modifiers', (done) => { + ipcMain.once('keypress', (event, key, code, keyCode, shiftKey, ctrlKey, altKey) => { assert.equal(key, 'Z') assert.equal(code, 'KeyZ') assert.equal(keyCode, 90) @@ -275,7 +271,7 @@ describe('webContents module', function () { }) }) - it('supports inserting CSS', function (done) { + it('supports inserting CSS', (done) => { w.loadURL('about:blank') w.webContents.insertCSS('body { background-repeat: round; }') w.webContents.executeJavaScript('window.getComputedStyle(document.body).getPropertyValue("background-repeat")', (result) => { @@ -284,9 +280,9 @@ describe('webContents module', function () { }) }) - it('supports inspecting an element in the devtools', function (done) { + it('supports inspecting an element in the devtools', (done) => { w.loadURL('about:blank') - w.webContents.once('devtools-opened', function () { + w.webContents.once('devtools-opened', () => { done() }) w.webContents.inspectElement(10, 10) @@ -310,22 +306,22 @@ describe('webContents module', function () { }) }) - describe('focus()', function () { - describe('when the web contents is hidden', function () { - it('does not blur the focused window', function (done) { + describe('focus()', () => { + describe('when the web contents is hidden', () => { + it('does not blur the focused window', (done) => { ipcMain.once('answer', (event, parentFocused, childFocused) => { assert.equal(parentFocused, true) assert.equal(childFocused, false) done() }) w.show() - w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'focus-web-contents.html')) + w.loadURL(`file://${path.join(__dirname, 'fixtures', 'pages', 'focus-web-contents.html')}`) }) }) }) - describe('getOSProcessId()', function () { - it('returns a valid procress id', function (done) { + describe('getOSProcessId()', () => { + it('returns a valid procress id', (done) => { assert.strictEqual(w.webContents.getOSProcessId(), 0) w.webContents.once('did-finish-load', () => { @@ -386,9 +382,7 @@ describe('webContents module', function () { let finalNavigation = false ipcMain.on('set-zoom', (e, host) => { const zoomLevel = hostZoomMap[host] - if (!finalNavigation) { - w.webContents.setZoomLevel(zoomLevel) - } + if (!finalNavigation) w.webContents.setZoomLevel(zoomLevel) e.sender.send(`${host}-zoom-set`) }) ipcMain.on('host1-zoom-level', (e, zoomLevel) => { @@ -467,12 +461,12 @@ describe('webContents module', function () { }) it('can persist when it contains iframe', (done) => { - const server = http.createServer(function (req, res) { + const server = http.createServer((req, res) => { setTimeout(() => { res.end() }, 200) }) - server.listen(0, '127.0.0.1', function () { + server.listen(0, '127.0.0.1', () => { const url = 'http://127.0.0.1:' + server.address().port const content = `` w.webContents.on('did-frame-finish-load', (e, isMainFrame) => { @@ -557,12 +551,12 @@ describe('webContents module', function () { }) }) - describe('will-prevent-unload event', function () { - it('does not emit if beforeunload returns undefined', function (done) { - w.once('closed', function () { + describe('will-prevent-unload event', () => { + it('does not emit if beforeunload returns undefined', (done) => { + w.once('closed', () => { done() }) - w.webContents.on('will-prevent-unload', function (e) { + w.webContents.on('will-prevent-unload', (e) => { assert.fail('should not have fired') }) w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-undefined.html')) @@ -575,15 +569,15 @@ describe('webContents module', function () { w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')) }) - it('supports calling preventDefault on will-prevent-unload events', function (done) { + it('supports calling preventDefault on will-prevent-unload events', (done) => { ipcRenderer.send('prevent-next-will-prevent-unload', w.webContents.id) w.once('closed', () => done()) w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')) }) }) - describe('setIgnoreMenuShortcuts(ignore)', function () { - it('does not throw', function () { + describe('setIgnoreMenuShortcuts(ignore)', () => { + it('does not throw', () => { assert.equal(w.webContents.setIgnoreMenuShortcuts(true), undefined) assert.equal(w.webContents.setIgnoreMenuShortcuts(false), undefined) }) @@ -594,7 +588,7 @@ describe('webContents module', function () { xdescribe('destroy()', () => { let server - before(function (done) { + before((done) => { server = http.createServer((request, response) => { switch (request.url) { case '/404': @@ -619,7 +613,7 @@ describe('webContents module', function () { }) }) - after(function () { + after(() => { server.close() server = null }) @@ -659,18 +653,18 @@ describe('webContents module', function () { describe('did-change-theme-color event', () => { it('is triggered with correct theme color', (done) => { - var count = 0 + let count = 0 w.webContents.on('did-change-theme-color', (e, color) => { if (count === 0) { - count++ + count += 1 assert.equal(color, '#FFEEDD') - w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'base-page.html')) + w.loadURL(`file://${path.join(__dirname, 'fixtures', 'pages', 'base-page.html')}`) } else if (count === 1) { assert.equal(color, null) done() } }) - w.loadURL('file://' + path.join(__dirname, 'fixtures', 'pages', 'theme-color.html')) + w.loadURL(`file://${path.join(__dirname, 'fixtures', 'pages', 'theme-color.html')}`) }) }) }) diff --git a/spec/api-web-request-spec.js b/spec/api-web-request-spec.js index 85afb4c9399..6ad0550eb7d 100644 --- a/spec/api-web-request-spec.js +++ b/spec/api-web-request-spec.js @@ -4,89 +4,79 @@ const qs = require('querystring') const remote = require('electron').remote const session = remote.session -describe('webRequest module', function () { - var ses = session.defaultSession - var server = http.createServer(function (req, res) { +describe('webRequest module', () => { + const ses = session.defaultSession + const server = http.createServer((req, res) => { if (req.url === '/serverRedirect') { res.statusCode = 301 res.setHeader('Location', 'http://' + req.rawHeaders[1]) res.end() } else { res.setHeader('Custom', ['Header']) - var content = req.url + let content = req.url if (req.headers.accept === '*/*;test/header') { content += 'header/received' } res.end(content) } }) - var defaultURL = null + let defaultURL = null - before(function (done) { - server.listen(0, '127.0.0.1', function () { - var port = server.address().port + before((done) => { + server.listen(0, '127.0.0.1', () => { + const port = server.address().port defaultURL = 'http://127.0.0.1:' + port + '/' done() }) }) - after(function () { + after(() => { server.close() }) - describe('webRequest.onBeforeRequest', function () { - afterEach(function () { + describe('webRequest.onBeforeRequest', () => { + afterEach(() => { ses.webRequest.onBeforeRequest(null) }) - it('can cancel the request', function (done) { - ses.webRequest.onBeforeRequest(function (details, callback) { + it('can cancel the request', (done) => { + ses.webRequest.onBeforeRequest((details, callback) => { callback({ cancel: true }) }) $.ajax({ url: defaultURL, - success: function () { + success: () => { done('unexpected success') }, - error: function () { + error: () => { done() } }) }) - it('can filter URLs', function (done) { - var filter = { - urls: [defaultURL + 'filter/*'] - } - ses.webRequest.onBeforeRequest(filter, function (details, callback) { - callback({ - cancel: true - }) + it('can filter URLs', (done) => { + const filter = { urls: [defaultURL + 'filter/*'] } + ses.webRequest.onBeforeRequest(filter, (details, callback) => { + callback({cancel: true}) }) $.ajax({ - url: defaultURL + 'nofilter/test', - success: function (data) { + url: `${defaultURL}nofilter/test`, + success: (data) => { assert.equal(data, '/nofilter/test') $.ajax({ - url: defaultURL + 'filter/test', - success: function () { - done('unexpected success') - }, - error: function () { - done() - } + url: `${defaultURL}filter/test`, + success: () => done('unexpected success'), + error: () => done() }) }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('receives details object', function (done) { - ses.webRequest.onBeforeRequest(function (details, callback) { + it('receives details object', (done) => { + ses.webRequest.onBeforeRequest((details, callback) => { assert.equal(typeof details.id, 'number') assert.equal(typeof details.timestamp, 'number') assert.equal(typeof details.webContentsId, 'number') @@ -98,162 +88,138 @@ describe('webRequest module', function () { }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('receives post data in details object', function (done) { - var postData = { + it('receives post data in details object', (done) => { + const postData = { name: 'post test', type: 'string' } - ses.webRequest.onBeforeRequest(function (details, callback) { + ses.webRequest.onBeforeRequest((details, callback) => { assert.equal(details.url, defaultURL) assert.equal(details.method, 'POST') assert.equal(details.uploadData.length, 1) - var data = qs.parse(details.uploadData[0].bytes.toString()) + const data = qs.parse(details.uploadData[0].bytes.toString()) assert.deepEqual(data, postData) - callback({ - cancel: true - }) + callback({ cancel: true }) }) $.ajax({ url: defaultURL, type: 'POST', data: postData, - success: function () {}, - error: function () { - done() - } + success: () => {}, + error: () => done() }) }) - it('can redirect the request', function (done) { - ses.webRequest.onBeforeRequest(function (details, callback) { + it('can redirect the request', (done) => { + ses.webRequest.onBeforeRequest((details, callback) => { if (details.url === defaultURL) { - callback({ - redirectURL: defaultURL + 'redirect' - }) + callback({ redirectURL: `${defaultURL}redirect` }) } else { callback({}) } }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/redirect') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) }) - describe('webRequest.onBeforeSendHeaders', function () { - afterEach(function () { + describe('webRequest.onBeforeSendHeaders', () => { + afterEach(() => { ses.webRequest.onBeforeSendHeaders(null) }) - it('receives details object', function (done) { - ses.webRequest.onBeforeSendHeaders(function (details, callback) { + it('receives details object', (done) => { + ses.webRequest.onBeforeSendHeaders((details, callback) => { assert.equal(typeof details.requestHeaders, 'object') assert.equal(details.requestHeaders['Foo.Bar'], 'baz') callback({}) }) $.ajax({ url: defaultURL, - headers: { - 'Foo.Bar': 'baz' - }, - success: function (data) { + headers: { 'Foo.Bar': 'baz' }, + success: (data) => { assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('can change the request headers', function (done) { - ses.webRequest.onBeforeSendHeaders(function (details, callback) { - var requestHeaders = details.requestHeaders + it('can change the request headers', (done) => { + ses.webRequest.onBeforeSendHeaders((details, callback) => { + const requestHeaders = details.requestHeaders requestHeaders.Accept = '*/*;test/header' - callback({ - requestHeaders: requestHeaders - }) + callback({ requestHeaders: requestHeaders }) }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/header/received') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('resets the whole headers', function (done) { - var requestHeaders = { + it('resets the whole headers', (done) => { + const requestHeaders = { Test: 'header' } - ses.webRequest.onBeforeSendHeaders(function (details, callback) { - callback({ - requestHeaders: requestHeaders - }) + ses.webRequest.onBeforeSendHeaders((details, callback) => { + callback({ requestHeaders: requestHeaders }) }) - ses.webRequest.onSendHeaders(function (details) { + ses.webRequest.onSendHeaders((details) => { assert.deepEqual(details.requestHeaders, requestHeaders) done() }) $.ajax({ url: defaultURL, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) }) - describe('webRequest.onSendHeaders', function () { - afterEach(function () { + describe('webRequest.onSendHeaders', () => { + afterEach(() => { ses.webRequest.onSendHeaders(null) }) - it('receives details object', function (done) { - ses.webRequest.onSendHeaders(function (details) { + it('receives details object', (done) => { + ses.webRequest.onSendHeaders((details) => { assert.equal(typeof details.requestHeaders, 'object') }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) }) - describe('webRequest.onHeadersReceived', function () { - afterEach(function () { + describe('webRequest.onHeadersReceived', () => { + afterEach(() => { ses.webRequest.onHeadersReceived(null) }) - it('receives details object', function (done) { - ses.webRequest.onHeadersReceived(function (details, callback) { + it('receives details object', (done) => { + ses.webRequest.onHeadersReceived((details, callback) => { assert.equal(details.statusLine, 'HTTP/1.1 200 OK') assert.equal(details.statusCode, 200) assert.equal(details.responseHeaders['Custom'], 'Header') @@ -261,76 +227,64 @@ describe('webRequest module', function () { }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('can change the response header', function (done) { - ses.webRequest.onHeadersReceived(function (details, callback) { - var responseHeaders = details.responseHeaders + it('can change the response header', (done) => { + ses.webRequest.onHeadersReceived((details, callback) => { + const responseHeaders = details.responseHeaders responseHeaders['Custom'] = ['Changed'] - callback({ - responseHeaders: responseHeaders - }) + callback({ responseHeaders: responseHeaders }) }) $.ajax({ url: defaultURL, - success: function (data, status, xhr) { + success: (data, status, xhr) => { assert.equal(xhr.getResponseHeader('Custom'), 'Changed') assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('does not change header by default', function (done) { - ses.webRequest.onHeadersReceived(function (details, callback) { + it('does not change header by default', (done) => { + ses.webRequest.onHeadersReceived((details, callback) => { callback({}) }) $.ajax({ url: defaultURL, - success: function (data, status, xhr) { + success: (data, status, xhr) => { assert.equal(xhr.getResponseHeader('Custom'), 'Header') assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('follows server redirect', function (done) { - ses.webRequest.onHeadersReceived(function (details, callback) { - var responseHeaders = details.responseHeaders - callback({ - responseHeaders: responseHeaders - }) + it('follows server redirect', (done) => { + ses.webRequest.onHeadersReceived((details, callback) => { + const responseHeaders = details.responseHeaders + callback({ responseHeaders: responseHeaders }) }) $.ajax({ url: defaultURL + 'serverRedirect', - success: function (data, status, xhr) { + success: (data, status, xhr) => { assert.equal(xhr.getResponseHeader('Custom'), 'Header') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) - it('can change the header status', function (done) { - ses.webRequest.onHeadersReceived(function (details, callback) { - var responseHeaders = details.responseHeaders + it('can change the header status', (done) => { + ses.webRequest.onHeadersReceived((details, callback) => { + const responseHeaders = details.responseHeaders callback({ responseHeaders: responseHeaders, statusLine: 'HTTP/1.1 404 Not Found' @@ -338,9 +292,8 @@ describe('webRequest module', function () { }) $.ajax({ url: defaultURL, - success: function (data, status, xhr) { - }, - error: function (xhr, errorType) { + success: (data, status, xhr) => {}, + error: (xhr, errorType) => { assert.equal(xhr.getResponseHeader('Custom'), 'Header') done() } @@ -348,13 +301,13 @@ describe('webRequest module', function () { }) }) - describe('webRequest.onResponseStarted', function () { - afterEach(function () { + describe('webRequest.onResponseStarted', () => { + afterEach(() => { ses.webRequest.onResponseStarted(null) }) - it('receives details object', function (done) { - ses.webRequest.onResponseStarted(function (details) { + it('receives details object', (done) => { + ses.webRequest.onResponseStarted((details) => { assert.equal(typeof details.fromCache, 'boolean') assert.equal(details.statusLine, 'HTTP/1.1 200 OK') assert.equal(details.statusCode, 200) @@ -362,36 +315,32 @@ describe('webRequest module', function () { }) $.ajax({ url: defaultURL, - success: function (data, status, xhr) { + success: (data, status, xhr) => { assert.equal(xhr.getResponseHeader('Custom'), 'Header') assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) }) - describe('webRequest.onBeforeRedirect', function () { - afterEach(function () { + describe('webRequest.onBeforeRedirect', () => { + afterEach(() => { ses.webRequest.onBeforeRedirect(null) ses.webRequest.onBeforeRequest(null) }) - it('receives details object', function (done) { - var redirectURL = defaultURL + 'redirect' - ses.webRequest.onBeforeRequest(function (details, callback) { + it('receives details object', (done) => { + const redirectURL = defaultURL + 'redirect' + ses.webRequest.onBeforeRequest((details, callback) => { if (details.url === defaultURL) { - callback({ - redirectURL: redirectURL - }) + callback({ redirectURL: redirectURL }) } else { callback({}) } }) - ses.webRequest.onBeforeRedirect(function (details) { + ses.webRequest.onBeforeRedirect((details) => { assert.equal(typeof details.fromCache, 'boolean') assert.equal(details.statusLine, 'HTTP/1.1 307 Internal Redirect') assert.equal(details.statusCode, 307) @@ -399,62 +348,54 @@ describe('webRequest module', function () { }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/redirect') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) }) - describe('webRequest.onCompleted', function () { - afterEach(function () { + describe('webRequest.onCompleted', () => { + afterEach(() => { ses.webRequest.onCompleted(null) }) - it('receives details object', function (done) { - ses.webRequest.onCompleted(function (details) { + it('receives details object', (done) => { + ses.webRequest.onCompleted((details) => { assert.equal(typeof details.fromCache, 'boolean') assert.equal(details.statusLine, 'HTTP/1.1 200 OK') assert.equal(details.statusCode, 200) }) $.ajax({ url: defaultURL, - success: function (data) { + success: (data) => { assert.equal(data, '/') done() }, - error: function (xhr, errorType) { - done(errorType) - } + error: (xhr, errorType) => done(errorType) }) }) }) - describe('webRequest.onErrorOccurred', function () { - afterEach(function () { + describe('webRequest.onErrorOccurred', () => { + afterEach(() => { ses.webRequest.onErrorOccurred(null) ses.webRequest.onBeforeRequest(null) }) - it('receives details object', function (done) { - ses.webRequest.onBeforeRequest(function (details, callback) { - callback({ - cancel: true - }) + it('receives details object', (done) => { + ses.webRequest.onBeforeRequest((details, callback) => { + callback({ cancel: true }) }) - ses.webRequest.onErrorOccurred(function (details) { + ses.webRequest.onErrorOccurred((details) => { assert.equal(details.error, 'net::ERR_BLOCKED_BY_CLIENT') done() }) $.ajax({ url: defaultURL, - success: function () { - done('unexpected success') - } + success: () => done('unexpected success') }) }) }) diff --git a/spec/chromium-spec.js b/spec/chromium-spec.js index 2f9f2b2795a..5095a066195 100644 --- a/spec/chromium-spec.js +++ b/spec/chromium-spec.js @@ -11,62 +11,55 @@ const {app, BrowserWindow, ipcMain, protocol, session, webContents} = remote const isCI = remote.getGlobal('isCi') -describe('chromium feature', function () { - var fixtures = path.resolve(__dirname, 'fixtures') - var listener = null +describe('chromium feature', () => { + const fixtures = path.resolve(__dirname, 'fixtures') + let listener = null let w = null - afterEach(function () { + afterEach(() => { if (listener != null) { window.removeEventListener('message', listener) } listener = null }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) - }) + afterEach(() => closeWindow(w).then(() => { w = null })) - describe('heap snapshot', function () { - it('does not crash', function () { + describe('heap snapshot', () => { + it('does not crash', () => { if (process.env.TRAVIS === 'true') return process.atomBinding('v8_util').takeHeapSnapshot() }) }) - describe('sending request of http protocol urls', function () { - it('does not crash', function (done) { - var server = http.createServer(function (req, res) { + describe('sending request of http protocol urls', () => { + it('does not crash', (done) => { + const server = http.createServer((req, res) => { res.end() server.close() done() }) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - $.get('http://127.0.0.1:' + port) + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + $.get(`http://127.0.0.1:${port}`) }) }) }) - xdescribe('navigator.webkitGetUserMedia', function () { - it('calls its callbacks', function (done) { + describe('navigator.webkitGetUserMedia', () => { + it('calls its callbacks', (done) => { navigator.webkitGetUserMedia({ audio: true, video: false - }, function () { - done() - }, function () { - done() - }) + }, () => done(), + () => done()) }) }) - describe('navigator.mediaDevices', function () { - if (isCI) { - return - } + describe('navigator.mediaDevices', () => { + if (isCI) return - it('can return labels of enumerated devices', function (done) { + it('can return labels of enumerated devices', (done) => { navigator.mediaDevices.enumerateDevices().then((devices) => { const labels = devices.map((device) => device.label) const labelFound = labels.some((label) => !!label) @@ -78,7 +71,7 @@ describe('chromium feature', function () { }).catch(done) }) - it('can return new device id when cookie storage is cleared', function (done) { + it('can return new device id when cookie storage is cleared', (done) => { const options = { origin: null, storages: ['cookies'] @@ -91,91 +84,78 @@ describe('chromium feature', function () { session: ses } }) - w.webContents.on('ipc-message', function (event, args) { - if (args[0] === 'deviceIds') { - deviceIds.push(args[1]) - } + w.webContents.on('ipc-message', (event, args) => { + if (args[0] === 'deviceIds') deviceIds.push(args[1]) if (deviceIds.length === 2) { assert.notDeepEqual(deviceIds[0], deviceIds[1]) - closeWindow(w).then(function () { + closeWindow(w).then(() => { w = null done() - }).catch(function (error) { - done(error) - }) + }).catch((error) => done(error)) } else { - ses.clearStorageData(options, function () { + ses.clearStorageData(options, () => { w.webContents.reload() }) } }) - w.loadURL('file://' + fixtures + '/pages/media-id-reset.html') + w.loadURL(`file://${fixtures}/pages/media-id-reset.html`) }) }) - describe('navigator.language', function () { - it('should not be empty', function () { + describe('navigator.language', () => { + it('should not be empty', () => { assert.notEqual(navigator.language, '') }) }) - describe('navigator.serviceWorker', function () { - it('should register for file scheme', function (done) { - w = new BrowserWindow({ - show: false - }) - w.webContents.on('ipc-message', function (event, args) { + describe('navigator.serviceWorker', () => { + it('should register for file scheme', (done) => { + w = new BrowserWindow({ show: false }) + w.webContents.on('ipc-message', (event, args) => { if (args[0] === 'reload') { w.webContents.reload() } else if (args[0] === 'error') { - done('unexpected error : ' + args[1]) + done(`unexpected error : ${args[1]}`) } else if (args[0] === 'response') { assert.equal(args[1], 'Hello from serviceWorker!') session.defaultSession.clearStorageData({ storages: ['serviceworkers'] - }, function () { - done() - }) + }, () => done()) } }) w.loadURL(`file://${fixtures}/pages/service-worker/index.html`) }) - it('should register for intercepted file scheme', function (done) { + it('should register for intercepted file scheme', (done) => { const customSession = session.fromPartition('intercept-file') - customSession.protocol.interceptBufferProtocol('file', function (request, callback) { + customSession.protocol.interceptBufferProtocol('file', (request, callback) => { let file = url.parse(request.url).pathname - // Remove leading slash before drive letter on Windows - if (file[0] === '/' && process.platform === 'win32') { - file = file.slice(1) - } + if (file[0] === '/' && process.platform === 'win32') file = file.slice(1) + const content = fs.readFileSync(path.normalize(file)) const ext = path.extname(file) let type = 'text/html' - if (ext === '.js') { - type = 'application/javascript' - } + + if (ext === '.js') type = 'application/javascript' callback({data: content, mimeType: type}) - }, function (error) { + }, (error) => { if (error) done(error) }) w = new BrowserWindow({ show: false, - webPreferences: { - session: customSession - } + webPreferences: { session: customSession } }) - w.webContents.on('ipc-message', function (event, args) { + w.webContents.on('ipc-message', (event, args) => { if (args[0] === 'reload') { w.webContents.reload() } else if (args[0] === 'error') { - done('unexpected error : ' + args[1]) + done(`unexpected error : ${args[1]}`) } else if (args[0] === 'response') { assert.equal(args[1], 'Hello from serviceWorker!') customSession.clearStorageData({ storages: ['serviceworkers'] - }, function () { + }, () => { customSession.protocol.uninterceptProtocol('file', (error) => done(error)) }) } @@ -184,53 +164,51 @@ describe('chromium feature', function () { }) }) - describe('window.open', function () { - if (process.env.TRAVIS === 'true' && process.platform === 'darwin') { - return - } + describe('window.open', () => { + if (process.env.TRAVIS === 'true' && process.platform === 'darwin') return - it('returns a BrowserWindowProxy object', function () { - var b = window.open('about:blank', '', 'show=no') + it('returns a BrowserWindowProxy object', () => { + const b = window.open('about:blank', '', 'show=no') assert.equal(b.closed, false) assert.equal(b.constructor.name, 'BrowserWindowProxy') b.close() }) - it('accepts "nodeIntegration" as feature', function (done) { - var b - listener = function (event) { + it('accepts "nodeIntegration" as feature', (done) => { + let b + listener = (event) => { assert.equal(event.data.isProcessGlobalUndefined, true) b.close() done() } window.addEventListener('message', listener) - b = window.open('file://' + fixtures + '/pages/window-opener-node.html', '', 'nodeIntegration=no,show=no') + b = window.open(`file://${fixtures}/pages/window-opener-node.html`, '', 'nodeIntegration=no,show=no') }) - it('inherit options of parent window', function (done) { - var b - listener = function (event) { - var ref1 = remote.getCurrentWindow().getSize() - var width = ref1[0] - var height = ref1[1] - assert.equal(event.data, 'size: ' + width + ' ' + height) + it('inherit options of parent window', (done) => { + let b + listener = (event) => { + const ref1 = remote.getCurrentWindow().getSize() + const width = ref1[0] + const height = ref1[1] + assert.equal(event.data, `size: ${width} ${height}`) b.close() done() } window.addEventListener('message', listener) - b = window.open('file://' + fixtures + '/pages/window-open-size.html', '', 'show=no') + b = window.open(`file://${fixtures}/pages/window-open-size.html`, '', 'show=no') }) - it('disables node integration when it is disabled on the parent window', function (done) { - var b - listener = function (event) { + it('disables node integration when it is disabled on the parent window', (done) => { + let b + listener = (event) => { assert.equal(event.data.isProcessGlobalUndefined, true) b.close() done() } window.addEventListener('message', listener) - var windowUrl = require('url').format({ + const windowUrl = require('url').format({ pathname: `${fixtures}/pages/window-opener-no-node-integration.html`, protocol: 'file', query: { @@ -241,8 +219,8 @@ describe('chromium feature', function () { b = window.open(windowUrl, '', 'nodeIntegration=no,show=no') }) - it('disables node integration when it is disabled on the parent window for chrome devtools URLs', function (done) { - var b + it('disables node integration when it is disabled on the parent window for chrome devtools URLs', (done) => { + let b app.once('web-contents-created', (event, contents) => { contents.once('did-finish-load', () => { contents.executeJavaScript('typeof process').then((typeofProcessGlobal) => { @@ -255,8 +233,8 @@ describe('chromium feature', function () { b = window.open('chrome-devtools://devtools/bundled/inspector.html', '', 'nodeIntegration=no,show=no') }) - it('disables JavaScript when it is disabled on the parent window', function (done) { - var b + it('disables JavaScript when it is disabled on the parent window', (done) => { + let b app.once('web-contents-created', (event, contents) => { contents.once('did-finish-load', () => { app.once('browser-window-created', (event, window) => { @@ -272,7 +250,7 @@ describe('chromium feature', function () { }) }) - var windowUrl = require('url').format({ + const windowUrl = require('url').format({ pathname: `${fixtures}/pages/window-no-javascript.html`, protocol: 'file', slashes: true @@ -280,16 +258,16 @@ describe('chromium feature', function () { b = window.open(windowUrl, '', 'javascript=no,show=no') }) - it('disables the tag when it is disabled on the parent window', function (done) { + it('disables the tag when it is disabled on the parent window', (done) => { let b - listener = function (event) { + listener = (event) => { assert.equal(event.data.isWebViewGlobalUndefined, true) b.close() done() } window.addEventListener('message', listener) - var windowUrl = require('url').format({ + const windowUrl = require('url').format({ pathname: `${fixtures}/pages/window-opener-no-webview-tag.html`, protocol: 'file', query: { @@ -300,24 +278,24 @@ describe('chromium feature', function () { b = window.open(windowUrl, '', 'webviewTag=no,nodeIntegration=yes,show=no') }) - it('does not override child options', function (done) { - var b, size - size = { + it('does not override child options', (done) => { + let b + const size = { width: 350, height: 450 } - listener = function (event) { - assert.equal(event.data, 'size: ' + size.width + ' ' + size.height) + listener = (event) => { + assert.equal(event.data, `size: ${size.width} ${size.height}`) b.close() done() } window.addEventListener('message', listener) - b = window.open('file://' + fixtures + '/pages/window-open-size.html', '', 'show=no,width=' + size.width + ',height=' + size.height) + b = window.open(`file://${fixtures}/pages/window-open-size.html`, '', 'show=no,width=' + size.width + ',height=' + size.height) }) it('handles cycles when merging the parent options into the child options', (done) => { w = BrowserWindow.fromId(ipcRenderer.sendSync('create-window-with-options-cycle')) - w.loadURL('file://' + fixtures + '/pages/window-open.html') + w.loadURL(`file://${fixtures}/pages/window-open.html`) w.webContents.once('new-window', (event, url, frameName, disposition, options) => { assert.equal(options.show, false) assert.deepEqual(options.foo, { @@ -337,12 +315,13 @@ describe('chromium feature', function () { }) }) - it('defines a window.location getter', function (done) { - var b, targetURL + it('defines a window.location getter', (done) => { + let b + let targetURL if (process.platform === 'win32') { - targetURL = 'file:///' + fixtures.replace(/\\/g, '/') + '/pages/base-page.html' + targetURL = `file:///${fixtures.replace(/\\/g, '/')}/pages/base-page.html` } else { - targetURL = 'file://' + fixtures + '/pages/base-page.html' + targetURL = `file://${fixtures}/pages/base-page.html` } app.once('browser-window-created', (event, window) => { window.webContents.once('did-finish-load', () => { @@ -354,34 +333,33 @@ describe('chromium feature', function () { b = window.open(targetURL) }) - it('defines a window.location setter', function (done) { + it('defines a window.location setter', (done) => { let b app.once('browser-window-created', (event, {webContents}) => { - webContents.once('did-finish-load', function () { + webContents.once('did-finish-load', () => { // When it loads, redirect - b.location = 'file://' + fixtures + '/pages/base-page.html' - webContents.once('did-finish-load', function () { + b.location = `file://${fixtures}/pages/base-page.html` + webContents.once('did-finish-load', () => { // After our second redirect, cleanup and callback b.close() done() }) }) }) - // Load a page that definitely won't redirect b = window.open('about:blank') }) - it('open a blank page when no URL is specified', function (done) { + it('open a blank page when no URL is specified', (done) => { let b app.once('browser-window-created', (event, {webContents}) => { - webContents.once('did-finish-load', function () { + webContents.once('did-finish-load', () => { const {location} = b b.close() assert.equal(location, 'about:blank') let c app.once('browser-window-created', (event, {webContents}) => { - webContents.once('did-finish-load', function () { + webContents.once('did-finish-load', () => { const {location} = c c.close() assert.equal(location, 'about:blank') @@ -394,17 +372,17 @@ describe('chromium feature', function () { b = window.open() }) - it('throws an exception when the arguments cannot be converted to strings', function () { - assert.throws(function () { + it('throws an exception when the arguments cannot be converted to strings', () => { + assert.throws(() => { window.open('', {toString: null}) }, /Cannot convert object to primitive value/) - assert.throws(function () { + assert.throws(() => { window.open('', '', {toString: 3}) }, /Cannot convert object to primitive value/) }) - it('sets the window title to the specified frameName', function (done) { + it('sets the window title to the specified frameName', (done) => { let b app.once('browser-window-created', (event, createdWindow) => { assert.equal(createdWindow.getTitle(), 'hello') @@ -414,7 +392,7 @@ describe('chromium feature', function () { b = window.open('', 'hello') }) - it('does not throw an exception when the frameName is a built-in object property', function (done) { + it('does not throw an exception when the frameName is a built-in object property', (done) => { let b app.once('browser-window-created', (event, createdWindow) => { assert.equal(createdWindow.getTitle(), '__proto__') @@ -424,32 +402,30 @@ describe('chromium feature', function () { b = window.open('', '__proto__') }) - it('does not throw an exception when the features include webPreferences', function () { + it('does not throw an exception when the features include webPreferences', () => { let b - assert.doesNotThrow(function () { + assert.doesNotThrow(() => { b = window.open('', '', 'webPreferences=') }) b.close() }) }) - describe('window.opener', function () { - let url = 'file://' + fixtures + '/pages/window-opener.html' + describe('window.opener', () => { + let url = `file://${fixtures}/pages/window-opener.html` - it('is null for main window', function (done) { - w = new BrowserWindow({ - show: false - }) - w.webContents.once('ipc-message', function (event, args) { + it('is null for main window', (done) => { + w = new BrowserWindow({ show: false }) + w.webContents.once('ipc-message', (event, args) => { assert.deepEqual(args, ['opener', null]) done() }) w.loadURL(url) }) - it('is not null for window opened by window.open', function (done) { + it('is not null for window opened by window.open', (done) => { let b - listener = function (event) { + listener = (event) => { assert.equal(event.data, 'object') b.close() done() @@ -459,29 +435,27 @@ describe('chromium feature', function () { }) }) - describe('window.opener access from BrowserWindow', function () { + describe('window.opener access from BrowserWindow', () => { const scheme = 'other' let url = `${scheme}://${fixtures}/pages/window-opener-location.html` let w = null - before(function (done) { - protocol.registerFileProtocol(scheme, function (request, callback) { + before((done) => { + protocol.registerFileProtocol(scheme, (request, callback) => { callback(`${fixtures}/pages/window-opener-location.html`) - }, function (error) { - done(error) - }) + }, (error) => done(error)) }) - after(function () { + after(() => { protocol.unregisterProtocol(scheme) }) - afterEach(function () { + afterEach(() => { w.close() }) - it('does nothing when origin of current window does not match opener', function (done) { - listener = function (event) { + it('does nothing when origin of current window does not match opener', (done) => { + listener = (event) => { assert.equal(event.data, undefined) done() } @@ -489,8 +463,8 @@ describe('chromium feature', function () { w = window.open(url, '', 'show=no') }) - it('works when origin matches', function (done) { - listener = function (event) { + it('works when origin matches', (done) => { + listener = (event) => { assert.equal(event.data, location.href) done() } @@ -498,8 +472,8 @@ describe('chromium feature', function () { w = window.open(`file://${fixtures}/pages/window-opener-location.html`, '', 'show=no') }) - it('works when origin does not match opener but has node integration', function (done) { - listener = function (event) { + it('works when origin does not match opener but has node integration', (done) => { + listener = (event) => { assert.equal(event.data, location.href) done() } @@ -508,31 +482,29 @@ describe('chromium feature', function () { }) }) - describe('window.opener access from ', function () { + describe('window.opener access from ', () => { const scheme = 'other' const srcPath = `${fixtures}/pages/webview-opener-postMessage.html` const pageURL = `file://${fixtures}/pages/window-opener-location.html` let webview = null - before(function (done) { - protocol.registerFileProtocol(scheme, function (request, callback) { + before((done) => { + protocol.registerFileProtocol(scheme, (request, callback) => { callback(srcPath) - }, function (error) { - done(error) - }) + }, (error) => done(error)) }) - after(function () { + after(() => { protocol.unregisterProtocol(scheme) }) - afterEach(function () { + afterEach(() => { if (webview != null) webview.remove() }) - it('does nothing when origin of webview src URL does not match opener', function (done) { + it('does nothing when origin of webview src URL does not match opener', (done) => { webview = new WebView() - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'null') done() }) @@ -548,9 +520,9 @@ describe('chromium feature', function () { document.body.appendChild(webview) }) - it('works when origin matches', function (done) { + it('works when origin matches', (done) => { webview = new WebView() - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, webview.src) done() }) @@ -566,9 +538,9 @@ describe('chromium feature', function () { document.body.appendChild(webview) }) - it('works when origin does not match opener but has node integration', function (done) { + it('works when origin does not match opener but has node integration', (done) => { webview = new WebView() - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { webview.remove() assert.equal(e.message, webview.src) done() @@ -587,13 +559,13 @@ describe('chromium feature', function () { }) }) - describe('window.postMessage', function () { - it('sets the source and origin correctly', function (done) { - var b - listener = function (event) { + describe('window.postMessage', () => { + it('sets the source and origin correctly', (done) => { + let b + listener = (event) => { window.removeEventListener('message', listener) b.close() - var message = JSON.parse(event.data) + const message = JSON.parse(event.data) assert.equal(message.data, 'testing') assert.equal(message.origin, 'file://') assert.equal(message.sourceEqualsOpener, true) @@ -602,26 +574,26 @@ describe('chromium feature', function () { } window.addEventListener('message', listener) app.once('browser-window-created', (event, {webContents}) => { - webContents.once('did-finish-load', function () { + webContents.once('did-finish-load', () => { b.postMessage('testing', '*') }) }) - b = window.open('file://' + fixtures + '/pages/window-open-postMessage.html', '', 'show=no') + b = window.open(`file://${fixtures}/pages/window-open-postMessage.html`, '', 'show=no') }) - it('throws an exception when the targetOrigin cannot be converted to a string', function () { - var b = window.open('') - assert.throws(function () { + it('throws an exception when the targetOrigin cannot be converted to a string', () => { + const b = window.open('') + assert.throws(() => { b.postMessage('test', {toString: null}) }, /Cannot convert object to primitive value/) b.close() }) }) - describe('window.opener.postMessage', function () { - it('sets source and origin correctly', function (done) { - var b - listener = function (event) { + describe('window.opener.postMessage', () => { + it('sets source and origin correctly', (done) => { + let b + listener = (event) => { window.removeEventListener('message', listener) b.close() assert.equal(event.source, b) @@ -629,12 +601,12 @@ describe('chromium feature', function () { done() } window.addEventListener('message', listener) - b = window.open('file://' + fixtures + '/pages/window-opener-postMessage.html', '', 'show=no') + b = window.open(`file://${fixtures}/pages/window-opener-postMessage.html`, '', 'show=no') }) - it('supports windows opened from a ', function (done) { + it('supports windows opened from a ', (done) => { const webview = new WebView() - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { webview.remove() assert.equal(e.message, 'message') done() @@ -651,29 +623,29 @@ describe('chromium feature', function () { document.body.appendChild(webview) }) - describe('targetOrigin argument', function () { + describe('targetOrigin argument', () => { let serverURL let server - beforeEach(function (done) { - server = http.createServer(function (req, res) { + beforeEach((done) => { + server = http.createServer((req, res) => { res.writeHead(200) const filePath = path.join(fixtures, 'pages', 'window-opener-targetOrigin.html') res.end(fs.readFileSync(filePath, 'utf8')) }) - server.listen(0, '127.0.0.1', function () { + server.listen(0, '127.0.0.1', () => { serverURL = `http://127.0.0.1:${server.address().port}` done() }) }) - afterEach(function () { + afterEach(() => { server.close() }) - it('delivers messages that match the origin', function (done) { + it('delivers messages that match the origin', (done) => { let b - listener = function (event) { + listener = (event) => { window.removeEventListener('message', listener) b.close() assert.equal(event.data, 'deliver') @@ -685,32 +657,30 @@ describe('chromium feature', function () { }) }) - describe('creating a Uint8Array under browser side', function () { - it('does not crash', function () { - var RUint8Array = remote.getGlobal('Uint8Array') - var arr = new RUint8Array() + describe('creating a Uint8Array under browser side', () => { + it('does not crash', () => { + const RUint8Array = remote.getGlobal('Uint8Array') + const arr = new RUint8Array() assert(arr) }) }) - describe('webgl', function () { - if (isCI && process.platform === 'win32') { - return - } + describe('webgl', () => { + if (isCI && process.platform === 'win32') return - it('can be get as context in canvas', function () { + it('can be get as context in canvas', () => { if (process.platform === 'linux') return - var webgl = document.createElement('canvas').getContext('webgl') + const webgl = document.createElement('canvas').getContext('webgl') assert.notEqual(webgl, null) }) }) - describe('web workers', function () { - it('Worker can work', function (done) { - var worker = new Worker('../fixtures/workers/worker.js') - var message = 'ping' - worker.onmessage = function (event) { + describe('web workers', () => { + it('Worker can work', (done) => { + const worker = new Worker('../fixtures/workers/worker.js') + const message = 'ping' + worker.onmessage = (event) => { assert.equal(event.data, message) worker.terminate() done() @@ -718,95 +688,95 @@ describe('chromium feature', function () { worker.postMessage(message) }) - it('Worker has no node integration by default', function (done) { + it('Worker has no node integration by default', (done) => { let worker = new Worker('../fixtures/workers/worker_node.js') - worker.onmessage = function (event) { + worker.onmessage = (event) => { assert.equal(event.data, 'undefined undefined undefined undefined') worker.terminate() done() } }) - it('Worker has node integration with nodeIntegrationInWorker', function (done) { + it('Worker has node integration with nodeIntegrationInWorker', (done) => { let webview = new WebView() - webview.addEventListener('ipc-message', function (e) { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'object function object function') webview.remove() done() }) - webview.src = 'file://' + fixtures + '/pages/worker.html' + webview.src = `file://${fixtures}/pages/worker.html` webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker') document.body.appendChild(webview) }) - it('SharedWorker can work', function (done) { - var worker = new SharedWorker('../fixtures/workers/shared_worker.js') - var message = 'ping' - worker.port.onmessage = function (event) { + it('SharedWorker can work', (done) => { + const worker = new SharedWorker('../fixtures/workers/shared_worker.js') + const message = 'ping' + worker.port.onmessage = (event) => { assert.equal(event.data, message) done() } worker.port.postMessage(message) }) - it('SharedWorker has no node integration by default', function (done) { + it('SharedWorker has no node integration by default', (done) => { let worker = new SharedWorker('../fixtures/workers/shared_worker_node.js') - worker.port.onmessage = function (event) { + worker.port.onmessage = (event) => { assert.equal(event.data, 'undefined undefined undefined undefined') done() } }) - it('SharedWorker has node integration with nodeIntegrationInWorker', function (done) { + it('SharedWorker has node integration with nodeIntegrationInWorker', (done) => { let webview = new WebView() - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { console.log(e) }) - webview.addEventListener('ipc-message', function (e) { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'object function object function') webview.remove() done() }) - webview.src = 'file://' + fixtures + '/pages/shared_worker.html' + webview.src = `file://${fixtures}/pages/shared_worker.html` webview.setAttribute('webpreferences', 'nodeIntegration, nodeIntegrationInWorker') document.body.appendChild(webview) }) }) - describe('iframe', function () { - var iframe = null + describe('iframe', () => { + let iframe = null - beforeEach(function () { + beforeEach(() => { iframe = document.createElement('iframe') }) - afterEach(function () { + afterEach(() => { document.body.removeChild(iframe) }) - it('does not have node integration', function (done) { - iframe.src = 'file://' + fixtures + '/pages/set-global.html' + it('does not have node integration', (done) => { + iframe.src = `file://${fixtures}/pages/set-global.html` document.body.appendChild(iframe) - iframe.onload = function () { + iframe.onload = () => { assert.equal(iframe.contentWindow.test, 'undefined undefined undefined') done() } }) }) - describe('storage', function () { - it('requesting persitent quota works', function (done) { - navigator.webkitPersistentStorage.requestQuota(1024 * 1024, function (grantedBytes) { + describe('storage', () => { + it('requesting persitent quota works', (done) => { + navigator.webkitPersistentStorage.requestQuota(1024 * 1024, (grantedBytes) => { assert.equal(grantedBytes, 1048576) done() }) }) - describe('custom non standard schemes', function () { + describe('custom non standard schemes', () => { const protocolName = 'storage' let contents = null - before(function (done) { - const handler = function (request, callback) { + before((done) => { + const handler = (request, callback) => { let parsedUrl = url.parse(request.url) let filename switch (parsedUrl.pathname) { @@ -817,28 +787,26 @@ describe('chromium feature', function () { case '/cookie' : filename = 'cookie.html'; break default : filename = '' } - callback({path: fixtures + '/pages/storage/' + filename}) + callback({path: `${fixtures}/pages/storage/${filename}`}) } - protocol.registerFileProtocol(protocolName, handler, function (error) { - done(error) - }) + protocol.registerFileProtocol(protocolName, handler, (error) => done(error)) }) - after(function (done) { + after((done) => { protocol.unregisterProtocol(protocolName, () => done()) }) - beforeEach(function () { + beforeEach(() => { contents = webContents.create({}) }) - afterEach(function () { + afterEach(() => { contents.destroy() contents = null }) - it('cannot access localStorage', function (done) { - ipcMain.once('local-storage-response', function (event, error) { + it('cannot access localStorage', (done) => { + ipcMain.once('local-storage-response', (event, error) => { assert.equal( error, 'Failed to read the \'localStorage\' property from \'Window\': Access is denied for this document.') @@ -847,87 +815,85 @@ describe('chromium feature', function () { contents.loadURL(protocolName + '://host/localStorage') }) - it('cannot access sessionStorage', function (done) { - ipcMain.once('session-storage-response', function (event, error) { + it('cannot access sessionStorage', (done) => { + ipcMain.once('session-storage-response', (event, error) => { assert.equal( error, 'Failed to read the \'sessionStorage\' property from \'Window\': Access is denied for this document.') done() }) - contents.loadURL(protocolName + '://host/sessionStorage') + contents.loadURL(`${protocolName}://host/sessionStorage`) }) - it('cannot access WebSQL database', function (done) { - ipcMain.once('web-sql-response', function (event, error) { + it('cannot access WebSQL database', (done) => { + ipcMain.once('web-sql-response', (event, error) => { assert.equal( error, 'An attempt was made to break through the security policy of the user agent.') done() }) - contents.loadURL(protocolName + '://host/WebSQL') + contents.loadURL(`${protocolName}://host/WebSQL`) }) - it('cannot access indexedDB', function (done) { - ipcMain.once('indexed-db-response', function (event, error) { + it('cannot access indexedDB', (done) => { + ipcMain.once('indexed-db-response', (event, error) => { assert.equal(error, 'The user denied permission to access the database.') done() }) - contents.loadURL(protocolName + '://host/indexedDB') + contents.loadURL(`${protocolName}://host/indexedDB`) }) - it('cannot access cookie', function (done) { - ipcMain.once('cookie-response', function (event, cookie) { + it('cannot access cookie', (done) => { + ipcMain.once('cookie-response', (event, cookie) => { assert(!cookie) done() }) - contents.loadURL(protocolName + '://host/cookie') + contents.loadURL(`${protocolName}://host/cookie`) }) }) }) - describe('websockets', function () { - var wss = null - var server = null - var WebSocketServer = ws.Server + describe('websockets', () => { + let wss = null + let server = null + const WebSocketServer = ws.Server - afterEach(function () { + afterEach(() => { wss.close() server.close() }) - it('has user agent', function (done) { + it('has user agent', (done) => { server = http.createServer() - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - wss = new WebSocketServer({ - server: server - }) + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + wss = new WebSocketServer({ server: server }) wss.on('error', done) - wss.on('connection', function (ws) { + wss.on('connection', (ws) => { if (ws.upgradeReq.headers['user-agent']) { done() } else { done('user agent is empty') } }) - var socket = new WebSocket(`ws://127.0.0.1:${port}`) + const socket = new WebSocket(`ws://127.0.0.1:${port}`) assert(socket) }) }) }) - describe('Promise', function () { - it('resolves correctly in Node.js calls', function (done) { + describe('Promise', () => { + it('resolves correctly in Node.js calls', (done) => { document.registerElement('x-element', { prototype: Object.create(HTMLElement.prototype, { createdCallback: { - value: function () {} + value: () => {} } }) }) - setImmediate(function () { - var called = false - Promise.resolve().then(function () { + setImmediate(() => { + let called = false + Promise.resolve().then(() => { done(called ? void 0 : new Error('wrong sequence')) }) document.createElement('x-element') @@ -935,17 +901,17 @@ describe('chromium feature', function () { }) }) - it('resolves correctly in Electron calls', function (done) { + it('resolves correctly in Electron calls', (done) => { document.registerElement('y-element', { prototype: Object.create(HTMLElement.prototype, { createdCallback: { - value: function () {} + value: () => {} } }) }) - remote.getGlobal('setImmediate')(function () { - var called = false - Promise.resolve().then(function () { + remote.getGlobal('setImmediate')(() => { + let called = false + Promise.resolve().then(() => { done(called ? void 0 : new Error('wrong sequence')) }) document.createElement('y-element') @@ -954,29 +920,26 @@ describe('chromium feature', function () { }) }) - describe('fetch', function () { - it('does not crash', function (done) { - const server = http.createServer(function (req, res) { + describe('fetch', () => { + it('does not crash', (done) => { + const server = http.createServer((req, res) => { res.end('test') server.close() }) - server.listen(0, '127.0.0.1', function () { + server.listen(0, '127.0.0.1', () => { const port = server.address().port - fetch(`http://127.0.0.1:${port}`).then((res) => { - return res.body.getReader() - }).then((reader) => { - reader.read().then((r) => { - reader.cancel() - done() - }) - }).catch(function (e) { - done(e) - }) + fetch(`http://127.0.0.1:${port}`).then((res) => res.body.getReader()) + .then((reader) => { + reader.read().then((r) => { + reader.cancel() + done() + }) + }).catch((e) => done(e)) }) }) }) - describe('PDF Viewer', function () { + describe('PDF Viewer', () => { const pdfSource = url.format({ pathname: path.join(fixtures, 'assets', 'cat.pdf').replace(/\\/g, '/'), protocol: 'file', @@ -1002,13 +965,13 @@ describe('chromium feature', function () { }) } - it('opens when loading a pdf resource as top level navigation', function (done) { + it('opens when loading a pdf resource as top level navigation', (done) => { createBrowserWindow({plugins: true}) - ipcMain.once('pdf-loaded', function (event, state) { + ipcMain.once('pdf-loaded', (event, state) => { assert.equal(state, 'success') done() }) - w.webContents.on('page-title-updated', function () { + w.webContents.on('page-title-updated', () => { const parsedURL = url.parse(w.webContents.getURL(), true) assert.equal(parsedURL.protocol, 'chrome:') assert.equal(parsedURL.hostname, 'pdf-viewer') @@ -1018,13 +981,13 @@ describe('chromium feature', function () { w.webContents.loadURL(pdfSource) }) - it('opens a pdf link given params, the query string should be escaped', function (done) { + it('opens a pdf link given params, the query string should be escaped', (done) => { createBrowserWindow({plugins: true}) - ipcMain.once('pdf-loaded', function (event, state) { + ipcMain.once('pdf-loaded', (event, state) => { assert.equal(state, 'success') done() }) - w.webContents.on('page-title-updated', function () { + w.webContents.on('page-title-updated', () => { const parsedURL = url.parse(w.webContents.getURL(), true) assert.equal(parsedURL.protocol, 'chrome:') assert.equal(parsedURL.hostname, 'pdf-viewer') @@ -1036,10 +999,10 @@ describe('chromium feature', function () { w.webContents.loadURL(pdfSourceWithParams) }) - it('should download a pdf when plugins are disabled', function (done) { + it('should download a pdf when plugins are disabled', (done) => { createBrowserWindow({plugins: false}) ipcRenderer.sendSync('set-download-option', false, false) - ipcRenderer.once('download-done', function (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) { + ipcRenderer.once('download-done', (event, state, url, mimeType, receivedBytes, totalBytes, disposition, filename) => { assert.equal(state, 'completed') assert.equal(filename, 'cat.pdf') assert.equal(mimeType, 'application/pdf') @@ -1049,7 +1012,7 @@ describe('chromium feature', function () { w.webContents.loadURL(pdfSource) }) - it('should not open when pdf is requested as sub resource', function (done) { + it('should not open when pdf is requested as sub resource', (done) => { createBrowserWindow({plugins: true}) webFrame.registerURLSchemeAsPrivileged('file', { secure: false, @@ -1057,54 +1020,50 @@ describe('chromium feature', function () { allowServiceWorkers: false, corsEnabled: false }) - fetch(pdfSource).then(function (res) { + fetch(pdfSource).then((res) => { assert.equal(res.status, 200) assert.notEqual(document.title, 'cat.pdf') done() - }).catch(function (e) { - done(e) - }) + }).catch((e) => done(e)) }) }) - describe('window.alert(message, title)', function () { - it('throws an exception when the arguments cannot be converted to strings', function () { - assert.throws(function () { + describe('window.alert(message, title)', () => { + it('throws an exception when the arguments cannot be converted to strings', () => { + assert.throws(() => { window.alert({toString: null}) }, /Cannot convert object to primitive value/) - assert.throws(function () { + assert.throws(() => { window.alert('message', {toString: 3}) }, /Cannot convert object to primitive value/) }) }) - describe('window.confirm(message, title)', function () { - it('throws an exception when the arguments cannot be converted to strings', function () { - assert.throws(function () { + describe('window.confirm(message, title)', () => { + it('throws an exception when the arguments cannot be converted to strings', () => { + assert.throws(() => { window.confirm({toString: null}, 'title') }, /Cannot convert object to primitive value/) - assert.throws(function () { + assert.throws(() => { window.confirm('message', {toString: 3}) }, /Cannot convert object to primitive value/) }) }) - describe('window.history', function () { - describe('window.history.go(offset)', function () { - it('throws an exception when the argumnet cannot be converted to a string', function () { - assert.throws(function () { + describe('window.history', () => { + describe('window.history.go(offset)', () => { + it('throws an exception when the argumnet cannot be converted to a string', () => { + assert.throws(() => { window.history.go({toString: null}) }, /Cannot convert object to primitive value/) }) }) - describe('window.history.pushState', function () { + describe('window.history.pushState', () => { it('should push state after calling history.pushState() from the same url', (done) => { - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) w.webContents.once('did-finish-load', () => { // History should have current page by now. assert.equal(w.webContents.length(), 1) diff --git a/spec/modules-spec.js b/spec/modules-spec.js index 51f54201f56..f082aeddcd3 100644 --- a/spec/modules-spec.js +++ b/spec/modules-spec.js @@ -7,45 +7,45 @@ const {closeWindow} = require('./window-helpers') const nativeModulesEnabled = remote.getGlobal('nativeModulesEnabled') -describe('modules support', function () { - var fixtures = path.join(__dirname, 'fixtures') +describe('modules support', () => { + const fixtures = path.join(__dirname, 'fixtures') - describe('third-party module', function () { - describe('runas', function () { + describe('third-party module', () => { + describe('runas', () => { if (!nativeModulesEnabled) return - it('can be required in renderer', function () { + it('can be required in renderer', () => { require('runas') }) - it('can be required in node binary', function (done) { - var runas = path.join(fixtures, 'module', 'runas.js') - var child = require('child_process').fork(runas) - child.on('message', function (msg) { + it('can be required in node binary', (done) => { + const runas = path.join(fixtures, 'module', 'runas.js') + const child = require('child_process').fork(runas) + child.on('message', (msg) => { assert.equal(msg, 'ok') done() }) }) }) - describe('ffi', function () { + describe('ffi', () => { if (!nativeModulesEnabled) return if (process.platform === 'win32') return - it('does not crash', function () { - var ffi = require('ffi') - var libm = ffi.Library('libm', { + it('does not crash', () => { + const ffi = require('ffi') + const libm = ffi.Library('libm', { ceil: ['double', ['double']] }) assert.equal(libm.ceil(1.5), 2) }) }) - describe('q', function () { - var Q = require('q') - describe('Q.when', function () { - it('emits the fullfil callback', function (done) { - Q(true).then(function (val) { + describe('q', () => { + const Q = require('q') + describe('Q.when', () => { + it('emits the fullfil callback', (done) => { + Q(true).then((val) => { assert.equal(val, true) done() }) @@ -53,9 +53,9 @@ describe('modules support', function () { }) }) - describe('coffee-script', function () { - it('can be registered and used to require .coffee files', function () { - assert.doesNotThrow(function () { + describe('coffee-script', () => { + it('can be registered and used to require .coffee files', () => { + assert.doesNotThrow(() => { require('coffee-script').register() }) assert.strictEqual(require('./fixtures/module/test.coffee'), true) @@ -63,36 +63,36 @@ describe('modules support', function () { }) }) - describe('global variables', function () { - describe('process', function () { - it('can be declared in a module', function () { + describe('global variables', () => { + describe('process', () => { + it('can be declared in a module', () => { assert.strictEqual(require('./fixtures/module/declare-process'), 'declared process') }) }) - describe('global', function () { - it('can be declared in a module', function () { + describe('global', () => { + it('can be declared in a module', () => { assert.strictEqual(require('./fixtures/module/declare-global'), 'declared global') }) }) - describe('Buffer', function () { - it('can be declared in a module', function () { + describe('Buffer', () => { + it('can be declared in a module', () => { assert.strictEqual(require('./fixtures/module/declare-buffer'), 'declared Buffer') }) }) }) - describe('Module._nodeModulePaths', function () { - describe('when the path is inside the resources path', function () { - it('does not include paths outside of the resources path', function () { + describe('Module._nodeModulePaths', () => { + describe('when the path is inside the resources path', () => { + it('does not include paths outside of the resources path', () => { let modulePath = process.resourcesPath assert.deepEqual(Module._nodeModulePaths(modulePath), [ path.join(process.resourcesPath, 'node_modules') ]) modulePath = process.resourcesPath + '-foo' - let nodeModulePaths = Module._nodeModulePaths(modulePath) + const nodeModulePaths = Module._nodeModulePaths(modulePath) assert(nodeModulePaths.includes(path.join(modulePath, 'node_modules'))) assert(nodeModulePaths.includes(path.join(modulePath, '..', 'node_modules'))) @@ -124,8 +124,8 @@ describe('modules support', function () { }) }) - describe('when the path is outside the resources path', function () { - it('includes paths outside of the resources path', function () { + describe('when the path is outside the resources path', () => { + it('includes paths outside of the resources path', () => { let modulePath = path.resolve('/foo') assert.deepEqual(Module._nodeModulePaths(modulePath), [ path.join(modulePath, 'node_modules'), @@ -140,9 +140,7 @@ describe('modules support', function () { let w beforeEach(() => { - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({show: false}) }) afterEach(async () => { diff --git a/spec/node-spec.js b/spec/node-spec.js index 7e83ec9e565..1603b160ca6 100644 --- a/spec/node-spec.js +++ b/spec/node-spec.js @@ -7,80 +7,80 @@ const {ipcRenderer, remote} = require('electron') const isCI = remote.getGlobal('isCi') -describe('node feature', function () { - var fixtures = path.join(__dirname, 'fixtures') +describe('node feature', () => { + const fixtures = path.join(__dirname, 'fixtures') - describe('child_process', function () { - describe('child_process.fork', function () { - it('works in current process', function (done) { - var child = ChildProcess.fork(path.join(fixtures, 'module', 'ping.js')) - child.on('message', function (msg) { + describe('child_process', () => { + describe('child_process.fork', () => { + it('works in current process', (done) => { + const child = ChildProcess.fork(path.join(fixtures, 'module', 'ping.js')) + child.on('message', (msg) => { assert.equal(msg, 'message') done() }) child.send('message') }) - it('preserves args', function (done) { - var args = ['--expose_gc', '-test', '1'] - var child = ChildProcess.fork(path.join(fixtures, 'module', 'process_args.js'), args) - child.on('message', function (msg) { + it('preserves args', (done) => { + const args = ['--expose_gc', '-test', '1'] + const child = ChildProcess.fork(path.join(fixtures, 'module', 'process_args.js'), args) + child.on('message', (msg) => { assert.deepEqual(args, msg.slice(2)) done() }) child.send('message') }) - it('works in forked process', function (done) { - var child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js')) - child.on('message', function (msg) { + it('works in forked process', (done) => { + const child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js')) + child.on('message', (msg) => { assert.equal(msg, 'message') done() }) child.send('message') }) - it('works in forked process when options.env is specifed', function (done) { - var child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js'), [], { + it('works in forked process when options.env is specifed', (done) => { + const child = ChildProcess.fork(path.join(fixtures, 'module', 'fork_ping.js'), [], { path: process.env['PATH'] }) - child.on('message', function (msg) { + child.on('message', (msg) => { assert.equal(msg, 'message') done() }) child.send('message') }) - it('works in browser process', function (done) { - var fork = remote.require('child_process').fork - var child = fork(path.join(fixtures, 'module', 'ping.js')) - child.on('message', function (msg) { + it('works in browser process', (done) => { + const fork = remote.require('child_process').fork + const child = fork(path.join(fixtures, 'module', 'ping.js')) + child.on('message', (msg) => { assert.equal(msg, 'message') done() }) child.send('message') }) - it('has String::localeCompare working in script', function (done) { - var child = ChildProcess.fork(path.join(fixtures, 'module', 'locale-compare.js')) - child.on('message', function (msg) { + it('has String::localeCompare working in script', (done) => { + const child = ChildProcess.fork(path.join(fixtures, 'module', 'locale-compare.js')) + child.on('message', (msg) => { assert.deepEqual(msg, [0, -1, 1]) done() }) child.send('message') }) - it('has setImmediate working in script', function (done) { - var child = ChildProcess.fork(path.join(fixtures, 'module', 'set-immediate.js')) - child.on('message', function (msg) { + it('has setImmediate working in script', (done) => { + const child = ChildProcess.fork(path.join(fixtures, 'module', 'set-immediate.js')) + child.on('message', (msg) => { assert.equal(msg, 'ok') done() }) child.send('message') }) - it('pipes stdio', function (done) { - let child = ChildProcess.fork(path.join(fixtures, 'module', 'process-stdout.js'), {silent: true}) + it('pipes stdio', (done) => { + const child = ChildProcess.fork(path.join(fixtures, 'module', 'process-stdout.js'), {silent: true}) let data = '' child.stdout.on('data', (chunk) => { data += String(chunk) @@ -92,7 +92,7 @@ describe('node feature', function () { }) }) - it('works when sending a message to a process forked with the --eval argument', function (done) { + it('works when sending a message to a process forked with the --eval argument', (done) => { const source = "process.on('message', (message) => { process.send(message) })" const forked = ChildProcess.fork('--eval', [source]) forked.once('message', (message) => { @@ -103,16 +103,14 @@ describe('node feature', function () { }) }) - describe('child_process.spawn', function () { + describe('child_process.spawn', () => { let child - afterEach(function () { - if (child != null) { - child.kill() - } + afterEach(() => { + if (child != null) child.kill() }) - it('supports spawning Electron as a node process via the ELECTRON_RUN_AS_NODE env var', function (done) { + it('supports spawning Electron as a node process via the ELECTRON_RUN_AS_NODE env var', (done) => { child = ChildProcess.spawn(process.execPath, [path.join(__dirname, 'fixtures', 'module', 'run-as-node.js')], { env: { ELECTRON_RUN_AS_NODE: true @@ -120,10 +118,10 @@ describe('node feature', function () { }) let output = '' - child.stdout.on('data', function (data) { + child.stdout.on('data', (data) => { output += data }) - child.stdout.on('close', function () { + child.stdout.on('close', () => { assert.deepEqual(JSON.parse(output), { processLog: process.platform === 'win32' ? 'function' : 'undefined', processType: 'undefined', @@ -133,7 +131,7 @@ describe('node feature', function () { }) }) - it('supports starting the v8 inspector with --inspect/--inspect-brk', function (done) { + it('supports starting the v8 inspector with --inspect/--inspect-brk', (done) => { child = ChildProcess.spawn(process.execPath, ['--inspect-brk', path.join(__dirname, 'fixtures', 'module', 'run-as-node.js')], { env: { ELECTRON_RUN_AS_NODE: true @@ -141,36 +139,31 @@ describe('node feature', function () { }) let output = '' - child.stderr.on('data', function (data) { + child.stderr.on('data', (data) => { output += data - - if (output.trim().startsWith('Debugger listening on ws://')) { - done() - } + if (output.trim().startsWith('Debugger listening on ws://')) done() }) - child.stdout.on('data', function (data) { + child.stdout.on('data', (data) => { done(new Error(`Unexpected output: ${data.toString()}`)) }) }) }) }) - describe('contexts', function () { - describe('setTimeout in fs callback', function () { - if (process.env.TRAVIS === 'true') { - return - } + describe('contexts', () => { + describe('setTimeout in fs callback', () => { + if (process.env.TRAVIS === 'true') return - it('does not crash', function (done) { - fs.readFile(__filename, function () { + it('does not crash', (done) => { + fs.readFile(__filename, () => { setTimeout(done, 0) }) }) }) - describe('error thrown in renderer process node context', function () { - it('gets emitted as a process uncaughtException event', function (done) { + describe('error thrown in renderer process node context', () => { + it('gets emitted as a process uncaughtException event', (done) => { const error = new Error('boo!') const listeners = process.listeners('uncaughtException') process.removeAllListeners('uncaughtException') @@ -188,30 +181,31 @@ describe('node feature', function () { }) }) - describe('error thrown in main process node context', function () { - it('gets emitted as a process uncaughtException event', function () { + describe('error thrown in main process node context', () => { + it('gets emitted as a process uncaughtException event', () => { const error = ipcRenderer.sendSync('handle-uncaught-exception', 'hello') assert.equal(error, 'hello') }) }) - describe('promise rejection in main process node context', function () { - it('gets emitted as a process unhandledRejection event', function () { + describe('promise rejection in main process node context', () => { + it('gets emitted as a process unhandledRejection event', () => { const error = ipcRenderer.sendSync('handle-unhandled-rejection', 'hello') assert.equal(error, 'hello') }) }) - describe('setTimeout called under Chromium event loop in browser process', function () { - it('can be scheduled in time', function (done) { + describe('setTimeout called under Chromium event loop in browser process', () => { + it('can be scheduled in time', (done) => { remote.getGlobal('setTimeout')(done, 0) }) }) - describe('setInterval called under Chromium event loop in browser process', function () { - it('can be scheduled in time', function (done) { - var clear, interval - clear = function () { + describe('setInterval called under Chromium event loop in browser process', () => { + it('can be scheduled in time', (done) => { + let clear + let interval + clear = () => { remote.getGlobal('clearInterval')(interval) done() } @@ -220,29 +214,29 @@ describe('node feature', function () { }) }) - describe('message loop', function () { - describe('process.nextTick', function () { - it('emits the callback', function (done) { + describe('message loop', () => { + describe('process.nextTick', () => { + it('emits the callback', (done) => { process.nextTick(done) }) - it('works in nested calls', function (done) { - process.nextTick(function () { - process.nextTick(function () { + it('works in nested calls', (done) => { + process.nextTick(() => { + process.nextTick(() => { process.nextTick(done) }) }) }) }) - describe('setImmediate', function () { - it('emits the callback', function (done) { + describe('setImmediate', () => { + it('emits the callback', (done) => { setImmediate(done) }) - it('works in nested calls', function (done) { - setImmediate(function () { - setImmediate(function () { + it('works in nested calls', (done) => { + setImmediate(() => { + setImmediate(() => { setImmediate(done) }) }) @@ -250,19 +244,17 @@ describe('node feature', function () { }) }) - describe('net.connect', function () { - if (process.platform !== 'darwin') { - return - } + describe('net.connect', () => { + if (process.platform !== 'darwin') return - it('emit error when connect to a socket path without listeners', function (done) { - var socketPath = path.join(os.tmpdir(), 'atom-shell-test.sock') - var script = path.join(fixtures, 'module', 'create_socket.js') - var child = ChildProcess.fork(script, [socketPath]) - child.on('exit', function (code) { + it('emit error when connect to a socket path without listeners', (done) => { + const socketPath = path.join(os.tmpdir(), 'atom-shell-test.sock') + const script = path.join(fixtures, 'module', 'create_socket.js') + const child = ChildProcess.fork(script, [socketPath]) + child.on('exit', (code) => { assert.equal(code, 0) - var client = require('net').connect(socketPath) - client.on('error', function (error) { + const client = require('net').connect(socketPath) + client.on('error', (error) => { assert.equal(error.code, 'ECONNREFUSED') done() }) @@ -270,45 +262,45 @@ describe('node feature', function () { }) }) - describe('Buffer', function () { - it('can be created from WebKit external string', function () { - var p = document.createElement('p') + describe('Buffer', () => { + it('can be created from WebKit external string', () => { + const p = document.createElement('p') p.innerText = '闲云潭影日悠悠,物换星移几度秋' - var b = new Buffer(p.innerText) + const b = new Buffer(p.innerText) assert.equal(b.toString(), '闲云潭影日悠悠,物换星移几度秋') assert.equal(Buffer.byteLength(p.innerText), 45) }) - it('correctly parses external one-byte UTF8 string', function () { - var p = document.createElement('p') + it('correctly parses external one-byte UTF8 string', () => { + const p = document.createElement('p') p.innerText = 'Jøhänñéß' - var b = new Buffer(p.innerText) + const b = new Buffer(p.innerText) assert.equal(b.toString(), 'Jøhänñéß') assert.equal(Buffer.byteLength(p.innerText), 13) }) - it('does not crash when creating large Buffers', function () { - var buffer = new Buffer(new Array(4096).join(' ')) + it('does not crash when creating large Buffers', () => { + let buffer = new Buffer(new Array(4096).join(' ')) assert.equal(buffer.length, 4095) buffer = new Buffer(new Array(4097).join(' ')) assert.equal(buffer.length, 4096) }) }) - describe('process.stdout', function () { - it('does not throw an exception when accessed', function () { - assert.doesNotThrow(function () { + describe('process.stdout', () => { + it('does not throw an exception when accessed', () => { + assert.doesNotThrow(() => { process.stdout }) }) - it('does not throw an exception when calling write()', function () { - assert.doesNotThrow(function () { + it('does not throw an exception when calling write()', () => { + assert.doesNotThrow(() => { process.stdout.write('test') }) }) - it('should have isTTY defined on Mac and Linux', function () { + it('should have isTTY defined on Mac and Linux', () => { if (isCI) return if (process.platform === 'win32') { @@ -319,26 +311,26 @@ describe('node feature', function () { }) }) - describe('process.stdin', function () { - it('does not throw an exception when accessed', function () { - assert.doesNotThrow(function () { + describe('process.stdin', () => { + it('does not throw an exception when accessed', () => { + assert.doesNotThrow(() => { process.stdin }) }) - it('returns null when read from', function () { + it('returns null when read from', () => { assert.equal(process.stdin.read(), null) }) }) - describe('process.version', function () { - it('should not have -pre', function () { + describe('process.version', () => { + it('should not have -pre', () => { assert(!process.version.endsWith('-pre')) }) }) - describe('vm.createContext', function () { - it('should not crash', function () { + describe('vm.createContext', () => { + it('should not crash', () => { require('vm').runInNewContext('') }) }) diff --git a/spec/webview-spec.js b/spec/webview-spec.js index 656465f034e..63b17e65d8d 100644 --- a/spec/webview-spec.js +++ b/spec/webview-spec.js @@ -12,32 +12,29 @@ const nativeModulesEnabled = remote.getGlobal('nativeModulesEnabled') describe(' tag', function () { this.timeout(3 * 60 * 1000) - var fixtures = path.join(__dirname, 'fixtures') - - var webview = null + const fixtures = path.join(__dirname, 'fixtures') + let webview = null let w = null - beforeEach(function () { + beforeEach(() => { webview = new WebView() }) - afterEach(function () { + afterEach(() => { if (!document.body.contains(webview)) { document.body.appendChild(webview) } webview.remove() - return closeWindow(w).then(function () { w = null }) + return closeWindow(w).then(() => { w = null }) }) - it('works without script tag in page', function (done) { + it('works without script tag in page', (done) => { w = new BrowserWindow({show: false}) - ipcMain.once('pong', function () { - done() - }) + ipcMain.once('pong', () => done()) w.loadURL('file://' + fixtures + '/pages/webview-no-script.html') }) - it('is disabled when nodeIntegration is disabled', function (done) { + it('is disabled when nodeIntegration is disabled', (done) => { w = new BrowserWindow({ show: false, webPreferences: { @@ -45,17 +42,17 @@ describe(' tag', function () { preload: path.join(fixtures, 'module', 'preload-webview.js') } }) - ipcMain.once('webview', function (event, type) { + ipcMain.once('webview', (event, type) => { if (type === 'undefined') { done() } else { done('WebView still exists') } }) - w.loadURL('file://' + fixtures + '/pages/webview-no-script.html') + w.loadURL(`file://${fixtures}/pages/webview-no-script.html`) }) - it('is enabled when the webviewTag option is enabled and the nodeIntegration option is disabled', function (done) { + it('is enabled when the webviewTag option is enabled and the nodeIntegration option is disabled', (done) => { w = new BrowserWindow({ show: false, webPreferences: { @@ -64,42 +61,42 @@ describe(' tag', function () { webviewTag: true } }) - ipcMain.once('webview', function (event, type) { + ipcMain.once('webview', (event, type) => { if (type !== 'undefined') { done() } else { done('WebView is not created') } }) - w.loadURL('file://' + fixtures + '/pages/webview-no-script.html') + w.loadURL(`file://${fixtures}/pages/webview-no-script.html`) }) - describe('src attribute', function () { - it('specifies the page to load', function (done) { - webview.addEventListener('console-message', function (e) { + describe('src attribute', () => { + it('specifies the page to load', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'a') done() }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) - it('navigates to new page when changed', function (done) { - var listener = function () { - webview.src = 'file://' + fixtures + '/pages/b.html' - webview.addEventListener('console-message', function (e) { + it('navigates to new page when changed', (done) => { + const listener = () => { + webview.src = `file://${fixtures}/pages/b.html` + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'b') done() }) webview.removeEventListener('did-finish-load', listener) } webview.addEventListener('did-finish-load', listener) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) - it('resolves relative URLs', function (done) { - var listener = function (e) { + it('resolves relative URLs', (done) => { + const listener = (e) => { assert.equal(e.message, 'Window script is loaded before preload script') webview.removeEventListener('console-message', listener) done() @@ -109,7 +106,7 @@ describe(' tag', function () { document.body.appendChild(webview) }) - it('ignores empty values', function () { + it('ignores empty values', () => { assert.equal(webview.src, '') webview.src = '' assert.equal(webview.src, '') @@ -120,41 +117,41 @@ describe(' tag', function () { }) }) - describe('nodeintegration attribute', function () { - it('inserts no node symbols when not set', function (done) { - webview.addEventListener('console-message', function (e) { + describe('nodeintegration attribute', () => { + it('inserts no node symbols when not set', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'undefined undefined undefined undefined') done() }) - webview.src = 'file://' + fixtures + '/pages/c.html' + webview.src = `file://${fixtures}/pages/c.html` document.body.appendChild(webview) }) - it('inserts node symbols when set', function (done) { - webview.addEventListener('console-message', function (e) { + it('inserts node symbols when set', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'function object object') done() }) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/d.html' + webview.src = `file://${fixtures}/pages/d.html` document.body.appendChild(webview) }) - it('loads node symbols after POST navigation when set', function (done) { + it('loads node symbols after POST navigation when set', (done) => { // FIXME Figure out why this is timing out on AppVeyor if (process.env.APPVEYOR === 'True') return done() - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'function object object') done() }) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/post.html' + webview.src = `file://${fixtures}/pages/post.html` document.body.appendChild(webview) }) - it('disables node integration on child windows when it is disabled on the webview', function (done) { - app.once('browser-window-created', function (event, window) { + it('disables node integration on child windows when it is disabled on the webview', (done) => { + app.once('browser-window-created', (event, window) => { assert.equal(window.webContents.getWebPreferences().nodeIntegration, false) done() }) @@ -172,12 +169,12 @@ describe(' tag', function () { document.body.appendChild(webview) }) - it('loads native modules when navigation happens', function (done) { + it('loads native modules when navigation happens', (done) => { if (!nativeModulesEnabled) return done() - var listener = function () { + const listener = () => { webview.removeEventListener('did-finish-load', listener) - var listener2 = function (e) { + const listener2 = (e) => { assert.equal(e.message, 'function') done() } @@ -186,88 +183,88 @@ describe(' tag', function () { } webview.addEventListener('did-finish-load', listener) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/native-module.html' + webview.src = `file://${fixtures}/pages/native-module.html` document.body.appendChild(webview) }) }) - describe('preload attribute', function () { - it('loads the script before other scripts in window', function (done) { - var listener = function (e) { + describe('preload attribute', () => { + it('loads the script before other scripts in window', (done) => { + const listener = (e) => { assert.equal(e.message, 'function object object function') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) - webview.setAttribute('preload', fixtures + '/module/preload.js') - webview.src = 'file://' + fixtures + '/pages/e.html' + webview.setAttribute('preload', `${fixtures}/module/preload.js`) + webview.src = `file://${fixtures}/pages/e.html` document.body.appendChild(webview) }) - it('preload script can still use "process" and "Buffer" when nodeintegration is off', function (done) { - webview.addEventListener('console-message', function (e) { + it('preload script can still use "process" and "Buffer" when nodeintegration is off', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'object undefined object function') done() }) - webview.setAttribute('preload', fixtures + '/module/preload-node-off.js') - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.setAttribute('preload', `${fixtures}/module/preload-node-off.js`) + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('preload script can require modules that still use "process" and "Buffer" when nodeintegration is off', function (done) { - webview.addEventListener('console-message', function (e) { + it('preload script can require modules that still use "process" and "Buffer" when nodeintegration is off', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'object undefined object function undefined') done() }) - webview.setAttribute('preload', fixtures + '/module/preload-node-off-wrapper.js') - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.setAttribute('preload', `${fixtures}/module/preload-node-off-wrapper.js`) + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('receives ipc message in preload script', function (done) { - var message = 'boom!' - var listener = function (e) { + it('receives ipc message in preload script', (done) => { + const message = 'boom!' + const listener = (e) => { assert.equal(e.channel, 'pong') assert.deepEqual(e.args, [message]) webview.removeEventListener('ipc-message', listener) done() } - var listener2 = function () { + const listener2 = () => { webview.send('ping', message) webview.removeEventListener('did-finish-load', listener2) } webview.addEventListener('ipc-message', listener) webview.addEventListener('did-finish-load', listener2) - webview.setAttribute('preload', fixtures + '/module/preload-ipc.js') - webview.src = 'file://' + fixtures + '/pages/e.html' + webview.setAttribute('preload', `${fixtures}/module/preload-ipc.js`) + webview.src = `file://${fixtures}/pages/e.html` document.body.appendChild(webview) }) - it('works without script tag in page', function (done) { - var listener = function (e) { + it('works without script tag in page', (done) => { + const listener = (e) => { assert.equal(e.message, 'function object object function') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) - webview.setAttribute('preload', fixtures + '/module/preload.js') - webview.src = 'file://' + fixtures + '/pages/base-page.html' + webview.setAttribute('preload', `${fixtures}/module/preload.js`) + webview.src = `file://${fixtures}pages/base-page.html` document.body.appendChild(webview) }) - it('resolves relative URLs', function (done) { - var listener = function (e) { + it('resolves relative URLs', (done) => { + const listener = (e) => { assert.equal(e.message, 'function object object function') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) - webview.src = 'file://' + fixtures + '/pages/e.html' + webview.src = `file://${fixtures}/pages/e.html` webview.preload = '../fixtures/module/preload.js' document.body.appendChild(webview) }) - it('ignores empty values', function () { + it('ignores empty values', () => { assert.equal(webview.preload, '') webview.preload = '' assert.equal(webview.preload, '') @@ -278,191 +275,189 @@ describe(' tag', function () { }) }) - describe('httpreferrer attribute', function () { - it('sets the referrer url', function (done) { - var referrer = 'http://github.com/' - var listener = function (e) { + describe('httpreferrer attribute', () => { + it('sets the referrer url', (done) => { + const referrer = 'http://github.com/' + const listener = (e) => { assert.equal(e.message, referrer) webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) webview.setAttribute('httpreferrer', referrer) - webview.src = 'file://' + fixtures + '/pages/referrer.html' + webview.src = `file://${fixtures}/pages/referrer.html` document.body.appendChild(webview) }) }) - describe('useragent attribute', function () { - it('sets the user agent', function (done) { - var referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko' - var listener = function (e) { + describe('useragent attribute', () => { + it('sets the user agent', (done) => { + const referrer = 'Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; AS; rv:11.0) like Gecko' + const listener = (e) => { assert.equal(e.message, referrer) webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) webview.setAttribute('useragent', referrer) - webview.src = 'file://' + fixtures + '/pages/useragent.html' + webview.src = `file://${fixtures}/pages/useragent.html` document.body.appendChild(webview) }) }) - describe('disablewebsecurity attribute', function () { - it('does not disable web security when not set', function (done) { - var jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') - var src = ` ` - var encoded = btoa(unescape(encodeURIComponent(src))) - var listener = function (e) { + describe('disablewebsecurity attribute', () => { + it('does not disable web security when not set', (done) => { + const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') + const src = ` ` + const encoded = btoa(unescape(encodeURIComponent(src))) + const listener = (e) => { assert(/Not allowed to load local resource/.test(e.message)) webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) - webview.src = 'data:text/html;base64,' + encoded + webview.src = `data:text/html;base64,${encoded}` document.body.appendChild(webview) }) - it('disables web security when set', function (done) { - var jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') - var src = ` ` - var encoded = btoa(unescape(encodeURIComponent(src))) - var listener = function (e) { + it('disables web security when set', (done) => { + const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') + const src = ` ` + const encoded = btoa(unescape(encodeURIComponent(src))) + const listener = (e) => { assert.equal(e.message, 'ok') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) webview.setAttribute('disablewebsecurity', '') - webview.src = 'data:text/html;base64,' + encoded + webview.src = `data:text/html;base64,${encoded}` document.body.appendChild(webview) }) - it('does not break node integration', function (done) { - webview.addEventListener('console-message', function (e) { + it('does not break node integration', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'function object object') done() }) webview.setAttribute('nodeintegration', 'on') webview.setAttribute('disablewebsecurity', '') - webview.src = 'file://' + fixtures + '/pages/d.html' + webview.src = `file://${fixtures}/pages/d.html` document.body.appendChild(webview) }) - it('does not break preload script', function (done) { - var listener = function (e) { + it('does not break preload script', (done) => { + const listener = (e) => { assert.equal(e.message, 'function object object function') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) webview.setAttribute('disablewebsecurity', '') - webview.setAttribute('preload', fixtures + '/module/preload.js') - webview.src = 'file://' + fixtures + '/pages/e.html' + webview.setAttribute('preload', `${fixtures}/module/preload.js`) + webview.src = `file://${fixtures}/pages/e.html` document.body.appendChild(webview) }) }) - describe('partition attribute', function () { - it('inserts no node symbols when not set', function (done) { - webview.addEventListener('console-message', function (e) { + describe('partition attribute', () => { + it('inserts no node symbols when not set', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'undefined undefined undefined undefined') done() }) - webview.src = 'file://' + fixtures + '/pages/c.html' + webview.src = `file://${fixtures}/pages/c.html` webview.partition = 'test1' document.body.appendChild(webview) }) - it('inserts node symbols when set', function (done) { - webview.addEventListener('console-message', function (e) { + it('inserts node symbols when set', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'function object object') done() }) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/d.html' + webview.src = `file://${fixtures}/pages/d.html` webview.partition = 'test2' document.body.appendChild(webview) }) - it('isolates storage for different id', function (done) { - var listener = function (e) { + it('isolates storage for different id', (done) => { + const listener = (e) => { assert.equal(e.message, ' 0') webview.removeEventListener('console-message', listener) done() } window.localStorage.setItem('test', 'one') webview.addEventListener('console-message', listener) - webview.src = 'file://' + fixtures + '/pages/partition/one.html' + webview.src = `file://${fixtures}/pages/partition/one.html` webview.partition = 'test3' document.body.appendChild(webview) }) - it('uses current session storage when no id is provided', function (done) { - var listener = function (e) { + it('uses current session storage when no id is provided', (done) => { + const listener = (e) => { assert.equal(e.message, 'one 1') webview.removeEventListener('console-message', listener) done() } window.localStorage.setItem('test', 'one') webview.addEventListener('console-message', listener) - webview.src = 'file://' + fixtures + '/pages/partition/one.html' + webview.src = `file://${fixtures}/pages/partition/one.html` document.body.appendChild(webview) }) }) - describe('allowpopups attribute', function () { - if (process.env.TRAVIS === 'true' && process.platform === 'darwin') { - return - } + describe('allowpopups attribute', () => { + if (process.env.TRAVIS === 'true' && process.platform === 'darwin') return - it('can not open new window when not set', function (done) { - var listener = function (e) { + it('can not open new window when not set', (done) => { + const listener = (e) => { assert.equal(e.message, 'null') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) - webview.src = 'file://' + fixtures + '/pages/window-open-hide.html' + webview.src = `file://${fixtures}/pages/window-open-hide.html` document.body.appendChild(webview) }) - it('can open new window when set', function (done) { - var listener = function (e) { + it('can open new window when set', (done) => { + const listener = (e) => { assert.equal(e.message, 'window') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) webview.setAttribute('allowpopups', 'on') - webview.src = 'file://' + fixtures + '/pages/window-open-hide.html' + webview.src = `file://${fixtures}/pages/window-open-hide.html` document.body.appendChild(webview) }) }) - describe('webpreferences attribute', function () { - it('can enable nodeintegration', function (done) { - webview.addEventListener('console-message', function (e) { + describe('webpreferences attribute', () => { + it('can enable nodeintegration', (done) => { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'function object object') done() }) webview.setAttribute('webpreferences', 'nodeIntegration') - webview.src = 'file://' + fixtures + '/pages/d.html' + webview.src = `file://${fixtures}/pages/d.html` document.body.appendChild(webview) }) - it('can disables web security and enable nodeintegration', function (done) { - var jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') - var src = ` ` - var encoded = btoa(unescape(encodeURIComponent(src))) - var listener = function (e) { + it('can disables web security and enable nodeintegration', (done) => { + const jqueryPath = path.join(__dirname, '/static/jquery-2.0.3.min.js') + const src = ` ` + const encoded = btoa(unescape(encodeURIComponent(src))) + const listener = (e) => { assert.equal(e.message, 'ok function') webview.removeEventListener('console-message', listener) done() } webview.addEventListener('console-message', listener) webview.setAttribute('webpreferences', 'webSecurity=no, nodeIntegration=yes') - webview.src = 'data:text/html;base64,' + encoded + webview.src = `data:text/html;base64,${encoded}` document.body.appendChild(webview) }) @@ -499,60 +494,58 @@ describe(' tag', function () { }) }) - describe('new-window event', function () { - if (process.env.TRAVIS === 'true' && process.platform === 'darwin') { - return - } + describe('new-window event', () => { + if (process.env.TRAVIS === 'true' && process.platform === 'darwin') return - it('emits when window.open is called', function (done) { - webview.addEventListener('new-window', function (e) { + it('emits when window.open is called', (done) => { + webview.addEventListener('new-window', (e) => { assert.equal(e.url, 'http://host/') assert.equal(e.frameName, 'host') done() }) - webview.src = 'file://' + fixtures + '/pages/window-open.html' + webview.src = `file://${fixtures}/pages/window-open.html` document.body.appendChild(webview) }) - it('emits when link with target is called', function (done) { - webview.addEventListener('new-window', function (e) { + it('emits when link with target is called', (done) => { + webview.addEventListener('new-window', (e) => { assert.equal(e.url, 'http://host/') assert.equal(e.frameName, 'target') done() }) - webview.src = 'file://' + fixtures + '/pages/target-name.html' + webview.src = `file://${fixtures}/pages/target-name.html` document.body.appendChild(webview) }) }) - describe('ipc-message event', function () { - it('emits when guest sends a ipc message to browser', function (done) { - webview.addEventListener('ipc-message', function (e) { + describe('ipc-message event', () => { + it('emits when guest sends a ipc message to browser', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'channel') assert.deepEqual(e.args, ['arg1', 'arg2']) done() }) - webview.src = 'file://' + fixtures + '/pages/ipc-message.html' + webview.src = `file://${fixtures}/pages/ipc-message.html` webview.setAttribute('nodeintegration', 'on') document.body.appendChild(webview) }) }) - describe('page-title-set event', function () { - it('emits when title is set', function (done) { - webview.addEventListener('page-title-set', function (e) { + describe('page-title-set event', () => { + it('emits when title is set', (done) => { + webview.addEventListener('page-title-set', (e) => { assert.equal(e.title, 'test') assert(e.explicitSet) done() }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) }) - describe('page-favicon-updated event', function () { - it('emits when favicon urls are received', function (done) { - webview.addEventListener('page-favicon-updated', function (e) { + describe('page-favicon-updated event', () => { + it('emits when favicon urls are received', (done) => { + webview.addEventListener('page-favicon-updated', (e) => { assert.equal(e.favicons.length, 2) if (process.platform === 'win32') { assert(/^file:\/\/\/[A-Z]:\/favicon.png$/i.test(e.favicons[0])) @@ -561,33 +554,33 @@ describe(' tag', function () { } done() }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) }) - describe('will-navigate event', function () { - it('emits when a url that leads to oustide of the page is clicked', function (done) { - webview.addEventListener('will-navigate', function (e) { + describe('will-navigate event', () => { + it('emits when a url that leads to oustide of the page is clicked', (done) => { + webview.addEventListener('will-navigate', (e) => { assert.equal(e.url, 'http://host/') done() }) - webview.src = 'file://' + fixtures + '/pages/webview-will-navigate.html' + webview.src = `file://${fixtures}/pages/webview-will-navigate.html` document.body.appendChild(webview) }) }) - describe('did-navigate event', function () { - var p = path.join(fixtures, 'pages', 'webview-will-navigate.html') + describe('did-navigate event', () => { + let p = path.join(fixtures, 'pages', 'webview-will-navigate.html') p = p.replace(/\\/g, '/') - var pageUrl = url.format({ + const pageUrl = url.format({ protocol: 'file', slashes: true, pathname: p }) - it('emits when a url that leads to outside of the page is clicked', function (done) { - webview.addEventListener('did-navigate', function (e) { + it('emits when a url that leads to outside of the page is clicked', (done) => { + webview.addEventListener('did-navigate', (e) => { assert.equal(e.url, pageUrl) done() }) @@ -596,42 +589,42 @@ describe(' tag', function () { }) }) - describe('did-navigate-in-page event', function () { - it('emits when an anchor link is clicked', function (done) { - var p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html') + describe('did-navigate-in-page event', () => { + it('emits when an anchor link is clicked', (done) => { + let p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page.html') p = p.replace(/\\/g, '/') - var pageUrl = url.format({ + const pageUrl = url.format({ protocol: 'file', slashes: true, pathname: p }) - webview.addEventListener('did-navigate-in-page', function (e) { - assert.equal(e.url, pageUrl + '#test_content') + webview.addEventListener('did-navigate-in-page', (e) => { + assert.equal(e.url, `${pageUrl}#test_content`) done() }) webview.src = pageUrl document.body.appendChild(webview) }) - it('emits when window.history.replaceState is called', function (done) { - webview.addEventListener('did-navigate-in-page', function (e) { + it('emits when window.history.replaceState is called', (done) => { + webview.addEventListener('did-navigate-in-page', (e) => { assert.equal(e.url, 'http://host/') done() }) - webview.src = 'file://' + fixtures + '/pages/webview-did-navigate-in-page-with-history.html' + webview.src = `file://${fixtures}/pages/webview-did-navigate-in-page-with-history.html` document.body.appendChild(webview) }) - it('emits when window.location.hash is changed', function (done) { - var p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html') + it('emits when window.location.hash is changed', (done) => { + let p = path.join(fixtures, 'pages', 'webview-did-navigate-in-page-with-hash.html') p = p.replace(/\\/g, '/') - var pageUrl = url.format({ + const pageUrl = url.format({ protocol: 'file', slashes: true, pathname: p }) - webview.addEventListener('did-navigate-in-page', function (e) { - assert.equal(e.url, pageUrl + '#test') + webview.addEventListener('did-navigate-in-page', (e) => { + assert.equal(e.url, `${pageUrl}#test`) done() }) webview.src = pageUrl @@ -639,91 +632,89 @@ describe(' tag', function () { }) }) - describe('close event', function () { - it('should fire when interior page calls window.close', function (done) { - webview.addEventListener('close', function () { - done() - }) - webview.src = 'file://' + fixtures + '/pages/close.html' + describe('close event', () => { + it('should fire when interior page calls window.close', (done) => { + webview.addEventListener('close', () => done()) + webview.src = `file://${fixtures}/pages/close.html` document.body.appendChild(webview) }) }) - describe('devtools-opened event', function () { - it('should fire when webview.openDevTools() is called', function (done) { - var listener = function () { + describe('devtools-opened event', () => { + it('should fire when webview.openDevTools() is called', (done) => { + const listener = () => { webview.removeEventListener('devtools-opened', listener) webview.closeDevTools() done() } webview.addEventListener('devtools-opened', listener) - webview.addEventListener('dom-ready', function () { + webview.addEventListener('dom-ready', () => { webview.openDevTools() }) - webview.src = 'file://' + fixtures + '/pages/base-page.html' + webview.src = `file://${fixtures}/pages/base-page.html` document.body.appendChild(webview) }) }) - describe('devtools-closed event', function () { - it('should fire when webview.closeDevTools() is called', function (done) { - var listener2 = function () { + describe('devtools-closed event', () => { + it('should fire when webview.closeDevTools() is called', (done) => { + const listener2 = () => { webview.removeEventListener('devtools-closed', listener2) done() } - var listener = function () { + const listener = () => { webview.removeEventListener('devtools-opened', listener) webview.closeDevTools() } webview.addEventListener('devtools-opened', listener) webview.addEventListener('devtools-closed', listener2) - webview.addEventListener('dom-ready', function () { + webview.addEventListener('dom-ready', () => { webview.openDevTools() }) - webview.src = 'file://' + fixtures + '/pages/base-page.html' + webview.src = `file://${fixtures}/pages/base-page.html` document.body.appendChild(webview) }) }) - describe('devtools-focused event', function () { - it('should fire when webview.openDevTools() is called', function (done) { - var listener = function () { + describe('devtools-focused event', () => { + it('should fire when webview.openDevTools() is called', (done) => { + const listener = () => { webview.removeEventListener('devtools-focused', listener) webview.closeDevTools() done() } webview.addEventListener('devtools-focused', listener) - webview.addEventListener('dom-ready', function () { + webview.addEventListener('dom-ready', () => { webview.openDevTools() }) - webview.src = 'file://' + fixtures + '/pages/base-page.html' + webview.src = `file://${fixtures}/pages/base-page.html` document.body.appendChild(webview) }) }) - describe('.reload()', function () { - it('should emit beforeunload handler', function (done) { - var listener = function (e) { + describe('.reload()', () => { + it('should emit beforeunload handler', (done) => { + const listener = (e) => { assert.equal(e.channel, 'onbeforeunload') webview.removeEventListener('ipc-message', listener) done() } - var listener2 = function () { + const listener2 = () => { webview.reload() webview.removeEventListener('did-finish-load', listener2) } webview.addEventListener('ipc-message', listener) webview.addEventListener('did-finish-load', listener2) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/beforeunload-false.html' + webview.src = `file://${fixtures}/pages/beforeunload-false.html` document.body.appendChild(webview) }) }) - describe('.goForward()', function () { - it('should work after a replaced history entry', function (done) { - var loadCount = 1 - var listener = function (e) { + describe('.goForward()', () => { + it('should work after a replaced history entry', (done) => { + let loadCount = 1 + const listener = (e) => { if (loadCount === 1) { assert.equal(e.channel, 'history') assert.equal(e.args[0], 1) @@ -738,9 +729,9 @@ describe(' tag', function () { } } - var loadListener = function (e) { + const loadListener = (e) => { if (loadCount === 1) { - webview.src = 'file://' + fixtures + '/pages/base-page.html' + webview.src = `file://${fixtures}/pages/base-page.html` } else if (loadCount === 2) { assert(webview.canGoBack()) assert(!webview.canGoForward()) @@ -756,20 +747,20 @@ describe(' tag', function () { done() } - loadCount++ + loadCount += 1 } webview.addEventListener('ipc-message', listener) webview.addEventListener('did-finish-load', loadListener) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/history-replace.html' + webview.src = `file://${fixtures}/pages/history-replace.html` document.body.appendChild(webview) }) }) - describe('.clearHistory()', function () { - it('should clear the navigation history', function (done) { - var listener = function (e) { + describe('.clearHistory()', () => { + it('should clear the navigation history', (done) => { + const listener = (e) => { assert.equal(e.channel, 'history') assert.equal(e.args[0], 2) assert(webview.canGoBack()) @@ -780,18 +771,18 @@ describe(' tag', function () { } webview.addEventListener('ipc-message', listener) webview.setAttribute('nodeintegration', 'on') - webview.src = 'file://' + fixtures + '/pages/history.html' + webview.src = `file://${fixtures}/pages/history.html` document.body.appendChild(webview) }) }) - describe('basic auth', function () { - var auth = require('basic-auth') + describe('basic auth', () => { + const auth = require('basic-auth') - it('should authenticate with correct credentials', function (done) { - var message = 'Authenticated' - var server = http.createServer(function (req, res) { - var credentials = auth(req) + it('should authenticate with correct credentials', (done) => { + const message = 'Authenticated' + const server = http.createServer((req, res) => { + const credentials = auth(req) if (credentials.name === 'test' && credentials.pass === 'test') { res.end(message) } else { @@ -799,64 +790,64 @@ describe(' tag', function () { } server.close() }) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - webview.addEventListener('ipc-message', function (e) { + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, message) done() }) - webview.src = 'file://' + fixtures + '/pages/basic-auth.html?port=' + port + webview.src = `file://${fixtures}/pages/basic-auth.html?port=${port}` webview.setAttribute('nodeintegration', 'on') document.body.appendChild(webview) }) }) }) - describe('dom-ready event', function () { - it('emits when document is loaded', function (done) { - var server = http.createServer(function () {}) - server.listen(0, '127.0.0.1', function () { - var port = server.address().port - webview.addEventListener('dom-ready', function () { + describe('dom-ready event', () => { + it('emits when document is loaded', (done) => { + const server = http.createServer(() => {}) + server.listen(0, '127.0.0.1', () => { + const port = server.address().port + webview.addEventListener('dom-ready', () => { done() }) - webview.src = 'file://' + fixtures + '/pages/dom-ready.html?port=' + port + webview.src = `file://${fixtures}/pages/dom-ready.html?port=${port}` document.body.appendChild(webview) }) }) - it('throws a custom error when an API method is called before the event is emitted', function () { - assert.throws(function () { + it('throws a custom error when an API method is called before the event is emitted', () => { + assert.throws(() => { webview.stop() }, 'Cannot call stop because the webContents is unavailable. The WebView must be attached to the DOM and the dom-ready event emitted before this method can be called.') }) }) - describe('executeJavaScript', function () { - it('should support user gesture', function (done) { + describe('executeJavaScript', () => { + it('should support user gesture', (done) => { if (process.env.TRAVIS !== 'true' || process.platform === 'darwin') return done() - var listener = function () { + const listener = () => { webview.removeEventListener('enter-html-full-screen', listener) done() } - var listener2 = function () { - var jsScript = "document.querySelector('video').webkitRequestFullscreen()" + const listener2 = () => { + const jsScript = "document.querySelector('video').webkitRequestFullscreen()" webview.executeJavaScript(jsScript, true) webview.removeEventListener('did-finish-load', listener2) } webview.addEventListener('enter-html-full-screen', listener) webview.addEventListener('did-finish-load', listener2) - webview.src = 'file://' + fixtures + '/pages/fullscreen.html' + webview.src = `file://${fixtures}/pages/fullscreen.html` document.body.appendChild(webview) }) - it('can return the result of the executed script', function (done) { + it('can return the result of the executed script', (done) => { if (process.env.TRAVIS === 'true' && process.platform === 'darwin') return done() - var listener = function () { - var jsScript = "'4'+2" - webview.executeJavaScript(jsScript, false, function (result) { + const listener = () => { + const jsScript = "'4'+2" + webview.executeJavaScript(jsScript, false, (result) => { assert.equal(result, '42') done() }) @@ -868,32 +859,32 @@ describe(' tag', function () { }) }) - describe('sendInputEvent', function () { - it('can send keyboard event', function (done) { - webview.addEventListener('ipc-message', function (e) { + describe('sendInputEvent', () => { + it('can send keyboard event', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'keyup') assert.deepEqual(e.args, ['C', 'KeyC', 67, true, false]) done() }) - webview.addEventListener('dom-ready', function () { + webview.addEventListener('dom-ready', () => { webview.sendInputEvent({ type: 'keyup', keyCode: 'c', modifiers: ['shift'] }) }) - webview.src = 'file://' + fixtures + '/pages/onkeyup.html' + webview.src = `file://${fixtures}/pages/onkeyup.html` webview.setAttribute('nodeintegration', 'on') document.body.appendChild(webview) }) - it('can send mouse event', function (done) { - webview.addEventListener('ipc-message', function (e) { + it('can send mouse event', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'mouseup') assert.deepEqual(e.args, [10, 20, false, true]) done() }) - webview.addEventListener('dom-ready', function () { + webview.addEventListener('dom-ready', () => { webview.sendInputEvent({ type: 'mouseup', modifiers: ['ctrl'], @@ -901,32 +892,32 @@ describe(' tag', function () { y: 20 }) }) - webview.src = 'file://' + fixtures + '/pages/onmouseup.html' + webview.src = `file://${fixtures}/pages/onmouseup.html` webview.setAttribute('nodeintegration', 'on') document.body.appendChild(webview) }) }) - describe('media-started-playing media-paused events', function () { - it('emits when audio starts and stops playing', function (done) { - var audioPlayed = false - webview.addEventListener('media-started-playing', function () { + describe('media-started-playing media-paused events', () => { + it('emits when audio starts and stops playing', (done) => { + let audioPlayed = false + webview.addEventListener('media-started-playing', () => { audioPlayed = true }) - webview.addEventListener('media-paused', function () { + webview.addEventListener('media-paused', () => { assert(audioPlayed) done() }) - webview.src = 'file://' + fixtures + '/pages/audio.html' + webview.src = `file://${fixtures}/pages/audio.html` document.body.appendChild(webview) }) }) - describe('found-in-page event', function () { - it('emits when a request is made', function (done) { + describe('found-in-page event', () => { + it('emits when a request is made', (done) => { let requestId = null let activeMatchOrdinal = [] - const listener = function (e) { + const listener = (e) => { assert.equal(e.result.requestId, requestId) assert.equal(e.result.matches, 3) activeMatchOrdinal.push(e.result.activeMatchOrdinal) @@ -938,29 +929,27 @@ describe(' tag', function () { listener2() } } - const listener2 = function () { + const listener2 = () => { requestId = webview.findInPage('virtual') } webview.addEventListener('found-in-page', listener) webview.addEventListener('did-finish-load', listener2) - webview.src = 'file://' + fixtures + '/pages/content.html' + webview.src = `file://${fixtures}/pages/content.html` document.body.appendChild(webview) }) }) - xdescribe('did-change-theme-color event', function () { - it('emits when theme color changes', function (done) { - webview.addEventListener('did-change-theme-color', function () { - done() - }) - webview.src = 'file://' + fixtures + '/pages/theme-color.html' + describe('did-change-theme-color event', () => { + it('emits when theme color changes', (done) => { + webview.addEventListener('did-change-theme-color', () => done()) + webview.src = `file://${fixtures}/pages/theme-color.html` document.body.appendChild(webview) }) }) - describe('permission-request event', function () { + describe('permission-request event', () => { function setUpRequestHandler (webview, requestedPermission, completed) { - var listener = function (webContents, permission, callback) { + const listener = function (webContents, permission, callback) { if (webContents.getId() === webview.getId()) { // requestMIDIAccess with sysex requests both midi and midiSysex so // grant the first midi one and then reject the midiSysex one @@ -976,94 +965,89 @@ describe(' tag', function () { session.fromPartition(webview.partition).setPermissionRequestHandler(listener) } - it('emits when using navigator.getUserMedia api', function (done) { - if (isCI) { - done() - return - } + it('emits when using navigator.getUserMedia api', (done) => { + if (isCI) return done() - webview.addEventListener('ipc-message', function (e) { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'message') assert.deepEqual(e.args, ['PermissionDeniedError']) done() }) - webview.src = 'file://' + fixtures + '/pages/permissions/media.html' + webview.src = `file://${fixtures}/pages/permissions/media.html` webview.partition = 'permissionTest' webview.setAttribute('nodeintegration', 'on') setUpRequestHandler(webview, 'media') document.body.appendChild(webview) }) - it('emits when using navigator.geolocation api', function (done) { - webview.addEventListener('ipc-message', function (e) { + it('emits when using navigator.geolocation api', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'message') assert.deepEqual(e.args, ['User denied Geolocation']) done() }) - webview.src = 'file://' + fixtures + '/pages/permissions/geolocation.html' + webview.src = `file://${fixtures}/pages/permissions/geolocation.html` webview.partition = 'permissionTest' webview.setAttribute('nodeintegration', 'on') setUpRequestHandler(webview, 'geolocation') document.body.appendChild(webview) }) - it('emits when using navigator.requestMIDIAccess without sysex api', function (done) { - webview.addEventListener('ipc-message', function (e) { + it('emits when using navigator.requestMIDIAccess without sysex api', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'message') assert.deepEqual(e.args, ['SecurityError']) done() }) - webview.src = 'file://' + fixtures + '/pages/permissions/midi.html' + webview.src = `file://${fixtures}/pages/permissions/midi.html` webview.partition = 'permissionTest' webview.setAttribute('nodeintegration', 'on') setUpRequestHandler(webview, 'midi') document.body.appendChild(webview) }) - it('emits when using navigator.requestMIDIAccess with sysex api', function (done) { - webview.addEventListener('ipc-message', function (e) { + it('emits when using navigator.requestMIDIAccess with sysex api', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'message') assert.deepEqual(e.args, ['SecurityError']) done() }) - webview.src = 'file://' + fixtures + '/pages/permissions/midi-sysex.html' + webview.src = `file://${fixtures}/pages/permissions/midi-sysex.html` webview.partition = 'permissionTest' webview.setAttribute('nodeintegration', 'on') setUpRequestHandler(webview, 'midiSysex') document.body.appendChild(webview) }) - it('emits when accessing external protocol', function (done) { + it('emits when accessing external protocol', (done) => { webview.src = 'magnet:test' webview.partition = 'permissionTest' setUpRequestHandler(webview, 'openExternal', done) document.body.appendChild(webview) }) - it('emits when using Notification.requestPermission', function (done) { - webview.addEventListener('ipc-message', function (e) { + it('emits when using Notification.requestPermission', (done) => { + webview.addEventListener('ipc-message', (e) => { assert.equal(e.channel, 'message') assert.deepEqual(e.args, ['granted']) done() }) - webview.src = 'file://' + fixtures + '/pages/permissions/notification.html' + webview.src = `file://${fixtures}/pages/permissions/notification.html` webview.partition = 'permissionTest' webview.setAttribute('nodeintegration', 'on') - session.fromPartition(webview.partition).setPermissionRequestHandler(function (webContents, permission, callback) { + session.fromPartition(webview.partition).setPermissionRequestHandler((webContents, permission, callback) => { if (webContents.getId() === webview.getId()) { assert.equal(permission, 'notifications') - setTimeout(function () { - callback(true) - }, 10) + setTimeout(() => { callback(true) }, 10) } }) document.body.appendChild(webview) }) }) - describe('.getWebContents', function () { - it('can return the webcontents associated', function (done) { - webview.addEventListener('did-finish-load', function () { + describe('.getWebContents', () => { + it('can return the webcontents associated', (done) => { + webview.addEventListener('did-finish-load', () => { const webviewContents = webview.getWebContents() assert(webviewContents) assert.equal(webviewContents.getURL(), 'about:blank') @@ -1074,18 +1058,18 @@ describe(' tag', function () { }) }) - describe('did-get-response-details event', function () { - it('emits for the page and its resources', function (done) { + describe('did-get-response-details event', () => { + it('emits for the page and its resources', (done) => { // expected {fileName: resourceType} pairs - var expectedResources = { + const expectedResources = { 'did-get-response-details.html': 'mainFrame', 'logo.png': 'image' } - var responses = 0 - webview.addEventListener('did-get-response-details', function (event) { - responses++ - var fileName = event.newURL.slice(event.newURL.lastIndexOf('/') + 1) - var expectedType = expectedResources[fileName] + let responses = 0 + webview.addEventListener('did-get-response-details', (event) => { + responses += 1 + const fileName = event.newURL.slice(event.newURL.lastIndexOf('/') + 1) + const expectedType = expectedResources[fileName] assert(!!expectedType, `Unexpected response details for ${event.newURL}`) assert(typeof event.status === 'boolean', 'status should be boolean') assert.equal(event.httpResponseCode, 200) @@ -1094,45 +1078,38 @@ describe(' tag', function () { assert(!!event.headers, 'headers should be present') assert(typeof event.headers === 'object', 'headers should be object') assert.equal(event.resourceType, expectedType, 'Incorrect resourceType') - if (responses === Object.keys(expectedResources).length) { - done() - } + if (responses === Object.keys(expectedResources).length) done() }) - webview.src = 'file://' + path.join(fixtures, 'pages', 'did-get-response-details.html') + webview.src = `file://${path.join(fixtures, 'pages', 'did-get-response-details.html')}` document.body.appendChild(webview) }) }) - describe('document.visibilityState/hidden', function () { - afterEach(function () { + describe('document.visibilityState/hidden', () => { + afterEach(() => { ipcMain.removeAllListeners('pong') }) - it('updates when the window is shown after the ready-to-show event', function (done) { - w = new BrowserWindow({ - show: false - }) - - w.once('ready-to-show', function () { + it('updates when the window is shown after the ready-to-show event', (done) => { + w = new BrowserWindow({ show: false }) + w.once('ready-to-show', () => { w.show() }) - ipcMain.on('pong', function (event, visibilityState, hidden) { + ipcMain.on('pong', (event, visibilityState, hidden) => { if (!hidden) { assert.equal(visibilityState, 'visible') done() } }) - w.loadURL('file://' + fixtures + '/pages/webview-visibilitychange.html') + w.loadURL(`file://${fixtures}/pages/webview-visibilitychange.html`) }) - it('inherits the parent window visibility state and receives visibilitychange events', function (done) { - w = new BrowserWindow({ - show: false - }) + it('inherits the parent window visibility state and receives visibilitychange events', (done) => { + w = new BrowserWindow({ show: false }) - ipcMain.once('pong', function (event, visibilityState, hidden) { + ipcMain.once('pong', (event, visibilityState, hidden) => { assert.equal(visibilityState, 'hidden') assert.equal(hidden, true) @@ -1141,11 +1118,9 @@ describe(' tag', function () { assert.equal(hidden, false) done() }) - w.webContents.emit('-window-visibility-change', 'visible') }) - - w.loadURL('file://' + fixtures + '/pages/webview-visibilitychange.html') + w.loadURL(`file://${fixtures}/pages/webview-visibilitychange.html`) }) }) @@ -1157,7 +1132,7 @@ describe(' tag', function () { done() }) webview.setAttribute('nodeintegration', 'yes') - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) @@ -1166,7 +1141,7 @@ describe(' tag', function () { webview.addEventListener('destroyed', () => { done() }) - webview.src = 'file://' + fixtures + '/pages/c.html' + webview.src = `file://${fixtures}/pages/c.html` document.body.appendChild(webview) }) @@ -1178,146 +1153,140 @@ describe(' tag', function () { }) webview.setAttribute('nodeintegration', 'yes') webview.setAttribute('preload', path.join(fixtures, 'module', 'preload-set-global.js')) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) }) describe('did-attach-webview event', () => { it('is emitted when a webview has been attached', (done) => { - w = new BrowserWindow({ - show: false - }) + w = new BrowserWindow({ show: false }) w.webContents.on('did-attach-webview', (event, webContents) => { ipcMain.once('webview-dom-ready', (event, id) => { assert.equal(webContents.id, id) done() }) }) - w.loadURL('file://' + fixtures + '/pages/webview-did-attach-event.html') + w.loadURL(`file://${fixtures}/pages/webview-did-attach-event.html`) }) }) - it('loads devtools extensions registered on the parent window', function (done) { - w = new BrowserWindow({ - show: false - }) - + it('loads devtools extensions registered on the parent window', (done) => { + w = new BrowserWindow({ show: false }) BrowserWindow.removeDevToolsExtension('foo') - var extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo') + const extensionPath = path.join(__dirname, 'fixtures', 'devtools-extensions', 'foo') BrowserWindow.addDevToolsExtension(extensionPath) - w.loadURL('file://' + fixtures + '/pages/webview-devtools.html') + w.loadURL(`file://${fixtures}/pages/webview-devtools.html`) - ipcMain.once('answer', function (event, message) { + ipcMain.once('answer', (event, message) => { assert.equal(message.runtimeId, 'foo') assert.notEqual(message.tabId, w.webContents.id) done() }) }) - describe('guestinstance attribute', function () { - it('before loading there is no attribute', function () { + describe('guestinstance attribute', () => { + it('before loading there is no attribute', () => { document.body.appendChild(webview) assert(!webview.hasAttribute('guestinstance')) }) - it('loading a page sets the guest view', function (done) { - var loadListener = function () { + it('loading a page sets the guest view', (done) => { + const loadListener = () => { webview.removeEventListener('did-finish-load', loadListener, false) - var instance = webview.getAttribute('guestinstance') + const instance = webview.getAttribute('guestinstance') assert.equal(instance, parseInt(instance)) - var guest = getGuestWebContents(parseInt(instance)) + const guest = getGuestWebContents(parseInt(instance)) assert.equal(guest, webview.getWebContents()) done() } webview.addEventListener('did-finish-load', loadListener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('deleting the attribute destroys the webview', function (done) { - var loadListener = function () { + it('deleting the attribute destroys the webview', (done) => { + const loadListener = () => { webview.removeEventListener('did-finish-load', loadListener, false) - var destroyListener = function () { + const destroyListener = () => { webview.removeEventListener('destroyed', destroyListener, false) assert.equal(getGuestWebContents(instance), null) done() } webview.addEventListener('destroyed', destroyListener, false) - var instance = parseInt(webview.getAttribute('guestinstance')) + const instance = parseInt(webview.getAttribute('guestinstance')) webview.removeAttribute('guestinstance') } webview.addEventListener('did-finish-load', loadListener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('setting the attribute on a new webview moves the contents', function (done) { - var loadListener = function () { + it('setting the attribute on a new webview moves the contents', (done) => { + const loadListener = () => { webview.removeEventListener('did-finish-load', loadListener, false) - var webContents = webview.getWebContents() - var instance = webview.getAttribute('guestinstance') + const webContents = webview.getWebContents() + const instance = webview.getAttribute('guestinstance') - var destroyListener = function () { + const destroyListener = () => { webview.removeEventListener('destroyed', destroyListener, false) assert.equal(webContents, webview2.getWebContents()) // Make sure that events are hooked up to the right webview now - webview2.addEventListener('console-message', function (e) { + webview2.addEventListener('console-message', (e) => { assert.equal(e.message, 'a') document.body.removeChild(webview2) done() }) - webview2.src = 'file://' + fixtures + '/pages/a.html' + webview2.src = `file://${fixtures}/pages/a.html` } webview.addEventListener('destroyed', destroyListener, false) - var webview2 = new WebView() + const webview2 = new WebView() webview2.setAttribute('guestinstance', instance) document.body.appendChild(webview2) } webview.addEventListener('did-finish-load', loadListener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('setting the attribute to an invalid guestinstance does nothing', function (done) { - var loadListener = function () { + it('setting the attribute to an invalid guestinstance does nothing', (done) => { + const loadListener = () => { webview.removeEventListener('did-finish-load', loadListener, false) webview.setAttribute('guestinstance', 55) // Make sure that events are still hooked up to the webview - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'a') done() }) - - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` } webview.addEventListener('did-finish-load', loadListener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('setting the attribute on an existing webview moves the contents', function (done) { - var load1Listener = function () { + it('setting the attribute on an existing webview moves the contents', (done) => { + const load1Listener = () => { webview.removeEventListener('did-finish-load', load1Listener, false) - var webContents = webview.getWebContents() - var instance = webview.getAttribute('guestinstance') - var destroyedInstance + const webContents = webview.getWebContents() + const instance = webview.getAttribute('guestinstance') + let destroyedInstance - var destroyListener = function () { + const destroyListener = () => { webview.removeEventListener('destroyed', destroyListener, false) assert.equal(webContents, webview2.getWebContents()) assert.equal(null, getGuestWebContents(parseInt(destroyedInstance))) // Make sure that events are hooked up to the right webview now - webview2.addEventListener('console-message', function (e) { + webview2.addEventListener('console-message', (e) => { assert.equal(e.message, 'a') document.body.removeChild(webview2) done() @@ -1327,8 +1296,8 @@ describe(' tag', function () { } webview.addEventListener('destroyed', destroyListener, false) - var webview2 = new WebView() - var load2Listener = function () { + const webview2 = new WebView() + const load2Listener = () => { webview2.removeEventListener('did-finish-load', load2Listener, false) destroyedInstance = webview2.getAttribute('guestinstance') assert.notEqual(instance, destroyedInstance) @@ -1344,71 +1313,69 @@ describe(' tag', function () { document.body.appendChild(webview) }) - it('moving a guest back to its original webview should work', function (done) { - var loadListener = function () { + it('moving a guest back to its original webview should work', (done) => { + const loadListener = () => { webview.removeEventListener('did-finish-load', loadListener, false) - var webContents = webview.getWebContents() - var instance = webview.getAttribute('guestinstance') + const webContents = webview.getWebContents() + const instance = webview.getAttribute('guestinstance') - var destroy1Listener = function () { + const destroy1Listener = () => { webview.removeEventListener('destroyed', destroy1Listener, false) assert.equal(webContents, webview2.getWebContents()) assert.equal(null, webview.getWebContents()) - var destroy2Listener = function () { + const destroy2Listener = () => { webview2.removeEventListener('destroyed', destroy2Listener, false) assert.equal(webContents, webview.getWebContents()) assert.equal(null, webview2.getWebContents()) // Make sure that events are hooked up to the right webview now - webview.addEventListener('console-message', function (e) { + webview.addEventListener('console-message', (e) => { assert.equal(e.message, 'a') document.body.removeChild(webview2) done() }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` } webview2.addEventListener('destroyed', destroy2Listener, false) - webview.setAttribute('guestinstance', instance) } webview.addEventListener('destroyed', destroy1Listener, false) - var webview2 = new WebView() + const webview2 = new WebView() webview2.setAttribute('guestinstance', instance) document.body.appendChild(webview2) } webview.addEventListener('did-finish-load', loadListener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('setting the attribute on a webview in a different window moves the contents', function (done) { - var loadListener = function () { + it('setting the attribute on a webview in a different window moves the contents', (done) => { + const loadListener = () => { webview.removeEventListener('did-finish-load', loadListener, false) - var instance = webview.getAttribute('guestinstance') + const instance = webview.getAttribute('guestinstance') w = new BrowserWindow({ show: false }) - w.webContents.once('did-finish-load', function () { - ipcMain.once('pong', function () { + w.webContents.once('did-finish-load', () => { + ipcMain.once('pong', () => { assert(!webview.hasAttribute('guestinstance')) - done() }) w.webContents.send('guestinstance', instance) }) - w.loadURL('file://' + fixtures + '/pages/webview-move-to-window.html') + w.loadURL(`file://${fixtures}/pages/webview-move-to-window.html`) } webview.addEventListener('did-finish-load', loadListener, false) - webview.src = 'file://' + fixtures + '/api/blank.html' + webview.src = `file://${fixtures}/api/blank.html` document.body.appendChild(webview) }) - it('does not delete the guestinstance attribute when moving the webview to another parent node', function (done) { + it('does not delete the guestinstance attribute when moving the webview to another parent node', (done) => { webview.addEventListener('dom-ready', function domReadyListener () { - webview.addEventListener('did-attach', function () { + webview.addEventListener('did-attach', () => { assert(webview.guestinstance != null) assert(webview.getWebContents() != null) done() @@ -1416,20 +1383,20 @@ describe(' tag', function () { document.body.replaceChild(webview, div) }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` const div = document.createElement('div') div.appendChild(webview) document.body.appendChild(div) }) - it('does not destroy the webContents when hiding/showing the webview (regression)', function (done) { + it('does not destroy the webContents when hiding/showing the webview (regression)', (done) => { webview.addEventListener('dom-ready', function domReadyListener () { const instance = webview.getAttribute('guestinstance') assert(instance != null) // Wait for event directly since attach happens asynchronously over IPC - ipcMain.once('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', function () { + ipcMain.once('ELECTRON_GUEST_VIEW_MANAGER_ATTACH_GUEST', () => { assert(webview.getWebContents() != null) assert.equal(instance, webview.getAttribute('guestinstance')) done() @@ -1439,18 +1406,18 @@ describe(' tag', function () { webview.offsetHeight webview.style.display = 'block' }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) - it('does not reload the webContents when hiding/showing the webview (regression)', function (done) { + it('does not reload the webContents when hiding/showing the webview (regression)', (done) => { webview.addEventListener('dom-ready', function domReadyListener () { - webview.addEventListener('did-start-loading', function () { + webview.addEventListener('did-start-loading', () => { done(new Error('webview started loading unexpectedly')) }) // Wait for event directly since attach happens asynchronously over IPC - webview.addEventListener('did-attach', function () { + webview.addEventListener('did-attach', () => { done() }) @@ -1458,15 +1425,15 @@ describe(' tag', function () { webview.offsetHeight webview.style.display = 'block' }) - webview.src = 'file://' + fixtures + '/pages/a.html' + webview.src = `file://${fixtures}/pages/a.html` document.body.appendChild(webview) }) }) - describe('DOM events', function () { + describe('DOM events', () => { let div - beforeEach(function () { + beforeEach(() => { div = document.createElement('div') div.style.width = '100px' div.style.height = '10px' @@ -1475,12 +1442,12 @@ describe(' tag', function () { webview.style.width = '100%' }) - afterEach(function () { + afterEach(() => { if (div != null) div.remove() }) - it('emits resize events', function (done) { - webview.addEventListener('dom-ready', function () { + it('emits resize events', (done) => { + webview.addEventListener('dom-ready', () => { div.style.width = '1234px' div.style.height = '789px' }) @@ -1505,9 +1472,9 @@ describe(' tag', function () { assert(!webview.hasAttribute('disableguestresize')) }) - it('resizes guest when attribute is not present', done => { + it('resizes guest when attribute is not present', (done) => { w = new BrowserWindow({show: false, width: 200, height: 200}) - w.loadURL('file://' + fixtures + '/pages/webview-guest-resize.html') + w.loadURL(`file://${fixtures}/pages/webview-guest-resize.html`) w.webContents.once('did-finish-load', () => { const CONTENT_SIZE = 300 @@ -1536,7 +1503,7 @@ describe(' tag', function () { it('does not resize guest when attribute is present', done => { w = new BrowserWindow({show: false, width: 200, height: 200}) - w.loadURL('file://' + fixtures + '/pages/webview-no-guest-resize.html') + w.loadURL(`file://${fixtures}/pages/webview-no-guest-resize.html`) w.webContents.once('did-finish-load', () => { const CONTENT_SIZE = 300 @@ -1569,7 +1536,7 @@ describe(' tag', function () { it('dispatches element resize event even when attribute is present', done => { w = new BrowserWindow({show: false, width: 200, height: 200}) - w.loadURL('file://' + fixtures + '/pages/webview-no-guest-resize.html') + w.loadURL(`file://${fixtures}/pages/webview-no-guest-resize.html`) w.webContents.once('did-finish-load', () => { const CONTENT_SIZE = 300 @@ -1587,7 +1554,7 @@ describe(' tag', function () { if (process.env.TRAVIS === 'true') return done() w = new BrowserWindow({show: false, width: 200, height: 200}) - w.loadURL('file://' + fixtures + '/pages/webview-no-guest-resize.html') + w.loadURL(`file://${fixtures}/pages/webview-no-guest-resize.html`) w.webContents.once('did-finish-load', () => { const GUEST_WIDTH = 10 @@ -1696,7 +1663,7 @@ describe(' tag', function () { }) describe('nativeWindowOpen option', () => { - beforeEach(function () { + beforeEach(() => { webview.setAttribute('allowpopups', 'on') webview.setAttribute('nodeintegration', 'on') webview.setAttribute('webpreferences', 'nativeWindowOpen=1') @@ -1707,7 +1674,7 @@ describe(' tag', function () { assert.equal(content, 'Hello') done() }) - webview.src = 'file://' + path.join(fixtures, 'api', 'native-window-open-blank.html') + webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}` document.body.appendChild(webview) }) @@ -1716,7 +1683,7 @@ describe(' tag', function () { assert.equal(content, 'Hello') done() }) - webview.src = 'file://' + path.join(fixtures, 'api', 'native-window-open-file.html') + webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-file.html')}` document.body.appendChild(webview) }) @@ -1726,7 +1693,7 @@ describe(' tag', function () { assert.equal(windowOpenReturnedNull, true) done() }) - webview.src = 'file://' + path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html') + webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-no-allowpopups.html')}` document.body.appendChild(webview) }) @@ -1735,25 +1702,23 @@ describe(' tag', function () { assert.equal(content, 'Blocked a frame with origin "file://" from accessing a cross-origin frame.') done() }) - webview.src = 'file://' + path.join(fixtures, 'api', 'native-window-open-cross-origin.html') + webview.src = `file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}` document.body.appendChild(webview) }) it('emits a new-window event', (done) => { - webview.addEventListener('new-window', function (e) { + webview.addEventListener('new-window', (e) => { assert.equal(e.url, 'http://host/') assert.equal(e.frameName, 'host') done() }) - webview.src = 'file://' + fixtures + '/pages/window-open.html' + webview.src = `file://${fixtures}/pages/window-open.html` document.body.appendChild(webview) }) it('emits a browser-window-created event', (done) => { - app.once('browser-window-created', () => { - done() - }) - webview.src = 'file://' + fixtures + '/pages/window-open.html' + app.once('browser-window-created', () => done()) + webview.src = `file://${fixtures}/pages/window-open.html` document.body.appendChild(webview) }) @@ -1764,7 +1729,7 @@ describe(' tag', function () { done() } }) - webview.src = 'file://' + fixtures + '/pages/window-open.html' + webview.src = `file://${fixtures}/pages/window-open.html` document.body.appendChild(webview) }) }) From da21d6cddaf683fce0d8e9d7f71c40b417be8855 Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Fri, 27 Oct 2017 14:21:46 -0700 Subject: [PATCH 122/185] :wrench: Don't call idleWakeupsPerSecond on Windows --- atom/browser/api/atom_api_app.cc | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index d8ce8170fb0..d878926580a 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -1073,8 +1073,17 @@ std::vector App::GetAppMetrics(v8::Isolate* isolate) { cpu_dict.Set("percentCPUUsage", process_metric.second->metrics->GetPlatformIndependentCPUUsage() / processor_count); + +#if !defined(OS_WIN) cpu_dict.Set("idleWakeupsPerSecond", process_metric.second->metrics->GetIdleWakeupsPerSecond()); +#else + // Chrome's underlying process_metrics.cc will throw a non-fatal warning + // that this method isn't implemented on Windows, so set it to 0 instead + // of calling it + cpu_dict.Set("idleWakeupsPerSecond", 0); +#endif + pid_dict.Set("cpu", cpu_dict); pid_dict.Set("pid", process_metric.second->pid); pid_dict.Set("type", From 91414dde62f9b829f2ebb856eb040fc764f7596c Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Mon, 30 Oct 2017 11:19:50 -0700 Subject: [PATCH 123/185] :wrench: I can't believe this helps --- atom/browser/native_window.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 487557cd311..0a0db7c548a 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -117,6 +117,14 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { bool center; if (options.Get(options::kX, &x) && options.Get(options::kY, &y)) { SetPosition(gfx::Point(x, y)); + +#if DEFINEED(OS_WIN) + // Dirty, dirty workaround for + // https://github.com/electron/electron/issues/10862 + // Somehow, we need to call `SetBounds` twice to get + // usable results. The root cause is still unknown. + SetPosition(gfx::Point(x, y)); +#endif } else if (options.Get(options::kCenter, ¢er) && center) { Center(); } From 603060f051fc45a5160828d19e704ea3262d104d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 30 Oct 2017 22:51:22 -0400 Subject: [PATCH 124/185] add new tests --- lib/common/api/crash-reporter.js | 59 ++++++++------------ spec/api-crash-reporter-spec.js | 93 ++++++++++++++++++++++++++++---- 2 files changed, 107 insertions(+), 45 deletions(-) diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index 7a54e24fbc2..c69eb1ea1b0 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -9,36 +9,25 @@ const binding = process.atomBinding('crash_reporter') class CrashReporter { start (options) { - if (options == null) { - options = {} - } + if (options == null) options = {} this.productName = options.productName != null ? options.productName : app.getName() - let {companyName, extra, ignoreSystemCrashHandler, submitURL, uploadToServer} = options - if (uploadToServer == null) { - // TODO: Remove deprecated autoSubmit property in 2.0 - uploadToServer = options.autoSubmit - } + let { + companyName, + extra, + ignoreSystemCrashHandler, + submitURL, + uploadToServer + } = options - if (uploadToServer == null) { - uploadToServer = true - } + if (uploadToServer == null) uploadToServer = options.autoSubmit || true + if (ignoreSystemCrashHandler == null) ignoreSystemCrashHandler = false + if (extra == null) extra = {} + + if (extra._productName == null) extra._productName = this.getProductName() + if (extra._companyName == null) extra._companyName = companyName + if (extra._version == null) extra._version = app.getVersion() - if (ignoreSystemCrashHandler == null) { - ignoreSystemCrashHandler = false - } - if (extra == null) { - extra = {} - } - if (extra._productName == null) { - extra._productName = this.getProductName() - } - if (extra._companyName == null) { - extra._companyName = companyName - } - if (extra._version == null) { - extra._version = app.getVersion() - } if (companyName == null) { throw new Error('companyName is a required option to crashReporter.start') } @@ -47,15 +36,14 @@ class CrashReporter { } if (process.platform === 'win32') { + const env = { ELECTRON_INTERNAL_CRASH_SERVICE: 1 } const args = [ '--reporter-url=' + submitURL, '--application-name=' + this.getProductName(), '--crashes-directory=' + this.getCrashesDirectory(), '--v=1' ] - const env = { - ELECTRON_INTERNAL_CRASH_SERVICE: 1 - } + this._crashServiceProcess = spawn(process.execPath, args, { env: env, detached: true @@ -67,11 +55,7 @@ class CrashReporter { getLastCrashReport () { const reports = this.getUploadedReports() - if (reports.length > 0) { - return reports[0] - } else { - return null - } + return (reports.length > 0) ? reports[0] : null } getUploadedReports () { @@ -79,7 +63,7 @@ class CrashReporter { } getCrashesDirectory () { - const crashesDir = this.getProductName() + ' Crashes' + const crashesDir = `${this.getProductName()} Crashes` return path.join(this.getTempDirectory(), crashesDir) } @@ -95,7 +79,6 @@ class CrashReporter { try { this.tempDirectory = app.getPath('temp') } catch (error) { - // app.getPath may throw so fallback to OS temp directory this.tempDirectory = os.tmpdir() } } @@ -118,6 +101,10 @@ class CrashReporter { } } + removeExtraParameter (key) { + binding.setExtraParameter(key) + } + setExtraParameter (key, value) { binding.setExtraParameter(key, value) } diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 0598677fea2..a81edb0337c 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -35,9 +35,7 @@ describe('crashReporter module', () => { beforeEach(() => { stopServer = null - w = new BrowserWindow(Object.assign({ - show: false - }, browserWindowOpts)) + w = new BrowserWindow(Object.assign({ show: false }, browserWindowOpts)) }) afterEach(() => closeWindow(w).then(() => { w = null })) @@ -199,7 +197,22 @@ describe('crashReporter module', () => { } }) - describe('.start(options)', () => { + // complete + describe('getProductName', () => { + it('returns the product name if one is specified', () => { + const name = crashReporter.getProductName() + assert.equal(name, 'Zombies') + }) + }) + + describe('getTempDirectory', () => { + it('returns temp directory for app if one is specified', () => { + const tempDir = crashReporter.getTempDirectory() + assert.equal(tempDir, app.getPath('temp')) + }) + }) + + describe('start(options)', () => { it('requires that the companyName and submitURL options be specified', () => { assert.throws(() => { crashReporter.start({companyName: 'Missing submitURL'}) @@ -208,7 +221,6 @@ describe('crashReporter module', () => { crashReporter.start({submitURL: 'Missing companyName'}) }, /companyName is a required option to crashReporter\.start/) }) - it('can be called multiple times', () => { assert.doesNotThrow(() => { crashReporter.start({ @@ -223,13 +235,37 @@ describe('crashReporter module', () => { }) }) }) + // complete + describe('getCrashesDirectory', () => { + it('correctly returns the directory', () => { + const crashesDir = crashReporter.getCrashesDirectory() + const dir = `${app.getPath('temp')}Zombies Crashes` + assert.equal(crashesDir, dir) + }) + }) - describe('.get/setUploadToServer', () => { + describe('getUploadedReports', () => { + it('returns an array of reports', () => { + const reports = crashReporter.getUploadedReports() + assert(typeof reports === 'object') + }) + }) + + describe('getLastCrashReport', () => { + it('correctly returns the most recent report', () => { + // TODO(codebytere): figure this out + const reports = crashReporter.getUploadedReports() + const lastReport = reports[0] + assert(lastReport != null) + }) + }) + + // complete + describe('getUploadToServer()', () => { it('throws an error when called from the renderer process', () => { assert.throws(() => require('electron').crashReporter.getUploadToServer()) }) - - it('can be read/set from the main process', () => { + it('returns true when uploadToServer is true', () => { if (process.platform === 'darwin') { crashReporter.start({ companyName: 'Umbrella Corporation', @@ -237,13 +273,52 @@ describe('crashReporter module', () => { uploadToServer: true }) assert.equal(crashReporter.getUploadToServer(), true) + } + }) + it('returns false when uploadToServer is false', () => { + if (process.platform === 'darwin') { + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: 'http://127.0.0.1/crashes', + uploadToServer: false + }) + assert.equal(crashReporter.getUploadToServer(), false) + } + }) + }) + + // complete + describe('setUploadToServer(uploadToServer)', () => { + it('throws an error when called from the renderer process', () => { + assert.throws(() => require('electron').crashReporter.setUploadToServer('arg')) + }) + it('sets uploadToServer false when called with false', () => { + if (process.platform === 'darwin') { + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: 'http://127.0.0.1/crashes', + uploadToServer: true + }) crashReporter.setUploadToServer(false) assert.equal(crashReporter.getUploadToServer(), false) - } else { + } + }) + it('sets uploadToServer true when called with true', () => { + if (process.platform === 'darwin') { + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: 'http://127.0.0.1/crashes', + uploadToServer: false + }) + crashReporter.setUploadToServer(true) assert.equal(crashReporter.getUploadToServer(), true) } }) }) + + describe('setExtraParameter', () => { + // + }) }) const waitForCrashReport = () => { From 06075c44990e9ac3a221ac2dddb4c225eb61e38c Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 30 Oct 2017 23:12:04 -0400 Subject: [PATCH 125/185] extrapolate removeExtraParameter into new method --- atom/common/api/atom_api_crash_reporter.cc | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc index 0edd787e558..9a6fd27ed52 100644 --- a/atom/common/api/atom_api_crash_reporter.cc +++ b/atom/common/api/atom_api_crash_reporter.cc @@ -31,12 +31,12 @@ struct Converter { namespace { -void SetExtraParameter(const std::string& key, mate::Arguments* args) { - std::string value; - if (args->GetNext(&value)) - CrashReporter::GetInstance()->SetExtraParameter(key, value); - else - CrashReporter::GetInstance()->RemoveExtraParameter(key); +void SetExtraParameter(const std::string& key, const std::string& value) { + CrashReporter::GetInstance()->SetExtraParameter(key, value); +} + +void RemoveExtraParameter(const std::string& key) { + CrashReporter::GetInstance()->RemoveExtraParameter(key); } @@ -46,6 +46,7 @@ void Initialize(v8::Local exports, v8::Local unused, auto reporter = base::Unretained(CrashReporter::GetInstance()); dict.SetMethod("start", base::Bind(&CrashReporter::Start, reporter)); dict.SetMethod("setExtraParameter", &SetExtraParameter); + dict.SetMethod("removeExtraParameter", &SetExtraParameter); dict.SetMethod("getUploadedReports", base::Bind(&CrashReporter::GetUploadedReports, reporter)); dict.SetMethod("setUploadToServer", From cb78e4875bb3c653505cd7c2d59f5f112cdbf413 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 30 Oct 2017 23:15:57 -0400 Subject: [PATCH 126/185] fix two failing tests --- lib/common/api/crash-reporter.js | 2 +- spec/api-crash-reporter-spec.js | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 5 deletions(-) diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index c69eb1ea1b0..79ae5e56b22 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -102,7 +102,7 @@ class CrashReporter { } removeExtraParameter (key) { - binding.setExtraParameter(key) + binding.removeExtraParameter(key) } setExtraParameter (key, value) { diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index a81edb0337c..ad688f26b60 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,7 +11,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe('crashReporter module', () => { +describe.only('crashReporter module', () => { if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return let originalTempDirectory = null @@ -201,7 +201,11 @@ describe('crashReporter module', () => { describe('getProductName', () => { it('returns the product name if one is specified', () => { const name = crashReporter.getProductName() - assert.equal(name, 'Zombies') + if(process.platform === 'win32') { + assert.equal(name, 'Zombies') + } else { + assert.equal(name, 'Electron Test') + } }) }) @@ -235,15 +239,22 @@ describe('crashReporter module', () => { }) }) }) + // complete describe('getCrashesDirectory', () => { it('correctly returns the directory', () => { const crashesDir = crashReporter.getCrashesDirectory() - const dir = `${app.getPath('temp')}Zombies Crashes` + let dir + if (process.platform === 'win32') { + dir = `${app.getPath('temp')}/Zombies Crashes` + } else { + dir = `${app.getPath('temp')}/Electron Test Crashes` + } assert.equal(crashesDir, dir) }) }) + // complete describe('getUploadedReports', () => { it('returns an array of reports', () => { const reports = crashReporter.getUploadedReports() @@ -251,9 +262,9 @@ describe('crashReporter module', () => { }) }) + // complete describe('getLastCrashReport', () => { it('correctly returns the most recent report', () => { - // TODO(codebytere): figure this out const reports = crashReporter.getUploadedReports() const lastReport = reports[0] assert(lastReport != null) From b2a735ef4f627fa0ca0e8645036ac0ab7a4aaf9c Mon Sep 17 00:00:00 2001 From: Vanessa Yuen Date: Tue, 31 Oct 2017 17:21:13 +0800 Subject: [PATCH 127/185] test build script super rough draft --- test-builds.sh | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100755 test-builds.sh diff --git a/test-builds.sh b/test-builds.sh new file mode 100755 index 00000000000..deae329a91d --- /dev/null +++ b/test-builds.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +_project=$1 +_branch=$2 +_circle_token=$3 + +trigger_build_url=https://circleci.com/api/v1.1/project/github/${_project}/tree/${_branch}?circle-token=${_circle_token} + +post_data=$(cat < Date: Tue, 31 Oct 2017 10:38:48 -0400 Subject: [PATCH 128/185] add crashReporter parameter tests --- spec/api-crash-reporter-spec.js | 38 ++++++++++++++++++++++++--------- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index ad688f26b60..411186205ea 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,7 +11,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe.only('crashReporter module', () => { +describe('crashReporter module', () => { if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return let originalTempDirectory = null @@ -197,11 +197,10 @@ describe.only('crashReporter module', () => { } }) - // complete describe('getProductName', () => { it('returns the product name if one is specified', () => { const name = crashReporter.getProductName() - if(process.platform === 'win32') { + if (process.platform === 'win32') { assert.equal(name, 'Zombies') } else { assert.equal(name, 'Electron Test') @@ -240,7 +239,6 @@ describe.only('crashReporter module', () => { }) }) - // complete describe('getCrashesDirectory', () => { it('correctly returns the directory', () => { const crashesDir = crashReporter.getCrashesDirectory() @@ -254,7 +252,6 @@ describe.only('crashReporter module', () => { }) }) - // complete describe('getUploadedReports', () => { it('returns an array of reports', () => { const reports = crashReporter.getUploadedReports() @@ -262,7 +259,6 @@ describe.only('crashReporter module', () => { }) }) - // complete describe('getLastCrashReport', () => { it('correctly returns the most recent report', () => { const reports = crashReporter.getUploadedReports() @@ -271,7 +267,6 @@ describe.only('crashReporter module', () => { }) }) - // complete describe('getUploadToServer()', () => { it('throws an error when called from the renderer process', () => { assert.throws(() => require('electron').crashReporter.getUploadToServer()) @@ -298,7 +293,6 @@ describe.only('crashReporter module', () => { }) }) - // complete describe('setUploadToServer(uploadToServer)', () => { it('throws an error when called from the renderer process', () => { assert.throws(() => require('electron').crashReporter.setUploadToServer('arg')) @@ -327,8 +321,32 @@ describe.only('crashReporter module', () => { }) }) - describe('setExtraParameter', () => { - // + describe('Parameters', () => { + it('returns all of the current parameters', () => { + const parameters = crashReporter.getParameters() + assert(typeof parameters === Object) + }) + it('adds a parameter', () => { + // only run on MacOS + if (process.platform !== 'darwin') return + + crashReporter.addParameter('hello', 'world') + const updatedParams = crashReporter.getParameters() + + assert(updatedParams.includes('hello')) + }) + it('removes a parameter', () => { + // only run on MacOS + if (process.platform !== 'darwin') return + + crashReporter.addParameter('hello', 'world') + const originalParams = crashReporter.getParameters() + assert(originalParams.includes('hello')) + + crashReporter.removeExtraParameter('hello') + const updatedParams = crashReporter.getParameters() + assert(!updatedParams.includes('hello')) + }) }) }) From 08b8f2df5575b151c752db0e6ab413bfe7cd2fbb Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Tue, 31 Oct 2017 08:38:33 -0700 Subject: [PATCH 129/185] :memo: Typo! --- atom/browser/native_window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 0a0db7c548a..0010928f92e 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -118,7 +118,7 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { if (options.Get(options::kX, &x) && options.Get(options::kY, &y)) { SetPosition(gfx::Point(x, y)); -#if DEFINEED(OS_WIN) +#if DEFINED(OS_WIN) // Dirty, dirty workaround for // https://github.com/electron/electron/issues/10862 // Somehow, we need to call `SetBounds` twice to get From a9c13359dc4c38cb357c3826c35dac563ade7391 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 31 Oct 2017 13:06:54 -0400 Subject: [PATCH 130/185] first attempt to add new GetParameters method to CrashReporter --- atom/common/api/atom_api_crash_reporter.cc | 6 +++++- atom/common/crash_reporter/crash_reporter.cc | 11 ++++++----- atom/common/crash_reporter/crash_reporter.h | 1 + lib/common/api/crash-reporter.js | 4 ++++ 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc index 9a6fd27ed52..255283ab762 100644 --- a/atom/common/api/atom_api_crash_reporter.cc +++ b/atom/common/api/atom_api_crash_reporter.cc @@ -39,6 +39,9 @@ void RemoveExtraParameter(const std::string& key) { CrashReporter::GetInstance()->RemoveExtraParameter(key); } +crash_reporter::CrashReporter::StringMap GetParameters() { + return CrashReporter::GetInstance()->GetParameters(); +} void Initialize(v8::Local exports, v8::Local unused, v8::Local context, void* priv) { @@ -46,7 +49,8 @@ void Initialize(v8::Local exports, v8::Local unused, auto reporter = base::Unretained(CrashReporter::GetInstance()); dict.SetMethod("start", base::Bind(&CrashReporter::Start, reporter)); dict.SetMethod("setExtraParameter", &SetExtraParameter); - dict.SetMethod("removeExtraParameter", &SetExtraParameter); + dict.SetMethod("removeExtraParameter", &RemoveExtraParameter); + dict.SetMethod("getParameters", &GetParameters); dict.SetMethod("getUploadedReports", base::Bind(&CrashReporter::GetUploadedReports, reporter)); dict.SetMethod("setUploadToServer", diff --git a/atom/common/crash_reporter/crash_reporter.cc b/atom/common/crash_reporter/crash_reporter.cc index d901f83fa49..b65720b8bc2 100644 --- a/atom/common/crash_reporter/crash_reporter.cc +++ b/atom/common/crash_reporter/crash_reporter.cc @@ -83,14 +83,15 @@ void CrashReporter::InitBreakpad(const std::string& product_name, bool skip_system_crash_handler) { } -void CrashReporter::SetUploadParameters() { -} +void CrashReporter::SetUploadParameters() {} void CrashReporter::SetExtraParameter(const std::string& key, - const std::string& value) { -} + const std::string& value) {} -void CrashReporter::RemoveExtraParameter(const std::string& key) { +void CrashReporter::RemoveExtraParameter(const std::string& key) {} + +StringMap CrashReporter::GetParameters() { + return upload_parameters_; } #if defined(OS_MACOSX) && defined(MAS_BUILD) diff --git a/atom/common/crash_reporter/crash_reporter.h b/atom/common/crash_reporter/crash_reporter.h index 2bdcd9b02d3..1ef16ed505b 100644 --- a/atom/common/crash_reporter/crash_reporter.h +++ b/atom/common/crash_reporter/crash_reporter.h @@ -40,6 +40,7 @@ class CrashReporter { virtual void SetExtraParameter(const std::string& key, const std::string& value); virtual void RemoveExtraParameter(const std::string& key); + virtual CrashReporter::StringMap GetParameters(); protected: CrashReporter(); diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index 79ae5e56b22..6b9f14a9785 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -108,6 +108,10 @@ class CrashReporter { setExtraParameter (key, value) { binding.setExtraParameter(key, value) } + + getParameters (key, value) { + binding.getParameters() + } } module.exports = new CrashReporter() From 58708d6242fce9d28ea5d597a21656cd1becc21f Mon Sep 17 00:00:00 2001 From: Felix Rieseberg Date: Tue, 31 Oct 2017 10:31:05 -0700 Subject: [PATCH 131/185] :wrench: Lowercase --- atom/browser/native_window.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/atom/browser/native_window.cc b/atom/browser/native_window.cc index 0010928f92e..813b33f5c57 100644 --- a/atom/browser/native_window.cc +++ b/atom/browser/native_window.cc @@ -118,7 +118,7 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) { if (options.Get(options::kX, &x) && options.Get(options::kY, &y)) { SetPosition(gfx::Point(x, y)); -#if DEFINED(OS_WIN) +#if defined(OS_WIN) // Dirty, dirty workaround for // https://github.com/electron/electron/issues/10862 // Somehow, we need to call `SetBounds` twice to get From 3136f833a5a9921cc0e7e55d2c5776506b8ea0fe Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 31 Oct 2017 13:51:44 -0400 Subject: [PATCH 132/185] fixes and updates to GetParameters --- atom/common/api/atom_api_crash_reporter.cc | 2 +- atom/common/crash_reporter/crash_reporter.cc | 5 ++- atom/common/crash_reporter/crash_reporter.h | 2 +- .../crash_reporter/crash_reporter_mac.mm | 5 +-- lib/common/api/crash-reporter.js | 2 +- spec/api-crash-reporter-spec.js | 32 +++++++++++++++---- 6 files changed, 33 insertions(+), 15 deletions(-) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc index 255283ab762..b3d395aa26d 100644 --- a/atom/common/api/atom_api_crash_reporter.cc +++ b/atom/common/api/atom_api_crash_reporter.cc @@ -39,7 +39,7 @@ void RemoveExtraParameter(const std::string& key) { CrashReporter::GetInstance()->RemoveExtraParameter(key); } -crash_reporter::CrashReporter::StringMap GetParameters() { +std::map GetParameters() { return CrashReporter::GetInstance()->GetParameters(); } diff --git a/atom/common/crash_reporter/crash_reporter.cc b/atom/common/crash_reporter/crash_reporter.cc index b65720b8bc2..0793c056668 100644 --- a/atom/common/crash_reporter/crash_reporter.cc +++ b/atom/common/crash_reporter/crash_reporter.cc @@ -80,8 +80,7 @@ void CrashReporter::InitBreakpad(const std::string& product_name, const std::string& submit_url, const base::FilePath& crashes_dir, bool auto_submit, - bool skip_system_crash_handler) { -} + bool skip_system_crash_handler) {} void CrashReporter::SetUploadParameters() {} @@ -90,7 +89,7 @@ void CrashReporter::SetExtraParameter(const std::string& key, void CrashReporter::RemoveExtraParameter(const std::string& key) {} -StringMap CrashReporter::GetParameters() { +std::map CrashReporter::GetParameters() { return upload_parameters_; } diff --git a/atom/common/crash_reporter/crash_reporter.h b/atom/common/crash_reporter/crash_reporter.h index 1ef16ed505b..ca85ad71777 100644 --- a/atom/common/crash_reporter/crash_reporter.h +++ b/atom/common/crash_reporter/crash_reporter.h @@ -40,7 +40,7 @@ class CrashReporter { virtual void SetExtraParameter(const std::string& key, const std::string& value); virtual void RemoveExtraParameter(const std::string& key); - virtual CrashReporter::StringMap GetParameters(); + virtual std::map GetParameters(); protected: CrashReporter(); diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm index 990e1b3b195..bd8660f05d2 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ b/atom/common/crash_reporter/crash_reporter_mac.mm @@ -107,10 +107,11 @@ void CrashReporterMac::SetCrashKeyValue(const base::StringPiece& key, void CrashReporterMac::SetExtraParameter(const std::string& key, const std::string& value) { - if (simple_string_dictionary_) + if (simple_string_dictionary_) { SetCrashKeyValue(key, value); - else + } else { upload_parameters_[key] = value; + } } void CrashReporterMac::RemoveExtraParameter(const std::string& key) { diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index 6b9f14a9785..7cbf1e2b793 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -110,7 +110,7 @@ class CrashReporter { } getParameters (key, value) { - binding.getParameters() + return binding.getParameters() } } diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 411186205ea..e7c56a1ca8e 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -321,31 +321,49 @@ describe('crashReporter module', () => { }) }) - describe('Parameters', () => { + describe.only('Parameters', () => { it('returns all of the current parameters', () => { + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: 'http://127.0.0.1/crashes' + }) + const parameters = crashReporter.getParameters() - assert(typeof parameters === Object) + assert(typeof parameters === 'object') }) it('adds a parameter', () => { // only run on MacOS if (process.platform !== 'darwin') return - crashReporter.addParameter('hello', 'world') + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: 'http://127.0.0.1/crashes' + }) + + crashReporter.setExtraParameter('hello', 'world') const updatedParams = crashReporter.getParameters() - assert(updatedParams.includes('hello')) + console.log(updatedParams) + + assert('hello' in updatedParams) }) it('removes a parameter', () => { // only run on MacOS if (process.platform !== 'darwin') return - crashReporter.addParameter('hello', 'world') + crashReporter.start({ + companyName: 'Umbrella Corporation', + submitURL: 'http://127.0.0.1/crashes' + }) + + crashReporter.setExtraParameter('hello', 'world') const originalParams = crashReporter.getParameters() - assert(originalParams.includes('hello')) + console.log(originalParams) + assert('hello' in originalParams) crashReporter.removeExtraParameter('hello') const updatedParams = crashReporter.getParameters() - assert(!updatedParams.includes('hello')) + assert(!('hello' in originalParams)) }) }) }) From a538e479941e2dc547c170d83684b5a8e00c8fa8 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 31 Oct 2017 18:19:04 -0400 Subject: [PATCH 133/185] complete GetParameters method & all tests passing --- .../crash_reporter/crash_reporter_mac.h | 2 ++ .../crash_reporter/crash_reporter_mac.mm | 15 ++++++++++++ spec/api-crash-reporter-spec.js | 23 ++++++++----------- 3 files changed, 26 insertions(+), 14 deletions(-) diff --git a/atom/common/crash_reporter/crash_reporter_mac.h b/atom/common/crash_reporter/crash_reporter_mac.h index 583c99a86e9..1ee252d189a 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.h +++ b/atom/common/crash_reporter/crash_reporter_mac.h @@ -5,6 +5,7 @@ #ifndef ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_ #define ATOM_COMMON_CRASH_REPORTER_CRASH_REPORTER_MAC_H_ +#include #include #include @@ -37,6 +38,7 @@ class CrashReporterMac : public CrashReporter { void SetExtraParameter(const std::string& key, const std::string& value) override; void RemoveExtraParameter(const std::string& key) override; + std::map GetParameters() override; private: friend struct base::DefaultSingletonTraits; diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm index bd8660f05d2..8792842f1b2 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ b/atom/common/crash_reporter/crash_reporter_mac.mm @@ -121,6 +121,21 @@ void CrashReporterMac::RemoveExtraParameter(const std::string& key) { upload_parameters_.erase(key); } +std::map CrashReporterMac::GetParameters() { + if (simple_string_dictionary_) { + std::map ret; + crashpad::SimpleStringDictionary::Iterator iter(*simple_string_dictionary_); + for(;;) { + const crashpad::SimpleStringDictionary::Entry* entry = iter.Next(); + if (!entry) break; + ret[entry->key] = entry->value; + } + return ret; + } else { + return upload_parameters_; + } +} + std::vector CrashReporterMac::GetUploadedReports(const base::FilePath& crashes_dir) { std::vector uploaded_reports; diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index e7c56a1ca8e..1d01242e894 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,7 +11,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe('crashReporter module', () => { +describe.only('crashReporter module', () => { if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return let originalTempDirectory = null @@ -71,7 +71,6 @@ describe('crashReporter module', () => { done: done }) }) - it('should send minidump when node processes crash', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() @@ -104,7 +103,6 @@ describe('crashReporter module', () => { done: done }) }) - it('should not send minidump if uploadToServer is false', function (done) { this.timeout(120000) @@ -166,7 +164,6 @@ describe('crashReporter module', () => { done: testDone.bind(null, true) }) }) - it('should send minidump with updated extra parameters', function (done) { if (process.env.APPVEYOR === 'True') return done() if (process.env.TRAVIS === 'true') return done() @@ -178,12 +175,12 @@ describe('crashReporter module', () => { const crashUrl = url.format({ protocol: 'file', pathname: path.join(fixtures, 'api', 'crash-restart.html'), - search: '?port=' + port + search: `?port=${port}` }) w.loadURL(crashUrl) }, processType: 'renderer', - done: done + done: done() }) }) }) @@ -271,7 +268,7 @@ describe('crashReporter module', () => { it('throws an error when called from the renderer process', () => { assert.throws(() => require('electron').crashReporter.getUploadToServer()) }) - it('returns true when uploadToServer is true', () => { + it('returns true when uploadToServer is set to true', () => { if (process.platform === 'darwin') { crashReporter.start({ companyName: 'Umbrella Corporation', @@ -281,13 +278,14 @@ describe('crashReporter module', () => { assert.equal(crashReporter.getUploadToServer(), true) } }) - it('returns false when uploadToServer is false', () => { + it('returns false when uploadToServer is set to false', () => { if (process.platform === 'darwin') { crashReporter.start({ companyName: 'Umbrella Corporation', submitURL: 'http://127.0.0.1/crashes', - uploadToServer: false + uploadToServer: true }) + crashReporter.setUploadToServer(false) assert.equal(crashReporter.getUploadToServer(), false) } }) @@ -321,7 +319,7 @@ describe('crashReporter module', () => { }) }) - describe.only('Parameters', () => { + describe('Parameters', () => { it('returns all of the current parameters', () => { crashReporter.start({ companyName: 'Umbrella Corporation', @@ -343,8 +341,6 @@ describe('crashReporter module', () => { crashReporter.setExtraParameter('hello', 'world') const updatedParams = crashReporter.getParameters() - console.log(updatedParams) - assert('hello' in updatedParams) }) it('removes a parameter', () => { @@ -358,12 +354,11 @@ describe('crashReporter module', () => { crashReporter.setExtraParameter('hello', 'world') const originalParams = crashReporter.getParameters() - console.log(originalParams) assert('hello' in originalParams) crashReporter.removeExtraParameter('hello') const updatedParams = crashReporter.getParameters() - assert(!('hello' in originalParams)) + assert(!('hello' in updatedParams)) }) }) }) From 7b08a935496de036efe129bdb19e18801ea9cb1d Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 31 Oct 2017 18:31:44 -0400 Subject: [PATCH 134/185] remove pesky 'only' --- spec/api-crash-reporter-spec.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 1d01242e894..f7155b28b2e 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,7 +11,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe.only('crashReporter module', () => { +describe('crashReporter module', () => { if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return let originalTempDirectory = null From 93df164485e3bae3cd8fea6a71e0cac6576590f6 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 31 Oct 2017 23:42:25 -0400 Subject: [PATCH 135/185] add const and other small edits --- atom/common/api/atom_api_crash_reporter.cc | 2 +- atom/common/crash_reporter/crash_reporter.cc | 14 +++++++++----- atom/common/crash_reporter/crash_reporter.h | 2 +- atom/common/crash_reporter/crash_reporter_mac.h | 2 +- atom/common/crash_reporter/crash_reporter_mac.mm | 7 +++---- lib/common/api/crash-reporter.js | 7 +++++-- spec/api-crash-reporter-spec.js | 8 ++++---- 7 files changed, 24 insertions(+), 18 deletions(-) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc index b3d395aa26d..c13844d9fd4 100644 --- a/atom/common/api/atom_api_crash_reporter.cc +++ b/atom/common/api/atom_api_crash_reporter.cc @@ -39,7 +39,7 @@ void RemoveExtraParameter(const std::string& key) { CrashReporter::GetInstance()->RemoveExtraParameter(key); } -std::map GetParameters() { +std::map GetParameters() const { return CrashReporter::GetInstance()->GetParameters(); } diff --git a/atom/common/crash_reporter/crash_reporter.cc b/atom/common/crash_reporter/crash_reporter.cc index 0793c056668..e264904146c 100644 --- a/atom/common/crash_reporter/crash_reporter.cc +++ b/atom/common/crash_reporter/crash_reporter.cc @@ -80,16 +80,20 @@ void CrashReporter::InitBreakpad(const std::string& product_name, const std::string& submit_url, const base::FilePath& crashes_dir, bool auto_submit, - bool skip_system_crash_handler) {} + bool skip_system_crash_handler) { +} -void CrashReporter::SetUploadParameters() {} +void CrashReporter::SetUploadParameters() { +} void CrashReporter::SetExtraParameter(const std::string& key, - const std::string& value) {} + const std::string& value) { +} -void CrashReporter::RemoveExtraParameter(const std::string& key) {} +void CrashReporter::RemoveExtraParameter(const std::string& key) { +} -std::map CrashReporter::GetParameters() { +std::map CrashReporter::GetParameters() const { return upload_parameters_; } diff --git a/atom/common/crash_reporter/crash_reporter.h b/atom/common/crash_reporter/crash_reporter.h index ca85ad71777..c0a4042bcd6 100644 --- a/atom/common/crash_reporter/crash_reporter.h +++ b/atom/common/crash_reporter/crash_reporter.h @@ -40,7 +40,7 @@ class CrashReporter { virtual void SetExtraParameter(const std::string& key, const std::string& value); virtual void RemoveExtraParameter(const std::string& key); - virtual std::map GetParameters(); + virtual std::map GetParameters() const; protected: CrashReporter(); diff --git a/atom/common/crash_reporter/crash_reporter_mac.h b/atom/common/crash_reporter/crash_reporter_mac.h index 1ee252d189a..9ea8c7284c9 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.h +++ b/atom/common/crash_reporter/crash_reporter_mac.h @@ -38,7 +38,7 @@ class CrashReporterMac : public CrashReporter { void SetExtraParameter(const std::string& key, const std::string& value) override; void RemoveExtraParameter(const std::string& key) override; - std::map GetParameters() override; + std::map GetParameters() const override; private: friend struct base::DefaultSingletonTraits; diff --git a/atom/common/crash_reporter/crash_reporter_mac.mm b/atom/common/crash_reporter/crash_reporter_mac.mm index 8792842f1b2..df393b90a76 100644 --- a/atom/common/crash_reporter/crash_reporter_mac.mm +++ b/atom/common/crash_reporter/crash_reporter_mac.mm @@ -121,19 +121,18 @@ void CrashReporterMac::RemoveExtraParameter(const std::string& key) { upload_parameters_.erase(key); } -std::map CrashReporterMac::GetParameters() { +std::map CrashReporterMac::GetParameters() const { if (simple_string_dictionary_) { std::map ret; crashpad::SimpleStringDictionary::Iterator iter(*simple_string_dictionary_); for(;;) { - const crashpad::SimpleStringDictionary::Entry* entry = iter.Next(); + const auto entry = iter.Next(); if (!entry) break; ret[entry->key] = entry->value; } return ret; - } else { - return upload_parameters_; } + return upload_parameters_; } std::vector diff --git a/lib/common/api/crash-reporter.js b/lib/common/api/crash-reporter.js index 7cbf1e2b793..75fdc4a3db1 100644 --- a/lib/common/api/crash-reporter.js +++ b/lib/common/api/crash-reporter.js @@ -20,7 +20,8 @@ class CrashReporter { uploadToServer } = options - if (uploadToServer == null) uploadToServer = options.autoSubmit || true + if (uploadToServer == null) uploadToServer = options.autoSubmit + if (uploadToServer == null) uploadToServer = true if (ignoreSystemCrashHandler == null) ignoreSystemCrashHandler = false if (extra == null) extra = {} @@ -36,7 +37,9 @@ class CrashReporter { } if (process.platform === 'win32') { - const env = { ELECTRON_INTERNAL_CRASH_SERVICE: 1 } + const env = { + ELECTRON_INTERNAL_CRASH_SERVICE: 1 + } const args = [ '--reporter-url=' + submitURL, '--application-name=' + this.getProductName(), diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index f7155b28b2e..663f501f32d 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,7 +11,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe('crashReporter module', () => { +describe.only('crashReporter module', () => { if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return let originalTempDirectory = null @@ -197,10 +197,10 @@ describe('crashReporter module', () => { describe('getProductName', () => { it('returns the product name if one is specified', () => { const name = crashReporter.getProductName() - if (process.platform === 'win32') { - assert.equal(name, 'Zombies') - } else { + if (process.platform === 'darwin') { assert.equal(name, 'Electron Test') + } else { + assert.equal(name, 'Zombies') } }) }) From 7f89cd0774323b82426fc4d1f991181b93b8a1d2 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 31 Oct 2017 23:55:22 -0400 Subject: [PATCH 136/185] remove const from non-member function --- atom/common/api/atom_api_crash_reporter.cc | 2 +- spec/api-crash-reporter-spec.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/atom/common/api/atom_api_crash_reporter.cc b/atom/common/api/atom_api_crash_reporter.cc index c13844d9fd4..b3d395aa26d 100644 --- a/atom/common/api/atom_api_crash_reporter.cc +++ b/atom/common/api/atom_api_crash_reporter.cc @@ -39,7 +39,7 @@ void RemoveExtraParameter(const std::string& key) { CrashReporter::GetInstance()->RemoveExtraParameter(key); } -std::map GetParameters() const { +std::map GetParameters() { return CrashReporter::GetInstance()->GetParameters(); } diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 663f501f32d..1c89b6f6756 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -11,7 +11,7 @@ const {closeWindow} = require('./window-helpers') const {remote} = require('electron') const {app, BrowserWindow, crashReporter} = remote.require('electron') -describe.only('crashReporter module', () => { +describe('crashReporter module', () => { if (process.mas || process.env.DISABLE_CRASH_REPORTER_TESTS) return let originalTempDirectory = null From 0adf775d9a387772e5eaa50ec9e918f66d1622ea Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 1 Nov 2017 08:57:22 -0400 Subject: [PATCH 137/185] clean fixture and fix failing travis test --- spec/api-crash-reporter-spec.js | 9 +++--- spec/fixtures/api/crash.html | 54 ++++++++++++++++++--------------- 2 files changed, 33 insertions(+), 30 deletions(-) diff --git a/spec/api-crash-reporter-spec.js b/spec/api-crash-reporter-spec.js index 1c89b6f6756..1cd6bbc3e7c 100644 --- a/spec/api-crash-reporter-spec.js +++ b/spec/api-crash-reporter-spec.js @@ -197,11 +197,8 @@ describe('crashReporter module', () => { describe('getProductName', () => { it('returns the product name if one is specified', () => { const name = crashReporter.getProductName() - if (process.platform === 'darwin') { - assert.equal(name, 'Electron Test') - } else { - assert.equal(name, 'Zombies') - } + const expectedName = (process.platform === 'darwin') ? 'Electron Test' : 'Zombies' + assert.equal(name, expectedName) }) }) @@ -258,6 +255,8 @@ describe('crashReporter module', () => { describe('getLastCrashReport', () => { it('correctly returns the most recent report', () => { + if (process.env.TRAVIS === 'True') return + const reports = crashReporter.getUploadedReports() const lastReport = reports[0] assert(lastReport != null) diff --git a/spec/fixtures/api/crash.html b/spec/fixtures/api/crash.html index 8b64eddd25b..a3dbeb6ded4 100644 --- a/spec/fixtures/api/crash.html +++ b/spec/fixtures/api/crash.html @@ -1,30 +1,34 @@ + - + if (process.platform === 'win32') { + ipcRenderer.sendSync('crash-service-pid', crashReporter._crashServiceProcess.pid) + } + + if (!uploadToServer) { + ipcRenderer.sendSync('list-existing-dumps') + } + + setImmediate(() => { process.crash() }) + - + + \ No newline at end of file From d2e1705c800a72b7d25c2cc5ba05b5a7f33b3c38 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 1 Nov 2017 10:48:09 -0400 Subject: [PATCH 138/185] convert app and browser spec to ES6 --- spec/api-browser-window-spec.js | 1173 +++++++++++++------------------ spec/api-shell-spec.js | 22 +- 2 files changed, 515 insertions(+), 680 deletions(-) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index 6cb668206d4..1c42a96da45 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -14,13 +14,14 @@ const {app, ipcMain, BrowserWindow, protocol, webContents} = remote const isCI = remote.getGlobal('isCi') const nativeModulesEnabled = remote.getGlobal('nativeModulesEnabled') -describe('BrowserWindow module', function () { - var fixtures = path.resolve(__dirname, 'fixtures') - var w = null - var ws = null - var server, postData +describe('BrowserWindow module', () => { + const fixtures = path.resolve(__dirname, 'fixtures') + let w = null + let ws = null + let server + let postData - before(function (done) { + before((done) => { const filePath = path.join(fixtures, 'pages', 'a.html') const fileStats = fs.statSync(filePath) postData = [ @@ -36,14 +37,12 @@ describe('BrowserWindow module', function () { modificationTime: fileStats.mtime.getTime() / 1000 } ] - server = http.createServer(function (req, res) { + server = http.createServer((req, res) => { function respond () { if (req.method === 'POST') { let body = '' req.on('data', (data) => { - if (data) { - body += data - } + if (data) body += data }) req.on('end', () => { let parsedData = qs.parse(body) @@ -61,18 +60,18 @@ describe('BrowserWindow module', function () { } setTimeout(respond, req.url.includes('slow') ? 200 : 0) }) - server.listen(0, '127.0.0.1', function () { - server.url = 'http://127.0.0.1:' + server.address().port + server.listen(0, '127.0.0.1', () => { + server.url = `http://127.0.0.1:${server.address().port}` done() }) }) - after(function () { + after(() => { server.close() server = null }) - beforeEach(function () { + beforeEach(() => { w = new BrowserWindow({ show: false, width: 400, @@ -83,14 +82,14 @@ describe('BrowserWindow module', function () { }) }) - afterEach(function () { - return closeWindow(w).then(function () { w = null }) + afterEach(() => { + return closeWindow(w).then(() => { w = null }) }) - describe('BrowserWindow.close()', function () { + describe('BrowserWindow.close()', () => { let server - before(function (done) { + before((done) => { server = http.createServer((request, response) => { switch (request.url) { case '/404': @@ -119,36 +118,28 @@ describe('BrowserWindow module', function () { }) }) - after(function () { + after(() => { server.close() server = null }) - it('should emit unload handler', function (done) { - w.webContents.on('did-finish-load', function () { - w.close() - }) - w.once('closed', function () { - var test = path.join(fixtures, 'api', 'unload') - var content = fs.readFileSync(test) + it('should emit unload handler', (done) => { + w.webContents.on('did-finish-load', () => { w.close() }) + w.once('closed', () => { + const test = path.join(fixtures, 'api', 'unload') + const content = fs.readFileSync(test) fs.unlinkSync(test) assert.equal(String(content), 'unload') done() }) w.loadURL('file://' + path.join(fixtures, 'api', 'unload.html')) }) - - it('should emit beforeunload handler', function (done) { - w.once('onbeforeunload', function () { - done() - }) - w.webContents.on('did-finish-load', function () { - w.close() - }) - w.loadURL('file://' + path.join(fixtures, 'api', 'beforeunload-false.html')) + it('should emit beforeunload handler', (done) => { + w.once('onbeforeunload', () => { done() }) + w.webContents.on('did-finish-load', () => { w.close() }) + w.loadURL(`file://${path.join(fixtures, 'api', 'beforeunload-false.html')}`) }) - - it('should not crash when invoked synchronously inside navigation observer', function (done) { + it('should not crash when invoked synchronously inside navigation observer', (done) => { const events = [ { name: 'did-start-loading', url: `${server.url}/200` }, { name: 'did-get-redirect-request', url: `${server.url}/301` }, @@ -174,69 +165,60 @@ describe('BrowserWindow module', function () { } let gen = genNavigationEvent() - ipcRenderer.on(responseEvent, function () { + ipcRenderer.on(responseEvent, () => { if (!gen.next().value) done() }) gen.next() }) }) - describe('window.close()', function () { - it('should emit unload handler', function (done) { - w.once('closed', function () { - var test = path.join(fixtures, 'api', 'close') - var content = fs.readFileSync(test) + describe('window.close()', () => { + it('should emit unload handler', (done) => { + w.once('closed', () => { + const test = path.join(fixtures, 'api', 'close') + const content = fs.readFileSync(test) fs.unlinkSync(test) assert.equal(String(content), 'close') done() }) - w.loadURL('file://' + path.join(fixtures, 'api', 'close.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'close.html')}`) }) - - it('should emit beforeunload handler', function (done) { - w.once('onbeforeunload', function () { - done() - }) - w.loadURL('file://' + path.join(fixtures, 'api', 'close-beforeunload-false.html')) + it('should emit beforeunload handler', (done) => { + w.once('onbeforeunload', () => { done() }) + w.loadURL(`file://${path.join(fixtures, 'api', 'close-beforeunload-false.html')}`) }) }) - describe('BrowserWindow.destroy()', function () { - it('prevents users to access methods of webContents', function () { + describe('BrowserWindow.destroy()', () => { + it('prevents users to access methods of webContents', () => { const contents = w.webContents w.destroy() - assert.throws(function () { + assert.throws(() => { contents.getId() }, /Object has been destroyed/) }) }) - describe('BrowserWindow.loadURL(url)', function () { - it('should emit did-start-loading event', function (done) { - w.webContents.on('did-start-loading', function () { - done() - }) + describe('BrowserWindow.loadURL(url)', () => { + it('should emit did-start-loading event', (done) => { + w.webContents.on('did-start-loading', () => { done() }) w.loadURL('about:blank') }) - - it('should emit ready-to-show event', function (done) { - w.on('ready-to-show', function () { - done() - }) + it('should emit ready-to-show event', (done) => { + w.on('ready-to-show', () => { done() }) w.loadURL('about:blank') }) - - it('should emit did-get-response-details event', function (done) { + it('should emit did-get-response-details event', (done) => { // expected {fileName: resourceType} pairs - var expectedResources = { + const expectedResources = { 'did-get-response-details.html': 'mainFrame', 'logo.png': 'image' } - var responses = 0 - w.webContents.on('did-get-response-details', function (event, status, newUrl, oldUrl, responseCode, method, referrer, headers, resourceType) { - responses++ - var fileName = newUrl.slice(newUrl.lastIndexOf('/') + 1) - var expectedType = expectedResources[fileName] + let responses = 0 + w.webContents.on('did-get-response-details', (event, status, newUrl, oldUrl, responseCode, method, referrer, headers, resourceType) => { + responses += 1 + const fileName = newUrl.slice(newUrl.lastIndexOf('/') + 1) + const expectedType = expectedResources[fileName] assert(!!expectedType, `Unexpected response details for ${newUrl}`) assert(typeof status === 'boolean', 'status should be boolean') assert.equal(responseCode, 200) @@ -245,15 +227,12 @@ describe('BrowserWindow module', function () { assert(!!headers, 'headers should be present') assert(typeof headers === 'object', 'headers should be object') assert.equal(resourceType, expectedType, 'Incorrect resourceType') - if (responses === Object.keys(expectedResources).length) { - done() - } + if (responses === Object.keys(expectedResources).length) done() }) - w.loadURL('file://' + path.join(fixtures, 'pages', 'did-get-response-details.html')) + w.loadURL(`file://${path.join(fixtures, 'pages', 'did-get-response-details.html')}`) }) - - it('should emit did-fail-load event for files that do not exist', function (done) { - w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { + it('should emit did-fail-load event for files that do not exist', (done) => { + w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => { assert.equal(code, -6) assert.equal(desc, 'ERR_FILE_NOT_FOUND') assert.equal(isMainFrame, true) @@ -261,9 +240,8 @@ describe('BrowserWindow module', function () { }) w.loadURL('file://a.txt') }) - - it('should emit did-fail-load event for invalid URL', function (done) { - w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { + it('should emit did-fail-load event for invalid URL', (done) => { + w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => { assert.equal(desc, 'ERR_INVALID_URL') assert.equal(code, -300) assert.equal(isMainFrame, true) @@ -271,25 +249,22 @@ describe('BrowserWindow module', function () { }) w.loadURL('http://example:port') }) - - it('should set `mainFrame = false` on did-fail-load events in iframes', function (done) { - w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { + it('should set `mainFrame = false` on did-fail-load events in iframes', (done) => { + w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => { assert.equal(isMainFrame, false) done() }) - w.loadURL('file://' + path.join(fixtures, 'api', 'did-fail-load-iframe.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'did-fail-load-iframe.html')}`) }) - - it('does not crash in did-fail-provisional-load handler', function (done) { - w.webContents.once('did-fail-provisional-load', function () { + it('does not crash in did-fail-provisional-load handler', (done) => { + w.webContents.once('did-fail-provisional-load', () => { w.loadURL('http://127.0.0.1:11111') done() }) w.loadURL('http://127.0.0.1:11111') }) - - it('should emit did-fail-load event for URL exceeding character limit', function (done) { - w.webContents.on('did-fail-load', function (event, code, desc, url, isMainFrame) { + it('should emit did-fail-load event for URL exceeding character limit', (done) => { + w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => { assert.equal(desc, 'ERR_INVALID_URL') assert.equal(code, -300) assert.equal(isMainFrame, true) @@ -299,17 +274,14 @@ describe('BrowserWindow module', function () { w.loadURL(`data:image/png;base64,${data}`) }) - describe('POST navigations', function () { - afterEach(() => { - w.webContents.session.webRequest.onBeforeSendHeaders(null) - }) + describe('POST navigations', () => { + afterEach(() => { w.webContents.session.webRequest.onBeforeSendHeaders(null) }) - it('supports specifying POST data', function (done) { + it('supports specifying POST data', (done) => { w.webContents.on('did-finish-load', () => done()) w.loadURL(server.url, {postData: postData}) }) - - it('sets the content type header on URL encoded forms', function (done) { + it('sets the content type header on URL encoded forms', (done) => { w.webContents.on('did-finish-load', () => { w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => { assert.equal(details.requestHeaders['content-type'], 'application/x-www-form-urlencoded') @@ -325,8 +297,7 @@ describe('BrowserWindow module', function () { }) w.loadURL(server.url) }) - - it('sets the content type header on multi part forms', function (done) { + it('sets the content type header on multi part forms', (done) => { w.webContents.on('did-finish-load', () => { w.webContents.session.webRequest.onBeforeSendHeaders((details, callback) => { assert(details.requestHeaders['content-type'].startsWith('multipart/form-data; boundary=----WebKitFormBoundary')) @@ -350,7 +321,7 @@ describe('BrowserWindow module', function () { }) it('should support support base url for data urls', (done) => { - ipcMain.once('answer', function (event, test) { + ipcMain.once('answer', (event, test) => { assert.equal(test, 'test') done() }) @@ -358,33 +329,27 @@ describe('BrowserWindow module', function () { }) }) - describe('will-navigate event', function () { + describe('will-navigate event', () => { it('allows the window to be closed from the event listener', (done) => { ipcRenderer.send('close-on-will-navigate', w.id) - ipcRenderer.once('closed-on-will-navigate', () => { - done() - }) - w.loadURL('file://' + fixtures + '/pages/will-navigate.html') + ipcRenderer.once('closed-on-will-navigate', () => { done() }) + w.loadURL(`file://${fixtures}/pages/will-navigate.html`) }) }) - describe('BrowserWindow.show()', function () { - if (isCI) { - return - } + describe('BrowserWindow.show()', () => { + if (isCI) return - it('should focus on window', function () { + it('should focus on window', () => { w.show() assert(w.isFocused()) }) - - it('should make the window visible', function () { + it('should make the window visible', () => { w.show() assert(w.isVisible()) }) - - it('emits when window is shown', function (done) { - w.once('show', function () { + it('emits when window is shown', (done) => { + w.once('show', () => { assert.equal(w.isVisible(), true) done() }) @@ -392,25 +357,21 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.hide()', function () { - if (isCI) { - return - } + describe('BrowserWindow.hide()', () => { + if (isCI) return - it('should defocus on window', function () { + it('should defocus on window', () => { w.hide() assert(!w.isFocused()) }) - - it('should make the window not visible', function () { + it('should make the window not visible', () => { w.show() w.hide() assert(!w.isVisible()) }) - - it('emits when window is hidden', function (done) { + it('emits when window is hidden', (done) => { w.show() - w.once('hide', function () { + w.once('hide', () => { assert.equal(w.isVisible(), false) done() }) @@ -418,46 +379,46 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.showInactive()', function () { - it('should not focus on window', function () { + describe('BrowserWindow.showInactive()', () => { + it('should not focus on window', () => { w.showInactive() assert(!w.isFocused()) }) }) - describe('BrowserWindow.focus()', function () { - it('does not make the window become visible', function () { + describe('BrowserWindow.focus()', () => { + it('does not make the window become visible', () => { assert.equal(w.isVisible(), false) w.focus() assert.equal(w.isVisible(), false) }) }) - describe('BrowserWindow.blur()', function () { - it('removes focus from window', function () { + describe('BrowserWindow.blur()', () => { + it('removes focus from window', () => { w.blur() assert(!w.isFocused()) }) }) - describe('BrowserWindow.capturePage(rect, callback)', function () { - it('calls the callback with a Buffer', function (done) { + describe('BrowserWindow.capturePage(rect, callback)', () => { + it('calls the callback with a Buffer', (done) => { w.capturePage({ x: 0, y: 0, width: 100, height: 100 - }, function (image) { + }, (image) => { assert.equal(image.isEmpty(), true) done() }) }) }) - describe('BrowserWindow.setSize(width, height)', function () { - it('sets the window size', function (done) { - var size = [300, 400] - w.once('resize', function () { + describe('BrowserWindow.setSize(width, height)', () => { + it('sets the window size', (done) => { + const size = [300, 400] + w.once('resize', () => { assertBoundsEqual(w.getSize(), size) done() }) @@ -465,8 +426,8 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setMinimum/MaximumSize(width, height)', function () { - it('sets the maximum and minimum size of the window', function () { + describe('BrowserWindow.setMinimum/MaximumSize(width, height)', () => { + it('sets the maximum and minimum size of the window', () => { assert.deepEqual(w.getMinimumSize(), [0, 0]) assert.deepEqual(w.getMaximumSize(), [0, 0]) @@ -480,12 +441,12 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setAspectRatio(ratio)', function () { - it('resets the behaviour when passing in 0', function (done) { - var size = [300, 400] + describe('BrowserWindow.setAspectRatio(ratio)', () => { + it('resets the behaviour when passing in 0', (done) => { + const size = [300, 400] w.setAspectRatio(1 / 2) w.setAspectRatio(0) - w.once('resize', function () { + w.once('resize', () => { assertBoundsEqual(w.getSize(), size) done() }) @@ -493,11 +454,11 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setPosition(x, y)', function () { - it('sets the window position', function (done) { - var pos = [10, 10] - w.once('move', function () { - var newPos = w.getPosition() + describe('BrowserWindow.setPosition(x, y)', () => { + it('sets the window position', (done) => { + const pos = [10, 10] + w.once('move', () => { + const newPos = w.getPosition() assert.equal(newPos[0], pos[0]) assert.equal(newPos[1], pos[1]) done() @@ -506,16 +467,15 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setContentSize(width, height)', function () { - it('sets the content size', function () { - var size = [400, 400] + describe('BrowserWindow.setContentSize(width, height)', () => { + it('sets the content size', () => { + const size = [400, 400] w.setContentSize(size[0], size[1]) var after = w.getContentSize() assert.equal(after[0], size[0]) assert.equal(after[1], size[1]) }) - - it('works for a frameless window', function () { + it('works for a frameless window', () => { w.destroy() w = new BrowserWindow({ show: false, @@ -523,25 +483,24 @@ describe('BrowserWindow module', function () { width: 400, height: 400 }) - var size = [400, 400] + const size = [400, 400] w.setContentSize(size[0], size[1]) - var after = w.getContentSize() + const after = w.getContentSize() assert.equal(after[0], size[0]) assert.equal(after[1], size[1]) }) }) - describe('BrowserWindow.setContentBounds(bounds)', function () { - it('sets the content size and position', function (done) { - var bounds = {x: 10, y: 10, width: 250, height: 250} - w.once('resize', function () { + describe('BrowserWindow.setContentBounds(bounds)', () => { + it('sets the content size and position', (done) => { + const bounds = {x: 10, y: 10, width: 250, height: 250} + w.once('resize', () => { assertBoundsEqual(w.getContentBounds(), bounds) done() }) w.setContentBounds(bounds) }) - - it('works for a frameless window', function (done) { + it('works for a frameless window', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -549,8 +508,8 @@ describe('BrowserWindow module', function () { width: 300, height: 300 }) - var bounds = {x: 10, y: 10, width: 250, height: 250} - w.once('resize', function () { + const bounds = {x: 10, y: 10, width: 250, height: 250} + w.once('resize', () => { assert.deepEqual(w.getContentBounds(), bounds) done() }) @@ -558,9 +517,9 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setProgressBar(progress)', function () { - it('sets the progress', function () { - assert.doesNotThrow(function () { + describe('BrowserWindow.setProgressBar(progress)', () => { + it('sets the progress', () => { + assert.doesNotThrow(() => { if (process.platform === 'darwin') { app.dock.setIcon(path.join(fixtures, 'assets', 'logo.png')) } @@ -572,28 +531,25 @@ describe('BrowserWindow module', function () { w.setProgressBar(-1) }) }) - - it('sets the progress using "paused" mode', function () { - assert.doesNotThrow(function () { + it('sets the progress using "paused" mode', () => { + assert.doesNotThrow(() => { w.setProgressBar(0.5, {mode: 'paused'}) }) }) - - it('sets the progress using "error" mode', function () { - assert.doesNotThrow(function () { + it('sets the progress using "error" mode', () => { + assert.doesNotThrow(() => { w.setProgressBar(0.5, {mode: 'error'}) }) }) - - it('sets the progress using "normal" mode', function () { - assert.doesNotThrow(function () { + it('sets the progress using "normal" mode', () => { + assert.doesNotThrow(() => { w.setProgressBar(0.5, {mode: 'normal'}) }) }) }) - describe('BrowserWindow.setAlwaysOnTop(flag, level)', function () { - it('sets the window as always on top', function () { + describe('BrowserWindow.setAlwaysOnTop(flag, level)', () => { + it('sets the window as always on top', () => { assert.equal(w.isAlwaysOnTop(), false) w.setAlwaysOnTop(true, 'screen-saver') assert.equal(w.isAlwaysOnTop(), true) @@ -602,26 +558,23 @@ describe('BrowserWindow module', function () { w.setAlwaysOnTop(true) assert.equal(w.isAlwaysOnTop(), true) }) - - it('raises an error when relativeLevel is out of bounds', function () { + it('raises an error when relativeLevel is out of bounds', () => { if (process.platform !== 'darwin') return - assert.throws(function () { + assert.throws(() => { w.setAlwaysOnTop(true, '', -2147483644) }) - assert.throws(function () { + assert.throws(() => { w.setAlwaysOnTop(true, '', 2147483632) }) }) }) - describe('BrowserWindow.alwaysOnTop() resets level on minimize', function () { - if (process.platform !== 'darwin') { - return - } + describe('BrowserWindow.alwaysOnTop() resets level on minimize', () => { + if (process.platform !== 'darwin') return - it('resets the windows level on minimize', function () { + it('resets the windows level on minimize', () => { assert.equal(w.isAlwaysOnTop(), false) w.setAlwaysOnTop(true, 'screen-saver') assert.equal(w.isAlwaysOnTop(), true) @@ -637,10 +590,8 @@ describe('BrowserWindow module', function () { it('is not available on non-macOS platforms', () => { assert.ok(!w.setAutoHideCursor) }) - return } - it('allows changing cursor auto-hiding', () => { assert.doesNotThrow(() => { w.setAutoHideCursor(false) @@ -651,9 +602,7 @@ describe('BrowserWindow module', function () { describe('BrowserWindow.selectPreviousTab()', () => { it('does not throw', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return assert.doesNotThrow(() => { w.selectPreviousTab() @@ -663,9 +612,7 @@ describe('BrowserWindow module', function () { describe('BrowserWindow.selectNextTab()', () => { it('does not throw', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return assert.doesNotThrow(() => { w.selectNextTab() @@ -675,9 +622,7 @@ describe('BrowserWindow module', function () { describe('BrowserWindow.mergeAllWindows()', () => { it('does not throw', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return assert.doesNotThrow(() => { w.mergeAllWindows() @@ -687,9 +632,7 @@ describe('BrowserWindow module', function () { describe('BrowserWindow.moveTabToNewWindow()', () => { it('does not throw', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return assert.doesNotThrow(() => { w.moveTabToNewWindow() @@ -699,9 +642,7 @@ describe('BrowserWindow module', function () { describe('BrowserWindow.toggleTabBar()', () => { it('does not throw', () => { - if (process.platform !== 'darwin') { - return - } + if (process.platform !== 'darwin') return assert.doesNotThrow(() => { w.toggleTabBar() @@ -709,11 +650,10 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.addTabbedWindow()', function (done) { - it('does not throw', function () { - if (process.platform !== 'darwin') { - return - } + describe('BrowserWindow.addTabbedWindow()', (done) => { + it('does not throw', () => { + if (process.platform !== 'darwin') return + const tabbedWindow = new BrowserWindow({}) assert.doesNotThrow(() => { w.addTabbedWindow(tabbedWindow) @@ -722,9 +662,9 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setVibrancy(type)', function () { - it('allows setting, changing, and removing the vibrancy', function () { - assert.doesNotThrow(function () { + describe('BrowserWindow.setVibrancy(type)', () => { + it('allows setting, changing, and removing the vibrancy', () => { + assert.doesNotThrow(() => { w.setVibrancy('light') w.setVibrancy('dark') w.setVibrancy(null) @@ -734,13 +674,13 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setAppDetails(options)', function () { - it('supports setting the app details', function () { + describe('BrowserWindow.setAppDetails(options)', () => { + it('supports setting the app details', () => { if (process.platform !== 'win32') return const iconPath = path.join(fixtures, 'assets', 'icon.ico') - assert.doesNotThrow(function () { + assert.doesNotThrow(() => { w.setAppDetails({appId: 'my.app.id'}) w.setAppDetails({appIconPath: iconPath, appIconIndex: 0}) w.setAppDetails({appIconPath: iconPath}) @@ -757,47 +697,39 @@ describe('BrowserWindow module', function () { w.setAppDetails({}) }) - assert.throws(function () { + assert.throws(() => { w.setAppDetails() }, /Insufficient number of arguments\./) }) }) - describe('BrowserWindow.fromId(id)', function () { - it('returns the window with id', function () { + describe('BrowserWindow.fromId(id)', () => { + it('returns the window with id', () => { assert.equal(w.id, BrowserWindow.fromId(w.id).id) }) }) - describe('BrowserWindow.fromWebContents(webContents)', function () { + describe('BrowserWindow.fromWebContents(webContents)', () => { let contents = null - beforeEach(function () { - contents = webContents.create({}) - }) + beforeEach(() => { contents = webContents.create({}) }) - afterEach(function () { - contents.destroy() - }) + afterEach(() => { contents.destroy() }) - it('returns the window with the webContents', function () { + it('returns the window with the webContents', () => { assert.equal(BrowserWindow.fromWebContents(w.webContents).id, w.id) assert.equal(BrowserWindow.fromWebContents(contents), undefined) }) }) - describe('BrowserWindow.fromDevToolsWebContents(webContents)', function () { + describe('BrowserWindow.fromDevToolsWebContents(webContents)', () => { let contents = null - beforeEach(function () { - contents = webContents.create({}) - }) + beforeEach(() => { contents = webContents.create({}) }) - afterEach(function () { - contents.destroy() - }) + afterEach(() => { contents.destroy() }) - it('returns the window with the webContents', function (done) { + it('returns the window with the webContents', (done) => { w.webContents.once('devtools-opened', () => { assert.equal(BrowserWindow.fromDevToolsWebContents(w.devToolsWebContents).id, w.id) assert.equal(BrowserWindow.fromDevToolsWebContents(w.webContents), undefined) @@ -808,8 +740,8 @@ describe('BrowserWindow module', function () { }) }) - describe('BrowserWindow.setOpacity(opacity)', function () { - it('make window with initial opacity', function () { + describe('BrowserWindow.setOpacity(opacity)', () => { + it('make window with initial opacity', () => { w.destroy() w = new BrowserWindow({ show: false, @@ -819,9 +751,8 @@ describe('BrowserWindow module', function () { }) assert.equal(w.getOpacity(), 0.5) }) - - it('allows setting the opacity', function () { - assert.doesNotThrow(function () { + it('allows setting the opacity', () => { + assert.doesNotThrow(() => { w.setOpacity(0.0) assert.equal(w.getOpacity(), 0.0) w.setOpacity(0.5) @@ -832,8 +763,8 @@ describe('BrowserWindow module', function () { }) }) - describe('"useContentSize" option', function () { - it('make window created with content size when used', function () { + describe('"useContentSize" option', () => { + it('make window created with content size when used', () => { w.destroy() w = new BrowserWindow({ show: false, @@ -841,18 +772,16 @@ describe('BrowserWindow module', function () { height: 400, useContentSize: true }) - var contentSize = w.getContentSize() + const contentSize = w.getContentSize() assert.equal(contentSize[0], 400) assert.equal(contentSize[1], 400) }) - - it('make window created with window size when not used', function () { - var size = w.getSize() + it('make window created with window size when not used', () => { + const size = w.getSize() assert.equal(size[0], 400) assert.equal(size[1], 400) }) - - it('works for a frameless window', function () { + it('works for a frameless window', () => { w.destroy() w = new BrowserWindow({ show: false, @@ -861,24 +790,20 @@ describe('BrowserWindow module', function () { height: 400, useContentSize: true }) - var contentSize = w.getContentSize() + const contentSize = w.getContentSize() assert.equal(contentSize[0], 400) assert.equal(contentSize[1], 400) - var size = w.getSize() + const size = w.getSize() assert.equal(size[0], 400) assert.equal(size[1], 400) }) }) - describe('"titleBarStyle" option', function () { - if (process.platform !== 'darwin') { - return - } - if (parseInt(os.release().split('.')[0]) < 14) { - return - } + describe('"titleBarStyle" option', () => { + if (process.platform !== 'darwin') return + if (parseInt(os.release().split('.')[0]) < 14) return - it('creates browser window with hidden title bar', function () { + it('creates browser window with hidden title bar', () => { w.destroy() w = new BrowserWindow({ show: false, @@ -886,11 +811,10 @@ describe('BrowserWindow module', function () { height: 400, titleBarStyle: 'hidden' }) - var contentSize = w.getContentSize() + const contentSize = w.getContentSize() assert.equal(contentSize[1], 400) }) - - it('creates browser window with hidden inset title bar', function () { + it('creates browser window with hidden inset title bar', () => { w.destroy() w = new BrowserWindow({ show: false, @@ -898,17 +822,15 @@ describe('BrowserWindow module', function () { height: 400, titleBarStyle: 'hidden-inset' }) - var contentSize = w.getContentSize() + const contentSize = w.getContentSize() assert.equal(contentSize[1], 400) }) }) - describe('enableLargerThanScreen" option', function () { - if (process.platform === 'linux') { - return - } + describe('enableLargerThanScreen" option', () => { + if (process.platform === 'linux') return - beforeEach(function () { + beforeEach(() => { w.destroy() w = new BrowserWindow({ show: true, @@ -918,15 +840,14 @@ describe('BrowserWindow module', function () { }) }) - it('can move the window out of screen', function () { + it('can move the window out of screen', () => { w.setPosition(-10, -10) - var after = w.getPosition() + const after = w.getPosition() assert.equal(after[0], -10) assert.equal(after[1], -10) }) - - it('can set the window larger than screen', function () { - var size = screen.getPrimaryDisplay().size + it('can set the window larger than screen', () => { + const size = screen.getPrimaryDisplay().size size.width += 100 size.height += 100 w.setSize(size.width, size.height) @@ -934,8 +855,8 @@ describe('BrowserWindow module', function () { }) }) - describe('"zoomToPageWidth" option', function () { - it('sets the window width to the page width when used', function () { + describe('"zoomToPageWidth" option', () => { + it('sets the window width to the page width when used', () => { if (process.platform !== 'darwin') return w.destroy() @@ -950,8 +871,8 @@ describe('BrowserWindow module', function () { }) }) - describe('"tabbingIdentifier" option', function () { - it('can be set on a window', function () { + describe('"tabbingIdentifier" option', () => { + it('can be set on a window', () => { w.destroy() w = new BrowserWindow({ tabbingIdentifier: 'group1' @@ -964,15 +885,13 @@ describe('BrowserWindow module', function () { }) }) - describe('"webPreferences" option', function () { - afterEach(function () { - ipcMain.removeAllListeners('answer') - }) + describe('"webPreferences" option', () => { + afterEach(() => { ipcMain.removeAllListeners('answer') }) - describe('"preload" option', function () { - it('loads the script before other scripts in window', function (done) { - var preload = path.join(fixtures, 'module', 'set-global.js') - ipcMain.once('answer', function (event, test) { + describe('"preload" option', () => { + it('loads the script before other scripts in window', (done) => { + const preload = path.join(fixtures, 'module', 'set-global.js') + ipcMain.once('answer', (event, test) => { assert.equal(test, 'preload') done() }) @@ -983,12 +902,11 @@ describe('BrowserWindow module', function () { preload: preload } }) - w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'preload.html')}`) }) - - it('can successfully delete the Buffer global', function (done) { - var preload = path.join(fixtures, 'module', 'delete-buffer.js') - ipcMain.once('answer', function (event, test) { + it('can successfully delete the Buffer global', (done) => { + const preload = path.join(fixtures, 'module', 'delete-buffer.js') + ipcMain.once('answer', (event, test) => { assert.equal(test.toString(), 'buffer') done() }) @@ -999,14 +917,14 @@ describe('BrowserWindow module', function () { preload: preload } }) - w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'preload.html')}`) }) }) - describe('"node-integration" option', function () { - it('disables node integration when specified to false', function (done) { - var preload = path.join(fixtures, 'module', 'send-later.js') - ipcMain.once('answer', function (event, typeofProcess, typeofBuffer) { + describe('"node-integration" option', () => { + it('disables node integration when specified to false', (done) => { + const preload = path.join(fixtures, 'module', 'send-later.js') + ipcMain.once('answer', (event, typeofProcess, typeofBuffer) => { assert.equal(typeofProcess, 'undefined') assert.equal(typeofBuffer, 'undefined') done() @@ -1019,11 +937,11 @@ describe('BrowserWindow module', function () { nodeIntegration: false } }) - w.loadURL('file://' + path.join(fixtures, 'api', 'blank.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'blank.html')}`) }) }) - describe('"sandbox" option', function () { + describe('"sandbox" option', () => { function waitForEvents (emitter, events, callback) { let count = events.length for (let event of events) { @@ -1044,19 +962,19 @@ describe('BrowserWindow module', function () { }) } - before(function (done) { - protocol.interceptStringProtocol('http', crossDomainHandler, function () { + before((done) => { + protocol.interceptStringProtocol('http', crossDomainHandler, () => { done() }) }) - after(function (done) { - protocol.uninterceptProtocol('http', function () { + after((done) => { + protocol.uninterceptProtocol('http', () => { done() }) }) - it('exposes ipcRenderer to preload script', function (done) { + it('exposes ipcRenderer to preload script', (done) => { ipcMain.once('answer', function (event, test) { assert.equal(test, 'preload') done() @@ -1072,7 +990,7 @@ describe('BrowserWindow module', function () { w.loadURL('file://' + path.join(fixtures, 'api', 'preload.html')) }) - it('exposes "exit" event to preload script', function (done) { + it('exposes "exit" event to preload script', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1094,7 +1012,7 @@ describe('BrowserWindow module', function () { }) }) - it('should open windows in same domain with cross-scripting enabled', function (done) { + it('should open windows in same domain with cross-scripting enabled', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1123,7 +1041,7 @@ describe('BrowserWindow module', function () { }) }) - it('should open windows in another domain with cross-scripting disabled', function (done) { + it('should open windows in another domain with cross-scripting disabled', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1162,7 +1080,7 @@ describe('BrowserWindow module', function () { }) }) - it('should inherit the sandbox setting in opened windows', function (done) { + it('should inherit the sandbox setting in opened windows', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1180,7 +1098,7 @@ describe('BrowserWindow module', function () { w.loadURL(`file://${path.join(fixtures, 'api', 'new-window.html')}`) }) - it('should open windows with the options configured via new-window event listeners', function (done) { + it('should open windows with the options configured via new-window event listeners', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1199,7 +1117,7 @@ describe('BrowserWindow module', function () { w.loadURL(`file://${path.join(fixtures, 'api', 'new-window.html')}`) }) - it('should set ipc event sender correctly', function (done) { + it('should set ipc event sender correctly', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1230,15 +1148,15 @@ describe('BrowserWindow module', function () { }) }) - describe('event handling', function () { - it('works for window events', function (done) { + describe('event handling', () => { + it('works for window events', (done) => { waitForEvents(w, [ 'page-title-updated' ], done) w.loadURL('file://' + path.join(fixtures, 'api', 'sandbox.html?window-events')) }) - it('works for stop events', function (done) { + it('works for stop events', (done) => { waitForEvents(w.webContents, [ 'did-navigate', 'did-fail-load', @@ -1247,7 +1165,7 @@ describe('BrowserWindow module', function () { w.loadURL('file://' + path.join(fixtures, 'api', 'sandbox.html?webcontents-stop')) }) - it('works for web contents events', function (done) { + it('works for web contents events', (done) => { waitForEvents(w.webContents, [ 'did-finish-load', 'did-frame-finish-load', @@ -1262,7 +1180,7 @@ describe('BrowserWindow module', function () { }) }) - it('can get printer list', function (done) { + it('can get printer list', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1272,14 +1190,14 @@ describe('BrowserWindow module', function () { } }) w.loadURL('data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E') - w.webContents.once('did-finish-load', function () { + w.webContents.once('did-finish-load', () => { const printers = w.webContents.getPrinters() assert.equal(Array.isArray(printers), true) done() }) }) - it('can print to PDF', function (done) { + it('can print to PDF', (done) => { w.destroy() w = new BrowserWindow({ show: false, @@ -1289,7 +1207,7 @@ describe('BrowserWindow module', function () { } }) w.loadURL('data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E') - w.webContents.once('did-finish-load', function () { + w.webContents.once('did-finish-load', () => { w.webContents.printToPDF({}, function (error, data) { assert.equal(error, null) assert.equal(data instanceof Buffer, true) @@ -1426,33 +1344,29 @@ describe('BrowserWindow module', function () { assert.equal(content, 'Hello') done() }) - w.loadURL('file://' + path.join(fixtures, 'api', 'native-window-open-blank.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'native-window-open-blank.html')}`) }) - it('opens window of same domain with cross-scripting enabled', (done) => { ipcMain.once('answer', (event, content) => { assert.equal(content, 'Hello') done() }) - w.loadURL('file://' + path.join(fixtures, 'api', 'native-window-open-file.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'native-window-open-file.html')}`) }) - it('blocks accessing cross-origin frames', (done) => { ipcMain.once('answer', (event, content) => { assert.equal(content, 'Blocked a frame with origin "file://" from accessing a cross-origin frame.') done() }) - w.loadURL('file://' + path.join(fixtures, 'api', 'native-window-open-cross-origin.html')) + w.loadURL(`file://${path.join(fixtures, 'api', 'native-window-open-cross-origin.html')}`) }) - it('opens window from