зеркало из https://github.com/mozilla/gecko-dev.git
Merge autoland to central, a=merge
MozReview-Commit-ID: FTkalcNxO2k
This commit is contained in:
Коммит
8294014f54
|
@ -3,3 +3,4 @@
|
||||||
[browser_EventEmitter.js]
|
[browser_EventEmitter.js]
|
||||||
[browser_Storage.js]
|
[browser_Storage.js]
|
||||||
[browser_Heartbeat.js]
|
[browser_Heartbeat.js]
|
||||||
|
skip-if = true # bug 1325409
|
||||||
|
|
|
@ -140,19 +140,36 @@ normalize_path = normalize_path()
|
||||||
@imports(_from='which', _import='which')
|
@imports(_from='which', _import='which')
|
||||||
@imports(_from='which', _import='WhichError')
|
@imports(_from='which', _import='WhichError')
|
||||||
@imports('itertools')
|
@imports('itertools')
|
||||||
|
@imports('sys')
|
||||||
@imports(_from='os', _import='pathsep')
|
@imports(_from='os', _import='pathsep')
|
||||||
|
@imports(_from='os', _import='environ')
|
||||||
def find_program(file, paths=None):
|
def find_program(file, paths=None):
|
||||||
|
# The following snippet comes from `which` itself, with a slight
|
||||||
|
# modification to use lowercase extensions, because it's confusing rustup
|
||||||
|
# (on top of making results not really appealing to the eye).
|
||||||
|
|
||||||
|
# Windows has the concept of a list of extensions (PATHEXT env var).
|
||||||
|
if sys.platform.startswith("win"):
|
||||||
|
exts = [e.lower()
|
||||||
|
for e in environ.get("PATHEXT", "").split(pathsep)]
|
||||||
|
# If '.exe' is not in exts then obviously this is Win9x and
|
||||||
|
# or a bogus PATHEXT, then use a reasonable default.
|
||||||
|
if '.exe' not in exts:
|
||||||
|
exts = ['.com', '.exe', '.bat']
|
||||||
|
else:
|
||||||
|
exts = None
|
||||||
|
|
||||||
try:
|
try:
|
||||||
if is_absolute_or_relative(file):
|
if is_absolute_or_relative(file):
|
||||||
return normalize_path(which(os.path.basename(file),
|
return normalize_path(which(os.path.basename(file),
|
||||||
[os.path.dirname(file)]))
|
[os.path.dirname(file)], exts=exts))
|
||||||
if paths:
|
if paths:
|
||||||
if not isinstance(paths, (list, tuple)):
|
if not isinstance(paths, (list, tuple)):
|
||||||
die("Paths provided to find_program must be a list of strings, "
|
die("Paths provided to find_program must be a list of strings, "
|
||||||
"not %r", paths)
|
"not %r", paths)
|
||||||
paths = list(itertools.chain(
|
paths = list(itertools.chain(
|
||||||
*(p.split(pathsep) for p in paths if p)))
|
*(p.split(pathsep) for p in paths if p)))
|
||||||
return normalize_path(which(file, path=paths))
|
return normalize_path(which(file, path=paths, exts=exts))
|
||||||
except WhichError:
|
except WhichError:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
@ -188,7 +188,7 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="propertyContainer" class="theme-separator" tabindex="0">
|
<div id="propertyContainer" class="theme-separator" tabindex="0" dir="ltr">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"></div>
|
<div id="computedview-no-results" hidden="" data-localization="content=inspector.noProperties"></div>
|
||||||
|
|
|
@ -490,7 +490,8 @@ ServoStyleSet::NoteStyleSheetsChanged()
|
||||||
void
|
void
|
||||||
ServoStyleSet::AssertTreeIsClean()
|
ServoStyleSet::AssertTreeIsClean()
|
||||||
{
|
{
|
||||||
if (Element* root = mPresContext->Document()->GetRootElement()) {
|
DocumentStyleRootIterator iter(mPresContext->Document());
|
||||||
|
while (Element* root = iter.GetNextStyleRoot()) {
|
||||||
Servo_AssertTreeIsClean(root);
|
Servo_AssertTreeIsClean(root);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -369,7 +369,17 @@ class RefTest(object):
|
||||||
|
|
||||||
# Enable leaks detection to its own log file.
|
# Enable leaks detection to its own log file.
|
||||||
self.leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
|
self.leakLogFile = os.path.join(profileDir, "runreftest_leaks.log")
|
||||||
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leakLogFile
|
|
||||||
|
# Leak checking was broken in reftest unnoticed for a length of time. During
|
||||||
|
# this time, a leak slipped into the crashtest suite. The leak checking was
|
||||||
|
# fixed by bug 1325148, but it couldn't land until the regression in crashtest
|
||||||
|
# was also fixed or backed out. Rather than waiting and risking new regressions,
|
||||||
|
# temporarily disable leak checking in crashtest. Fix is tracked by bug 1325215.
|
||||||
|
if options.suite == 'crashtest' and mozinfo.info['os'] == 'linux':
|
||||||
|
self.log.warning('WARNING | leakcheck disabled due to bug 1325215')
|
||||||
|
else:
|
||||||
|
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leakLogFile
|
||||||
|
|
||||||
return browserEnv
|
return browserEnv
|
||||||
|
|
||||||
def killNamedOrphans(self, pname):
|
def killNamedOrphans(self, pname):
|
||||||
|
|
|
@ -146,11 +146,13 @@ class MachCommands(MachCommandBase):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
for future in as_completed(futures):
|
for future in as_completed(futures):
|
||||||
output, ret = future.result()
|
output, ret, test_path = future.result()
|
||||||
|
|
||||||
for line in output:
|
for line in output:
|
||||||
self.log(logging.INFO, 'python-test', {'line': line.rstrip()}, '{line}')
|
self.log(logging.INFO, 'python-test', {'line': line.rstrip()}, '{line}')
|
||||||
|
|
||||||
|
if ret and not return_code:
|
||||||
|
self.log(logging.ERROR, 'python-test', {'test_path': test_path, 'ret': ret}, 'Setting retcode to {ret} from {test_path}')
|
||||||
return_code = return_code or ret
|
return_code = return_code or ret
|
||||||
except KeyboardInterrupt:
|
except KeyboardInterrupt:
|
||||||
# Hack to force stop currently running threads.
|
# Hack to force stop currently running threads.
|
||||||
|
@ -159,6 +161,7 @@ class MachCommands(MachCommandBase):
|
||||||
thread._threads_queues.clear()
|
thread._threads_queues.clear()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
|
self.log(logging.INFO, 'python-test', {'return_code': return_code}, 'Return code from mach python-test: {return_code}')
|
||||||
return return_code
|
return return_code
|
||||||
|
|
||||||
def _run_python_test(self, test_path):
|
def _run_python_test(self, test_path):
|
||||||
|
@ -204,4 +207,4 @@ class MachCommands(MachCommandBase):
|
||||||
else:
|
else:
|
||||||
_log('Test passed: {}'.format(test_path))
|
_log('Test passed: {}'.format(test_path))
|
||||||
|
|
||||||
return output, return_code
|
return output, return_code, test_path
|
||||||
|
|
|
@ -537,6 +537,16 @@ class BaseBootstrapper(object):
|
||||||
cargo_bin = os.path.join(cargo_home, 'bin')
|
cargo_bin = os.path.join(cargo_home, 'bin')
|
||||||
return cargo_home, cargo_bin
|
return cargo_home, cargo_bin
|
||||||
|
|
||||||
|
def win_to_msys_path(self, path):
|
||||||
|
'''Convert a windows-style path to msys style.'''
|
||||||
|
drive, path = os.path.splitdrive(path)
|
||||||
|
path = '/'.join(path.split('\\'))
|
||||||
|
if drive:
|
||||||
|
if path[0] == '/':
|
||||||
|
path = path[1:]
|
||||||
|
path = '/%s/%s' % (drive[:-1], path)
|
||||||
|
return path
|
||||||
|
|
||||||
def print_rust_path_advice(self, template, cargo_home, cargo_bin):
|
def print_rust_path_advice(self, template, cargo_home, cargo_bin):
|
||||||
# Suggest ~/.cargo/env if it exists.
|
# Suggest ~/.cargo/env if it exists.
|
||||||
if os.path.exists(os.path.join(cargo_home, 'env')):
|
if os.path.exists(os.path.join(cargo_home, 'env')):
|
||||||
|
@ -546,7 +556,7 @@ class BaseBootstrapper(object):
|
||||||
# so fall back to a manual PATH update. Bootstrap
|
# so fall back to a manual PATH update. Bootstrap
|
||||||
# only runs under msys, so a unix-style shell command
|
# only runs under msys, so a unix-style shell command
|
||||||
# is appropriate there.
|
# is appropriate there.
|
||||||
cmd = 'export PATH=%s:$PATH' % cargo_bin
|
cmd = 'export PATH=%s:$PATH' % self.win_to_msys_path(cargo_bin)
|
||||||
print(template % {
|
print(template % {
|
||||||
'cargo_bin': cargo_bin,
|
'cargo_bin': cargo_bin,
|
||||||
'cmd': cmd,
|
'cmd': cmd,
|
||||||
|
|
|
@ -175,7 +175,7 @@ class ConfigureTestSandbox(ConfigureSandbox):
|
||||||
path_out.value = fake_short_path(path_in)
|
path_out.value = fake_short_path(path_in)
|
||||||
return length
|
return length
|
||||||
|
|
||||||
def which(self, command, path=None):
|
def which(self, command, path=None, exts=None):
|
||||||
for parent in (path or self._search_path):
|
for parent in (path or self._search_path):
|
||||||
c = mozpath.abspath(mozpath.join(parent, command))
|
c = mozpath.abspath(mozpath.join(parent, command))
|
||||||
for candidate in (c, ensure_exe_extension(c)):
|
for candidate in (c, ensure_exe_extension(c)):
|
||||||
|
|
|
@ -475,6 +475,8 @@ def build_macosx_engine_payload(config, task, task_def):
|
||||||
|
|
||||||
@payload_builder('buildbot-bridge')
|
@payload_builder('buildbot-bridge')
|
||||||
def build_buildbot_bridge_payload(config, task, task_def):
|
def build_buildbot_bridge_payload(config, task, task_def):
|
||||||
|
del task['extra']['treeherder']
|
||||||
|
del task['extra']['treeherderEnv']
|
||||||
worker = task['worker']
|
worker = task['worker']
|
||||||
task_def['payload'] = {
|
task_def['payload'] = {
|
||||||
'buildername': worker['buildername'],
|
'buildername': worker['buildername'],
|
||||||
|
|
|
@ -29,7 +29,7 @@ class TestDVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
with self.marionette.using_context('content'):
|
with self.marionette.using_context('content'):
|
||||||
self.marionette.navigate(self.url)
|
self.marionette.navigate(self.url)
|
||||||
|
|
||||||
self.assertEqual(self.locationbar.identity_box.get_attribute('className'),
|
self.assertEqual(self.locationbar.identity_box.get_property('className'),
|
||||||
'verifiedDomain')
|
'verifiedDomain')
|
||||||
|
|
||||||
# Open the identity popup
|
# Open the identity popup
|
||||||
|
@ -41,7 +41,7 @@ class TestDVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
cert = self.browser.tabbar.selected_tab.certificate
|
cert = self.browser.tabbar.selected_tab.certificate
|
||||||
|
|
||||||
# The shown host equals to the certificate
|
# The shown host equals to the certificate
|
||||||
self.assertEqual(self.identity_popup.view.main.host.get_attribute('textContent'),
|
self.assertEqual(self.identity_popup.view.main.host.get_property('textContent'),
|
||||||
cert['commonName'])
|
cert['commonName'])
|
||||||
|
|
||||||
# Only the secure label is visible in the main view
|
# Only the secure label is visible in the main view
|
||||||
|
@ -52,7 +52,9 @@ class TestDVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
|
self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
|
||||||
|
|
||||||
self.identity_popup.view.main.expander.click()
|
self.identity_popup.view.main.expander.click()
|
||||||
Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
|
Wait(self.marionette).until(
|
||||||
|
lambda _: self.identity_popup.view.security.selected,
|
||||||
|
message='Security view of identity popup has not been selected.')
|
||||||
|
|
||||||
# Only the secure label is visible in the security view
|
# Only the secure label is visible in the security view
|
||||||
secure_label = self.identity_popup.view.security.secure_connection_label
|
secure_label = self.identity_popup.view.security.secure_connection_label
|
||||||
|
@ -62,7 +64,7 @@ class TestDVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
|
self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
|
||||||
|
|
||||||
verifier_label = self.browser.localize_property('identity.identified.verifier')
|
verifier_label = self.browser.localize_property('identity.identified.verifier')
|
||||||
self.assertEqual(self.identity_popup.view.security.verifier.get_attribute('textContent'),
|
self.assertEqual(self.identity_popup.view.security.verifier.get_property('textContent'),
|
||||||
verifier_label.replace("%S", cert['issuerOrganization']))
|
verifier_label.replace("%S", cert['issuerOrganization']))
|
||||||
|
|
||||||
def opener(mn):
|
def opener(mn):
|
||||||
|
@ -73,11 +75,11 @@ class TestDVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
self.assertEqual(deck.selected_panel, deck.security)
|
self.assertEqual(deck.selected_panel, deck.security)
|
||||||
|
|
||||||
self.assertEqual(deck.security.domain.get_attribute('value'),
|
self.assertEqual(deck.security.domain.get_property('value'),
|
||||||
cert['commonName'])
|
cert['commonName'])
|
||||||
|
|
||||||
self.assertEqual(deck.security.owner.get_attribute('value'),
|
self.assertEqual(deck.security.owner.get_property('value'),
|
||||||
page_info_window.localize_property('securityNoOwner'))
|
page_info_window.localize_property('securityNoOwner'))
|
||||||
|
|
||||||
self.assertEqual(deck.security.verifier.get_attribute('value'),
|
self.assertEqual(deck.security.verifier.get_property('value'),
|
||||||
cert['issuerOrganization'])
|
cert['issuerOrganization'])
|
||||||
|
|
|
@ -30,7 +30,7 @@ class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.marionette.navigate(self.url)
|
self.marionette.navigate(self.url)
|
||||||
|
|
||||||
# Check the identity box
|
# Check the identity box
|
||||||
self.assertEqual(self.locationbar.identity_box.get_attribute('className'),
|
self.assertEqual(self.locationbar.identity_box.get_property('className'),
|
||||||
'verifiedIdentity')
|
'verifiedIdentity')
|
||||||
|
|
||||||
# Get the information from the certificate
|
# Get the information from the certificate
|
||||||
|
@ -38,9 +38,9 @@ class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
address = self.puppeteer.security.get_address_from_certificate(cert)
|
address = self.puppeteer.security.get_address_from_certificate(cert)
|
||||||
|
|
||||||
# Check the identity popup label displays
|
# Check the identity popup label displays
|
||||||
self.assertEqual(self.locationbar.identity_organization_label.get_attribute('value'),
|
self.assertEqual(self.locationbar.identity_organization_label.get_property('value'),
|
||||||
cert['organization'])
|
cert['organization'])
|
||||||
self.assertEqual(self.locationbar.identity_country_label.get_attribute('value'),
|
self.assertEqual(self.locationbar.identity_country_label.get_property('value'),
|
||||||
'(' + address['country'] + ')')
|
'(' + address['country'] + ')')
|
||||||
|
|
||||||
# Open the identity popup
|
# Open the identity popup
|
||||||
|
@ -50,7 +50,7 @@ class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertEqual(self.identity_popup.element.get_attribute('connection'), 'secure-ev')
|
self.assertEqual(self.identity_popup.element.get_attribute('connection'), 'secure-ev')
|
||||||
|
|
||||||
# For EV certificates no hostname but the organization name is shown
|
# For EV certificates no hostname but the organization name is shown
|
||||||
self.assertEqual(self.identity_popup.view.main.host.get_attribute('textContent'),
|
self.assertEqual(self.identity_popup.view.main.host.get_property('textContent'),
|
||||||
cert['organization'])
|
cert['organization'])
|
||||||
|
|
||||||
# Only the secure label is visible in the main view
|
# Only the secure label is visible in the main view
|
||||||
|
@ -73,8 +73,7 @@ class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
|
self.assertEqual(insecure_label.value_of_css_property('display'), 'none')
|
||||||
|
|
||||||
# Check the organization name
|
# Check the organization name
|
||||||
self.assertEqual(security_view.owner.get_attribute('textContent'),
|
self.assertEqual(security_view.owner.get_property('textContent'), cert['organization'])
|
||||||
cert['organization'])
|
|
||||||
|
|
||||||
# Check the owner location string
|
# Check the owner location string
|
||||||
# More information:
|
# More information:
|
||||||
|
@ -82,14 +81,12 @@ class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
location = self.browser.localize_property('identity.identified.state_and_country')
|
location = self.browser.localize_property('identity.identified.state_and_country')
|
||||||
location = location.replace('%S', address['state'], 1).replace('%S', address['country'])
|
location = location.replace('%S', address['state'], 1).replace('%S', address['country'])
|
||||||
location = address['city'] + '\n' + location
|
location = address['city'] + '\n' + location
|
||||||
self.assertEqual(security_view.owner_location.get_attribute('textContent'),
|
self.assertEqual(security_view.owner_location.get_property('textContent'), location)
|
||||||
location)
|
|
||||||
|
|
||||||
# Check the verifier
|
# Check the verifier
|
||||||
l10n_verifier = self.browser.localize_property('identity.identified.verifier')
|
l10n_verifier = self.browser.localize_property('identity.identified.verifier')
|
||||||
l10n_verifier = l10n_verifier.replace('%S', cert['issuerOrganization'])
|
l10n_verifier = l10n_verifier.replace('%S', cert['issuerOrganization'])
|
||||||
self.assertEqual(security_view.verifier.get_attribute('textContent'),
|
self.assertEqual(security_view.verifier.get_property('textContent'), l10n_verifier)
|
||||||
l10n_verifier)
|
|
||||||
|
|
||||||
# Open the Page Info window by clicking the More Information button
|
# Open the Page Info window by clicking the More Information button
|
||||||
page_info = self.browser.open_page_info_window(
|
page_info = self.browser.open_page_info_window(
|
||||||
|
@ -101,14 +98,14 @@ class TestEVCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
# Verify the domain listed on the security panel
|
# Verify the domain listed on the security panel
|
||||||
self.assertIn(cert['commonName'],
|
self.assertIn(cert['commonName'],
|
||||||
page_info.deck.security.domain.get_attribute('value'))
|
page_info.deck.security.domain.get_property('value'))
|
||||||
|
|
||||||
# Verify the owner listed on the security panel
|
# Verify the owner listed on the security panel
|
||||||
self.assertEqual(page_info.deck.security.owner.get_attribute('value'),
|
self.assertEqual(page_info.deck.security.owner.get_property('value'),
|
||||||
cert['organization'])
|
cert['organization'])
|
||||||
|
|
||||||
# Verify the verifier listed on the security panel
|
# Verify the verifier listed on the security panel
|
||||||
self.assertEqual(page_info.deck.security.verifier.get_attribute('value'),
|
self.assertEqual(page_info.deck.security.verifier.get_property('value'),
|
||||||
cert['issuerOrganization'])
|
cert['issuerOrganization'])
|
||||||
finally:
|
finally:
|
||||||
page_info.close()
|
page_info.close()
|
||||||
|
|
|
@ -25,7 +25,7 @@ class TestMixedContentPage(PuppeteerMixin, MarionetteTestCase):
|
||||||
with self.marionette.using_context('content'):
|
with self.marionette.using_context('content'):
|
||||||
self.marionette.navigate(self.url)
|
self.marionette.navigate(self.url)
|
||||||
|
|
||||||
self.assertEqual(self.locationbar.identity_box.get_attribute('className'),
|
self.assertEqual(self.locationbar.identity_box.get_property('className'),
|
||||||
'unknownIdentity mixedDisplayContent')
|
'unknownIdentity mixedDisplayContent')
|
||||||
|
|
||||||
# Open the identity popup
|
# Open the identity popup
|
||||||
|
|
|
@ -46,7 +46,7 @@ class TestMixedScriptContentBlocking(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
# First call to Wait() needs a longer timeout due to the reload of the web page.
|
# First call to Wait() needs a longer timeout due to the reload of the web page.
|
||||||
Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
|
Wait(self.marionette, timeout=self.marionette.timeout.page_load).until(
|
||||||
lambda _: self.locationbar.identity_box.get_attribute('className') == identity,
|
lambda _: self.locationbar.identity_box.get_property('className') == identity,
|
||||||
message='Expected identity "{}" not found'.format(identity)
|
message='Expected identity "{}" not found'.format(identity)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -39,7 +39,7 @@ class TestNoCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertFalse(favicon_hidden, 'The identity icon is visible')
|
self.assertFalse(favicon_hidden, 'The identity icon is visible')
|
||||||
|
|
||||||
# Check that the identity box organization label is blank
|
# Check that the identity box organization label is blank
|
||||||
self.assertEqual(self.locationbar.identity_organization_label.get_attribute('value'), '',
|
self.assertEqual(self.locationbar.identity_organization_label.get_property('value'), '',
|
||||||
'The organization has no label')
|
'The organization has no label')
|
||||||
|
|
||||||
# Open the identity popup
|
# Open the identity popup
|
||||||
|
@ -70,12 +70,12 @@ class TestNoCertificate(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
# Check the domain listed on the security panel contains the url's host name
|
# Check the domain listed on the security panel contains the url's host name
|
||||||
self.assertIn(urlparse(self.url).hostname,
|
self.assertIn(urlparse(self.url).hostname,
|
||||||
page_info.deck.security.domain.get_attribute('value'))
|
page_info.deck.security.domain.get_property('value'))
|
||||||
|
|
||||||
# Check the owner label equals localized 'securityNoOwner'
|
# Check the owner label equals localized 'securityNoOwner'
|
||||||
self.assertEqual(page_info.deck.security.owner.get_attribute('value'),
|
self.assertEqual(page_info.deck.security.owner.get_property('value'),
|
||||||
page_info.localize_property('securityNoOwner'))
|
page_info.localize_property('securityNoOwner'))
|
||||||
|
|
||||||
# Check the verifier label equals localized 'notset'
|
# Check the verifier label equals localized 'notset'
|
||||||
self.assertEqual(page_info.deck.security.verifier.get_attribute('value'),
|
self.assertEqual(page_info.deck.security.verifier.get_property('value'),
|
||||||
page_info.localize_property('notset'))
|
page_info.localize_property('notset'))
|
||||||
|
|
|
@ -50,7 +50,7 @@ class TestSecurityNotification(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.marionette.navigate(self.urls[1])
|
self.marionette.navigate(self.urls[1])
|
||||||
|
|
||||||
Wait(self.marionette).until(lambda _: (
|
Wait(self.marionette).until(lambda _: (
|
||||||
self.identity_box.get_attribute('className') == 'verifiedIdentity')
|
self.identity_box.get_property('className') == 'verifiedIdentity')
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_insecure_website(self):
|
def test_insecure_website(self):
|
||||||
|
@ -58,5 +58,5 @@ class TestSecurityNotification(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.marionette.navigate(self.urls[2])
|
self.marionette.navigate(self.urls[2])
|
||||||
|
|
||||||
Wait(self.marionette).until(lambda _: (
|
Wait(self.marionette).until(lambda _: (
|
||||||
self.identity_box.get_attribute('className') == 'unknownIdentity')
|
self.identity_box.get_property('className') == 'unknownIdentity')
|
||||||
)
|
)
|
||||||
|
|
|
@ -76,7 +76,7 @@ class TestSSLStatusAfterRestart(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
self.locationbar.open_identity_popup()
|
self.locationbar.open_identity_popup()
|
||||||
|
|
||||||
# Check the type shown on the idenity popup doorhanger
|
# Check the type shown on the identity popup doorhanger
|
||||||
self.assertEqual(self.identity_popup.element.get_attribute('connection'),
|
self.assertEqual(self.identity_popup.element.get_attribute('connection'),
|
||||||
cert_type)
|
cert_type)
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ class TestSSLStatusAfterRestart(PuppeteerMixin, MarionetteTestCase):
|
||||||
Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
|
Wait(self.marionette).until(lambda _: self.identity_popup.view.security.selected)
|
||||||
|
|
||||||
# Check the identity label
|
# Check the identity label
|
||||||
self.assertEqual(self.locationbar.identity_organization_label.get_attribute('value'),
|
self.assertEqual(self.locationbar.identity_organization_label.get_property('value'),
|
||||||
identity)
|
identity)
|
||||||
|
|
||||||
# Get the information from the certificate
|
# Get the information from the certificate
|
||||||
|
@ -101,10 +101,10 @@ class TestSSLStatusAfterRestart(PuppeteerMixin, MarionetteTestCase):
|
||||||
# If this is a wildcard cert, check only the domain
|
# If this is a wildcard cert, check only the domain
|
||||||
if cert['commonName'].startswith('*'):
|
if cert['commonName'].startswith('*'):
|
||||||
self.assertIn(self.puppeteer.security.get_domain_from_common_name(cert['commonName']),
|
self.assertIn(self.puppeteer.security.get_domain_from_common_name(cert['commonName']),
|
||||||
page_info.deck.security.domain.get_attribute('value'),
|
page_info.deck.security.domain.get_property('value'),
|
||||||
'Expected domain found in certificate for ' + url)
|
'Expected domain found in certificate for ' + url)
|
||||||
else:
|
else:
|
||||||
self.assertEqual(page_info.deck.security.domain.get_attribute('value'),
|
self.assertEqual(page_info.deck.security.domain.get_property('value'),
|
||||||
cert['commonName'],
|
cert['commonName'],
|
||||||
'Domain value matches certificate common name.')
|
'Domain value matches certificate common name.')
|
||||||
|
|
||||||
|
@ -114,11 +114,11 @@ class TestSSLStatusAfterRestart(PuppeteerMixin, MarionetteTestCase):
|
||||||
else:
|
else:
|
||||||
owner = page_info.localize_property('securityNoOwner')
|
owner = page_info.localize_property('securityNoOwner')
|
||||||
|
|
||||||
self.assertEqual(page_info.deck.security.owner.get_attribute('value'), owner,
|
self.assertEqual(page_info.deck.security.owner.get_property('value'), owner,
|
||||||
'Expected owner label found for ' + url)
|
'Expected owner label found for ' + url)
|
||||||
|
|
||||||
# Verify the verifier listed on the security panel
|
# Verify the verifier listed on the security panel
|
||||||
self.assertEqual(page_info.deck.security.verifier.get_attribute('value'),
|
self.assertEqual(page_info.deck.security.verifier.get_property('value'),
|
||||||
cert['issuerOrganization'],
|
cert['issuerOrganization'],
|
||||||
'Verifier matches issuer of certificate for ' + url)
|
'Verifier matches issuer of certificate for ' + url)
|
||||||
page_info.close()
|
page_info.close()
|
||||||
|
|
|
@ -27,31 +27,31 @@ class TestAboutWindow(PuppeteerMixin, MarionetteTestCase):
|
||||||
"""Test correct retrieval of elements."""
|
"""Test correct retrieval of elements."""
|
||||||
self.assertNotEqual(self.about_window.dtds, [])
|
self.assertNotEqual(self.about_window.dtds, [])
|
||||||
|
|
||||||
self.assertEqual(self.deck.element.get_attribute('localName'), 'deck')
|
self.assertEqual(self.deck.element.get_property('localName'), 'deck')
|
||||||
|
|
||||||
# apply panel
|
# apply panel
|
||||||
panel = self.deck.apply
|
panel = self.deck.apply
|
||||||
self.assertEqual(panel.element.get_attribute('localName'), 'hbox')
|
self.assertEqual(panel.element.get_property('localName'), 'hbox')
|
||||||
self.assertEqual(panel.button.get_attribute('localName'), 'button')
|
self.assertEqual(panel.button.get_property('localName'), 'button')
|
||||||
|
|
||||||
# check_for_updates panel
|
# check_for_updates panel
|
||||||
panel = self.deck.check_for_updates
|
panel = self.deck.check_for_updates
|
||||||
self.assertEqual(panel.element.get_attribute('localName'), 'hbox')
|
self.assertEqual(panel.element.get_property('localName'), 'hbox')
|
||||||
self.assertEqual(panel.button.get_attribute('localName'), 'button')
|
self.assertEqual(panel.button.get_property('localName'), 'button')
|
||||||
|
|
||||||
# checking_for_updates panel
|
# checking_for_updates panel
|
||||||
self.assertEqual(self.deck.checking_for_updates.element.get_attribute('localName'), 'hbox')
|
self.assertEqual(self.deck.checking_for_updates.element.get_property('localName'), 'hbox')
|
||||||
|
|
||||||
# download_and_install panel
|
# download_and_install panel
|
||||||
panel = self.deck.download_and_install
|
panel = self.deck.download_and_install
|
||||||
self.assertEqual(panel.element.get_attribute('localName'), 'hbox')
|
self.assertEqual(panel.element.get_property('localName'), 'hbox')
|
||||||
self.assertEqual(panel.button.get_attribute('localName'), 'button')
|
self.assertEqual(panel.button.get_property('localName'), 'button')
|
||||||
|
|
||||||
# download_failed panel
|
# download_failed panel
|
||||||
self.assertEqual(self.deck.download_failed.element.get_attribute('localName'), 'hbox')
|
self.assertEqual(self.deck.download_failed.element.get_property('localName'), 'hbox')
|
||||||
|
|
||||||
# downloading panel
|
# downloading panel
|
||||||
self.assertEqual(self.deck.downloading.element.get_attribute('localName'), 'hbox')
|
self.assertEqual(self.deck.downloading.element.get_property('localName'), 'hbox')
|
||||||
|
|
||||||
def test_open_window(self):
|
def test_open_window(self):
|
||||||
"""Test various opening strategies."""
|
"""Test various opening strategies."""
|
||||||
|
|
|
@ -21,32 +21,32 @@ class TestPageInfoWindow(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertNotEqual(page_info.dtds, [])
|
self.assertNotEqual(page_info.dtds, [])
|
||||||
self.assertNotEqual(page_info.properties, [])
|
self.assertNotEqual(page_info.properties, [])
|
||||||
|
|
||||||
self.assertEqual(page_info.deck.element.get_attribute('localName'), 'deck')
|
self.assertEqual(page_info.deck.element.get_property('localName'), 'deck')
|
||||||
|
|
||||||
# feed panel
|
# feed panel
|
||||||
self.assertEqual(page_info.deck.feed.element.get_attribute('localName'), 'vbox')
|
self.assertEqual(page_info.deck.feed.element.get_property('localName'), 'vbox')
|
||||||
|
|
||||||
# general panel
|
# general panel
|
||||||
self.assertEqual(page_info.deck.general.element.get_attribute('localName'), 'vbox')
|
self.assertEqual(page_info.deck.general.element.get_property('localName'), 'vbox')
|
||||||
|
|
||||||
# media panel
|
# media panel
|
||||||
self.assertEqual(page_info.deck.media.element.get_attribute('localName'), 'vbox')
|
self.assertEqual(page_info.deck.media.element.get_property('localName'), 'vbox')
|
||||||
|
|
||||||
# permissions panel
|
# permissions panel
|
||||||
self.assertEqual(page_info.deck.permissions.element.get_attribute('localName'), 'vbox')
|
self.assertEqual(page_info.deck.permissions.element.get_property('localName'), 'vbox')
|
||||||
|
|
||||||
# security panel
|
# security panel
|
||||||
panel = page_info.deck.select(page_info.deck.security)
|
panel = page_info.deck.select(page_info.deck.security)
|
||||||
|
|
||||||
self.assertEqual(panel.element.get_attribute('localName'), 'vbox')
|
self.assertEqual(panel.element.get_property('localName'), 'vbox')
|
||||||
|
|
||||||
self.assertEqual(panel.domain.get_attribute('localName'), 'textbox')
|
self.assertEqual(panel.domain.get_property('localName'), 'textbox')
|
||||||
self.assertEqual(panel.owner.get_attribute('localName'), 'textbox')
|
self.assertEqual(panel.owner.get_property('localName'), 'textbox')
|
||||||
self.assertEqual(panel.verifier.get_attribute('localName'), 'textbox')
|
self.assertEqual(panel.verifier.get_property('localName'), 'textbox')
|
||||||
|
|
||||||
self.assertEqual(panel.view_certificate.get_attribute('localName'), 'button')
|
self.assertEqual(panel.view_certificate.get_property('localName'), 'button')
|
||||||
self.assertEqual(panel.view_cookies.get_attribute('localName'), 'button')
|
self.assertEqual(panel.view_cookies.get_property('localName'), 'button')
|
||||||
self.assertEqual(panel.view_passwords.get_attribute('localName'), 'button')
|
self.assertEqual(panel.view_passwords.get_property('localName'), 'button')
|
||||||
|
|
||||||
def test_select(self):
|
def test_select(self):
|
||||||
"""Test properties and methods for switching between panels."""
|
"""Test properties and methods for switching between panels."""
|
||||||
|
|
|
@ -23,8 +23,8 @@ class TestTabBar(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.assertEqual(len(tabbar.tabs), 1)
|
self.assertEqual(len(tabbar.tabs), 1)
|
||||||
self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
|
self.assertEqual(tabbar.tabs[0].handle, self.marionette.current_window_handle)
|
||||||
|
|
||||||
self.assertEqual(tabbar.newtab_button.get_attribute('localName'), 'toolbarbutton')
|
self.assertEqual(tabbar.newtab_button.get_property('localName'), 'toolbarbutton')
|
||||||
self.assertEqual(tabbar.toolbar.get_attribute('localName'), 'tabs')
|
self.assertEqual(tabbar.toolbar.get_property('localName'), 'tabs')
|
||||||
|
|
||||||
def test_open_close(self):
|
def test_open_close(self):
|
||||||
tabbar = self.browser.tabbar
|
tabbar = self.browser.tabbar
|
||||||
|
@ -127,8 +127,8 @@ class TestTab(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
self.assertEqual(tab.window, self.browser)
|
self.assertEqual(tab.window, self.browser)
|
||||||
|
|
||||||
self.assertEqual(tab.tab_element.get_attribute('localName'), 'tab')
|
self.assertEqual(tab.tab_element.get_property('localName'), 'tab')
|
||||||
self.assertEqual(tab.close_button.get_attribute('localName'), 'toolbarbutton')
|
self.assertEqual(tab.close_button.get_property('localName'), 'toolbarbutton')
|
||||||
|
|
||||||
def test_certificate(self):
|
def test_certificate(self):
|
||||||
url = self.marionette.absolute_url('layout/mozilla.html')
|
url = self.marionette.absolute_url('layout/mozilla.html')
|
||||||
|
|
|
@ -26,11 +26,11 @@ class TestNavBar(PuppeteerMixin, MarionetteTestCase):
|
||||||
""")
|
""")
|
||||||
|
|
||||||
def test_elements(self):
|
def test_elements(self):
|
||||||
self.assertEqual(self.navbar.back_button.get_attribute('localName'), 'toolbarbutton')
|
self.assertEqual(self.navbar.back_button.get_property('localName'), 'toolbarbutton')
|
||||||
self.assertEqual(self.navbar.forward_button.get_attribute('localName'), 'toolbarbutton')
|
self.assertEqual(self.navbar.forward_button.get_property('localName'), 'toolbarbutton')
|
||||||
self.assertEqual(self.navbar.home_button.get_attribute('localName'), 'toolbarbutton')
|
self.assertEqual(self.navbar.home_button.get_property('localName'), 'toolbarbutton')
|
||||||
self.assertEqual(self.navbar.menu_button.get_attribute('localName'), 'toolbarbutton')
|
self.assertEqual(self.navbar.menu_button.get_property('localName'), 'toolbarbutton')
|
||||||
self.assertEqual(self.navbar.toolbar.get_attribute('localName'), 'toolbar')
|
self.assertEqual(self.navbar.toolbar.get_property('localName'), 'toolbar')
|
||||||
|
|
||||||
def test_buttons(self):
|
def test_buttons(self):
|
||||||
self.marionette.set_context('content')
|
self.marionette.set_context('content')
|
||||||
|
@ -85,24 +85,24 @@ class TestLocationBar(PuppeteerMixin, MarionetteTestCase):
|
||||||
self.locationbar = self.browser.navbar.locationbar
|
self.locationbar = self.browser.navbar.locationbar
|
||||||
|
|
||||||
def test_elements(self):
|
def test_elements(self):
|
||||||
self.assertEqual(self.locationbar.urlbar.get_attribute('localName'), 'textbox')
|
self.assertEqual(self.locationbar.urlbar.get_property('localName'), 'textbox')
|
||||||
self.assertIn('urlbar-input', self.locationbar.urlbar_input.get_attribute('className'))
|
self.assertIn('urlbar-input', self.locationbar.urlbar_input.get_property('className'))
|
||||||
|
|
||||||
self.assertEqual(self.locationbar.connection_icon.get_attribute('localName'), 'image')
|
self.assertEqual(self.locationbar.connection_icon.get_property('localName'), 'image')
|
||||||
self.assertEqual(self.locationbar.identity_box.get_attribute('localName'), 'box')
|
self.assertEqual(self.locationbar.identity_box.get_property('localName'), 'box')
|
||||||
self.assertEqual(self.locationbar.identity_country_label.get_attribute('localName'),
|
self.assertEqual(self.locationbar.identity_country_label.get_property('localName'),
|
||||||
'label')
|
'label')
|
||||||
self.assertEqual(self.locationbar.identity_organization_label.get_attribute('localName'),
|
self.assertEqual(self.locationbar.identity_organization_label.get_property('localName'),
|
||||||
'label')
|
'label')
|
||||||
self.assertEqual(self.locationbar.identity_icon.get_attribute('localName'), 'image')
|
self.assertEqual(self.locationbar.identity_icon.get_property('localName'), 'image')
|
||||||
self.assertEqual(self.locationbar.history_drop_marker.get_attribute('localName'),
|
self.assertEqual(self.locationbar.history_drop_marker.get_property('localName'),
|
||||||
'dropmarker')
|
'dropmarker')
|
||||||
self.assertEqual(self.locationbar.reload_button.get_attribute('localName'),
|
self.assertEqual(self.locationbar.reload_button.get_property('localName'),
|
||||||
'toolbarbutton')
|
'toolbarbutton')
|
||||||
self.assertEqual(self.locationbar.stop_button.get_attribute('localName'),
|
self.assertEqual(self.locationbar.stop_button.get_property('localName'),
|
||||||
'toolbarbutton')
|
'toolbarbutton')
|
||||||
|
|
||||||
self.assertEqual(self.locationbar.contextmenu.get_attribute('localName'), 'menupopup')
|
self.assertEqual(self.locationbar.contextmenu.get_property('localName'), 'menupopup')
|
||||||
self.assertEqual(self.locationbar.get_contextmenu_entry('paste').get_attribute('cmd'),
|
self.assertEqual(self.locationbar.get_contextmenu_entry('paste').get_attribute('cmd'),
|
||||||
'cmd_paste')
|
'cmd_paste')
|
||||||
|
|
||||||
|
@ -162,7 +162,7 @@ class TestAutoCompleteResults(PuppeteerMixin, MarionetteTestCase):
|
||||||
visible_result_count = len(self.autocomplete_results.visible_results)
|
visible_result_count = len(self.autocomplete_results.visible_results)
|
||||||
self.assertTrue(visible_result_count > 0)
|
self.assertTrue(visible_result_count > 0)
|
||||||
self.assertEqual(visible_result_count,
|
self.assertEqual(visible_result_count,
|
||||||
int(results.get_attribute('itemCount')))
|
int(results.get_property('itemCount')))
|
||||||
|
|
||||||
def test_close(self):
|
def test_close(self):
|
||||||
self.browser.navbar.locationbar.urlbar.send_keys('a')
|
self.browser.navbar.locationbar.urlbar.send_keys('a')
|
||||||
|
@ -226,39 +226,39 @@ class TestIdentityPopup(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
# Test main view elements
|
# Test main view elements
|
||||||
main = self.identity_popup.view.main
|
main = self.identity_popup.view.main
|
||||||
self.assertEqual(main.element.get_attribute('localName'), 'panelview')
|
self.assertEqual(main.element.get_property('localName'), 'panelview')
|
||||||
|
|
||||||
self.assertEqual(main.expander.get_attribute('localName'), 'button')
|
self.assertEqual(main.expander.get_property('localName'), 'button')
|
||||||
self.assertEqual(main.host.get_attribute('localName'), 'label')
|
self.assertEqual(main.host.get_property('localName'), 'label')
|
||||||
self.assertEqual(main.insecure_connection_label.get_attribute('localName'),
|
self.assertEqual(main.insecure_connection_label.get_property('localName'),
|
||||||
'description')
|
'description')
|
||||||
self.assertEqual(main.internal_connection_label.get_attribute('localName'),
|
self.assertEqual(main.internal_connection_label.get_property('localName'),
|
||||||
'description')
|
'description')
|
||||||
self.assertEqual(main.secure_connection_label.get_attribute('localName'),
|
self.assertEqual(main.secure_connection_label.get_property('localName'),
|
||||||
'description')
|
'description')
|
||||||
|
|
||||||
self.assertEqual(main.permissions.get_attribute('localName'), 'vbox')
|
self.assertEqual(main.permissions.get_property('localName'), 'vbox')
|
||||||
|
|
||||||
# Test security view elements
|
# Test security view elements
|
||||||
security = self.identity_popup.view.security
|
security = self.identity_popup.view.security
|
||||||
self.assertEqual(security.element.get_attribute('localName'), 'panelview')
|
self.assertEqual(security.element.get_property('localName'), 'panelview')
|
||||||
|
|
||||||
self.assertEqual(security.host.get_attribute('localName'), 'label')
|
self.assertEqual(security.host.get_property('localName'), 'label')
|
||||||
self.assertEqual(security.insecure_connection_label.get_attribute('localName'),
|
self.assertEqual(security.insecure_connection_label.get_property('localName'),
|
||||||
'description')
|
'description')
|
||||||
self.assertEqual(security.secure_connection_label.get_attribute('localName'),
|
self.assertEqual(security.secure_connection_label.get_property('localName'),
|
||||||
'description')
|
'description')
|
||||||
|
|
||||||
self.assertEqual(security.owner.get_attribute('localName'), 'description')
|
self.assertEqual(security.owner.get_property('localName'), 'description')
|
||||||
self.assertEqual(security.owner_location.get_attribute('localName'), 'description')
|
self.assertEqual(security.owner_location.get_property('localName'), 'description')
|
||||||
self.assertEqual(security.verifier.get_attribute('localName'), 'description')
|
self.assertEqual(security.verifier.get_property('localName'), 'description')
|
||||||
|
|
||||||
self.assertEqual(security.disable_mixed_content_blocking_button.get_attribute('localName'),
|
self.assertEqual(security.disable_mixed_content_blocking_button.get_property('localName'),
|
||||||
'button')
|
'button')
|
||||||
self.assertEqual(security.enable_mixed_content_blocking_button.get_attribute('localName'),
|
self.assertEqual(security.enable_mixed_content_blocking_button.get_property('localName'),
|
||||||
'button')
|
'button')
|
||||||
|
|
||||||
self.assertEqual(security.more_info_button.get_attribute('localName'), 'button')
|
self.assertEqual(security.more_info_button.get_property('localName'), 'button')
|
||||||
|
|
||||||
def test_open_close(self):
|
def test_open_close(self):
|
||||||
with self.marionette.using_context('content'):
|
with self.marionette.using_context('content'):
|
||||||
|
|
|
@ -36,13 +36,13 @@ class TestUpdateWizard(PuppeteerMixin, MarionetteTestCase):
|
||||||
|
|
||||||
def test_elements(self):
|
def test_elements(self):
|
||||||
"""Test correct retrieval of elements."""
|
"""Test correct retrieval of elements."""
|
||||||
self.assertEqual(self.wizard.element.get_attribute('localName'), 'wizard')
|
self.assertEqual(self.wizard.element.get_property('localName'), 'wizard')
|
||||||
|
|
||||||
buttons = ('cancel_button', 'extra1_button', 'extra2_button',
|
buttons = ('cancel_button', 'extra1_button', 'extra2_button',
|
||||||
'finish_button', 'next_button', 'previous_button',
|
'finish_button', 'next_button', 'previous_button',
|
||||||
)
|
)
|
||||||
for button in buttons:
|
for button in buttons:
|
||||||
self.assertEqual(getattr(self.wizard, button).get_attribute('localName'),
|
self.assertEqual(getattr(self.wizard, button).get_property('localName'),
|
||||||
'button')
|
'button')
|
||||||
|
|
||||||
panels = ('checking', 'downloading', 'dummy', 'error_patching', 'error',
|
panels = ('checking', 'downloading', 'dummy', 'error_patching', 'error',
|
||||||
|
@ -50,13 +50,13 @@ class TestUpdateWizard(PuppeteerMixin, MarionetteTestCase):
|
||||||
'manual_update', 'no_updates_found', 'updates_found_basic',
|
'manual_update', 'no_updates_found', 'updates_found_basic',
|
||||||
)
|
)
|
||||||
for panel in panels:
|
for panel in panels:
|
||||||
self.assertEqual(getattr(self.wizard, panel).element.get_attribute('localName'),
|
self.assertEqual(getattr(self.wizard, panel).element.get_property('localName'),
|
||||||
'wizardpage')
|
'wizardpage')
|
||||||
|
|
||||||
# elements of the checking panel
|
# elements of the checking panel
|
||||||
self.assertEqual(self.wizard.checking.progress.get_attribute('localName'),
|
self.assertEqual(self.wizard.checking.progress.get_property('localName'),
|
||||||
'progressmeter')
|
'progressmeter')
|
||||||
|
|
||||||
# elements of the downloading panel
|
# elements of the downloading panel
|
||||||
self.assertEqual(self.wizard.downloading.progress.get_attribute('localName'),
|
self.assertEqual(self.wizard.downloading.progress.get_property('localName'),
|
||||||
'progressmeter')
|
'progressmeter')
|
||||||
|
|
|
@ -30,12 +30,11 @@ this.capture = {};
|
||||||
* The canvas element where the element has been painted on.
|
* The canvas element where the element has been painted on.
|
||||||
*/
|
*/
|
||||||
capture.element = function (node, highlights=[]) {
|
capture.element = function (node, highlights=[]) {
|
||||||
let doc = node.ownerDocument;
|
let win = node.ownerDocument.defaultView;
|
||||||
let win = doc.defaultView;
|
|
||||||
let rect = node.getBoundingClientRect();
|
let rect = node.getBoundingClientRect();
|
||||||
|
|
||||||
return capture.canvas(
|
return capture.canvas(
|
||||||
doc,
|
win,
|
||||||
rect.left,
|
rect.left,
|
||||||
rect.top,
|
rect.top,
|
||||||
rect.width,
|
rect.width,
|
||||||
|
@ -44,12 +43,12 @@ capture.element = function (node, highlights=[]) {
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Take a screenshot of the document's viewport, taking into account
|
* Take a screenshot of the window's viewport by taking into account
|
||||||
* the current window's offset.
|
* the current offsets.
|
||||||
*
|
*
|
||||||
* @param {Document} document
|
* @param {DOMWindow} win
|
||||||
* The DOM document providing the document element to capture,
|
* The DOM window providing the document element to capture,
|
||||||
* and a window for determining the offset of the viewport.
|
* and the offsets for the viewport.
|
||||||
* @param {Array.<Node>=} highlights
|
* @param {Array.<Node>=} highlights
|
||||||
* Optional array of nodes, around which a border will be marked to
|
* Optional array of nodes, around which a border will be marked to
|
||||||
* highlight them in the screenshot.
|
* highlight them in the screenshot.
|
||||||
|
@ -57,25 +56,24 @@ capture.element = function (node, highlights=[]) {
|
||||||
* @return {HTMLCanvasElement}
|
* @return {HTMLCanvasElement}
|
||||||
* The canvas element where the viewport has been painted on.
|
* The canvas element where the viewport has been painted on.
|
||||||
*/
|
*/
|
||||||
capture.viewport = function (document, highlights=[]) {
|
capture.viewport = function (win, highlights=[]) {
|
||||||
let win = document.defaultView;
|
let rootNode = win.document.documentElement;
|
||||||
let docEl = document.documentElement;
|
|
||||||
|
|
||||||
return capture.canvas(
|
return capture.canvas(
|
||||||
document,
|
win,
|
||||||
win.pageXOffset,
|
win.pageXOffset,
|
||||||
win.pageYOffset,
|
win.pageYOffset,
|
||||||
docEl.clientWidth,
|
rootNode.clientWidth,
|
||||||
docEl.clientHeight,
|
rootNode.clientHeight,
|
||||||
highlights);
|
highlights);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Low-level interface to draw a rectangle off the framebuffer.
|
* Low-level interface to draw a rectangle off the framebuffer.
|
||||||
*
|
*
|
||||||
* @param {Document} document
|
* @param {DOMWindow} win
|
||||||
* A DOM document providing the window used to the framebuffer,
|
* The DOM window used for the framebuffer, and providing the interfaces
|
||||||
* and interfaces for creating an HTMLCanvasElement.
|
* for creating an HTMLCanvasElement.
|
||||||
* @param {number} left
|
* @param {number} left
|
||||||
* The left, X axis offset of the rectangle.
|
* The left, X axis offset of the rectangle.
|
||||||
* @param {number} top
|
* @param {number} top
|
||||||
|
@ -92,15 +90,23 @@ capture.viewport = function (document, highlights=[]) {
|
||||||
* The canvas on which the selection from the window's framebuffer
|
* The canvas on which the selection from the window's framebuffer
|
||||||
* has been painted on.
|
* has been painted on.
|
||||||
*/
|
*/
|
||||||
capture.canvas = function (document, left, top, width, height, highlights=[]) {
|
capture.canvas = function (win, left, top, width, height, highlights=[]) {
|
||||||
let win = document.defaultView;
|
let scale = win.devicePixelRatio;
|
||||||
|
|
||||||
let canvas = document.createElementNS(XHTML_NS, "canvas");
|
let canvas = win.document.createElementNS(XHTML_NS, "canvas");
|
||||||
canvas.width = width;
|
canvas.width = width * scale;
|
||||||
canvas.height = height;
|
canvas.height = height * scale;
|
||||||
|
|
||||||
let ctx = canvas.getContext(CONTEXT_2D);
|
let ctx = canvas.getContext(CONTEXT_2D);
|
||||||
ctx.drawWindow(win, left, top, width, height, BG_COLOUR);
|
let flags = ctx.DRAWWINDOW_DRAW_CARET;
|
||||||
|
// Disabled in bug 1243415 for webplatform-test failures due to out of view elements.
|
||||||
|
// Needs https://github.com/w3c/web-platform-tests/issues/4383 fixed.
|
||||||
|
// ctx.DRAWWINDOW_DRAW_VIEW;
|
||||||
|
// Bug 1009762 - Crash in [@ mozilla::gl::ReadPixelsIntoDataSurface]
|
||||||
|
// ctx.DRAWWINDOW_USE_WIDGET_LAYERS;
|
||||||
|
|
||||||
|
ctx.scale(scale, scale);
|
||||||
|
ctx.drawWindow(win, left, top, width, height, BG_COLOUR, flags);
|
||||||
ctx = capture.highlight_(ctx, highlights, top, left);
|
ctx = capture.highlight_(ctx, highlights, top, left);
|
||||||
|
|
||||||
return canvas;
|
return canvas;
|
||||||
|
|
|
@ -1,19 +1,31 @@
|
||||||
<?xml version="1.0"?>
|
<?xml version="1.0"?>
|
||||||
|
|
||||||
<!-- This Source Code Form is subject to the terms of the Mozilla Public
|
<!-- 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
|
- 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/. -->
|
- file, You can obtain one at http://mozilla.org/MPL/2.0/. -->
|
||||||
|
|
||||||
<!DOCTYPE dialog [
|
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
|
||||||
]>
|
|
||||||
|
|
||||||
<dialog id="dialogTest"
|
|
||||||
buttons="accept, cancel"
|
|
||||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
|
||||||
|
|
||||||
|
|
||||||
<vbox id="things">
|
<dialog id="testDialog"
|
||||||
<checkbox id="testBox" label="box" />
|
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||||
|
title="Test Dialog"
|
||||||
|
buttons="accept,cancel">
|
||||||
|
|
||||||
|
<vbox flex="1" style="min-width: 300px; min-height: 500px;">
|
||||||
|
<label>Settings</label>
|
||||||
|
<separator class="thin"/>
|
||||||
|
<richlistbox id="test-list" flex="1">
|
||||||
|
<richlistitem id="item-choose" orient="horizontal" selected="true">
|
||||||
|
<label id="choose-label" value="First Entry" flex="1"/>
|
||||||
|
<button id="choose-button" oncommand="" label="Choose..."/>
|
||||||
|
</richlistitem>
|
||||||
|
</richlistbox>
|
||||||
|
<separator class="thin"/>
|
||||||
|
<checkbox id="check-box" label="Test Mode 2" />
|
||||||
|
<hbox align="center">
|
||||||
|
<label id="text-box-label" control="text-box">Name:</label>
|
||||||
|
<textbox id="text-box" flex="1" />
|
||||||
|
</hbox>
|
||||||
</vbox>
|
</vbox>
|
||||||
|
|
||||||
</dialog>
|
</dialog>
|
||||||
|
|
|
@ -69,8 +69,14 @@ class HTMLElement(object):
|
||||||
"""Returns the requested property, or None if the property is
|
"""Returns the requested property, or None if the property is
|
||||||
not set.
|
not set.
|
||||||
"""
|
"""
|
||||||
body = {"id": self.id, "name": name}
|
try:
|
||||||
return self.marionette._send_message("getElementProperty", body, key="value")
|
body = {"id": self.id, "name": name}
|
||||||
|
return self.marionette._send_message("getElementProperty", body, key="value")
|
||||||
|
except errors.UnknownCommandException:
|
||||||
|
# Keep backward compatibility for code which uses get_attribute() to
|
||||||
|
# also retrieve element properties.
|
||||||
|
# Remove when Firefox 55 is stable.
|
||||||
|
return self.get_attribute(name)
|
||||||
|
|
||||||
def click(self):
|
def click(self):
|
||||||
self.marionette._send_message("clickElement", {"id": self.id})
|
self.marionette._send_message("clickElement", {"id": self.id})
|
||||||
|
|
|
@ -22,6 +22,7 @@ Cu.import("chrome://marionette/content/addon.js");
|
||||||
Cu.import("chrome://marionette/content/assert.js");
|
Cu.import("chrome://marionette/content/assert.js");
|
||||||
Cu.import("chrome://marionette/content/atom.js");
|
Cu.import("chrome://marionette/content/atom.js");
|
||||||
Cu.import("chrome://marionette/content/browser.js");
|
Cu.import("chrome://marionette/content/browser.js");
|
||||||
|
Cu.import("chrome://marionette/content/capture.js");
|
||||||
Cu.import("chrome://marionette/content/cert.js");
|
Cu.import("chrome://marionette/content/cert.js");
|
||||||
Cu.import("chrome://marionette/content/element.js");
|
Cu.import("chrome://marionette/content/element.js");
|
||||||
Cu.import("chrome://marionette/content/error.js");
|
Cu.import("chrome://marionette/content/error.js");
|
||||||
|
@ -1842,7 +1843,8 @@ GeckoDriver.prototype.getElementAttribute = function*(cmd, resp) {
|
||||||
case Context.CHROME:
|
case Context.CHROME:
|
||||||
let win = this.getCurrentWindow();
|
let win = this.getCurrentWindow();
|
||||||
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
let el = this.curBrowser.seenEls.get(id, {frame: win});
|
||||||
resp.body.value = atom.getElementAttribute(el, name, this.getCurrentWindow());
|
|
||||||
|
resp.body.value = el.getAttribute(name);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Context.CONTENT:
|
case Context.CONTENT:
|
||||||
|
@ -2393,6 +2395,9 @@ GeckoDriver.prototype.clearImportedScripts = function*(cmd, resp) {
|
||||||
* Reference to a web element.
|
* Reference to a web element.
|
||||||
* @param {string} highlights
|
* @param {string} highlights
|
||||||
* List of web elements to highlight.
|
* List of web elements to highlight.
|
||||||
|
* @param {boolean} full
|
||||||
|
* True to take a screenshot of the entire document element. Is not
|
||||||
|
* considered if {@code id} is not defined. Defaults to true.
|
||||||
* @param {boolean} hash
|
* @param {boolean} hash
|
||||||
* True if the user requests a hash of the image data.
|
* True if the user requests a hash of the image data.
|
||||||
*
|
*
|
||||||
|
@ -2407,44 +2412,41 @@ GeckoDriver.prototype.takeScreenshot = function (cmd, resp) {
|
||||||
|
|
||||||
switch (this.context) {
|
switch (this.context) {
|
||||||
case Context.CHROME:
|
case Context.CHROME:
|
||||||
let win = this.getCurrentWindow();
|
let canvas;
|
||||||
let canvas = win.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
|
let highlightEls = [];
|
||||||
let doc;
|
|
||||||
if (this.appName == "B2G") {
|
|
||||||
doc = win.document.body;
|
|
||||||
} else {
|
|
||||||
doc = win.document.documentElement;
|
|
||||||
}
|
|
||||||
let docRect = doc.getBoundingClientRect();
|
|
||||||
let width = docRect.width;
|
|
||||||
let height = docRect.height;
|
|
||||||
|
|
||||||
// Convert width and height from CSS pixels (potentially fractional)
|
let container = {frame: this.getCurrentWindow().document.defaultView};
|
||||||
// to device pixels (integer).
|
|
||||||
let scale = win.devicePixelRatio;
|
|
||||||
canvas.setAttribute("width", Math.round(width * scale));
|
|
||||||
canvas.setAttribute("height", Math.round(height * scale));
|
|
||||||
|
|
||||||
let context = canvas.getContext("2d");
|
if (!container.frame) {
|
||||||
let flags;
|
throw new NoSuchWindowError('Unable to locate window');
|
||||||
if (this.appName == "B2G") {
|
}
|
||||||
flags =
|
|
||||||
context.DRAWWINDOW_DRAW_CARET |
|
for (let h of highlights) {
|
||||||
context.DRAWWINDOW_DRAW_VIEW |
|
let el = this.curBrowser.seenEls.get(h, container);
|
||||||
context.DRAWWINDOW_USE_WIDGET_LAYERS;
|
highlightEls.push(el);
|
||||||
} else {
|
}
|
||||||
// Bug 1075168: CanvasRenderingContext2D image is distorted
|
|
||||||
// when using certain flags in chrome context.
|
// viewport
|
||||||
flags =
|
if (!id && !full) {
|
||||||
context.DRAWWINDOW_DRAW_VIEW |
|
canvas = capture.viewport(container.frame, highlightEls);
|
||||||
context.DRAWWINDOW_USE_WIDGET_LAYERS;
|
|
||||||
|
// element or full document element
|
||||||
|
} else {
|
||||||
|
let node;
|
||||||
|
if (id) {
|
||||||
|
node = this.curBrowser.seenEls.get(id, container);
|
||||||
|
} else {
|
||||||
|
node = container.frame.document.documentElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas = capture.element(node, highlightEls);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hash) {
|
||||||
|
return capture.toHash(canvas);
|
||||||
|
} else {
|
||||||
|
return capture.toBase64(canvas);
|
||||||
}
|
}
|
||||||
context.scale(scale, scale);
|
|
||||||
context.drawWindow(win, 0, 0, width, height, "rgb(255,255,255)", flags);
|
|
||||||
let dataUrl = canvas.toDataURL("image/png", "");
|
|
||||||
let data = dataUrl.substring(dataUrl.indexOf(",") + 1);
|
|
||||||
resp.body.value = data;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case Context.CONTENT:
|
case Context.CONTENT:
|
||||||
if (hash) {
|
if (hash) {
|
||||||
|
|
|
@ -51,7 +51,7 @@ class TestMouseAction(MarionetteTestCase):
|
||||||
def context_menu_state():
|
def context_menu_state():
|
||||||
with self.marionette.using_context("chrome"):
|
with self.marionette.using_context("chrome"):
|
||||||
cm_el = self.marionette.find_element(By.ID, "contentAreaContextMenu")
|
cm_el = self.marionette.find_element(By.ID, "contentAreaContextMenu")
|
||||||
return cm_el.get_attribute("state")
|
return cm_el.get_property("state")
|
||||||
|
|
||||||
self.assertEqual("closed", context_menu_state())
|
self.assertEqual("closed", context_menu_state())
|
||||||
self.action.context_click(click_el).perform()
|
self.action.context_click(click_el).perform()
|
||||||
|
@ -88,20 +88,20 @@ class TestMouseAction(MarionetteTestCase):
|
||||||
|
|
||||||
with self.marionette.using_context("chrome"):
|
with self.marionette.using_context("chrome"):
|
||||||
urlbar = self.marionette.find_element(By.ID, "urlbar")
|
urlbar = self.marionette.find_element(By.ID, "urlbar")
|
||||||
self.assertEqual("", urlbar.get_attribute("value"))
|
self.assertEqual("", urlbar.get_property("value"))
|
||||||
|
|
||||||
urlbar.send_keys(test_word)
|
urlbar.send_keys(test_word)
|
||||||
self.assertEqual(urlbar.get_attribute("value"), test_word)
|
self.assertEqual(urlbar.get_property("value"), test_word)
|
||||||
(self.action.double_click(urlbar).perform()
|
(self.action.double_click(urlbar).perform()
|
||||||
.key_down(self.mod_key)
|
.key_down(self.mod_key)
|
||||||
.key_down("x").perform())
|
.key_down("x").perform())
|
||||||
self.assertEqual(urlbar.get_attribute("value"), "")
|
self.assertEqual(urlbar.get_property("value"), "")
|
||||||
|
|
||||||
def test_chrome_context_click_action(self):
|
def test_chrome_context_click_action(self):
|
||||||
self.marionette.set_context("chrome")
|
self.marionette.set_context("chrome")
|
||||||
def context_menu_state():
|
def context_menu_state():
|
||||||
cm_el = self.marionette.find_element(By.ID, "tabContextMenu")
|
cm_el = self.marionette.find_element(By.ID, "tabContextMenu")
|
||||||
return cm_el.get_attribute("state")
|
return cm_el.get_property("state")
|
||||||
|
|
||||||
currtab = self.marionette.execute_script("return gBrowser.selectedTab")
|
currtab = self.marionette.execute_script("return gBrowser.selectedTab")
|
||||||
self.assertEqual("closed", context_menu_state())
|
self.assertEqual("closed", context_menu_state())
|
||||||
|
|
|
@ -10,54 +10,104 @@ import urllib
|
||||||
|
|
||||||
from unittest import skip
|
from unittest import skip
|
||||||
|
|
||||||
from marionette_driver.by import By
|
from marionette_driver import By
|
||||||
|
from marionette_driver.errors import JavascriptException, NoSuchWindowException
|
||||||
from marionette_harness import MarionetteTestCase, WindowManagerMixin
|
from marionette_harness import MarionetteTestCase, skip_if_mobile, WindowManagerMixin
|
||||||
|
|
||||||
|
|
||||||
def inline(doc, mime="text/html;charset=utf-8"):
|
def inline(doc, mime="text/html;charset=utf-8"):
|
||||||
return "data:{0},{1}".format(mime, urllib.quote(doc))
|
return "data:{0},{1}".format(mime, urllib.quote(doc))
|
||||||
|
|
||||||
|
|
||||||
ELEMENT = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVklEQVRoge3PMQ0AMAzAsPJHVWYbjEWTj/zx7O75oXk9AAISD6QWSC2QWiC1QGqB1AKpBVILpBZILZBaILVAaoHUAqkFUgukFkgtkFogtUBqgdT6BnIBMKa1DtYxhPkAAAAASUVORK5CYII="
|
box = inline("<body><div id='box'><p id='green' style='width: 50px; height: 50px; "
|
||||||
HIGHLIGHTED_ELEMENT = "iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAYAAAAeP4ixAAAAVklEQVRoge3PQRHAQAgAMfyrwhm1sb3JIwIyN3MvmJu53f01kRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRGpEakRqRmvciL/gAQgW/OxTpMPwAAAAASUVORK5CYII="
|
"background: silver;'></p></div></body>")
|
||||||
|
input = inline("<body><input id='text-input'></input></body>")
|
||||||
|
long = inline("<body style='height: 300vh'><p style='margin-top: 100vh'>foo</p></body>")
|
||||||
box = inline(
|
short = inline("<body style='height: 10vh'></body>")
|
||||||
"<div id=green style='width: 50px; height: 50px; background: silver;'></div>")
|
svg = inline("""
|
||||||
long = inline("<body style='height: 300vh'><p style='margin-top: 100vh'>foo")
|
<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20">
|
||||||
short = inline("<body style='height: 10vh'>")
|
<rect height="20" width="20"/>
|
||||||
svg = inline("""<svg xmlns="http://www.w3.org/2000/svg" height="20" width="20">
|
</svg>""", mime="image/svg+xml")
|
||||||
<rect height="20" width="20"/>
|
|
||||||
</svg>""", mime="image/svg+xml")
|
|
||||||
|
|
||||||
|
|
||||||
class ScreenCaptureTestCase(MarionetteTestCase):
|
class ScreenCaptureTestCase(MarionetteTestCase):
|
||||||
def assert_png(self, string):
|
|
||||||
"""Test that string is a Base64 encoded PNG file."""
|
def setUp(self):
|
||||||
image = base64.decodestring(string)
|
super(ScreenCaptureTestCase, self).setUp()
|
||||||
|
|
||||||
|
self._device_pixel_ratio = None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def device_pixel_ratio(self):
|
||||||
|
if self._device_pixel_ratio is None:
|
||||||
|
self._device_pixel_ratio = self.marionette.execute_script("""
|
||||||
|
return window.devicePixelRatio
|
||||||
|
""")
|
||||||
|
return self._device_pixel_ratio
|
||||||
|
|
||||||
|
@property
|
||||||
|
def document_element(self):
|
||||||
|
return self.marionette.find_element(By.CSS_SELECTOR, ":root")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def page_y_offset(self):
|
||||||
|
return self.marionette.execute_script("return window.pageYOffset")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def viewport_dimensions(self):
|
||||||
|
return self.marionette.execute_script("""
|
||||||
|
return [arguments[0].clientWidth,
|
||||||
|
arguments[0].clientHeight];
|
||||||
|
""", script_args=[self.document_element])
|
||||||
|
|
||||||
|
def assert_png(self, screenshot):
|
||||||
|
"""Test that screenshot is a Base64 encoded PNG file."""
|
||||||
|
image = base64.decodestring(screenshot)
|
||||||
self.assertEqual(imghdr.what("", image), "png")
|
self.assertEqual(imghdr.what("", image), "png")
|
||||||
|
|
||||||
def get_image_dimensions(self, string):
|
def assert_formats(self, element=None):
|
||||||
self.assert_png(string)
|
if element is None:
|
||||||
image = base64.decodestring(string)
|
element = self.document_element
|
||||||
|
|
||||||
|
screenshot_default = self.marionette.screenshot(element=element)
|
||||||
|
screenshot_image = self.marionette.screenshot(element=element, format="base64")
|
||||||
|
binary1 = self.marionette.screenshot(element=element, format="binary")
|
||||||
|
binary2 = self.marionette.screenshot(element=element, format="binary")
|
||||||
|
hash1 = self.marionette.screenshot(element=element, format="hash")
|
||||||
|
hash2 = self.marionette.screenshot(element=element, format="hash")
|
||||||
|
|
||||||
|
# Valid data should have been returned
|
||||||
|
self.assert_png(screenshot_image)
|
||||||
|
self.assertEqual(imghdr.what("", binary1), "png")
|
||||||
|
self.assertEqual(screenshot_image, base64.b64encode(binary1))
|
||||||
|
self.assertEqual(hash1, hashlib.sha256(screenshot_image).hexdigest())
|
||||||
|
|
||||||
|
# Different formats produce different data
|
||||||
|
self.assertNotEqual(screenshot_image, binary1)
|
||||||
|
self.assertNotEqual(screenshot_image, hash1)
|
||||||
|
self.assertNotEqual(binary1, hash1)
|
||||||
|
|
||||||
|
# A second capture should be identical
|
||||||
|
self.assertEqual(screenshot_image, screenshot_default)
|
||||||
|
self.assertEqual(binary1, binary2)
|
||||||
|
self.assertEqual(hash1, hash2)
|
||||||
|
|
||||||
|
def get_element_dimensions(self, element):
|
||||||
|
rect = element.rect
|
||||||
|
return rect["width"], rect["height"]
|
||||||
|
|
||||||
|
def get_image_dimensions(self, screenshot):
|
||||||
|
self.assert_png(screenshot)
|
||||||
|
image = base64.decodestring(screenshot)
|
||||||
width, height = struct.unpack(">LL", image[16:24])
|
width, height = struct.unpack(">LL", image[16:24])
|
||||||
return int(width), int(height)
|
return int(width), int(height)
|
||||||
|
|
||||||
|
def scale(self, rect):
|
||||||
|
return (int(rect[0] * self.device_pixel_ratio),
|
||||||
|
int(rect[1] * self.device_pixel_ratio))
|
||||||
|
|
||||||
|
|
||||||
class TestScreenCaptureChrome(WindowManagerMixin, ScreenCaptureTestCase):
|
class TestScreenCaptureChrome(WindowManagerMixin, ScreenCaptureTestCase):
|
||||||
@property
|
|
||||||
def primary_window_dimensions(self):
|
|
||||||
current_window = self.marionette.current_chrome_window_handle
|
|
||||||
self.marionette.switch_to_window(self.start_window)
|
|
||||||
with self.marionette.using_context("chrome"):
|
|
||||||
rv = tuple(self.marionette.execute_script("""
|
|
||||||
let el = document.documentElement;
|
|
||||||
let rect = el.getBoundingClientRect();
|
|
||||||
return [rect.width, rect.height];
|
|
||||||
"""))
|
|
||||||
self.marionette.switch_to_window(current_window)
|
|
||||||
return rv
|
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
super(TestScreenCaptureChrome, self).setUp()
|
super(TestScreenCaptureChrome, self).setUp()
|
||||||
|
@ -67,90 +117,245 @@ class TestScreenCaptureChrome(WindowManagerMixin, ScreenCaptureTestCase):
|
||||||
self.close_all_windows()
|
self.close_all_windows()
|
||||||
super(TestScreenCaptureChrome, self).tearDown()
|
super(TestScreenCaptureChrome, self).tearDown()
|
||||||
|
|
||||||
# A full chrome window screenshot is not the outer dimensions of
|
@property
|
||||||
# the window, but instead the bounding box of the <window> inside
|
def window_dimensions(self):
|
||||||
# <browser>.
|
return tuple(self.marionette.execute_script("""
|
||||||
def test_window(self):
|
let el = document.documentElement;
|
||||||
ss = self.marionette.screenshot()
|
let rect = el.getBoundingClientRect();
|
||||||
self.assert_png(ss)
|
return [rect.width, rect.height];
|
||||||
self.assertEqual(self.primary_window_dimensions,
|
"""))
|
||||||
self.get_image_dimensions(ss))
|
|
||||||
|
|
||||||
def test_chrome_delegation(self):
|
def open_dialog(self, url=None, width=None, height=None):
|
||||||
with self.marionette.using_context("content"):
|
if url is None:
|
||||||
content = self.marionette.screenshot()
|
url = "chrome://marionette/content/test_dialog.xul"
|
||||||
chrome = self.marionette.screenshot()
|
|
||||||
self.assertNotEqual(content, chrome)
|
def opener():
|
||||||
|
features = "chrome"
|
||||||
|
if height is not None:
|
||||||
|
features += ",height={}".format(height)
|
||||||
|
if width is not None:
|
||||||
|
features += ",width={}".format(width)
|
||||||
|
|
||||||
# This tests that GeckoDriver#takeScreenshot uses
|
|
||||||
# currentContext.document.documentElement instead of looking for a
|
|
||||||
# <window> element, which does not exist for all windows.
|
|
||||||
def test_secondary_windows(self):
|
|
||||||
def open_window_with_js():
|
|
||||||
self.marionette.execute_script("""
|
self.marionette.execute_script("""
|
||||||
window.open('chrome://marionette/content/test_dialog.xul', 'foo',
|
window.open(arguments[0], "", arguments[1]);
|
||||||
'dialog,height=200,width=300');
|
""", script_args=[url, features])
|
||||||
""")
|
|
||||||
|
|
||||||
new_window = self.open_window(open_window_with_js)
|
return self.open_window(opener)
|
||||||
self.marionette.switch_to_window(new_window)
|
|
||||||
|
|
||||||
ss = self.marionette.screenshot()
|
def test_capture_different_context(self):
|
||||||
size = self.get_image_dimensions(ss)
|
"""Check that screenshots in content and chrome are different."""
|
||||||
self.assert_png(ss)
|
with self.marionette.using_context("content"):
|
||||||
self.assertNotEqual(self.primary_window_dimensions, size)
|
screenshot_content = self.marionette.screenshot()
|
||||||
|
screenshot_chrome = self.marionette.screenshot()
|
||||||
|
self.assertNotEqual(screenshot_content, screenshot_chrome)
|
||||||
|
|
||||||
|
@skip_if_mobile
|
||||||
|
def test_capture_element(self):
|
||||||
|
dialog = self.open_dialog()
|
||||||
|
self.marionette.switch_to_window(dialog)
|
||||||
|
|
||||||
|
# Ensure we only capture the element
|
||||||
|
el = self.marionette.find_element(By.ID, "test-list")
|
||||||
|
screenshot_element = self.marionette.screenshot(element=el)
|
||||||
|
self.assertEqual(self.scale(self.get_element_dimensions(el)),
|
||||||
|
self.get_image_dimensions(screenshot_element))
|
||||||
|
|
||||||
|
# Ensure we do not capture the full window
|
||||||
|
screenshot_dialog = self.marionette.screenshot()
|
||||||
|
self.assertNotEqual(screenshot_dialog, screenshot_element)
|
||||||
|
|
||||||
self.marionette.close_chrome_window()
|
self.marionette.close_chrome_window()
|
||||||
self.marionette.switch_to_window(self.start_window)
|
self.marionette.switch_to_window(self.start_window)
|
||||||
|
|
||||||
|
def test_capture_flags(self):
|
||||||
|
dialog = self.open_dialog()
|
||||||
|
self.marionette.switch_to_window(dialog)
|
||||||
|
|
||||||
class Content(ScreenCaptureTestCase):
|
textbox = self.marionette.find_element(By.ID, "text-box")
|
||||||
@property
|
textbox.send_keys("")
|
||||||
def body_scroll_dimensions(self):
|
screenshot_focus = self.marionette.screenshot()
|
||||||
return tuple(self.marionette.execute_script(
|
|
||||||
"return [document.body.scrollWidth, document.body.scrollHeight]"))
|
|
||||||
|
|
||||||
@property
|
self.marionette.execute_script("arguments[0].blur();", script_args=[textbox])
|
||||||
def viewport_dimensions(self):
|
screenshot_no_focus = self.marionette.screenshot()
|
||||||
return tuple(self.marionette.execute_script("""
|
|
||||||
let docEl = document.documentElement;
|
|
||||||
return [docEl.clientWidth, docEl.clientHeight];"""))
|
|
||||||
|
|
||||||
@property
|
self.marionette.close_chrome_window()
|
||||||
def document_element(self):
|
self.marionette.switch_to_window(self.start_window)
|
||||||
return self.marionette.execute_script("return document.documentElement")
|
|
||||||
|
|
||||||
@property
|
self.assertNotEqual(screenshot_focus, screenshot_no_focus)
|
||||||
def page_y_offset(self):
|
|
||||||
return self.marionette.execute_script("return window.pageYOffset")
|
def test_capture_full_area(self):
|
||||||
|
# A full capture is not the outer dimensions of the window,
|
||||||
|
# but instead the bounding box of the window's root node (documentElement).
|
||||||
|
screenshot_full = self.marionette.screenshot()
|
||||||
|
screenshot_root = self.marionette.screenshot(element=self.document_element)
|
||||||
|
|
||||||
|
self.assert_png(screenshot_full)
|
||||||
|
self.assert_png(screenshot_root)
|
||||||
|
self.assertEqual(screenshot_root, screenshot_full)
|
||||||
|
self.assertEqual(self.scale(self.get_element_dimensions(self.document_element)),
|
||||||
|
self.get_image_dimensions(screenshot_full))
|
||||||
|
|
||||||
|
def test_capture_viewport(self):
|
||||||
|
# Load a HTML test page into the chrome window to get scrollbars
|
||||||
|
test_page = self.marionette.absolute_url("test.html")
|
||||||
|
dialog = self.open_dialog(url=test_page, width=50, height=50)
|
||||||
|
self.marionette.switch_to_window(dialog)
|
||||||
|
|
||||||
|
# Size of screenshot has to match viewport size
|
||||||
|
screenshot = self.marionette.screenshot(full=False)
|
||||||
|
self.assert_png(screenshot)
|
||||||
|
self.assertEqual(self.scale(self.viewport_dimensions),
|
||||||
|
self.get_image_dimensions(screenshot))
|
||||||
|
self.assertNotEqual(self.scale(self.window_dimensions),
|
||||||
|
self.get_image_dimensions(screenshot))
|
||||||
|
|
||||||
|
self.marionette.close_chrome_window()
|
||||||
|
self.marionette.switch_to_window(self.start_window)
|
||||||
|
|
||||||
|
@skip("https://bugzilla.mozilla.org/show_bug.cgi?id=1213875")
|
||||||
|
def test_capture_scroll_element_into_view(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def test_capture_window_already_closed(self):
|
||||||
|
dialog = self.open_dialog()
|
||||||
|
self.marionette.switch_to_window(dialog)
|
||||||
|
self.marionette.close_chrome_window()
|
||||||
|
|
||||||
|
self.assertRaises(NoSuchWindowException, self.marionette.screenshot)
|
||||||
|
self.marionette.switch_to_window(self.start_window)
|
||||||
|
|
||||||
|
def test_formats(self):
|
||||||
|
dialog = self.open_dialog()
|
||||||
|
self.marionette.switch_to_window(dialog)
|
||||||
|
|
||||||
|
self.assert_formats()
|
||||||
|
|
||||||
|
self.marionette.close_chrome_window()
|
||||||
|
self.marionette.switch_to_window(self.start_window)
|
||||||
|
|
||||||
|
def test_format_unknown(self):
|
||||||
|
with self.assertRaises(ValueError):
|
||||||
|
self.marionette.screenshot(format="cheese")
|
||||||
|
|
||||||
|
@skip_if_mobile
|
||||||
|
def test_highlight_elements(self):
|
||||||
|
dialog = self.open_dialog()
|
||||||
|
self.marionette.switch_to_window(dialog)
|
||||||
|
|
||||||
|
# Highlighting the element itself shouldn't make the image larger
|
||||||
|
element = self.marionette.find_element(By.ID, "test-list")
|
||||||
|
screenshot_element = self.marionette.screenshot(element=element)
|
||||||
|
screenshot_highlight = self.marionette.screenshot(element=element,
|
||||||
|
highlights=[element])
|
||||||
|
self.assertEqual(self.scale(self.get_element_dimensions(element)),
|
||||||
|
self.get_image_dimensions(screenshot_element))
|
||||||
|
self.assertNotEqual(screenshot_element, screenshot_highlight)
|
||||||
|
|
||||||
|
# Highlighting a sub element
|
||||||
|
button = self.marionette.find_element(By.ID, "choose-button")
|
||||||
|
screenshot_highlight_button = self.marionette.screenshot(element=element,
|
||||||
|
highlights=[button])
|
||||||
|
self.assertNotEqual(screenshot_element, screenshot_highlight_button)
|
||||||
|
self.assertNotEqual(screenshot_highlight, screenshot_highlight_button)
|
||||||
|
|
||||||
|
self.marionette.close_chrome_window()
|
||||||
|
self.marionette.switch_to_window(self.start_window)
|
||||||
|
|
||||||
|
def test_highlight_element_not_seen(self):
|
||||||
|
"""Check that for not found elements an exception is raised."""
|
||||||
|
with self.marionette.using_context('content'):
|
||||||
|
self.marionette.navigate(box)
|
||||||
|
content_element = self.marionette.find_element(By.ID, "green")
|
||||||
|
|
||||||
|
self.assertRaisesRegexp(JavascriptException, "Element reference not seen before",
|
||||||
|
self.marionette.screenshot, highlights=[content_element])
|
||||||
|
|
||||||
|
chrome_document_element = self.document_element
|
||||||
|
with self.marionette.using_context('content'):
|
||||||
|
self.assertRaisesRegexp(JavascriptException, "Element reference not seen before",
|
||||||
|
self.marionette.screenshot,
|
||||||
|
highlights=[chrome_document_element])
|
||||||
|
|
||||||
|
|
||||||
|
class TestScreenCaptureContent(WindowManagerMixin, ScreenCaptureTestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
ScreenCaptureTestCase.setUp(self)
|
super(TestScreenCaptureContent, self).setUp()
|
||||||
self.marionette.set_context("content")
|
self.marionette.set_context("content")
|
||||||
|
|
||||||
def test_html_document_element(self):
|
def tearDown(self):
|
||||||
|
self.close_all_tabs()
|
||||||
|
super(TestScreenCaptureContent, self).tearDown()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def scroll_dimensions(self):
|
||||||
|
return tuple(self.marionette.execute_script("""
|
||||||
|
return [document.body.scrollWidth, document.body.scrollHeight]
|
||||||
|
"""))
|
||||||
|
|
||||||
|
@skip_if_mobile # Needs application independent method to open a new tab
|
||||||
|
def test_capture_tab_already_closed(self):
|
||||||
|
tab = self.open_tab()
|
||||||
|
self.marionette.switch_to_window(tab)
|
||||||
|
self.marionette.close()
|
||||||
|
|
||||||
|
self.assertRaises(NoSuchWindowException, self.marionette.screenshot)
|
||||||
|
self.marionette.switch_to_window(self.start_tab)
|
||||||
|
|
||||||
|
def test_capture_element(self):
|
||||||
|
self.marionette.navigate(box)
|
||||||
|
el = self.marionette.find_element(By.TAG_NAME, "div")
|
||||||
|
screenshot = self.marionette.screenshot(element=el)
|
||||||
|
self.assert_png(screenshot)
|
||||||
|
self.assertEqual(self.scale(self.get_element_dimensions(el)),
|
||||||
|
self.get_image_dimensions(screenshot))
|
||||||
|
|
||||||
|
@skip("https://bugzilla.mozilla.org/show_bug.cgi?id=1213875")
|
||||||
|
def test_capture_element_scrolled_into_view(self):
|
||||||
self.marionette.navigate(long)
|
self.marionette.navigate(long)
|
||||||
string = self.marionette.screenshot()
|
el = self.marionette.find_element(By.TAG_NAME, "p")
|
||||||
self.assert_png(string)
|
screenshot = self.marionette.screenshot(element=el)
|
||||||
self.assertEqual(
|
self.assert_png(screenshot)
|
||||||
self.body_scroll_dimensions, self.get_image_dimensions(string))
|
self.assertEqual(self.scale(self.get_element_dimensions(el)),
|
||||||
|
self.get_image_dimensions(screenshot))
|
||||||
|
self.assertGreater(self.page_y_offset, 0)
|
||||||
|
|
||||||
def test_svg_document_element(self):
|
def test_capture_flags(self):
|
||||||
|
self.marionette.navigate(input)
|
||||||
|
|
||||||
|
textbox = self.marionette.find_element(By.ID, "text-input")
|
||||||
|
textbox.send_keys("")
|
||||||
|
screenshot_focus = self.marionette.screenshot()
|
||||||
|
|
||||||
|
self.marionette.execute_script("arguments[0].blur();", script_args=[textbox])
|
||||||
|
screenshot_no_focus = self.marionette.screenshot()
|
||||||
|
|
||||||
|
self.assertNotEqual(screenshot_focus, screenshot_no_focus)
|
||||||
|
|
||||||
|
def test_capture_html_document_element(self):
|
||||||
|
self.marionette.navigate(long)
|
||||||
|
screenshot = self.marionette.screenshot()
|
||||||
|
self.assert_png(screenshot)
|
||||||
|
self.assertEqual(self.scale(self.scroll_dimensions),
|
||||||
|
self.get_image_dimensions(screenshot))
|
||||||
|
|
||||||
|
def test_capture_svg_document_element(self):
|
||||||
self.marionette.navigate(svg)
|
self.marionette.navigate(svg)
|
||||||
doc_el = self.document_element
|
screenshot = self.marionette.screenshot()
|
||||||
string = self.marionette.screenshot()
|
self.assert_png(screenshot)
|
||||||
self.assert_png(string)
|
self.assertEqual(self.scale(self.get_element_dimensions(self.document_element)),
|
||||||
self.assertEqual((doc_el.rect["width"], doc_el.rect["height"]),
|
self.get_image_dimensions(screenshot))
|
||||||
self.get_image_dimensions(string))
|
|
||||||
|
|
||||||
def test_viewport(self):
|
def test_capture_viewport(self):
|
||||||
|
url = self.marionette.absolute_url("clicks.html")
|
||||||
self.marionette.navigate(short)
|
self.marionette.navigate(short)
|
||||||
string = self.marionette.screenshot(full=False)
|
self.marionette.navigate(url)
|
||||||
self.assert_png(string)
|
screenshot = self.marionette.screenshot(full=False)
|
||||||
self.assertEqual(
|
self.assert_png(screenshot)
|
||||||
self.viewport_dimensions, self.get_image_dimensions(string))
|
self.assertEqual(self.scale(self.viewport_dimensions),
|
||||||
|
self.get_image_dimensions(screenshot))
|
||||||
|
|
||||||
def test_viewport_after_scroll(self):
|
def test_capture_viewport_after_scroll(self):
|
||||||
self.marionette.navigate(long)
|
self.marionette.navigate(long)
|
||||||
before = self.marionette.screenshot()
|
before = self.marionette.screenshot()
|
||||||
el = self.marionette.find_element(By.TAG_NAME, "p")
|
el = self.marionette.find_element(By.TAG_NAME, "p")
|
||||||
|
@ -160,48 +365,32 @@ class Content(ScreenCaptureTestCase):
|
||||||
self.assertNotEqual(before, after)
|
self.assertNotEqual(before, after)
|
||||||
self.assertGreater(self.page_y_offset, 0)
|
self.assertGreater(self.page_y_offset, 0)
|
||||||
|
|
||||||
def test_element(self):
|
def test_formats(self):
|
||||||
self.marionette.navigate(box)
|
self.marionette.navigate(box)
|
||||||
el = self.marionette.find_element(By.TAG_NAME, "div")
|
|
||||||
string = self.marionette.screenshot(element=el)
|
|
||||||
self.assert_png(string)
|
|
||||||
self.assertEqual(
|
|
||||||
(el.rect["width"], el.rect["height"]), self.get_image_dimensions(string))
|
|
||||||
self.assertEqual(ELEMENT, string)
|
|
||||||
|
|
||||||
@skip("https://bugzilla.mozilla.org/show_bug.cgi?id=1213875")
|
# Use a smaller region to speed up the test
|
||||||
def test_element_scrolled_into_view(self):
|
element = self.marionette.find_element(By.TAG_NAME, "div")
|
||||||
self.marionette.navigate(long)
|
self.assert_formats(element=element)
|
||||||
el = self.marionette.find_element(By.TAG_NAME, "p")
|
|
||||||
string = self.marionette.screenshot(element=el)
|
|
||||||
self.assert_png(string)
|
|
||||||
self.assertEqual(
|
|
||||||
(el.rect["width"], el.rect["height"]), self.get_image_dimensions(string))
|
|
||||||
self.assertGreater(self.page_y_offset, 0)
|
|
||||||
|
|
||||||
def test_element_with_highlight(self):
|
def test_format_unknown(self):
|
||||||
self.marionette.navigate(box)
|
|
||||||
el = self.marionette.find_element(By.TAG_NAME, "div")
|
|
||||||
string = self.marionette.screenshot(element=el, highlights=[el])
|
|
||||||
self.assert_png(string)
|
|
||||||
self.assertEqual(
|
|
||||||
(el.rect["width"], el.rect["height"]), self.get_image_dimensions(string))
|
|
||||||
self.assertEqual(HIGHLIGHTED_ELEMENT, string)
|
|
||||||
|
|
||||||
def test_binary_element(self):
|
|
||||||
self.marionette.navigate(box)
|
|
||||||
el = self.marionette.find_element(By.TAG_NAME, "div")
|
|
||||||
bin = self.marionette.screenshot(element=el, format="binary")
|
|
||||||
enc = base64.b64encode(bin)
|
|
||||||
self.assertEqual(ELEMENT, enc)
|
|
||||||
|
|
||||||
def test_unknown_format(self):
|
|
||||||
with self.assertRaises(ValueError):
|
with self.assertRaises(ValueError):
|
||||||
self.marionette.screenshot(format="cheese")
|
self.marionette.screenshot(format="cheese")
|
||||||
|
|
||||||
def test_hash_format(self):
|
def test_highlight_elements(self):
|
||||||
self.marionette.navigate(box)
|
self.marionette.navigate(box)
|
||||||
el = self.marionette.find_element(By.TAG_NAME, "div")
|
element = self.marionette.find_element(By.TAG_NAME, "div")
|
||||||
content = self.marionette.screenshot(element=el, format="hash")
|
|
||||||
hash = hashlib.sha256(ELEMENT).hexdigest()
|
# Highlighting the element itself shouldn't make the image larger
|
||||||
self.assertEqual(content, hash)
|
screenshot_element = self.marionette.screenshot(element=element)
|
||||||
|
screenshot_highlight = self.marionette.screenshot(element=element,
|
||||||
|
highlights=[element])
|
||||||
|
self.assertEqual(self.scale(self.get_element_dimensions(element)),
|
||||||
|
self.get_image_dimensions(screenshot_highlight))
|
||||||
|
self.assertNotEqual(screenshot_element, screenshot_highlight)
|
||||||
|
|
||||||
|
# Highlighting a sub element
|
||||||
|
paragraph = self.marionette.find_element(By.ID, "green")
|
||||||
|
screenshot_highlight_paragraph = self.marionette.screenshot(element=element,
|
||||||
|
highlights=[paragraph])
|
||||||
|
self.assertNotEqual(screenshot_element, screenshot_highlight_paragraph)
|
||||||
|
self.assertNotEqual(screenshot_highlight, screenshot_highlight_paragraph)
|
||||||
|
|
|
@ -1673,7 +1673,7 @@ function screenshot(id, full=true, highlights=[]) {
|
||||||
|
|
||||||
// viewport
|
// viewport
|
||||||
if (!id && !full) {
|
if (!id && !full) {
|
||||||
canvas = capture.viewport(curContainer.frame.document, highlightEls);
|
canvas = capture.viewport(curContainer.frame, highlightEls);
|
||||||
|
|
||||||
// element or full document element
|
// element or full document element
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -62,7 +62,7 @@ class TabBar(UIBaseLib):
|
||||||
|
|
||||||
:return: Index of the selected tab.
|
:return: Index of the selected tab.
|
||||||
"""
|
"""
|
||||||
return int(self.toolbar.get_attribute('selectedIndex'))
|
return int(self.toolbar.get_property('selectedIndex'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_tab(self):
|
def selected_tab(self):
|
||||||
|
|
|
@ -98,7 +98,7 @@ class LocationBar(UIBaseLib):
|
||||||
self.focus('shortcut')
|
self.focus('shortcut')
|
||||||
self.urlbar.send_keys(keys.Keys.DELETE)
|
self.urlbar.send_keys(keys.Keys.DELETE)
|
||||||
Wait(self.marionette).until(
|
Wait(self.marionette).until(
|
||||||
lambda _: self.urlbar.get_attribute('value') == '',
|
lambda _: self.value == '',
|
||||||
message='Contents of location bar could not be cleared.')
|
message='Contents of location bar could not be cleared.')
|
||||||
|
|
||||||
def close_context_menu(self):
|
def close_context_menu(self):
|
||||||
|
@ -298,7 +298,7 @@ class LocationBar(UIBaseLib):
|
||||||
|
|
||||||
:returns: The urlbar value.
|
:returns: The urlbar value.
|
||||||
"""
|
"""
|
||||||
return self.urlbar.get_attribute('value')
|
return self.urlbar.get_property('value')
|
||||||
|
|
||||||
|
|
||||||
class AutocompleteResults(UIBaseLib):
|
class AutocompleteResults(UIBaseLib):
|
||||||
|
@ -342,7 +342,7 @@ class AutocompleteResults(UIBaseLib):
|
||||||
{'class': 'ac-emphasize-text ac-emphasize-text-%s' % match_type}
|
{'class': 'ac-emphasize-text ac-emphasize-text-%s' % match_type}
|
||||||
)
|
)
|
||||||
|
|
||||||
return [node.get_attribute('textContent') for node in emphasized_nodes]
|
return [node.get_property('textContent') for node in emphasized_nodes]
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def visible_results(self):
|
def visible_results(self):
|
||||||
|
@ -350,7 +350,7 @@ class AutocompleteResults(UIBaseLib):
|
||||||
|
|
||||||
:returns: The list of visible results.
|
:returns: The list of visible results.
|
||||||
"""
|
"""
|
||||||
match_count = self.element.get_attribute('_matchCount')
|
match_count = self.element.get_property('_matchCount')
|
||||||
|
|
||||||
return self.marionette.execute_script("""
|
return self.marionette.execute_script("""
|
||||||
let rv = [];
|
let rv = [];
|
||||||
|
@ -370,7 +370,7 @@ class AutocompleteResults(UIBaseLib):
|
||||||
|
|
||||||
:returns: True when the popup is open, otherwise false.
|
:returns: True when the popup is open, otherwise false.
|
||||||
"""
|
"""
|
||||||
return self.element.get_attribute('state') == 'open'
|
return self.element.get_property('state') == 'open'
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def is_complete(self):
|
def is_complete(self):
|
||||||
|
@ -404,7 +404,7 @@ class AutocompleteResults(UIBaseLib):
|
||||||
|
|
||||||
:returns: The index.
|
:returns: The index.
|
||||||
"""
|
"""
|
||||||
return self.results.get_attribute('selectedIndex')
|
return self.results.get_property('selectedIndex')
|
||||||
|
|
||||||
|
|
||||||
class IdentityPopup(UIBaseLib):
|
class IdentityPopup(UIBaseLib):
|
||||||
|
@ -421,7 +421,7 @@ class IdentityPopup(UIBaseLib):
|
||||||
|
|
||||||
:returns: True when the popup is open, otherwise false.
|
:returns: True when the popup is open, otherwise false.
|
||||||
"""
|
"""
|
||||||
return self.element.get_attribute('state') == 'open'
|
return self.element.get_property('state') == 'open'
|
||||||
|
|
||||||
def close(self, force=False):
|
def close(self, force=False):
|
||||||
"""Closes the identity popup by hitting the escape key.
|
"""Closes the identity popup by hitting the escape key.
|
||||||
|
|
|
@ -98,7 +98,7 @@ class Deck(UIBaseLib):
|
||||||
|
|
||||||
:return: Index of the selected panel.
|
:return: Index of the selected panel.
|
||||||
"""
|
"""
|
||||||
return int(self.element.get_attribute('selectedIndex'))
|
return int(self.element.get_property('selectedIndex'))
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def selected_panel(self):
|
def selected_panel(self):
|
||||||
|
@ -133,7 +133,7 @@ class PageInfoPanel(Panel):
|
||||||
|
|
||||||
:returns: Reference to the tab element.
|
:returns: Reference to the tab element.
|
||||||
"""
|
"""
|
||||||
name = self.element.get_attribute('id').split('Panel')[0]
|
name = self.element.get_property('id').split('Panel')[0]
|
||||||
return self.window.window_element.find_element(By.ID, name + 'Tab')
|
return self.window.window_element.find_element(By.ID, name + 'Tab')
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -48,12 +48,12 @@ class ShutdownLeaks(object):
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
if not self.seenShutdown:
|
if not self.seenShutdown:
|
||||||
self.logger.warning(
|
self.logger.error(
|
||||||
"TEST-UNEXPECTED-FAIL | ShutdownLeaks | process() called before end of test suite")
|
"TEST-UNEXPECTED-FAIL | ShutdownLeaks | process() called before end of test suite")
|
||||||
|
|
||||||
for test in self._parseLeakingTests():
|
for test in self._parseLeakingTests():
|
||||||
for url, count in self._zipLeakedWindows(test["leakedWindows"]):
|
for url, count in self._zipLeakedWindows(test["leakedWindows"]):
|
||||||
self.logger.warning(
|
self.logger.error(
|
||||||
"TEST-UNEXPECTED-FAIL | %s | leaked %d window(s) until shutdown "
|
"TEST-UNEXPECTED-FAIL | %s | leaked %d window(s) until shutdown "
|
||||||
"[url = %s]" % (test["fileName"], count, url))
|
"[url = %s]" % (test["fileName"], count, url))
|
||||||
|
|
||||||
|
@ -62,9 +62,9 @@ class ShutdownLeaks(object):
|
||||||
(test["fileName"], test["leakedWindowsString"]))
|
(test["fileName"], test["leakedWindowsString"]))
|
||||||
|
|
||||||
if test["leakedDocShells"]:
|
if test["leakedDocShells"]:
|
||||||
self.logger.warning("TEST-UNEXPECTED-FAIL | %s | leaked %d docShell(s) until "
|
self.logger.error("TEST-UNEXPECTED-FAIL | %s | leaked %d docShell(s) until "
|
||||||
"shutdown" %
|
"shutdown" %
|
||||||
(test["fileName"], len(test["leakedDocShells"])))
|
(test["fileName"], len(test["leakedDocShells"])))
|
||||||
self.logger.info("TEST-INFO | %s | docShell(s) leaked: %s" %
|
self.logger.info("TEST-INFO | %s | docShell(s) leaked: %s" %
|
||||||
(test["fileName"], ', '.join(["[pid = %s] [id = %s]" %
|
(test["fileName"], ', '.join(["[pid = %s] [id = %s]" %
|
||||||
x for x in test["leakedDocShells"]]
|
x for x in test["leakedDocShells"]]
|
||||||
|
@ -77,7 +77,7 @@ class ShutdownLeaks(object):
|
||||||
|
|
||||||
# log line has invalid format
|
# log line has invalid format
|
||||||
if not pid or not serial:
|
if not pid or not serial:
|
||||||
self.logger.warning(
|
self.logger.error(
|
||||||
"TEST-UNEXPECTED-FAIL | ShutdownLeaks | failed to parse line <%s>" % line)
|
"TEST-UNEXPECTED-FAIL | ShutdownLeaks | failed to parse line <%s>" % line)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -99,7 +99,7 @@ class ShutdownLeaks(object):
|
||||||
|
|
||||||
# log line has invalid format
|
# log line has invalid format
|
||||||
if not pid or not id:
|
if not pid or not id:
|
||||||
self.logger.warning(
|
self.logger.error(
|
||||||
"TEST-UNEXPECTED-FAIL | ShutdownLeaks | failed to parse line <%s>" % line)
|
"TEST-UNEXPECTED-FAIL | ShutdownLeaks | failed to parse line <%s>" % line)
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -233,8 +233,8 @@ class LSANLeaks(object):
|
||||||
|
|
||||||
def process(self):
|
def process(self):
|
||||||
if self.fatalError:
|
if self.fatalError:
|
||||||
self.logger.warning("TEST-UNEXPECTED-FAIL | LeakSanitizer | LeakSanitizer "
|
self.logger.error("TEST-UNEXPECTED-FAIL | LeakSanitizer | LeakSanitizer "
|
||||||
"has encountered a fatal error.")
|
"has encountered a fatal error.")
|
||||||
|
|
||||||
if self.foundFrames:
|
if self.foundFrames:
|
||||||
self.logger.info("TEST-INFO | LeakSanitizer | To show the "
|
self.logger.info("TEST-INFO | LeakSanitizer | To show the "
|
||||||
|
@ -243,7 +243,7 @@ class LSANLeaks(object):
|
||||||
"in testing/mozbase/mozrunner/mozrunner/utils.py")
|
"in testing/mozbase/mozrunner/mozrunner/utils.py")
|
||||||
|
|
||||||
for f in self.foundFrames:
|
for f in self.foundFrames:
|
||||||
self.logger.warning(
|
self.logger.error(
|
||||||
"TEST-UNEXPECTED-FAIL | LeakSanitizer | leak at " + f)
|
"TEST-UNEXPECTED-FAIL | LeakSanitizer | leak at " + f)
|
||||||
|
|
||||||
def _finishStack(self):
|
def _finishStack(self):
|
||||||
|
|
|
@ -275,6 +275,9 @@ def setup_argument_parser():
|
||||||
|
|
||||||
import imp
|
import imp
|
||||||
path = os.path.join(build_obj.topobjdir, mochitest_dir, 'runtests.py')
|
path = os.path.join(build_obj.topobjdir, mochitest_dir, 'runtests.py')
|
||||||
|
if not os.path.exists(path):
|
||||||
|
path = os.path.join(here, "runtests.py")
|
||||||
|
|
||||||
with open(path, 'r') as fh:
|
with open(path, 'r') as fh:
|
||||||
imp.load_module('mochitest', fh, path,
|
imp.load_module('mochitest', fh, path,
|
||||||
('.py', 'r', imp.PY_SOURCE))
|
('.py', 'r', imp.PY_SOURCE))
|
||||||
|
|
|
@ -824,6 +824,7 @@ class MochitestDesktop(object):
|
||||||
self.result = {}
|
self.result = {}
|
||||||
|
|
||||||
self.start_script = os.path.join(here, 'start_desktop.js')
|
self.start_script = os.path.join(here, 'start_desktop.js')
|
||||||
|
self.disable_leak_checking = False
|
||||||
|
|
||||||
def update_mozinfo(self):
|
def update_mozinfo(self):
|
||||||
"""walk up directories to find mozinfo.json update the info"""
|
"""walk up directories to find mozinfo.json update the info"""
|
||||||
|
@ -1495,7 +1496,8 @@ toolbar#nav-bar {
|
||||||
self.log.error(str(e))
|
self.log.error(str(e))
|
||||||
return None
|
return None
|
||||||
|
|
||||||
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
|
if not self.disable_leak_checking:
|
||||||
|
browserEnv["XPCOM_MEM_BLOAT_LOG"] = self.leak_report_file
|
||||||
|
|
||||||
try:
|
try:
|
||||||
gmp_path = self.getGMPPluginPath(options)
|
gmp_path = self.getGMPPluginPath(options)
|
||||||
|
@ -1939,12 +1941,13 @@ toolbar#nav-bar {
|
||||||
args.append('-foreground')
|
args.append('-foreground')
|
||||||
self.start_script_args.append(testUrl or 'about:blank')
|
self.start_script_args.append(testUrl or 'about:blank')
|
||||||
|
|
||||||
if detectShutdownLeaks:
|
if detectShutdownLeaks and not self.disable_leak_checking:
|
||||||
shutdownLeaks = ShutdownLeaks(self.log)
|
shutdownLeaks = ShutdownLeaks(self.log)
|
||||||
else:
|
else:
|
||||||
shutdownLeaks = None
|
shutdownLeaks = None
|
||||||
|
|
||||||
if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac):
|
if mozinfo.info["asan"] and (mozinfo.isLinux or mozinfo.isMac) \
|
||||||
|
and not self.disable_leak_checking:
|
||||||
lsanLeaks = LSANLeaks(self.log)
|
lsanLeaks = LSANLeaks(self.log)
|
||||||
else:
|
else:
|
||||||
lsanLeaks = None
|
lsanLeaks = None
|
||||||
|
@ -2201,6 +2204,36 @@ toolbar#nav-bar {
|
||||||
result = 1 # default value, if no tests are run.
|
result = 1 # default value, if no tests are run.
|
||||||
for d in dirs:
|
for d in dirs:
|
||||||
print "dir: %s" % d
|
print "dir: %s" % d
|
||||||
|
|
||||||
|
# BEGIN LEAKCHECK HACK
|
||||||
|
# Leak checking was broken in mochitest unnoticed for a length of time. During
|
||||||
|
# this time, several leaks slipped through. The leak checking was fixed by bug
|
||||||
|
# 1325148, but it couldn't land until all the regressions were also fixed or
|
||||||
|
# backed out. Rather than waiting and risking new regressions, in the meantime
|
||||||
|
# this code will selectively disable leak checking on flavors/directories where
|
||||||
|
# known regressions exist. At least this way we can prevent further damage while
|
||||||
|
# they get fixed.
|
||||||
|
|
||||||
|
info = mozinfo.info
|
||||||
|
skip_leak_conditions = [
|
||||||
|
(options.flavor in ('browser', 'chrome', 'plain') and d.startswith('toolkit/components/extensions/test/mochitest'), 'bug 1325158'), # noqa
|
||||||
|
(info['debug'] and options.flavor == 'browser' and d.startswith('browser/components/extensions/test/browser'), 'bug 1325141'), # noqa
|
||||||
|
(info['debug'] and options.flavor == 'plain' and d == 'dom/animation/test/css-animations', 'bug 1325277'), # noqa
|
||||||
|
(info['debug'] and options.flavor == 'plain' and d == 'dom/tests/mochitest/gamepad' and info['os'] == 'win', 'bug 1324592'), # noqa
|
||||||
|
(info['debug'] and options.flavor == 'plain' and d == 'toolkit/components/prompts/test' and info['os'] == 'mac', 'bug 1325275'), # noqa
|
||||||
|
(info['debug'] and options.flavor == 'plain' and d == 'tests/dom/xhr/tests', 'bug 1325438'), # noqa
|
||||||
|
]
|
||||||
|
|
||||||
|
for condition, reason in skip_leak_conditions:
|
||||||
|
if condition:
|
||||||
|
self.log.warning('WARNING | disabling leakcheck due to {}'.format(reason))
|
||||||
|
self.disable_leak_checking = True
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
self.disable_leak_checking = False
|
||||||
|
|
||||||
|
# END LEAKCHECK HACK
|
||||||
|
|
||||||
tests_in_dir = [t for t in testsToRun if os.path.dirname(t) == d]
|
tests_in_dir = [t for t in testsToRun if os.path.dirname(t) == d]
|
||||||
|
|
||||||
# If we are using --run-by-dir, we should not use the profile path (if) provided
|
# If we are using --run-by-dir, we should not use the profile path (if) provided
|
||||||
|
|
|
@ -38,8 +38,6 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
|
||||||
processString = "%s process:" % processType
|
processString = "%s process:" % processType
|
||||||
crashedOnPurpose = False
|
crashedOnPurpose = False
|
||||||
totalBytesLeaked = None
|
totalBytesLeaked = None
|
||||||
logAsWarning = False
|
|
||||||
leakAnalysis = []
|
|
||||||
leakedObjectAnalysis = []
|
leakedObjectAnalysis = []
|
||||||
leakedObjectNames = []
|
leakedObjectNames = []
|
||||||
recordLeakedObjects = False
|
recordLeakedObjects = False
|
||||||
|
@ -68,9 +66,9 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
|
||||||
# log, particularly on B2G. Eventually, these should be split into multiple
|
# log, particularly on B2G. Eventually, these should be split into multiple
|
||||||
# logs (bug 1068869), but for now, we report the largest leak.
|
# logs (bug 1068869), but for now, we report the largest leak.
|
||||||
if totalBytesLeaked is not None:
|
if totalBytesLeaked is not None:
|
||||||
leakAnalysis.append("WARNING | leakcheck | %s "
|
log.warning("leakcheck | %s "
|
||||||
"multiple BloatView byte totals found"
|
"multiple BloatView byte totals found"
|
||||||
% processString)
|
% processString)
|
||||||
else:
|
else:
|
||||||
totalBytesLeaked = 0
|
totalBytesLeaked = 0
|
||||||
if bytesLeaked > totalBytesLeaked:
|
if bytesLeaked > totalBytesLeaked:
|
||||||
|
@ -83,22 +81,15 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
|
||||||
else:
|
else:
|
||||||
recordLeakedObjects = False
|
recordLeakedObjects = False
|
||||||
if size < 0 or bytesLeaked < 0 or numLeaked < 0:
|
if size < 0 or bytesLeaked < 0 or numLeaked < 0:
|
||||||
leakAnalysis.append("TEST-UNEXPECTED-FAIL | leakcheck | %s negative leaks caught!"
|
log.error("TEST-UNEXPECTED-FAIL | leakcheck | %s negative leaks caught!"
|
||||||
% processString)
|
% processString)
|
||||||
logAsWarning = True
|
|
||||||
continue
|
continue
|
||||||
if name != "TOTAL" and numLeaked != 0 and recordLeakedObjects:
|
if name != "TOTAL" and numLeaked != 0 and recordLeakedObjects:
|
||||||
leakedObjectNames.append(name)
|
leakedObjectNames.append(name)
|
||||||
leakedObjectAnalysis.append("TEST-INFO | leakcheck | %s leaked %d %s"
|
leakedObjectAnalysis.append("TEST-INFO | leakcheck | %s leaked %d %s"
|
||||||
% (processString, numLeaked, name))
|
% (processString, numLeaked, name))
|
||||||
|
|
||||||
leakAnalysis.extend(leakedObjectAnalysis)
|
log.info('\n'.join(leakedObjectAnalysis))
|
||||||
if logAsWarning:
|
|
||||||
log.warning('\n'.join(leakAnalysis))
|
|
||||||
else:
|
|
||||||
log.info('\n'.join(leakAnalysis))
|
|
||||||
|
|
||||||
logAsWarning = False
|
|
||||||
|
|
||||||
if totalBytesLeaked is None:
|
if totalBytesLeaked is None:
|
||||||
# We didn't see a line with name 'TOTAL'
|
# We didn't see a line with name 'TOTAL'
|
||||||
|
@ -109,8 +100,8 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
|
||||||
log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks"
|
log.info("TEST-INFO | leakcheck | %s ignoring missing output line for total leaks"
|
||||||
% processString)
|
% processString)
|
||||||
else:
|
else:
|
||||||
log.info("TEST-UNEXPECTED-FAIL | leakcheck | %s missing output line for total leaks!"
|
log.error("TEST-UNEXPECTED-FAIL | leakcheck | %s missing output line for total leaks!"
|
||||||
% processString)
|
% processString)
|
||||||
log.info("TEST-INFO | leakcheck | missing output line from log file %s"
|
log.info("TEST-INFO | leakcheck | missing output line from log file %s"
|
||||||
% leakLogFileName)
|
% leakLogFileName)
|
||||||
return
|
return
|
||||||
|
@ -120,12 +111,6 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
|
||||||
processString)
|
processString)
|
||||||
return
|
return
|
||||||
|
|
||||||
if totalBytesLeaked > leakThreshold:
|
|
||||||
logAsWarning = True
|
|
||||||
# Fail the run if we're over the threshold (which defaults to 0)
|
|
||||||
prefix = "TEST-UNEXPECTED-FAIL"
|
|
||||||
else:
|
|
||||||
prefix = "WARNING"
|
|
||||||
# Create a comma delimited string of the first N leaked objects found,
|
# Create a comma delimited string of the first N leaked objects found,
|
||||||
# to aid with bug summary matching in TBPL. Note: The order of the objects
|
# to aid with bug summary matching in TBPL. Note: The order of the objects
|
||||||
# had no significance (they're sorted alphabetically).
|
# had no significance (they're sorted alphabetically).
|
||||||
|
@ -134,14 +119,15 @@ def process_single_leak_file(leakLogFileName, processType, leakThreshold,
|
||||||
if len(leakedObjectNames) > maxSummaryObjects:
|
if len(leakedObjectNames) > maxSummaryObjects:
|
||||||
leakedObjectSummary += ', ...'
|
leakedObjectSummary += ', ...'
|
||||||
|
|
||||||
|
message = "leakcheck | %s %d bytes leaked (%s)" % (
|
||||||
|
processString, totalBytesLeaked, leakedObjectSummary)
|
||||||
|
|
||||||
# totalBytesLeaked will include any expected leaks, so it can be off
|
# totalBytesLeaked will include any expected leaks, so it can be off
|
||||||
# by a few thousand bytes.
|
# by a few thousand bytes.
|
||||||
if logAsWarning:
|
if totalBytesLeaked > leakThreshold:
|
||||||
log.warning("%s | leakcheck | %s %d bytes leaked (%s)"
|
log.error("TEST-UNEXPECTED-FAIL | %s" % message)
|
||||||
% (prefix, processString, totalBytesLeaked, leakedObjectSummary))
|
|
||||||
else:
|
else:
|
||||||
log.info("%s | leakcheck | %s %d bytes leaked (%s)"
|
log.warning(message)
|
||||||
% (prefix, processString, totalBytesLeaked, leakedObjectSummary))
|
|
||||||
|
|
||||||
|
|
||||||
def process_leak_log(leak_log_file, leak_thresholds=None,
|
def process_leak_log(leak_log_file, leak_thresholds=None,
|
||||||
|
@ -175,8 +161,8 @@ def process_leak_log(leak_log_file, leak_thresholds=None,
|
||||||
|
|
||||||
leakLogFile = leak_log_file
|
leakLogFile = leak_log_file
|
||||||
if not os.path.exists(leakLogFile):
|
if not os.path.exists(leakLogFile):
|
||||||
log.info(
|
log.warning(
|
||||||
"WARNING | leakcheck | refcount logging is off, so leaks can't be detected!")
|
"leakcheck | refcount logging is off, so leaks can't be detected!")
|
||||||
return
|
return
|
||||||
|
|
||||||
leakThresholds = leak_thresholds or {}
|
leakThresholds = leak_thresholds or {}
|
||||||
|
@ -192,8 +178,8 @@ def process_leak_log(leak_log_file, leak_thresholds=None,
|
||||||
|
|
||||||
for processType in leakThresholds:
|
for processType in leakThresholds:
|
||||||
if processType not in knownProcessTypes:
|
if processType not in knownProcessTypes:
|
||||||
log.info("TEST-UNEXPECTED-FAIL | leakcheck | Unknown process type %s in leakThresholds"
|
log.error("TEST-UNEXPECTED-FAIL | leakcheck | "
|
||||||
% processType)
|
"Unknown process type %s in leakThresholds" % processType)
|
||||||
|
|
||||||
(leakLogFileDir, leakFileBase) = os.path.split(leakLogFile)
|
(leakLogFileDir, leakFileBase) = os.path.split(leakLogFile)
|
||||||
if leakFileBase[-4:] == ".log":
|
if leakFileBase[-4:] == ".log":
|
||||||
|
@ -211,8 +197,8 @@ def process_leak_log(leak_log_file, leak_thresholds=None,
|
||||||
else:
|
else:
|
||||||
processType = "default"
|
processType = "default"
|
||||||
if processType not in knownProcessTypes:
|
if processType not in knownProcessTypes:
|
||||||
log.info("TEST-UNEXPECTED-FAIL | leakcheck | Leak log with unknown process type %s"
|
log.error("TEST-UNEXPECTED-FAIL | leakcheck | "
|
||||||
% processType)
|
"Leak log with unknown process type %s" % processType)
|
||||||
leakThreshold = leakThresholds.get(processType, 0)
|
leakThreshold = leakThresholds.get(processType, 0)
|
||||||
process_single_leak_file(thisFile, processType, leakThreshold,
|
process_single_leak_file(thisFile, processType, leakThreshold,
|
||||||
processType in ignoreMissingLeaks,
|
processType in ignoreMissingLeaks,
|
||||||
|
|
|
@ -314,7 +314,9 @@ stage-extensions: make-stage-dir
|
||||||
|
|
||||||
check::
|
check::
|
||||||
$(eval cores=$(shell $(PYTHON) -c 'import multiprocessing; print(multiprocessing.cpu_count())'))
|
$(eval cores=$(shell $(PYTHON) -c 'import multiprocessing; print(multiprocessing.cpu_count())'))
|
||||||
|
@echo "Starting 'mach python-test' with -j$(cores)"
|
||||||
@$(topsrcdir)/mach --log-no-times python-test -j$(cores)
|
@$(topsrcdir)/mach --log-no-times python-test -j$(cores)
|
||||||
|
@echo "Finished 'mach python-test' successfully"
|
||||||
|
|
||||||
|
|
||||||
.PHONY: \
|
.PHONY: \
|
||||||
|
|
Загрузка…
Ссылка в новой задаче