diff --git a/testing/marionette/client/marionette/marionette_test.py b/testing/marionette/client/marionette/marionette_test.py index cd45db52a8b9..eaf41149aac5 100644 --- a/testing/marionette/client/marionette/marionette_test.py +++ b/testing/marionette/client/marionette/marionette_test.py @@ -195,6 +195,12 @@ def __new__(cls, name, bases, attrs): return type.__new__(cls, name, bases, attrs) +class JSTest: + head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];") + context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];") + timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);") + inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);") + class CommonTestCase(unittest.TestCase): __metaclass__ = MetaParameterized @@ -486,6 +492,109 @@ def close_test_container(self): 'iframe[src*="app://test-container.gaiamobile.org/index.html"]' )) + def run_js_test(self, filename, marionette=None): + ''' + Run a JavaScript test file and collect its set of assertions + into the current test's results. + + :param filename: The path to the JavaScript test file to execute. + May be relative to the current script. + :param marionette: The Marionette object in which to execute the test. + Defaults to self.marionette. + ''' + marionette = marionette or self.marionette + if not os.path.isabs(filename): + # Find the caller's filename and make the path relative to that. + caller_file = sys._getframe(1).f_globals.get('__file__', '') + caller_file = os.path.abspath(caller_file) + filename = os.path.join(os.path.dirname(caller_file), filename) + self.assert_(os.path.exists(filename), + 'Script "%s" must exist' % filename) + original_test_name = self.marionette.test_name + self.marionette.test_name = os.path.basename(filename) + f = open(filename, 'r') + js = f.read() + args = [] + + head_js = JSTest.head_js_re.search(js); + if head_js: + head_js = head_js.group(3) + head = open(os.path.join(os.path.dirname(filename), head_js), 'r') + js = head.read() + js; + + context = JSTest.context_re.search(js) + if context: + context = context.group(3) + else: + context = 'content' + marionette.set_context(context) + + if context != 'chrome': + marionette.navigate('data:text/html,test page') + + timeout = JSTest.timeout_re.search(js) + if timeout: + timeout = timeout.group(3) + marionette.set_script_timeout(timeout) + + inactivity_timeout = JSTest.inactivity_timeout_re.search(js) + if inactivity_timeout: + inactivity_timeout = inactivity_timeout.group(3) + + try: + results = marionette.execute_js_script( + js, + args, + special_powers=True, + inactivity_timeout=inactivity_timeout, + filename=os.path.basename(filename) + ) + + self.assertTrue(not 'timeout' in filename, + 'expected timeout not triggered') + + if 'fail' in filename: + self.assertTrue(len(results['failures']) > 0, + "expected test failures didn't occur") + else: + for failure in results['failures']: + diag = "" if failure.get('diag') is None else failure['diag'] + name = "got false, expected true" if failure.get('name') is None else failure['name'] + self.logger.test_status(self.test_name, name, 'FAIL', + message=diag) + for failure in results['expectedFailures']: + diag = "" if failure.get('diag') is None else failure['diag'] + name = "got false, expected false" if failure.get('name') is None else failure['name'] + self.logger.test_status(self.test_name, name, 'FAIL', + expected='FAIL', message=diag) + for failure in results['unexpectedSuccesses']: + diag = "" if failure.get('diag') is None else failure['diag'] + name = "got true, expected false" if failure.get('name') is None else failure['name'] + self.logger.test_status(self.test_name, name, 'PASS', + expected='FAIL', message=diag) + self.assertEqual(0, len(results['failures']), + '%d tests failed' % len(results['failures'])) + if len(results['unexpectedSuccesses']) > 0: + raise _UnexpectedSuccess('') + if len(results['expectedFailures']) > 0: + raise _ExpectedFailure((AssertionError, AssertionError(''), None)) + + self.assertTrue(results['passed'] + + len(results['failures']) + + len(results['expectedFailures']) + + len(results['unexpectedSuccesses']) > 0, + 'no tests run') + + except ScriptTimeoutException: + if 'timeout' in filename: + # expected exception + pass + else: + self.loglines = marionette.get_logs() + raise + self.marionette.test_name = original_test_name + + class MarionetteTestCase(CommonTestCase): @@ -559,10 +668,6 @@ def wait_for_condition(self, method, timeout=30): class MarionetteJSTestCase(CommonTestCase): - head_js_re = re.compile(r"MARIONETTE_HEAD_JS(\s*)=(\s*)['|\"](.*?)['|\"];") - context_re = re.compile(r"MARIONETTE_CONTEXT(\s*)=(\s*)['|\"](.*?)['|\"];") - timeout_re = re.compile(r"MARIONETTE_TIMEOUT(\s*)=(\s*)(\d+);") - inactivity_timeout_re = re.compile(r"MARIONETTE_INACTIVITY_TIMEOUT(\s*)=(\s*)(\d+);") match_re = re.compile(r"test_(.*)\.js$") def __init__(self, marionette_weakref, methodName='runTest', jsFile=None, **kwargs): @@ -580,86 +685,9 @@ def add_tests_to_suite(cls, mod_name, filepath, suite, testloader, marionette, t def runTest(self): if self.marionette.session is None: self.marionette.start_session() - self.marionette.test_name = os.path.basename(self.jsFile) self.marionette.execute_script("log('TEST-START: %s');" % self.jsFile.replace('\\', '\\\\')) - f = open(self.jsFile, 'r') - js = f.read() - args = [] - - if os.path.basename(self.jsFile).startswith('test_'): - head_js = self.head_js_re.search(js); - if head_js: - head_js = head_js.group(3) - head = open(os.path.join(os.path.dirname(self.jsFile), head_js), 'r') - js = head.read() + js; - - context = self.context_re.search(js) - if context: - context = context.group(3) - self.marionette.set_context(context) - - if context != "chrome": - self.marionette.navigate('data:text/html,test page') - - timeout = self.timeout_re.search(js) - if timeout: - timeout = timeout.group(3) - self.marionette.set_script_timeout(timeout) - - inactivity_timeout = self.inactivity_timeout_re.search(js) - if inactivity_timeout: - inactivity_timeout = inactivity_timeout.group(3) - - try: - results = self.marionette.execute_js_script(js, - args, - special_powers=True, - inactivity_timeout=inactivity_timeout, - filename=os.path.basename(self.jsFile)) - - self.assertTrue(not 'timeout' in self.jsFile, - 'expected timeout not triggered') - - if 'fail' in self.jsFile: - self.assertTrue(len(results['failures']) > 0, - "expected test failures didn't occur") - else: - for failure in results['failures']: - diag = "" if failure.get('diag') is None else failure['diag'] - name = "got false, expected true" if failure.get('name') is None else failure['name'] - self.logger.test_status(self.test_name, name, 'FAIL', - message=diag) - for failure in results['expectedFailures']: - diag = "" if failure.get('diag') is None else failure['diag'] - name = "got false, expected false" if failure.get('name') is None else failure['name'] - self.logger.test_status(self.test_name, name, 'FAIL', - expected='FAIL', message=diag) - for failure in results['unexpectedSuccesses']: - diag = "" if failure.get('diag') is None else failure['diag'] - name = "got true, expected false" if failure.get('name') is None else failure['name'] - self.logger.test_status(self.test_name, name, 'PASS', - expected='FAIL', message=diag) - self.assertEqual(0, len(results['failures']), - '%d tests failed' % len(results['failures'])) - if len(results['unexpectedSuccesses']) > 0: - raise _UnexpectedSuccess('') - if len(results['expectedFailures']) > 0: - raise _ExpectedFailure((AssertionError, AssertionError(''), None)) - - self.assertTrue(results['passed'] - + len(results['failures']) - + len(results['expectedFailures']) - + len(results['unexpectedSuccesses']) > 0, - 'no tests run') - - except ScriptTimeoutException: - if 'timeout' in self.jsFile: - # expected exception - pass - else: - self.loglines = self.marionette.get_logs() - raise + self.run_js_test(self.jsFile) self.marionette.execute_script("log('TEST-END: %s');" % self.jsFile.replace('\\', '\\\\')) self.marionette.test_name = None diff --git a/testing/marionette/client/marionette/tests/unit/test_run_js_test.py b/testing/marionette/client/marionette/tests/unit/test_run_js_test.py new file mode 100644 index 000000000000..f901460c3ce4 --- /dev/null +++ b/testing/marionette/client/marionette/tests/unit/test_run_js_test.py @@ -0,0 +1,10 @@ +# Any copyright is dedicated to the Public Domain. +# http://creativecommons.org/publicdomain/zero/1.0/ + +from marionette_test import MarionetteTestCase +import unittest + +class TestRunJSTest(MarionetteTestCase): + def test_basic(self): + self.run_js_test('test_simpletest_pass.js') + self.run_js_test('test_simpletest_fail.js')