diff --git a/addons/web/__openerp__.py b/addons/web/__openerp__.py index 5941a6aa5b0..a4000856afe 100644 --- a/addons/web/__openerp__.py +++ b/addons/web/__openerp__.py @@ -14,81 +14,7 @@ This module provides the core of the OpenERP Web Client. 'data': [ 'views/webclient_templates.xml', ], - 'js': [ - "static/lib/es5-shim/es5-shim.min.js", - "static/lib/datejs/globalization/en-US.js", - "static/lib/datejs/core.js", - "static/lib/datejs/parser.js", - "static/lib/datejs/sugarpak.js", - "static/lib/datejs/extras.js", - "static/lib/jquery/jquery.js", - "static/lib/jquery.form/jquery.form.js", - "static/lib/jquery.validate/jquery.validate.js", - "static/lib/jquery.ba-bbq/jquery.ba-bbq.js", - "static/lib/spinjs/spin.js", - "static/lib/jquery.autosize/jquery.autosize.js", - "static/lib/jquery.blockUI/jquery.blockUI.js", - "static/lib/jquery.hotkeys/jquery.hotkeys.js", - "static/lib/jquery.placeholder/jquery.placeholder.js", - "static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js", - "static/lib/jquery.ui.timepicker/js/jquery-ui-timepicker-addon.js", - "static/lib/jquery.ui.notify/js/jquery.notify.js", - "static/lib/jquery.deferred-queue/jquery.deferred-queue.js", - "static/lib/jquery.scrollTo/jquery.scrollTo-min.js", - "static/lib/jquery.textext/jquery.textext.js", - "static/lib/jquery.timeago/jquery.timeago.js", - "static/lib/bootstrap/js/bootstrap.js", - "static/lib/qweb/qweb2.js", - "static/lib/underscore/underscore.js", - "static/lib/underscore.string/lib/underscore.string.js", - "static/lib/backbone/backbone.js", - "static/lib/cleditor/jquery.cleditor.js", - "static/lib/py.js/lib/py.js", - "static/lib/select2/select2.js", - "static/src/js/openerpframework.js", - "static/src/js/boot.js", - "static/src/js/testing.js", - "static/src/js/pyeval.js", - "static/src/js/core.js", - "static/src/js/formats.js", - "static/src/js/chrome.js", - "static/src/js/views.js", - "static/src/js/data.js", - "static/src/js/data_export.js", - "static/src/js/search.js", - "static/src/js/view_list.js", - "static/src/js/view_form.js", - "static/src/js/view_list_editable.js", - "static/src/js/view_tree.js", - ], - 'css' : [ - "static/lib/jquery.ui.bootstrap/css/custom-theme/jquery-ui-1.9.0.custom.css", - "static/lib/jquery.ui.timepicker/css/jquery-ui-timepicker-addon.css", - "static/lib/jquery.ui.notify/css/ui.notify.css", - "static/lib/jquery.textext/jquery.textext.css", - "static/lib/fontawesome/css/font-awesome.css", - "static/lib/bootstrap/css/bootstrap.css", - "static/lib/select2/select2.css", - "static/src/css/base.css", - "static/src/css/data_export.css", - "static/lib/cleditor/jquery.cleditor.css", - ], 'qweb' : [ "static/src/xml/*.xml", ], - 'test': [ - "static/test/testing.js", - "static/test/framework.js", - "static/test/registry.js", - "static/test/form.js", - "static/test/data.js", - "static/test/list-utils.js", - "static/test/formats.js", - "static/test/rpc-misordered.js", - "static/test/evals.js", - "static/test/search.js", - "static/test/list.js", - "static/test/list-editable.js", - "static/test/mutex.js" - ], } diff --git a/addons/web/controllers/__init__.py b/addons/web/controllers/__init__.py index 74c27518ece..12a7e529b67 100644 --- a/addons/web/controllers/__init__.py +++ b/addons/web/controllers/__init__.py @@ -1,2 +1 @@ from . import main -from . import testing diff --git a/addons/web/controllers/main.py b/addons/web/controllers/main.py index 5bf31d341ac..4c7259c000d 100644 --- a/addons/web/controllers/main.py +++ b/addons/web/controllers/main.py @@ -31,6 +31,7 @@ except ImportError: import openerp import openerp.modules.registry +from openerp.addons.base.ir.ir_qweb import AssetsBundle, QWebTemplateNotFound from openerp.tools.translate import _ from openerp import http @@ -52,50 +53,6 @@ env.filters["json"] = simplejson.dumps # OpenERP Web helpers #---------------------------------------------------------- -def rjsmin(script): - """ Minify js with a clever regex. - Taken from http://opensource.perlig.de/rjsmin - Apache License, Version 2.0 """ - def subber(match): - """ Substitution callback """ - groups = match.groups() - return ( - groups[0] or - groups[1] or - groups[2] or - groups[3] or - (groups[4] and '\n') or - (groups[5] and ' ') or - (groups[6] and ' ') or - (groups[7] and ' ') or - '' - ) - - result = re.sub( - r'([^\047"/\000-\040]+)|((?:(?:\047[^\047\\\r\n]*(?:\\(?:[^\r\n]|\r?' - r'\n|\r)[^\047\\\r\n]*)*\047)|(?:"[^"\\\r\n]*(?:\\(?:[^\r\n]|\r?\n|' - r'\r)[^"\\\r\n]*)*"))[^\047"/\000-\040]*)|(?:(?<=[(,=:\[!&|?{};\r\n]' - r')(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/' - r'))*((?:/(?![\r\n/*])[^/\\\[\r\n]*(?:(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*' - r'(?:\\[^\r\n][^\\\]\r\n]*)*\]))[^/\\\[\r\n]*)*/)[^\047"/\000-\040]*' - r'))|(?:(?<=[\000-#%-,./:-@\[-^`{-~-]return)(?:[\000-\011\013\014\01' - r'6-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*((?:/(?![\r\n/*])[^/' - r'\\\[\r\n]*(?:(?:\\[^\r\n]|(?:\[[^\\\]\r\n]*(?:\\[^\r\n][^\\\]\r\n]' - r'*)*\]))[^/\\\[\r\n]*)*/)[^\047"/\000-\040]*))|(?<=[^\000-!#%&(*,./' - r':-@\[\\^`{|~])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/' - r'*][^*]*\*+)*/))*(?:((?:(?://[^\r\n]*)?[\r\n]))(?:[\000-\011\013\01' - r'4\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))*)+(?=[^\000-\040"#' - r'%-\047)*,./:-@\\-^`|-~])|(?<=[^\000-#%-,./:-@\[-^`{-~-])((?:[\000-' - r'\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=[^' - r'\000-#%-,./:-@\[-^`{-~-])|(?<=\+)((?:[\000-\011\013\014\016-\040]|' - r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=\+)|(?<=-)((?:[\000-\011\0' - r'13\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)))+(?=-)|(?:[\0' - r'00-\011\013\014\016-\040]|(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/))+|(?:' - r'(?:(?://[^\r\n]*)?[\r\n])(?:[\000-\011\013\014\016-\040]|(?:/\*[^*' - r']*\*+(?:[^/*][^*]*\*+)*/))*)+', subber, '\n%s\n' % script - ).strip() - return result - db_list = http.db_list db_monodb = http.db_monodb @@ -309,45 +266,6 @@ def concat_xml(file_list): root.append(child) return ElementTree.tostring(root, 'utf-8'), checksum.hexdigest() -def concat_files(file_list, reader=None, intersperse=""): - """ Concatenates contents of all provided files - - :param list(str) file_list: list of files to check - :param function reader: reading procedure for each file - :param str intersperse: string to intersperse between file contents - :returns: (concatenation_result, checksum) - :rtype: (str, str) - """ - checksum = hashlib.new('sha1') - if not file_list: - return '', checksum.hexdigest() - - if reader is None: - def reader(f): - import codecs - with codecs.open(f, 'rb', "utf-8-sig") as fp: - return fp.read().encode("utf-8") - - files_content = [] - for fname in file_list: - contents = reader(fname) - checksum.update(contents) - files_content.append(contents) - - files_concat = intersperse.join(files_content) - return files_concat, checksum.hexdigest() - -concat_js_cache = {} - -def concat_js(file_list): - content, checksum = concat_files(file_list, intersperse=';') - if checksum in concat_js_cache: - content = concat_js_cache[checksum] - else: - content = rjsmin(content) - concat_js_cache[checksum] = content - return content, checksum - def fs2web(path): """convert FS path into web path""" return '/'.join(path.split(os.path.sep)) @@ -371,30 +289,17 @@ def manifest_glob(extension, addons=None, db=None, include_remotes=False): r.append((None, pattern)) else: for path in glob.glob(os.path.normpath(os.path.join(addons_path, addon, pattern))): - # Hack for IE, who limit 288Ko, 4095 rules, 31 sheets - # http://support.microsoft.com/kb/262161/en - if pattern == "static/lib/bootstrap/css/bootstrap.css": - if include_remotes: - r.insert(0, (None, fs2web(path[len(addons_path):]))) - else: - r.append((path, fs2web(path[len(addons_path):]))) + r.append((path, fs2web(path[len(addons_path):]))) return r -def manifest_list(extension, mods=None, db=None, debug=False): +def manifest_list(extension, mods=None, db=None, debug=None): """ list ressources to load specifying either: mods: a comma separated string listing modules db: a database name (return all installed modules in that database) """ + if debug is not None: + _logger.warning("openerp.addons.web.main.manifest_list(): debug parameter is deprecated") files = manifest_glob(extension, addons=mods, db=db, include_remotes=True) - if not debug: - path = '/web/webclient/' + extension - if mods is not None: - path += '?' + werkzeug.url_encode({'mods': mods}) - elif db: - path += '?' + werkzeug.url_encode({'db': db}) - - remotes = [wp for fp, wp in files if fp is None] - return [path] + remotes return [wp for _fp, wp in files] def get_last_modified(files): @@ -411,7 +316,7 @@ def get_last_modified(files): for f in files) return datetime.datetime(1970, 1, 1) -def make_conditional(response, last_modified=None, etag=None): +def make_conditional(response, last_modified=None, etag=None, max_age=0): """ Makes the provided response conditional based upon the request, and mandates revalidation from clients @@ -426,7 +331,7 @@ def make_conditional(response, last_modified=None, etag=None): :rtype: werkzeug.wrappers.Response """ response.cache_control.must_revalidate = True - response.cache_control.max_age = 0 + response.cache_control.max_age = max_age if last_modified: response.last_modified = last_modified if etag: @@ -603,6 +508,10 @@ html_template = """ OpenERP + + + + %(css)s %(js)s - - - - -
-
- - -% for module, jss, tests, templates in files: - % for js in jss: - % if not js.endswith('/apps.js'): - - % endif - % endfor - % if tests or templates: - - % endif - % if tests: - % for test in tests: - - % endfor - % endif -% endfor - -""", default_filters=['h']) - -class TestRunnerController(http.Controller): - - @http.route('/web/tests', type='http', auth="none") - def index(self, mod=None, **kwargs): - ms = module.get_modules() - manifests = dict( - (name, desc) - for name, desc in zip(ms, map(self.load_manifest, ms)) - if desc # remove not-actually-openerp-modules - ) - - if not mod: - return NOMODULE_TEMPLATE.render(modules=( - (manifest['name'], name) - for name, manifest in manifests.iteritems() - if any(testfile.endswith('.js') - for testfile in manifest['test']) - )) - sorted_mods = module_topological_sort(dict( - (name, manifest.get('depends', [])) - for name, manifest in manifests.iteritems() - )) - # to_load and to_test should be zippable lists of the same length. - # A falsy value in to_test indicate nothing to test at that index (just - # load the corresponding part of to_load) - to_test = sorted_mods - if mod != '*': - if mod not in manifests: - return request.not_found(NOTFOUND.render(module=mod)) - idx = sorted_mods.index(mod) - to_test = [None] * len(sorted_mods) - to_test[idx] = mod - - tests_candicates = [ - filter(lambda path: path.endswith('.js'), - manifests[mod]['test'] if mod else []) - for mod in to_test] - # remove trailing test-less modules - tests = reversed(list( - itertools.dropwhile( - operator.not_, - reversed(tests_candicates)))) - - files = [ - (mod, manifests[mod]['js'], tests, manifests[mod]['qweb']) - for mod, tests in itertools.izip(sorted_mods, tests) - ] - - return TESTING.render(files=files, dependencies=json.dumps( - [name for name in sorted_mods - if module.get_module_resource(name, 'static') - if manifests[name]['js']])) - - def load_manifest(self, name): - manifest = module.load_information_from_description_file(name) - if manifest: - path = module.get_module_path(name) - manifest['js'] = list( - self.expand_patterns(path, manifest.get('js', []))) - manifest['test'] = list( - self.expand_patterns(path, manifest.get('test', []))) - manifest['qweb'] = list( - self.expand_patterns(path, manifest.get('qweb', []))) - return manifest - - def expand_patterns(self, root, patterns): - for pattern in patterns: - normalized_pattern = os.path.normpath(os.path.join(root, pattern)) - for path in glob.glob(normalized_pattern): - # replace OS path separators (from join & normpath) by URI ones - yield path[len(root):].replace(os.path.sep, '/') - diff --git a/addons/web/static/src/js/chrome.js b/addons/web/static/src/js/chrome.js index 3c1f55df981..4f12a915a7c 100644 --- a/addons/web/static/src/js/chrome.js +++ b/addons/web/static/src/js/chrome.js @@ -1457,7 +1457,7 @@ instance.web.embed = function (origin, dbname, login, key, action, options) { $('head').append($('', { 'rel': 'stylesheet', 'type': 'text/css', - 'href': origin +'/web/webclient/css' + 'href': origin +'/web/css/web.assets_webclient' })); var currentScript = document.currentScript; if (!currentScript) { diff --git a/addons/web/static/src/js/testing.js b/addons/web/static/src/js/testing.js index 1f1c718ad5f..5e9483addc1 100644 --- a/addons/web/static/src/js/testing.js +++ b/addons/web/static/src/js/testing.js @@ -48,15 +48,6 @@ openerp.testing = {}; testing.dependencies = window['oe_all_dependencies'] || []; testing.current_module = null; - testing.templates = { }; - testing.add_template = function (name) { - var xhr = QWeb2.Engine.prototype.get_xhr(); - xhr.open('GET', name, false); - xhr.send(null); - (testing.templates[testing.current_module] = - testing.templates[testing.current_module] || []) - .push(xhr.responseXML); - }; /** * Function which does not do anything */ @@ -206,7 +197,7 @@ openerp.testing = {}; teardown: testing.noop }); - QUnit.module(testing.current_module + '.' + name, {_oe: options}); + QUnit.module(name, {_oe: options}); body(testing['case']); }; testing['case'] = function (name, options, callback) { @@ -244,18 +235,6 @@ openerp.testing = {}; expect(opts.asserts); } - if (opts.templates) { - for(var i=0; i options.timeout) { - sendMessage('fail.timeout'); - phantom.exit(); - } -}, 100); - -// Create a new page. -var page = require('webpage').create(); - -// The client page must send its messages via alert(jsonstring). -page.onAlert = function(args) { - sendMessage(JSON.parse(args)); -}; - -// Keep track if the client-side helper script already has been injected. -var injected; -page.onUrlChanged = function(newUrl) { - injected = false; - sendMessage('onUrlChanged', newUrl); -}; - -// Relay console logging messages. -page.onConsoleMessage = function(message) { - sendMessage('console', message); -}; - -// For debugging. -page.onResourceRequested = function(request) { - sendMessage('onResourceRequested', request.url); -}; - -page.onResourceReceived = function(request) { - if (request.stage === 'end') { - sendMessage('onResourceReceived', request.url); - } -}; - -// Run when the page has finished loading. -page.onLoadFinished = function(status) { - // The window has loaded. - sendMessage('onLoadFinished', status); - if (status === 'success') { - if (options.inject && !injected) { - // Inject client-side helper script, but only if it has not yet been - // injected. - sendMessage('inject', options.inject); - page.injectJs(options.inject); - } - } else { - // File loading failure. - sendMessage('fail.load', url); - phantom.exit(); - } -}; - -// Actually load url. -page.open(url); diff --git a/addons/web/tests/qunitsuite/grunt/license b/addons/web/tests/qunitsuite/grunt/license deleted file mode 100644 index 90c336c39d3..00000000000 --- a/addons/web/tests/qunitsuite/grunt/license +++ /dev/null @@ -1,22 +0,0 @@ -Copyright (c) 2012 "Cowboy" Ben Alman - -Permission is hereby granted, free of charge, to any person -obtaining a copy of this software and associated documentation -files (the "Software"), to deal in the Software without -restriction, including without limitation the rights to use, -copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the -Software is furnished to do so, subject to the following -conditions: - -The above copyright notice and this permission notice shall be -included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR -OTHER DEALINGS IN THE SOFTWARE. diff --git a/addons/web/tests/qunitsuite/grunt/phantomjs.json b/addons/web/tests/qunitsuite/grunt/phantomjs.json deleted file mode 100644 index 9e26dfeeb6e..00000000000 --- a/addons/web/tests/qunitsuite/grunt/phantomjs.json +++ /dev/null @@ -1 +0,0 @@ -{} \ No newline at end of file diff --git a/addons/web/tests/qunitsuite/grunt/qunit-phantomjs-bridge.js b/addons/web/tests/qunitsuite/grunt/qunit-phantomjs-bridge.js deleted file mode 100644 index 032fe8a3aa0..00000000000 --- a/addons/web/tests/qunitsuite/grunt/qunit-phantomjs-bridge.js +++ /dev/null @@ -1,88 +0,0 @@ -/* - * grunt - * http://gruntjs.com/ - * - * Copyright (c) 2012 "Cowboy" Ben Alman - * Licensed under the MIT license. - * http://benalman.com/about/license/ - */ - -/*global QUnit:true, alert:true*/ - -'use strict'; - -// Don't re-order tests. -QUnit.config.reorder = false; -// Run tests serially, not in parallel. -QUnit.config.autorun = false; - -// Send messages to the parent PhantomJS process via alert! Good times!! -function sendMessage() { - var args = [].slice.call(arguments); - alert(JSON.stringify(args)); -} - -// These methods connect QUnit to PhantomJS. -QUnit.log(function(obj) { - // What is this I don’t even - if (obj.message === '[object Object], undefined:undefined') { return; } - // Parse some stuff before sending it. - var actual = QUnit.jsDump.parse(obj.actual); - var expected = QUnit.jsDump.parse(obj.expected); - // Send it. - sendMessage('qunit.log', obj.result, actual, expected, obj.message, obj.source); -}); - -QUnit.testStart(function(obj) { - sendMessage('qunit.testStart', obj.name); -}); - -QUnit.testDone(function(obj) { - sendMessage('qunit.testDone', obj.name, obj.failed, obj.passed, obj.total); -}); - -QUnit.moduleStart(function(obj) { - sendMessage('qunit.moduleStart', obj.name); -}); - -QUnit.moduleDone(function(obj) { - sendMessage('qunit.moduleDone', obj.name, obj.failed, obj.passed, obj.total); -}); - -QUnit.begin(function() { - sendMessage('qunit.begin'); -}); - -QUnit.done(function(obj) { - sendMessage('qunit.done', obj.failed, obj.passed, obj.total, obj.runtime); -}); - -// PhantomJS (up to and including 1.7) uses a version of webkit so old -// it does not have Function.prototype.bind: -// http://code.google.com/p/phantomjs/issues/detail?id=522 - -// Use moz polyfill: -// https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Global_Objects/Function/bind#Compatibility -if (!Function.prototype.bind) { - Function.prototype.bind = function (oThis) { - if (typeof this !== "function") { - // closest thing possible to the ECMAScript 5 internal IsCallable function - throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable"); - } - - var aArgs = Array.prototype.slice.call(arguments, 1), - fToBind = this, - fNOP = function () {}, - fBound = function () { - return fToBind.apply(this instanceof fNOP && oThis - ? this - : oThis, - aArgs.concat(Array.prototype.slice.call(arguments))); - }; - - fNOP.prototype = this.prototype; - fBound.prototype = new fNOP(); - - return fBound; - }; -} diff --git a/addons/web/tests/qunitsuite/suite.py b/addons/web/tests/qunitsuite/suite.py deleted file mode 100644 index 54d2e18e36e..00000000000 --- a/addons/web/tests/qunitsuite/suite.py +++ /dev/null @@ -1,136 +0,0 @@ -import json -import subprocess -import unittest -import os -import time - -ROOT = os.path.join(os.path.dirname(__file__), 'grunt') - -__all__ = ['QUnitSuite'] - -def _exc_info_to_string(err, test): - return err - -class QUnitTest(unittest.TestCase): - def __init__(self, module, name): - self.module = module - self.name = name - self.failed = False - def shortDescription(self): - return None - def __repr__(self): - return '' % (self.module, self.name) - def __str__(self): - return '%s: %s' % (self.module, self.name) - -class QUnitSuite(unittest.TestSuite): - def __init__(self, qunitfile, timeout=5000): - super(QUnitSuite, self).__init__() - self.testfile = qunitfile - self.timeout = timeout - self._module = None - self._test = None - - def run(self, result): - try: - subprocess.call(['phantomjs', '-v'], - stdout=open(os.devnull, 'w'), - stderr=subprocess.STDOUT) - except OSError: - test = QUnitTest('phantomjs', 'javascript tests') - result.startTest(test) - result.startTest(test) - result.addSkip(test , "phantomjs command not found") - result.stopTest(test) - return - - result._exc_info_to_string = _exc_info_to_string - try: - self._run(result) - finally: - del result._exc_info_to_string - - def _run(self, result): - phantom = subprocess.Popen([ - 'phantomjs', - '--config=%s' % os.path.join(ROOT, 'phantomjs.json'), - os.path.join(ROOT, 'bootstrap.js'), self.testfile, - json.dumps({ - 'timeout': self.timeout, - 'inject': os.path.join(ROOT, 'qunit-phantomjs-bridge.js') - }) - ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - - try: - while True: - line = phantom.stdout.readline() - if line: - if self.process(line, result): - break - else: - time.sleep(0.1) - finally: - # If the phantomjs process hasn't quit, kill it - if phantom.poll() is None: - phantom.terminate() - - def process(self, line, result): - try: - args = json.loads(line) - except ValueError: # phantomjs stderr - if 'CoreText' not in line: - print line - return False - event_name = args[0] - - if event_name == 'qunit.done': - return True - elif event_name == 'fail.load': - self.add_error(result, "PhantomJS unable to load %s" % args[1]) - return True - elif event_name == 'fail.timeout': - self.add_error(result, "PhantomJS timed out, possibly due to a" - " missing QUnit start() call") - return True - - elif event_name == 'qunit.moduleStart': - self._module = args[1].encode('utf-8') if args[1] else '' - elif event_name == 'qunit.moduleStop': - self._test = None - self._module = None - elif event_name == 'qunit.testStart': - self._test = QUnitTest(self._module, args[1].encode('utf-8')) - result.startTest(self._test) - elif event_name == 'qunit.testDone': - if not self._test.failed: - result.addSuccess(self._test) - result.stopTest(self._test) - self._test = None - elif event_name == 'qunit.log': - if args[1]: - return False - - self._test.failed = True - result.addFailure( - self._test, self.failure_to_str(*args[2:])) - elif event_name == 'console': - print args[1] - - return False - - def add_error(self, result, s): - test = QUnitTest('phantomjs', 'startup') - result.startTest(test) - result.addError(test, s) - result.stopTest(test) - - def failure_to_str(self, actual, expected, message, source): - if message or actual == expected: - formatted = str(message or '') - else: - formatted = "%s != %s" % (actual, expected) - - if source: - formatted += '\n\n' + source - - return formatted diff --git a/addons/web/tests/test_js.py b/addons/web/tests/test_js.py index 0bab1de96a5..496d7e283bc 100644 --- a/addons/web/tests/test_js.py +++ b/addons/web/tests/test_js.py @@ -1,24 +1,6 @@ -import urllib -import urlparse -from openerp import sql_db, tools -from qunitsuite.suite import QUnitSuite +import openerp -class WebSuite(QUnitSuite): - def __init__(self, module): - url = urlparse.urlunsplit([ - 'http', - 'localhost:{port}'.format(port=tools.config['xmlrpc_port']), - '/web/tests', - urllib.urlencode({ - 'mod': module, - 'source': tools.config['db_name'], - 'supadmin': tools.config['admin_passwd'], - 'password': 'admin', - }), - '' - ]) - super(WebSuite, self).__init__(url, 50000) +class WebSuite(openerp.tests.HttpCase): + def test_01_js(self): + self.phantom_js('/web/tests?mod=web',"","", login='admin') -def load_tests(loader, standard_tests, _): - standard_tests.addTest(WebSuite('web')) - return standard_tests diff --git a/addons/web/views/webclient_templates.xml b/addons/web/views/webclient_templates.xml index 46bae5f83ca..2c3a16ac13f 100644 --- a/addons/web/views/webclient_templates.xml +++ b/addons/web/views/webclient_templates.xml @@ -3,6 +3,101 @@ --> + + + + +