mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
18 Commits
v17.0.0-ni
...
v17.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2a2a1a834c | ||
|
|
c4d35cd18c | ||
|
|
1e618ef06c | ||
|
|
c40a292099 | ||
|
|
5899a72df9 | ||
|
|
a938af3f54 | ||
|
|
97a109991e | ||
|
|
20b4813cf8 | ||
|
|
a6e5ff3607 | ||
|
|
639f4428a5 | ||
|
|
120cff38c5 | ||
|
|
ec34c6c6e7 | ||
|
|
3bf42593ba | ||
|
|
e88a2955da | ||
|
|
0f0ed5921d | ||
|
|
771a8f70da | ||
|
|
3193d7e99b | ||
|
|
be8b1a2727 |
2
DEPS
2
DEPS
@@ -17,7 +17,7 @@ vars = {
|
||||
'chromium_version':
|
||||
'96.0.4664.4',
|
||||
'node_version':
|
||||
'v16.12.0',
|
||||
'v16.13.0',
|
||||
'nan_version':
|
||||
# The following commit hash of NAN is v2.14.2 with *only* changes to the
|
||||
# test suite. This should be updated to a specific tag when one becomes
|
||||
|
||||
@@ -1 +1 @@
|
||||
17.0.0-nightly.20211026
|
||||
17.0.0-nightly.20211102
|
||||
@@ -15,6 +15,8 @@ static_library("chrome") {
|
||||
sources = [
|
||||
"//chrome/browser/accessibility/accessibility_ui.cc",
|
||||
"//chrome/browser/accessibility/accessibility_ui.h",
|
||||
"//chrome/browser/app_mode/app_mode_utils.cc",
|
||||
"//chrome/browser/app_mode/app_mode_utils.h",
|
||||
"//chrome/browser/browser_process.cc",
|
||||
"//chrome/browser/browser_process.h",
|
||||
"//chrome/browser/devtools/devtools_contents_resizing_strategy.cc",
|
||||
@@ -51,6 +53,20 @@ static_library("chrome") {
|
||||
"//chrome/browser/process_singleton.h",
|
||||
"//chrome/browser/ui/browser_dialogs.cc",
|
||||
"//chrome/browser/ui/browser_dialogs.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_bubble_type.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_controller_base.h",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_manager.cc",
|
||||
"//chrome/browser/ui/exclusive_access/exclusive_access_manager.h",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_controller.h",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.cc",
|
||||
"//chrome/browser/ui/exclusive_access/fullscreen_within_tab_helper.h",
|
||||
"//chrome/browser/ui/exclusive_access/keyboard_lock_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/keyboard_lock_controller.h",
|
||||
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.cc",
|
||||
"//chrome/browser/ui/exclusive_access/mouse_lock_controller.h",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.cc",
|
||||
"//chrome/browser/ui/views/autofill/autofill_popup_view_utils.h",
|
||||
"//chrome/browser/ui/views/eye_dropper/eye_dropper.cc",
|
||||
@@ -114,6 +130,7 @@ static_library("chrome") {
|
||||
"//components/keyed_service/content",
|
||||
"//components/paint_preview/buildflags",
|
||||
"//components/proxy_config",
|
||||
"//components/services/language_detection/public/mojom",
|
||||
"//content/public/browser",
|
||||
"//services/strings",
|
||||
]
|
||||
|
||||
@@ -59,10 +59,9 @@ an issue:
|
||||
* [Testing and Debugging](tutorial/application-debugging.md)
|
||||
* [Debugging the Main Process](tutorial/debugging-main-process.md)
|
||||
* [Debugging with Visual Studio Code](tutorial/debugging-vscode.md)
|
||||
* [Using Selenium and WebDriver](tutorial/using-selenium-and-webdriver.md)
|
||||
* [Testing on Headless CI Systems (Travis, Jenkins)](tutorial/testing-on-headless-ci.md)
|
||||
* [DevTools Extension](tutorial/devtools-extension.md)
|
||||
* [Automated Testing with a Custom Driver](tutorial/automated-testing-with-a-custom-driver.md)
|
||||
* [Automated Testing](tutorial/automated-testing.md)
|
||||
* [REPL](tutorial/repl.md)
|
||||
* [Distribution](tutorial/application-distribution.md)
|
||||
* [Supported Platforms](tutorial/support.md#supported-platforms)
|
||||
|
||||
@@ -36,10 +36,10 @@ Returns:
|
||||
* `launchInfo` Record<string, any> | [NotificationResponse](structures/notification-response.md) _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the `NSUserNotification` or information from
|
||||
[`UNNotificationResponse`](structures/notification-response.md) that was used to open the
|
||||
application, if it was launched from Notification Center. You can also call
|
||||
`app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
holds the `userInfo` of the [`NSUserNotification`](https://developer.apple.com/documentation/foundation/nsusernotification)
|
||||
or information from [`UNNotificationResponse`](https://developer.apple.com/documentation/usernotifications/unnotificationresponse)
|
||||
that was used to open the application, if it was launched from Notification Center.
|
||||
You can also call `app.isReady()` to check if this event has already fired and `app.whenReady()`
|
||||
to get a Promise that is fulfilled when Electron is initialized.
|
||||
|
||||
### Event: 'window-all-closed'
|
||||
|
||||
@@ -197,7 +197,7 @@ Returns `Boolean` - Whether the clipboard supports the specified `format`.
|
||||
```js
|
||||
const { clipboard } = require('electron')
|
||||
|
||||
const hasFormat = clipboard.has('<p>selection</p>')
|
||||
const hasFormat = clipboard.has('public/utf8-plain-text')
|
||||
console.log(hasFormat)
|
||||
// 'true' or 'false'
|
||||
```
|
||||
|
||||
@@ -4,23 +4,77 @@ These guides are intended for people working on the Electron project itself.
|
||||
For guides on Electron app development, see
|
||||
[/docs/README.md](../README.md#guides-and-tutorials).
|
||||
|
||||
* [Code of Conduct](https://github.com/electron/electron/blob/main/CODE_OF_CONDUCT.md)
|
||||
* [Contributing to Electron](https://github.com/electron/electron/blob/main/CONTRIBUTING.md)
|
||||
## Table of Contents
|
||||
|
||||
* [Issues](issues.md)
|
||||
* [Pull Requests](pull-requests.md)
|
||||
* [Documentation Styleguide](coding-style.md#documentation)
|
||||
* [Source Code Directory Structure](source-code-directory-structure.md)
|
||||
* [Coding Style](coding-style.md)
|
||||
* [Using clang-format on C++ Code](clang-format.md)
|
||||
* [Using clang-tidy on C++ Code](clang-tidy.md)
|
||||
* [Build System Overview](build-system-overview.md)
|
||||
* [Build Instructions (macOS)](build-instructions-macos.md)
|
||||
* [Build Instructions (Windows)](build-instructions-windows.md)
|
||||
* [Build Instructions (Linux)](build-instructions-linux.md)
|
||||
* [Build Instructions](build-instructions-gn.md)
|
||||
* [macOS](build-instructions-macos.md)
|
||||
* [Windows](build-instructions-windows.md)
|
||||
* [Linux](build-instructions-linux.md)
|
||||
* [Chromium Development](chromium-development.md)
|
||||
* [V8 Development](v8-development.md)
|
||||
* [Testing](testing.md)
|
||||
* [Debugging on Windows](debug-instructions-windows.md)
|
||||
* [Debugging on macOS](debugging-instructions-macos.md)
|
||||
* [Setting Up Symbol Server in Debugger](setting-up-symbol-server.md)
|
||||
* [Debugging](debugging.md)
|
||||
* [Patches](patches.md)
|
||||
|
||||
## Getting Started
|
||||
|
||||
In order to contribute to Electron, the first thing you'll want to do is get the code.
|
||||
|
||||
[Electron's `build-tools`](https://github.com/electron/build-tools) automate much of the setup for compiling Electron from source with different configurations and build targets.
|
||||
|
||||
If you would prefer to build Electron manually, see the [build instructions](build-instructions-gn.md).
|
||||
|
||||
Once you've checked out and built the code, you may want to take a look around the source tree to get a better idea
|
||||
of what each directory is responsible for. The [source code directory structure](source-code-directory-structure.md) gives a good overview of the purpose of each directory.
|
||||
|
||||
## Opening Issues on Electron
|
||||
|
||||
For any issue, there are generally three ways an individual can contribute:
|
||||
|
||||
1. By opening the issue for discussion
|
||||
* If you believe that you have found a new bug in Electron, you should report it by creating a new issue in
|
||||
the [`electron/electron` issue tracker](https://github.com/electron/electron/issues).
|
||||
2. By helping to triage the issue
|
||||
* You can do this either by providing assistive details (a reproducible test case that demonstrates a bug) or by providing suggestions to address the issue.
|
||||
3. By helping to resolve the issue
|
||||
* This can be done by demonstrating that the issue is not a bug or is fixed;
|
||||
but more often, by opening a pull request that changes the source in `electron/electron`
|
||||
in a concrete and reviewable manner.
|
||||
|
||||
See [issues](issues.md) for more information.
|
||||
|
||||
## Making a Pull Request to Electron
|
||||
|
||||
Most pull requests opened against the `electron/electron` repository include
|
||||
changes to either the C/C++ code in the `shell/` folder,
|
||||
the TypeScript code in the `lib/` folder, the documentation in `docs/`,
|
||||
or tests in the `spec/` and `spec-main/` folders.
|
||||
|
||||
See [pull requests](pull-requests.md) for more information.
|
||||
|
||||
If you want to add a new API module to Electron, you'll want to look in [creating API](creating-api.md).
|
||||
|
||||
## Governance
|
||||
|
||||
Electron has a fully-fledged governance system that oversees activity in Electron and whose working groups are responsible for areas like APIs, releases, and upgrades to Electron's dependencies including Chromium and Node.js. Depending on how frequently and to what end you want to contribute, you may want to consider joining a working group.
|
||||
|
||||
Details about each group and their reponsibilities can be found in the [governance repo](https://github.com/electron/governance).
|
||||
|
||||
## Patches in Electron
|
||||
|
||||
Electron is built on two major upstream projects: Chromium and Node.js. Each of these projects has several of their own dependencies, too. We try our best to use these dependencies exactly as they are but sometimes we can't achieve our goals without patching those upstream dependencies to fit our use cases.
|
||||
|
||||
As such, we maintain a collection of patches as part of our source tree. The process for adding or altering one of these patches to Electron's source tree via a pull request can be found in [patches](patches.md).
|
||||
|
||||
## Debugging
|
||||
|
||||
There are many different approaches to debugging issues and bugs in Electron, many of which
|
||||
are platform specific.
|
||||
|
||||
For an overview of information related to debugging Electron itself (and not an app _built with Electron_), see [debugging](debugging.md).
|
||||
|
||||
@@ -16,6 +16,19 @@ Check the build prerequisites for your platform before proceeding
|
||||
|
||||
[Electron's Build Tools](https://github.com/electron/build-tools) automate much of the setup for compiling Electron from source with different configurations and build targets. If you wish to set up the environment manually, the instructions are listed below.
|
||||
|
||||
Electron uses [GN](https://gn.googlesource.com/gn) for project generation and
|
||||
[ninja](https://ninja-build.org/) for building. Project configurations can
|
||||
be found in the `.gn` and `.gni` files.
|
||||
|
||||
## GN Files
|
||||
|
||||
The following `gn` files contain the main rules for building Electron:
|
||||
|
||||
* `BUILD.gn` defines how Electron itself is built and
|
||||
includes the default configurations for linking with Chromium.
|
||||
* `build/args/{testing,release,all}.gn` contain the default build arguments for
|
||||
building Electron.
|
||||
|
||||
## GN prerequisites
|
||||
|
||||
You'll need to install [`depot_tools`][depot-tools], the toolset
|
||||
|
||||
@@ -1,80 +0,0 @@
|
||||
# Build System Overview
|
||||
|
||||
Electron uses [GN](https://gn.googlesource.com/gn) for project generation and
|
||||
[ninja](https://ninja-build.org/) for building. Project configurations can
|
||||
be found in the `.gn` and `.gni` files.
|
||||
|
||||
## GN Files
|
||||
|
||||
The following `gn` files contain the main rules for building Electron:
|
||||
|
||||
* `BUILD.gn` defines how Electron itself is built and
|
||||
includes the default configurations for linking with Chromium.
|
||||
* `build/args/{debug,release,all}.gn` contain the default build arguments for
|
||||
building Electron.
|
||||
|
||||
## Component Build
|
||||
|
||||
Since Chromium is quite a large project, the final linking stage can take
|
||||
quite a few minutes, which makes it hard for development. In order to solve
|
||||
this, Chromium introduced the "component build", which builds each component as
|
||||
a separate shared library, making linking very quick but sacrificing file size
|
||||
and performance.
|
||||
|
||||
Electron inherits this build option from Chromium. In `Debug` builds, the
|
||||
binary will be linked to a shared library version of Chromium's components to
|
||||
achieve fast linking time; for `Release` builds, the binary will be linked to
|
||||
the static library versions, so we can have the best possible binary size and
|
||||
performance.
|
||||
|
||||
## Tests
|
||||
|
||||
**NB** _this section is out of date and contains information that is no longer
|
||||
relevant to the GN-built electron._
|
||||
|
||||
Test your changes conform to the project coding style using:
|
||||
|
||||
```sh
|
||||
$ npm run lint
|
||||
```
|
||||
|
||||
Test functionality using:
|
||||
|
||||
```sh
|
||||
$ npm test
|
||||
```
|
||||
|
||||
Whenever you make changes to Electron source code, you'll need to re-run the
|
||||
build before the tests:
|
||||
|
||||
```sh
|
||||
$ npm run build && npm test
|
||||
```
|
||||
|
||||
You can make the test suite run faster by isolating the specific test or block
|
||||
you're currently working on using Mocha's
|
||||
[exclusive tests](https://mochajs.org/#exclusive-tests) feature. Append
|
||||
`.only` to any `describe` or `it` function call:
|
||||
|
||||
```js
|
||||
describe.only('some feature', () => {
|
||||
// ... only tests in this block will be run
|
||||
})
|
||||
```
|
||||
|
||||
Alternatively, you can use mocha's `grep` option to only run tests matching the
|
||||
given regular expression pattern:
|
||||
|
||||
```sh
|
||||
$ npm test -- --grep child_process
|
||||
```
|
||||
|
||||
Tests that include native modules (e.g. `runas`) can't be executed with the
|
||||
debug build (see [#2558](https://github.com/electron/electron/issues/2558) for
|
||||
details), but they will work with the release build.
|
||||
|
||||
To run the tests with the release build use:
|
||||
|
||||
```sh
|
||||
$ npm test -- -R
|
||||
```
|
||||
@@ -1,13 +1,39 @@
|
||||
# Chromium Development
|
||||
|
||||
> A collection of resources for learning about Chromium and tracking its development
|
||||
|
||||
- [@ChromiumDev](https://twitter.com/ChromiumDev) on Twitter
|
||||
- [@googlechrome](https://twitter.com/googlechrome) on Twitter
|
||||
- [Blog](https://blog.chromium.org)
|
||||
- [Code Search](https://cs.chromium.org/)
|
||||
- [Source Code](https://cs.chromium.org/chromium/src/)
|
||||
- [Development Calendar and Release Info](https://www.chromium.org/developers/calendar)
|
||||
- [Discussion Groups](https://www.chromium.org/developers/discussion-groups)
|
||||
> A collection of resources for learning about Chromium and tracking its development.
|
||||
|
||||
See also [V8 Development](v8-development.md)
|
||||
|
||||
## Contributing to Chromium
|
||||
|
||||
- [Checking Out and Building](https://chromium.googlesource.com/chromium/src/+/main/docs/#checking-out-and-building)
|
||||
- [Windows](https://chromium.googlesource.com/chromium/src/+/main/docs/windows_build_instructions.md)
|
||||
- [macOS](https://chromium.googlesource.com/chromium/src/+/main/docs/mac_build_instructions.md)
|
||||
- [Linux](https://chromium.googlesource.com/chromium/src/+/main/docs/linux/build_instructions.md)
|
||||
|
||||
- [Contributing](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/docs/contributing.md) - This document outlines the process of getting a code change merged to the Chromium source tree.
|
||||
- Assumes a working Chromium checkout and build.
|
||||
|
||||
## Resources for Chromium Development
|
||||
|
||||
### Code Resources
|
||||
|
||||
- [Code Search](https://cs.chromium.org/) - Indexed and searchable source code for Chromium and associated projects.
|
||||
- [Source Code](https://cs.chromium.org/chromium/src/) - The source code for Chromium itself.
|
||||
- [Chromium Review](https://chromium-review.googlesource.com) - The searchable code host which facilitates code reviews for Chromium and related projects.
|
||||
|
||||
### Informational Resources
|
||||
|
||||
- [Chromium Dash](https://chromiumdash.appspot.com/home) - Chromium Dash ties together multiple data sources in order to present a consolidated view of what's going on in Chromium and Chrome, plus related projects like V8, WebRTC & Skia.
|
||||
- [Schedule](https://chromiumdash.appspot.com/schedule) - Review upcoming Chromium release schedule.
|
||||
- [Branches](https://chromiumdash.appspot.com/branches) - Look up which branch corresponds to which milestone.
|
||||
- [Releases](https://chromiumdash.appspot.com/releases) - See what version of Chromium is shipping to each release channel and look up changes between each version.
|
||||
- [Commits](https://chromiumdash.appspot.com/commits) - See and search for commits to the Chromium source tree by commit SHA or committer username.
|
||||
- [Discussion Groups](https://www.chromium.org/developers/discussion-groups) - Subscribe to the following groups to get project updates and discuss the Chromium projects, and to get help in developing for Chromium-based browsers.
|
||||
- [Chromium Slack](https://www.chromium.org/developers/slack) - a virtual meeting place where Chromium ecosystem developers can foster community and coordinate work.
|
||||
|
||||
## Social Links
|
||||
|
||||
- [Blog](https://blog.chromium.org) - News and developments from Chromium.
|
||||
- [@ChromiumDev](https://twitter.com/ChromiumDev) - Twitter account containing news & guidance for developers from the Google Chrome Developer Relations team.
|
||||
- [@googlechrome](https://twitter.com/googlechrome) - Official Twitter account for the Google Chrome browser.
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
# Using clang-format on C++ Code
|
||||
|
||||
[`clang-format`](https://clang.llvm.org/docs/ClangFormat.html) is a tool to
|
||||
automatically format C/C++/Objective-C code, so that developers don't need to
|
||||
worry about style issues during code reviews.
|
||||
|
||||
It is highly recommended to format your changed C++ code before opening pull
|
||||
requests, which will save you and the reviewers' time.
|
||||
|
||||
You can install `clang-format` and `git-clang-format` via
|
||||
`npm install -g clang-format`.
|
||||
|
||||
To automatically format a file according to Electron C++ code style, run
|
||||
`clang-format -i path/to/electron/file.cc`. It should work on macOS/Linux/Windows.
|
||||
|
||||
The workflow to format your changed code:
|
||||
|
||||
1. Make codes changes in Electron repository.
|
||||
2. Run `git add your_changed_file.cc`.
|
||||
3. Run `git-clang-format`, and you will probably see modifications in
|
||||
`your_changed_file.cc`, these modifications are generated from `clang-format`.
|
||||
4. Run `git add your_changed_file.cc`, and commit your change.
|
||||
5. Now the branch is ready to be opened as a pull request.
|
||||
|
||||
If you want to format the changed code on your latest git commit (HEAD), you can
|
||||
run `git-clang-format HEAD~1`. See `git-clang-format -h` for more details.
|
||||
|
||||
## Editor Integration
|
||||
|
||||
You can also integrate `clang-format` directly into your favorite editors.
|
||||
For further guidance on setting up editor integration, see these pages:
|
||||
|
||||
* [Atom](https://atom.io/packages/clang-format)
|
||||
* [Vim & Emacs](https://clang.llvm.org/docs/ClangFormat.html#vim-integration)
|
||||
* [Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=xaver.clang-format)
|
||||
@@ -25,9 +25,8 @@ You can run `npm run lint` to show any style issues detected by `cpplint` and
|
||||
## C++ and Python
|
||||
|
||||
For C++ and Python, we follow Chromium's [Coding
|
||||
Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md). You can use
|
||||
[clang-format](clang-format.md) to format the C++ code automatically. There is
|
||||
also a script `script/cpplint.py` to check whether all files conform.
|
||||
Style](https://chromium.googlesource.com/chromium/src/+/refs/heads/main/styleguide/styleguide.md).
|
||||
There is also a script `script/cpplint.py` to check whether all files conform.
|
||||
|
||||
The Python version we are using now is Python 2.7.
|
||||
|
||||
|
||||
@@ -2,25 +2,22 @@
|
||||
|
||||
If you experience crashes or issues in Electron that you believe are not caused
|
||||
by your JavaScript application, but instead by Electron itself, debugging can
|
||||
be a little bit tricky, especially for developers not used to native/C++
|
||||
debugging. However, using lldb, and the Electron source code, you can enable
|
||||
be a little bit tricky especially for developers not used to native/C++
|
||||
debugging. However, using `lldb` and the Electron source code, you can enable
|
||||
step-through debugging with breakpoints inside Electron's source code.
|
||||
You can also use [XCode for debugging](debugging-instructions-macos-xcode.md) if
|
||||
you prefer a graphical interface.
|
||||
You can also use [XCode for debugging](debugging-with-xcode.md) if you prefer a graphical interface.
|
||||
|
||||
## Requirements
|
||||
|
||||
* **A debug build of Electron**: The easiest way is usually building it
|
||||
yourself, using the tools and prerequisites listed in the
|
||||
[build instructions for macOS](build-instructions-macos.md). While you can
|
||||
attach to and debug Electron as you can download it directly, you will
|
||||
find that it is heavily optimized, making debugging substantially more
|
||||
difficult: The debugger will not be able to show you the content of all
|
||||
* **A testing build of Electron**: The easiest way is usually to build it from source,
|
||||
which you can do by following the instructions in the [build instructions](./build-instructions-macos.md). While you can attach to and debug Electron as you can download it directly, you will
|
||||
find that it is heavily optimized, making debugging substantially more difficult.
|
||||
In this case the debugger will not be able to show you the content of all
|
||||
variables and the execution path can seem strange because of inlining,
|
||||
tail calls, and other compiler optimizations.
|
||||
|
||||
* **Xcode**: In addition to Xcode, also install the Xcode command line tools.
|
||||
They include LLDB, the default debugger in Xcode on macOS. It supports
|
||||
* **Xcode**: In addition to Xcode, you should also install the Xcode command line tools.
|
||||
They include [LLDB](https://lldb.llvm.org/), the default debugger in Xcode on macOS. It supports
|
||||
debugging C, Objective-C and C++ on the desktop and iOS devices and simulator.
|
||||
|
||||
* **.lldbinit**: Create or edit `~/.lldbinit` to allow Chromium code to be properly source-mapped.
|
||||
@@ -22,7 +22,7 @@ with breakpoints inside Electron's source code.
|
||||
|
||||
* **Visual Studio with C++ Tools**: The free community editions of Visual
|
||||
Studio 2013 and Visual Studio 2015 both work. Once installed,
|
||||
[configure Visual Studio to use Electron's Symbol server](setting-up-symbol-server.md).
|
||||
[configure Visual Studio to use Electron's Symbol server](debugging-with-symbol-server.md).
|
||||
It will enable Visual Studio to gain a better understanding of what happens
|
||||
inside Electron, making it easier to present variables in a human-readable
|
||||
format.
|
||||
@@ -90,3 +90,20 @@ out [this video tutorial][procmon-instructions] provided by Microsoft.
|
||||
|
||||
[sys-internals]: https://technet.microsoft.com/en-us/sysinternals/processmonitor.aspx
|
||||
[procmon-instructions]: https://channel9.msdn.com/shows/defrag-tools/defrag-tools-4-process-monitor
|
||||
|
||||
## Using WinDbg
|
||||
<!-- TODO(@codebytere): add images and more information here? -->
|
||||
|
||||
It's possible to debug crashes and issues in the Renderer process with [WinDbg](https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/getting-started-with-windbg).
|
||||
|
||||
To attach to a debug a process with WinDbg:
|
||||
|
||||
1. Add `--renderer-startup-dialog` as a command line flag to Electron.
|
||||
2. Launch the app you are intending to debug.
|
||||
3. A dialog box will appear with a pid: “Renderer starting with pid: 1234”.
|
||||
4. Launch WinDbg and choose “File > Attach to process” in the application menu.
|
||||
5. Enter in pid from the dialog box in Step 3.
|
||||
6. See that the debugger will be in a paused state, and that there is a command line in the app to enter text into.
|
||||
7. Type “g” into the above command line to start the debuggee.
|
||||
8. Press the enter key to continue the program.
|
||||
9. Go back to the dialog box and press “ok”.
|
||||
49
docs/development/debugging.md
Normal file
49
docs/development/debugging.md
Normal file
@@ -0,0 +1,49 @@
|
||||
# Electron Debugging
|
||||
|
||||
There are many different approaches to debugging issues and bugs in Electron, many of which
|
||||
are platform specific.
|
||||
|
||||
Some of the more common approaches are outlined below.
|
||||
|
||||
## Generic Debugging
|
||||
|
||||
Chromium contains logging macros which can aid debugging by printing information to console in C++ and Objective-C++.
|
||||
|
||||
You might use this to print out variable values, function names, and line numbers, amonst other things.
|
||||
|
||||
Some examples:
|
||||
|
||||
```cpp
|
||||
LOG(INFO) << "bitmap.width(): " << bitmap.width();
|
||||
|
||||
LOG(INFO, bitmap.width() > 10) << "bitmap.width() is greater than 10!";
|
||||
```
|
||||
|
||||
There are also different levels of logging severity: `INFO`, `WARN`, and `ERROR`.
|
||||
|
||||
See [logging.h](https://chromium.googlesource.com/chromium/src/base/+/refs/heads/main/logging.h) in Chromium's source tree for more information and examples.
|
||||
|
||||
## Printing Stacktraces
|
||||
|
||||
Chromium contains a helper to print stack traces to console without interrrupting the program.
|
||||
|
||||
```cpp
|
||||
#include "base/debug/stack_trace.h"
|
||||
...
|
||||
base::debug::StackTrace().Print();
|
||||
```
|
||||
|
||||
This will allow you to observe call chains and identify potential issue areas.
|
||||
|
||||
## Platform-Specific Debugging
|
||||
<!-- TODO(@codebytere): add debugging file for Linux-->
|
||||
|
||||
- [macOS Debugging](debugging-on-macos.md)
|
||||
- [Debugging with Xcode](debugging-with-xcode.md)
|
||||
- [Windows Debugging](debugging-on-windows.md)
|
||||
|
||||
## Debugging with the Symbol Server
|
||||
|
||||
Debug symbols allow you to have better debugging sessions. They have information about the functions contained in executables and dynamic libraries and provide you with information to get clean call stacks. A Symbol Server allows the debugger to load the correct symbols, binaries and sources automatically without forcing users to download large debugging files.
|
||||
|
||||
For more information about how to set up a symbol server for Electron, see [debugging with a symbol server](debugging-with-symbol-server.md).
|
||||
@@ -25,16 +25,14 @@ in your config file.
|
||||
When you are using Goma you can run `ninja` with a substantially higher `j`
|
||||
value than would normally be supported by your machine.
|
||||
|
||||
Please do not set a value higher than **200** on Windows or Linux and
|
||||
**50** on macOS. We monitor Goma system usage, and users found to be abusing
|
||||
it with unreasonable concurrency will be de-activated.
|
||||
Please do not set a value higher than **200**. We monitor Goma system usage, and users
|
||||
found to be abusing it with unreasonable concurrency will be de-activated.
|
||||
|
||||
```bash
|
||||
ninja -C out/Testing electron -j 200
|
||||
```
|
||||
|
||||
If you're using `build-tools`, appropriate `-j` values will automatically
|
||||
be used for you.
|
||||
If you're using `build-tools`, appropriate `-j` values will automatically be used for you.
|
||||
|
||||
## Monitoring Goma
|
||||
|
||||
|
||||
@@ -79,7 +79,7 @@ $ git add my/changed/files
|
||||
$ git commit
|
||||
```
|
||||
|
||||
Note that multiple commits often get squashed when they are landed.
|
||||
Note that multiple commits get squashed when they are landed.
|
||||
|
||||
#### Commit message guidelines
|
||||
|
||||
@@ -180,18 +180,10 @@ $ git push origin my-branch
|
||||
### Step 9: Opening the Pull Request
|
||||
|
||||
From within GitHub, opening a new pull request will present you with a template
|
||||
that should be filled out:
|
||||
that should be filled out. It can be found [here](../../.github/PULL_REQUEST_TEMPLATE.md).
|
||||
|
||||
```markdown
|
||||
<!--
|
||||
Thank you for your pull request. Please provide a description above and review
|
||||
the requirements below.
|
||||
|
||||
Bug fixes and new features should include tests and possibly benchmarks.
|
||||
|
||||
Contributors guide: https://github.com/electron/electron/blob/main/CONTRIBUTING.md
|
||||
-->
|
||||
```
|
||||
If you do not adequately complete this template, your PR may be delayed in being merged as maintainers
|
||||
seek more information or clarify ambiguities.
|
||||
|
||||
### Step 10: Discuss and update
|
||||
|
||||
|
||||
@@ -12,29 +12,18 @@ coding style, please see the [coding-style](coding-style.md) document.
|
||||
|
||||
## Linting
|
||||
|
||||
To ensure that your JavaScript is in compliance with the Electron coding
|
||||
style, run `npm run lint-js`, which will run `standard` against both
|
||||
Electron itself as well as the unit tests. If you are using an editor
|
||||
with a plugin/addon system, you might want to use one of the many
|
||||
[StandardJS addons][standard-addons] to be informed of coding style
|
||||
violations before you ever commit them.
|
||||
To ensure that your changes are in compliance with the Electron coding
|
||||
style, run `npm run lint`, which will run a variety of linting checks
|
||||
against your changes depending on which areas of the code they touch.
|
||||
|
||||
To run `standard` with parameters, run `npm run lint-js --` followed by
|
||||
arguments you want passed to `standard`.
|
||||
|
||||
To ensure that your C++ is in compliance with the Electron coding style,
|
||||
run `npm run lint-cpp`, which runs a `cpplint` script. We recommend that
|
||||
you use `clang-format` and prepared [a short tutorial](clang-format.md).
|
||||
|
||||
There is not a lot of Python in this repository, but it too is governed
|
||||
by coding style rules. `npm run lint-py` will check all Python, using
|
||||
`pylint` to do so.
|
||||
Many of these checks are included as precommit hooks, so it's likely
|
||||
you error would be caught at commit time.
|
||||
|
||||
## Unit Tests
|
||||
|
||||
If you are not using [build-tools](https://github.com/electron/build-tools),
|
||||
ensure that that name you have configured for your
|
||||
local build of Electron is one of `Testing`, `Release`, `Default`, `Debug`, or
|
||||
local build of Electron is one of `Testing`, `Release`, `Default`, or
|
||||
you have set `process.env.ELECTRON_OUT_DIR`. Without these set, Electron will fail
|
||||
to perform some pre-testing steps.
|
||||
|
||||
@@ -43,12 +32,34 @@ app (surprise!) that can be found in the `spec` folder. Note that it has
|
||||
its own `package.json` and that its dependencies are therefore not defined
|
||||
in the top-level `package.json`.
|
||||
|
||||
To run only tests in a specific process, run `npm run test --runners=PROCESS`
|
||||
where `PROCESS` is one of `main` or `remote`.
|
||||
|
||||
To run only specific tests matching a pattern, run `npm run test --
|
||||
-g=PATTERN`, replacing the `PATTERN` with a regex that matches the tests
|
||||
you would like to run. As an example: If you want to run only IPC tests, you
|
||||
would run `npm run test -- -g ipc`.
|
||||
|
||||
[standard-addons]: https://standardjs.com/#are-there-text-editor-plugins
|
||||
## Node.js Smoke Tests
|
||||
|
||||
If you've made changes that might affect the way Node.js is embedded into Electron,
|
||||
we have a test runner that runs all of the tests from Node.js, using Electron's custom fork
|
||||
of Node.js.
|
||||
|
||||
To run all of the Node.js tests:
|
||||
|
||||
```bash
|
||||
$ node script/node-spec-runner.js
|
||||
```
|
||||
|
||||
To run a single Node.js test:
|
||||
|
||||
```bash
|
||||
$ node script/node-spec-runner.js parallel/test-crypto-keygen
|
||||
```
|
||||
|
||||
where the argument passed to the runner is the path to the test in
|
||||
the Node.js source tree.
|
||||
|
||||
### Testing on Windows 10 devices
|
||||
|
||||
|
||||
@@ -1,48 +1,7 @@
|
||||
# Accessibility
|
||||
|
||||
Making accessible applications is important and we're happy to provide
|
||||
functionality to [Devtron][devtron] and [Spectron][spectron] that gives
|
||||
developers the opportunity to make their apps better for everyone.
|
||||
|
||||
---
|
||||
|
||||
Accessibility concerns in Electron applications are similar to those of
|
||||
websites because they're both ultimately HTML. With Electron apps, however,
|
||||
you can't use the online resources for accessibility audits because your app
|
||||
doesn't have a URL to point the auditor to.
|
||||
|
||||
These features bring those auditing tools to your Electron app. You can
|
||||
choose to add audits to your tests with Spectron or use them within DevTools
|
||||
with Devtron. Read on for a summary of the tools.
|
||||
|
||||
## Spectron
|
||||
|
||||
In the testing framework Spectron, you can now audit each window and `<webview>`
|
||||
tag in your application. For example:
|
||||
|
||||
```javascript
|
||||
app.client.auditAccessibility().then((audit) => {
|
||||
if (audit.failed) {
|
||||
console.error(audit.message)
|
||||
}
|
||||
})
|
||||
```
|
||||
|
||||
You can read more about this feature in [Spectron's documentation][spectron-a11y].
|
||||
|
||||
## Devtron
|
||||
|
||||
In Devtron, there is an accessibility tab which will allow you to audit a
|
||||
page in your app, sort and filter the results.
|
||||
|
||||
![devtron screenshot][devtron-screenshot]
|
||||
|
||||
Both of these tools are using the [Accessibility Developer Tools][a11y-devtools]
|
||||
library built by Google for Chrome. You can learn more about the accessibility
|
||||
audit rules this library uses on that [repository's wiki][a11y-devtools-wiki].
|
||||
|
||||
If you know of other great accessibility tools for Electron, add them to the
|
||||
accessibility documentation with a pull request.
|
||||
websites because they're both ultimately HTML.
|
||||
|
||||
## Manually enabling accessibility features
|
||||
|
||||
@@ -84,10 +43,6 @@ CFStringRef kAXManualAccessibility = CFSTR("AXManualAccessibility");
|
||||
}
|
||||
```
|
||||
|
||||
[devtron]: https://electronjs.org/devtron
|
||||
[devtron-screenshot]: https://cloud.githubusercontent.com/assets/1305617/17156618/9f9bcd72-533f-11e6-880d-389115f40a2a.png
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
[spectron-a11y]: https://github.com/electron/spectron#accessibility-testing
|
||||
[a11y-docs]: https://www.chromium.org/developers/design-documents/accessibility#TOC-How-Chrome-detects-the-presence-of-Assistive-Technology
|
||||
[a11y-devtools]: https://github.com/GoogleChrome/accessibility-developer-tools
|
||||
[a11y-devtools-wiki]: https://github.com/GoogleChrome/accessibility-developer-tools/wiki/Audit-Rules
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
# Automated Testing with a Custom Driver
|
||||
|
||||
To write automated tests for your Electron app, you will need a way to "drive" your application. [Spectron](https://electronjs.org/spectron) is a commonly-used solution which lets you emulate user actions via [WebDriver](https://webdriver.io/). However, it's also possible to write your own custom driver using node's builtin IPC-over-STDIO. The benefit of a custom driver is that it tends to require less overhead than Spectron, and lets you expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [child_process](https://nodejs.org/api/child_process.html) API. The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js [process](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js
|
||||
// listen for IPC messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more high-level functions. Here is an example of how you can do this:
|
||||
|
||||
```js
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
In the app, you'd need to write a simple handler for the RPC calls:
|
||||
|
||||
```js
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your test-driver as follows:
|
||||
|
||||
```js
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
265
docs/tutorial/automated-testing.md
Normal file
265
docs/tutorial/automated-testing.md
Normal file
@@ -0,0 +1,265 @@
|
||||
# Automated Testing
|
||||
|
||||
Test automation is an efficient way of validating that your application code works as intended.
|
||||
While Electron doesn't actively maintain its own testing solution, this guide will go over a couple
|
||||
ways you can run end-to-end automated tests on your Electron app.
|
||||
|
||||
## Using the WebDriver interface
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
There are a few ways that you can set up testing using WebDriver.
|
||||
|
||||
### With WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) (WDIO) is a test automation framework that provides a
|
||||
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
|
||||
(e.g. reporter and services) that can help you put together your test setup.
|
||||
|
||||
#### Install the testrunner
|
||||
|
||||
First you need to run the WebdriverIO starter toolkit in your project root directory:
|
||||
|
||||
```sh npm2yarn
|
||||
npx wdio . --yes
|
||||
```
|
||||
|
||||
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
|
||||
|
||||
#### Connect WDIO to your Electron app
|
||||
|
||||
Update the capabilities in your configuration file to point to your Electron app binary:
|
||||
|
||||
```javascript title='wdio.conf.js'
|
||||
export.config = {
|
||||
// ...
|
||||
capabilities: [{
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}]
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
#### Run your tests
|
||||
|
||||
To run your tests:
|
||||
|
||||
```sh
|
||||
$ npx wdio run wdio.conf.js
|
||||
```
|
||||
|
||||
[chrome-driver]: https://sites.google.com/chromium.org/driver/
|
||||
|
||||
### With Selenium
|
||||
|
||||
[Selenium](https://www.selenium.dev/) is a web automation framework that
|
||||
exposes bindings to WebDriver APIs in many languages. Their Node.js bindings
|
||||
are available under the `selenium-webdriver` package on NPM.
|
||||
|
||||
#### Run a ChromeDriver server
|
||||
|
||||
In order to use Selenium with Electron, you need to download the `electron-chromedriver`
|
||||
binary, and run it:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev electron-chromedriver
|
||||
./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later.
|
||||
|
||||
#### Connect Selenium to ChromeDriver
|
||||
|
||||
Next, install Selenium into your project:
|
||||
|
||||
```sh npm2yarn
|
||||
npm install --save-dev selenium-webdriver
|
||||
```
|
||||
|
||||
Usage of `selenium-webdriver` with Electron is the same as with
|
||||
normal websites, except that you have to manually specify how to connect
|
||||
ChromeDriver and where to find the binary of your Electron app:
|
||||
|
||||
```js title='test.js'
|
||||
const webdriver = require('selenium-webdriver')
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by ChromeDriver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Using a custom test driver
|
||||
|
||||
It's also possible to write your own custom driver using Node.js' built-in IPC-over-STDIO.
|
||||
Custom test drivers require you to write additional app code, but have lower overhead and let you
|
||||
expose custom methods to your test suite.
|
||||
|
||||
To create a custom driver, we'll use Node.js' [`child_process`](https://nodejs.org/api/child_process.html) API.
|
||||
The test suite will spawn the Electron process, then establish a simple messaging protocol:
|
||||
|
||||
```js title='testDriver.js'
|
||||
const childProcess = require('child_process')
|
||||
const electronPath = require('electron')
|
||||
|
||||
// spawn the process
|
||||
const env = { /* ... */ }
|
||||
const stdio = ['inherit', 'inherit', 'inherit', 'ipc']
|
||||
const appProcess = childProcess.spawn(electronPath, ['./app'], { stdio, env })
|
||||
|
||||
// listen for IPC messages from the app
|
||||
appProcess.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send an IPC message to the app
|
||||
appProcess.send({ my: 'message' })
|
||||
```
|
||||
|
||||
From within the Electron app, you can listen for messages and send replies using the Node.js
|
||||
[`process`](https://nodejs.org/api/process.html) API:
|
||||
|
||||
```js title='main.js'
|
||||
// listen for messages from the test suite
|
||||
process.on('message', (msg) => {
|
||||
// ...
|
||||
})
|
||||
|
||||
// send a message to the test suite
|
||||
process.send({ my: 'message' })
|
||||
```
|
||||
|
||||
We can now communicate from the test suite to the Electron app using the `appProcess` object.
|
||||
|
||||
For convenience, you may want to wrap `appProcess` in a driver object that provides more
|
||||
high-level functions. Here is an example of how you can do this. Let's start by creating
|
||||
a `TestDriver` class:
|
||||
|
||||
```js title='testDriver.js'
|
||||
class TestDriver {
|
||||
constructor ({ path, args, env }) {
|
||||
this.rpcCalls = []
|
||||
|
||||
// start child process
|
||||
env.APP_TEST_DRIVER = 1 // let the app know it should listen for messages
|
||||
this.process = childProcess.spawn(path, args, { stdio: ['inherit', 'inherit', 'inherit', 'ipc'], env })
|
||||
|
||||
// handle rpc responses
|
||||
this.process.on('message', (message) => {
|
||||
// pop the handler
|
||||
const rpcCall = this.rpcCalls[message.msgId]
|
||||
if (!rpcCall) return
|
||||
this.rpcCalls[message.msgId] = null
|
||||
// reject/resolve
|
||||
if (message.reject) rpcCall.reject(message.reject)
|
||||
else rpcCall.resolve(message.resolve)
|
||||
})
|
||||
|
||||
// wait for ready
|
||||
this.isReady = this.rpc('isReady').catch((err) => {
|
||||
console.error('Application failed to start', err)
|
||||
this.stop()
|
||||
process.exit(1)
|
||||
})
|
||||
}
|
||||
|
||||
// simple RPC call
|
||||
// to use: driver.rpc('method', 1, 2, 3).then(...)
|
||||
async rpc (cmd, ...args) {
|
||||
// send rpc request
|
||||
const msgId = this.rpcCalls.length
|
||||
this.process.send({ msgId, cmd, args })
|
||||
return new Promise((resolve, reject) => this.rpcCalls.push({ resolve, reject }))
|
||||
}
|
||||
|
||||
stop () {
|
||||
this.process.kill()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = { TestDriver };
|
||||
```
|
||||
|
||||
In your app code, can then write a simple handler to receive RPC calls:
|
||||
|
||||
```js title='main.js'
|
||||
const METHODS = {
|
||||
isReady () {
|
||||
// do any setup needed
|
||||
return true
|
||||
}
|
||||
// define your RPC-able methods here
|
||||
}
|
||||
|
||||
const onMessage = async ({ msgId, cmd, args }) => {
|
||||
let method = METHODS[cmd]
|
||||
if (!method) method = () => new Error('Invalid method: ' + cmd)
|
||||
try {
|
||||
const resolve = await method(...args)
|
||||
process.send({ msgId, resolve })
|
||||
} catch (err) {
|
||||
const reject = {
|
||||
message: err.message,
|
||||
stack: err.stack,
|
||||
name: err.name
|
||||
}
|
||||
process.send({ msgId, reject })
|
||||
}
|
||||
}
|
||||
|
||||
if (process.env.APP_TEST_DRIVER) {
|
||||
process.on('message', onMessage)
|
||||
}
|
||||
```
|
||||
|
||||
Then, in your test suite, you can use your `TestDriver` class with the test automation
|
||||
framework of your choosing. The following example uses
|
||||
[`ava`](https://www.npmjs.com/package/ava), but other popular choices like Jest
|
||||
or Mocha would work as well:
|
||||
|
||||
```js title='test.js'
|
||||
const test = require('ava')
|
||||
const electronPath = require('electron')
|
||||
const { TestDriver } = require('./testDriver')
|
||||
|
||||
const app = new TestDriver({
|
||||
path: electronPath,
|
||||
args: ['./app'],
|
||||
env: {
|
||||
NODE_ENV: 'test'
|
||||
}
|
||||
})
|
||||
test.before(async t => {
|
||||
await app.isReady
|
||||
})
|
||||
test.after.always('cleanup', async t => {
|
||||
await app.stop()
|
||||
})
|
||||
```
|
||||
@@ -73,7 +73,7 @@ until the maintainers feel the maintenance burden is too high to continue doing
|
||||
* 17.x.y
|
||||
* 16.x.y
|
||||
* 15.x.y
|
||||
* 13
|
||||
* 14.x.y
|
||||
|
||||
### End-of-life
|
||||
|
||||
|
||||
@@ -1,173 +0,0 @@
|
||||
# Selenium and WebDriver
|
||||
|
||||
From [ChromeDriver - WebDriver for Chrome][chrome-driver]:
|
||||
|
||||
> WebDriver is an open source tool for automated testing of web apps across many
|
||||
> browsers. It provides capabilities for navigating to web pages, user input,
|
||||
> JavaScript execution, and more. ChromeDriver is a standalone server which
|
||||
> implements WebDriver's wire protocol for Chromium. It is being developed by
|
||||
> members of the Chromium and WebDriver teams.
|
||||
|
||||
## Setting up Spectron
|
||||
|
||||
[Spectron][spectron] is the officially supported ChromeDriver testing framework
|
||||
for Electron. It is built on top of [WebdriverIO](https://webdriver.io/) and
|
||||
has helpers to access Electron APIs in your tests and bundles ChromeDriver.
|
||||
|
||||
```sh
|
||||
$ npm install --save-dev spectron
|
||||
```
|
||||
|
||||
```javascript
|
||||
// A simple test to verify a visible window is opened with a title
|
||||
const Application = require('spectron').Application
|
||||
const assert = require('assert')
|
||||
|
||||
const myApp = new Application({
|
||||
path: '/Applications/MyApp.app/Contents/MacOS/MyApp'
|
||||
})
|
||||
|
||||
const verifyWindowIsVisibleWithTitle = async (app) => {
|
||||
await app.start()
|
||||
try {
|
||||
// Check if the window is visible
|
||||
const isVisible = await app.browserWindow.isVisible()
|
||||
// Verify the window is visible
|
||||
assert.strictEqual(isVisible, true)
|
||||
// Get the window's title
|
||||
const title = await app.client.getTitle()
|
||||
// Verify the window's title
|
||||
assert.strictEqual(title, 'My App')
|
||||
} catch (error) {
|
||||
// Log any failures
|
||||
console.error('Test failed', error.message)
|
||||
}
|
||||
// Stop the application
|
||||
await app.stop()
|
||||
}
|
||||
|
||||
verifyWindowIsVisibleWithTitle(myApp)
|
||||
```
|
||||
|
||||
## Setting up with WebDriverJs
|
||||
|
||||
[WebDriverJs](https://www.selenium.dev/selenium/docs/api/javascript/index.html) provides
|
||||
a Node package for testing with web driver, we will use it as an example.
|
||||
|
||||
### 1. Start ChromeDriver
|
||||
|
||||
First you need to download the `chromedriver` binary, and run it:
|
||||
|
||||
```sh
|
||||
$ npm install electron-chromedriver
|
||||
$ ./node_modules/.bin/chromedriver
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later
|
||||
|
||||
### 2. Install WebDriverJS
|
||||
|
||||
```sh
|
||||
$ npm install selenium-webdriver
|
||||
```
|
||||
|
||||
### 3. Connect to ChromeDriver
|
||||
|
||||
The usage of `selenium-webdriver` with Electron is the same with
|
||||
upstream, except that you have to manually specify how to connect
|
||||
chrome driver and where to find Electron's binary:
|
||||
|
||||
```javascript
|
||||
const webdriver = require('selenium-webdriver')
|
||||
|
||||
const driver = new webdriver.Builder()
|
||||
// The "9515" is the port opened by chrome driver.
|
||||
.usingServer('http://localhost:9515')
|
||||
.withCapabilities({
|
||||
'goog:chromeOptions': {
|
||||
// Here is the path to your Electron binary.
|
||||
binary: '/Path-to-Your-App.app/Contents/MacOS/Electron'
|
||||
}
|
||||
})
|
||||
.forBrowser('chrome') // note: use .forBrowser('electron') for selenium-webdriver <= 3.6.0
|
||||
.build()
|
||||
|
||||
driver.get('http://www.google.com')
|
||||
driver.findElement(webdriver.By.name('q')).sendKeys('webdriver')
|
||||
driver.findElement(webdriver.By.name('btnG')).click()
|
||||
driver.wait(() => {
|
||||
return driver.getTitle().then((title) => {
|
||||
return title === 'webdriver - Google Search'
|
||||
})
|
||||
}, 1000)
|
||||
|
||||
driver.quit()
|
||||
```
|
||||
|
||||
## Setting up with WebdriverIO
|
||||
|
||||
[WebdriverIO](https://webdriver.io/) provides a Node package for testing with web
|
||||
driver.
|
||||
|
||||
### 1. Start ChromeDriver
|
||||
|
||||
First you need to download the `chromedriver` binary, and run it:
|
||||
|
||||
```sh
|
||||
$ npm install electron-chromedriver
|
||||
$ ./node_modules/.bin/chromedriver --url-base=wd/hub --port=9515
|
||||
Starting ChromeDriver (v2.10.291558) on port 9515
|
||||
Only local connections are allowed.
|
||||
```
|
||||
|
||||
Remember the port number `9515`, which will be used later
|
||||
|
||||
### 2. Install WebdriverIO
|
||||
|
||||
```sh
|
||||
$ npm install webdriverio
|
||||
```
|
||||
|
||||
### 3. Connect to chrome driver
|
||||
|
||||
```javascript
|
||||
const webdriverio = require('webdriverio')
|
||||
const options = {
|
||||
host: 'localhost', // Use localhost as chrome driver server
|
||||
port: 9515, // "9515" is the port opened by chrome driver.
|
||||
desiredCapabilities: {
|
||||
browserName: 'chrome',
|
||||
'goog:chromeOptions': {
|
||||
binary: '/Path-to-Your-App/electron', // Path to your Electron binary.
|
||||
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const client = webdriverio.remote(options)
|
||||
|
||||
client
|
||||
.init()
|
||||
.url('http://google.com')
|
||||
.setValue('#q', 'webdriverio')
|
||||
.click('#btnG')
|
||||
.getTitle().then((title) => {
|
||||
console.log('Title was: ' + title)
|
||||
})
|
||||
.end()
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
To test your application without rebuilding Electron,
|
||||
[place](application-distribution.md)
|
||||
your app source into Electron's resource directory.
|
||||
|
||||
Alternatively, pass an argument to run with your Electron binary that points to
|
||||
your app's folder. This eliminates the need to copy-paste your app into
|
||||
Electron's resource directory.
|
||||
|
||||
[chrome-driver]: https://sites.google.com/a/chromium.org/chromedriver/
|
||||
[spectron]: https://electronjs.org/spectron
|
||||
@@ -93,7 +93,7 @@ Debugging native modules can be done with Visual Studio 2017 (running on your de
|
||||
1. Launch your app `.exe` on the target device via the _Command Prompt_ (passing `--inspect-brk` to pause it before any native modules are loaded).
|
||||
2. Launch Visual Studio 2017 on your development machine.
|
||||
3. Connect to the target device by selecting _Debug > Attach to Process..._ and enter the device's IP address and the port number displayed by the Visual Studio Remote Debugger tool.
|
||||
4. Click _Refresh_ and select the [appropriate Electron process to attach](../development/debug-instructions-windows.md).
|
||||
4. Click _Refresh_ and select the [appropriate Electron process to attach](../development/debugging-on-windows.md).
|
||||
5. You may need to make sure that any symbols for native modules in your app are loaded correctly. To configure this, head to _Debug > Options..._ in Visual Studio 2017, and add the folders containing your `.pdb` symbols under _Debugging > Symbols_.
|
||||
6. Once attached, set any appropriate breakpoints and resume JavaScript execution using Chrome's [remote tools for Node](debugging-main-process.md).
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "17.0.0-nightly.20211026",
|
||||
"version": "17.0.0-nightly.20211102",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -109,3 +109,4 @@ fix_expose_decrementcapturercount_in_web_contents_impl.patch
|
||||
feat_add_data_parameter_to_processsingleton.patch
|
||||
mas_gate_private_enterprise_APIs
|
||||
load_v8_snapshot_in_browser_process.patch
|
||||
fix_patch_out_permissions_checks_in_exclusive_access.patch
|
||||
|
||||
@@ -61,7 +61,7 @@ index eec994c4252f17d9c9c41e66d5dae6509ed98a18..e538c9b76da4d4435e10cd3848438446
|
||||
#if defined(OS_WIN)
|
||||
bool EscapeVirtualization(const base::FilePath& user_data_dir);
|
||||
diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
|
||||
index 727333dd6abec99643e31bc77ed2cc8f3d5a0a0b..e5361397f78636816507355e7db6a9e55e6ed234 100644
|
||||
index a04d139f958a7aaef9b96e8c29317ccf7c97f009..29188668a69047b3ad3bebd1f0057565a330b509 100644
|
||||
--- a/chrome/browser/process_singleton_posix.cc
|
||||
+++ b/chrome/browser/process_singleton_posix.cc
|
||||
@@ -567,6 +567,7 @@ class ProcessSingleton::LinuxWatcher
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Shelley Vohr <shelley.vohr@gmail.com>
|
||||
Date: Mon, 25 Oct 2021 21:45:57 +0200
|
||||
Subject: fix: patch out permissions checks in exclusive_access
|
||||
|
||||
This patch is necessary in order to properly enable
|
||||
navigator.keyboard.{(un)?lock}() functionality. We don't have a concept
|
||||
of PermissionManager nor of a Profile, so this would not affect usage of
|
||||
the API.
|
||||
|
||||
We might consider potentially using our own permissions handler,
|
||||
but it's not strictly necessary for this API to work to spec.
|
||||
|
||||
Profile check has been upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3247196
|
||||
|
||||
diff --git a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
index e9c8a4a4bb7334682ceeec05b3a3e872de0192ab..861307591f3721c398c454126cb5a9be9a5e9764 100644
|
||||
--- a/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
+++ b/chrome/browser/ui/exclusive_access/fullscreen_controller.cc
|
||||
@@ -368,13 +368,9 @@ void FullscreenController::EnterFullscreenModeInternal(
|
||||
// Do not enter fullscreen mode if disallowed by pref. This prevents the user
|
||||
// from manually entering fullscreen mode and also disables kiosk mode on
|
||||
// desktop platforms.
|
||||
- if (!exclusive_access_manager()
|
||||
- ->context()
|
||||
- ->GetProfile()
|
||||
- ->GetPrefs()
|
||||
- ->GetBoolean(prefs::kFullscreenAllowed)) {
|
||||
+ auto* profile = exclusive_access_manager()->context()->GetProfile();
|
||||
+ if (!profile || !profile->GetPrefs()->GetBoolean(prefs::kFullscreenAllowed))
|
||||
return;
|
||||
- }
|
||||
#endif
|
||||
|
||||
toggled_into_fullscreen_ = true;
|
||||
@@ -387,6 +383,7 @@ void FullscreenController::EnterFullscreenModeInternal(
|
||||
url = extension_caused_fullscreen_;
|
||||
}
|
||||
|
||||
+#if 0
|
||||
if (display_id != display::kInvalidDisplayId) {
|
||||
// Check, but do not prompt, for permission to request a specific screen.
|
||||
// Sites generally need permission to get the display id in the first place.
|
||||
@@ -400,6 +397,7 @@ void FullscreenController::EnterFullscreenModeInternal(
|
||||
display_id = display::kInvalidDisplayId;
|
||||
}
|
||||
}
|
||||
+#endif
|
||||
|
||||
if (option == BROWSER)
|
||||
base::RecordAction(base::UserMetricsAction("ToggleFullscreen"));
|
||||
@@ -76,7 +76,7 @@ index 0d7c1db6489d95a40c66808c3f838b0740e46ff6..eec994c4252f17d9c9c41e66d5dae650
|
||||
|
||||
#if defined(OS_MAC)
|
||||
diff --git a/chrome/browser/process_singleton_posix.cc b/chrome/browser/process_singleton_posix.cc
|
||||
index 4547eb8563e1af57aad991d9d1e2cf02c778380a..727333dd6abec99643e31bc77ed2cc8f3d5a0a0b 100644
|
||||
index 4547eb8563e1af57aad991d9d1e2cf02c778380a..a04d139f958a7aaef9b96e8c29317ccf7c97f009 100644
|
||||
--- a/chrome/browser/process_singleton_posix.cc
|
||||
+++ b/chrome/browser/process_singleton_posix.cc
|
||||
@@ -80,6 +80,7 @@
|
||||
@@ -171,7 +171,7 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..727333dd6abec99643e31bc77ed2cc8f
|
||||
ProcessSingleton::NotifyResult
|
||||
ProcessSingleton::NotifyOtherProcessWithTimeoutOrCreate(
|
||||
const base::CommandLine& command_line,
|
||||
@@ -999,12 +1039,26 @@ bool ProcessSingleton::Create() {
|
||||
@@ -999,14 +1039,32 @@ bool ProcessSingleton::Create() {
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -180,15 +180,15 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..727333dd6abec99643e31bc77ed2cc8f
|
||||
- // do not support Unix domain sockets.
|
||||
- if (!socket_dir_.CreateUniqueTempDir()) {
|
||||
- LOG(ERROR) << "Failed to create socket directory.";
|
||||
- return false;
|
||||
+ base::FilePath tmp_dir;
|
||||
+ if (!base::GetTempDir(&tmp_dir)) {
|
||||
+ LOG(ERROR) << "Failed to get temporary directory.";
|
||||
return false;
|
||||
}
|
||||
|
||||
+ if (IsAppSandboxed()) {
|
||||
+ // For sandboxed applications, the tmp dir could be too long to fit
|
||||
+ // addr->sun_path, so we need to make it as short as possible.
|
||||
+ base::FilePath tmp_dir;
|
||||
+ if (!base::GetTempDir(&tmp_dir)) {
|
||||
+ LOG(ERROR) << "Failed to get temporary directory.";
|
||||
+ return false;
|
||||
+ }
|
||||
+ if (!socket_dir_.Set(tmp_dir.Append("S"))) {
|
||||
+ LOG(ERROR) << "Failed to set socket directory.";
|
||||
+ return false;
|
||||
@@ -197,14 +197,19 @@ index 4547eb8563e1af57aad991d9d1e2cf02c778380a..727333dd6abec99643e31bc77ed2cc8f
|
||||
+ // Create the socket file somewhere in /tmp which is usually mounted as a
|
||||
+ // normal filesystem. Some network filesystems (notably AFS) are screwy and
|
||||
+ // do not support Unix domain sockets.
|
||||
+ if (!socket_dir_.CreateUniqueTempDir()) {
|
||||
+ // Prefer CreateUniqueTempDirUnderPath rather than CreateUniqueTempDir as
|
||||
+ // the latter will calculate unique paths based on bundle ids which can
|
||||
+ // increase the socket path length than what is allowed.
|
||||
+ if (!socket_dir_.CreateUniqueTempDirUnderPath(tmp_dir)) {
|
||||
+ LOG(ERROR) << "Failed to create socket directory.";
|
||||
+ return false;
|
||||
+ }
|
||||
}
|
||||
|
||||
+ }
|
||||
+
|
||||
// Check that the directory was created with the correct permissions.
|
||||
@@ -1046,10 +1100,13 @@ bool ProcessSingleton::Create() {
|
||||
int dir_mode = 0;
|
||||
CHECK(base::GetPosixFilePermissions(socket_dir_.GetPath(), &dir_mode) &&
|
||||
@@ -1046,10 +1104,13 @@ bool ProcessSingleton::Create() {
|
||||
if (listen(sock, 5) < 0)
|
||||
NOTREACHED() << "listen failed: " << base::safe_strerror(errno);
|
||||
|
||||
|
||||
@@ -24,3 +24,4 @@ repl_fix_crash_when_sharedarraybuffer_disabled.patch
|
||||
fix_readbarrier_undefined_symbol_error_on_woa_arm64.patch
|
||||
chore_fix_-wimplicit-fallthrough.patch
|
||||
fix_event_with_invalid_timestamp_in_trace_log.patch
|
||||
test_fix_test-datetime-change-notify_after_daylight_change.patch
|
||||
|
||||
@@ -1772,7 +1772,7 @@ index 0000000000000000000000000000000000000000..d1d6b51e8c0c5bc6a5d09e217eb30483
|
||||
+ args = rebase_path(inputs + outputs, root_build_dir)
|
||||
+}
|
||||
diff --git a/src/node_version.h b/src/node_version.h
|
||||
index 7d8e7e507b2481e1f49c8da7c75a58dc8f90640e..d8ed5d33c3cf786ba2df9d37083c1ef103e06489 100644
|
||||
index 08e957472cfeca84af8cdc951af3c0de99c7b56c..330d77e868a50e1d0b71d773ab6b4b337ab20428 100644
|
||||
--- a/src/node_version.h
|
||||
+++ b/src/node_version.h
|
||||
@@ -89,7 +89,10 @@
|
||||
|
||||
@@ -8,7 +8,7 @@ modules from being used in the renderer process. This should be upstreamed as
|
||||
a customizable error message.
|
||||
|
||||
diff --git a/src/node_binding.cc b/src/node_binding.cc
|
||||
index e323f76261f2028ef58da74066f9112d8a5a8df2..02d8566caffb86d05645fb602ca7b5c6b8c71aa9 100644
|
||||
index e323f76261f2028ef58da74066f9112d8a5a8df2..bec34a61e0be78d863e476c75647e3496aa6a2c5 100644
|
||||
--- a/src/node_binding.cc
|
||||
+++ b/src/node_binding.cc
|
||||
@@ -4,6 +4,7 @@
|
||||
@@ -27,7 +27,7 @@ index e323f76261f2028ef58da74066f9112d8a5a8df2..02d8566caffb86d05645fb602ca7b5c6
|
||||
+ char errmsg[1024];
|
||||
+ snprintf(errmsg,
|
||||
+ sizeof(errmsg),
|
||||
+ "Loading non-context-aware native module in renderer: '%s', but app.allowRendererProcessReuse is true. See https://github.com/electron/electron/issues/18397.",
|
||||
+ "Loading non-context-aware native module in renderer: '%s'. See https://github.com/electron/electron/issues/18397.",
|
||||
+ *filename);
|
||||
+ env->ThrowError(errmsg);
|
||||
return false;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Piotr Rybak <rybak.piotr@yahoo.com>
|
||||
Date: Sun, 31 Oct 2021 17:58:09 +0900
|
||||
Subject: test: fix test-datetime-change-notify after daylight change
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Add standard timezone name for Dublin without daylight saving
|
||||
|
||||
PR-URL: https://github.com/nodejs/node/pull/40684
|
||||
Reviewed-By: Michaël Zasso <targos@protonmail.com>
|
||||
Reviewed-By: Tobias Nießen <tniessen@tnie.de>
|
||||
Reviewed-By: Voltrex <mohammadkeyvanzade94@gmail.com>
|
||||
(cherry picked from commit 747ef34fb0c9c1f2924ab1b79ea000c87e67a8eb)
|
||||
|
||||
diff --git a/test/parallel/test-datetime-change-notify.js b/test/parallel/test-datetime-change-notify.js
|
||||
index 9cd6d7abfd898ac6781b04422362a6b459b7dc2c..01843511907077857be22c9bc7e7f8568fc677d1 100644
|
||||
--- a/test/parallel/test-datetime-change-notify.js
|
||||
+++ b/test/parallel/test-datetime-change-notify.js
|
||||
@@ -18,15 +18,15 @@ const cases = [
|
||||
},
|
||||
{
|
||||
timeZone: 'America/New_York',
|
||||
- expected: /Eastern (Standard|Daylight) Time/,
|
||||
+ expected: /Eastern (?:Standard|Daylight) Time/,
|
||||
},
|
||||
{
|
||||
timeZone: 'America/Los_Angeles',
|
||||
- expected: /Pacific (Standard|Daylight) Time/,
|
||||
+ expected: /Pacific (?:Standard|Daylight) Time/,
|
||||
},
|
||||
{
|
||||
timeZone: 'Europe/Dublin',
|
||||
- expected: /Irish/,
|
||||
+ expected: /Irish Standard Time|Greenwich Mean Time/,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -90,6 +90,7 @@ const LINTERS = [{
|
||||
spawnAndCheckExitCode('python', ['script/run-clang-format.py', ...filenames]);
|
||||
}
|
||||
const filter = [
|
||||
'-readability/braces',
|
||||
'-readability/casting',
|
||||
'-whitespace/braces',
|
||||
'-whitespace/indent',
|
||||
|
||||
@@ -174,7 +174,7 @@ async function updateWinRC (components) {
|
||||
// updates support.md file with new semver values (stable only)
|
||||
async function updateSupported (version, filePath) {
|
||||
const v = parseInt(version);
|
||||
const newVersions = [`* ${v}.x.y`, `* ${v - 1}.x.y`, `* ${v - 2}.x.y`, `* ${v - 3}`];
|
||||
const newVersions = [`* ${v}.x.y`, `* ${v - 1}.x.y`, `* ${v - 2}.x.y`, `* ${v - 3}.x.y`];
|
||||
const contents = await readFile(filePath, 'utf8');
|
||||
const previousVersions = contents.split('\n').filter((elem) => {
|
||||
return (/[^\n]*\.x\.y[^\n]*/).test(elem);
|
||||
|
||||
@@ -254,7 +254,7 @@ void BrowserWindow::OnCloseButtonClicked(bool* prevent_default) {
|
||||
ScheduleUnresponsiveEvent(5000);
|
||||
|
||||
// Already closed by renderer.
|
||||
if (!web_contents())
|
||||
if (!web_contents() || !api_web_contents_)
|
||||
return;
|
||||
|
||||
// Required to make beforeunload handler work.
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "base/threading/thread_task_runner_handle.h"
|
||||
#include "base/values.h"
|
||||
#include "chrome/browser/browser_process.h"
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_manager.h"
|
||||
#include "chrome/browser/ui/views/eye_dropper/eye_dropper.h"
|
||||
#include "chrome/common/pref_names.h"
|
||||
#include "components/prefs/pref_service.h"
|
||||
@@ -630,6 +631,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -668,6 +670,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -688,6 +691,7 @@ WebContents::WebContents(v8::Isolate* isolate,
|
||||
: id_(GetAllWebContents().Add(this)),
|
||||
devtools_file_system_indexer_(
|
||||
base::MakeRefCounted<DevToolsFileSystemIndexer>()),
|
||||
exclusive_access_manager_(std::make_unique<ExclusiveAccessManager>(this)),
|
||||
file_task_runner_(
|
||||
base::ThreadPool::CreateSequencedTaskRunner({base::MayBlock()}))
|
||||
#if BUILDFLAG(ENABLE_PRINTING)
|
||||
@@ -1252,6 +1256,40 @@ void WebContents::ContentsZoomChange(bool zoom_in) {
|
||||
Emit("zoom-changed", zoom_in ? "in" : "out");
|
||||
}
|
||||
|
||||
Profile* WebContents::GetProfile() {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool WebContents::IsFullscreen() const {
|
||||
return owner_window_ && owner_window_->IsFullscreen();
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreen(const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
const int64_t display_id) {}
|
||||
|
||||
void WebContents::ExitFullscreen() {}
|
||||
|
||||
void WebContents::UpdateExclusiveAccessExitBubbleContent(
|
||||
const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,
|
||||
bool force_update) {}
|
||||
|
||||
void WebContents::OnExclusiveAccessUserInput() {}
|
||||
|
||||
content::WebContents* WebContents::GetActiveWebContents() {
|
||||
return web_contents();
|
||||
}
|
||||
|
||||
bool WebContents::CanUserExitFullscreen() const {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WebContents::IsExclusiveAccessBubbleDisplayed() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
void WebContents::EnterFullscreenModeForTab(
|
||||
content::RenderFrameHost* requesting_frame,
|
||||
const blink::mojom::FullscreenOptions& options) {
|
||||
@@ -1262,6 +1300,8 @@ void WebContents::EnterFullscreenModeForTab(
|
||||
base::BindRepeating(&WebContents::OnEnterFullscreenModeForTab,
|
||||
base::Unretained(this), requesting_frame, options);
|
||||
permission_helper->RequestFullscreenPermission(callback);
|
||||
exclusive_access_manager_->fullscreen_controller()->EnterFullscreenModeForTab(
|
||||
requesting_frame, options.display_id);
|
||||
}
|
||||
|
||||
void WebContents::OnEnterFullscreenModeForTab(
|
||||
@@ -1298,6 +1338,9 @@ void WebContents::ExitFullscreenModeForTab(content::WebContents* source) {
|
||||
// `chrome/browser/ui/exclusive_access/fullscreen_controller.cc`.
|
||||
source->GetRenderViewHost()->GetWidget()->SynchronizeVisualProperties();
|
||||
}
|
||||
|
||||
exclusive_access_manager_->fullscreen_controller()->ExitFullscreenModeForTab(
|
||||
source);
|
||||
}
|
||||
|
||||
void WebContents::RendererUnresponsive(
|
||||
@@ -1346,6 +1389,18 @@ void WebContents::FindReply(content::WebContents* web_contents,
|
||||
Emit("found-in-page", result.GetHandle());
|
||||
}
|
||||
|
||||
void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
|
||||
bool esc_key_locked) {
|
||||
exclusive_access_manager_->keyboard_lock_controller()->RequestKeyboardLock(
|
||||
web_contents, esc_key_locked);
|
||||
}
|
||||
|
||||
void WebContents::CancelKeyboardLockRequest(
|
||||
content::WebContents* web_contents) {
|
||||
exclusive_access_manager_->keyboard_lock_controller()
|
||||
->CancelKeyboardLockRequest(web_contents);
|
||||
}
|
||||
|
||||
bool WebContents::CheckMediaAccessPermission(
|
||||
content::RenderFrameHost* render_frame_host,
|
||||
const GURL& security_origin,
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "base/observer_list_types.h"
|
||||
#include "chrome/browser/devtools/devtools_eye_dropper.h"
|
||||
#include "chrome/browser/devtools/devtools_file_system_indexer.h"
|
||||
#include "chrome/browser/ui/exclusive_access/exclusive_access_context.h" // nogncheck
|
||||
#include "content/common/cursors/webcursor.h"
|
||||
#include "content/common/frame.mojom.h"
|
||||
#include "content/public/browser/devtools_agent_host.h"
|
||||
@@ -74,6 +75,8 @@ namespace gin {
|
||||
class Arguments;
|
||||
}
|
||||
|
||||
class ExclusiveAccessManager;
|
||||
|
||||
namespace electron {
|
||||
|
||||
class ElectronBrowserContext;
|
||||
@@ -98,7 +101,8 @@ using DevicePermissionMap = std::map<
|
||||
std::map<url::Origin, std::vector<std::unique_ptr<base::Value>>>>>;
|
||||
|
||||
// Wrapper around the content::WebContents.
|
||||
class WebContents : public gin::Wrappable<WebContents>,
|
||||
class WebContents : public ExclusiveAccessContext,
|
||||
public gin::Wrappable<WebContents>,
|
||||
public gin_helper::EventEmitterMixin<WebContents>,
|
||||
public gin_helper::Constructible<WebContents>,
|
||||
public gin_helper::Pinnable<WebContents>,
|
||||
@@ -549,6 +553,9 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
const gfx::Rect& selection_rect,
|
||||
int active_match_ordinal,
|
||||
bool final_update) override;
|
||||
void RequestKeyboardLock(content::WebContents* web_contents,
|
||||
bool esc_key_locked) override;
|
||||
void CancelKeyboardLockRequest(content::WebContents* web_contents) override;
|
||||
bool CheckMediaAccessPermission(content::RenderFrameHost* render_frame_host,
|
||||
const GURL& security_origin,
|
||||
blink::mojom::MediaStreamType type) override;
|
||||
@@ -647,6 +654,24 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
void EnumerateDirectory(content::WebContents* web_contents,
|
||||
scoped_refptr<content::FileSelectListener> listener,
|
||||
const base::FilePath& path) override;
|
||||
|
||||
// ExclusiveAccessContext:
|
||||
Profile* GetProfile() override;
|
||||
bool IsFullscreen() const override;
|
||||
void EnterFullscreen(const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
const int64_t display_id) override;
|
||||
void ExitFullscreen() override;
|
||||
void UpdateExclusiveAccessExitBubbleContent(
|
||||
const GURL& url,
|
||||
ExclusiveAccessBubbleType bubble_type,
|
||||
ExclusiveAccessBubbleHideCallback bubble_first_hide_callback,
|
||||
bool force_update) override;
|
||||
void OnExclusiveAccessUserInput() override;
|
||||
content::WebContents* GetActiveWebContents() override;
|
||||
bool CanUserExitFullscreen() const override;
|
||||
bool IsExclusiveAccessBubbleDisplayed() const override;
|
||||
|
||||
bool IsFullscreenForTabOrPending(const content::WebContents* source) override;
|
||||
blink::SecurityStyle GetSecurityStyle(
|
||||
content::WebContents* web_contents,
|
||||
@@ -760,6 +785,8 @@ class WebContents : public gin::Wrappable<WebContents>,
|
||||
|
||||
scoped_refptr<DevToolsFileSystemIndexer> devtools_file_system_indexer_;
|
||||
|
||||
std::unique_ptr<ExclusiveAccessManager> exclusive_access_manager_;
|
||||
|
||||
std::unique_ptr<DevToolsEyeDropper> eye_dropper_;
|
||||
|
||||
ElectronBrowserContext* browser_context_;
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "chrome/common/chrome_version.h"
|
||||
#include "components/net_log/chrome_net_log.h"
|
||||
#include "components/network_hints/common/network_hints.mojom.h"
|
||||
#include "content/browser/keyboard_lock/keyboard_lock_service_impl.h" // nogncheck
|
||||
#include "content/browser/site_instance_impl.h" // nogncheck
|
||||
#include "content/public/browser/browser_main_runner.h"
|
||||
#include "content/public/browser/browser_ppapi_host.h"
|
||||
@@ -1571,6 +1572,8 @@ void ElectronBrowserClient::RegisterBrowserInterfaceBindersForFrame(
|
||||
base::BindRepeating(&badging::BadgeManager::BindFrameReceiver));
|
||||
map->Add<electron::mojom::ElectronBrowser>(
|
||||
base::BindRepeating(&BindElectronBrowser));
|
||||
map->Add<blink::mojom::KeyboardLockService>(base::BindRepeating(
|
||||
&content::KeyboardLockServiceImpl::CreateMojoService));
|
||||
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
|
||||
map->Add<extensions::mime_handler::MimeHandlerService>(
|
||||
base::BindRepeating(&BindMimeHandlerService));
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "base/command_line.h"
|
||||
#include "content/public/browser/web_contents.h"
|
||||
#include "services/device/public/cpp/hid/hid_switches.h"
|
||||
#include "shell/browser/hid/hid_chooser_context.h"
|
||||
#include "shell/browser/hid/hid_chooser_context_factory.h"
|
||||
#include "shell/browser/hid/hid_chooser_controller.h"
|
||||
@@ -103,7 +105,8 @@ const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
|
||||
}
|
||||
|
||||
bool ElectronHidDelegate::IsFidoAllowedForOrigin(const url::Origin& origin) {
|
||||
return false;
|
||||
return base::CommandLine::ForCurrentProcess()->HasSwitch(
|
||||
switches::kDisableHidBlocklist);
|
||||
}
|
||||
|
||||
void ElectronHidDelegate::OnDeviceAdded(
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 17,0,0,20211026
|
||||
PRODUCTVERSION 17,0,0,20211026
|
||||
FILEVERSION 17,0,0,20211102
|
||||
PRODUCTVERSION 17,0,0,20211102
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -16,6 +16,9 @@
|
||||
#include "base/mac/mac_util.h"
|
||||
#include "base/mac/scoped_cftyperef.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "shell/common/gin_converters/file_path_converter.h"
|
||||
|
||||
@@ -290,6 +293,27 @@ void ReadDialogPaths(NSOpenPanel* dialog, std::vector<base::FilePath>* paths) {
|
||||
ReadDialogPathsWithBookmarks(dialog, paths, &ignored_bookmarks);
|
||||
}
|
||||
|
||||
void ResolvePromiseInNextTick(gin_helper::Promise<v8::Local<v8::Value>> promise,
|
||||
v8::Local<v8::Value> value) {
|
||||
// The completionHandler runs inside a transaction commit, and we should
|
||||
// not do any runModal inside it. However since we can not control what
|
||||
// users will run in the microtask, we have to delay the resolution until
|
||||
// next tick, otherwise crash like this may happen:
|
||||
// https://github.com/electron/electron/issues/26884
|
||||
base::PostTask(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(
|
||||
[](gin_helper::Promise<v8::Local<v8::Value>> promise,
|
||||
v8::Global<v8::Value> global) {
|
||||
v8::Isolate* isolate = promise.isolate();
|
||||
v8::Locker locker(isolate);
|
||||
v8::HandleScope handle_scope(isolate);
|
||||
v8::Local<v8::Value> value = global.Get(isolate);
|
||||
promise.Resolve(value);
|
||||
},
|
||||
std::move(promise), v8::Global<v8::Value>(promise.isolate(), value)));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool ShowOpenDialogSync(const DialogSettings& settings,
|
||||
@@ -320,7 +344,6 @@ void OpenDialogCompletion(int chosen,
|
||||
#if defined(MAS_BUILD)
|
||||
dict.Set("bookmarks", std::vector<std::string>());
|
||||
#endif
|
||||
promise.Resolve(dict);
|
||||
} else {
|
||||
std::vector<base::FilePath> paths;
|
||||
dict.Set("canceled", false);
|
||||
@@ -336,8 +359,9 @@ void OpenDialogCompletion(int chosen,
|
||||
ReadDialogPaths(dialog, &paths);
|
||||
dict.Set("filePaths", paths);
|
||||
#endif
|
||||
promise.Resolve(dict);
|
||||
}
|
||||
ResolvePromiseInNextTick(promise.As<v8::Local<v8::Value>>(),
|
||||
dict.GetHandle());
|
||||
}
|
||||
|
||||
void ShowOpenDialog(const DialogSettings& settings,
|
||||
@@ -410,7 +434,8 @@ void SaveDialogCompletion(int chosen,
|
||||
}
|
||||
#endif
|
||||
}
|
||||
promise.Resolve(dict);
|
||||
ResolvePromiseInNextTick(promise.As<v8::Local<v8::Value>>(),
|
||||
dict.GetHandle());
|
||||
}
|
||||
|
||||
void ShowSaveDialog(const DialogSettings& settings,
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "base/mac/scoped_nsobject.h"
|
||||
#include "base/no_destructor.h"
|
||||
#include "base/strings/sys_string_conversions.h"
|
||||
#include "base/task/post_task.h"
|
||||
#include "content/public/browser/browser_task_traits.h"
|
||||
#include "content/public/browser/browser_thread.h"
|
||||
#include "shell/browser/native_window.h"
|
||||
#include "skia/ext/skia_utils_mac.h"
|
||||
#include "ui/gfx/image/image_skia.h"
|
||||
@@ -160,20 +163,26 @@ void ShowMessageBox(const MessageBoxSettings& settings,
|
||||
__block absl::optional<int> id = std::move(settings.id);
|
||||
__block int cancel_id = settings.cancel_id;
|
||||
|
||||
[alert beginSheetModalForWindow:window
|
||||
completionHandler:^(NSModalResponse response) {
|
||||
if (id)
|
||||
GetDialogsMap().erase(*id);
|
||||
// When the alert is cancelled programmatically, the
|
||||
// response would be something like -1000. This currently
|
||||
// only happens when users call CloseMessageBox API, and we
|
||||
// should return cancelId as result.
|
||||
if (response < 0)
|
||||
response = cancel_id;
|
||||
std::move(callback_).Run(
|
||||
response, alert.suppressionButton.state == NSOnState);
|
||||
[alert release];
|
||||
}];
|
||||
auto handler = ^(NSModalResponse response) {
|
||||
if (id)
|
||||
GetDialogsMap().erase(*id);
|
||||
// When the alert is cancelled programmatically, the response would be
|
||||
// something like -1000. This currently only happens when users call
|
||||
// CloseMessageBox API, and we should return cancelId as result.
|
||||
if (response < 0)
|
||||
response = cancel_id;
|
||||
bool suppressed = alert.suppressionButton.state == NSOnState;
|
||||
[alert release];
|
||||
// The completionHandler runs inside a transaction commit, and we should
|
||||
// not do any runModal inside it. However since we can not control what
|
||||
// users will run in the callback, we have to delay running the callback
|
||||
// until next tick, otherwise crash like this may happen:
|
||||
// https://github.com/electron/electron/issues/26884
|
||||
base::PostTask(
|
||||
FROM_HERE, {content::BrowserThread::UI},
|
||||
base::BindOnce(std::move(callback_), response, suppressed));
|
||||
};
|
||||
[alert beginSheetModalForWindow:window completionHandler:handler];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -51,17 +51,7 @@ bool Clipboard::Has(const std::string& format_string,
|
||||
|
||||
std::string Clipboard::Read(const std::string& format_string) {
|
||||
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
|
||||
ui::ClipboardFormatType format(
|
||||
ui::ClipboardFormatType::CustomPlatformType(format_string));
|
||||
|
||||
std::string data;
|
||||
clipboard->ReadData(format, /* data_dst = */ nullptr, &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Clipboard::ReadBuffer(const std::string& format_string,
|
||||
gin_helper::Arguments* args) {
|
||||
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
|
||||
std::map<std::string, std::string> custom_format_names;
|
||||
custom_format_names =
|
||||
clipboard->ExtractCustomPlatformNames(ui::ClipboardBuffer::kCopyPaste,
|
||||
@@ -73,12 +63,24 @@ v8::Local<v8::Value> Clipboard::ReadBuffer(const std::string& format_string,
|
||||
/* data_dst = */ nullptr);
|
||||
}
|
||||
#endif
|
||||
CHECK(custom_format_names.find(format_string) != custom_format_names.end());
|
||||
ui::ClipboardFormatType format(ui::ClipboardFormatType::CustomPlatformType(
|
||||
custom_format_names[format_string]));
|
||||
|
||||
ui::ClipboardFormatType format;
|
||||
if (custom_format_names.find(format_string) != custom_format_names.end()) {
|
||||
format =
|
||||
ui::ClipboardFormatType(ui::ClipboardFormatType::CustomPlatformType(
|
||||
custom_format_names[format_string]));
|
||||
} else {
|
||||
format = ui::ClipboardFormatType(
|
||||
ui::ClipboardFormatType::CustomPlatformType(format_string));
|
||||
}
|
||||
std::string data;
|
||||
clipboard->ReadData(format, /* data_dst = */ nullptr, &data);
|
||||
return data;
|
||||
}
|
||||
|
||||
v8::Local<v8::Value> Clipboard::ReadBuffer(const std::string& format_string,
|
||||
gin_helper::Arguments* args) {
|
||||
std::string data = Read(format_string);
|
||||
return node::Buffer::Copy(args->isolate(), data.data(), data.length())
|
||||
.ToLocalChecked();
|
||||
}
|
||||
|
||||
@@ -106,6 +106,12 @@ class Promise : public PromiseBase {
|
||||
return resolved.GetHandle();
|
||||
}
|
||||
|
||||
// Convert to another type.
|
||||
template <typename NT>
|
||||
Promise<NT> As() {
|
||||
return Promise<NT>(isolate(), GetInner());
|
||||
}
|
||||
|
||||
// Promise resolution is a microtask
|
||||
// We use the MicrotasksRunner to trigger the running of pending microtasks
|
||||
v8::Maybe<bool> Resolve(const RT& value) {
|
||||
|
||||
@@ -110,6 +110,11 @@ describe('BrowserWindow module', () => {
|
||||
await closed;
|
||||
});
|
||||
|
||||
it('should not crash if called after webContents is destroyed', () => {
|
||||
w.webContents.destroy();
|
||||
w.webContents.on('destroyed', () => w.close());
|
||||
});
|
||||
|
||||
it('should emit unload handler', async () => {
|
||||
await w.loadFile(path.join(fixtures, 'api', 'unload.html'));
|
||||
const closed = emittedOnce(w, 'closed');
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
const { expect } = require('chai');
|
||||
const path = require('path');
|
||||
const { Buffer } = require('buffer');
|
||||
const { ifdescribe } = require('./spec-helpers');
|
||||
const { ifdescribe, ifit } = require('./spec-helpers');
|
||||
|
||||
const { clipboard, nativeImage } = require('electron');
|
||||
|
||||
@@ -62,14 +62,20 @@ ifdescribe(process.platform !== 'win32' || process.arch !== 'arm64')('clipboard
|
||||
});
|
||||
});
|
||||
|
||||
ifdescribe(process.platform !== 'linux')('clipboard.read()', () => {
|
||||
it('does not crash when reading various custom clipboard types', () => {
|
||||
describe('clipboard.read()', () => {
|
||||
ifit(process.platform !== 'linux')('does not crash when reading various custom clipboard types', () => {
|
||||
const type = process.platform === 'darwin' ? 'NSFilenamesPboardType' : 'FileNameW';
|
||||
|
||||
expect(() => {
|
||||
const result = clipboard.read(type);
|
||||
}).to.not.throw();
|
||||
});
|
||||
it('can read data written with writeBuffer', () => {
|
||||
const testText = 'Testing read';
|
||||
const buffer = Buffer.from(testText, 'utf8');
|
||||
clipboard.writeBuffer('public/utf8-plain-text', buffer);
|
||||
expect(clipboard.read('public/utf8-plain-text')).to.equal(testText);
|
||||
});
|
||||
});
|
||||
|
||||
describe('clipboard.write()', () => {
|
||||
|
||||
Reference in New Issue
Block a user