Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
/**
* Test that the reader mode button appears and works properly on
* reader-able content.
*/
const TEST_PREFS = [["reader.parse-on-load.enabled", true]];
const TEST_PATH = getRootDirectory(gTestPath).replace(
);
var readerButton = document.getElementById("reader-mode-button");
ChromeUtils.defineESModuleGetters(this, {
});
add_task(async function test_reader_button() {
registerCleanupFunction(function () {
// Reset test prefs.
TEST_PREFS.forEach(([name]) => {
Services.prefs.clearUserPref(name);
});
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
// Set required test prefs.
TEST_PREFS.forEach(([name, value]) => {
Services.prefs.setBoolPref(name, value);
});
let tab = (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser));
is_element_hidden(
readerButton,
"Reader mode button is not present on a new tab"
);
ok(
!UITour.isInfoOnTarget(window, "readerMode-urlBar"),
"Info panel shouldn't appear without the reader mode button"
);
// Point tab to a test page that is reader-able.
let url = TEST_PATH + "readerModeArticle.html";
// Set up favicon for testing.
let favicon =
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAA" +
"AAAA6fptVAAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==";
info("Adding visit so we can add favicon");
await PlacesTestUtils.addVisits(new URL(url));
info("Adding favicon");
await PlacesTestUtils.addFavicons(new Map([[url, favicon]]));
info("Opening tab and waiting for reader mode button to show up");
await promiseTabLoadEvent(tab, url);
await TestUtils.waitForCondition(() => !readerButton.hidden);
is_element_visible(
readerButton,
"Reader mode button is present on a reader-able page"
);
// Switch page into reader mode.
let promiseTabLoad = promiseTabLoadEvent(tab);
readerButton.click();
await promiseTabLoad;
let readerUrl = gBrowser.selectedBrowser.currentURI.spec;
ok(
readerUrl.startsWith("about:reader"),
"about:reader loaded after clicking reader mode button"
);
is_element_visible(
readerButton,
"Reader mode button is present on about:reader"
);
let iconEl = tab.iconImage;
await TestUtils.waitForCondition(
() => iconEl.getBoundingClientRect().width != 0
);
is_element_visible(iconEl, "Favicon should be visible");
is(iconEl.src, favicon, "Correct favicon should be loaded");
is(gURLBar.untrimmedValue, url, "gURLBar value is about:reader URL");
is(
gURLBar.value,
UrlbarTestUtils.trimURL(url),
"gURLBar is displaying original article URL"
);
// Check selected value for URL bar
await new Promise((resolve, reject) => {
waitForClipboard(
url,
function () {
gURLBar.focus();
gURLBar.select();
goDoCommand("cmd_copy");
},
resolve,
reject
);
});
info("Got correct URL when copying");
// Switch page back out of reader mode.
let promisePageShow = BrowserTestUtils.waitForContentEvent(
tab.linkedBrowser,
"pageshow",
false,
e => e.target.location.href != "about:blank"
);
readerButton.click();
await promisePageShow;
is(
gBrowser.selectedBrowser.currentURI.spec,
url,
"Back to the original page after clicking active reader mode button"
);
ok(
gBrowser.selectedBrowser.canGoForward,
"Moved one step back in the session history."
);
let nonReadableUrl = TEST_PATH + "readerModeNonArticle.html";
// Load a new tab that is NOT reader-able.
let newTab = (gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser));
await promiseTabLoadEvent(newTab, nonReadableUrl);
await TestUtils.waitForCondition(() => readerButton.hidden);
is_element_hidden(
readerButton,
"Reader mode button is not present on a non-reader-able page"
);
// Switch back to the original tab to make sure reader mode button is still visible.
gBrowser.removeCurrentTab();
await TestUtils.waitForCondition(() => !readerButton.hidden);
is_element_visible(
readerButton,
"Reader mode button is present on a reader-able page"
);
// Load a new tab in reader mode that is NOT reader-able in the reader mode.
newTab = gBrowser.selectedTab = BrowserTestUtils.addTab(gBrowser);
let promiseAboutReaderError = BrowserTestUtils.waitForContentEvent(
newTab.linkedBrowser,
"AboutReaderContentError"
);
await promiseTabLoadEvent(newTab, "about:reader?url=" + nonReadableUrl);
await promiseAboutReaderError;
await TestUtils.waitForCondition(() => !readerButton.hidden);
is_element_visible(
readerButton,
"Reader mode button is present on about:reader even in error state"
);
// Switch page back out of reader mode.
promisePageShow = BrowserTestUtils.waitForContentEvent(
newTab.linkedBrowser,
"pageshow",
false,
e => e.target.location.href != "about:blank"
);
readerButton.click();
await promisePageShow;
is(
gBrowser.selectedBrowser.currentURI.spec,
nonReadableUrl,
"Back to the original non-reader-able page after clicking active reader mode button"
);
await TestUtils.waitForCondition(() => readerButton.hidden);
is_element_hidden(
readerButton,
"Reader mode button is not present on a non-reader-able page"
);
});
add_task(async function test_getOriginalUrl() {
let { ReaderMode } = ChromeUtils.importESModule(
"resource://gre/modules/ReaderMode.sys.mjs"
);
is(
ReaderMode.getOriginalUrl("about:reader?url=" + encodeURIComponent(url)),
url,
"Found original URL from encoded URL"
);
is(
ReaderMode.getOriginalUrl("about:reader?foobar"),
null,
"Did not find original URL from malformed reader URL"
);
is(
ReaderMode.getOriginalUrl(url),
null,
"Did not find original URL from non-reader URL"
);
is(
ReaderMode.getOriginalUrl("about:reader?url=" + encodeURIComponent(badUrl)),
badUrl,
"Found original URL from encoded malformed URL"
);
is(
ReaderMode.getOriginalUrl("about:reader?url=" + badUrl),
badUrl,
"Found original URL from non-encoded malformed URL"
);
});
add_task(async function test_reader_view_element_attribute_transform() {
registerCleanupFunction(function () {
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
function observeAttribute(element, attributes, triggerFn, checkFn) {
return new Promise(resolve => {
let observer = new MutationObserver(mutations => {
for (let mu of mutations) {
if (element.getAttribute(mu.attributeName) !== mu.oldValue) {
if (checkFn()) {
resolve();
observer.disconnect();
return;
}
}
}
});
observer.observe(element, {
attributes: true,
attributeOldValue: true,
attributeFilter: Array.isArray(attributes) ? attributes : [attributes],
});
triggerFn();
});
}
let menuitem = document.getElementById("menu_readerModeItem");
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
is(
menuitem.hidden,
true,
"menuitem element should have the hidden attribute"
);
info("Navigate a reader-able page");
function waitForNonBlankPage() {
return BrowserTestUtils.waitForContentEvent(
tab.linkedBrowser,
"pageshow",
false,
e => e.target.location.href != "about:blank"
);
}
let waitForPageshow = waitForNonBlankPage();
await observeAttribute(
menuitem,
"hidden",
() => {
let url = TEST_PATH + "readerModeArticle.html";
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
},
() => !menuitem.hidden
);
is(
menuitem.hidden,
false,
"menuitem's hidden attribute should be false on a reader-able page"
);
await waitForPageshow;
info("Navigate a non-reader-able page");
waitForPageshow = waitForNonBlankPage();
await observeAttribute(
menuitem,
"hidden",
() => {
let url = TEST_PATH + "readerModeArticleHiddenNodes.html";
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
},
() => menuitem.hidden
);
is(
menuitem.hidden,
true,
"menuitem's hidden attribute should be true on a non-reader-able page"
);
await waitForPageshow;
info("Navigate a reader-able page");
waitForPageshow = waitForNonBlankPage();
await observeAttribute(
menuitem,
"hidden",
() => {
let url = TEST_PATH + "readerModeArticle.html";
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
},
() => !menuitem.hidden
);
is(
menuitem.hidden,
false,
"menuitem's hidden attribute should be false on a reader-able page"
);
await waitForPageshow;
info("Enter Reader Mode");
waitForPageshow = waitForNonBlankPage();
await observeAttribute(
readerButton,
"readeractive",
() => {
readerButton.click();
},
() => readerButton.getAttribute("readeractive") == "true"
);
is(
readerButton.getAttribute("readeractive"),
"true",
"readerButton's readeractive attribute should be true when entering reader mode"
);
await waitForPageshow;
info("Exit Reader Mode");
waitForPageshow = waitForNonBlankPage();
await observeAttribute(
readerButton,
["readeractive", "hidden"],
() => {
readerButton.click();
},
() => {
info(
`active: ${readerButton.getAttribute("readeractive")}; hidden: ${
menuitem.hidden
}`
);
return !readerButton.getAttribute("readeractive") && !menuitem.hidden;
}
);
ok(
!readerButton.getAttribute("readeractive"),
"readerButton's readeractive attribute should be empty when reader mode is exited"
);
ok(!menuitem.hidden, "menuitem should not be hidden.");
await waitForPageshow;
info("Navigate a non-reader-able page");
waitForPageshow = waitForNonBlankPage();
await observeAttribute(
menuitem,
"hidden",
() => {
let url = TEST_PATH + "readerModeArticleHiddenNodes.html";
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
},
() => menuitem.hidden
);
is(
menuitem.hidden,
true,
"menuitem's hidden attribute should be true on a non-reader-able page"
);
await waitForPageshow;
});
add_task(async function test_reader_mode_lang() {
let url = TEST_PATH + "readerModeArticle.html";
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser);
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, url);
await promiseTabLoadEvent(tab, url);
await TestUtils.waitForCondition(() => !readerButton.hidden);
// Switch page into reader mode.
let promiseTabLoad = promiseTabLoadEvent(tab);
readerButton.click();
await promiseTabLoad;
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], () => {
let container = content.document.querySelector(".container");
is(container.lang, "en");
});
});