diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index af54202e14..ceb314251d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,17 +4,27 @@ # https://git-scm.com/docs/gitignore # Most stuff in here is owned by the Community & Safety WG... -/.github/* @electron/wg-community +/.github/* @electron/wg-community # ...except the Admin WG maintains this file. -/.github/CODEOWNERS @electron/wg-admin +/.github/CODEOWNERS @electron/wg-admin # Upgrades WG -/patches/ @electron/wg-upgrades +/patches/ @electron/wg-upgrades # Docs & Tooling WG /default_app/ @electron/wg-docs-tools -/docs/ @electron/wg-docs-tools +/docs/ @electron/wg-docs-tools # Releases WG -/npm/ @electron/wg-releases +/npm/ @electron/wg-releases +/script/release-notes @electron/wg-releases +/script/prepare-release.js @electron/wg-releases +/script/bump-version.js @electron/wg-releases +/script/ci-release-build.js @electron/wg-releases +/script/release.js @electron/wg-releases +/script/upload-to-github.js @electron/wg-releases +/script/release-artifact-cleanup.js @electron/wg-releases +/script/get-last-major-for-master.js @electron/wg-releases +/script/find-release.js @electron/wg-releases +/script/download-circleci-artifacts.js @electron/wg-releases \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/Bug_report.md b/.github/ISSUE_TEMPLATE/Bug_report.md index 1b4d835470..296f4bd143 100644 --- a/.github/ISSUE_TEMPLATE/Bug_report.md +++ b/.github/ISSUE_TEMPLATE/Bug_report.md @@ -20,7 +20,7 @@ about: Create a report to help us improve Electron * * **Operating System:** * -* **Last Known Working Electron version:**: +* **Last Known Working Electron version:** * ### Expected Behavior diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 09f7823505..edb63e6b06 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -6.0.0-nightly.20190404 \ No newline at end of file +7.0.0-nightly.20190521 \ No newline at end of file diff --git a/atom/app/atom_main_delegate.cc b/atom/app/atom_main_delegate.cc index 316e1dedcf..03b7efded3 100644 --- a/atom/app/atom_main_delegate.cc +++ b/atom/app/atom_main_delegate.cc @@ -142,7 +142,10 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) { #if defined(DEBUG) // Print logging to debug.log on Windows settings.logging_dest = logging::LOG_TO_ALL; - settings.log_file = L"debug.log"; + base::FilePath log_filename; + base::PathService::Get(base::DIR_EXE, &log_filename); + log_filename = log_filename.AppendASCII("debug.log"); + settings.log_file = log_filename.value().c_str(); settings.lock_log = logging::LOCK_LOG_FILE; settings.delete_old = logging::DELETE_OLD_LOG_FILE; #else diff --git a/atom/browser/api/atom_api_app.cc b/atom/browser/api/atom_api_app.cc index 9bd0858a2b..3dba8915fd 100644 --- a/atom/browser/api/atom_api_app.cc +++ b/atom/browser/api/atom_api_app.cc @@ -773,6 +773,10 @@ void App::SelectClientCertificate( } } +void App::OnGpuInfoUpdate() { + Emit("gpu-info-update"); +} + void App::OnGpuProcessCrashed(base::TerminationStatus status) { Emit("gpu-process-crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED); diff --git a/atom/browser/api/atom_api_app.h b/atom/browser/api/atom_api_app.h index 0d147f9455..f08b8b427a 100644 --- a/atom/browser/api/atom_api_app.h +++ b/atom/browser/api/atom_api_app.h @@ -157,6 +157,7 @@ class App : public AtomBrowserClient::Delegate, bool* no_javascript_access) override; // content::GpuDataManagerObserver: + void OnGpuInfoUpdate() override; void OnGpuProcessCrashed(base::TerminationStatus status) override; // content::BrowserChildProcessObserver: diff --git a/atom/browser/api/atom_api_browser_view.cc b/atom/browser/api/atom_api_browser_view.cc index 4dfdb15da7..a67b7fc89d 100644 --- a/atom/browser/api/atom_api_browser_view.cc +++ b/atom/browser/api/atom_api_browser_view.cc @@ -68,7 +68,7 @@ void BrowserView::Init(v8::Isolate* isolate, const mate::Dictionary& options) { mate::Dictionary web_preferences = mate::Dictionary::CreateEmpty(isolate); options.Get(options::kWebPreferences, &web_preferences); - web_preferences.Set("isBrowserView", true); + web_preferences.Set("type", "browserView"); mate::Handle web_contents = WebContents::Create(isolate, web_preferences); diff --git a/atom/browser/api/atom_api_web_contents.cc b/atom/browser/api/atom_api_web_contents.cc index 896c928c38..a9792e50f8 100644 --- a/atom/browser/api/atom_api_web_contents.cc +++ b/atom/browser/api/atom_api_web_contents.cc @@ -297,20 +297,12 @@ WebContents::WebContents(v8::Isolate* isolate, // Read options. options.Get("backgroundThrottling", &background_throttling_); - // FIXME(zcbenz): We should read "type" parameter for better design, but - // on Windows we have encountered a compiler bug that if we read "type" - // from |options| and then set |type_|, a memory corruption will happen - // and Electron will soon crash. - // Remvoe this after we upgraded to use VS 2015 Update 3. + // Get type + options.Get("type", &type_); + bool b = false; - if (options.Get("isGuest", &b) && b) - type_ = Type::WEB_VIEW; - else if (options.Get("isBackgroundPage", &b) && b) - type_ = Type::BACKGROUND_PAGE; - else if (options.Get("isBrowserView", &b) && b) - type_ = Type::BROWSER_VIEW; #if BUILDFLAG(ENABLE_OSR) - else if (options.Get(options::kOffscreen, &b) && b) + if (options.Get(options::kOffscreen, &b) && b) type_ = Type::OFF_SCREEN; #endif @@ -2266,7 +2258,6 @@ void WebContents::BuildPrototype(v8::Isolate* isolate, .SetMethod("beginFrameSubscription", &WebContents::BeginFrameSubscription) .SetMethod("endFrameSubscription", &WebContents::EndFrameSubscription) .SetMethod("startDrag", &WebContents::StartDrag) - .SetMethod("isGuest", &WebContents::IsGuest) .SetMethod("attachToIframe", &WebContents::AttachToIframe) .SetMethod("detachFromOuterFrame", &WebContents::DetachFromOuterFrame) .SetMethod("isOffscreen", &WebContents::IsOffScreen) diff --git a/atom/browser/atom_paths.h b/atom/browser/atom_paths.h index c51af1447f..01e03056a9 100644 --- a/atom/browser/atom_paths.h +++ b/atom/browser/atom_paths.h @@ -28,19 +28,23 @@ enum { #if defined(OS_LINUX) DIR_APP_DATA, // Application Data directory under the user profile. -#else +#endif + + PATH_END, // End of new paths. Those that follow redirect to base::DIR_* + +#if !defined(OS_LINUX) DIR_APP_DATA = base::DIR_APP_DATA, #endif #if defined(OS_POSIX) - DIR_CACHE = base::DIR_CACHE, // Directory where to put cache data. + DIR_CACHE = base::DIR_CACHE // Directory where to put cache data. #else - DIR_CACHE = base::DIR_APP_DATA, + DIR_CACHE = base::DIR_APP_DATA #endif - - PATH_END }; +static_assert(PATH_START < PATH_END, "invalid PATH boundaries"); + } // namespace atom #endif // ATOM_BROWSER_ATOM_PATHS_H_ diff --git a/atom/browser/native_window_views.cc b/atom/browser/native_window_views.cc index 305583c94d..f9369ad588 100644 --- a/atom/browser/native_window_views.cc +++ b/atom/browser/native_window_views.cc @@ -5,7 +5,6 @@ #include "atom/browser/native_window_views.h" #if defined(OS_WIN) -#include #include #endif @@ -62,7 +61,6 @@ #include "atom/browser/ui/win/atom_desktop_window_tree_host_win.h" #include "skia/ext/skia_utils_win.h" #include "ui/base/win/shell.h" -#include "ui/display/display.h" #include "ui/display/screen.h" #include "ui/display/win/screen_win.h" #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h" @@ -473,24 +471,15 @@ void NativeWindowViews::SetEnabledInternal(bool enable) { #endif } +#if defined(USE_X11) void NativeWindowViews::Maximize() { -#if defined(OS_WIN) - // For window without WS_THICKFRAME style, we can not call Maximize(). - if (!(::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME)) { - restore_bounds_ = GetBounds(); - auto display = - display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition()); - SetBounds(display.work_area(), false); - return; - } -#endif - if (IsVisible()) widget()->Maximize(); else widget()->native_widget_private()->Show(ui::SHOW_STATE_MAXIMIZED, gfx::Rect()); } +#endif void NativeWindowViews::Unmaximize() { #if defined(OS_WIN) diff --git a/atom/browser/native_window_views_win.cc b/atom/browser/native_window_views_win.cc index cd46d8f186..d6fd2ae581 100644 --- a/atom/browser/native_window_views_win.cc +++ b/atom/browser/native_window_views_win.cc @@ -2,14 +2,19 @@ // Use of this source code is governed by the MIT license that can be // found in the LICENSE file. +#include +#include + #include "atom/browser/browser.h" #include "atom/browser/native_window_views.h" #include "atom/browser/ui/views/root_view.h" #include "atom/common/atom_constants.h" #include "content/public/browser/browser_accessibility_state.h" #include "ui/base/win/accessibility_misc_utils.h" +#include "ui/display/display.h" #include "ui/display/win/screen_win.h" #include "ui/gfx/geometry/insets.h" +#include "ui/views/widget/native_widget_private.h" // Must be included after other Windows headers. #include @@ -138,11 +143,155 @@ bool IsScreenReaderActive() { return screenReader && UiaClientsAreListening(); } +// We use "enum" instead of "enum class" because we need to do bitwise compare. +enum AppbarAutohideEdge { + TOP = 1 << 0, + LEFT = 1 << 1, + BOTTOM = 1 << 2, + RIGHT = 1 << 3, +}; + +// The thickness of an auto-hide taskbar in pixel. +constexpr int kAutoHideTaskbarThicknessPx = 2; + +// Code is copied from chrome_views_delegate_win.cc. +bool MonitorHasAutohideTaskbarForEdge(UINT edge, HMONITOR monitor) { + APPBARDATA taskbar_data = {sizeof(APPBARDATA), NULL, 0, edge}; + taskbar_data.hWnd = ::GetForegroundWindow(); + + // MSDN documents an ABM_GETAUTOHIDEBAREX, which supposedly takes a monitor + // rect and returns autohide bars on that monitor. This sounds like a good + // idea for multi-monitor systems. Unfortunately, it appears to not work at + // least some of the time (erroneously returning NULL) and there's almost no + // online documentation or other sample code using it that suggests ways to + // address this problem. We do the following:- + // 1. Use the ABM_GETAUTOHIDEBAR message. If it works, i.e. returns a valid + // window we are done. + // 2. If the ABM_GETAUTOHIDEBAR message does not work we query the auto hide + // state of the taskbar and then retrieve its position. That call returns + // the edge on which the taskbar is present. If it matches the edge we + // are looking for, we are done. + // NOTE: This call spins a nested run loop. + HWND taskbar = reinterpret_cast( + SHAppBarMessage(ABM_GETAUTOHIDEBAR, &taskbar_data)); + if (!::IsWindow(taskbar)) { + APPBARDATA taskbar_data = {sizeof(APPBARDATA), 0, 0, 0}; + unsigned int taskbar_state = SHAppBarMessage(ABM_GETSTATE, &taskbar_data); + if (!(taskbar_state & ABS_AUTOHIDE)) + return false; + + taskbar_data.hWnd = ::FindWindow(L"Shell_TrayWnd", NULL); + if (!::IsWindow(taskbar_data.hWnd)) + return false; + + SHAppBarMessage(ABM_GETTASKBARPOS, &taskbar_data); + if (taskbar_data.uEdge == edge) + taskbar = taskbar_data.hWnd; + } + + // There is a potential race condition here: + // 1. A maximized chrome window is fullscreened. + // 2. It is switched back to maximized. + // 3. In the process the window gets a WM_NCCACLSIZE message which calls us to + // get the autohide state. + // 4. The worker thread is invoked. It calls the API to get the autohide + // state. On Windows versions earlier than Windows 7, taskbars could + // easily be always on top or not. + // This meant that we only want to look for taskbars which have the topmost + // bit set. However this causes problems in cases where the window on the + // main thread is still in the process of switching away from fullscreen. + // In this case the taskbar might not yet have the topmost bit set. + // 5. The main thread resumes and does not leave space for the taskbar and + // hence it does not pop when hovered. + // + // To address point 4 above, it is best to not check for the WS_EX_TOPMOST + // window style on the taskbar, as starting from Windows 7, the topmost + // style is always set. We don't support XP and Vista anymore. + if (::IsWindow(taskbar)) { + if (MonitorFromWindow(taskbar, MONITOR_DEFAULTTONEAREST) == monitor) + return true; + // In some cases like when the autohide taskbar is on the left of the + // secondary monitor, the MonitorFromWindow call above fails to return the + // correct monitor the taskbar is on. We fallback to MonitorFromPoint for + // the cursor position in that case, which seems to work well. + POINT cursor_pos = {0}; + GetCursorPos(&cursor_pos); + if (MonitorFromPoint(cursor_pos, MONITOR_DEFAULTTONEAREST) == monitor) + return true; + } + return false; +} + +int GetAppbarAutohideEdges(HWND hwnd) { + HMONITOR monitor = MonitorFromWindow(hwnd, MONITOR_DEFAULTTONULL); + if (!monitor) + return 0; + + int edges = 0; + if (MonitorHasAutohideTaskbarForEdge(ABE_LEFT, monitor)) + edges |= AppbarAutohideEdge::LEFT; + if (MonitorHasAutohideTaskbarForEdge(ABE_TOP, monitor)) + edges |= AppbarAutohideEdge::TOP; + if (MonitorHasAutohideTaskbarForEdge(ABE_RIGHT, monitor)) + edges |= AppbarAutohideEdge::RIGHT; + if (MonitorHasAutohideTaskbarForEdge(ABE_BOTTOM, monitor)) + edges |= AppbarAutohideEdge::BOTTOM; + return edges; +} + } // namespace std::set NativeWindowViews::forwarding_windows_; HHOOK NativeWindowViews::mouse_hook_ = NULL; +void NativeWindowViews::Maximize() { + int autohide_edges = 0; + if (!has_frame()) + autohide_edges = GetAppbarAutohideEdges(GetAcceleratedWidget()); + + // Only use Maximize() when: + // 1. window has WS_THICKFRAME style; + // 2. and window is not frameless when there is autohide taskbar. + if ((::GetWindowLong(GetAcceleratedWidget(), GWL_STYLE) & WS_THICKFRAME) && + (has_frame() || autohide_edges == 0)) { + if (IsVisible()) + widget()->Maximize(); + else + widget()->native_widget_private()->Show(ui::SHOW_STATE_MAXIMIZED, + gfx::Rect()); + return; + } + + gfx::Insets insets; + if (!has_frame()) { + // When taskbar is autohide, we need to leave some space so the window + // isn't treated as a "fullscreen app", which would cause the taskbars + // to disappear. + // + // This trick comes from hwnd_message_handler.cc. While Chromium already + // does this for normal window, somehow it is not applying the trick when + // using frameless window, and we have to do it ourselves. + float scale_factor = + display::win::ScreenWin::GetScaleFactorForHWND(GetAcceleratedWidget()); + int thickness = std::ceil(kAutoHideTaskbarThicknessPx / scale_factor); + if (autohide_edges & AppbarAutohideEdge::LEFT) + insets.set_left(-thickness); + if (autohide_edges & AppbarAutohideEdge::TOP) + insets.set_top(-thickness); + if (autohide_edges & AppbarAutohideEdge::RIGHT) + insets.set_right(thickness); + if (autohide_edges & AppbarAutohideEdge::BOTTOM) + insets.set_bottom(thickness); + } + + restore_bounds_ = GetBounds(); + auto display = + display::Screen::GetScreen()->GetDisplayNearestPoint(GetPosition()); + gfx::Rect bounds = display.work_area(); + bounds.Inset(insets); + SetBounds(bounds, false); +} + bool NativeWindowViews::ExecuteWindowsCommand(int command_id) { std::string command = AppCommandToString(command_id); NotifyWindowExecuteAppCommand(command); diff --git a/atom/browser/resources/mac/Info.plist b/atom/browser/resources/mac/Info.plist index 5c211bee8d..0b68c5e231 100644 --- a/atom/browser/resources/mac/Info.plist +++ b/atom/browser/resources/mac/Info.plist @@ -17,9 +17,9 @@ CFBundleIconFile electron.icns CFBundleVersion - 6.0.0-nightly.20190404 + 7.0.0-nightly.20190521 CFBundleShortVersionString - 6.0.0-nightly.20190404 + 7.0.0-nightly.20190521 LSApplicationCategoryType public.app-category.developer-tools LSMinimumSystemVersion diff --git a/atom/browser/resources/win/atom.rc b/atom/browser/resources/win/atom.rc index 1539922e13..c5c12cac59 100644 --- a/atom/browser/resources/win/atom.rc +++ b/atom/browser/resources/win/atom.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 6,0,0,20190404 - PRODUCTVERSION 6,0,0,20190404 + FILEVERSION 7,0,0,20190521 + PRODUCTVERSION 7,0,0,20190521 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -68,12 +68,12 @@ BEGIN BEGIN VALUE "CompanyName", "GitHub, Inc." VALUE "FileDescription", "Electron" - VALUE "FileVersion", "6.0.0" + VALUE "FileVersion", "7.0.0" VALUE "InternalName", "electron.exe" VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved." VALUE "OriginalFilename", "electron.exe" VALUE "ProductName", "Electron" - VALUE "ProductVersion", "6.0.0" + VALUE "ProductVersion", "7.0.0" VALUE "SquirrelAwareVersion", "1" END END diff --git a/atom/browser/ui/file_dialog_win.cc b/atom/browser/ui/file_dialog_win.cc index 71f5187546..b6bf533eec 100644 --- a/atom/browser/ui/file_dialog_win.cc +++ b/atom/browser/ui/file_dialog_win.cc @@ -117,7 +117,7 @@ void RunSaveDialogInNewThread(const RunState& run_state, bool result = ShowSaveDialogSync(settings, &path); run_state.ui_task_runner->PostTask( FROM_HERE, - base::BindOnce(&OnSaveDialogDone, std::move(promise), result, path)); + base::BindOnce(&OnSaveDialogDone, std::move(promise), !result, path)); run_state.ui_task_runner->DeleteSoon(FROM_HERE, run_state.dialog_thread); } @@ -321,7 +321,7 @@ void ShowSaveDialog(const DialogSettings& settings, RunState run_state; if (!CreateDialogThread(&run_state)) { mate::Dictionary dict = mate::Dictionary::CreateEmpty(promise.isolate()); - dict.Set("canceled", false); + dict.Set("canceled", true); dict.Set("filePath", base::FilePath()); promise.Resolve(dict.GetHandle()); } else { diff --git a/atom/browser/web_contents_preferences.cc b/atom/browser/web_contents_preferences.cc index b4399263d9..b55273d92b 100644 --- a/atom/browser/web_contents_preferences.cc +++ b/atom/browser/web_contents_preferences.cc @@ -108,8 +108,8 @@ WebContentsPreferences::WebContentsPreferences( mate::Dictionary copied(isolate, web_preferences.GetHandle()->Clone()); // Following fields should not be stored. copied.Delete("embedder"); - copied.Delete("isGuest"); copied.Delete("session"); + copied.Delete("type"); mate::ConvertFromV8(isolate, copied.GetHandle(), &preference_); web_contents->SetUserData(UserDataKey(), base::WrapUnique(this)); diff --git a/atom/browser/web_dialog_helper.cc b/atom/browser/web_dialog_helper.cc index f583cf4881..c5af15b8d4 100644 --- a/atom/browser/web_dialog_helper.cc +++ b/atom/browser/web_dialog_helper.cc @@ -35,7 +35,8 @@ using blink::mojom::FileChooserParams; namespace { class FileSelectHelper : public base::RefCounted, - public content::WebContentsObserver { + public content::WebContentsObserver, + public atom::DirectoryListerHelperDelegate { public: FileSelectHelper(content::RenderFrameHost* render_frame_host, std::unique_ptr listener, @@ -71,23 +72,61 @@ class FileSelectHelper : public base::RefCounted, isolate, base::Bind(&FileSelectHelper::OnSaveDialogDone, this))))); } + void OnDirectoryListerDone(std::vector file_info, + base::FilePath base_dir) override { + OnFilesSelected(std::move(file_info), base_dir); + Release(); + } + private: friend class base::RefCounted; ~FileSelectHelper() override {} + void EnumerateDirectory(base::FilePath base_dir) { + auto* lister = new net::DirectoryLister( + base_dir, net::DirectoryLister::NO_SORT_RECURSIVE, + new atom::DirectoryListerHelper(base_dir, this)); + lister->Start(); + // It is difficult for callers to know how long to keep a reference to + // this instance. We AddRef() here to keep the instance alive after we + // return to the caller. Once the directory lister is complete we + // Release() in OnDirectoryListerDone() and at that point we run + // OnFilesSelected() which will deref the last reference held by the + // listener. + AddRef(); + } + void OnOpenDialogDone(mate::Dictionary result) { std::vector file_info; bool canceled = true; result.Get("canceled", &canceled); + base::FilePath base_dir; + // For certain file chooser modes (kUploadFolder) we need to do some async + // work before calling back to the listener. In that particular case the + // listener is called from the directory enumerator. + bool ready_to_call_listener = false; if (!canceled) { std::vector paths; if (result.Get("filePaths", &paths)) { - for (auto& path : paths) { - file_info.push_back(FileChooserFileInfo::NewNativeFile( - blink::mojom::NativeFileInfo::New( - path, path.BaseName().AsUTF16Unsafe()))); + // If we are uploading a folder we need to enumerate its contents + if (mode_ == FileChooserParams::Mode::kUploadFolder && + paths.size() >= 1) { + base_dir = paths[0]; + + // Actually enumerate soemwhere off-thread + base::SequencedTaskRunnerHandle::Get()->PostTask( + FROM_HERE, base::BindOnce(&FileSelectHelper::EnumerateDirectory, + this, base_dir)); + } else { + for (auto& path : paths) { + file_info.push_back(FileChooserFileInfo::NewNativeFile( + blink::mojom::NativeFileInfo::New( + path, path.BaseName().AsUTF16Unsafe()))); + } + + ready_to_call_listener = true; } if (render_frame_host_ && !paths.empty()) { @@ -98,7 +137,9 @@ class FileSelectHelper : public base::RefCounted, } } } - OnFilesSelected(std::move(file_info)); + + if (ready_to_call_listener) + OnFilesSelected(std::move(file_info), base_dir); } void OnSaveDialogDone(mate::Dictionary result) { @@ -114,12 +155,13 @@ class FileSelectHelper : public base::RefCounted, path, path.BaseName().AsUTF16Unsafe()))); } } - OnFilesSelected(std::move(file_info)); + OnFilesSelected(std::move(file_info), base::FilePath()); } - void OnFilesSelected(std::vector file_info) { + void OnFilesSelected(std::vector file_info, + base::FilePath base_dir) { if (listener_) { - listener_->FileSelected(std::move(file_info), base::FilePath(), mode_); + listener_->FileSelected(std::move(file_info), base_dir, mode_); listener_.reset(); } render_frame_host_ = nullptr; @@ -216,6 +258,30 @@ file_dialog::Filters GetFileTypesFromAcceptType( namespace atom { +DirectoryListerHelper::DirectoryListerHelper( + base::FilePath base, + DirectoryListerHelperDelegate* helper) + : base_dir_(base), delegate_(helper) {} +DirectoryListerHelper::~DirectoryListerHelper() {} + +void DirectoryListerHelper::OnListFile( + const net::DirectoryLister::DirectoryListerData& data) { + // We don't want to return directory paths, only file paths + if (data.info.IsDirectory()) + return; + + paths_.push_back(data.path); +} +void DirectoryListerHelper::OnListDone(int error) { + std::vector file_info; + for (auto path : paths_) + file_info.push_back(FileChooserFileInfo::NewNativeFile( + blink::mojom::NativeFileInfo::New(path, base::string16()))); + + delegate_->OnDirectoryListerDone(std::move(file_info), base_dir_); + delete this; +} + WebDialogHelper::WebDialogHelper(NativeWindow* window, bool offscreen) : window_(window), offscreen_(offscreen), weak_factory_(this) {} diff --git a/atom/browser/web_dialog_helper.h b/atom/browser/web_dialog_helper.h index 3574552d4a..ccb7ab8ffa 100644 --- a/atom/browser/web_dialog_helper.h +++ b/atom/browser/web_dialog_helper.h @@ -6,8 +6,10 @@ #define ATOM_BROWSER_WEB_DIALOG_HELPER_H_ #include +#include #include "base/memory/weak_ptr.h" +#include "net/base/directory_lister.h" #include "third_party/blink/public/mojom/choosers/file_chooser.mojom.h" namespace base { @@ -22,6 +24,32 @@ class WebContents; namespace atom { +class DirectoryListerHelperDelegate { + public: + virtual void OnDirectoryListerDone( + std::vector file_info, + base::FilePath base_dir) = 0; +}; + +class DirectoryListerHelper + : public net::DirectoryLister::DirectoryListerDelegate { + public: + DirectoryListerHelper(base::FilePath base, + DirectoryListerHelperDelegate* helper); + ~DirectoryListerHelper() override; + + private: + void OnListFile( + const net::DirectoryLister::DirectoryListerData& data) override; + void OnListDone(int error) override; + + base::FilePath base_dir_; + DirectoryListerHelperDelegate* delegate_; + std::vector paths_; + + DISALLOW_COPY_AND_ASSIGN(DirectoryListerHelper); +}; + class NativeWindow; class WebDialogHelper { diff --git a/atom/common/atom_version.h b/atom/common/atom_version.h index 15aa74cc3f..650400bc8f 100644 --- a/atom/common/atom_version.h +++ b/atom/common/atom_version.h @@ -5,11 +5,11 @@ #ifndef ATOM_COMMON_ATOM_VERSION_H_ #define ATOM_COMMON_ATOM_VERSION_H_ -#define ATOM_MAJOR_VERSION 6 +#define ATOM_MAJOR_VERSION 7 #define ATOM_MINOR_VERSION 0 #define ATOM_PATCH_VERSION 0 // clang-format off -#define ATOM_PRE_RELEASE_VERSION -nightly.20190404 +#define ATOM_PRE_RELEASE_VERSION -nightly.20190521 // clang-format on #ifndef ATOM_STRINGIFY diff --git a/docs/api/app.md b/docs/api/app.md index 4e8332efa9..976b6b1eb8 100644 --- a/docs/api/app.md +++ b/docs/api/app.md @@ -343,6 +343,10 @@ app.on('login', (event, webContents, request, authInfo, callback) => { }) ``` +### Event: 'gpu-info-update' + +Emitted whenever there is a GPU info update. + ### Event: 'gpu-process-crashed' Returns: @@ -400,8 +404,10 @@ Returns: * `workingDirectory` String - The second instance's working directory This event will be emitted inside the primary instance of your application -when a second instance has been executed. `argv` is an Array of the second instance's -command line arguments, and `workingDirectory` is its current working directory. Usually +when a second instance has been executed and calls `app.requestSingleInstanceLock()`. + +`argv` is an Array of the second instance's command line arguments, +and `workingDirectory` is its current working directory. Usually applications respond to this by making their primary window focused and non-minimized. @@ -684,7 +690,7 @@ To set the locale, you'll want to use a command line switch at app startup, whic ### `app.getLocaleCountryCode()` -Returns `string` - User operating system's locale two-letter [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) country code. The value is taken from native OS APIs. +Returns `String` - User operating system's locale two-letter [ISO 3166](https://www.iso.org/iso-3166-country-codes.html) country code. The value is taken from native OS APIs. **Note:** When unable to detect locale country code, it returns empty string. @@ -1012,6 +1018,8 @@ Returns [`ProcessMetric[]`](structures/process-metric.md): Array of `ProcessMetr Returns [`GPUFeatureStatus`](structures/gpu-feature-status.md) - The Graphics Feature Status from `chrome://gpu/`. +**Note:** This information is only usable after the `gpu-info-update` event is emitted. + ### `app.getGPUInfo(infoType)` * `infoType` String - Values can be either `basic` for basic info or `complete` for complete info. diff --git a/docs/api/breaking-changes.md b/docs/api/breaking-changes.md index 87997b73e7..7875a1fecf 100644 --- a/docs/api/breaking-changes.md +++ b/docs/api/breaking-changes.md @@ -1,4 +1,4 @@ -# API Contract +# Breaking Changes Breaking changes will be documented here, and deprecation warnings added to JS code where possible, at least [one major version](../tutorial/electron-versioning.md#semver) before the change is made. @@ -8,6 +8,16 @@ The `FIXME` string is used in code comments to denote things that should be fixe ## Planned Breaking API Changes (7.0) +### Node Headers URL + +This is the URL specified as `disturl` in a `.npmrc` file or as the `--dist-url` +command line flag when building native Node modules. Both will be supported for +the forseeable future but it is reccomened that you switch. + +Deprecated: https://atom.io/download/electron + +Replace with: https://electronjs.org/headers + ### `session.clearAuthCache(options)` The `session.clearAuthCache` API no longer accepts options for what to clear, and instead unconditionally clears the whole cache. diff --git a/docs/api/browser-window.md b/docs/api/browser-window.md index 8bbc39fea9..44c8e7307c 100644 --- a/docs/api/browser-window.md +++ b/docs/api/browser-window.md @@ -592,7 +592,7 @@ win.on('app-command', (e, cmd) => { }) ``` -The following app commands are explictly supported on Linux: +The following app commands are explicitly supported on Linux: * `browser-backward` * `browser-forward` diff --git a/docs/api/menu.md b/docs/api/menu.md index ae864eef83..421ace48b4 100644 --- a/docs/api/menu.md +++ b/docs/api/menu.md @@ -10,7 +10,7 @@ Creates a new menu. ### Static Methods -The `menu` class has the following static methods: +The `Menu` class has the following static methods: #### `Menu.setApplicationMenu(menu)` diff --git a/docs/api/native-image.md b/docs/api/native-image.md index 704631d0df..f6c4569d3f 100644 --- a/docs/api/native-image.md +++ b/docs/api/native-image.md @@ -177,7 +177,7 @@ Creates a new `NativeImage` instance from `dataURL`. 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) +given image name. See [`System Icons`](https://developer.apple.com/design/human-interface-guidelines/macos/icons-and-images/system-icons/) for a list of possible values. The `hslShift` is applied to the image with the following rules diff --git a/docs/api/sandbox-option.md b/docs/api/sandbox-option.md index 7d24bee28a..e293d3416d 100644 --- a/docs/api/sandbox-option.md +++ b/docs/api/sandbox-option.md @@ -113,8 +113,8 @@ window.open = customWindowOpen Important things to notice in the preload script: - Even though the sandboxed renderer doesn't have Node.js running, it still has - access to a limited node-like environment: `Buffer`, `process`, `setImmediate` - and `require` are available. + access to a limited node-like environment: `Buffer`, `process`, `setImmediate`, + `clearImmediate` and `require` are available. - The preload script can indirectly access all APIs from the main process through the `remote` and `ipcRenderer` modules. - The preload script must be contained in a single script, but it is possible to have @@ -162,16 +162,17 @@ feature. We are still not aware of the security implications of exposing some Electron renderer APIs to the preload script, but here are some things to consider before rendering untrusted content: -- A preload script can accidentally leak privileged APIs to untrusted code. +- A preload script can accidentally leak privileged APIs to untrusted code, + unless [`contextIsolation`](../tutorial/security.md#3-enable-context-isolation-for-remote-content) + is also enabled. - Some bug in V8 engine may allow malicious code to access the renderer preload APIs, effectively granting full access to the system through the `remote` - module. + module. Therefore, it is highly recommended to + [disable the `remote` module](../tutorial/security.md#15-disable-the-remote-module). + If disabling is not feasible, you should selectively + [filter the `remote` module](../tutorial/security.md#16-filter-the-remote-module). Since rendering untrusted content in Electron is still uncharted territory, the APIs exposed to the sandbox preload script should be considered more unstable than the rest of Electron APIs, and may have breaking changes to fix security issues. - -One planned enhancement that should greatly increase security is to block IPC -messages from sandboxed renderers by default, allowing the main process to -explicitly define a set of messages the renderer is allowed to send. diff --git a/docs/api/session.md b/docs/api/session.md index 9887ec1d3b..d104696867 100644 --- a/docs/api/session.md +++ b/docs/api/session.md @@ -203,7 +203,7 @@ The `proxyBypassRules` is a comma separated list of rules described below: * `url` URL -Returns `Promise` - Resolves with the proxy information for `url`. +Returns `Promise` - Resolves with the proxy information for `url`. #### `ses.setDownloadPath(path)` diff --git a/docs/tutorial/using-native-node-modules.md b/docs/tutorial/using-native-node-modules.md index 9bb57be44e..58e855ffe6 100644 --- a/docs/tutorial/using-native-node-modules.md +++ b/docs/tutorial/using-native-node-modules.md @@ -55,7 +55,7 @@ export npm_config_target=1.2.3 export npm_config_arch=x64 export npm_config_target_arch=x64 # Download headers for Electron. -export npm_config_disturl=https://atom.io/download/electron +export npm_config_disturl=https://electronjs.org/headers # Tell node-pre-gyp that we are building for Electron. export npm_config_runtime=electron # Tell node-pre-gyp to build module from source code. @@ -72,7 +72,7 @@ use `node-gyp` directly to build for Electron: ```sh cd /path-to-module/ -HOME=~/.electron-gyp node-gyp rebuild --target=1.2.3 --arch=x64 --dist-url=https://atom.io/download/electron +HOME=~/.electron-gyp node-gyp rebuild --target=1.2.3 --arch=x64 --dist-url=https://electronjs.org/headers ``` * `HOME=~/.electron-gyp` changes where to find development headers. diff --git a/filenames.gni b/filenames.gni index 9702deb9c8..3a4f7e27a9 100644 --- a/filenames.gni +++ b/filenames.gni @@ -49,7 +49,6 @@ filenames = { "lib/browser/utils.ts", "lib/common/api/clipboard.js", "lib/common/api/deprecate.ts", - "lib/common/api/deprecations.js", "lib/common/api/is-promise.js", "lib/common/api/exports/electron.js", "lib/common/api/module-list.js", diff --git a/lib/browser/api/dialog.js b/lib/browser/api/dialog.js index 43d93040b2..24c29c5684 100644 --- a/lib/browser/api/dialog.js +++ b/lib/browser/api/dialog.js @@ -47,7 +47,11 @@ const checkAppInitialized = function () { const saveDialog = (sync, window, options) => { checkAppInitialized() - if (window && window.constructor !== BrowserWindow) options = window + if (window && window.constructor !== BrowserWindow) { + options = window + window = null + } + if (options == null) options = { title: 'Save' } const { @@ -74,7 +78,11 @@ const saveDialog = (sync, window, options) => { const openDialog = (sync, window, options) => { checkAppInitialized() - if (window && window.constructor !== BrowserWindow) options = window + if (window && window.constructor !== BrowserWindow) { + options = window + window = null + } + if (options == null) { options = { title: 'Open', @@ -115,7 +123,11 @@ const openDialog = (sync, window, options) => { const messageBox = (sync, window, options) => { checkAppInitialized() - if (window && window.constructor !== BrowserWindow) options = window + if (window && window.constructor !== BrowserWindow) { + options = window + window = null + } + if (options == null) options = { type: 'none' } const messageBoxTypes = ['none', 'info', 'warning', 'error', 'question'] diff --git a/lib/browser/api/web-contents.js b/lib/browser/api/web-contents.js index 3eeb718f3b..0e515961ce 100644 --- a/lib/browser/api/web-contents.js +++ b/lib/browser/api/web-contents.js @@ -354,9 +354,6 @@ WebContents.prototype._init = function () { app.emit('renderer-process-crashed', event, this, ...args) }) - deprecate.event(this, 'did-get-response-details', '-did-get-response-details') - deprecate.event(this, 'did-get-redirect-request', '-did-get-redirect-request') - // The devtools requests the webContents to reload. this.on('devtools-reload-page', function () { this.reload() diff --git a/lib/browser/chrome-extension.js b/lib/browser/chrome-extension.js index 966d67834a..39df4ec657 100644 --- a/lib/browser/chrome-extension.js +++ b/lib/browser/chrome-extension.js @@ -93,7 +93,7 @@ const startBackgroundPages = function (manifest) { const contents = webContents.create({ partition: 'persist:__chrome_extension', - isBackgroundPage: true, + type: 'backgroundPage', sandbox: true, enableRemoteModule: false }) diff --git a/lib/browser/guest-view-manager.js b/lib/browser/guest-view-manager.js index 01673497cc..8cef1602da 100644 --- a/lib/browser/guest-view-manager.js +++ b/lib/browser/guest-view-manager.js @@ -59,7 +59,7 @@ const createGuest = function (embedder, params) { } const guest = webContents.create({ - isGuest: true, + type: 'webview', partition: params.partition, embedder: embedder }) diff --git a/lib/browser/guest-window-manager.js b/lib/browser/guest-window-manager.js index ee4b185594..2593227ef2 100644 --- a/lib/browser/guest-window-manager.js +++ b/lib/browser/guest-window-manager.js @@ -28,7 +28,7 @@ const mergeOptions = function (child, parent, visited) { visited.add(parent) for (const key in parent) { - if (key === 'isBrowserView') continue + if (key === 'type') continue if (!hasProp.call(parent, key)) continue if (key in child && key !== 'webPreferences') continue @@ -244,7 +244,7 @@ ipcMainInternal.on('ELECTRON_GUEST_WINDOW_MANAGER_INTERNAL_WINDOW_OPEN', functio options = mergeBrowserWindowOptions(event.sender, options) event.sender.emit('new-window', event, url, frameName, disposition, options, additionalFeatures, referrer) const { newGuest } = event - if ((event.sender.isGuest() && !event.sender.allowPopups) || event.defaultPrevented) { + if ((event.sender.getType() === 'webview' && !event.sender.allowPopups) || event.defaultPrevented) { if (newGuest != null) { if (options.webContents === newGuest.webContents) { // the webContents is not changed, so set defaultPrevented to false to diff --git a/lib/common/api/deprecations.js b/lib/common/api/deprecations.js deleted file mode 100644 index f4c4d74d6b..0000000000 --- a/lib/common/api/deprecations.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict' - -const deprecate = require('electron').deprecate - -exports.setHandler = function (deprecationHandler) { - deprecate.setHandler(deprecationHandler) -} - -exports.getHandler = function () { - return deprecate.getHandler() -} diff --git a/lib/common/api/module-list.js b/lib/common/api/module-list.js index 3741f17fb6..f5fc756fc9 100644 --- a/lib/common/api/module-list.js +++ b/lib/common/api/module-list.js @@ -7,6 +7,5 @@ module.exports = [ { name: 'shell', file: 'shell' }, // The internal modules, invisible unless you know their names. { name: 'deprecate', file: 'deprecate', private: true }, - { name: 'deprecations', file: 'deprecations', private: true }, { name: 'isPromise', file: 'is-promise', private: true } ] diff --git a/lib/renderer/window-setup.ts b/lib/renderer/window-setup.ts index c219d0f737..5080a818f8 100644 --- a/lib/renderer/window-setup.ts +++ b/lib/renderer/window-setup.ts @@ -81,9 +81,7 @@ class LocationProxy { // It's right, that's bad, but we're doing it anway. (guestURL as any)[propertyKey] = newVal - return this.ipcRenderer.sendSync( - 'ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', - this.guestId, 'loadURL', guestURL.toString()) + return this._invokeWebContentsMethodSync('loadURL', guestURL.toString()) } } }) @@ -102,7 +100,7 @@ class LocationProxy { } private getGuestURL (): URL | null { - const urlString = ipcRendererInternal.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'getURL') + const urlString = this._invokeWebContentsMethodSync('getURL') as string try { return new URL(urlString) } catch (e) { @@ -111,6 +109,10 @@ class LocationProxy { return null } + + private _invokeWebContentsMethodSync (method: string, ...args: any[]) { + return ipcRendererInternal.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, method, ...args) + } } class BrowserWindowProxy { @@ -127,7 +129,7 @@ class BrowserWindowProxy { } public set location (url: string | any) { url = resolveURL(url) - ipcRendererInternal.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, 'loadURL', url) + this._invokeWebContentsMethodSync('loadURL', url) } constructor (guestId: number) { @@ -145,23 +147,35 @@ class BrowserWindowProxy { } public focus () { - ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'focus') + this._invokeWindowMethod('focus') } public blur () { - ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, 'blur') + this._invokeWindowMethod('blur') } public print () { - ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'print') + this._invokeWebContentsMethod('print') } public postMessage (message: any, targetOrigin: any) { ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_POSTMESSAGE', this.guestId, message, toString(targetOrigin), window.location.origin) } - public eval (...args: any[]) { - ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, 'executeJavaScript', ...args) + public eval (code: string) { + this._invokeWebContentsMethod('executeJavaScript', code) + } + + private _invokeWindowMethod (method: string, ...args: any[]) { + return ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_METHOD', this.guestId, method, ...args) + } + + private _invokeWebContentsMethod (method: string, ...args: any[]) { + return ipcRendererInternal.send('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD', this.guestId, method, ...args) + } + + private _invokeWebContentsMethodSync (method: string, ...args: any[]) { + return ipcRendererInternal.sendSync('ELECTRON_GUEST_WINDOW_MANAGER_WEB_CONTENTS_METHOD_SYNC', this.guestId, method, ...args) } } diff --git a/native_mate/README.md b/native_mate/README.md index e5d056bfed..655e8f7f12 100644 --- a/native_mate/README.md +++ b/native_mate/README.md @@ -53,4 +53,4 @@ void Initialize(v8::Handle exports) { [chromium-gin-lib]: https://code.google.com/p/chromium/codesearch#chromium/src/gin/README.md&sq=package:chromium -[electron]: http://electron.atom.io/ +[electron]: https://electronjs.org/ diff --git a/package.json b/package.json index c78f630106..8f401f753d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "6.0.0-nightly.20190404", + "version": "7.0.0-nightly.20190521", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { @@ -47,7 +47,6 @@ "remark-preset-lint-markdown-style-guide": "^2.1.1", "request": "^2.88.0", "semver": "^5.6.0", - "serve": "^6.5.8", "shx": "^0.3.2", "standard-markdown": "^5.0.0", "sumchecker": "^2.0.2", @@ -133,4 +132,4 @@ "git add filenames.auto.gni" ] } -} +} \ No newline at end of file diff --git a/script/upload-node-checksums.py b/script/upload-node-checksums.py index 4d301ce2b9..bc701a3c7b 100755 --- a/script/upload-node-checksums.py +++ b/script/upload-node-checksums.py @@ -10,7 +10,7 @@ import tempfile from lib.config import s3_config from lib.util import download, rm_rf, s3put, safe_mkdir -DIST_URL = 'https://atom.io/download/electron/' +DIST_URL = 'https://electronjs.org/headers/' def main(): diff --git a/spec/api-browser-view-spec.js b/spec/api-browser-view-spec.js index fbbb4ebe01..1d59342969 100644 --- a/spec/api-browser-view-spec.js +++ b/spec/api-browser-view-spec.js @@ -1,6 +1,5 @@ 'use strict' -const assert = require('assert') const chai = require('chai') const ChildProcess = require('child_process') const dirtyChai = require('dirty-chai') @@ -169,7 +168,7 @@ describe('BrowserView module', () => { expect(view1.id).to.be.not.null() const views = w.getBrowserViews() - expect(views.length).to.equal(2) + expect(views).to.have.lengthOf(2) expect(views[0].webContents.id).to.equal(view1.webContents.id) expect(views[1].webContents.id).to.equal(view2.webContents.id) @@ -243,9 +242,9 @@ describe('BrowserView module', () => { w.setBrowserView(view) view.webContents.once('new-window', (e, url, frameName, disposition, options, additionalFeatures) => { e.preventDefault() - assert.strictEqual(url, 'http://host/') - assert.strictEqual(frameName, 'host') - assert.strictEqual(additionalFeatures[0], 'this-is-not-a-standard-feature') + expect(url).to.equal('http://host/') + expect(frameName).to.equal('host') + expect(additionalFeatures[0]).to.equal('this-is-not-a-standard-feature') done() }) view.webContents.loadFile(path.join(fixtures, 'pages', 'window-open.html')) diff --git a/spec/api-browser-window-spec.js b/spec/api-browser-window-spec.js index b2bc71d6b4..ff4fc79edf 100644 --- a/spec/api-browser-window-spec.js +++ b/spec/api-browser-window-spec.js @@ -1,6 +1,5 @@ 'use strict' -const assert = require('assert') const chai = require('chai') const dirtyChai = require('dirty-chai') const fs = require('fs') @@ -164,7 +163,7 @@ describe('BrowserWindow module', () => { const test = path.join(fixtures, 'api', 'unload') const content = fs.readFileSync(test) fs.unlinkSync(test) - assert.strictEqual(String(content), 'unload') + expect(String(content)).to.equal('unload') done() }) w.loadFile(path.join(fixtures, 'api', 'unload.html')) @@ -211,7 +210,7 @@ describe('BrowserWindow module', () => { const test = path.join(fixtures, 'api', 'close') const content = fs.readFileSync(test) fs.unlinkSync(test) - assert.strictEqual(String(content), 'close') + expect(String(content)).to.equal('close') done() }) w.loadFile(path.join(fixtures, 'api', 'close.html')) @@ -226,9 +225,9 @@ describe('BrowserWindow module', () => { it('prevents users to access methods of webContents', () => { const contents = w.webContents w.destroy() - assert.throws(() => { + expect(() => { contents.getProcessId() - }, /Object has been destroyed/) + }).to.throw('Object has been destroyed') }) it('should not crash when destroying windows with pending events', (done) => { const responseEvent = 'destroy-test-completed' @@ -248,25 +247,25 @@ describe('BrowserWindow module', () => { }) 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.strictEqual(code, -6) - assert.strictEqual(desc, 'ERR_FILE_NOT_FOUND') - assert.strictEqual(isMainFrame, true) + expect(code).to.equal(-6) + expect(desc).to.equal('ERR_FILE_NOT_FOUND') + expect(isMainFrame).to.be.true() done() }) w.loadURL('file://a.txt') }) it('should emit did-fail-load event for invalid URL', (done) => { w.webContents.on('did-fail-load', (event, code, desc, url, isMainFrame) => { - assert.strictEqual(desc, 'ERR_INVALID_URL') - assert.strictEqual(code, -300) - assert.strictEqual(isMainFrame, true) + expect(desc).to.equal('ERR_INVALID_URL') + expect(code).to.equal(-300) + expect(isMainFrame).to.be.true() done() }) w.loadURL('http://example:port') }) 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.strictEqual(isMainFrame, false) + expect(isMainFrame).to.be.false() done() }) w.loadFile(path.join(fixtures, 'api', 'did-fail-load-iframe.html')) @@ -280,9 +279,9 @@ describe('BrowserWindow module', () => { }) 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.strictEqual(desc, 'ERR_INVALID_URL') - assert.strictEqual(code, -300) - assert.strictEqual(isMainFrame, true) + expect(desc).to.equal('ERR_INVALID_URL') + expect(code).to.equal(-300) + expect(isMainFrame).to.be.true() done() }) const data = Buffer.alloc(2 * 1024 * 1024).toString('base64') @@ -331,7 +330,7 @@ describe('BrowserWindow module', () => { form.submit() `) const details = await requestDetails - assert.strictEqual(details.requestHeaders['content-type'], 'application/x-www-form-urlencoded') + expect(details.requestHeaders['content-type']).to.equal('application/x-www-form-urlencoded') }) it('sets the content type header on multi part forms', async () => { await w.loadURL(server.url) @@ -353,13 +352,13 @@ describe('BrowserWindow module', () => { form.submit() `) const details = await requestDetails - assert(details.requestHeaders['content-type'].startsWith('multipart/form-data; boundary=----WebKitFormBoundary')) + expect(details.requestHeaders['content-type'].startsWith('multipart/form-data; boundary=----WebKitFormBoundary')).to.be.true() }) }) it('should support support base url for data urls', (done) => { ipcMain.once('answer', (event, test) => { - assert.strictEqual(test, 'test') + expect(test).to.equal('test') done() }) w.loadURL('data:text/html,', { baseURLForDataURL: `file://${path.join(fixtures, 'api')}${path.sep}` }) @@ -440,15 +439,15 @@ describe('BrowserWindow module', () => { it('should focus on window', () => { w.show() - assert(w.isFocused()) + expect(w.isFocused()).to.be.true() }) it('should make the window visible', () => { w.show() - assert(w.isVisible()) + expect(w.isVisible()).to.be.true() }) it('emits when window is shown', (done) => { w.once('show', () => { - assert.strictEqual(w.isVisible(), true) + expect(w.isVisible()).to.be.true() done() }) w.show() @@ -464,17 +463,17 @@ describe('BrowserWindow module', () => { it('should defocus on window', () => { w.hide() - assert(!w.isFocused()) + expect(w.isFocused()).to.be.false() }) it('should make the window not visible', () => { w.show() w.hide() - assert(!w.isVisible()) + expect(w.isVisible()).to.be.false() }) it('emits when window is hidden', (done) => { w.show() w.once('hide', () => { - assert.strictEqual(w.isVisible(), false) + expect(w.isVisible()).to.be.false() done() }) w.hide() @@ -484,22 +483,22 @@ describe('BrowserWindow module', () => { describe('BrowserWindow.showInactive()', () => { it('should not focus on window', () => { w.showInactive() - assert(!w.isFocused()) + expect(w.isFocused()).to.be.false() }) }) describe('BrowserWindow.focus()', () => { it('does not make the window become visible', () => { - assert.strictEqual(w.isVisible(), false) + expect(w.isVisible()).to.be.false() w.focus() - assert.strictEqual(w.isVisible(), false) + expect(w.isVisible()).to.be.false() }) }) describe('BrowserWindow.blur()', () => { it('removes focus from window', () => { w.blur() - assert(!w.isFocused()) + expect(w.isFocused()).to.be.false() }) }) @@ -507,7 +506,7 @@ describe('BrowserWindow module', () => { it('returns the opener window when dev tools window is focused', (done) => { w.show() w.webContents.once('devtools-focused', () => { - assert.deepStrictEqual(BrowserWindow.getFocusedWindow(), w) + expect(BrowserWindow.getFocusedWindow()).to.equal(w) done() }) w.webContents.openDevTools({ mode: 'undocked' }) @@ -520,38 +519,38 @@ describe('BrowserWindow module', () => { const wShownInactive = emittedOnce(w, 'show') w.showInactive() await wShownInactive - assert(!w.isFocused()) + expect(w.isFocused()).to.be.false() const otherWindow = new BrowserWindow({ show: false, title: 'otherWindow' }) const otherWindowShown = emittedOnce(otherWindow, 'show') otherWindow.loadURL('data:text/html,') otherWindow.show() await otherWindowShown - assert(otherWindow.isFocused()) + expect(otherWindow.isFocused()).to.be.true() w.moveTop() const wPos = w.getPosition() const wMoving = emittedOnce(w, 'move') w.setPosition(wPos[0] + posDelta, wPos[1] + posDelta) await wMoving - assert(!w.isFocused()) - assert(otherWindow.isFocused()) + expect(w.isFocused()).to.be.false() + expect(otherWindow.isFocused()).to.be.true() const wFocused = emittedOnce(w, 'focus') w.focus() await wFocused - assert(w.isFocused()) + expect(w.isFocused()).to.be.true() otherWindow.moveTop() const otherWindowPos = otherWindow.getPosition() const otherWindowMoving = emittedOnce(otherWindow, 'move') otherWindow.setPosition(otherWindowPos[0] + posDelta, otherWindowPos[1] + posDelta) await otherWindowMoving - assert(!otherWindow.isFocused()) - assert(w.isFocused()) + expect(otherWindow.isFocused()).to.be.false() + expect(w.isFocused()).to.be.true() await closeWindow(otherWindow, { assertSingleWindow: false }).then(() => { - assert.strictEqual(BrowserWindow.getAllWindows().length, 2) // Test window + w + expect(BrowserWindow.getAllWindows()).to.have.lengthOf(2) // Test window + w }) }) }) @@ -594,7 +593,7 @@ describe('BrowserWindow module', () => { const fullBounds = { x: 440, y: 225, width: 500, height: 400 } w.setBounds(fullBounds) - assertBoundsEqual(w.getBounds(), fullBounds) + expectBoundsEqual(w.getBounds(), fullBounds) }) it('sets the window bounds with partial bounds', () => { @@ -605,7 +604,7 @@ describe('BrowserWindow module', () => { w.setBounds(boundsUpdate) const expectedBounds = Object.assign(fullBounds, boundsUpdate) - assertBoundsEqual(w.getBounds(), expectedBounds) + expectBoundsEqual(w.getBounds(), expectedBounds) }) }) @@ -617,22 +616,22 @@ describe('BrowserWindow module', () => { w.setSize(size[0], size[1]) await resized - assertBoundsEqual(w.getSize(), size) + expectBoundsEqual(w.getSize(), size) }) }) describe('BrowserWindow.setMinimum/MaximumSize(width, height)', () => { it('sets the maximum and minimum size of the window', () => { - assert.deepStrictEqual(w.getMinimumSize(), [0, 0]) - assert.deepStrictEqual(w.getMaximumSize(), [0, 0]) + expect(w.getMinimumSize()).to.deep.equal([0, 0]) + expect(w.getMaximumSize()).to.deep.equal([0, 0]) w.setMinimumSize(100, 100) - assertBoundsEqual(w.getMinimumSize(), [100, 100]) - assertBoundsEqual(w.getMaximumSize(), [0, 0]) + expectBoundsEqual(w.getMinimumSize(), [100, 100]) + expectBoundsEqual(w.getMaximumSize(), [0, 0]) w.setMaximumSize(900, 600) - assertBoundsEqual(w.getMinimumSize(), [100, 100]) - assertBoundsEqual(w.getMaximumSize(), [900, 600]) + expectBoundsEqual(w.getMinimumSize(), [100, 100]) + expectBoundsEqual(w.getMaximumSize(), [900, 600]) }) }) @@ -642,7 +641,7 @@ describe('BrowserWindow module', () => { w.setAspectRatio(1 / 2) w.setAspectRatio(0) w.once('resize', () => { - assertBoundsEqual(w.getSize(), size) + expectBoundsEqual(w.getSize(), size) done() }) w.setSize(size[0], size[1]) @@ -654,8 +653,7 @@ describe('BrowserWindow module', () => { const pos = [10, 10] w.once('move', () => { const newPos = w.getPosition() - assert.strictEqual(newPos[0], pos[0]) - assert.strictEqual(newPos[1], pos[1]) + expect(newPos).to.deep.equal(pos) done() }) w.setPosition(pos[0], pos[1]) @@ -667,8 +665,7 @@ describe('BrowserWindow module', () => { const size = [400, 400] w.setContentSize(size[0], size[1]) const after = w.getContentSize() - assert.strictEqual(after[0], size[0]) - assert.strictEqual(after[1], size[1]) + expect(after).to.deep.equal(size) }) it('works for a frameless window', () => { w.destroy() @@ -681,8 +678,7 @@ describe('BrowserWindow module', () => { const size = [400, 400] w.setContentSize(size[0], size[1]) const after = w.getContentSize() - assert.strictEqual(after[0], size[0]) - assert.strictEqual(after[1], size[1]) + expect(after).to.deep.equal(size) }) }) @@ -690,7 +686,7 @@ describe('BrowserWindow module', () => { 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) + expectBoundsEqual(w.getContentBounds(), bounds) done() }) w.setContentBounds(bounds) @@ -705,7 +701,7 @@ describe('BrowserWindow module', () => { }) const bounds = { x: 10, y: 10, width: 250, height: 250 } w.once('resize', () => { - assert.deepStrictEqual(w.getContentBounds(), bounds) + expect(w.getContentBounds()).to.deep.equal(bounds) done() }) w.setContentBounds(bounds) @@ -717,7 +713,7 @@ describe('BrowserWindow module', () => { it(`checks normal bounds after resize`, (done) => { const size = [300, 400] w.once('resize', () => { - assertBoundsEqual(w.getNormalBounds(), w.getBounds()) + expectBoundsEqual(w.getNormalBounds(), w.getBounds()) done() }) w.setSize(size[0], size[1]) @@ -725,7 +721,7 @@ describe('BrowserWindow module', () => { it(`checks normal bounds after move`, (done) => { const pos = [10, 10] w.once('move', () => { - assertBoundsEqual(w.getNormalBounds(), w.getBounds()) + expectBoundsEqual(w.getNormalBounds(), w.getBounds()) done() }) w.setPosition(pos[0], pos[1]) @@ -740,7 +736,7 @@ describe('BrowserWindow module', () => { it(`checks normal bounds when maximized`, (done) => { const bounds = w.getBounds() w.once('maximize', () => { - assertBoundsEqual(w.getNormalBounds(), bounds) + expectBoundsEqual(w.getNormalBounds(), bounds) done() }) w.show() @@ -752,7 +748,7 @@ describe('BrowserWindow module', () => { w.unmaximize() }) w.once('unmaximize', () => { - assertBoundsEqual(w.getNormalBounds(), bounds) + expectBoundsEqual(w.getNormalBounds(), bounds) done() }) w.show() @@ -768,7 +764,7 @@ describe('BrowserWindow module', () => { it(`checks normal bounds when minimized`, (done) => { const bounds = w.getBounds() w.once('minimize', () => { - assertBoundsEqual(w.getNormalBounds(), bounds) + expectBoundsEqual(w.getNormalBounds(), bounds) done() }) w.show() @@ -780,7 +776,7 @@ describe('BrowserWindow module', () => { w.restore() }) w.once('restore', () => { - assertBoundsEqual(w.getNormalBounds(), bounds) + expectBoundsEqual(w.getNormalBounds(), bounds) done() }) w.show() @@ -799,7 +795,7 @@ describe('BrowserWindow module', () => { it(`checks normal bounds when fullscreen'ed`, (done) => { const bounds = w.getBounds() w.once('enter-full-screen', () => { - assertBoundsEqual(w.getNormalBounds(), bounds) + expectBoundsEqual(w.getNormalBounds(), bounds) done() }) w.show() @@ -811,7 +807,7 @@ describe('BrowserWindow module', () => { w.setFullScreen(false) }) w.once('leave-full-screen', () => { - assertBoundsEqual(w.getNormalBounds(), bounds) + expectBoundsEqual(w.getNormalBounds(), bounds) done() }) w.show() @@ -822,7 +818,7 @@ describe('BrowserWindow module', () => { describe('BrowserWindow.setProgressBar(progress)', () => { it('sets the progress', () => { - assert.doesNotThrow(() => { + expect(() => { if (process.platform === 'darwin') { app.dock.setIcon(path.join(fixtures, 'assets', 'logo.png')) } @@ -832,34 +828,34 @@ describe('BrowserWindow module', () => { app.dock.setIcon(null) } w.setProgressBar(-1) - }) + }).to.not.throw() }) it('sets the progress using "paused" mode', () => { - assert.doesNotThrow(() => { + expect(() => { w.setProgressBar(0.5, { mode: 'paused' }) - }) + }).to.not.throw() }) it('sets the progress using "error" mode', () => { - assert.doesNotThrow(() => { + expect(() => { w.setProgressBar(0.5, { mode: 'error' }) - }) + }).to.not.throw() }) it('sets the progress using "normal" mode', () => { - assert.doesNotThrow(() => { + expect(() => { w.setProgressBar(0.5, { mode: 'normal' }) - }) + }).to.not.throw() }) }) describe('BrowserWindow.setAlwaysOnTop(flag, level)', () => { it('sets the window as always on top', () => { - assert.strictEqual(w.isAlwaysOnTop(), false) + expect(w.isAlwaysOnTop()).to.be.false() w.setAlwaysOnTop(true, 'screen-saver') - assert.strictEqual(w.isAlwaysOnTop(), true) + expect(w.isAlwaysOnTop()).to.be.true() w.setAlwaysOnTop(false) - assert.strictEqual(w.isAlwaysOnTop(), false) + expect(w.isAlwaysOnTop()).to.be.false() w.setAlwaysOnTop(true) - assert.strictEqual(w.isAlwaysOnTop(), true) + expect(w.isAlwaysOnTop()).to.be.true() }) it('raises an error when relativeLevel is out of bounds', function () { if (process.platform !== 'darwin') { @@ -871,13 +867,13 @@ describe('BrowserWindow module', () => { return } - assert.throws(() => { + expect(() => { w.setAlwaysOnTop(true, '', -2147483644) - }) + }).to.throw() - assert.throws(() => { + expect(() => { w.setAlwaysOnTop(true, '', 2147483632) - }) + }).to.throw() }) }) @@ -889,13 +885,13 @@ describe('BrowserWindow module', () => { }) it('resets the windows level on minimize', () => { - assert.strictEqual(w.isAlwaysOnTop(), false) + expect(w.isAlwaysOnTop()).to.be.false() w.setAlwaysOnTop(true, 'screen-saver') - assert.strictEqual(w.isAlwaysOnTop(), true) + expect(w.isAlwaysOnTop()).to.be.true() w.minimize() - assert.strictEqual(w.isAlwaysOnTop(), false) + expect(w.isAlwaysOnTop()).to.be.false() w.restore() - assert.strictEqual(w.isAlwaysOnTop(), true) + expect(w.isAlwaysOnTop()).to.be.true() }) }) @@ -908,10 +904,10 @@ describe('BrowserWindow module', () => { }) it('allows changing cursor auto-hiding', () => { - assert.doesNotThrow(() => { + expect(() => { w.setAutoHideCursor(false) w.setAutoHideCursor(true) - }) + }).to.not.throw() }) }) @@ -923,7 +919,7 @@ describe('BrowserWindow module', () => { }) it('is not available', () => { - assert.ok(!w.setAutoHideCursor) + expect(w.setAutoHideCursor).to.be.undefined() }) }) }) @@ -936,9 +932,9 @@ describe('BrowserWindow module', () => { }) it('does not throw', () => { - assert.doesNotThrow(() => { + expect(() => { w.selectPreviousTab() - }) + }).to.not.throw() }) }) @@ -950,9 +946,9 @@ describe('BrowserWindow module', () => { }) it('does not throw', () => { - assert.doesNotThrow(() => { + expect(() => { w.selectNextTab() - }) + }).to.not.throw() }) }) @@ -964,9 +960,9 @@ describe('BrowserWindow module', () => { }) it('does not throw', () => { - assert.doesNotThrow(() => { + expect(() => { w.mergeAllWindows() - }) + }).to.not.throw() }) }) @@ -978,9 +974,9 @@ describe('BrowserWindow module', () => { }) it('does not throw', () => { - assert.doesNotThrow(() => { + expect(() => { w.moveTabToNewWindow() - }) + }).to.not.throw() }) }) @@ -992,9 +988,9 @@ describe('BrowserWindow module', () => { }) it('does not throw', () => { - assert.doesNotThrow(() => { + expect(() => { w.toggleTabBar() - }) + }).to.not.throw() }) }) @@ -1007,22 +1003,22 @@ describe('BrowserWindow module', () => { it('does not throw', (done) => { const tabbedWindow = new BrowserWindow({}) - assert.doesNotThrow(() => { + expect(() => { w.addTabbedWindow(tabbedWindow) - }) + }).to.not.throw() - assert.strictEqual(BrowserWindow.getAllWindows().length, 3) // Test window + w + tabbedWindow + expect(BrowserWindow.getAllWindows()).to.have.lengthOf(3) // Test window + w + tabbedWindow closeWindow(tabbedWindow, { assertSingleWindow: false }).then(() => { - assert.strictEqual(BrowserWindow.getAllWindows().length, 2) // Test window + w + expect(BrowserWindow.getAllWindows()).to.have.lengthOf(2) // Test window + w done() }) }) it('throws when called on itself', () => { - assert.throws(() => { + expect(() => { w.addTabbedWindow(w) - }, /AddTabbedWindow cannot be called by a window on itself./) + }).to.throw('AddTabbedWindow cannot be called by a window on itself.') }) }) @@ -1034,14 +1030,14 @@ describe('BrowserWindow module', () => { }) it('does not throw', () => { - assert.doesNotThrow(() => { + expect(() => { w.setWindowButtonVisibility(true) w.setWindowButtonVisibility(false) - }) + }).to.not.throw() }) it('throws with custom title bar buttons', () => { - assert.throws(() => { + expect(() => { w.destroy() w = new BrowserWindow({ show: false, @@ -1049,19 +1045,19 @@ describe('BrowserWindow module', () => { frame: false }) w.setWindowButtonVisibility(true) - }, /Not supported for this window/) + }).to.throw('Not supported for this window') }) }) describe('BrowserWindow.setVibrancy(type)', () => { it('allows setting, changing, and removing the vibrancy', () => { - assert.doesNotThrow(() => { + expect(() => { w.setVibrancy('light') w.setVibrancy('dark') w.setVibrancy(null) w.setVibrancy('ultra-dark') w.setVibrancy('') - }) + }).to.not.throw() }) }) @@ -1075,7 +1071,7 @@ describe('BrowserWindow module', () => { it('supports setting the app details', () => { const iconPath = path.join(fixtures, 'assets', 'icon.ico') - assert.doesNotThrow(() => { + expect(() => { w.setAppDetails({ appId: 'my.app.id' }) w.setAppDetails({ appIconPath: iconPath, appIconIndex: 0 }) w.setAppDetails({ appIconPath: iconPath }) @@ -1090,17 +1086,17 @@ describe('BrowserWindow module', () => { relaunchDisplayName: 'My app name' }) w.setAppDetails({}) - }) + }).to.not.throw() - assert.throws(() => { + expect(() => { w.setAppDetails() - }, /Insufficient number of arguments\./) + }).to.throw('Insufficient number of arguments.') }) }) describe('BrowserWindow.fromId(id)', () => { it('returns the window with id', () => { - assert.strictEqual(w.id, BrowserWindow.fromId(w.id).id) + expect(BrowserWindow.fromId(w.id).id).to.equal(w.id) }) }) @@ -1112,8 +1108,8 @@ describe('BrowserWindow module', () => { afterEach(() => { contents.destroy() }) it('returns the window with the webContents', () => { - assert.strictEqual(BrowserWindow.fromWebContents(w.webContents).id, w.id) - assert.strictEqual(BrowserWindow.fromWebContents(contents), undefined) + expect(BrowserWindow.fromWebContents(w.webContents).id).to.equal(w.id) + expect(BrowserWindow.fromWebContents(contents)).to.be.undefined() }) }) @@ -1126,9 +1122,9 @@ describe('BrowserWindow module', () => { it('returns the window with the webContents', (done) => { w.webContents.once('devtools-opened', () => { - assert.strictEqual(BrowserWindow.fromDevToolsWebContents(w.devToolsWebContents).id, w.id) - assert.strictEqual(BrowserWindow.fromDevToolsWebContents(w.webContents), undefined) - assert.strictEqual(BrowserWindow.fromDevToolsWebContents(contents), undefined) + expect(BrowserWindow.fromDevToolsWebContents(w.devToolsWebContents).id).to.equal(w.id) + expect(BrowserWindow.fromDevToolsWebContents(w.webContents)).to.be.undefined() + expect(BrowserWindow.fromDevToolsWebContents(contents)).to.be.undefined() done() }) w.webContents.openDevTools() @@ -1157,12 +1153,12 @@ describe('BrowserWindow module', () => { }) it('returns the window with the browserView', () => { - assert.strictEqual(BrowserWindow.fromBrowserView(bv).id, w.id) + expect(BrowserWindow.fromBrowserView(bv).id).to.equal(w.id) }) it('returns undefined if not attached', () => { w.setBrowserView(null) - assert.strictEqual(BrowserWindow.fromBrowserView(bv), null) + expect(BrowserWindow.fromBrowserView(bv)).to.be.null() }) }) @@ -1175,28 +1171,28 @@ describe('BrowserWindow module', () => { height: 400, opacity: 0.5 }) - assert.strictEqual(w.getOpacity(), 0.5) + expect(w.getOpacity()).to.equal(0.5) }) it('allows setting the opacity', () => { - assert.doesNotThrow(() => { + expect(() => { w.setOpacity(0.0) - assert.strictEqual(w.getOpacity(), 0.0) + expect(w.getOpacity()).to.equal(0.0) w.setOpacity(0.5) - assert.strictEqual(w.getOpacity(), 0.5) + expect(w.getOpacity()).to.equal(0.5) w.setOpacity(1.0) - assert.strictEqual(w.getOpacity(), 1.0) - }) + expect(w.getOpacity()).to.equal(1.0) + }).to.not.throw() }) }) describe('BrowserWindow.setShape(rects)', () => { it('allows setting shape', () => { - assert.doesNotThrow(() => { + expect(() => { w.setShape([]) w.setShape([{ x: 0, y: 0, width: 100, height: 100 }]) w.setShape([{ x: 0, y: 0, width: 100, height: 100 }, { x: 0, y: 200, width: 1000, height: 100 }]) w.setShape([]) - }) + }).to.not.throw() }) }) @@ -1210,13 +1206,11 @@ describe('BrowserWindow module', () => { useContentSize: true }) const contentSize = w.getContentSize() - assert.strictEqual(contentSize[0], 400) - assert.strictEqual(contentSize[1], 400) + expect(contentSize).to.deep.equal([400, 400]) }) it('make window created with window size when not used', () => { const size = w.getSize() - assert.strictEqual(size[0], 400) - assert.strictEqual(size[1], 400) + expect(size).to.deep.equal([400, 400]) }) it('works for a frameless window', () => { w.destroy() @@ -1228,11 +1222,9 @@ describe('BrowserWindow module', () => { useContentSize: true }) const contentSize = w.getContentSize() - assert.strictEqual(contentSize[0], 400) - assert.strictEqual(contentSize[1], 400) + expect(contentSize).to.deep.equal([400, 400]) const size = w.getSize() - assert.strictEqual(size[0], 400) - assert.strictEqual(size[1], 400) + expect(size).to.deep.equal([400, 400]) }) }) @@ -1256,7 +1248,7 @@ describe('BrowserWindow module', () => { titleBarStyle: 'hidden' }) const contentSize = w.getContentSize() - assert.strictEqual(contentSize[1], 400) + expect(contentSize).to.deep.equal([400, 400]) }) it('creates browser window with hidden inset title bar', () => { w.destroy() @@ -1267,7 +1259,7 @@ describe('BrowserWindow module', () => { titleBarStyle: 'hiddenInset' }) const contentSize = w.getContentSize() - assert.strictEqual(contentSize[1], 400) + expect(contentSize).to.deep.equal([400, 400]) }) }) @@ -1291,15 +1283,14 @@ describe('BrowserWindow module', () => { it('can move the window out of screen', () => { w.setPosition(-10, -10) const after = w.getPosition() - assert.strictEqual(after[0], -10) - assert.strictEqual(after[1], -10) + expect(after).to.deep.equal([-10, -10]) }) 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) - assertBoundsEqual(w.getSize(), [size.width, size.height]) + expectBoundsEqual(w.getSize(), [size.width, size.height]) }) }) @@ -1319,7 +1310,7 @@ describe('BrowserWindow module', () => { zoomToPageWidth: true }) w.maximize() - assert.strictEqual(w.getSize()[0], 500) + expect(w.getSize()[0]).to.equal(500) }) }) @@ -1439,7 +1430,7 @@ describe('BrowserWindow module', () => { const defaultSession = session.defaultSession beforeEach(() => { - assert.deepStrictEqual(defaultSession.getPreloads(), []) + expect(defaultSession.getPreloads()).to.deep.equal([]) defaultSession.setPreloads(preloads) }) afterEach(() => { @@ -1447,15 +1438,15 @@ describe('BrowserWindow module', () => { }) it('can set multiple session preload script', function () { - assert.deepStrictEqual(defaultSession.getPreloads(), preloads) + expect(defaultSession.getPreloads()).to.deep.equal(preloads) }) const generateSpecs = (description, sandbox) => { describe(description, () => { it('loads the script before other scripts in window including normal preloads', function (done) { ipcMain.once('vars', function (event, preload1, preload2) { - assert.strictEqual(preload1, 'preload-1') - assert.strictEqual(preload2, 'preload-1-2') + expect(preload1).to.equal('preload-1') + expect(preload2).to.equal('preload-1-2') done() }) w.destroy() @@ -1479,7 +1470,7 @@ describe('BrowserWindow module', () => { it('adds extra args to process.argv in the renderer process', (done) => { const preload = path.join(fixtures, 'module', 'check-arguments.js') ipcMain.once('answer', (event, argv) => { - assert.ok(argv.includes('--my-magic-arg')) + expect(argv).to.include('--my-magic-arg') done() }) w.destroy() @@ -1497,7 +1488,7 @@ describe('BrowserWindow module', () => { it('adds extra value args to process.argv in the renderer process', (done) => { const preload = path.join(fixtures, 'module', 'check-arguments.js') ipcMain.once('answer', (event, argv) => { - assert.ok(argv.includes('--my-magic-arg=foo')) + expect(argv).to.include('--my-magic-arg=foo') done() }) w.destroy() @@ -1517,8 +1508,8 @@ describe('BrowserWindow module', () => { it('disables node integration by default', (done) => { const preload = path.join(fixtures, 'module', 'send-later.js') ipcMain.once('answer', (event, typeofProcess, typeofBuffer) => { - assert.strictEqual(typeofProcess, 'undefined') - assert.strictEqual(typeofBuffer, 'undefined') + expect(typeofProcess).to.equal('undefined') + expect(typeofBuffer).to.equal('undefined') done() }) w.destroy() @@ -1586,7 +1577,7 @@ describe('BrowserWindow module', () => { it('exposes ipcRenderer to preload script', (done) => { ipcMain.once('answer', function (event, test) { - assert.strictEqual(test, 'preload') + expect(test).to.equal('preload') done() }) w.destroy() @@ -1603,7 +1594,7 @@ describe('BrowserWindow module', () => { it('exposes ipcRenderer to preload script (path has special chars)', function (done) { const preloadSpecialChars = path.join(fixtures, 'module', 'preload-sandboxæø åü.js') ipcMain.once('answer', function (event, test) { - assert.strictEqual(test, 'preload') + expect(test).to.equal('preload') done() }) w.destroy() @@ -1646,7 +1637,7 @@ describe('BrowserWindow module', () => { if (process.platform === 'win32') { expectedUrl = 'file:///' + htmlPath.replace(/\\/g, '/') } - assert.strictEqual(url, expectedUrl) + expect(url).to.equal(expectedUrl) done() }) w.loadURL(pageUrl) @@ -1669,12 +1660,12 @@ describe('BrowserWindow module', () => { if (process.platform === 'win32') { expectedUrl = 'file:///' + htmlPath.replace(/\\/g, '/') } - assert.strictEqual(url, expectedUrl) - assert.strictEqual(frameName, 'popup!') - assert.strictEqual(options.width, 500) - assert.strictEqual(options.height, 600) + expect(url).to.equal(expectedUrl) + expect(frameName).to.equal('popup!') + expect(options.width).to.equal(500) + expect(options.height).to.equal(600) ipcMain.once('answer', function (event, html) { - assert.strictEqual(html, '

scripting from opener

') + expect(html).to.equal('

scripting from opener

') done() }) }) @@ -1752,7 +1743,7 @@ describe('BrowserWindow module', () => { const preloadPath = path.join(fixtures, 'api', 'new-window-preload.js') ipcRenderer.send('set-web-preferences-on-next-new-window', w.webContents.id, 'preload', preloadPath) ipcMain.once('answer', (event, args) => { - assert.strictEqual(args.includes('--enable-sandbox'), true) + expect(args).to.include('--enable-sandbox') done() }) w.loadFile(path.join(fixtures, 'api', 'new-window.html')) @@ -1771,7 +1762,7 @@ describe('BrowserWindow module', () => { ipcRenderer.send('set-web-preferences-on-next-new-window', w.webContents.id, 'preload', preloadPath) ipcRenderer.send('set-web-preferences-on-next-new-window', w.webContents.id, 'foo', 'bar') ipcMain.once('answer', (event, args, webPreferences) => { - assert.strictEqual(webPreferences.foo, 'bar') + expect(webPreferences.foo).to.equal('bar') done() }) w.loadFile(path.join(fixtures, 'api', 'new-window.html')) @@ -1791,15 +1782,15 @@ describe('BrowserWindow module', () => { let childWc w.webContents.once('new-window', (e, url, frameName, disposition, options) => { childWc = options.webContents - assert.notStrictEqual(w.webContents, childWc) + expect(w.webContents).to.not.equal(childWc) }) ipcMain.once('parent-ready', function (event) { - assert.strictEqual(w.webContents, event.sender) + expect(w.webContents).to.equal(event.sender) event.sender.send('verified') }) ipcMain.once('child-ready', function (event) { - assert(childWc) - assert.strictEqual(childWc, event.sender) + expect(childWc).to.be.an('object') + expect(childWc).to.equal(event.sender) event.sender.send('verified') }) waitForEvents(ipcMain, [ @@ -1855,7 +1846,7 @@ describe('BrowserWindow module', () => { // We need to give it some time so the windows get properly disposed (at least on OSX). setTimeout(() => { const currentWebContents = webContents.getAllWebContents().map((i) => i.id) - assert.deepStrictEqual(currentWebContents, initialWebContents) + expect(currentWebContents).to.deep.equal(initialWebContents) done() }, 100) }) @@ -1891,7 +1882,7 @@ describe('BrowserWindow module', () => { ipcMain.once('answer', (event, arg) => { ipcMain.removeAllListeners('reloaded') ipcMain.removeAllListeners('get-remote-module-path') - assert.strictEqual(arg, 'hi') + expect(arg).to.equal('hi') done() }) }) @@ -1926,7 +1917,7 @@ describe('BrowserWindow module', () => { ipcMain.once('answer', (event, arg) => { ipcMain.removeAllListeners('reloaded') ipcMain.removeAllListeners('get-remote-module-path') - assert.strictEqual(arg, 'hi child window') + expect(arg).to.equal('hi child window') done() }) }) @@ -2008,37 +1999,37 @@ describe('BrowserWindow module', () => { it('opens window of about:blank with cross-scripting enabled', (done) => { ipcMain.once('answer', (event, content) => { - assert.strictEqual(content, 'Hello') + expect(content).to.equal('Hello') done() }) w.loadFile(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.strictEqual(content, 'Hello') + expect(content).to.equal('Hello') done() }) w.loadFile(path.join(fixtures, 'api', 'native-window-open-file.html')) }) it('blocks accessing cross-origin frames', (done) => { ipcMain.once('answer', (event, content) => { - assert.strictEqual(content, 'Blocked a frame with origin "file://" from accessing a cross-origin frame.') + expect(content).to.equal('Blocked a frame with origin "file://" from accessing a cross-origin frame.') done() }) w.loadFile(path.join(fixtures, 'api', 'native-window-open-cross-origin.html')) }) it('opens window from