Merge mozilla-central to b2g-inbound

--HG--
rename : browser/components/migration/tests/unit/test_fx_fhr.js => browser/components/migration/tests/unit/test_fx_telemetry.js
extra : rebase_source : e274f592a1f49a14c57ea09dffa5c29e9c5ec2d1
This commit is contained in:
Carsten "Tomcat" Book 2016-01-21 12:30:56 +01:00
Родитель 2805ccddb1 adbf945ebf
Коммит b52ca99105
582 изменённых файлов: 8501 добавлений и 11098 удалений

Просмотреть файл

@ -141,6 +141,7 @@ NotificationController::IsUpdatePending()
void
NotificationController::WillRefresh(mozilla::TimeStamp aTime)
{
PROFILER_LABEL_FUNC(js::ProfileEntry::Category::OTHER);
Telemetry::AutoTimer<Telemetry::A11Y_UPDATE_TIME> updateTimer;
// If the document accessible that notification collector was created for is

Просмотреть файл

@ -0,0 +1,29 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=2 et sw=2 tw=80: */
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_a11y_TextRange_inl_h__
#define mozilla_a11y_TextRange_inl_h__
#include "TextRange.h"
#include "HyperTextAccessible.h"
namespace mozilla {
namespace a11y {
inline Accessible*
TextRange::Container() const
{
uint32_t pos1 = 0, pos2 = 0;
nsAutoTArray<Accessible*, 30> parents1, parents2;
return CommonParent(mStartContainer, mEndContainer,
&parents1, &pos1, &parents2, &pos2);
}
} // namespace a11y
} // namespace mozilla
#endif

Просмотреть файл

@ -4,10 +4,9 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "TextRange.h"
#include "TextRange-inl.h"
#include "Accessible-inl.h"
#include "HyperTextAccessible.h"
#include "nsAccUtils.h"
namespace mozilla {
@ -59,42 +58,6 @@ TextRange::TextRange(HyperTextAccessible* aRoot,
{
}
Accessible*
TextRange::Container() const
{
if (mStartContainer == mEndContainer)
return mStartContainer;
// Build the chain of parents
Accessible* p1 = mStartContainer;
Accessible* p2 = mEndContainer;
nsAutoTArray<Accessible*, 30> parents1, parents2;
do {
parents1.AppendElement(p1);
p1 = p1->Parent();
} while (p1);
do {
parents2.AppendElement(p2);
p2 = p2->Parent();
} while (p2);
// Find where the parent chain differs
uint32_t pos1 = parents1.Length();
uint32_t pos2 = parents2.Length();
Accessible* parent = nullptr;
uint32_t len = 0;
for (len = std::min(pos1, pos2); len > 0; --len) {
Accessible* child1 = parents1.ElementAt(--pos1);
Accessible* child2 = parents2.ElementAt(--pos2);
if (child1 != child2)
break;
parent = child1;
}
return parent;
}
void
TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
{
@ -111,28 +74,11 @@ TextRange::EmbeddedChildren(nsTArray<Accessible*>* aChildren) const
Accessible* p1 = mStartContainer->GetChildAtOffset(mStartOffset);
Accessible* p2 = mEndContainer->GetChildAtOffset(mEndOffset);
uint32_t pos1 = 0, pos2 = 0;
nsAutoTArray<Accessible*, 30> parents1, parents2;
do {
parents1.AppendElement(p1);
p1 = p1->Parent();
} while (p1);
do {
parents2.AppendElement(p2);
p2 = p2->Parent();
} while (p2);
// Find deepest common container.
uint32_t pos1 = parents1.Length();
uint32_t pos2 = parents2.Length();
Accessible* container = nullptr;
for (uint32_t len = std::min(pos1, pos2); len > 0; --len) {
Accessible* child1 = parents1.ElementAt(--pos1);
Accessible* child2 = parents2.ElementAt(--pos2);
if (child1 != child2)
break;
container = child1;
}
Accessible* container =
CommonParent(p1, p2, &parents1, &pos1, &parents2, &pos2);
// Traverse the tree up to the container and collect embedded objects.
for (uint32_t idx = 0; idx < pos1 - 1; idx++) {
@ -196,6 +142,95 @@ TextRange::Normalize(ETextUnit aUnit)
}
bool
TextRange::Crop(Accessible* aContainer)
{
uint32_t boundaryPos = 0, containerPos = 0;
nsAutoTArray<Accessible*, 30> boundaryParents, containerParents;
// Crop the start boundary.
Accessible* container = nullptr;
Accessible* boundary = mStartContainer->GetChildAtOffset(mStartOffset);
if (boundary != aContainer) {
CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
&containerParents, &containerPos);
if (boundaryPos == 0) {
if (containerPos != 0) {
// The container is contained by the start boundary, reduce the range to
// the point starting at the container.
aContainer->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
static_cast<Accessible*>(mStartContainer)->AddRef();
}
else {
// The start boundary and the container are siblings.
container = aContainer;
}
}
else if (containerPos != 0) {
// The container does not contain the start boundary.
boundary = boundaryParents[boundaryPos];
container = containerParents[containerPos];
}
if (container) {
// If the range start is after the container, then make the range invalid.
if (boundary->IndexInParent() > container->IndexInParent()) {
return !!(mRoot = nullptr);
}
// If the range starts before the container, then reduce the range to
// the point starting at the container.
if (boundary->IndexInParent() < container->IndexInParent()) {
container->ToTextPoint(mStartContainer.StartAssignment(), &mStartOffset);
mStartContainer.get()->AddRef();
}
}
boundaryParents.SetLengthAndRetainStorage(0);
containerParents.SetLengthAndRetainStorage(0);
}
boundary = mEndContainer->GetChildAtOffset(mEndOffset);
if (boundary == aContainer) {
return true;
}
// Crop the end boundary.
container = nullptr;
CommonParent(boundary, aContainer, &boundaryParents, &boundaryPos,
&containerParents, &containerPos);
if (boundaryPos == 0) {
if (containerPos != 0) {
aContainer->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
static_cast<Accessible*>(mEndContainer)->AddRef();
}
else {
container = aContainer;
}
}
else if (containerPos != 0) {
boundary = boundaryParents[boundaryPos];
container = containerParents[containerPos];
}
if (!container) {
return true;
}
if (boundary->IndexInParent() < container->IndexInParent()) {
return !!(mRoot = nullptr);
}
if (boundary->IndexInParent() > container->IndexInParent()) {
container->ToTextPoint(mEndContainer.StartAssignment(), &mEndOffset, false);
static_cast<Accessible*>(mEndContainer)->AddRef();
}
return true;
}
void
TextRange::FindText(const nsAString& aText, EDirection aDirection,
nsCaseTreatment aCaseSensitive, TextRange* aFoundRange) const
@ -296,5 +331,46 @@ TextRange::MoveInternal(ETextUnit aUnit, int32_t aCount,
}
Accessible*
TextRange::CommonParent(Accessible* aAcc1, Accessible* aAcc2,
nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const
{
if (aAcc1 == aAcc2) {
return aAcc1;
}
MOZ_ASSERT(aParents1->Length() == 0 || aParents2->Length() == 0,
"Wrong arguments");
// Build the chain of parents.
Accessible* p1 = aAcc1;
Accessible* p2 = aAcc2;
do {
aParents1->AppendElement(p1);
p1 = p1->Parent();
} while (p1);
do {
aParents2->AppendElement(p2);
p2 = p2->Parent();
} while (p2);
// Find where the parent chain differs
*aPos1 = aParents1->Length();
*aPos2 = aParents2->Length();
Accessible* parent = nullptr;
uint32_t len = 0;
for (len = std::min(*aPos1, *aPos2); len > 0; --len) {
Accessible* child1 = aParents1->ElementAt(--(*aPos1));
Accessible* child2 = aParents2->ElementAt(--(*aPos2));
if (child1 != child2)
break;
parent = child1;
}
return parent;
}
} // namespace a11y
} // namespace mozilla

Просмотреть файл

@ -131,6 +131,12 @@ public:
*/
void Normalize(ETextUnit aUnit);
/**
* Crops the range if it overlaps the given accessible element boundaries,
* returns true if the range was cropped successfully.
*/
bool Crop(Accessible* aContainer);
enum EDirection {
eBackward,
eForward
@ -243,6 +249,14 @@ private:
HyperTextAccessible* aStopContainer = nullptr,
int32_t aStopOffset = 0);
/**
* A helper method returning a common parent for two given accessible
* elements.
*/
Accessible* CommonParent(Accessible* aAcc1, Accessible* aAcc2,
nsTArray<Accessible*>* aParents1, uint32_t* aPos1,
nsTArray<Accessible*>* aParents2, uint32_t* aPos2) const;
RefPtr<HyperTextAccessible> mRoot;
RefPtr<HyperTextAccessible> mStartContainer;
RefPtr<HyperTextAccessible> mEndContainer;

Просмотреть файл

@ -2250,6 +2250,30 @@ Accessible::AnchorURIAt(uint32_t aAnchorIndex)
return nullptr;
}
void
Accessible::ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
bool aIsBefore) const
{
if (IsHyperText()) {
*aContainer = const_cast<Accessible*>(this)->AsHyperText();
*aOffset = aIsBefore ? 0 : (*aContainer)->CharacterCount();
return;
}
const Accessible* child = nullptr;
const Accessible* parent = this;
do {
child = parent;
parent = parent->Parent();
} while (parent && !parent->IsHyperText());
if (parent) {
*aContainer = const_cast<Accessible*>(parent)->AsHyperText();
*aOffset = (*aContainer)->GetChildOffset(
child->IndexInParent() + static_cast<int32_t>(!aIsBefore));
}
}
////////////////////////////////////////////////////////////////////////////////
// SelectAccessible

Просмотреть файл

@ -758,6 +758,12 @@ public:
*/
virtual already_AddRefed<nsIURI> AnchorURIAt(uint32_t aAnchorIndex);
/**
* Returns a text point for the accessible element.
*/
void ToTextPoint(HyperTextAccessible** aContainer, int32_t* aOffset,
bool aIsBefore = true) const;
//////////////////////////////////////////////////////////////////////////////
// SelectAccessible

Просмотреть файл

@ -1769,7 +1769,7 @@ HyperTextAccessible::EnclosingRange(a11y::TextRange& aRange) const
void
HyperTextAccessible::SelectionRanges(nsTArray<a11y::TextRange>* aRanges) const
{
NS_ASSERTION(aRanges->Length() != 0, "TextRange array supposed to be empty");
MOZ_ASSERT(aRanges->Length() == 0, "TextRange array supposed to be empty");
dom::Selection* sel = DOMSelection();
if (!sel)

Просмотреть файл

@ -258,7 +258,7 @@ public:
* @param aInvalidateAfter [in, optional] indicates whether invalidate
* cached offsets for next siblings of the child
*/
int32_t GetChildOffset(Accessible* aChild,
int32_t GetChildOffset(const Accessible* aChild,
bool aInvalidateAfter = false) const
{
int32_t index = GetIndexOf(aChild);

Просмотреть файл

@ -11,6 +11,7 @@ GARBAGE += $(MIDL_GENERATED_FILES)
MIDL_INTERFACES = \
Accessible2.idl \
Accessible2_2.idl \
Accessible2_3.idl \
AccessibleAction.idl \
AccessibleApplication.idl \
AccessibleComponent.idl \

Просмотреть файл

@ -13,7 +13,7 @@ interface nsIVariant;
/**
* A range representing a piece of text in the document.
*/
[scriptable, uuid(525b3401-8a67-4822-b35d-661065767cd8)]
[scriptable, uuid(c4515623-55f9-4543-a3d5-c1e9afa588f4)]
interface nsIAccessibleTextRange : nsISupports
{
readonly attribute nsIAccessibleText startContainer;
@ -81,6 +81,11 @@ interface nsIAccessibleTextRange : nsISupports
*/
void normalize(in unsigned long aUnit);
/**
* Crops the range by the given accessible element.
*/
boolean crop(in nsIAccessible aContainer);
/**
* Return range enclosing the found text.
*/

Просмотреть файл

@ -473,6 +473,10 @@ function testTextRange(aRange, aRangeDescr, aStartContainer, aStartOffset,
is(aRange.endOffset, aEndOffset,
"Wrong end offset of " + aRangeDescr);
if (aText === undefined) {
return;
}
is(aRange.text, aText, "Wrong text of " + aRangeDescr);
var children = aRange.embeddedChildren;

Просмотреть файл

@ -1,3 +1,4 @@
[DEFAULT]
[test_general.html]
[test_selection.html]

Просмотреть файл

@ -0,0 +1,120 @@
<!DOCTYPE html>
<html>
<head>
<title>Text Range selection tests</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="../common.js"></script>
<script type="application/javascript"
src="../text.js"></script>
<script type="application/javascript"
src="../layout.js"></script>
<script type="application/javascript">
function doTest()
{
var sel = window.getSelection();
var p = getNode("p1");
var a = getNode("p2_a");
var range = document.createRange();
sel.addRange(range);
// the accessible is contained by the range
range.selectNode(p);
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #1", document, 3, document, 4);
ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #1.");
testTextRange(a11yrange, "cropped range #1", a, 0, a, 5);
// the range is contained by the accessible
range.selectNode(a);
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #2", p, 5, p, 6);
ok(a11yrange.crop(getAccessible(p)), "Range failed to crop #2.");
testTextRange(a11yrange, "cropped range #2", p, 5, p, 6);
// the range starts before the accessible and ends inside it
range.setStart(p, 0);
range.setEndAfter(a.firstChild, 4);
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #3", p, 0, a, 4);
ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #3.");
testTextRange(a11yrange, "cropped range #3", a, 0, a, 4);
// the range starts inside the accessible and ends after it
range.setStart(a.firstChild, 1);
range.setEndAfter(p);
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #4", a, 1, document, 4);
ok(a11yrange.crop(getAccessible(a)), "Range failed to crop #4.");
testTextRange(a11yrange, "cropped range #4", a, 1, a, 5);
// the range ends before the accessible
range.setStart(p.firstChild, 0);
range.setEnd(p.firstChild, 4);
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #5", p, 0, p, 4);
ok(!a11yrange.crop(getAccessible(a)), "Crop #5 succeeded while it shouldn't");
// the range starts after the accessible
range.setStart(p.lastChild, 0);
range.setEnd(p.lastChild, 4);
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #6", p, 6, p, 10);
ok(!a11yrange.crop(getAccessible(a)), "Crop #6 succeeded while it shouldn't");
// crop a range by a table
range.selectNode(getNode("c2"));
var a11yranges = getAccessible(document, [nsIAccessibleText]).selectionRanges;
var a11yrange = a11yranges.queryElementAt(0, nsIAccessibleTextRange);
testTextRange(a11yrange, "selection range #7", document, 4, document, 5);
ok(a11yrange.crop(getAccessible("table")), "Range failed to crop #7.");
testTextRange(a11yrange, "cropped range #7", "c2", 5, "c2", 6);
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTest);
</script>
</head>
<body>
<a target="_blank"
title="Implement IAccessible2_3::selectionRanges"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=1233118">Bug 1233118</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<p id="p1">text <a id="p2_a" href="www">link<img id="p2_img", src="../moz.png"></a> text</p>
<div id="c2">start<table id="table"><tr><td>cell</td></tr></table>end</div>
</body>
</html>

Просмотреть файл

@ -8,6 +8,7 @@
#include "Accessible2_i.c"
#include "Accessible2_2_i.c"
#include "Accessible2_3_i.c"
#include "AccessibleRole.h"
#include "AccessibleStates.h"
@ -18,6 +19,7 @@
#include "nsIAccessibleTypes.h"
#include "mozilla/a11y/PDocAccessible.h"
#include "Relation.h"
#include "TextRange-inl.h"
#include "nsAccessibilityService.h"
#include "nsIPersistentProperties2.h"
@ -40,7 +42,9 @@ ia2Accessible::QueryInterface(REFIID iid, void** ppv)
*ppv = nullptr;
if (IID_IAccessible2_2 == iid)
if (IID_IAccessible2_3 == iid)
*ppv = static_cast<IAccessible2_3*>(this);
else if (IID_IAccessible2_2 == iid)
*ppv = static_cast<IAccessible2_2*>(this);
else if (IID_IAccessible2 == iid && !Compatibility::IsIA2Off())
*ppv = static_cast<IAccessible2*>(this);
@ -749,6 +753,58 @@ ia2Accessible::get_relationTargetsOfType(BSTR aType,
A11Y_TRYBLOCK_END
}
STDMETHODIMP
ia2Accessible::get_selectionRanges(IA2Range** aRanges,
long *aNRanges)
{
A11Y_TRYBLOCK_BEGIN
if (!aRanges || !aNRanges || aNRanges <= 0)
return E_INVALIDARG;
*aNRanges = 0;
AccessibleWrap* acc = static_cast<AccessibleWrap*>(this);
if (acc->IsDefunct())
return CO_E_OBJNOTCONNECTED;
nsAutoTArray<TextRange, 1> ranges;
acc->Document()->SelectionRanges(&ranges);
uint32_t len = ranges.Length();
for (uint32_t idx = 0; idx < len; idx++) {
if (!ranges[idx].Crop(acc)) {
ranges.RemoveElementAt(idx);
}
}
*aNRanges = ranges.Length();
*aRanges = static_cast<IA2Range*>(
::CoTaskMemAlloc(sizeof(IA2Range) * *aNRanges));
if (!*aRanges)
return E_OUTOFMEMORY;
for (uint32_t idx = 0; idx < static_cast<uint32_t>(*aNRanges); idx++) {
AccessibleWrap* anchor =
static_cast<AccessibleWrap*>(ranges[idx].StartContainer());
(*aRanges)[idx].anchor = static_cast<IAccessible2*>(anchor);
anchor->AddRef();
(*aRanges)[idx].anchorOffset = ranges[idx].StartOffset();
AccessibleWrap* active =
static_cast<AccessibleWrap*>(ranges[idx].EndContainer());
(*aRanges)[idx].active = static_cast<IAccessible2*>(active);
active->AddRef();
(*aRanges)[idx].activeOffset = ranges[idx].EndOffset();
}
return S_OK;
A11Y_TRYBLOCK_END
}
////////////////////////////////////////////////////////////////////////////////
// Helpers

Просмотреть файл

@ -9,13 +9,13 @@
#include "nsISupports.h"
#include "Accessible2_2.h"
#include "Accessible2_3.h"
namespace mozilla {
namespace a11y {
class Attribute;
class ia2Accessible : public IAccessible2_2
class ia2Accessible : public IAccessible2_3
{
public:
@ -104,6 +104,11 @@ public:
/* [out, retval] */ long* nTargets
);
// IAccessible2_3
virtual /* [propget] */ HRESULT STDMETHODCALLTYPE get_selectionRanges(
/* [out, size_is(,*nRanges)] */ IA2Range** ranges,
/* [out, retval] */ long *nRanges);
// Helper method
static HRESULT ConvertToIA2Attributes(nsIPersistentProperties* aAttributes,
BSTR* aIA2Attributes);

Просмотреть файл

@ -6,7 +6,7 @@
#include "xpcAccessibleTextRange.h"
#include "TextRange.h"
#include "TextRange-inl.h"
#include "xpcAccessibleDocument.h"
#include "nsIMutableArray.h"
@ -170,6 +170,16 @@ xpcAccessibleTextRange::Normalize(uint32_t aUnit)
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibleTextRange::Crop(nsIAccessible* aContainer, bool* aSuccess)
{
Accessible* container = aContainer->ToInternalAccessible();
NS_ENSURE_TRUE(container, NS_ERROR_INVALID_ARG);
*aSuccess = mRange.Crop(container);
return NS_OK;
}
NS_IMETHODIMP
xpcAccessibleTextRange::FindText(const nsAString& aText, bool aIsBackward,
bool aIsIgnoreCase,

Просмотреть файл

@ -49,6 +49,7 @@ public:
NS_IMETHOD MoveStart(uint32_t aUnit, int32_t aCount) final override;
NS_IMETHOD MoveEnd(uint32_t aUnit, int32_t aCount) final override;
NS_IMETHOD Normalize(uint32_t aUnit) final override;
NS_IMETHOD Crop(nsIAccessible* aContainer, bool* aSuccess) final override;
NS_IMETHOD FindText(const nsAString& aText, bool aIsBackward, bool aIsIgnoreCase,
nsIAccessibleTextRange** aRange) final override;
NS_IMETHOD FindAttr(uint32_t aAttr, nsIVariant* aVal, bool aIsBackward,

Просмотреть файл

@ -1394,8 +1394,9 @@ pref("dom.identity.enabled", false);
// Block insecure active content on https pages
pref("security.mixed_content.block_active_content", true);
// Show degraded UI for http pages with password fields
#ifdef NIGHTLY_BUILD
// Show degraded UI for http pages with password fields.
// Only for Nightly and Dev Edition for not, not for beta or release.
#ifndef RELEASE_BUILD
pref("security.insecure_password.ui.enabled", true);
#else
pref("security.insecure_password.ui.enabled", false);
@ -1404,6 +1405,8 @@ pref("security.insecure_password.ui.enabled", false);
// 1 = allow MITM for certificate pinning checks.
pref("security.cert_pinning.enforcement_level", 1);
// NB: Changes to this pref affect CERT_CHAIN_SHA1_POLICY_STATUS telemetry.
// See the comment in CertVerifier.cpp.
// 0 = allow SHA-1
pref("security.pki.sha1_enforcement_level", 0);

Просмотреть файл

@ -135,11 +135,17 @@
el.parentNode.removeChild(el);
el = document.getElementById("errorShortDescText_forbidden");
el.parentNode.removeChild(el);
el = document.getElementById("whyForbiddenButton");
el.parentNode.removeChild(el);
} else {
el = document.getElementById("ignoreWarningButton");
el.parentNode.removeChild(el);
el = document.getElementById("reportButton");
el.parentNode.removeChild(el);
// Remove red style: A "forbidden site" does not warrant the same level
// of anxiety as a security concern.
document.documentElement.className = "";
}
// Set sitename
@ -197,7 +203,7 @@
<h1 id="errorTitleText_phishing">&safeb.blocked.phishingPage.title;</h1>
<h1 id="errorTitleText_malware">&safeb.blocked.malwarePage.title;</h1>
<h1 id="errorTitleText_unwanted">&safeb.blocked.unwantedPage.title;</h1>
<h1 id="errorTitleText_forbidden">&safeb.blocked.forbiddenPage.title;</h1>
<h1 id="errorTitleText_forbidden">&safeb.blocked.forbiddenPage.title2;</h1>
</div>
<div id="errorLongContent">
@ -207,7 +213,7 @@
<p id="errorShortDescText_phishing">&safeb.blocked.phishingPage.shortDesc;</p>
<p id="errorShortDescText_malware">&safeb.blocked.malwarePage.shortDesc;</p>
<p id="errorShortDescText_unwanted">&safeb.blocked.unwantedPage.shortDesc;</p>
<p id="errorShortDescText_forbidden">&safeb.blocked.forbiddenPage.shortDesc;</p>
<p id="errorShortDescText_forbidden">&safeb.blocked.forbiddenPage.shortDesc2;</p>
</div>
<!-- Long Description -->
@ -222,6 +228,7 @@
<!-- Commands handled in browser.js -->
<button id="getMeOutButton">&safeb.palm.accept.label;</button>
<button id="reportButton">&safeb.palm.reportPage.label;</button>
<button id="whyForbiddenButton">&safeb.palm.whyForbidden.label;</button>
</div>
</div>
<div id="ignoreWarning">

Просмотреть файл

@ -2913,6 +2913,12 @@ var BrowserOnClick = {
this.ignoreWarningButton(reason);
}
break;
case "whyForbiddenButton":
// This is the "Why is this site blocked" button for family friendly browsing
// for Fennec. There's no desktop focused support page yet.
gBrowser.loadURI("https://support.mozilla.org/kb/controlledaccess");
break;
}
},

Просмотреть файл

@ -6031,8 +6031,11 @@
// visual status to selected until after we receive confirmation that its content has painted.
this._logicallySelected = val;
// If we're non-e10s we should update the visual selection as well at the same time
if (!gMultiProcessBrowser) {
// If we're non-e10s we should update the visual selection as well at the same time,
// *or* if we're e10s and the visually selected tab isn't changing, in which case the
// tab switcher code won't run and update anything else (like the before- and after-
// selected attributes).
if (!gMultiProcessBrowser || (val && this.hasAttribute("visuallyselected"))) {
this._visuallySelected = val;
}

Просмотреть файл

@ -554,7 +554,7 @@ add_task(function* test_offline_cache() {
// Store something to the offline cache
var appcacheserv = Cc["@mozilla.org/network/application-cache-service;1"]
.getService(Ci.nsIApplicationCacheService);
var appcachegroupid = appcacheserv.buildGroupID(makeURI(URL + "/manifest"), LoadContextInfo.default);
var appcachegroupid = appcacheserv.buildGroupIDForInfo(makeURI(URL + "/manifest"), LoadContextInfo.default);
var appcache = appcacheserv.createApplicationCache(appcachegroupid);
var storage = Services.cache2.appCacheStorage(LoadContextInfo.default, appcache);

Просмотреть файл

@ -4,4 +4,3 @@ support-files =
file_reflect_cookie_into_title.html
[browser_usercontext.js]
skip-if = e10s

Просмотреть файл

@ -161,7 +161,7 @@ FirefoxProfileMigrator.prototype._getResourcesInternal = function(sourceProfileD
}
}
// FHR related migrations.
// Telemetry related migrations.
let times = {
name: "times", // name is used only by tests.
type: types.OTHERDATA,
@ -178,69 +178,60 @@ FirefoxProfileMigrator.prototype._getResourcesInternal = function(sourceProfileD
);
}
};
let healthReporter = {
name: "healthreporter", // name is used only by tests...
let telemetry = {
name: "telemetry", // name is used only by tests...
type: types.OTHERDATA,
migrate: aCallback => {
// the health-reporter can't have been initialized yet so it's safe to
// copy the SQL file.
let createSubDir = (name) => {
let dir = currentProfileDir.clone();
dir.append(name);
dir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
return dir;
};
// We only support the default database name - copied from healthreporter.jsm
const DEFAULT_DATABASE_NAME = "healthreport.sqlite";
let path = OS.Path.join(sourceProfileDir.path, DEFAULT_DATABASE_NAME);
let sqliteFile = FileUtils.File(path);
if (sqliteFile.exists()) {
sqliteFile.copyTo(currentProfileDir, "");
}
// In unusual cases there may be 2 additional files - a "write ahead log"
// (-wal) file and a "shared memory file" (-shm). The wal file contains
// data that will be replayed when the DB is next opened, while the shm
// file is ignored in that case - the replay happens using only the wal.
// So we *do* copy a wal if it exists, but not a shm.
// See https://www.sqlite.org/tempfiles.html for more.
// (Note also we attempt these copies even if we can't find the DB, and
// rely on FHR itself to do the right thing if it can)
path = OS.Path.join(sourceProfileDir.path, DEFAULT_DATABASE_NAME + "-wal");
let sqliteWal = FileUtils.File(path);
if (sqliteWal.exists()) {
sqliteWal.copyTo(currentProfileDir, "");
}
// If the 'healthreport' directory exists we copy everything from it.
let subdir = this._getFileObject(sourceProfileDir, "healthreport");
// If the 'datareporting' directory exists we migrate files from it.
let haveStateFile = false;
let subdir = this._getFileObject(sourceProfileDir, "datareporting");
if (subdir && subdir.isDirectory()) {
// Copy all regular files.
let dest = currentProfileDir.clone();
dest.append("healthreport");
dest.create(Components.interfaces.nsIFile.DIRECTORY_TYPE,
FileUtils.PERMS_DIRECTORY);
// Copy only specific files.
let toCopy = ["state.json", "session-state.json"];
let dest = createSubDir("datareporting");
let enumerator = subdir.directoryEntries;
while (enumerator.hasMoreElements()) {
let file = enumerator.getNext().QueryInterface(Components.interfaces.nsIFile);
if (file.isDirectory()) {
let file = enumerator.getNext().QueryInterface(Ci.nsIFile);
if (file.isDirectory() || toCopy.indexOf(file.leafName) == -1) {
continue;
}
if (file.leafName == "state.json") {
haveStateFile = true;
}
file.copyTo(dest, "");
}
}
// If the 'datareporting' directory exists we copy just state.json
subdir = this._getFileObject(sourceProfileDir, "datareporting");
if (subdir && subdir.isDirectory()) {
let stateFile = this._getFileObject(subdir, "state.json");
if (stateFile) {
let dest = currentProfileDir.clone();
dest.append("datareporting");
dest.create(Components.interfaces.nsIFile.DIRECTORY_TYPE,
FileUtils.PERMS_DIRECTORY);
stateFile.copyTo(dest, "");
if (!haveStateFile) {
// Fall back to migrating the state file that contains the client id from healthreport/.
// We first moved the client id management from the FHR implementation to the datareporting
// service.
// Consequently, we try to migrate an existing FHR state file here as a fallback.
let subdir = this._getFileObject(sourceProfileDir, "healthreport");
if (subdir && subdir.isDirectory()) {
let stateFile = this._getFileObject(subdir, "state.json");
if (stateFile) {
let dest = createSubDir("healthreport");
stateFile.copyTo(dest, "");
}
}
}
aCallback(true);
}
}
return [places, cookies, passwords, formData, dictionary, bookmarksBackups,
session, times, healthReporter].filter(r => r);
session, times, telemetry].filter(r => r);
};
Object.defineProperty(FirefoxProfileMigrator.prototype, "startupOnlyMigrator", {

Просмотреть файл

@ -77,6 +77,13 @@ function writeToFile(dir, leafName, contents) {
outputStream.close();
}
function createSubDir(dir, subDirName) {
let subDir = dir.clone();
subDir.append(subDirName);
subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
return subDir;
}
function promiseMigrator(name, srcDir, targetDir) {
let migrator = Cc["@mozilla.org/profile/migrator;1?app=browser&type=firefox"]
.createInstance(Ci.nsISupports)
@ -92,150 +99,168 @@ function promiseMigrator(name, srcDir, targetDir) {
throw new Error("failed to find the " + name + " migrator");
}
function promiseFHRMigrator(srcDir, targetDir) {
return promiseMigrator("healthreporter", srcDir, targetDir);
function promiseTelemetryMigrator(srcDir, targetDir) {
return promiseMigrator("telemetry", srcDir, targetDir);
}
add_task(function* test_empty() {
let [srcDir, targetDir] = getTestDirs();
let ok = yield promiseFHRMigrator(srcDir, targetDir);
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true with empty directories");
// check both are empty
checkDirectoryContains(srcDir, {});
checkDirectoryContains(targetDir, {});
});
add_task(function* test_just_sqlite() {
add_task(function* test_migrate_files() {
let [srcDir, targetDir] = getTestDirs();
let contents = "hello there\n\n";
writeToFile(srcDir, "healthreport.sqlite", contents);
let ok = yield promiseFHRMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true with sqlite file copied");
checkDirectoryContains(targetDir, {
"healthreport.sqlite": contents,
// Set up datareporting files, some to copy, some not.
let stateContent = JSON.stringify({
clientId: "68d5474e-19dc-45c1-8e9a-81fca592707c",
});
});
let sessionStateContent = "foobar 5432";
let subDir = createSubDir(srcDir, "datareporting");
writeToFile(subDir, "state.json", stateContent);
writeToFile(subDir, "session-state.json", sessionStateContent);
writeToFile(subDir, "other.file", "do not copy");
add_task(function* test_sqlite_extras() {
let [srcDir, targetDir] = getTestDirs();
let archived = createSubDir(subDir, "archived");
writeToFile(archived, "other.file", "do not copy");
let contents_sqlite = "hello there\n\n";
writeToFile(srcDir, "healthreport.sqlite", contents_sqlite);
// Set up FHR files, they should not be copied.
writeToFile(srcDir, "healthreport.sqlite", "do not copy");
writeToFile(srcDir, "healthreport.sqlite-wal", "do not copy");
subDir = createSubDir(srcDir, "healthreport");
writeToFile(subDir, "state.json", "do not copy");
writeToFile(subDir, "other.file", "do not copy");
let contents_wal = "this is the wal\n\n";
writeToFile(srcDir, "healthreport.sqlite-wal", contents_wal);
// and the -shm - this should *not* be copied.
writeToFile(srcDir, "healthreport.sqlite-shm", "whatever");
let ok = yield promiseFHRMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true with sqlite file copied");
// Perform migration.
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true with important telemetry files copied");
checkDirectoryContains(targetDir, {
"healthreport.sqlite": contents_sqlite,
"healthreport.sqlite-wal": contents_wal,
});
});
add_task(function* test_sqlite_healthreport_not_dir() {
let [srcDir, targetDir] = getTestDirs();
let contents = "hello there\n\n";
writeToFile(srcDir, "healthreport.sqlite", contents);
writeToFile(srcDir, "healthreport", "I'm a file but should be a directory");
let ok = yield promiseFHRMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true even though the directory was a file");
// We should have only the sqlite file
checkDirectoryContains(targetDir, {
"healthreport.sqlite": contents,
});
});
add_task(function* test_sqlite_healthreport_empty() {
let [srcDir, targetDir] = getTestDirs();
let contents = "hello there\n\n";
writeToFile(srcDir, "healthreport.sqlite", contents);
// create an empty 'healthreport' subdir.
let subDir = srcDir.clone();
subDir.append("healthreport");
subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let ok = yield promiseFHRMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
// we should end up with the .sqlite file and an empty subdir in the target.
checkDirectoryContains(targetDir, {
"healthreport.sqlite": contents,
"healthreport": {},
});
});
add_task(function* test_sqlite_healthreport_contents() {
let [srcDir, targetDir] = getTestDirs();
let contents = "hello there\n\n";
writeToFile(srcDir, "healthreport.sqlite", contents);
// create an empty 'healthreport' subdir.
let subDir = srcDir.clone();
subDir.append("healthreport");
subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
writeToFile(subDir, "file1", "this is file 1");
writeToFile(subDir, "file2", "this is file 2");
let ok = yield promiseFHRMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
// we should end up with the .sqlite file and an empty subdir in the target.
checkDirectoryContains(targetDir, {
"healthreport.sqlite": contents,
"healthreport": {
"file1": "this is file 1",
"file2": "this is file 2",
"datareporting": {
"state.json": stateContent,
"session-state.json": sessionStateContent,
},
});
});
add_task(function* test_fallback_fhr_state() {
let [srcDir, targetDir] = getTestDirs();
// Test that we fall back to migrating FHR state if the datareporting
// state file does not exist.
let stateContent = JSON.stringify({
clientId: "68d5474e-19dc-45c1-8e9a-81fca592707c",
});
let subDir = createSubDir(srcDir, "healthreport");
writeToFile(subDir, "state.json", stateContent);
// Perform migration.
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
checkDirectoryContains(targetDir, {
"healthreport": {
"state.json": stateContent,
},
});
});
add_task(function* test_datareporting_not_dir() {
let [srcDir, targetDir] = getTestDirs();
writeToFile(srcDir, "datareporting", "I'm a file but should be a directory");
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true even though the directory was a file");
checkDirectoryContains(targetDir, {});
});
add_task(function* test_datareporting_empty() {
let [srcDir, targetDir] = getTestDirs();
// create an empty 'datareporting' subdir.
let subDir = srcDir.clone();
subDir.append("datareporting");
subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
let ok = yield promiseFHRMigrator(srcDir, targetDir);
// Migrate with an empty 'datareporting' subdir.
let subDir = createSubDir(srcDir, "datareporting");
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
// we should end up with nothing at all in the destination - state.json was
// missing so we didn't even create the target dir.
// We should end up with no migrated files.
checkDirectoryContains(targetDir, {
"datareporting": {},
});
});
add_task(function* test_healthreport_empty() {
let [srcDir, targetDir] = getTestDirs();
// Migrate with no 'datareporting' and an empty 'healthreport' subdir.
let subDir = createSubDir(srcDir, "healthreport");
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
// We should end up with no migrated files.
checkDirectoryContains(targetDir, {});
});
add_task(function* test_datareporting_many() {
let [srcDir, targetDir] = getTestDirs();
// create an empty 'datareporting' subdir.
let subDir = srcDir.clone();
subDir.append("datareporting");
subDir.create(Ci.nsIFile.DIRECTORY_TYPE, FileUtils.PERMS_DIRECTORY);
writeToFile(subDir, "state.json", "should be copied");
// Create some datareporting files.
let subDir = createSubDir(srcDir, "datareporting");
let shouldBeCopied = "should be copied";
writeToFile(subDir, "state.json", shouldBeCopied);
writeToFile(subDir, "session-state.json", shouldBeCopied);
writeToFile(subDir, "something.else", "should not");
createSubDir(subDir, "emptyDir");
let ok = yield promiseFHRMigrator(srcDir, targetDir);
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
checkDirectoryContains(targetDir, {
"datareporting" : {
"state.json": "should be copied",
"state.json": shouldBeCopied,
"session-state.json": shouldBeCopied,
}
});
});
add_task(function* test_no_session_state() {
let [srcDir, targetDir] = getTestDirs();
// Check that migration still works properly if we only have state.json.
let subDir = createSubDir(srcDir, "datareporting");
let stateContent = "abcd984";
writeToFile(subDir, "state.json", stateContent);
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
checkDirectoryContains(targetDir, {
"datareporting" : {
"state.json": stateContent,
}
});
});
add_task(function* test_no_state() {
let [srcDir, targetDir] = getTestDirs();
// Check that migration still works properly if we only have session-state.json.
let subDir = createSubDir(srcDir, "datareporting");
let sessionStateContent = "abcd512";
writeToFile(subDir, "session-state.json", sessionStateContent);
let ok = yield promiseTelemetryMigrator(srcDir, targetDir);
Assert.ok(ok, "callback should have been true");
checkDirectoryContains(targetDir, {
"datareporting" : {
"session-state.json": sessionStateContent,
}
});
});

Просмотреть файл

@ -12,7 +12,7 @@ skip-if = os != "mac" # Relies on ULibDir
[test_Chrome_passwords.js]
skip-if = os != "win"
[test_Edge_availability.js]
[test_fx_fhr.js]
[test_fx_telemetry.js]
[test_IE_bookmarks.js]
skip-if = os != "win"
[test_IE_cookies.js]

Просмотреть файл

@ -14,37 +14,28 @@ support-files =
webapi.html
[browser_426329.js]
skip-if = e10s # Bug ?????? - Test uses load event and checks event.target.
[browser_483086.js]
[browser_addEngine.js]
[browser_amazon.js]
[browser_amazon_behavior.js]
skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
[browser_bing.js]
[browser_bing_behavior.js]
skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
[browser_contextmenu.js]
skip-if = e10s # Bug ?????? - Test touches content (content.window.getSelection().QueryInterface(Ci.nsISelectionPrivate)....)
[browser_eBay.js]
[browser_eBay_behavior.js]
skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
[browser_google.js]
[browser_google_behavior.js]
skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
[browser_healthreport.js]
[browser_hiddenOneOffs_cleanup.js]
[browser_hiddenOneOffs_diacritics.js]
[browser_oneOffHeader.js]
skip-if = e10s # bug ?????? - Test alters the searchbar textbox value which causes issues with other tests in e10s.
[browser_private_search_perwindowpb.js]
skip-if = e10s # Bug ?????? - Test uses load event and checks event.target.
[browser_yahoo.js]
[browser_yahoo_behavior.js]
skip-if = e10s # Bug ?????? - some issue with progress listeners [JavaScript Error: "req.originalURI is null" {file: "chrome://mochitests/content/browser/browser/components/search/test/browser_bing_behavior.js" line: 127}]
[browser_abouthome_behavior.js]
skip-if = e10s || true # Bug ??????, Bug 1100301 - leaks windows until shutdown when --run-by-dir
skip-if = true # Bug ??????, Bug 1100301 - leaks windows until shutdown when --run-by-dir
[browser_searchbar_openpopup.js]
skip-if = os == "linux" || e10s # Linux has different focus behaviours and e10s seems to have timing issues.
skip-if = os == "linux" # Linux has different focus behaviours.
[browser_searchbar_keyboard_navigation.js]
[browser_searchbar_smallpanel_keyboard_navigation.js]
[browser_webapi.js]

Просмотреть файл

@ -1,14 +1,5 @@
// Instead of loading ChromeUtils.js into the test scope in browser-test.js for all tests,
// we only need ChromeUtils.js for a few files which is why we are using loadSubScript.
var ChromeUtils = {};
this._scriptLoader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Ci.mozIJSSubScriptLoader);
this._scriptLoader.loadSubScript("chrome://mochikit/content/tests/SimpleTest/ChromeUtils.js", ChromeUtils);
XPCOMUtils.defineLazyModuleGetter(this, "FormHistory",
"resource://gre/modules/FormHistory.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
function expectedURL(aSearchTerms) {
const ENGINE_HTML_BASE = "http://mochi.test:8888/browser/browser/components/search/test/test.html";
@ -53,73 +44,71 @@ function getMenuEntries() {
return entries;
}
function* countEntries(name, value) {
let deferred = Promise.defer();
let count = 0;
let obj = name && value ? {fieldname: name, value: value} : {};
FormHistory.count(obj,
{ handleResult: function(result) { count = result; },
handleError: function(error) { throw error; },
handleCompletion: function(reason) {
if (!reason) {
deferred.resolve(count);
function countEntries(name, value) {
return new Promise(resolve => {
let count = 0;
let obj = name && value ? {fieldname: name, value: value} : {};
FormHistory.count(obj,
{ handleResult: function(result) { count = result; },
handleError: function(error) { throw error; },
handleCompletion: function(reason) {
if (!reason) {
resolve(count);
}
}
}
});
return deferred.promise;
});
});
}
var searchBar;
var searchButton;
var searchEntries = ["test"];
function* promiseSetEngine() {
let deferred = Promise.defer();
var ss = Services.search;
function promiseSetEngine() {
return new Promise(resolve => {
var ss = Services.search;
function observer(aSub, aTopic, aData) {
switch (aData) {
case "engine-added":
var engine = ss.getEngineByName("Bug 426329");
ok(engine, "Engine was added.");
ss.currentEngine = engine;
break;
case "engine-current":
ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
searchBar = BrowserSearch.searchBar;
searchButton = document.getAnonymousElementByAttribute(searchBar,
"anonid", "search-go-button");
ok(searchButton, "got search-go-button");
searchBar.value = "test";
function observer(aSub, aTopic, aData) {
switch (aData) {
case "engine-added":
var engine = ss.getEngineByName("Bug 426329");
ok(engine, "Engine was added.");
ss.currentEngine = engine;
break;
case "engine-current":
ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");
searchBar = BrowserSearch.searchBar;
searchButton = document.getAnonymousElementByAttribute(searchBar,
"anonid", "search-go-button");
ok(searchButton, "got search-go-button");
searchBar.value = "test";
Services.obs.removeObserver(observer, "browser-search-engine-modified");
deferred.resolve();
break;
}
};
Services.obs.removeObserver(observer, "browser-search-engine-modified");
resolve();
break;
}
};
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
ss.addEngine("http://mochi.test:8888/browser/browser/components/search/test/426329.xml",
null, "data:image/x-icon,%00", false);
return deferred.promise;
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
ss.addEngine("http://mochi.test:8888/browser/browser/components/search/test/426329.xml",
null, "data:image/x-icon,%00", false);
});
}
function* promiseRemoveEngine() {
let deferred = Promise.defer();
var ss = Services.search;
function promiseRemoveEngine() {
return new Promise(resolve => {
var ss = Services.search;
function observer(aSub, aTopic, aData) {
if (aData == "engine-removed") {
Services.obs.removeObserver(observer, "browser-search-engine-modified");
deferred.resolve();
}
};
function observer(aSub, aTopic, aData) {
if (aData == "engine-removed") {
Services.obs.removeObserver(observer, "browser-search-engine-modified");
resolve();
}
};
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
var engine = ss.getEngineByName("Bug 426329");
ss.removeEngine(engine);
return deferred.promise;
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
var engine = ss.getEngineByName("Bug 426329");
ss.removeEngine(engine);
});
}
@ -130,22 +119,15 @@ function* prepareTest() {
preTabNo = gBrowser.tabs.length;
searchBar = BrowserSearch.searchBar;
let windowFocused = Promise.defer();
SimpleTest.waitForFocus(windowFocused.resolve, window);
yield windowFocused.promise;
yield SimpleTest.promiseFocus();
let deferred = Promise.defer();
if (document.activeElement != searchBar) {
searchBar.addEventListener("focus", function onFocus() {
searchBar.removeEventListener("focus", onFocus);
deferred.resolve();
});
gURLBar.focus();
searchBar.focus();
} else {
deferred.resolve();
}
return deferred.promise;
if (document.activeElement == searchBar)
return;
let focusPromise = BrowserTestUtils.waitForEvent(searchBar, "focus");
gURLBar.focus();
searchBar.focus();
yield focusPromise;
}
add_task(function* testSetupEngine() {
@ -153,90 +135,81 @@ add_task(function* testSetupEngine() {
});
add_task(function* testReturn() {
yield prepareTest();
yield* prepareTest();
EventUtils.synthesizeKey("VK_RETURN", {});
let event = yield promiseOnLoad();
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
is(gBrowser.tabs.length, preTabNo, "Return key did not open new tab");
is(event.originalTarget, preSelectedBrowser.contentDocument,
"Return key loaded results in current tab");
is(event.originalTarget.URL, expectedURL(searchBar.value), "testReturn opened correct search page");
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testReturn opened correct search page");
});
add_task(function* testAltReturn() {
yield prepareTest();
EventUtils.synthesizeKey("VK_RETURN", { altKey: true });
let event = yield promiseOnLoad();
yield* prepareTest();
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
EventUtils.synthesizeKey("VK_RETURN", { altKey: true });
});
is(gBrowser.tabs.length, preTabNo + 1, "Alt+Return key added new tab");
isnot(event.originalTarget, preSelectedBrowser.contentDocument,
"Alt+Return key loaded results in new tab");
is(event.originalTarget, gBrowser.contentDocument,
"Alt+Return key loaded results in foreground tab");
is(event.originalTarget.URL, expectedURL(searchBar.value), "testAltReturn opened correct search page");
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testAltReturn opened correct search page");
});
//Shift key has no effect for now, so skip it
add_task(function* testShiftAltReturn() {
return;
yield prepareTest();
yield* prepareTest();
let url = expectedURL(searchBar.value);
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
EventUtils.synthesizeKey("VK_RETURN", { shiftKey: true, altKey: true });
let event = yield promiseOnLoad();
let newTab = yield newTabPromise;
is(gBrowser.tabs.length, preTabNo + 1, "Shift+Alt+Return key added new tab");
isnot(event.originalTarget, preSelectedBrowser.contentDocument,
"Shift+Alt+Return key loaded results in new tab");
isnot(event.originalTarget, gBrowser.contentDocument,
"Shift+Alt+Return key loaded results in background tab");
is(event.originalTarget.URL, expectedURL(searchBar.value), "testShiftAltReturn opened correct search page");
is(gBrowser.currentURI.spec, url, "testShiftAltReturn opened correct search page");
});
add_task(function* testLeftClick() {
yield prepareTest();
yield* prepareTest();
simulateClick({ button: 0 }, searchButton);
let event = yield promiseOnLoad();
yield BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
is(gBrowser.tabs.length, preTabNo, "LeftClick did not open new tab");
is(event.originalTarget, preSelectedBrowser.contentDocument,
"LeftClick loaded results in current tab");
is(event.originalTarget.URL, expectedURL(searchBar.value), "testLeftClick opened correct search page");
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testLeftClick opened correct search page");
});
add_task(function* testMiddleClick() {
yield prepareTest();
simulateClick({ button: 1 }, searchButton);
let event = yield promiseOnLoad();
yield* prepareTest();
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
simulateClick({ button: 1 }, searchButton);
});
is(gBrowser.tabs.length, preTabNo + 1, "MiddleClick added new tab");
isnot(event.originalTarget, preSelectedBrowser.contentDocument,
"MiddleClick loaded results in new tab");
is(event.originalTarget, gBrowser.contentDocument,
"MiddleClick loaded results in foreground tab");
is(event.originalTarget.URL, expectedURL(searchBar.value), "testMiddleClick opened correct search page");
is(gBrowser.currentURI.spec, expectedURL(searchBar.value), "testMiddleClick opened correct search page");
});
add_task(function* testShiftMiddleClick() {
yield prepareTest();
yield* prepareTest();
let url = expectedURL(searchBar.value);
let newTabPromise = BrowserTestUtils.waitForNewTab(gBrowser, url);
simulateClick({ button: 1, shiftKey: true }, searchButton);
let event = yield promiseOnLoad();
let newTab = yield newTabPromise;
is(gBrowser.tabs.length, preTabNo + 1, "Shift+MiddleClick added new tab");
isnot(event.originalTarget, preSelectedBrowser.contentDocument,
"Shift+MiddleClick loaded results in new tab");
isnot(event.originalTarget, gBrowser.contentDocument,
"Shift+MiddleClick loaded results in background tab");
is(event.originalTarget.URL, expectedURL(searchBar.value), "testShiftMiddleClick opened correct search page");
is(newTab.linkedBrowser.currentURI.spec, url, "testShiftMiddleClick opened correct search page");
});
add_task(function* testRightClick() {
preTabNo = gBrowser.tabs.length;
content.location.href = "about:blank";
simulateClick({ button: 2 }, searchButton);
let deferred = Promise.defer();
setTimeout(function() {
is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
deferred.resolve();
}, 5000);
yield deferred.promise;
gBrowser.selectedBrowser.loadURI("about:blank");
yield new Promise(resolve => {
setTimeout(function() {
is(gBrowser.tabs.length, preTabNo, "RightClick did not open new tab");
is(gBrowser.currentURI.spec, "about:blank", "RightClick did nothing");
resolve();
}, 5000);
simulateClick({ button: 2 }, searchButton);
});
// The click in the searchbox focuses it, which opens the suggestion
// panel. Clean up after ourselves.
searchBar.textbox.popup.hidePopup();
@ -252,7 +225,7 @@ add_task(function* testSearchHistory() {
add_task(function* testAutocomplete() {
var popup = searchBar.textbox.popup;
let popupShownPromise = promiseEvent(popup, "popupshown");
let popupShownPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
searchBar.textbox.showHistoryPopup();
yield popupShownPromise;
checkMenuEntries(searchEntries);
@ -271,6 +244,6 @@ add_task(function* asyncCleanup() {
while (gBrowser.tabs.length != 1) {
gBrowser.removeTab(gBrowser.tabs[0], {animate: false});
}
content.location.href = "about:blank";
gBrowser.selectedBrowser.loadURI("about:blank");
yield promiseRemoveEngine();
});

Просмотреть файл

@ -119,6 +119,9 @@ function test() {
if (!(flags & docStart) || !webProgress.isTopLevel)
return;
if (req.originalURI.spec == "about:blank")
return;
info("received document start");
ok(req instanceof Ci.nsIChannel, "req is a channel");

Просмотреть файл

@ -136,6 +136,9 @@ function test() {
if (!(flags & docStart) || !webProgress.isTopLevel)
return;
if (req.originalURI.spec == "about:blank")
return;
info("received document start");
ok(req instanceof Ci.nsIChannel, "req is a channel");

Просмотреть файл

@ -136,6 +136,9 @@ function test() {
if (!(flags & docStart) || !webProgress.isTopLevel)
return;
if (req.originalURI.spec == "about:blank")
return;
info("received document start");
ok(req instanceof Ci.nsIChannel, "req is a channel");

Просмотреть файл

@ -4,9 +4,7 @@
* Test searching for the selected text using the context menu
*/
function test() {
waitForExplicitFinish();
add_task(function* () {
const ss = Services.search;
const ENGINE_NAME = "Foo";
var contextMenu;
@ -22,90 +20,79 @@ function test() {
resProt.setSubstitution("search-plugins",
Services.io.newURI(url, null, null));
function observer(aSub, aTopic, aData) {
switch (aData) {
case "engine-added":
var engine = ss.getEngineByName(ENGINE_NAME);
ok(engine, "Engine was added.");
ss.currentEngine = engine;
envService.set("XPCSHELL_TEST_PROFILE_DIR", originalValue);
resProt.setSubstitution("search-plugins", originalSubstitution);
break;
case "engine-current":
is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
startTest();
break;
case "engine-removed":
Services.obs.removeObserver(observer, "browser-search-engine-modified");
finish();
break;
}
}
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
ss.addEngine("resource://search-plugins/testEngine_mozsearch.xml",
null, "data:image/x-icon,%00", false);
function startTest() {
contextMenu = document.getElementById("contentAreaContextMenu");
ok(contextMenu, "Got context menu XUL");
doOnloadOnce(testContextMenu);
let tab = gBrowser.selectedTab = gBrowser.addTab("data:text/plain;charset=utf8,test%20search");
registerCleanupFunction(function () {
gBrowser.removeTab(tab);
});
}
function testContextMenu() {
function rightClickOnDocument() {
info("rightClickOnDocument: " + content.window.location);
waitForBrowserContextMenu(checkContextMenu);
var clickTarget = content.document.body;
var eventDetails = { type: "contextmenu", button: 2 };
EventUtils.synthesizeMouseAtCenter(clickTarget, eventDetails, content);
}
// check the search menu item and then perform a search
function checkContextMenu() {
info("checkContextMenu");
var searchItem = contextMenu.getElementsByAttribute("id", "context-searchselect")[0];
ok(searchItem, "Got search context menu item");
is(searchItem.label, 'Search ' + ENGINE_NAME + ' for "test search"', "Check context menu label");
is(searchItem.disabled, false, "Check that search context menu item is enabled");
doOnloadOnce(checkSearchURL);
searchItem.click();
contextMenu.hidePopup();
}
function checkSearchURL(event) {
is(event.originalTarget.URL,
"http://mochi.test:8888/browser/browser/components/search/test/?test=test+search&ie=utf-8&channel=contextsearch",
"Checking context menu search URL");
// Remove the tab opened by the search
gBrowser.removeCurrentTab();
ss.removeEngine(ss.currentEngine);
}
var selectionListener = {
notifySelectionChanged: function(doc, sel, reason) {
if (reason != Ci.nsISelectionListener.SELECTALL_REASON || sel.toString() != "test search")
return;
info("notifySelectionChanged: Text selected");
content.window.getSelection().QueryInterface(Ci.nsISelectionPrivate).
removeSelectionListener(selectionListener);
SimpleTest.executeSoon(rightClickOnDocument);
let searchDonePromise;
yield new Promise(resolve => {
function observer(aSub, aTopic, aData) {
switch (aData) {
case "engine-added":
var engine = ss.getEngineByName(ENGINE_NAME);
ok(engine, "Engine was added.");
ss.currentEngine = engine;
envService.set("XPCSHELL_TEST_PROFILE_DIR", originalValue);
resProt.setSubstitution("search-plugins", originalSubstitution);
break;
case "engine-current":
is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");
resolve();
break;
case "engine-removed":
Services.obs.removeObserver(observer, "browser-search-engine-modified");
if (searchDonePromise) {
searchDonePromise();
}
break;
}
};
}
// Delay the select all to avoid intermittent selection failures.
setTimeout(function delaySelectAll() {
info("delaySelectAll: " + content.window.location.toString());
// add a listener to know when the selection takes effect
content.window.getSelection().QueryInterface(Ci.nsISelectionPrivate).
addSelectionListener(selectionListener);
// select the text on the page
goDoCommand('cmd_selectAll');
}, 500);
}
}
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
ss.addEngine("resource://search-plugins/testEngine_mozsearch.xml",
null, "data:image/x-icon,%00", false);
});
contextMenu = document.getElementById("contentAreaContextMenu");
ok(contextMenu, "Got context menu XUL");
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, "data:text/plain;charset=utf8,test%20search");
yield ContentTask.spawn(tab.linkedBrowser, "", function*() {
return new Promise(resolve => {
content.document.addEventListener("selectionchange", function selectionChanged() {
content.document.removeEventListener("selectionchange", selectionChanged);
resolve();
});
content.document.getSelection().selectAllChildren(content.document.body);
});
});
var eventDetails = { type: "contextmenu", button: 2 };
let popupPromise = BrowserTestUtils.waitForEvent(contextMenu, "popupshown");
BrowserTestUtils.synthesizeMouseAtCenter("body", eventDetails, gBrowser.selectedBrowser);
yield popupPromise;
info("checkContextMenu");
var searchItem = contextMenu.getElementsByAttribute("id", "context-searchselect")[0];
ok(searchItem, "Got search context menu item");
is(searchItem.label, 'Search ' + ENGINE_NAME + ' for "test search"', "Check context menu label");
is(searchItem.disabled, false, "Check that search context menu item is enabled");
yield BrowserTestUtils.openNewForegroundTab(gBrowser, () => {
searchItem.click();
});
is(gBrowser.currentURI.spec,
"http://mochi.test:8888/browser/browser/components/search/test/?test=test+search&ie=utf-8&channel=contextsearch",
"Checking context menu search URL");
contextMenu.hidePopup();
// Remove the tab opened by the search
gBrowser.removeCurrentTab();
yield new Promise(resolve => {
searchDonePromise = resolve;
ss.removeEngine(ss.currentEngine);
});
gBrowser.removeCurrentTab();
});

Просмотреть файл

@ -136,6 +136,9 @@ function test() {
if (!(flags & docStart) || !webProgress.isTopLevel)
return;
if (req.originalURI.spec == "about:blank")
return;
info("received document start");
ok(req instanceof Ci.nsIChannel, "req is a channel");

Просмотреть файл

@ -134,6 +134,9 @@ function test() {
if (!(flags & docStart) || !webProgress.isTopLevel)
return;
if (req.originalURI.spec == "about:blank")
return;
info("received document start");
ok(req instanceof Ci.nsIChannel, "req is a channel");

Просмотреть файл

@ -2,103 +2,67 @@
// search in a private window, and then checks in the public window
// whether there is an autocomplete entry for the private search.
function test() {
add_task(function* () {
// Don't use about:home as the homepage for new windows
Services.prefs.setIntPref("browser.startup.page", 0);
registerCleanupFunction(() => Services.prefs.clearUserPref("browser.startup.page"));
waitForExplicitFinish();
let engineURL =
"http://mochi.test:8888/browser/browser/components/search/test/";
let windowsToClose = [];
registerCleanupFunction(function() {
let engine = Services.search.getEngineByName("Bug 426329");
Services.search.removeEngine(engine);
windowsToClose.forEach(function(win) {
win.close();
});
});
function onPageLoad(aWin, aCallback) {
aWin.gBrowser.addEventListener("DOMContentLoaded", function load(aEvent) {
let doc = aEvent.originalTarget;
info(doc.location.href);
if (doc.location.href.indexOf(engineURL) != -1) {
aWin.gBrowser.removeEventListener("DOMContentLoaded", load, false);
aCallback();
}
}, false);
}
function performSearch(aWin, aIsPrivate, aCallback) {
function performSearch(aWin, aIsPrivate) {
let searchBar = aWin.BrowserSearch.searchBar;
ok(searchBar, "got search bar");
onPageLoad(aWin, aCallback);
let loadPromise = BrowserTestUtils.browserLoaded(aWin.gBrowser.selectedBrowser);
searchBar.value = aIsPrivate ? "private test" : "public test";
searchBar.focus();
EventUtils.synthesizeKey("VK_RETURN", {}, aWin);
return loadPromise;
}
function addEngine(aCallback) {
let installCallback = {
onSuccess: function (engine) {
Services.search.currentEngine = engine;
aCallback();
},
onError: function (errorCode) {
ok(false, "failed to install engine: " + errorCode);
}
};
Services.search.addEngine(engineURL + "426329.xml", null,
"data:image/x-icon,%00", false, installCallback);
}
function testOnWindow(aIsPrivate, aCallback) {
let win = whenNewWindowLoaded({ private: aIsPrivate }, function() {
waitForFocus(aCallback, win);
});
function* testOnWindow(aIsPrivate) {
let win = yield BrowserTestUtils.openNewBrowserWindow({ private: aIsPrivate });
yield SimpleTest.promiseFocus(win);
windowsToClose.push(win);
return win;
}
addEngine(function() {
testOnWindow(false, function(win) {
performSearch(win, false, function() {
testOnWindow(true, function(win) {
performSearch(win, true, function() {
testOnWindow(false, function(win) {
checkSearchPopup(win, finish);
});
});
});
});
});
});
}
yield promiseNewEngine("426329.xml", { iconURL: "data:image/x-icon,%00" });
function checkSearchPopup(aWin, aCallback) {
let searchBar = aWin.BrowserSearch.searchBar;
let newWindow = yield* testOnWindow(false);
yield performSearch(newWindow, false);
newWindow = yield* testOnWindow(true);
yield performSearch(newWindow, true);
newWindow = yield* testOnWindow(false);
let searchBar = newWindow.BrowserSearch.searchBar;
searchBar.value = "p";
searchBar.focus();
let popup = searchBar.textbox.popup;
popup.addEventListener("popupshowing", function showing() {
popup.removeEventListener("popupshowing", showing, false);
let entries = getMenuEntries(searchBar);
for (let i = 0; i < entries.length; i++) {
isnot(entries[i], "private test",
"shouldn't see private autocomplete entries");
}
searchBar.textbox.toggleHistoryPopup();
searchBar.value = "";
aCallback();
}, false);
let popupPromise = BrowserTestUtils.waitForEvent(popup, "popupshown");
searchBar.textbox.showHistoryPopup();
}
yield popupPromise;
let entries = getMenuEntries(searchBar);
for (let i = 0; i < entries.length; i++) {
isnot(entries[i], "private test",
"shouldn't see private autocomplete entries");
}
searchBar.textbox.toggleHistoryPopup();
searchBar.value = "";
windowsToClose.forEach(function(win) {
win.close();
});
});
function getMenuEntries(searchBar) {
let entries = [];

Просмотреть файл

@ -381,20 +381,8 @@ add_task(function* test_tab_and_arrows() {
});
add_task(function* test_open_search() {
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
let deferred = Promise.defer();
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
deferred.resolve();
}, true);
let rootDir = getRootDirectory(gTestPath);
content.location = rootDir + "opensearch.html";
yield deferred.promise;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, rootDir + "opensearch.html");
let promise = promiseEvent(searchPopup, "popupshown");
info("Opening search panel");

Просмотреть файл

@ -413,7 +413,7 @@ add_no_popup_task(function* search_go_doesnt_open_popup() {
textbox.value = "foo";
searchbar.updateGoButtonVisibility();
let promise = promiseOnLoad();
let promise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
EventUtils.synthesizeMouseAtCenter(goButton, {});
yield promise;

Просмотреть файл

@ -309,20 +309,8 @@ add_task(function* test_tab_and_arrows() {
});
add_task(function* test_open_search() {
let tab = gBrowser.addTab();
gBrowser.selectedTab = tab;
let deferred = Promise.defer();
let browser = gBrowser.selectedBrowser;
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
deferred.resolve();
}, true);
let rootDir = getRootDirectory(gTestPath);
content.location = rootDir + "opensearch.html";
yield deferred.promise;
let tab = yield BrowserTestUtils.openNewForegroundTab(gBrowser, rootDir + "opensearch.html");
let promise = promiseEvent(searchPopup, "popupshown");
info("Opening search panel");

Просмотреть файл

@ -136,6 +136,9 @@ function test() {
if (!(flags & docStart) || !webProgress.isTopLevel)
return;
if (req.originalURI.spec == "about:blank")
return;
info("received document start");
ok(req instanceof Ci.nsIChannel, "req is a channel");

Просмотреть файл

@ -1,20 +1,6 @@
/* Any copyright is dedicated to the Public Domain.
* http://creativecommons.org/publicdomain/zero/1.0/ */
XPCOMUtils.defineLazyModuleGetter(this, "Promise",
"resource://gre/modules/Promise.jsm");
function whenNewWindowLoaded(aOptions, aCallback) {
let win = OpenBrowserWindow(aOptions);
let focused = SimpleTest.promiseFocus(win);
let startupFinished = TestUtils.topicObserved("browser-delayed-startup-finished",
subject => subject == win).then(() => win);
Promise.all([focused, startupFinished])
.then(results => executeSoon(() => aCallback(results[1])));
return win;
}
/**
* Recursively compare two objects and check that every property of expectedObj has the same value
* on actualObj.
@ -53,64 +39,16 @@ function getLocalizedPref(aPrefName, aDefault) {
return aDefault;
}
function waitForPopupShown(aPopupId, aCallback) {
let popup = document.getElementById(aPopupId);
info("waitForPopupShown: got popup: " + popup.id);
function onPopupShown() {
info("onPopupShown");
removePopupShownListener();
SimpleTest.executeSoon(aCallback);
}
function removePopupShownListener() {
popup.removeEventListener("popupshown", onPopupShown);
}
popup.addEventListener("popupshown", onPopupShown);
registerCleanupFunction(removePopupShownListener);
}
function promiseEvent(aTarget, aEventName, aPreventDefault) {
let deferred = Promise.defer();
aTarget.addEventListener(aEventName, function onEvent(aEvent) {
aTarget.removeEventListener(aEventName, onEvent, true);
function cancelEvent(event) {
if (aPreventDefault) {
aEvent.preventDefault();
event.preventDefault();
}
deferred.resolve();
}, true);
return deferred.promise;
}
function waitForBrowserContextMenu(aCallback) {
waitForPopupShown(gBrowser.selectedBrowser.contextMenu, aCallback);
}
function doOnloadOnce(aCallback) {
function doOnloadOnceListener(aEvent) {
info("doOnloadOnce: " + aEvent.originalTarget.location);
removeDoOnloadOnceListener();
SimpleTest.executeSoon(function doOnloadOnceCallback() {
aCallback(aEvent);
});
return true;
}
function removeDoOnloadOnceListener() {
gBrowser.removeEventListener("load", doOnloadOnceListener, true);
}
gBrowser.addEventListener("load", doOnloadOnceListener, true);
registerCleanupFunction(removeDoOnloadOnceListener);
}
function* promiseOnLoad() {
return new Promise(resolve => {
gBrowser.addEventListener("load", function onLoadListener(aEvent) {
let cw = aEvent.target.defaultView;
let tab = gBrowser._getTabForContentWindow(cw);
if (tab) {
info("onLoadListener: " + aEvent.originalTarget.location);
gBrowser.removeEventListener("load", onLoadListener, true);
resolve(aEvent);
}
}, true);
});
return BrowserTestUtils.waitForEvent(aTarget, aEventName, false, cancelEvent);
}
function promiseNewEngine(basename, options = {}) {
@ -123,7 +61,7 @@ function promiseNewEngine(basename, options = {}) {
onInitComplete: function() {
let url = getRootDirectory(gTestPath) + basename;
let current = Services.search.currentEngine;
Services.search.addEngine(url, null, "", false, {
Services.search.addEngine(url, null, options.iconURL || "", false, {
onSuccess: function (engine) {
info("Search engine added: " + basename);
if (setAsCurrent) {

Просмотреть файл

@ -11,15 +11,20 @@ function retrieveUserContextId(browser) {
add_task(function() {
for (let i = 0; i < 3; ++i) {
let tab = gBrowser.addTab("about:blank");
let tab = gBrowser.addTab("http://example.com/", {userContextId: i});
let browser = tab.linkedBrowser;
yield promiseBrowserLoaded(browser);
yield promiseTabState(tab, { userContextId: i, entries: [{ url: "http://example.com/" }] });
let userContextId = yield retrieveUserContextId(browser);
let tab2 = gBrowser.duplicateTab(tab);
let browser2 = tab2.linkedBrowser;
yield promiseTabRestored(tab2)
let userContextId = yield retrieveUserContextId(browser2);
is(userContextId, i, "The docShell has the correct userContextId");
yield promiseRemoveTab(tab);
yield promiseRemoveTab(tab2);
}
});

Просмотреть файл

@ -6,6 +6,7 @@
<!ENTITY safeb.palm.decline.label "Ignore this warning">
<!ENTITY safeb.palm.notforgery.label2 "This isn't a web forgery…">
<!ENTITY safeb.palm.reportPage.label "Why was this page blocked?">
<!ENTITY safeb.palm.whyForbidden.label "Why was this page blocked?">
<!ENTITY safeb.blocked.malwarePage.title "Reported Attack Page!">
<!-- Localization note (safeb.blocked.malwarePage.shortDesc) - Please don't translate the contents of the <span id="malware_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
@ -22,7 +23,7 @@
<!ENTITY safeb.blocked.phishingPage.shortDesc "This web page at <span id='phishing_sitename'/> has been reported as a web forgery and has been blocked based on your security preferences.">
<!ENTITY safeb.blocked.phishingPage.longDesc "<p>Web forgeries are designed to trick you into revealing personal or financial information by imitating sources you may trust.</p><p>Entering any information on this web page may result in identity theft or other fraud.</p>">
<!ENTITY safeb.blocked.forbiddenPage.title "Forbidden Site">
<!-- Localization note (safeb.blocked.forbiddenPage.shortDesc) - Please don't translate the contents of the <span id="forbidden_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.forbiddenPage.shortDesc "This Web page at <span id='forbidden_sitename'/> has been blocked based on your browser configuration.">
<!ENTITY safeb.blocked.forbiddenPage.title2 "Blocked Site">
<!-- Localization note (safeb.blocked.forbiddenPage.shortDesc2) - Please don't translate the contents of the <span id="forbidden_sitename"/> tag. It will be replaced at runtime with a domain name (e.g. www.badsite.com) -->
<!ENTITY safeb.blocked.forbiddenPage.shortDesc2 "The Web page at <span id='forbidden_sitename'/> has been blocked by your admin profile.">

Просмотреть файл

@ -96,9 +96,6 @@ const MIN_VISIBLE_HISTORY_TILES = 8;
// The max number of visible (not blocked) history tiles to test for inadjacency
const MAX_VISIBLE_HISTORY_TILES = 15;
// Divide frecency by this amount for pings
const PING_SCORE_DIVISOR = 10000;
// Allowed ping actions remotely stored as columns: case-insensitive [a-z0-9_]
const PING_ACTIONS = ["block", "click", "pin", "sponsored", "sponsored_link", "unpin", "view"];
@ -566,50 +563,13 @@ var DirectoryLinksProvider = {
}
catch (ex) {}
// Only send pings when enhancing tiles with an endpoint and valid action
// Bug 1240245 - We no longer send pings, but frequency capping and fetching
// tests depend on the following actions, so references to PING remain.
let invalidAction = PING_ACTIONS.indexOf(action) == -1;
if (!newtabEnhanced || pingEndPoint == "" || invalidAction) {
return Promise.resolve();
}
let actionIndex;
let data = {
locale: this.locale,
tiles: sites.reduce((tiles, site, pos) => {
// Only add data for non-empty tiles
if (site) {
// Remember which tiles data triggered the action
let {link} = site;
let tilesIndex = tiles.length;
if (triggeringSiteIndex == pos) {
actionIndex = tilesIndex;
}
// Make the payload in a way so keys can be excluded when stringified
let id = link.directoryId;
tiles.push({
id: id || site.enhancedId,
pin: site.isPinned() ? 1 : undefined,
pos: pos != tilesIndex ? pos : undefined,
past_impressions: pos == triggeringSiteIndex ? pastImpressions : undefined,
score: Math.round(link.frecency / PING_SCORE_DIVISOR) || undefined,
url: site.enhancedId && "",
});
}
return tiles;
}, []),
};
// Provide a direct index to the tile triggering the action
if (actionIndex !== undefined) {
data[action] = actionIndex;
}
// Package the data to be sent with the ping
let ping = this._newXHR();
ping.open("POST", pingEndPoint + (action == "view" ? "view" : "click"));
ping.send(JSON.stringify(data));
return Task.spawn(function* () {
// since we updated views/clicks we need write _frequencyCaps to disk
yield this._writeFrequencyCapFile();

Просмотреть файл

@ -371,8 +371,6 @@ function TabWindow(win) {
this.win = win;
this.tabbrowser = win.gBrowser;
this.cacheDims();
this.previews = new Map();
for (let i = 0; i < this.tabEvents.length; i++)
@ -394,6 +392,8 @@ function TabWindow(win) {
TabWindow.prototype = {
_enabled: false,
_cachedWidth: 0,
_cachedHeight: 0,
tabEvents: ["TabOpen", "TabClose", "TabSelect", "TabMove"],
winEvents: ["resize"],
@ -404,8 +404,8 @@ TabWindow.prototype = {
this.tabbrowser.removeTabsProgressListener(this);
for (let i = 0; i < this.winEvents.length; i++)
this.win.removeEventListener(this.winEvents[i], this, false);
for (let i = 0; i < this.winEvents.length; i++)
this.win.removeEventListener(this.winEvents[i], this, false);
for (let i = 0; i < this.tabEvents.length; i++)
this.tabbrowser.tabContainer.removeEventListener(this.tabEvents[i], this, false);

Просмотреть файл

@ -716,113 +716,6 @@ add_task(function* test_frequencyCappedSites_click() {
Services.prefs.setCharPref(kPingUrlPref, kPingUrl);
});
add_task(function* test_reportSitesAction() {
yield DirectoryLinksProvider.init();
let deferred, expectedPath, expectedPost;
let done = false;
server.registerPrefixHandler(kPingPath, (aRequest, aResponse) => {
if (done) {
return;
}
do_check_eq(aRequest.path, expectedPath);
let bodyStream = new BinaryInputStream(aRequest.bodyInputStream);
let bodyObject = JSON.parse(NetUtil.readInputStreamToString(bodyStream, bodyStream.available()));
isIdentical(bodyObject, expectedPost);
deferred.resolve();
});
function sendPingAndTest(path, action, index) {
deferred = Promise.defer();
expectedPath = kPingPath + path;
DirectoryLinksProvider.reportSitesAction(sites, action, index);
return deferred.promise;
}
// Start with a single pinned link at position 3
let sites = [,,{
isPinned: _ => true,
link: {
directoryId: 1,
frecency: 30000,
url: "http://directory1/",
},
}];
// Make sure we get the click ping for the directory link with fields we want
// and unwanted fields removed by stringify/parse
expectedPost = JSON.parse(JSON.stringify({
click: 0,
locale: "en-US",
tiles: [{
id: 1,
pin: 1,
pos: 2,
score: 3,
url: undefined,
}],
}));
yield sendPingAndTest("click", "click", 2);
// Try a pin click ping
delete expectedPost.click;
expectedPost.pin = 0;
yield sendPingAndTest("click", "pin", 2);
// Try a block click ping
delete expectedPost.pin;
expectedPost.block = 0;
yield sendPingAndTest("click", "block", 2);
// A view ping has no actions
delete expectedPost.block;
expectedPost.view = 0;
yield sendPingAndTest("view", "view", 2);
// Remove the identifier that makes it a directory link so just plain history
delete sites[2].link.directoryId;
delete expectedPost.tiles[0].id;
yield sendPingAndTest("view", "view", 2);
// Add directory link at position 0
sites[0] = {
isPinned: _ => false,
link: {
directoryId: 1234,
frecency: 1000,
url: "http://directory/",
}
};
expectedPost.tiles.unshift(JSON.parse(JSON.stringify({
id: 1234,
pin: undefined,
pos: undefined,
score: undefined,
url: undefined,
})));
expectedPost.view = 1;
yield sendPingAndTest("view", "view", 2);
// Make the history tile enhanced so it reports both id and url
sites[2].enhancedId = "id from enhanced";
expectedPost.tiles[1].id = "id from enhanced";
expectedPost.tiles[1].url = "";
yield sendPingAndTest("view", "view", 2);
// Click the 0th site / 0th tile
delete expectedPost.view;
expectedPost.click = 0;
yield sendPingAndTest("click", "click", 0);
// Click the 2th site / 1th tile
expectedPost.click = 1;
yield sendPingAndTest("click", "click", 2);
done = true;
});
add_task(function* test_fetchAndCacheLinks_local() {
yield DirectoryLinksProvider.init();
yield cleanJsonFile();
@ -1901,110 +1794,6 @@ add_task(function* test_inadjecentSites() {
yield promiseCleanDirectoryLinksProvider();
});
add_task(function* test_reportPastImpressions() {
let origIsTopPlacesSite = NewTabUtils.isTopPlacesSite;
NewTabUtils.isTopPlacesSite = () => true;
let origCurrentTopSiteCount = DirectoryLinksProvider._getCurrentTopSiteCount;
DirectoryLinksProvider._getCurrentTopSiteCount = () => 8;
let testUrl = "http://frequency.capped/link";
let targets = ["top.site.com"];
let data = {
suggested: [{
type: "affiliate",
frecent_sites: targets,
url: testUrl,
adgroup_name: "Test"
}]
};
let dataURI = "data:application/json," + JSON.stringify(data);
yield promiseSetupDirectoryLinksProvider({linksURL: dataURI});
// make DirectoryLinksProvider load json
let loadPromise = Promise.defer();
DirectoryLinksProvider.getLinks(_ => {loadPromise.resolve();});
yield loadPromise.promise;
// setup ping handler
let deferred, expectedPath, expectedAction, expectedImpressions;
let done = false;
server.registerPrefixHandler(kPingPath, (aRequest, aResponse) => {
if (done) {
return;
}
do_check_eq(aRequest.path, expectedPath);
let bodyStream = new BinaryInputStream(aRequest.bodyInputStream);
let bodyObject = JSON.parse(NetUtil.readInputStreamToString(bodyStream, bodyStream.available()));
let expectedActionIndex = bodyObject[expectedAction];
if (bodyObject.unpin) {
// unpin should not report past_impressions
do_check_false(bodyObject.tiles[expectedActionIndex].hasOwnProperty("past_impressions"));
}
else if (expectedImpressions) {
do_check_eq(bodyObject.tiles[expectedActionIndex].past_impressions.total, expectedImpressions);
do_check_eq(bodyObject.tiles[expectedActionIndex].past_impressions.daily, expectedImpressions);
}
else {
do_check_eq(expectedPath, "/ping/view");
do_check_false(bodyObject.tiles[expectedActionIndex].hasOwnProperty("past_impressions"));
}
deferred.resolve();
});
// setup ping sender
function sendPingAndTest(path, action, index) {
deferred = Promise.defer();
expectedPath = kPingPath + path;
expectedAction = action;
DirectoryLinksProvider.reportSitesAction(sites, action, index);
return deferred.promise;
}
// Start with a view ping first
let site = {
isPinned: _ => false,
link: {
directoryId: 1,
frecency: 30000,
frecent_sites: targets,
targetedSite: targets[0],
url: testUrl
}
};
let sites = [,
{
isPinned: _ => false,
link: {type: "history", url: "https://foo.com"}
},
site
];
yield sendPingAndTest("view", "view", 2);
yield sendPingAndTest("view", "view", 2);
yield sendPingAndTest("view", "view", 2);
expectedImpressions = DirectoryLinksProvider._frequencyCaps[testUrl].totalViews;
do_check_eq(expectedImpressions, 3);
// now report pin, unpin, block and click
sites.isPinned = _ => true;
yield sendPingAndTest("click", "pin", 2);
sites.isPinned = _ => false;
yield sendPingAndTest("click", "unpin", 2);
sites.isPinned = _ => false;
yield sendPingAndTest("click", "click", 2);
sites.isPinned = _ => false;
yield sendPingAndTest("click", "block", 2);
// Cleanup.
done = true;
NewTabUtils.isTopPlacesSite = origIsTopPlacesSite;
DirectoryLinksProvider._getCurrentTopSiteCount = origCurrentTopSiteCount;
});
add_task(function* test_blockSuggestedTiles() {
// Initial setup
let suggestedTile = suggestedTile1;

Просмотреть файл

@ -26,5 +26,9 @@ DIRS += [
if CONFIG['MAKENSISU']:
DIRS += ['installer/windows']
TEST_DIRS += [
'tools/mozscreenshots',
]
DIST_SUBDIR = 'browser'
export('DIST_SUBDIR')

Просмотреть файл

@ -0,0 +1,7 @@
[DEFAULT]
subsuite = screenshots
support-files =
head.js
[browser_screenshots.js]
tags = screenshots

Просмотреть файл

@ -0,0 +1,18 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
add_task(function* test() {
let { TestRunner } = Cu.import("chrome://mozscreenshots/content/TestRunner.jsm", {});
let sets = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
let setsEnv = env.get("MOZSCREENSHOTS_SETS");
if (setsEnv) {
sets = setsEnv.trim().split(",");
}
yield TestRunner.start(sets);
});

Просмотреть файл

@ -0,0 +1,20 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
const {AddonWatcher} = Cu.import("resource://gre/modules/AddonWatcher.jsm", {});
let TestRunner;
function setup() {
requestLongerTimeout(10);
info("Checking for mozscreenshots extension");
AddonManager.getAddonByID("mozscreenshots@mozilla.org", function(aAddon) {
isnot(aAddon, null, "The mozscreenshots extension should be installed");
AddonWatcher.ignoreAddonPermanently(aAddon.id);
});
}
add_task(setup);

Просмотреть файл

@ -0,0 +1,11 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']
TEST_DIRS += [
'mozscreenshots/extension',
]

Просмотреть файл

@ -0,0 +1,12 @@
# 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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
TEST_EXTENSIONS_DIR = $(DEPTH)/_tests/testing/mochitest/extensions
GENERATED_DIRS = $(TEST_EXTENSIONS_DIR)
XPI_PKGNAME = mozscreenshots@mozilla.org
include $(topsrcdir)/config/rules.mk
libs::
(cd $(DIST)/xpi-stage && tar $(TAR_CREATE_FLAGS) - $(XPI_NAME)) | (cd $(TEST_EXTENSIONS_DIR) && tar -xf -)

Просмотреть файл

@ -0,0 +1,175 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Screenshot"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel";
XPCOMUtils.defineLazyGetter(this, "log", () => {
let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
let consoleOptions = {
maxLogLevel: "info",
maxLogLevelPref: PREF_LOG_LEVEL,
prefix: "mozscreenshots",
};
return new ConsoleAPI(consoleOptions);
});
let Screenshot = {
_extensionPath: null,
_path: null,
_imagePrefix: "",
_imageExtension: ".png",
_screenshotFunction: null,
init(path, extensionPath, imagePrefix = "") {
this._path = path;
let dir = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
dir.initWithPath(this._path);
if (!dir.exists()) {
dir.create(Ci.nsIFile.DIRECTORY_TYPE, parseInt("0755", 8));
}
this._extensionPath = extensionPath;
this._imagePrefix = imagePrefix;
switch (Services.appinfo.OS) {
case "WINNT":
this._screenshotFunction = this._screenshotWindows;
break;
case "Darwin":
this._screenshotFunction = this._screenshotOSX;
break;
case "Linux":
this._screenshotFunction = this._screenshotLinux;
break;
default:
throw new Error("Unsupported operating system");
break;
}
},
_buildImagePath(baseName) {
return OS.Path.join(this._path, this._imagePrefix + baseName + this._imageExtension);
},
// Capture the whole screen using an external application.
captureExternal(filename) {
let imagePath = this._buildImagePath(filename);
return this._screenshotFunction(imagePath).then(() => {
log.debug("saved screenshot: " + filename);
});
},
///// helpers /////
_screenshotWindows(filename) {
return new Promise((resolve, reject) => {
let exe = Services.dirsvc.get("GreBinD", Ci.nsIFile);
exe.append("screenshot.exe");
if (!exe.exists()) {
exe = this._extensionPath.QueryInterface(Ci.nsIFileURL).file;
exe.append("lib");
exe.append("screenshot.exe");
}
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(exe);
let args = [filename];
process.runAsync(args, args.length, this._processObserver(resolve, reject));
});
},
_screenshotOSX: Task.async(function*(filename) {
let screencapture = (windowID = null) => {
return new Promise((resolve, reject) => {
// Get the screencapture executable
let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
file.initWithPath("/usr/sbin/screencapture");
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(file);
// Run the process.
let args = ["-x", "-t", "png"];
// Darwin version number for OS X 10.6 is 10.x
if (windowID && Services.sysinfo.getProperty("version").indexOf("10.") !== 0) {
// Capture only that window on 10.7+
args.push("-l");
args.push(windowID);
}
args.push(filename);
process.runAsync(args, args.length, this._processObserver(resolve, reject));
});
};
function readWindowID() {
let decoder = new TextDecoder();
let promise = OS.File.read("/tmp/mozscreenshots-windowid");
return promise.then(function onSuccess(array) {
return decoder.decode(array);
});
}
let promiseWindowID = () => {
return new Promise((resolve, reject) => {
// Get the window ID of the application (assuming its front-most)
let osascript = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
osascript.initWithPath("/bin/bash");
let osascriptP = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
osascriptP.init(osascript);
let osaArgs = ["-c", "/usr/bin/osascript -e 'tell application (path to frontmost application as text) to set winID to id of window 1' > /tmp/mozscreenshots-windowid"];
osascriptP.runAsync(osaArgs, osaArgs.length, this._processObserver(resolve, reject));
});
};
yield promiseWindowID();
let windowID = yield readWindowID();
yield screencapture(windowID);
}),
_screenshotLinux(filename) {
return new Promise((resolve, reject) => {
let file = Services.dirsvc.get("GreBinD", Ci.nsIFile);
file.append("screentopng");
let process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
process.init(file);
let args = [filename];
process.runAsync(args, args.length, this._processObserver(resolve, reject));
});
},
_processObserver(resolve, reject) {
return {
observe(subject, topic, data) {
switch (topic) {
case "process-finished":
try {
// Wait 1s after process to resolve
setTimeout(resolve, 1000);
} catch (ex) {
reject(ex);
}
break;
default:
reject(topic);
break;
};
},
};
},
};

Просмотреть файл

@ -0,0 +1,256 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["TestRunner"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const defaultSetNames = ["TabsInTitlebar", "Tabs", "WindowSize", "Toolbars", "LightweightThemes"];
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
Cu.import("resource://gre/modules/FileUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/osfile.jsm");
Cu.import("chrome://mozscreenshots/content/Screenshot.jsm");
// Create a new instance of the ConsoleAPI so we can control the maxLogLevel with a pref.
// See LOG_LEVELS in Console.jsm. Common examples: "All", "Info", "Warn", & "Error".
const PREF_LOG_LEVEL = "extensions.mozscreenshots@mozilla.org.loglevel";
XPCOMUtils.defineLazyGetter(this, "log", () => {
let ConsoleAPI = Cu.import("resource://gre/modules/Console.jsm", {}).ConsoleAPI;
let consoleOptions = {
maxLogLevel: "info",
maxLogLevelPref: PREF_LOG_LEVEL,
prefix: "mozscreenshots",
};
return new ConsoleAPI(consoleOptions);
});
this.TestRunner = {
combos: null,
completedCombos: 0,
currentComboIndex: 0,
_lastCombo: null,
_libDir: null,
init(extensionPath) {
let subDirs = ["mozscreenshots",
(new Date()).toISOString().replace(/:/g, "-") + "_" + Services.appinfo.OS];
let screenshotPath = FileUtils.getFile("TmpD", subDirs).path;
const MOZ_UPLOAD_DIR = env.get("MOZ_UPLOAD_DIR");
if (MOZ_UPLOAD_DIR) {
screenshotPath = MOZ_UPLOAD_DIR;
}
log.info("Saving screenshots to:", screenshotPath);
log.debug("TestRunner.init");
let screenshotPrefix = Services.appinfo.appBuildID + "_";
Screenshot.init(screenshotPath, extensionPath, screenshotPrefix);
this._libDir = extensionPath.QueryInterface(Ci.nsIFileURL).file.clone();
this._libDir.append("chrome");
this._libDir.append("mozscreenshots");
this._libDir.append("lib");
// Setup some prefs
Services.prefs.setCharPref("browser.aboutHomeSnippets.updateUrl", "data:");
Services.prefs.setCharPref("extensions.ui.lastCategory", "addons://list/extension");
// Don't let the caret blink since it causes false positives for image diffs
Services.prefs.setIntPref("ui.caretBlinkTime", -1);
},
/**
* Load specified sets, execute all combinations of them, and capture screenshots.
*/
start(setNames = null) {
setNames = setNames || defaultSetNames;
let sets = this.loadSets(setNames);
log.info(sets.length + " sets:", setNames);
this.combos = new LazyProduct(sets);
log.info(this.combos.length + " combinations");
this.currentComboIndex = this.completedCombos = 0;
this._lastCombo = null;
return Task.spawn(function* doStart() {
for (let i = 0; i < this.combos.length;
i++){
this.currentComboIndex = i;
yield* this._performCombo(this.combos.item(this.currentComboIndex));
}
log.info("Done: Completed " + this.completedCombos + " out of " +
this.combos.length + " configurations.");
this.cleanup();
}.bind(this));
},
/**
* Load sets of configurations from JSMs.
* @param {String[]} setNames - array of set names (e.g. ["Tabs", "WindowSize"].
* @return {Object[]} Array of sets containing `name` and `configurations` properties.
*/
loadSets(setNames) {
let sets = [];
for (let setName of setNames) {
try {
let imported = {};
Cu.import("chrome://mozscreenshots/content/configurations/" + setName + ".jsm",
imported);
imported[setName].init(this._libDir);
let configurationNames = Object.keys(imported[setName].configurations);
if (!configurationNames.length) {
throw new Error(setName + " has no configurations for this environment");
}
for (let config of configurationNames) {
// Automatically set the name property of the configuration object to
// its name from the configuration object.
imported[setName].configurations[config].name = config;
}
sets.push(imported[setName].configurations);
} catch (ex) {
log.error("Error loading set: " + setName);
log.error(ex);
throw ex;
}
}
return sets;
},
cleanup() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
while (gBrowser.tabs.length > 1) {
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
}
gBrowser.unpinTab(gBrowser.selectedTab);
gBrowser.selectedBrowser.loadURI("data:text/html;charset=utf-8,<h1>Done!");
browserWindow.restore();
},
///// helpers /////
_performCombo: function*(combo) {
let paddedComboIndex = padLeft(this.currentComboIndex + 1, String(this.combos.length).length);
log.info("Combination " + paddedComboIndex + "/" + this.combos.length + ": " +
this._comboName(combo).substring(1));
function changeConfig(config) {
log.debug("calling " + config.name);
let promise = config.applyConfig();
log.debug("called " + config.name);
return promise;
}
try {
// First go through and actually apply all of the configs
for (let i = 0; i < combo.length; i++) {
let config = combo[i];
if (!this._lastCombo || config !== this._lastCombo[i]) {
log.debug("promising", config.name);
yield changeConfig(config);
}
}
// Update the lastCombo since it's now been applied regardless of whether it's accepted below.
log.debug("fulfilled all applyConfig so setting lastCombo.");
this._lastCombo = combo;
// Then ask configs if the current setup is valid. We can't can do this in
// the applyConfig methods of the config since it doesn't know what configs
// later in the loop will do that may invalidate the combo.
for (let i = 0; i < combo.length; i++) {
let config = combo[i];
// A configuration can specify an optional verifyConfig method to indicate
// if the current config is valid for a screenshot. This gets called even
// if the this config was used in the lastCombo since another config may
// have invalidated it.
if (config.verifyConfig) {
log.debug("checking if the combo is valid with", config.name);
yield config.verifyConfig();
}
}
} catch (ex) {
log.warn("\tskipped configuration: " + ex);
// Don't set lastCombo here so that we properly know which configurations
// need to be applied since the last screenshot
// Return so we don't take a screenshot.
return;
}
yield this._onConfigurationReady(combo);
},
_onConfigurationReady(combo) {
let delayedScreenshot = () => {
let filename = padLeft(this.currentComboIndex + 1,
String(this.combos.length).length) + this._comboName(combo);
return Screenshot.captureExternal(filename)
.then(() => {
this.completedCombos++;
});
};
log.debug("_onConfigurationReady");
return Task.spawn(delayedScreenshot);
},
_comboName(combo) {
return combo.reduce(function(a, b) {
return a + "_" + b.name;
}, "");
},
};
/**
* Helper to lazily compute the Cartesian product of all of the sets of configurations.
**/
function LazyProduct(sets) {
/**
* An entry for each set with the value being:
* [the number of permutations of the sets with lower index,
* the number of items in the set at the index]
*/
this.sets = sets;
this.lookupTable = [];
let combinations = 1;
for (let i = this.sets.length - 1; i >= 0; i--) {
let set = this.sets[i];
let setLength = Object.keys(set).length;
this.lookupTable[i] = [combinations, setLength];
combinations *= setLength;
}
}
LazyProduct.prototype = {
get length() {
let last = this.lookupTable[0];
if (!last)
return 0;
return last[0] * last[1];
},
item(n) {
// For set i, get the item from the set with the floored value of
// (n / the number of permutations of the sets already chosen from) modulo the length of set i
let result = [];
for (let i = this.sets.length - 1; i >= 0; i--) {
let priorCombinations = this.lookupTable[i][0];
let setLength = this.lookupTable[i][1];
let keyIndex = Math.floor(n / priorCombinations) % setLength;
let keys = Object.keys(this.sets[i]);
result[i] = this.sets[i][keys[keyIndex]];
}
return result;
},
};
function padLeft(number, width, padding = "0") {
return padding.repeat(Math.max(0, width - String(number).length)) + number;
}

Просмотреть файл

@ -0,0 +1,72 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/*
#if 0
Workaround a build system bug where this file doesn't get packaged if not pre-processed.
#endif
*/
"use strict";
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const env = Cc["@mozilla.org/process/environment;1"].getService(Ci.nsIEnvironment);
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/AddonManager.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "TestRunner",
"chrome://mozscreenshots/content/TestRunner.jsm");
function install(data, reason) {
if (!isAppSupported()) {
uninstallExtension(data);
return;
}
AddonManager.getAddonByID(data.id, function(addon) {
// Enable on install in case the user disabled a prior version
if (addon) {
addon.userDisabled = false;
}
});
}
function startup(data, reason) {
if (!isAppSupported()) {
uninstallExtension(data);
return;
}
AddonManager.getAddonByID(data.id, function(addon) {
let extensionPath = addon.getResourceURI();
TestRunner.init(extensionPath);
});
}
function shutdown(data, reason) { }
function uninstall(data, reason) { }
/**
* @return boolean whether the test suite applies to the application.
*/
function isAppSupported() {
return true;
}
function uninstallExtension(data) {
AddonManager.getAddonByID(data.id, function(addon) {
addon.uninstall();
});
}
function startRun() {
let env = Cc["@mozilla.org/process/environment;1"]
.getService(Ci.nsIEnvironment);
let setsEnv = env.get("MOZSCREENSHOTS_SETS");
let sets = setsEnv ? setsEnv.split(",") : null;
TestRunner.start(sets);
}

Просмотреть файл

@ -0,0 +1,84 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["AppMenu"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.AppMenu = {
init(libDir) {},
configurations: {
appMenuClosed: {
applyConfig: Task.async(function*() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.PanelUI.hide();
}),
},
appMenuMainView: {
applyConfig() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let promise = browserWindow.PanelUI.show();
browserWindow.PanelUI.showMainView();
return promise;
},
},
appMenuHistorySubview: {
applyConfig() {
// History has a footer
if (isCustomizing()) {
return Promise.reject("Can't show subviews while customizing");
}
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let promise = browserWindow.PanelUI.show();
return promise.then(() => {
browserWindow.PanelUI.showMainView();
browserWindow.document.getElementById("history-panelmenu").click();
});
},
verifyConfig: verifyConfigHelper,
},
appMenuHelpSubview: {
applyConfig() {
if (isCustomizing()) {
return Promise.reject("Can't show subviews while customizing");
}
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let promise = browserWindow.PanelUI.show();
return promise.then(() => {
browserWindow.PanelUI.showMainView();
browserWindow.document.getElementById("PanelUI-help").click();
});
},
verifyConfig: verifyConfigHelper,
},
},
};
function verifyConfigHelper() {
if (isCustomizing()) {
return Promise.reject("AppMenu verifyConfigHelper");
}
return Promise.resolve("AppMenu verifyConfigHelper");
}
function isCustomizing() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (browserWindow.document.documentElement.hasAttribute("customizing")) {
return true;
}
return false;
}

Просмотреть файл

@ -0,0 +1,87 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Buttons"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource:///modules/CustomizableUI.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.Buttons = {
init(libDir) {
createWidget();
},
configurations: {
navBarButtons: {
applyConfig: Task.async(() =>{
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_NAVBAR);
}),
},
tabsToolbarButtons: {
applyConfig: Task.async(() => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_TABSTRIP);
}),
},
menuPanelButtons: {
applyConfig: Task.async(() => {
CustomizableUI.addWidgetToArea("screenshot-widget", CustomizableUI.AREA_PANEL);
}),
verifyConfig() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (browserWindow.PanelUI.panel.state == "closed") {
return Promise.reject("The button isn't shown when the panel isn't open.");
}
return Promise.resolve("menuPanelButtons.verifyConfig");
},
},
custPaletteButtons: {
applyConfig: Task.async(() => {
CustomizableUI.removeWidgetFromArea("screenshot-widget");
}),
verifyConfig() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (browserWindow.document.documentElement.getAttribute("customizing") != "true") {
return Promise.reject("The button isn't shown when we're not in customize mode.");
}
return Promise.resolve("custPaletteButtons.verifyConfig");
},
},
},
};
function createWidget() {
let id = "screenshot-widget";
let spec = {
id: id,
label: "My Button",
removable: true,
tooltiptext: "",
type: "button",
};
CustomizableUI.createWidget(spec);
// Append a <style> for the image
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let st = browserWindow.document.createElementNS("http://www.w3.org/1999/xhtml", "style");
let styles = "" +
"#screenshot-widget > .toolbarbutton-icon {" +
" list-style-image: url(chrome://browser/skin/Toolbar.png);" +
" -moz-image-region: rect(0px, 18px, 18px, 0px);" +
"}";
st.appendChild(browserWindow.document.createTextNode(styles));
browserWindow.document.documentElement.appendChild(st);
}

Просмотреть файл

@ -0,0 +1,61 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["CustomizeMode"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
this.CustomizeMode = {
init(libDir) {},
configurations: {
notCustomizing: {
applyConfig() {
return new Promise((resolve) => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (!browserWindow.document.documentElement.hasAttribute("customizing")) {
resolve("notCustomizing: already not customizing");
return;
}
function onCustomizationEnds() {
browserWindow.gNavToolbox.removeEventListener("aftercustomization",
onCustomizationEnds);
// Wait for final changes
setTimeout(() => resolve("notCustomizing: onCustomizationEnds"), 500);
}
browserWindow.gNavToolbox.addEventListener("aftercustomization",
onCustomizationEnds);
browserWindow.gCustomizeMode.exit();
});
},
},
customizing: {
applyConfig() {
return new Promise((resolve) => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (browserWindow.document.documentElement.hasAttribute("customizing")) {
resolve("customizing: already customizing");
return;
}
function onCustomizing() {
browserWindow.gNavToolbox.removeEventListener("customizationready",
onCustomizing);
// Wait for final changes
setTimeout(() => resolve("customizing: onCustomizing"), 500);
}
browserWindow.gNavToolbox.addEventListener("customizationready",
onCustomizing);
browserWindow.gCustomizeMode.enter();
});
},
},
},
};

Просмотреть файл

@ -0,0 +1,42 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["DevEdition"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const THEME_ID = "firefox-devedition@mozilla.org";
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.DevEdition = {
init(libDir) {},
configurations: {
devEditionLight: {
applyConfig: Task.async(() => {
Services.prefs.setCharPref("devtools.theme", "light");
LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(THEME_ID);
Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
}),
},
devEditionDark: {
applyConfig: Task.async(() => {
Services.prefs.setCharPref("devtools.theme", "dark");
LightweightThemeManager.currentTheme = LightweightThemeManager.getUsedTheme(THEME_ID);
Services.prefs.setBoolPref("browser.devedition.theme.showCustomizeButton", true);
}),
},
devEditionOff: {
applyConfig: Task.async(() => {
Services.prefs.clearUserPref("devtools.theme");
LightweightThemeManager.currentTheme = null;
Services.prefs.clearUserPref("browser.devedition.theme.showCustomizeButton");
}),
},
},
};

Просмотреть файл

@ -0,0 +1,50 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["DevTools"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://devtools/client/framework/gDevTools.jsm");
Cu.import("resource://gre/modules/Services.jsm");
let { devtools } = Cu.import("resource://gre/modules/devtools/Loader.jsm", {});
let TargetFactory = devtools.TargetFactory;
function getTargetForSelectedTab() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let target = TargetFactory.forTab(browserWindow.gBrowser.selectedTab);
return target;
}
this.DevTools = {
init(libDir) {
let panels = ["options", "webconsole", "inspector", "jsdebugger", "netmonitor"];
panels.forEach(panel => {
this.configurations[panel] = {};
this.configurations[panel].applyConfig = () => {
return gDevTools.showToolbox(getTargetForSelectedTab(), panel, "bottom");
};
});
},
configurations: {
bottomToolbox: {
applyConfig() {
return gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "bottom");
},
},
sideToolbox: {
applyConfig() {
return gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "side");
},
},
undockedToolbox: {
applyConfig() {
return gDevTools.showToolbox(getTargetForSelectedTab(), "inspector", "window");
},
}
},
};

Просмотреть файл

@ -0,0 +1,92 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["LightweightThemes"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/LightweightThemeManager.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
this.LightweightThemes = {
init(libDir) {
// convert -size 3000x200 canvas:black black_theme.png
let blackImage = libDir.clone();
blackImage.append("black_theme.png");
this._blackImageURL = Services.io.newFileURI(blackImage).spec;
// convert -size 3000x200 canvas:white white_theme.png
let whiteImage = libDir.clone();
whiteImage.append("white_theme.png");
this._whiteImageURL = Services.io.newFileURI(whiteImage).spec;
},
configurations: {
noLWT: {
applyConfig: Task.async(function*() {
LightweightThemeManager.currentTheme = null;
}),
},
darkLWT: {
applyConfig() {
LightweightThemeManager.setLocalTheme({
id: "black",
name: "black",
headerURL: LightweightThemes._blackImageURL,
footerURL: LightweightThemes._blackImageURL,
textcolor: "#ffffff",
accentcolor: "#111111",
});
// Wait for LWT listener
return new Promise(resolve => {
setTimeout(() => {
resolve("darkLWT");
}, 500);
});
},
verifyConfig: verifyConfigHelper,
},
lightLWT: {
applyConfig() {
LightweightThemeManager.setLocalTheme({
id: "white",
name: "white",
headerURL: LightweightThemes._whiteImageURL,
footerURL: LightweightThemes._whiteImageURL,
textcolor: "#000000",
accentcolor: "#eeeeee",
});
// Wait for LWT listener
return new Promise(resolve => {
setTimeout(() => {
resolve("lightLWT");
}, 500);
});
},
verifyConfig: verifyConfigHelper,
},
},
};
function verifyConfigHelper() {
return new Promise((resolve, reject) => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (browserWindow.document.documentElement.hasAttribute("lwtheme")) {
resolve("verifyConfigHelper");
} else {
reject("The @lwtheme attribute wasn't present so themes may not be available");
}
});
}

Просмотреть файл

@ -0,0 +1,53 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Preferences"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
this.Preferences = {
init(libDir) {
Services.prefs.setBoolPref("browser.preferences.inContent", true);
let panes = [
["paneGeneral", null],
["paneSearch", null],
["paneContent", null],
["paneApplications", null],
["panePrivacy", null],
["paneSecurity", null],
["paneSync", null],
["paneAdvanced", "generalTab"],
["paneAdvanced", "dataChoicesTab"],
["paneAdvanced", "networkTab"],
["paneAdvanced", "updateTab"],
["paneAdvanced", "encryptionTab"],
];
for (let [primary, advanced] of panes) {
let configName = primary + ("-" + advanced || "");
this.configurations[configName] = {};
this.configurations[configName].applyConfig = prefHelper.bind(null, primary, advanced);
}
},
configurations: {},
};
function prefHelper(primary, advanced) {
return new Promise((resolve) => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (primary == "paneAdvanced") {
browserWindow.openAdvancedPreferences(advanced);
} else {
browserWindow.openPreferences(primary);
}
setTimeout(resolve, 50);
});
}

Просмотреть файл

@ -0,0 +1,143 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Tabs"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const CUST_TAB = "chrome://browser/skin/customizableui/customizeFavicon.ico";
const PREFS_TAB = "chrome://browser/skin/preferences/in-content/favicon.ico";
const DEFAULT_FAVICON_TAB = `data:text/html,<meta charset="utf-8">
<title>No favicon</title>`;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.Tabs = {
init(libDir) {},
configurations: {
fiveTabs: {
applyConfig: Task.async(function*() {
fiveTabsHelper();
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
hoverTab(browserWindow.gBrowser.tabs[3]);
}),
},
fourPinned: {
applyConfig: Task.async(function*() {
fiveTabsHelper();
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let tab = browserWindow.gBrowser.addTab(PREFS_TAB);
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab(CUST_TAB);
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab("about:privatebrowsing");
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab("about:home");
browserWindow.gBrowser.pinTab(tab);
browserWindow.gBrowser.selectTabAtIndex(5);
hoverTab(browserWindow.gBrowser.tabs[2]);
// also hover the new tab button
let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.
gBrowser.tabContainer, "class", "tabs-newtab-button");
hoverTab(newTabButton);
browserWindow.gBrowser.tabs[browserWindow.gBrowser.tabs.length - 1].
setAttribute("beforehovered", true);
}),
},
twoPinnedWithOverflow: {
applyConfig: Task.async(function*() {
fiveTabsHelper();
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.gBrowser.loadTabs([
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
], true, true);
let tab = browserWindow.gBrowser.addTab(PREFS_TAB);
browserWindow.gBrowser.pinTab(tab);
tab = browserWindow.gBrowser.addTab(CUST_TAB);
browserWindow.gBrowser.pinTab(tab);
browserWindow.gBrowser.selectTabAtIndex(4);
hoverTab(browserWindow.gBrowser.tabs[6]);
}),
},
},
};
/* helpers */
function fiveTabsHelper() {
// some with no favicon and some with. Selected tab in middle.
closeAllButOneTab("about:addons");
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.gBrowser.loadTabs([
"about:addons",
"about:home",
DEFAULT_FAVICON_TAB,
"about:newtab",
CUST_TAB,
], true, true);
browserWindow.gBrowser.selectTabAtIndex(1);
}
function closeAllButOneTab(url = "about:blank") {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let gBrowser = browserWindow.gBrowser;
// Close all tabs except the last so we don't quit the browser.
while (gBrowser.tabs.length > 1)
gBrowser.removeTab(gBrowser.selectedTab, {animate: false});
gBrowser.selectedBrowser.loadURI(url);
if (gBrowser.selectedTab.pinned)
gBrowser.unpinTab(gBrowser.selectedTab);
let newTabButton = browserWindow.document.getAnonymousElementByAttribute(browserWindow.gBrowser.tabContainer, "class", "tabs-newtab-button");
hoverTab(newTabButton, false);
}
function hoverTab(tab, hover = true) {
const inIDOMUtils = Cc["@mozilla.org/inspector/dom-utils;1"].getService(Ci.inIDOMUtils);
if (hover) {
inIDOMUtils.addPseudoClassLock(tab, ":hover");
} else {
inIDOMUtils.clearPseudoClassLocks(tab);
}
// XXX TODO: this isn't necessarily testing what we ship
if (tab.nextElementSibling)
tab.nextElementSibling.setAttribute("afterhovered", hover || null);
if (tab.previousElementSibling)
tab.previousElementSibling.setAttribute("beforehovered", hover || null);
}

Просмотреть файл

@ -0,0 +1,37 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["TabsInTitlebar"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
const PREF_TABS_IN_TITLEBAR = "browser.tabs.drawInTitlebar";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.TabsInTitlebar = {
init(libDir) {},
configurations: {
tabsInTitlebar: {
applyConfig: Task.async(function*() {
if (Services.appinfo.OS == "Linux") {
return Promise.reject("TabsInTitlebar isn't supported on Linux");
}
Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, true);
}),
},
tabsOutsideTitlebar: {
applyConfig: Task.async(function*() {
Services.prefs.setBoolPref(PREF_TABS_IN_TITLEBAR, false);
}),
},
},
};

Просмотреть файл

@ -0,0 +1,56 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["Toolbars"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
this.Toolbars = {
init(libDir) {},
configurations: {
onlyNavBar: {
applyConfig: Task.async(function*() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
browserWindow.setToolbarVisibility(personalToolbar, false);
toggleMenubarIfNecessary(false);
}),
},
allToolbars: {
applyConfig: Task.async(function*() { // Boookmarks and menubar
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
let personalToolbar = browserWindow.document.getElementById("PersonalToolbar");
browserWindow.setToolbarVisibility(personalToolbar, true);
toggleMenubarIfNecessary(true);
}),
verifyConfig: Task.async(function*() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
if (browserWindow.fullScreen) {
return Promise.reject("The bookmark toolbar and menubar are not shown in fullscreen.");
}
}),
},
},
};
///// helpers /////
function toggleMenubarIfNecessary(visible) {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
// The menubar is not shown on OS X or while in fullScreen
if (Services.appinfo.OS != "Darwin" /*&& !browserWindow.fullScreen*/) {
let menubar = browserWindow.document.getElementById("toolbar-menubar");
browserWindow.setToolbarVisibility(menubar, visible);
}
}

Просмотреть файл

@ -0,0 +1,60 @@
/* 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 file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
this.EXPORTED_SYMBOLS = ["WindowSize"];
const {classes: Cc, interfaces: Ci, utils: Cu} = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Timer.jsm");
this.WindowSize = {
init(libDir) {
Services.prefs.setBoolPref("browser.fullscreen.autohide", false);
},
configurations: {
maximized: {
applyConfig: Task.async(function*() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.fullScreen = false;
// Wait for the Lion fullscreen transition to end as there doesn't seem to be an event
// and trying to maximize while still leaving fullscreen doesn't work.
yield new Promise((resolve, reject) => {
setTimeout(function waitToLeaveFS() {
browserWindow.maximize();
resolve();
}, Services.appinfo.OS == "Darwin" ? 1500 : 0);
});
}),
},
normal: {
applyConfig: Task.async(() => {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.fullScreen = false;
browserWindow.restore();
}),
},
fullScreen: {
applyConfig: Task.async(function*() {
let browserWindow = Services.wm.getMostRecentWindow("navigator:browser");
browserWindow.fullScreen = true;
// OS X Lion fullscreen transition takes a while
yield new Promise((resolve, reject) => {
setTimeout(function waitAfterEnteringFS() {
resolve();
}, Services.appinfo.OS == "Darwin" ? 1500 : 0);
});
}),
},
},
};

Просмотреть файл

@ -0,0 +1,33 @@
<?xml version="1.0"?>
<!-- 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
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:em="http://www.mozilla.org/2004/em-rdf#">
<Description about="urn:mozilla:install-manifest">
<em:id>mozscreenshots@mozilla.org</em:id>
#expand <em:version>__MOZILLA_VERSION_U__</em:version>
<em:bootstrap>true</em:bootstrap>
<!-- for running custom screenshot binaries -->
<em:unpack>true</em:unpack>
<!-- Front End MetaData -->
<em:name>mozscreenshots</em:name>
<em:description>Take screenshots of Mozilla applications in various UI configurations.</em:description>
<em:creator>Mozilla</em:creator>
<em:targetApplication>
<Description>
<!-- Firefox -->
<em:id>{ec8030f7-c20a-464f-9b0e-13a3a9e97384}</em:id>
#expand <em:minVersion>__MOZILLA_VERSION_U__</em:minVersion>
<em:maxVersion>*</em:maxVersion>
</Description>
</em:targetApplication>
</Description>
</RDF>

Просмотреть файл

@ -0,0 +1,6 @@
mozscreenshots.jar:
% content mozscreenshots chrome/mozscreenshots/
Screenshot.jsm
TestRunner.jsm
configurations/ (configurations/*.jsm)
lib/ (lib/*.png)

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 343 B

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 522 B

Просмотреть файл

@ -0,0 +1,17 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
XPI_NAME = 'mozscreenshots'
JAR_MANIFESTS += ['jar.mn']
USE_EXTENSION_MANIFEST = True
NO_JS_MANIFEST = True
FINAL_TARGET_PP_FILES += [
'bootstrap.js',
'install.rdf',
]

Просмотреть файл

@ -231,7 +231,7 @@ define([MOZ_BUILD_BACKEND],
BUILD_BACKENDS="RecursiveMake"
MOZ_ARG_ENABLE_STRING(build-backend,
[ --enable-build-backend={AndroidEclipse,CppEclipse,VisualStudio,FasterMake,CompileDB,ChromeMap}
[ --enable-build-backend={$($(dirname ]$[0)/$1/mach python -c "from mozbuild.backend import backends; print ','.join(sorted(backends))")}
Enable additional build backends],
[ BUILD_BACKENDS="RecursiveMake `echo $enableval | sed 's/,/ /g'`"])

Просмотреть файл

@ -258,7 +258,10 @@ Elf::Elf(std::ifstream &file)
segment->addSection(sections[j]);
// Make sure that our view of segments corresponds to the original
// ELF file.
assert(segment->getFileSize() == phdr.p_filesz);
// GNU gold likes to start some segments before the first section
// they contain. https://sourceware.org/bugzilla/show_bug.cgi?id=19392
unsigned int gold_adjustment = segment->getAddr() - phdr.p_vaddr;
assert(segment->getFileSize() == phdr.p_filesz - gold_adjustment);
// gold makes TLS segments end on an aligned virtual address, even
// when the underlying section ends before that, while bfd ld
// doesn't. It's fine if we don't keep that alignment.
@ -267,7 +270,7 @@ Elf::Elf(std::ifstream &file)
unsigned int align = segment->getAlign();
memsize = (memsize + align - 1) & ~(align - 1);
}
assert(memsize == phdr.p_memsz);
assert(memsize == phdr.p_memsz - gold_adjustment);
segments.push_back(segment);
}

5
config/external/nss/nss.symbols поставляемый
Просмотреть файл

@ -692,6 +692,11 @@ VFY_VerifyDataWithAlgorithmID
VFY_VerifyDigestDirect
_SGN_VerifyPKCS1DigestInfo
__PK11_SetCertificateNickname
# These symbols are not used by Firefox itself, but are used by Java's security
# libraries, which in turn are used by Java applets/plugins/etc. Provide them
# to make Java code happy.
NSS_VersionCheck
NSS_Initialize
#ifdef NSS_EXTRA_SYMBOLS_FILE
#include @NSS_EXTRA_SYMBOLS_FILE@
#endif

Просмотреть файл

@ -1581,7 +1581,3 @@ include $(MOZILLA_DIR)/config/makefiles/autotargets.mk
ifneq ($(NULL),$(AUTO_DEPS))
default all libs tools export:: $(AUTO_DEPS)
endif
export:: $(GENERATED_FILES)
GARBAGE += $(GENERATED_FILES)

Просмотреть файл

@ -139,7 +139,7 @@ DIST="$MOZ_BUILD_ROOT/dist"
MOZ_PYTHON
MOZ_BUILD_BACKEND
MOZ_BUILD_BACKEND(.)
MOZ_DEFAULT_COMPILER
@ -2288,6 +2288,11 @@ ia64*-hpux*)
# At least one MSVC header and several headers in-tree have
# unused typedefs, so turn this on.
CXXFLAGS="$CXXFLAGS -Wno-unused-local-typedef"
# Several JS engine header files use __declspec(dllimport) on
# classes, and clang-cl helpfully warns about its non-support
# for such cases. We're not particularly worried about that,
# so ignore that warning.
CXXFLAGS="$CXXFLAGS -Wno-ignored-attributes"
fi
# make 'foo == bar;' error out
CFLAGS="$CFLAGS -we4553"

Просмотреть файл

@ -81,8 +81,6 @@ var CallsListView = Heritage.extend(WidgetMethods, {
gutter.appendChild(index);
contents.appendChild(gutter);
// Not all function calls have a caller that was stringified (e.g.
// context calls have a "gl" or "ctx" caller preview).
if (call.callerPreview) {
let context = document.createElement("label");
context.className = "plain call-item-context";

Просмотреть файл

@ -40,7 +40,7 @@ function* ifTestingSupported() {
is(functionCalls[0].line, 25,
"The called function's line is correct.");
is(functionCalls[0].callerPreview, "ctx",
is(functionCalls[0].callerPreview, "Object",
"The called function's caller preview is correct.");
is(functionCalls[0].argsPreview, "0, 0, 128, 128",
"The called function's args preview is correct.");

Просмотреть файл

@ -41,7 +41,7 @@ function* ifTestingSupported() {
"The first called function's line is correct.");
is(functionCalls[0].argsPreview, "0, 0, 128, 128",
"The first called function's args preview is correct.");
is(functionCalls[0].callerPreview, "ctx",
is(functionCalls[0].callerPreview, "Object",
"The first called function's caller preview is correct.");
is(functionCalls[6].type, CallWatcherFront.METHOD_FUNCTION,
@ -54,7 +54,7 @@ function* ifTestingSupported() {
"The penultimate called function's line is correct.");
is(functionCalls[6].argsPreview, "10, 10, 55, 50",
"The penultimate called function's args preview is correct.");
is(functionCalls[6].callerPreview, "ctx",
is(functionCalls[6].callerPreview, "Object",
"The penultimate called function's caller preview is correct.");
is(functionCalls[7].type, CallWatcherFront.METHOD_FUNCTION,
@ -67,7 +67,7 @@ function* ifTestingSupported() {
"The last called function's line is correct.");
ok(functionCalls[7].argsPreview.includes("Function"),
"The last called function's args preview is correct.");
is(functionCalls[7].callerPreview, "",
is(functionCalls[7].callerPreview, "Object",
"The last called function's caller preview is correct.");
yield removeTab(target.tab);

Просмотреть файл

@ -41,7 +41,7 @@ function* ifTestingSupported() {
"The first called function's line is correct.");
is(functionCalls[0].argsPreview, "0, 0, 128, 128",
"The first called function's args preview is correct.");
is(functionCalls[0].callerPreview, "ctx",
is(functionCalls[0].callerPreview, "Object",
"The first called function's caller preview is correct.");
is(functionCalls[6].type, CallWatcherFront.METHOD_FUNCTION,
@ -54,7 +54,7 @@ function* ifTestingSupported() {
"The penultimate called function's line is correct.");
is(functionCalls[6].argsPreview, "10, 10, 55, 50",
"The penultimate called function's args preview is correct.");
is(functionCalls[6].callerPreview, "ctx",
is(functionCalls[6].callerPreview, "Object",
"The penultimate called function's caller preview is correct.");
is(functionCalls[7].type, CallWatcherFront.METHOD_FUNCTION,
@ -67,7 +67,7 @@ function* ifTestingSupported() {
"The last called function's line is correct.");
ok(functionCalls[7].argsPreview.includes("Function"),
"The last called function's args preview is correct.");
is(functionCalls[7].callerPreview, "",
is(functionCalls[7].callerPreview, "Object",
"The last called function's caller preview is correct.");
let firstNonDrawCall = yield functionCalls[1].getDetails();

Просмотреть файл

@ -21,22 +21,22 @@ function* ifTestingSupported() {
"All the function calls should now be displayed in the UI.");
testItem(CallsListView.getItemAtIndex(0),
"1", "ctx", "clearRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:25");
"1", "Object", "clearRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:25");
testItem(CallsListView.getItemAtIndex(1),
"2", "ctx", "fillStyle", " = rgb(192, 192, 192)", "doc_simple-canvas.html:20");
"2", "Object", "fillStyle", " = rgb(192, 192, 192)", "doc_simple-canvas.html:20");
testItem(CallsListView.getItemAtIndex(2),
"3", "ctx", "fillRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:21");
"3", "Object", "fillRect", "(0, 0, 128, 128)", "doc_simple-canvas.html:21");
testItem(CallsListView.getItemAtIndex(3),
"4", "ctx", "fillStyle", " = rgba(0, 0, 192, 0.5)", "doc_simple-canvas.html:20");
"4", "Object", "fillStyle", " = rgba(0, 0, 192, 0.5)", "doc_simple-canvas.html:20");
testItem(CallsListView.getItemAtIndex(4),
"5", "ctx", "fillRect", "(30, 30, 55, 50)", "doc_simple-canvas.html:21");
"5", "Object", "fillRect", "(30, 30, 55, 50)", "doc_simple-canvas.html:21");
testItem(CallsListView.getItemAtIndex(5),
"6", "ctx", "fillStyle", " = rgba(192, 0, 0, 0.5)", "doc_simple-canvas.html:20");
"6", "Object", "fillStyle", " = rgba(192, 0, 0, 0.5)", "doc_simple-canvas.html:20");
testItem(CallsListView.getItemAtIndex(6),
"7", "ctx", "fillRect", "(10, 10, 55, 50)", "doc_simple-canvas.html:21");
"7", "Object", "fillRect", "(10, 10, 55, 50)", "doc_simple-canvas.html:21");
testItem(CallsListView.getItemAtIndex(7),
"8", "", "requestAnimationFrame", "(Function)", "doc_simple-canvas.html:30");
@ -53,7 +53,7 @@ function* ifTestingSupported() {
is($(".call-item-context", item.target).getAttribute("value"), context,
"The item's context label has the correct text.");
} else {
is($(".call-item-context", item.target), null,
is($(".call-item-context", item.target) + "", "[object XULElement]",
"The item's context label should not be available.");
}

Просмотреть файл

@ -40,7 +40,7 @@ function* ifTestingSupported() {
"The visible item's line has the expected value.");
is(CallsListView.visibleItems[0].attachment.actor.argsPreview, "0, 0, 128, 128",
"The visible item's args have the expected value.");
is(CallsListView.visibleItems[0].attachment.actor.callerPreview, "ctx",
is(CallsListView.visibleItems[0].attachment.actor.callerPreview, "Object",
"The visible item's caller has the expected value.");
let secondRecordingFinished = once(window, EVENTS.SNAPSHOT_RECORDING_FINISHED);

Просмотреть файл

@ -28,7 +28,10 @@ let promise = require("promise");
const TEST_DIR = gTestPath.substr(0, gTestPath.lastIndexOf("/"));
const CHROME_URL_ROOT = TEST_DIR + "/";
const URL_ROOT = CHROME_URL_ROOT.replace("chrome://mochitests/content/", "http://example.com/");
const URL_ROOT = CHROME_URL_ROOT.replace("chrome://mochitests/content/",
"http://example.com/");
const URL_ROOT_SSL = CHROME_URL_ROOT.replace("chrome://mochitests/content/",
"https://example.com/");
// All test are asynchronous
waitForExplicitFinish();

Просмотреть файл

@ -8,7 +8,7 @@
const {PropertyView} =
require("devtools/client/inspector/computed/computed");
const TEST_URI = TEST_URL_ROOT + "doc_matched_selectors.html";
const TEST_URI = URL_ROOT + "doc_matched_selectors.html";
add_task(function*() {
yield addTab(TEST_URI);

Просмотреть файл

@ -7,7 +7,7 @@
// Tests that we correctly display appropriate media query titles in the
// property view.
const TEST_URI = TEST_URL_ROOT + "doc_media_queries.html";
const TEST_URI = URL_ROOT + "doc_media_queries.html";
var {PropertyView} = require("devtools/client/inspector/computed/computed");
var {CssLogic} = require("devtools/shared/inspector/css-logic");

Просмотреть файл

@ -7,7 +7,7 @@
// Tests that the computed view shows the original source link when source maps
// are enabled.
const TESTCASE_URI = TEST_URL_ROOT_SSL + "doc_sourcemaps.html";
const TESTCASE_URI = URL_ROOT_SSL + "doc_sourcemaps.html";
const PREF = "devtools.styleeditor.source-maps-enabled";
const SCSS_LOC = "doc_sourcemaps.scss:4";
const CSS_LOC = "doc_sourcemaps.css:1";

Просмотреть файл

@ -6,7 +6,7 @@
// Tests that pseudoelements are displayed correctly in the rule view.
const TEST_URI = TEST_URL_ROOT + "doc_pseudoelement.html";
const TEST_URI = URL_ROOT + "doc_pseudoelement.html";
add_task(function*() {
yield addTab(TEST_URI);

Просмотреть файл

@ -19,7 +19,9 @@ add_task(function*() {
info("Changing the node's style and waiting for the update");
let onUpdated = inspector.once("computed-view-refreshed");
getNode("#testdiv").style.cssText = "font-size: 15px; color: red;";
// FIXME: use the testActor to set style on the node.
content.document.querySelector("#testdiv")
.style.cssText = "font-size: 15px; color: red;";
yield onUpdated;
fontSize = getComputedViewPropertyValue(view, "font-size");

Просмотреть файл

@ -44,7 +44,7 @@ add_task(function*() {
yield checkSelectAll(view);
});
function checkCopySelection(view) {
function* checkCopySelection(view) {
info("Testing selection copy");
let contentDocument = view.styleDocument;
@ -63,16 +63,15 @@ function checkCopySelection(view) {
"font-size: 16px;[\\r\\n]+" +
"font-variant-caps: small-caps;[\\r\\n]*";
return waitForClipboard(() => {
fireCopyEvent(props[0]);
}, () => {
return checkClipboardData(expectedPattern);
}).then(() => {}, () => {
try {
yield waitForClipboard(() => fireCopyEvent(props[0]),
() => checkClipboardData(expectedPattern));
} catch (e) {
failedClipboard(expectedPattern);
});
}
}
function checkSelectAll(view) {
function* checkSelectAll(view) {
info("Testing select-all copy");
let contentDoc = view.styleDocument;
@ -86,13 +85,12 @@ function checkSelectAll(view) {
"font-size: 16px;[\\r\\n]+" +
"font-variant-caps: small-caps;[\\r\\n]*";
return waitForClipboard(() => {
fireCopyEvent(prop);
}, () => {
return checkClipboardData(expectedPattern);
}).then(() => {}, () => {
try {
yield waitForClipboard(() => fireCopyEvent(prop),
() => checkClipboardData(expectedPattern));
} catch (e) {
failedClipboard(expectedPattern);
});
}
}
function checkClipboardData(expectedPattern) {

Просмотреть файл

@ -1,137 +1,31 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
"use strict";
let Cu = Components.utils;
let {gDevTools} = Cu.import("resource://devtools/client/framework/gDevTools.jsm", {});
let {require} = Cu.import("resource://devtools/shared/Loader.jsm", {});
let {TargetFactory} = require("devtools/client/framework/target");
let {CssComputedView} =
require("devtools/client/inspector/computed/computed");
let DevToolsUtils = require("devtools/shared/DevToolsUtils");
let promise = require("promise");
let {console} =
Components.utils.import("resource://gre/modules/Console.jsm", {});
// Import the inspector's head.js first (which itself imports shared-head.js).
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
// All tests are asynchronous
waitForExplicitFinish();
const TEST_URL_ROOT =
"http://example.com/browser/devtools/client/inspector/computed/test/";
const TEST_URL_ROOT_SSL =
"https://example.com/browser/devtools/client/inspector/computed/test/";
const ROOT_TEST_DIR = getRootDirectory(gTestPath);
const FRAME_SCRIPT_URL = ROOT_TEST_DIR + "doc_frame_script.js";
// Auto clean-up when a test ends
registerCleanupFunction(function*() {
let target = TargetFactory.forTab(gBrowser.selectedTab);
yield gDevTools.closeToolbox(target);
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
// Uncomment this pref to dump all devtools emitted events to the console.
// Services.prefs.setBoolPref("devtools.dump.emit", true);
// Set the testing flag on gDevTools and reset it when the test ends
DevToolsUtils.testing = true;
registerCleanupFunction(() => DevToolsUtils.testing = false);
// Clean-up all prefs that might have been changed during a test run
// (safer here because if the test fails, then the pref is never reverted)
registerCleanupFunction(() => {
Services.prefs.clearUserPref("devtools.inspector.activeSidebar");
Services.prefs.clearUserPref("devtools.dump.emit");
Services.prefs.clearUserPref("devtools.defaultColorUnit");
});
/**
* The functions found below are here to ease test development and maintenance.
* Most of these functions are stateless and will require some form of context
* (the instance of the current toolbox, or inspector panel for instance).
*
* Most of these functions are async too and return promises.
*
* All tests should follow the following pattern:
*
* add_task(function*() {
* yield addTab(TEST_URI);
* let {toolbox, inspector, view} = yield openComputedView();
*
* yield selectNode("#test", inspector);
* yield someAsyncTestFunction(view);
* });
*
* add_task is the way to define the testcase in the test file. It accepts
* a single generator-function argument.
* The generator function should yield any async call.
*
* There is no need to clean tabs up at the end of a test as this is done
* automatically.
*
* It is advised not to store any references on the global scope. There
* shouldn't be a need to anyway. Thanks to add_task, test steps, even
* though asynchronous, can be described in a nice flat way, and
* if/for/while/... control flow can be used as in sync code, making it
* possible to write the outline of the test case all in add_task, and delegate
* actual processing and assertions to other functions.
* Open the toolbox, with the inspector tool visible, and the computed-view
* sidebar tab selected.
* @return a promise that resolves when the inspector is ready and the computed
* view is visible and ready
*/
/* *********************************************
* UTILS
* *********************************************
* General test utilities.
* Add new tabs, open the toolbox and switch to the various panels, select
* nodes, get node references, ...
*/
/**
* Add a new test tab in the browser and load the given url.
*
* @param {String} url
* The url to be loaded in the new tab
* @return a promise that resolves to the tab object when the url is loaded
*/
function addTab(url) {
info("Adding a new tab with URL: '" + url + "'");
let def = promise.defer();
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let browser = tab.linkedBrowser;
info("Loading the helper frame script " + FRAME_SCRIPT_URL);
browser.messageManager.loadFrameScript(FRAME_SCRIPT_URL, false);
browser.addEventListener("load", function onload() {
browser.removeEventListener("load", onload, true);
info("URL '" + url + "' loading complete");
def.resolve(tab);
}, true);
return def.promise;
}
/**
* Simple DOM node accesor function that takes either a node or a string css
* selector as argument and returns the corresponding node
*
* @param {String|DOMNode} nodeOrSelector
* @return {DOMNode|CPOW} Note that in e10s mode a CPOW object is returned which
* doesn't implement *all* of the DOMNode's properties
*/
function getNode(nodeOrSelector) {
info("Getting the node for '" + nodeOrSelector + "'");
return typeof nodeOrSelector === "string" ?
content.document.querySelector(nodeOrSelector) :
nodeOrSelector;
function openComputedView() {
return openInspectorSidebarTab("computedview").then(objects => {
return {
toolbox: objects.toolbox,
inspector: objects.inspector,
view: objects.view.view
};
});
}
/**
@ -146,187 +40,6 @@ function getNodeFront(selector, {walker}) {
return walker.querySelector(walker.rootNode, selector);
}
/*
* Set the inspector's current selection to a node or to the first match of the
* given css selector.
*
* @param {String|NodeFront} data
* The node to select
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @param {String} reason
* Defaults to "test" which instructs the inspector not
* to highlight the node upon selection
* @return {Promise} Resolves when the inspector is updated with the new node
*/
var selectNode = Task.async(function*(data, inspector, reason="test") {
info("Selecting the node for '" + data + "'");
let nodeFront = data;
if (!data._form) {
nodeFront = yield getNodeFront(data, inspector);
}
let updated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(nodeFront, reason);
yield updated;
});
/**
* Open the toolbox, with the inspector tool visible.
*
* @return a promise that resolves when the inspector is ready
*/
var openInspector = Task.async(function*() {
info("Opening the inspector");
let target = TargetFactory.forTab(gBrowser.selectedTab);
let inspector, toolbox;
// Checking if the toolbox and the inspector are already loaded
// The inspector-updated event should only be waited for if the inspector
// isn't loaded yet
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
inspector = toolbox.getPanel("inspector");
if (inspector) {
info("Toolbox and inspector already open");
return {
toolbox: toolbox,
inspector: inspector
};
}
}
info("Opening the toolbox");
toolbox = yield gDevTools.showToolbox(target, "inspector");
yield waitForToolboxFrameFocus(toolbox);
inspector = toolbox.getPanel("inspector");
info("Waiting for the inspector to update");
yield inspector.once("inspector-updated");
return {
toolbox: toolbox,
inspector: inspector
};
});
/**
* Wait for the toolbox frame to receive focus after it loads
*
* @param {Toolbox} toolbox
* @return a promise that resolves when focus has been received
*/
function waitForToolboxFrameFocus(toolbox) {
info("Making sure that the toolbox's frame is focused");
let def = promise.defer();
let win = toolbox.frame.contentWindow;
waitForFocus(def.resolve, win);
return def.promise;
}
/**
* Open the toolbox, with the inspector tool visible, and the sidebar that
* corresponds to the given id selected
*
* @return a promise that resolves when the inspector is ready and the sidebar
* view is visible and ready
*/
var openInspectorSideBar = Task.async(function*(id) {
let {toolbox, inspector} = yield openInspector();
if (!hasSideBarTab(inspector, id)) {
info("Waiting for the " + id + " sidebar to be ready");
yield inspector.sidebar.once(id + "-ready");
}
info("Selecting the " + id + " sidebar");
inspector.sidebar.select(id);
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab(id)[id].view
};
});
/**
* Open the toolbox, with the inspector tool visible, and the computed-view
* sidebar tab selected.
*
* @return a promise that resolves when the inspector is ready and the computed
* view is visible and ready
*/
function openComputedView() {
return openInspectorSideBar("computedview");
}
/**
* Wait for eventName on target to be delivered a number of times.
*
* @param {Object} target
* An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Number} numTimes
* Number of deliveries to wait for.
* @param {Boolean} useCapture
* Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function waitForNEvents(target, eventName, numTimes, useCapture = false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
let count = 0;
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
if (++count == numTimes) {
target[remove](eventName, onEvent, useCapture);
deferred.resolve.apply(deferred, aArgs);
}
}, useCapture);
break;
}
}
return deferred.promise;
}
/**
* Wait for eventName on target.
*
* @param {Object} target
* An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture
* Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
return waitForNEvents(target, eventName, 1, useCapture);
}
/**
* This shouldn't be used in the tests, but is useful when writing new tests or
* debugging existing tests in order to introduce delays in the test steps
*
* @param {Number} ms
* The time to wait
* @return A promise that resolves when the time is passed
*/
function wait(ms) {
let def = promise.defer();
content.setTimeout(def.resolve, ms);
return def.promise;
}
/**
* Listen for a new tab to open and return a promise that resolves when one
* does and completes the load event.
@ -343,23 +56,6 @@ var waitForTab = Task.async(function*() {
return tab;
});
/**
* @see SimpleTest.waitForClipboard
*
* @param {Function} setup
* Function to execute before checking for the
* clipboard content
* @param {String|Boolean} expected
* An expected string or validator function
* @return a promise that resolves when the expected string has been found or
* the validator function has returned true, rejects otherwise.
*/
function waitForClipboard(setup, expected) {
let def = promise.defer();
SimpleTest.waitForClipboard(expected, setup, def.resolve, def.reject);
return def.promise;
}
/**
* Dispatch the copy event on the given element
*/
@ -369,18 +65,6 @@ function fireCopyEvent(element) {
element.dispatchEvent(evt);
}
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
*
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Simulate the key input for the given input in the window.
*
@ -395,13 +79,6 @@ function synthesizeKeys(input, win) {
}
}
/* *********************************************
* COMPUTED-VIEW
* *********************************************
* Computed-view related utility functions.
* Allows to get properties, links, expand properties, ...
*/
/**
* Get references to the name and value span nodes corresponding to a given
* property name in the computed-view
@ -534,77 +211,3 @@ function getComputedViewLinkByIndex(view, index) {
let links = view.styleDocument.querySelectorAll(".rule-link .link");
return links[index];
}
/* *********************************************
* STYLE-EDITOR
* *********************************************
* Style-editor related utility functions.
*/
/**
* Wait for the toolbox to emit the styleeditor-selected event and when done
* wait for the stylesheet identified by href to be loaded in the stylesheet
* editor
*
* @param {Toolbox} toolbox
* @param {String} href
* Optional, if not provided, wait for the first editor to be ready
* @return a promise that resolves to the editor when the stylesheet editor is
* ready
*/
function waitForStyleEditor(toolbox, href) {
let def = promise.defer();
info("Waiting for the toolbox to switch to the styleeditor");
toolbox.once("styleeditor-selected").then(() => {
let panel = toolbox.getCurrentPanel();
ok(panel && panel.UI, "Styleeditor panel switched to front");
// A helper that resolves the promise once it receives an editor that
// matches the expected href. Returns false if the editor was not correct.
let gotEditor = (event, editor) => {
let currentHref = editor.styleSheet.href;
if (!href || (href && currentHref.endsWith(href))) {
info("Stylesheet editor selected");
panel.UI.off("editor-selected", gotEditor);
editor.getSourceEditor().then(sourceEditor => {
info("Stylesheet editor fully loaded");
def.resolve(sourceEditor);
});
return true;
}
info("The editor was incorrect. Waiting for editor-selected event.");
return false;
};
// The expected editor may already be selected. Check the if the currently
// selected editor is the expected one and if not wait for an
// editor-selected event.
if (!gotEditor("styleeditor-selected", panel.UI.selectedEditor)) {
// The expected editor is not selected (yet). Wait for it.
panel.UI.on("editor-selected", gotEditor);
}
});
return def.promise;
}
/**
* Reload the current page and wait for the inspector to be initialized after
* the navigation
*
* @param {InspectorPanel} inspector
* The instance of InspectorPanel currently loaded in the toolbox
* @return a promise that resolves after page reload and inspector
* initialization
*/
function reloadPage(inspector) {
let onNewRoot = inspector.once("new-root");
content.location.reload();
return onNewRoot.then(() => {
inspector.markup._waitForChildren();
});
}

Просмотреть файл

@ -5,23 +5,23 @@
requestLongerTimeout(2);
const TEST_URI = BASE_URI + "browser_fontinspector.html";
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
const FONTS = [
{name: "Ostrich Sans Medium", remote: true, url: BASE_URI + "ostrich-regular.ttf",
{name: "Ostrich Sans Medium", remote: true, url: URL_ROOT + "ostrich-regular.ttf",
format: "truetype", cssName: "bar"},
{name: "Ostrich Sans Black", remote: true, url: BASE_URI + "ostrich-black.ttf",
{name: "Ostrich Sans Black", remote: true, url: URL_ROOT + "ostrich-black.ttf",
format: "", cssName: "bar"},
{name: "Ostrich Sans Black", remote: true, url: BASE_URI + "ostrich-black.ttf",
{name: "Ostrich Sans Black", remote: true, url: URL_ROOT + "ostrich-black.ttf",
format: "", cssName: "bar"},
{name: "Ostrich Sans Medium", remote: true, url: BASE_URI + "ostrich-regular.ttf",
{name: "Ostrich Sans Medium", remote: true, url: URL_ROOT + "ostrich-regular.ttf",
format: "", cssName: "barnormal"},
];
add_task(function*() {
let { inspector, fontInspector } = yield openFontInspectorForURL(TEST_URI);
ok(!!fontInspector, "Font inspector document is alive.");
let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
ok(!!view, "Font inspector document is alive.");
let viewDoc = fontInspector.chromeDoc;
let viewDoc = view.chromeDoc;
yield testBodyFonts(inspector, viewDoc);
yield testDivFonts(inspector, viewDoc);

Просмотреть файл

@ -6,11 +6,11 @@
// Test that correct previews are shown if the text is edited after 'Show all'
// button is pressed.
const TEST_URI = BASE_URI + "browser_fontinspector.html";
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
add_task(function*() {
let { inspector, fontInspector } = yield openFontInspectorForURL(TEST_URI);
let viewDoc = fontInspector.chromeDoc;
let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
let viewDoc = view.chromeDoc;
info("Selecting a node that doesn't contain all document fonts.");
yield selectNode(".normal-text", inspector);
@ -36,7 +36,7 @@ add_task(function*() {
"The .normal-text didn't show all fonts.");
info("Editing the preview text.");
yield updatePreviewText(fontInspector, "The quick brown");
yield updatePreviewText(view, "The quick brown");
let numPreviews = viewDoc.querySelectorAll("#all-fonts .font-preview").length;
is(numPreviews, allFontsNumPreviews,

Просмотреть файл

@ -7,25 +7,25 @@
// exact preview images because they are drawn on a canvas causing them to vary
// between systems, platforms and software versions.
const TEST_URI = BASE_URI + "browser_fontinspector.html";
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
add_task(function*() {
let { inspector, fontInspector } = yield openFontInspectorForURL(TEST_URI);
let viewDoc = fontInspector.chromeDoc;
let {view} = yield openFontInspectorForURL(TEST_URI);
let viewDoc = view.chromeDoc;
let previews = viewDoc.querySelectorAll("#all-fonts .font-preview");
let initialPreviews = [...previews].map(p => p.src);
info("Typing 'Abc' to check that the reference previews are correct.");
yield updatePreviewText(fontInspector, "Abc");
yield updatePreviewText(view, "Abc");
checkPreviewImages(viewDoc, initialPreviews, true);
info("Typing something else to the preview box.");
yield updatePreviewText(fontInspector, "The quick brown");
yield updatePreviewText(view, "The quick brown");
checkPreviewImages(viewDoc, initialPreviews, false);
info("Blanking the input to restore default previews.");
yield updatePreviewText(fontInspector, "");
yield updatePreviewText(view, "");
checkPreviewImages(viewDoc, initialPreviews, true);
});

Просмотреть файл

@ -9,7 +9,7 @@ requestLongerTimeout(2);
const { getTheme, setTheme } = require("devtools/client/shared/theme");
const TEST_URI = BASE_URI + "browser_fontinspector.html";
const TEST_URI = URL_ROOT + "browser_fontinspector.html";
const originalTheme = getTheme();
registerCleanupFunction(() => {
@ -18,8 +18,8 @@ registerCleanupFunction(() => {
});
add_task(function* () {
let { inspector, fontInspector } = yield openFontInspectorForURL(TEST_URI);
let { chromeDoc: doc } = fontInspector;
let { inspector, view } = yield openFontInspectorForURL(TEST_URI);
let { chromeDoc: doc } = view;
yield selectNode(".normal-text", inspector);

Просмотреть файл

@ -2,79 +2,21 @@
/* 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
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
"use strict";
// shared-head.js handles imports, constants, and utility functions
Services.scriptloader.loadSubScript("chrome://mochitests/content/browser/devtools/client/framework/test/shared-head.js", this);
const BASE_URI = "http://mochi.test:8888/browser/devtools/client/inspector/fonts/test/";
/**
* Open the toolbox, with the inspector tool visible.
* @param {Function} cb Optional callback, if you don't want to use the returned
* promise
* @return a promise that resolves when the inspector is ready
*/
var openInspector = Task.async(function*(cb) {
info("Opening the inspector");
let target = TargetFactory.forTab(gBrowser.selectedTab);
let inspector, toolbox;
// Checking if the toolbox and the inspector are already loaded
// The inspector-updated event should only be waited for if the inspector
// isn't loaded yet
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
inspector = toolbox.getPanel("inspector");
if (inspector) {
info("Toolbox and inspector already open");
if (cb) {
return cb(inspector, toolbox);
} else {
return {
toolbox: toolbox,
inspector: inspector
};
}
}
}
info("Opening the toolbox");
toolbox = yield gDevTools.showToolbox(target, "inspector");
yield waitForToolboxFrameFocus(toolbox);
inspector = toolbox.getPanel("inspector");
info("Waiting for the inspector to update");
yield inspector.once("inspector-updated");
if (cb) {
return cb(inspector, toolbox);
} else {
return {
toolbox: toolbox,
inspector: inspector
};
}
});
// Import the inspector's head.js first (which itself imports shared-head.js).
Services.scriptloader.loadSubScript(
"chrome://mochitests/content/browser/devtools/client/inspector/test/head.js",
this);
/**
* Adds a new tab with the given URL, opens the inspector and selects the
* font-inspector tab.
*
* @return Object
* {
* toolbox,
* inspector,
* fontInspector
* }
* @return {Promise} resolves to a {toolbox, inspector, view} object
*/
var openFontInspectorForURL = Task.async(function* (url) {
info("Opening tab " + url);
var openFontInspectorForURL = Task.async(function*(url) {
yield addTab(url);
let { toolbox, inspector } = yield openInspector();
let {toolbox, inspector} = yield openInspectorSidebarTab("fontinspector");
/**
* Call selectNode to trigger font-inspector update so that we don't timeout
@ -88,74 +30,29 @@ var openFontInspectorForURL = Task.async(function* (url) {
* FontInspector.update that emits the 'fontinspector-updated' event.
*/
let onUpdated = inspector.once("fontinspector-updated");
yield selectNode("body", inspector);
inspector.sidebar.select("fontinspector");
info("Waiting for font-inspector to update.");
yield onUpdated;
info("Font Inspector ready.");
let { fontInspector } = inspector.sidebar.getWindowForTab("fontinspector");
return {
fontInspector,
toolbox,
inspector,
toolbox
view: inspector.sidebar.getWindowForTab("fontinspector").fontInspector
};
});
/**
* Select a node in the inspector given its selector.
*/
var selectNode = Task.async(function*(selector, inspector, reason="test") {
info("Selecting the node for '" + selector + "'");
let nodeFront = yield getNodeFront(selector, inspector);
let updated = inspector.once("inspector-updated");
inspector.selection.setNodeFront(nodeFront, reason);
yield updated;
});
/**
* Get the NodeFront for a given css selector, via the protocol
* @param {String|NodeFront} selector
* @param {InspectorPanel} inspector The instance of InspectorPanel currently
* loaded in the toolbox
* @return {Promise} Resolves to the NodeFront instance
*/
function getNodeFront(selector, {walker}) {
if (selector._form) {
return selector;
}
return walker.querySelector(walker.rootNode, selector);
}
/**
* Wait for the toolbox frame to receive focus after it loads
* @param {Toolbox} toolbox
* @return a promise that resolves when focus has been received
*/
function waitForToolboxFrameFocus(toolbox) {
info("Making sure that the toolbox's frame is focused");
let def = promise.defer();
let win = toolbox.frame.contentWindow;
waitForFocus(def.resolve, win);
return def.promise;
}
/**
* Clears the preview input field, types new text into it and waits for the
* preview images to be updated.
*
* @param {FontInspector} fontInspector - The FontInspector instance.
* @param {FontInspector} view - The FontInspector instance.
* @param {String} text - The text to preview.
*/
function* updatePreviewText(fontInspector, text) {
function* updatePreviewText(view, text) {
info(`Changing the preview text to '${text}'`);
let doc = fontInspector.chromeDoc;
let doc = view.chromeDoc;
let input = doc.getElementById("preview-text-input");
let update = fontInspector.inspector.once("fontinspector-updated");
let update = view.inspector.once("fontinspector-updated");
info("Focusing the input field.");
input.focus();

Просмотреть файл

@ -45,52 +45,29 @@ function selectAndHighlightNode(nodeOrSelector, inspector) {
return updated;
}
/**
* Checks whether the inspector's sidebar corresponding to the given id already
* exists
* @param {InspectorPanel}
* @param {String}
* @return {Boolean}
*/
function hasSideBarTab(inspector, id) {
return !!inspector.sidebar.getWindowForTab(id);
}
/**
* Open the toolbox, with the inspector tool visible, and the layout-view
* sidebar tab selected.
* @return a promise that resolves when the inspector is ready and the layout
* view is visible and ready
*/
var openLayoutView = Task.async(function*() {
let {toolbox, inspector} = yield openInspector();
function openLayoutView() {
return openInspectorSidebarTab("layoutview").then(objects => {
// The actual highligher show/hide methods are mocked in layoutview tests.
// The highlighter is tested in devtools/inspector/test.
function mockHighlighter({highlighter}) {
highlighter.showBoxModel = function(nodeFront, options) {
return promise.resolve();
};
highlighter.hideBoxModel = function() {
return promise.resolve();
};
}
mockHighlighter(objects.toolbox);
// The actual highligher show/hide methods are mocked in layoutview tests.
// The highlighter is tested in devtools/inspector/test.
function mockHighlighter({highlighter}) {
highlighter.showBoxModel = function(nodeFront, options) {
return promise.resolve();
};
highlighter.hideBoxModel = function() {
return promise.resolve();
};
}
mockHighlighter(toolbox);
if (!hasSideBarTab(inspector, "layoutview")) {
info("Waiting for the layoutview sidebar to be ready");
yield inspector.sidebar.once("layoutview-ready");
}
info("Selecting the layoutview sidebar");
inspector.sidebar.select("layoutview");
return {
toolbox: toolbox,
inspector: inspector,
view: inspector.sidebar.getWindowForTab("layoutview")["layoutview"]
};
});
return objects;
});
}
/**
* Wait for the layoutview-updated event.

Просмотреть файл

@ -5,10 +5,10 @@
"use strict";
// Test native anonymous content in the markupview.
const TEST_URL = TEST_URL_ROOT + "doc_markup_anonymous.html";
const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
add_task(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let {inspector} = yield openInspectorForURL(TEST_URL);
let pseudo = yield getNodeFront("#pseudo", inspector);

Просмотреть файл

@ -10,7 +10,7 @@ requestLongerTimeout(2);
const TEST_URL = "chrome://devtools/content/scratchpad/scratchpad.xul";
add_task(function*() {
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let {inspector} = yield openInspectorForURL(TEST_URL);
let toolbarbutton = yield getNodeFront("toolbarbutton", inspector);
let children = yield inspector.walker.children(toolbarbutton);

Просмотреть файл

@ -7,12 +7,12 @@
// Test shadow DOM content in the markupview.
// Note that many features are not yet enabled, but basic listing
// of elements should be working.
const TEST_URL = TEST_URL_ROOT + "doc_markup_anonymous.html";
const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
add_task(function*() {
Services.prefs.setBoolPref("dom.webcomponents.enabled", true);
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let {inspector} = yield openInspectorForURL(TEST_URL);
let shadow = yield getNodeFront("#shadow", inspector.markup);
let children = yield inspector.walker.children(shadow);

Просмотреть файл

@ -6,12 +6,12 @@
// Test native anonymous content in the markupview with devtools.inspector.showAllAnonymousContent
// set to true
const TEST_URL = TEST_URL_ROOT + "doc_markup_anonymous.html";
const TEST_URL = URL_ROOT + "doc_markup_anonymous.html";
add_task(function*() {
Services.prefs.setBoolPref("devtools.inspector.showAllAnonymousContent", true);
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let {inspector} = yield openInspectorForURL(TEST_URL);
let native = yield getNodeFront("#native", inspector);

Просмотреть файл

@ -12,7 +12,7 @@
// The correctness and cycling of the suggestions is covered in the ruleview
// tests.
const TEST_URL = TEST_URL_ROOT + "doc_markup_edit.html";
const TEST_URL = URL_ROOT + "doc_markup_edit.html";
// test data format :
// [
// what key to press,
@ -65,7 +65,7 @@ const TEST_DATA = [
add_task(function*() {
info("Opening the inspector on the test URL");
let {inspector} = yield addTab(TEST_URL).then(openInspector);
let {inspector} = yield openInspectorForURL(TEST_URL);
yield inspector.markup.expandAll();

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше