Fix HiddenBrowser test failures (#5134)
Wait for 'complete', not 'interactive', so we know the image has been loaded. And use single documentIsReady() implementation instead of copy-pasting.
This commit is contained in:
parent
eb54cd82f6
commit
93b677aaf4
9 changed files with 90 additions and 134 deletions
|
@ -244,6 +244,16 @@ class HiddenBrowser {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number | false} [allowInteractiveAfter = false] Delay (in milliseconds) before resolving on 'interactive'.
|
||||
* If false, documentIsReady() won't resolve until 'complete'.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
waitForDocument({ allowInteractiveAfter = false } = {}) {
|
||||
return this.browsingContext.currentWindowGlobal.getActor('DocumentIsReady')
|
||||
.sendQuery('waitForDocument', { allowInteractiveAfter });
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {String[]} props - 'characterSet', 'title', 'bodyText', 'documentHTML', 'cookie', 'channelInfo'
|
||||
|
|
|
@ -86,3 +86,9 @@ ChromeUtils.registerWindowActor("MendeleyAuth", {
|
|||
moduleURI: "chrome://zotero/content/actors/MendeleyAuthChild.jsm"
|
||||
}
|
||||
});
|
||||
|
||||
ChromeUtils.registerWindowActor("DocumentIsReady", {
|
||||
child: {
|
||||
moduleURI: "chrome://zotero/content/actors/DocumentIsReadyChild.jsm"
|
||||
}
|
||||
});
|
||||
|
|
14
chrome/content/zotero/actors/DocumentIsReadyChild.jsm
Normal file
14
chrome/content/zotero/actors/DocumentIsReadyChild.jsm
Normal file
|
@ -0,0 +1,14 @@
|
|||
var EXPORTED_SYMBOLS = ["DocumentIsReadyChild"];
|
||||
|
||||
let { documentIsReady } = ChromeUtils.importESModule("chrome://zotero/content/actors/actorUtils.mjs");
|
||||
|
||||
class DocumentIsReadyChild extends JSWindowActorChild {
|
||||
async receiveMessage({ name, data }) {
|
||||
if (name !== "waitForDocument") {
|
||||
return null;
|
||||
}
|
||||
|
||||
let { allowInteractiveAfter } = data;
|
||||
await documentIsReady(this.document, { allowInteractiveAfter });
|
||||
}
|
||||
}
|
|
@ -2,12 +2,14 @@
|
|||
|
||||
var EXPORTED_SYMBOLS = ["MendeleyAuthChild"]; // eslint-disable-line no-unused-vars
|
||||
|
||||
let { documentIsReady } = ChromeUtils.importESModule("chrome://zotero/content/actors/actorUtils.mjs");
|
||||
|
||||
class MendeleyAuthChild extends JSWindowActorChild { // eslint-disable-line no-unused-vars
|
||||
async receiveMessage(message) {
|
||||
let window = this.contentWindow;
|
||||
let document = window.document;
|
||||
let document = this.document;
|
||||
|
||||
await this.documentIsReady();
|
||||
// Wait for 'complete'
|
||||
await documentIsReady(document);
|
||||
|
||||
switch (message.name) {
|
||||
case "login":
|
||||
|
@ -36,34 +38,4 @@ class MendeleyAuthChild extends JSWindowActorChild { // eslint-disable-line no-u
|
|||
|
||||
return false;
|
||||
}
|
||||
|
||||
// From Mozilla's ScreenshotsComponentChild.jsm
|
||||
documentIsReady() {
|
||||
const contentWindow = this.contentWindow;
|
||||
const document = this.document;
|
||||
|
||||
function readyEnough() {
|
||||
return document.readyState === "complete";
|
||||
}
|
||||
|
||||
if (readyEnough()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
function onChange(event) {
|
||||
if (event.type === "pagehide") {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
reject(new Error("document unloaded before it was ready"));
|
||||
}
|
||||
else if (readyEnough()) {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
document.addEventListener("readystatechange", onChange);
|
||||
contentWindow.addEventListener("pagehide", onChange, { once: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
var EXPORTED_SYMBOLS = ["PageDataChild"];
|
||||
|
||||
let { documentIsReady } = ChromeUtils.importESModule("chrome://zotero/content/actors/actorUtils.mjs");
|
||||
|
||||
class PageDataChild extends JSWindowActorChild {
|
||||
async receiveMessage(message) {
|
||||
// Special case for loadURI: don't wait for document to be ready,
|
||||
|
@ -8,10 +10,10 @@ class PageDataChild extends JSWindowActorChild {
|
|||
return this.loadURI(message.data.uri);
|
||||
}
|
||||
|
||||
let window = this.contentWindow;
|
||||
let document = window.document;
|
||||
let document = this.document;
|
||||
|
||||
await this.documentIsReady();
|
||||
// Wait for 'interactive' or 'complete'
|
||||
await documentIsReady(document, { allowInteractiveAfter: 0 });
|
||||
|
||||
switch (message.name) {
|
||||
case "characterSet":
|
||||
|
@ -74,34 +76,4 @@ class PageDataChild extends JSWindowActorChild {
|
|||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// From Mozilla's ScreenshotsComponentChild.jsm
|
||||
documentIsReady() {
|
||||
const contentWindow = this.contentWindow;
|
||||
const document = this.document;
|
||||
|
||||
function readyEnough() {
|
||||
return document.readyState === "complete" || document.readyState === "interactive";
|
||||
}
|
||||
|
||||
if (readyEnough()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
function onChange(event) {
|
||||
if (event.type === "pagehide") {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
reject(new Error("document unloaded before it was ready"));
|
||||
}
|
||||
else if (readyEnough()) {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
document.addEventListener("readystatechange", onChange);
|
||||
contentWindow.addEventListener("pagehide", onChange, { once: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
var EXPORTED_SYMBOLS = ["SingleFileChild"];
|
||||
|
||||
let { documentIsReady } = ChromeUtils.importESModule("chrome://zotero/content/actors/actorUtils.mjs");
|
||||
|
||||
class SingleFileChild extends JSWindowActorChild {
|
||||
async receiveMessage(message) {
|
||||
let window = this.contentWindow;
|
||||
|
||||
await this.documentIsReady();
|
||||
// Wait for 'complete'
|
||||
await documentIsReady(this.document);
|
||||
|
||||
if (message.name !== 'snapshot') {
|
||||
return null;
|
||||
|
@ -179,34 +181,4 @@ class SingleFileChild extends JSWindowActorChild {
|
|||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// From Mozilla's ScreenshotsComponentChild.jsm
|
||||
documentIsReady() {
|
||||
const contentWindow = this.contentWindow;
|
||||
const document = this.document;
|
||||
|
||||
function readyEnough() {
|
||||
return document.readyState === "complete";
|
||||
}
|
||||
|
||||
if (readyEnough()) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
function onChange(event) {
|
||||
if (event.type === "pagehide") {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
reject(new Error("document unloaded before it was ready"));
|
||||
}
|
||||
else if (readyEnough()) {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
document.addEventListener("readystatechange", onChange);
|
||||
contentWindow.addEventListener("pagehide", onChange, { once: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
var EXPORTED_SYMBOLS = ["TranslationChild"];
|
||||
|
||||
let { documentIsReady } = ChromeUtils.importESModule("chrome://zotero/content/actors/actorUtils.mjs");
|
||||
|
||||
const TRANSLATE_SCRIPT_PATHS = [
|
||||
'src/zotero.js',
|
||||
|
@ -43,7 +44,8 @@ class TranslationChild extends JSWindowActorChild {
|
|||
_sandbox = null;
|
||||
|
||||
async receiveMessage(message) {
|
||||
await this.documentIsReady();
|
||||
// Wait for 'complete', or 'interactive' after a 100ms delay
|
||||
await documentIsReady(this.document, { allowInteractiveAfter: 100 });
|
||||
|
||||
let { name, data } = message;
|
||||
switch (name) {
|
||||
|
@ -302,39 +304,6 @@ class TranslationChild extends JSWindowActorChild {
|
|||
return sandbox;
|
||||
}
|
||||
|
||||
// From Mozilla's ScreenshotsComponentChild.jsm
|
||||
documentIsReady() {
|
||||
const contentWindow = this.contentWindow;
|
||||
const document = this.document;
|
||||
|
||||
if (document.readyState === "complete") {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
function ready() {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
resolve();
|
||||
}
|
||||
|
||||
function onChange(event) {
|
||||
if (event.type === "pagehide") {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
reject(new Error("document unloaded before it was ready"));
|
||||
}
|
||||
else if (document.readyState === "complete") {
|
||||
ready();
|
||||
}
|
||||
else if (document.readyState === "interactive") {
|
||||
setTimeout(ready, 100);
|
||||
}
|
||||
}
|
||||
document.addEventListener("readystatechange", onChange);
|
||||
contentWindow.addEventListener("pagehide", onChange, { once: true });
|
||||
});
|
||||
}
|
||||
|
||||
didDestroy() {
|
||||
if (this._sandbox) {
|
||||
Cu.nukeSandbox(this._sandbox);
|
||||
|
|
42
chrome/content/zotero/actors/actorUtils.mjs
Normal file
42
chrome/content/zotero/actors/actorUtils.mjs
Normal file
|
@ -0,0 +1,42 @@
|
|||
import { setTimeout } from "resource://gre/modules/Timer.sys.mjs";
|
||||
|
||||
/**
|
||||
* @param {Document} document
|
||||
* @param {number | false} [allowInteractiveAfter] Delay (in milliseconds) before resolving on 'interactive'.
|
||||
* If false, documentIsReady() won't resolve until 'complete'.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
export async function documentIsReady(document, { allowInteractiveAfter = false } = {}) {
|
||||
// Adapted from Mozilla's ScreenshotsComponentChild.jsm
|
||||
|
||||
function readyEnough(readyState) {
|
||||
if (readyState === "interactive" && allowInteractiveAfter !== false) {
|
||||
return allowInteractiveAfter > 0
|
||||
? new Promise(resolve => setTimeout(() => resolve(true), allowInteractiveAfter))
|
||||
: true;
|
||||
}
|
||||
return readyState === "complete";
|
||||
}
|
||||
|
||||
let contentWindow = document.defaultView;
|
||||
|
||||
if (await readyEnough(document.readyState)) {
|
||||
return Promise.resolve();
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
async function onChange(event) {
|
||||
if (event.type === "pagehide") {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
reject(new Error("document unloaded before it was ready"));
|
||||
}
|
||||
else if (await readyEnough(document.readyState)) {
|
||||
document.removeEventListener("readystatechange", onChange);
|
||||
contentWindow.removeEventListener("pagehide", onChange);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
document.addEventListener("readystatechange", onChange);
|
||||
contentWindow.addEventListener("pagehide", onChange, { once: true });
|
||||
});
|
||||
}
|
|
@ -22,7 +22,6 @@ describe("HiddenBrowser", function() {
|
|||
'/remote.png',
|
||||
{
|
||||
handle: function (request, response) {
|
||||
Zotero.debug('Something loaded the image')
|
||||
response.setHeader('Content-Type', 'image/png', false);
|
||||
response.setStatusLine(null, 200, 'OK');
|
||||
response.write('');
|
||||
|
@ -46,7 +45,7 @@ describe("HiddenBrowser", function() {
|
|||
let path = OS.Path.join(getTestDataDirectory().path, 'test-hidden.html');
|
||||
let browser = new HiddenBrowser({ blockRemoteResources: true });
|
||||
await browser.load(path);
|
||||
await browser.getPageData(['characterSet', 'bodyText']);
|
||||
await browser.waitForDocument();
|
||||
browser.destroy();
|
||||
assert.isFalse(pngRequested);
|
||||
});
|
||||
|
@ -55,7 +54,7 @@ describe("HiddenBrowser", function() {
|
|||
let path = OS.Path.join(getTestDataDirectory().path, 'test-hidden.html');
|
||||
let browser = new HiddenBrowser({ blockRemoteResources: false });
|
||||
await browser.load(path);
|
||||
await browser.getPageData(['characterSet', 'bodyText']);
|
||||
await browser.waitForDocument();
|
||||
browser.destroy();
|
||||
assert.isTrue(pngRequested);
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue