mirror of
https://github.com/electron/electron.git
synced 2026-04-10 03:01:51 -04:00
Compare commits
9 Commits
v14.0.0-ni
...
v14.0.0-ni
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5be2183dd7 | ||
|
|
2632564ccf | ||
|
|
521146f71e | ||
|
|
fb4e99e729 | ||
|
|
77365e701f | ||
|
|
1453a8e743 | ||
|
|
b9b734c9c4 | ||
|
|
7918ddb026 | ||
|
|
89df6b98da |
@@ -1 +1 @@
|
||||
14.0.0-nightly.20210324
|
||||
14.0.0-nightly.20210326
|
||||
@@ -75,6 +75,12 @@ This switch can not be used in `app.commandLine.appendSwitch` since it is parsed
|
||||
earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING`
|
||||
environment variable to achieve the same effect.
|
||||
|
||||
## --force-fieldtrials=`trials`
|
||||
|
||||
Field trials to be forcefully enabled or disabled.
|
||||
|
||||
For example: `WebRTC-Audio-Red-For-Opus/Enabled/`
|
||||
|
||||
### --host-rules=`rules`
|
||||
|
||||
A comma-separated list of `rules` that control how hostnames are mapped.
|
||||
|
||||
@@ -1131,6 +1131,7 @@ Ignore application menu shortcuts while this web contents is focused.
|
||||
* `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`.
|
||||
* `frameName` String - Name of the window provided in `window.open()`
|
||||
* `features` String - Comma separated list of window features provided to `window.open()`.
|
||||
|
||||
Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new
|
||||
window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window.
|
||||
Returning an unrecognized value such as a null, undefined, or an object
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "14.0.0-nightly.20210324",
|
||||
"version": "14.0.0-nightly.20210326",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
|
||||
@@ -47,7 +47,7 @@ def get_repo_root(path):
|
||||
|
||||
|
||||
def am(repo, patch_data, threeway=False, directory=None, exclude=None,
|
||||
committer_name=None, committer_email=None):
|
||||
committer_name=None, committer_email=None, keep_cr=True):
|
||||
args = []
|
||||
if threeway:
|
||||
args += ['--3way']
|
||||
@@ -56,6 +56,10 @@ def am(repo, patch_data, threeway=False, directory=None, exclude=None,
|
||||
if exclude is not None:
|
||||
for path_pattern in exclude:
|
||||
args += ['--exclude', path_pattern]
|
||||
if keep_cr is True:
|
||||
# Keep the CR of CRLF in case any patches target files with Windows line
|
||||
# endings.
|
||||
args += ['--keep-cr']
|
||||
|
||||
root_args = ['-C', repo]
|
||||
if committer_name is not None:
|
||||
@@ -230,7 +234,9 @@ def split_patches(patch_data):
|
||||
"""Split a concatenated series of patches into N separate patches"""
|
||||
patches = []
|
||||
patch_start = re.compile('^From [0-9a-f]+ ')
|
||||
for line in patch_data.splitlines():
|
||||
# Keep line endings in case any patches target files with CRLF.
|
||||
keep_line_endings = True
|
||||
for line in patch_data.splitlines(keep_line_endings):
|
||||
if patch_start.match(line):
|
||||
patches.append([])
|
||||
patches[-1].append(line)
|
||||
@@ -246,13 +252,23 @@ def munge_subject_to_filename(subject):
|
||||
|
||||
def get_file_name(patch):
|
||||
"""Return the name of the file to which the patch should be written"""
|
||||
file_name = None
|
||||
for line in patch:
|
||||
if line.startswith('Patch-Filename: '):
|
||||
return line[len('Patch-Filename: '):]
|
||||
file_name = line[len('Patch-Filename: '):]
|
||||
break
|
||||
# If no patch-filename header, munge the subject.
|
||||
for line in patch:
|
||||
if line.startswith('Subject: '):
|
||||
return munge_subject_to_filename(line[len('Subject: '):])
|
||||
if not file_name:
|
||||
for line in patch:
|
||||
if line.startswith('Subject: '):
|
||||
file_name = munge_subject_to_filename(line[len('Subject: '):])
|
||||
break
|
||||
return file_name.rstrip('\n')
|
||||
|
||||
|
||||
def join_patch(patch):
|
||||
"""Joins and formats patch contents"""
|
||||
return ''.join(remove_patch_filename(patch)).rstrip('\n') + '\n'
|
||||
|
||||
|
||||
def remove_patch_filename(patch):
|
||||
@@ -294,10 +310,8 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
for patch in patches:
|
||||
filename = get_file_name(patch)
|
||||
filepath = posixpath.join(out_dir, filename)
|
||||
existing_patch = io.open(filepath, 'r', encoding='utf-8').read()
|
||||
formatted_patch = (
|
||||
'\n'.join(remove_patch_filename(patch)).rstrip('\n') + '\n'
|
||||
)
|
||||
existing_patch = io.open(filepath, 'rb').read()
|
||||
formatted_patch = join_patch(patch)
|
||||
if formatted_patch != existing_patch:
|
||||
patch_count += 1
|
||||
if patch_count > 0:
|
||||
@@ -322,12 +336,11 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False):
|
||||
for patch in patches:
|
||||
filename = get_file_name(patch)
|
||||
file_path = posixpath.join(out_dir, filename)
|
||||
formatted_patch = (
|
||||
'\n'.join(remove_patch_filename(patch)).rstrip('\n') + '\n'
|
||||
)
|
||||
formatted_patch = join_patch(patch)
|
||||
# Write in binary mode to retain mixed line endings on write.
|
||||
with io.open(
|
||||
file_path, 'w', newline='\n', encoding='utf-8'
|
||||
file_path, 'wb'
|
||||
) as f:
|
||||
f.write(formatted_patch)
|
||||
f.write(formatted_patch.encode('utf-8'))
|
||||
pl.write(filename + '\n')
|
||||
|
||||
|
||||
@@ -207,7 +207,7 @@ const LINTERS = [{
|
||||
console.warn(`Patch file '${f}' has no description. Every patch must contain a justification for why the patch exists and the plan for its removal.`);
|
||||
return false;
|
||||
}
|
||||
const trailingWhitespace = patchText.split('\n').filter(line => line.startsWith('+')).some(line => /\s+$/.test(line));
|
||||
const trailingWhitespace = patchText.split(/\r?\n/).some(line => line.startsWith('+') && /\s+$/.test(line));
|
||||
if (trailingWhitespace) {
|
||||
console.warn(`Patch file '${f}' has trailing whitespace on some lines.`);
|
||||
return false;
|
||||
|
||||
@@ -279,6 +279,9 @@ void ElectronBrowserMainParts::PostEarlyInitialization() {
|
||||
base::FeatureList::ClearInstanceForTesting();
|
||||
InitializeFeatureList();
|
||||
|
||||
// Initialize field trials.
|
||||
InitializeFieldTrials();
|
||||
|
||||
// Initialize after user script environment creation.
|
||||
fake_browser_process_->PostEarlyInitialization();
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "base/base_switches.h"
|
||||
#include "base/command_line.h"
|
||||
#include "base/feature_list.h"
|
||||
#include "base/metrics/field_trial.h"
|
||||
#include "content/public/common/content_features.h"
|
||||
#include "electron/buildflags/buildflags.h"
|
||||
#include "media/base/media_switches.h"
|
||||
@@ -49,4 +50,12 @@ void InitializeFeatureList() {
|
||||
base::FeatureList::InitializeInstance(enable_features, disable_features);
|
||||
}
|
||||
|
||||
void InitializeFieldTrials() {
|
||||
auto* cmd_line = base::CommandLine::ForCurrentProcess();
|
||||
auto force_fieldtrials =
|
||||
cmd_line->GetSwitchValueASCII(::switches::kForceFieldTrials);
|
||||
|
||||
base::FieldTrialList::CreateTrialsFromString(force_fieldtrials);
|
||||
}
|
||||
|
||||
} // namespace electron
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
namespace electron {
|
||||
void InitializeFeatureList();
|
||||
}
|
||||
void InitializeFieldTrials();
|
||||
} // namespace electron
|
||||
|
||||
#endif // SHELL_BROWSER_FEATURE_LIST_H_
|
||||
|
||||
@@ -442,6 +442,14 @@ void NativeWindowViews::Hide() {
|
||||
if (!features::IsUsingOzonePlatform() && global_menu_bar_)
|
||||
global_menu_bar_->OnWindowUnmapped();
|
||||
#endif
|
||||
|
||||
#if defined(OS_WIN)
|
||||
// When the window is removed from the taskbar via win.hide(),
|
||||
// the thumbnail buttons need to be set up again.
|
||||
// Ensure that when the window is hidden,
|
||||
// the taskbar host is notified that it should re-add them.
|
||||
taskbar_host_.SetThumbarButtonsAdded(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
bool NativeWindowViews::IsVisible() {
|
||||
|
||||
@@ -50,8 +50,8 @@ END
|
||||
//
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION 14,0,0,20210324
|
||||
PRODUCTVERSION 14,0,0,20210324
|
||||
FILEVERSION 14,0,0,20210326
|
||||
PRODUCTVERSION 14,0,0,20210326
|
||||
FILEFLAGSMASK 0x3fL
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS 0x1L
|
||||
|
||||
@@ -114,11 +114,12 @@ bool TaskbarHost::SetThumbarButtons(HWND window,
|
||||
|
||||
// Finally add them to taskbar.
|
||||
HRESULT r;
|
||||
if (thumbar_buttons_added_)
|
||||
if (thumbar_buttons_added_) {
|
||||
r = taskbar_->ThumbBarUpdateButtons(window, kMaxButtonsCount,
|
||||
thumb_buttons);
|
||||
else
|
||||
} else {
|
||||
r = taskbar_->ThumbBarAddButtons(window, kMaxButtonsCount, thumb_buttons);
|
||||
}
|
||||
|
||||
thumbar_buttons_added_ = true;
|
||||
last_buttons_ = buttons;
|
||||
|
||||
@@ -60,6 +60,8 @@ class TaskbarHost {
|
||||
// Called by the window that there is a button in thumbar clicked.
|
||||
bool HandleThumbarButtonEvent(int button_id);
|
||||
|
||||
void SetThumbarButtonsAdded(bool added) { thumbar_buttons_added_ = added; }
|
||||
|
||||
private:
|
||||
// Initialize the taskbar object.
|
||||
bool InitializeTaskbar();
|
||||
|
||||
@@ -41,6 +41,8 @@ namespace context_bridge {
|
||||
const char* const kProxyFunctionPrivateKey = "electron_contextBridge_proxy_fn";
|
||||
const char* const kSupportsDynamicPropertiesPrivateKey =
|
||||
"electron_contextBridge_supportsDynamicProperties";
|
||||
const char* const kOriginalFunctionPrivateKey =
|
||||
"electron_contextBridge_original_fn";
|
||||
|
||||
} // namespace context_bridge
|
||||
|
||||
@@ -179,9 +181,26 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
// the global handle at the right time.
|
||||
if (value->IsFunction()) {
|
||||
auto func = v8::Local<v8::Function>::Cast(value);
|
||||
v8::MaybeLocal<v8::Value> maybe_original_fn = GetPrivate(
|
||||
source_context, func, context_bridge::kOriginalFunctionPrivateKey);
|
||||
|
||||
{
|
||||
v8::Context::Scope destination_scope(destination_context);
|
||||
v8::Local<v8::Value> proxy_func;
|
||||
|
||||
// If this function has already been sent over the bridge,
|
||||
// then it is being sent _back_ over the bridge and we can
|
||||
// simply return the original method here for performance reasons
|
||||
|
||||
// For safety reasons we check if the destination context is the
|
||||
// creation context of the original method. If it's not we proceed
|
||||
// with the proxy logic
|
||||
if (maybe_original_fn.ToLocal(&proxy_func) && proxy_func->IsFunction() &&
|
||||
proxy_func.As<v8::Object>()->CreationContext() ==
|
||||
destination_context) {
|
||||
return v8::MaybeLocal<v8::Value>(proxy_func);
|
||||
}
|
||||
|
||||
v8::Local<v8::Object> state =
|
||||
v8::Object::New(destination_context->GetIsolate());
|
||||
SetPrivate(destination_context, state,
|
||||
@@ -190,10 +209,12 @@ v8::MaybeLocal<v8::Value> PassValueToOtherContext(
|
||||
context_bridge::kSupportsDynamicPropertiesPrivateKey,
|
||||
gin::ConvertToV8(destination_context->GetIsolate(),
|
||||
support_dynamic_properties));
|
||||
v8::Local<v8::Value> proxy_func;
|
||||
|
||||
if (!v8::Function::New(destination_context, ProxyFunctionWrapper, state)
|
||||
.ToLocal(&proxy_func))
|
||||
return v8::MaybeLocal<v8::Value>();
|
||||
SetPrivate(destination_context, proxy_func.As<v8::Object>(),
|
||||
context_bridge::kOriginalFunctionPrivateKey, func);
|
||||
object_cache->CacheProxiedObject(value, proxy_func);
|
||||
return v8::MaybeLocal<v8::Value>(proxy_func);
|
||||
}
|
||||
|
||||
@@ -361,11 +361,8 @@ bool RendererClientBase::IsPluginHandledExternally(
|
||||
|
||||
bool RendererClientBase::IsOriginIsolatedPepperPlugin(
|
||||
const base::FilePath& plugin_path) {
|
||||
#if BUILDFLAG(ENABLE_PDF_VIEWER)
|
||||
return plugin_path.value() == kPdfPluginPath;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
// Isolate all Pepper plugins, including the PDF plugin.
|
||||
return true;
|
||||
}
|
||||
|
||||
std::unique_ptr<blink::WebPrescientNetworking>
|
||||
|
||||
@@ -353,6 +353,17 @@ describe('contextBridge', () => {
|
||||
expect(result).equal('return-value');
|
||||
});
|
||||
|
||||
it('should not double-proxy functions when they are returned to their origin side of the bridge', async () => {
|
||||
await makeBindingWindow(() => {
|
||||
contextBridge.exposeInMainWorld('example', (fn: any) => fn);
|
||||
});
|
||||
const result = await callWithBindings(async (root: any) => {
|
||||
const fn = () => null;
|
||||
return root.example(fn) === fn;
|
||||
});
|
||||
expect(result).equal(true);
|
||||
});
|
||||
|
||||
it('should proxy methods that are callable multiple times', async () => {
|
||||
await makeBindingWindow(() => {
|
||||
contextBridge.exposeInMainWorld('example', {
|
||||
|
||||
@@ -2,6 +2,9 @@ import { BrowserWindow, Session, session } from 'electron/main';
|
||||
|
||||
import { expect } from 'chai';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as http from 'http';
|
||||
import { AddressInfo } from 'net';
|
||||
import { closeWindow } from './window-helpers';
|
||||
import { emittedOnce } from './events-helpers';
|
||||
import { ifit, ifdescribe, delay } from './spec-helpers';
|
||||
@@ -10,9 +13,7 @@ const features = process._linkedBinding('electron_common_features');
|
||||
const v8Util = process._linkedBinding('electron_common_v8_util');
|
||||
|
||||
ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () {
|
||||
// TODO(zcbenz): Spellchecker loads really slow on ASan, we should provide
|
||||
// a small testing dictionary to make the tests load faster.
|
||||
this.timeout((process.env.IS_ASAN ? 700 : 20) * 1000);
|
||||
this.timeout((process.env.IS_ASAN ? 100 : 20) * 1000);
|
||||
|
||||
let w: BrowserWindow;
|
||||
|
||||
@@ -32,7 +33,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
// to detect spellchecker is to keep checking with a busy loop.
|
||||
async function rightClickUntil (fn: (params: Electron.ContextMenuParams) => boolean) {
|
||||
const now = Date.now();
|
||||
const timeout = (process.env.IS_ASAN ? 600 : 10) * 1000;
|
||||
const timeout = 10 * 1000;
|
||||
let contextMenuParams = await rightClick();
|
||||
while (!fn(contextMenuParams) && (Date.now() - now < timeout)) {
|
||||
await delay(100);
|
||||
@@ -41,6 +42,26 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
return contextMenuParams;
|
||||
}
|
||||
|
||||
// Setup a server to download hunspell dictionary.
|
||||
const server = http.createServer((req, res) => {
|
||||
// The provided is minimal dict for testing only, full list of words can
|
||||
// be found at src/third_party/hunspell_dictionaries/xx_XX.dic.
|
||||
fs.readFile(path.join(__dirname, '/../../third_party/hunspell_dictionaries/xx-XX-3-0.bdic'), function (err, data) {
|
||||
if (err) {
|
||||
console.error('Failed to read dictionary file');
|
||||
res.writeHead(404);
|
||||
res.end(JSON.stringify(err));
|
||||
return;
|
||||
}
|
||||
res.writeHead(200);
|
||||
res.end(data);
|
||||
});
|
||||
});
|
||||
before((done) => {
|
||||
server.listen(0, '127.0.0.1', () => done());
|
||||
});
|
||||
after(() => server.close());
|
||||
|
||||
beforeEach(async () => {
|
||||
w = new BrowserWindow({
|
||||
show: false,
|
||||
@@ -50,6 +71,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
contextIsolation: false
|
||||
}
|
||||
});
|
||||
w.webContents.session.setSpellCheckerDictionaryDownloadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}/`);
|
||||
w.webContents.session.setSpellCheckerLanguages(['en-US']);
|
||||
await w.loadFile(path.resolve(__dirname, './fixtures/chromium/spellchecker.html'));
|
||||
});
|
||||
@@ -62,7 +84,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
const shouldRun = process.platform !== 'win32';
|
||||
|
||||
ifit(shouldRun)('should detect correctly spelled words as correct', async () => {
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautiful and lovely"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typography"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()');
|
||||
const contextMenuParams = await rightClickUntil((contextMenuParams) => contextMenuParams.selectionText.length > 0);
|
||||
expect(contextMenuParams.misspelledWord).to.eq('');
|
||||
@@ -70,10 +92,10 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
});
|
||||
|
||||
ifit(shouldRun)('should detect incorrectly spelled words as incorrect', async () => {
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()');
|
||||
const contextMenuParams = await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0);
|
||||
expect(contextMenuParams.misspelledWord).to.eq('Beautifulllll');
|
||||
expect(contextMenuParams.misspelledWord).to.eq('typograpy');
|
||||
expect(contextMenuParams.dictionarySuggestions).to.have.length.of.at.least(1);
|
||||
});
|
||||
|
||||
@@ -81,24 +103,24 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
w.webContents.session.setSpellCheckerLanguages([]);
|
||||
await delay(500);
|
||||
w.webContents.session.setSpellCheckerLanguages(['en-US']);
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()');
|
||||
const contextMenuParams = await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0);
|
||||
expect(contextMenuParams.misspelledWord).to.eq('Beautifulllll');
|
||||
expect(contextMenuParams.misspelledWord).to.eq('typograpy');
|
||||
expect(contextMenuParams.dictionarySuggestions).to.have.length.of.at.least(1);
|
||||
});
|
||||
|
||||
ifit(shouldRun)('should expose webFrame spellchecker correctly', async () => {
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()');
|
||||
await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0);
|
||||
|
||||
const callWebFrameFn = (expr: string) => w.webContents.executeJavaScript('require("electron").webFrame.' + expr);
|
||||
|
||||
expect(await callWebFrameFn('isWordMisspelled("test")')).to.equal(false);
|
||||
expect(await callWebFrameFn('isWordMisspelled("testt")')).to.equal(true);
|
||||
expect(await callWebFrameFn('getWordSuggestions("test")')).to.be.empty();
|
||||
expect(await callWebFrameFn('getWordSuggestions("testt")')).to.not.be.empty();
|
||||
expect(await callWebFrameFn('isWordMisspelled("typography")')).to.equal(false);
|
||||
expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true);
|
||||
expect(await callWebFrameFn('getWordSuggestions("typography")')).to.be.empty();
|
||||
expect(await callWebFrameFn('getWordSuggestions("typograpy")')).to.not.be.empty();
|
||||
});
|
||||
|
||||
describe('spellCheckerEnabled', () => {
|
||||
@@ -107,7 +129,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
});
|
||||
|
||||
ifit(shouldRun)('can be dynamically changed', async () => {
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"');
|
||||
await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()');
|
||||
await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0);
|
||||
|
||||
@@ -116,12 +138,17 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function ()
|
||||
w.webContents.session.spellCheckerEnabled = false;
|
||||
v8Util.runUntilIdle();
|
||||
expect(w.webContents.session.spellCheckerEnabled).to.be.false();
|
||||
expect(await callWebFrameFn('isWordMisspelled("testt")')).to.equal(false);
|
||||
// spellCheckerEnabled is sent to renderer asynchronously and there is
|
||||
// no event notifying when it is finished, so wait a little while to
|
||||
// ensure the setting has been changed in renderer.
|
||||
await delay(500);
|
||||
expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(false);
|
||||
|
||||
w.webContents.session.spellCheckerEnabled = true;
|
||||
v8Util.runUntilIdle();
|
||||
expect(w.webContents.session.spellCheckerEnabled).to.be.true();
|
||||
expect(await callWebFrameFn('isWordMisspelled("testt")')).to.equal(true);
|
||||
await delay(500);
|
||||
expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user