[MERGE]Merge lp:~openerp-dev/openerp-web/trunk-improve-little-big-details.
bzr revid: vja@tinyerp.com-20121119125700-z5li5h7oo7237ify
@@ -1,19 +1,14 @@
|
||||
.*.swp
|
||||
.bzrignore
|
||||
.idea
|
||||
.project
|
||||
.pydevproject
|
||||
.ropeproject
|
||||
.settings
|
||||
.DS_Store
|
||||
openerp/addons/*
|
||||
openerp/filestore*
|
||||
.Python
|
||||
*.pyc
|
||||
*.pyo
|
||||
bin/*
|
||||
.*
|
||||
*.egg-info
|
||||
*.orig
|
||||
*.vim
|
||||
build/
|
||||
include/
|
||||
lib/
|
||||
share/
|
||||
doc/_build/*
|
||||
RE:^bin/
|
||||
RE:^dist/
|
||||
RE:^include/
|
||||
|
||||
RE:^share/
|
||||
RE:^man/
|
||||
RE:^lib/
|
||||
|
||||
RE:^addons/\w+/doc/_build/
|
||||
|
||||
@@ -41,6 +41,7 @@ This module provides the core of the OpenERP Web Client.
|
||||
"static/lib/cleditor/jquery.cleditor.js",
|
||||
"static/lib/py.js/lib/py.js",
|
||||
"static/src/js/boot.js",
|
||||
"static/src/js/testing.js",
|
||||
"static/src/js/corelib.js",
|
||||
"static/src/js/coresetup.js",
|
||||
"static/src/js/dates.js",
|
||||
@@ -68,5 +69,21 @@ This module provides the core of the OpenERP Web Client.
|
||||
'qweb' : [
|
||||
"static/src/xml/*.xml",
|
||||
],
|
||||
'test': [
|
||||
"static/test/testing.js",
|
||||
"static/test/class.js",
|
||||
"static/test/registry.js",
|
||||
"static/test/form.js",
|
||||
"static/test/list-utils.js",
|
||||
"static/test/formats.js",
|
||||
"static/test/rpc.js",
|
||||
"static/test/evals.js",
|
||||
"static/test/search.js",
|
||||
"static/test/Widget.js",
|
||||
"static/test/list.js",
|
||||
"static/test/list-editable.js",
|
||||
"static/test/mutex.js"
|
||||
],
|
||||
'bootstrap': True,
|
||||
'twitter': False,
|
||||
}
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
from . import main
|
||||
from . import testing
|
||||
|
||||
@@ -258,10 +258,16 @@ def concat_files(file_list, reader=None, intersperse=""):
|
||||
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=';')
|
||||
content = rjsmin(content)
|
||||
return content, checksum
|
||||
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"""
|
||||
@@ -786,6 +792,17 @@ class Database(openerpweb.Controller):
|
||||
params['db_original_name'],
|
||||
params['db_name'])
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def duplicate(self, req, fields):
|
||||
params = dict(map(operator.itemgetter('name', 'value'), fields))
|
||||
duplicate_attrs = (
|
||||
params['super_admin_pwd'],
|
||||
params['db_original_name'],
|
||||
params['db_name'],
|
||||
)
|
||||
|
||||
return req.session.proxy("db").duplicate_database(*duplicate_attrs)
|
||||
|
||||
@openerpweb.jsonrequest
|
||||
def drop(self, req, fields):
|
||||
password, db = operator.itemgetter(
|
||||
@@ -892,10 +909,7 @@ class Session(openerpweb.Controller):
|
||||
@openerpweb.jsonrequest
|
||||
def get_lang_list(self, req):
|
||||
try:
|
||||
return {
|
||||
'lang_list': (req.session.proxy("db").list_lang() or []),
|
||||
'error': ""
|
||||
}
|
||||
return req.session.proxy("db").list_lang() or []
|
||||
except Exception, e:
|
||||
return {"error": e, "title": "Languages"}
|
||||
|
||||
|
||||
@@ -0,0 +1,162 @@
|
||||
# coding=utf-8
|
||||
# -*- encoding: utf-8 -*-
|
||||
|
||||
import glob
|
||||
import itertools
|
||||
import json
|
||||
import operator
|
||||
import os
|
||||
|
||||
from mako.template import Template
|
||||
from openerp.modules import module
|
||||
|
||||
from .main import module_topological_sort
|
||||
from ..http import Controller, httprequest
|
||||
|
||||
NOMODULE_TEMPLATE = Template(u"""<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP Testing</title>
|
||||
</head>
|
||||
<body>
|
||||
<form action="/web/tests" method="GET">
|
||||
<button name="mod" value="*">Run all tests</button>
|
||||
<ul>
|
||||
% for name, module in modules:
|
||||
<li>${name} <button name="mod" value="${module}">
|
||||
Run Tests</button></li>
|
||||
% endfor
|
||||
</ul>
|
||||
</form>
|
||||
</body>
|
||||
</html>
|
||||
""")
|
||||
NOTFOUND = Template(u"""
|
||||
<p>Unable to find the module [${module}], please check that the module
|
||||
name is correct and the module is on OpenERP's path.</p>
|
||||
<a href="/web/tests"><< Back to tests</a>
|
||||
""")
|
||||
TESTING = Template(u"""<!DOCTYPE html>
|
||||
<html style="height: 100%">
|
||||
<%def name="to_path(module, p)">/${module}/${p}</%def>
|
||||
<head>
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge"/>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP Web Tests</title>
|
||||
<link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
|
||||
<link rel="stylesheet" href="/web/static/lib/qunit/qunit.css">
|
||||
<script src="/web/static/lib/qunit/qunit.js"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var oe_db_info = ${db_info};
|
||||
// List of modules, each module is preceded by its dependencies
|
||||
var oe_all_dependencies = ${dependencies};
|
||||
QUnit.config.testTimeout = 5 * 60 * 1000;
|
||||
</script>
|
||||
</head>
|
||||
<body id="oe" class="openerp">
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
% for module, jss, tests, templates in files:
|
||||
% for js in jss:
|
||||
<script src="${to_path(module, js)}"></script>
|
||||
% endfor
|
||||
% if tests or templates:
|
||||
<script>
|
||||
openerp.testing.current_module = "${module}";
|
||||
% for template in templates:
|
||||
openerp.testing.add_template("${to_path(module, template)}");
|
||||
% endfor
|
||||
</script>
|
||||
% endif
|
||||
% if tests:
|
||||
% for test in tests:
|
||||
<script type="text/javascript" src="${to_path(module, test)}"></script>
|
||||
% endfor
|
||||
% endif
|
||||
% endfor
|
||||
</html>
|
||||
""")
|
||||
|
||||
class TestRunnerController(Controller):
|
||||
_cp_path = '/web/tests'
|
||||
|
||||
@httprequest
|
||||
def index(self, req, 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 req.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)
|
||||
]
|
||||
|
||||
# if all three db_info parameters are present, send them to the page
|
||||
db_info = dict((k, v) for k, v in kwargs.iteritems()
|
||||
if k in ['source', 'supadmin', 'password'])
|
||||
if len(db_info) != 3:
|
||||
db_info = None
|
||||
|
||||
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']]), db_info=json.dumps(db_info))
|
||||
|
||||
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, '/')
|
||||
@@ -240,6 +240,103 @@ for instance (to take advantage of :js:func:`when` 's special
|
||||
treatment of single-value promises).
|
||||
|
||||
|
||||
jQuery.Deferred API
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. js:function:: when(deferreds…)
|
||||
|
||||
:param deferreds: deferred objects to multiplex
|
||||
:returns: a multiplexed deferred
|
||||
:rtype: :js:class:`Deferred`
|
||||
|
||||
.. js:class:: Deferred
|
||||
|
||||
.. js:function:: Deferred.then(doneCallback[, failCallback])
|
||||
|
||||
Attaches new callbacks to the resolution or rejection of the
|
||||
deferred object. Callbacks are executed in the order they are
|
||||
attached to the deferred.
|
||||
|
||||
To provide only a failure callback, pass ``null`` as the
|
||||
``doneCallback``, to provide only a success callback the
|
||||
second argument can just be ignored (and not passed at all).
|
||||
|
||||
Returns a new deferred which resolves to the result of the
|
||||
corresponding callback, if a callback returns a deferred
|
||||
itself that new deferred will be used as the resolution of the
|
||||
chain.
|
||||
|
||||
:param doneCallback: function called when the deferred is resolved
|
||||
:type doneCallback: Function
|
||||
:param failCallback: function called when the deferred is rejected
|
||||
:type failCallback: Function
|
||||
:returns: the deferred object on which it was called
|
||||
:rtype: :js:class:`Deferred`
|
||||
|
||||
.. js:function:: Deferred.done(doneCallback)
|
||||
|
||||
Attaches a new success callback to the deferred, shortcut for
|
||||
``deferred.then(doneCallback)``.
|
||||
|
||||
This is a jQuery extension to `CommonJS Promises/A`_ providing
|
||||
little value over calling :js:func:`~Deferred.then` directly,
|
||||
it should be avoided.
|
||||
|
||||
:param doneCallback: function called when the deferred is resolved
|
||||
:type doneCallback: Function
|
||||
:returns: the deferred object on which it was called
|
||||
:rtype: :js:class:`Deferred`
|
||||
|
||||
.. js:function:: Deferred.fail(failCallback)
|
||||
|
||||
Attaches a new failure callback to the deferred, shortcut for
|
||||
``deferred.then(null, failCallback)``.
|
||||
|
||||
A second jQuery extension to `Promises/A <CommonJS
|
||||
Promises/A>`_. Although it provides more value than
|
||||
:js:func:`~Deferred.done`, it still is not much and should be
|
||||
avoided as well.
|
||||
|
||||
:param failCallback: function called when the deferred is rejected
|
||||
:type failCallback: Function
|
||||
:returns: the deferred object on which it was called
|
||||
:rtype: :js:class:`Deferred`
|
||||
|
||||
.. js:function:: Deferred.promise()
|
||||
|
||||
Returns a read-only view of the deferred object, with all
|
||||
mutators (resolve and reject) methods removed.
|
||||
|
||||
.. js:function:: Deferred.resolve(value…)
|
||||
|
||||
Called to resolve a deferred, any value provided will be
|
||||
passed onto the success handlers of the deferred object.
|
||||
|
||||
Resolving a deferred which has already been resolved or
|
||||
rejected has no effect.
|
||||
|
||||
.. js:function:: Deferred.reject(value…)
|
||||
|
||||
Called to reject (fail) a deferred, any value provided will be
|
||||
passed onto the failure handler of the deferred object.
|
||||
|
||||
Rejecting a deferred which has already been resolved or
|
||||
rejected has no effect.
|
||||
|
||||
.. [#] or simply calling :js:class:`Deferred` as a function, the
|
||||
result is the same
|
||||
|
||||
.. [#] or not-promises, the `CommonJS Promises/B`_ role of
|
||||
:js:func:`when` is to be able to treat values and promises
|
||||
uniformly: :js:func:`when` will pass promises through directly,
|
||||
but non-promise values and objects will be transformed into a
|
||||
resolved promise (resolving themselves with the value itself).
|
||||
|
||||
jQuery's :js:func:`when` keeps this behavior making deferreds
|
||||
easy to build from "static" values, or allowing defensive code
|
||||
where expected promises are wrapped in :js:func:`when` just in
|
||||
case.
|
||||
|
||||
.. _promises: http://en.wikipedia.org/wiki/Promise_(programming)
|
||||
.. _jQuery's deferred: http://api.jquery.com/category/deferred-object/
|
||||
.. _CommonJS Promises/A: http://wiki.commonjs.org/wiki/Promises/A
|
||||
|
||||
@@ -16,10 +16,9 @@ import sys, os
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
sys.path.append(os.path.abspath('_themes'))
|
||||
sys.path.append(os.path.abspath('..'))
|
||||
sys.path.append(os.path.abspath('../openerp'))
|
||||
sys.path.insert(0, os.path.abspath('../addons'))
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# -- General configuration -----------------------------------------------------
|
||||
|
||||
@@ -43,7 +42,7 @@ source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'OpenERP Server Developers Documentation'
|
||||
project = u'OpenERP Web Developers Documentation'
|
||||
copyright = u'2012, OpenERP s.a.'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
@@ -53,7 +52,7 @@ copyright = u'2012, OpenERP s.a.'
|
||||
# The short X.Y version.
|
||||
version = '7.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '7.0b'
|
||||
release = '7.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
@@ -171,7 +170,7 @@ html_sidebars = {
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'openerp-server-doc'
|
||||
htmlhelp_basename = 'openerp-web-doc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output --------------------------------------------------
|
||||
@@ -190,7 +189,7 @@ latex_elements = {
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, documentclass [howto/manual]).
|
||||
latex_documents = [
|
||||
('index', 'openerp-server-doc.tex', u'OpenERP Server Developers Documentation',
|
||||
('index', 'openerp-web-doc.tex', u'OpenERP Web Developers Documentation',
|
||||
u'OpenERP s.a.', 'manual'),
|
||||
]
|
||||
|
||||
@@ -220,7 +219,7 @@ latex_documents = [
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'openerp-server-doc', u'OpenERP Server Developers Documentation',
|
||||
('index', 'openerp-web-doc', u'OpenERP Web Developers Documentation',
|
||||
[u'OpenERP s.a.'], 1)
|
||||
]
|
||||
|
||||
@@ -234,8 +233,8 @@ man_pages = [
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'OpenERPServerDocumentation', u'OpenERP Server Developers Documentation',
|
||||
u'OpenERP s.a.', 'OpenERPServerDocumentation', 'Developers documentation for the openobject-server project.',
|
||||
('index', 'OpenERPWebDocumentation', u'OpenERP Web Developers Documentation',
|
||||
u'OpenERP s.a.', 'OpenERPWebDocumentation', 'Developers documentation for the openerp-web project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
@@ -248,10 +247,12 @@ texinfo_documents = [
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
todo_include_todos = True
|
||||
|
||||
# Example configuration for intersphinx: refer to the Python standard library.
|
||||
intersphinx_mapping = {
|
||||
'python': ('http://docs.python.org/', None),
|
||||
'openerpweb': ('http://doc.openerp.com/trunk/developers/web', None),
|
||||
'openerpserver': ('http://doc.openerp.com/trunk/developers/server', None),
|
||||
'openerpdev': ('http://doc.openerp.com/trunk/developers', None),
|
||||
'openerpcommand': ('http://doc.openerp.com/trunk/developers/command', None),
|
||||
}
|
||||
|
||||
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 6.6 KiB |
|
After Width: | Height: | Size: 64 KiB |
|
After Width: | Height: | Size: 20 KiB |
|
After Width: | Height: | Size: 20 KiB |
@@ -14,6 +14,8 @@ Contents:
|
||||
presentation
|
||||
async
|
||||
|
||||
testing
|
||||
|
||||
widget
|
||||
qweb
|
||||
rpc
|
||||
@@ -24,7 +26,6 @@ Contents:
|
||||
|
||||
changelog-7.0
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
test_empty_find (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok
|
||||
test_ids_shortcut (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok
|
||||
test_regular_find (openerp.addons.web.tests.test_dataset.TestDataSetController) ... ok
|
||||
web.testing.stack: direct, value, success ... ok
|
||||
web.testing.stack: direct, deferred, success ... ok
|
||||
web.testing.stack: direct, value, error ... ok
|
||||
web.testing.stack: direct, deferred, failure ... ok
|
||||
web.testing.stack: successful setup ... ok
|
||||
web.testing.stack: successful teardown ... ok
|
||||
web.testing.stack: successful setup and teardown ... ok
|
||||
|
||||
[snip ~150 lines]
|
||||
|
||||
test_convert_complex_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
|
||||
test_convert_complex_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
|
||||
test_convert_literal_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
|
||||
test_convert_literal_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
|
||||
test_retrieve_nonliteral_context (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
|
||||
test_retrieve_nonliteral_domain (openerp.addons.web.tests.test_view.DomainsAndContextsTest) ... ok
|
||||
|
||||
----------------------------------------------------------------------
|
||||
Ran 181 tests in 15.706s
|
||||
|
||||
OK
|
||||
|
||||
@@ -0,0 +1,693 @@
|
||||
.. highlight:: javascript
|
||||
|
||||
Testing in OpenERP Web
|
||||
======================
|
||||
|
||||
Javascript Unit Testing
|
||||
-----------------------
|
||||
|
||||
OpenERP Web 7.0 includes means to unit-test both the core code of
|
||||
OpenERP Web and your own javascript modules. On the javascript side,
|
||||
unit-testing is based on QUnit_ with a number of helpers and
|
||||
extensions for better integration with OpenERP.
|
||||
|
||||
To see what the runner looks like, find (or start) an OpenERP server
|
||||
with the web client enabled, and navigate to ``/web/tests`` e.g. `on
|
||||
OpenERP's CI <http://trunk.runbot.openerp.com/web/tests>`_. This will
|
||||
show the runner selector, which lists all modules with javascript unit
|
||||
tests, and allows starting any of them (or all javascript tests in all
|
||||
modules at once).
|
||||
|
||||
.. image:: ./images/runner.png
|
||||
:align: center
|
||||
|
||||
Clicking any runner button will launch the corresponding tests in the
|
||||
bundled QUnit_ runner:
|
||||
|
||||
.. image:: ./images/tests.png
|
||||
:align: center
|
||||
|
||||
Writing a test case
|
||||
-------------------
|
||||
|
||||
The first step is to list the test file(s). This is done through the
|
||||
``test`` key of the openerp manifest, by adding javascript files to it
|
||||
(next to the usual YAML files, if any):
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
'name': "Demonstration of web/javascript tests",
|
||||
'category': 'Hidden',
|
||||
'depends': ['web'],
|
||||
'test': ['static/test/demo.js'],
|
||||
}
|
||||
|
||||
and to create the corresponding test file(s)
|
||||
|
||||
.. note::
|
||||
|
||||
Test files which do not exist will be ignored, if all test files
|
||||
of a module are ignored (can not be found), the test runner will
|
||||
consider that the module has no javascript tests.
|
||||
|
||||
After that, refreshing the runner selector will display the new module
|
||||
and allow running all of its (0 so far) tests:
|
||||
|
||||
.. image:: ./images/runner2.png
|
||||
:align: center
|
||||
|
||||
The next step is to create a test case::
|
||||
|
||||
openerp.testing.section('basic section', function (test) {
|
||||
test('my first test', function () {
|
||||
ok(false, "this test has run");
|
||||
});
|
||||
});
|
||||
|
||||
All testing helpers and structures live in the ``openerp.testing``
|
||||
module. OpenERP tests live in a :js:func:`~openerp.testing.section`,
|
||||
which is itself part of a module. The first argument to a section is
|
||||
the name of the section, the second one is the section body.
|
||||
|
||||
:js:func:`test <openerp.testing.case>`, provided by the
|
||||
:js:func:`~openerp.testing.section` to the callback, is used to
|
||||
register a given test case which will be run whenever the test runner
|
||||
actually does its job. OpenERP Web test case use standard `QUnit
|
||||
assertions`_ within them.
|
||||
|
||||
Launching the test runner at this point will run the test and display
|
||||
the corresponding assertion message, with red colors indicating the
|
||||
test failed:
|
||||
|
||||
.. image:: ./images/tests2.png
|
||||
:align: center
|
||||
|
||||
Fixing the test (by replacing ``false`` to ``true`` in the assertion)
|
||||
will make it pass:
|
||||
|
||||
.. image:: ./images/tests3.png
|
||||
:align: center
|
||||
|
||||
Assertions
|
||||
----------
|
||||
|
||||
As noted above, OpenERP Web's tests use `qunit assertions`_. They are
|
||||
available globally (so they can just be called without references to
|
||||
anything). The following list is available:
|
||||
|
||||
.. js:function:: ok(state[, message])
|
||||
|
||||
checks that ``state`` is truthy (in the javascript sense)
|
||||
|
||||
.. js:function:: strictEqual(actual, expected[, message])
|
||||
|
||||
checks that the actual (produced by a method being tested) and
|
||||
expected values are identical (roughly equivalent to ``ok(actual
|
||||
=== expected, message)``)
|
||||
|
||||
.. js:function:: notStrictEqual(actual, expected[, message])
|
||||
|
||||
checks that the actual and expected values are *not* identical
|
||||
(roughly equivalent to ``ok(actual !== expected, message)``)
|
||||
|
||||
.. js:function:: deepEqual(actual, expected[, message])
|
||||
|
||||
deep comparison between actual and expected: recurse into
|
||||
containers (objects and arrays) to ensure that they have the same
|
||||
keys/number of elements, and the values match.
|
||||
|
||||
.. js:function:: notDeepEqual(actual, expected[, message])
|
||||
|
||||
inverse operation to :js:func:`deepEqual`
|
||||
|
||||
.. js:function:: throws(block[, expected][, message])
|
||||
|
||||
checks that, when called, the ``block`` throws an
|
||||
error. Optionally validates that error against ``expected``.
|
||||
|
||||
:param Function block:
|
||||
:param expected: if a regexp, checks that the thrown error's
|
||||
message matches the regular expression. If an
|
||||
error type, checks that the thrown error is of
|
||||
that type.
|
||||
:type expected: Error | RegExp
|
||||
|
||||
.. js:function:: equal(actual, expected[, message])
|
||||
|
||||
checks that ``actual`` and ``expected`` are loosely equal, using
|
||||
the ``==`` operator and its coercion rules.
|
||||
|
||||
.. js:function:: notEqual(actual, expected[, message])
|
||||
|
||||
inverse operation to :js:func:`equal`
|
||||
|
||||
Getting an OpenERP instance
|
||||
---------------------------
|
||||
|
||||
The OpenERP instance is the base through which most OpenERP Web
|
||||
modules behaviors (functions, objects, …) are accessed. As a result,
|
||||
the test framework automatically builds one, and loads the module
|
||||
being tested and all of its dependencies inside it. This new instance
|
||||
is provided as the first positional parameter to your test
|
||||
cases. Let's observe by adding javascript code (not test code) to the
|
||||
test module:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
'name': "Demonstration of web/javascript tests",
|
||||
'category': 'Hidden',
|
||||
'depends': ['web'],
|
||||
'js': ['static/src/js/demo.js'],
|
||||
'test': ['static/test/demo.js'],
|
||||
}
|
||||
|
||||
::
|
||||
|
||||
// src/js/demo.js
|
||||
openerp.web_tests_demo = function (instance) {
|
||||
instance.web_tests_demo = {
|
||||
value_true: true,
|
||||
SomeType: instance.web.Class.extend({
|
||||
init: function (value) {
|
||||
this.value = value;
|
||||
}
|
||||
})
|
||||
};
|
||||
};
|
||||
|
||||
and then adding a new test case, which simply checks that the
|
||||
``instance`` contains all the expected stuff we created in the
|
||||
module::
|
||||
|
||||
// test/demo.js
|
||||
test('module content', function (instance) {
|
||||
ok(instance.web_tests_demo.value_true, "should have a true value");
|
||||
var type_instance = new instance.web_tests_demo.SomeType(42);
|
||||
strictEqual(type_instance.value, 42, "should have provided value");
|
||||
});
|
||||
|
||||
DOM Scratchpad
|
||||
--------------
|
||||
|
||||
As in the wider client, arbitrarily accessing document content is
|
||||
strongly discouraged during tests. But DOM access is still needed to
|
||||
e.g. fully initialize :js:class:`widgets <~openerp.web.Widget>` before
|
||||
testing them.
|
||||
|
||||
Thus, a test case gets a DOM scratchpad as its second positional
|
||||
parameter, in a jQuery instance. That scratchpad is fully cleaned up
|
||||
before each test, and as long as it doesn't do anything outside the
|
||||
scratchpad your code can do whatever it wants::
|
||||
|
||||
// test/demo.js
|
||||
test('DOM content', function (instance, $scratchpad) {
|
||||
$scratchpad.html('<div><span class="foo bar">ok</span></div>');
|
||||
ok($scratchpad.find('span').hasClass('foo'),
|
||||
"should have provided class");
|
||||
});
|
||||
test('clean scratchpad', function (instance, $scratchpad) {
|
||||
ok(!$scratchpad.children().length, "should have no content");
|
||||
ok(!$scratchpad.text(), "should have no text");
|
||||
});
|
||||
|
||||
.. note::
|
||||
|
||||
The top-level element of the scratchpad is not cleaned up, test
|
||||
cases can add text or DOM children but shoud not alter
|
||||
``$scratchpad`` itself.
|
||||
|
||||
Loading templates
|
||||
-----------------
|
||||
|
||||
To avoid the corresponding processing costs, by default templates are
|
||||
not loaded into QWeb. If you need to render e.g. widgets making use of
|
||||
QWeb templates, you can request their loading through the
|
||||
:js:attr:`~TestOptions.templates` option to the :js:func:`test case
|
||||
function <openerp.testing.case>`.
|
||||
|
||||
This will automatically load all relevant templates in the instance's
|
||||
qweb before running the test case:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
{
|
||||
'name': "Demonstration of web/javascript tests",
|
||||
'category': 'Hidden',
|
||||
'depends': ['web'],
|
||||
'js': ['static/src/js/demo.js'],
|
||||
'test': ['static/test/demo.js'],
|
||||
'qweb': ['static/src/xml/demo.xml'],
|
||||
}
|
||||
|
||||
.. code-block:: xml
|
||||
|
||||
<!-- src/xml/demo.xml -->
|
||||
<templates id="template" xml:space="preserve">
|
||||
<t t-name="DemoTemplate">
|
||||
<t t-foreach="5" t-as="value">
|
||||
<p><t t-esc="value"/></p>
|
||||
</t>
|
||||
</t>
|
||||
</templates>
|
||||
|
||||
::
|
||||
|
||||
// test/demo.js
|
||||
test('templates', {templates: true}, function (instance) {
|
||||
var s = instance.web.qweb.render('DemoTemplate');
|
||||
var texts = $(s).find('p').map(function () {
|
||||
return $(this).text();
|
||||
}).get();
|
||||
|
||||
deepEqual(texts, ['0', '1', '2', '3', '4']);
|
||||
});
|
||||
|
||||
Asynchronous cases
|
||||
------------------
|
||||
|
||||
The test case examples so far are all synchronous, they execute from
|
||||
the first to the last line and once the last line has executed the
|
||||
test is done. But the web client is full of :doc:`asynchronous code
|
||||
</async>`, and thus test cases need to be async-aware.
|
||||
|
||||
This is done by returning a :js:class:`deferred <Deferred>` from the
|
||||
case callback::
|
||||
|
||||
// test/demo.js
|
||||
test('asynchronous', {
|
||||
asserts: 1
|
||||
}, function () {
|
||||
var d = $.Deferred();
|
||||
setTimeout(function () {
|
||||
ok(true);
|
||||
d.resolve();
|
||||
}, 100);
|
||||
return d;
|
||||
});
|
||||
|
||||
This example also uses the :js:class:`options parameter <TestOptions>`
|
||||
to specify the number of assertions the case should expect, if less or
|
||||
more assertions are specified the case will count as failed.
|
||||
|
||||
Asynchronous test cases *must* specify the number of assertions they
|
||||
will run. This allows more easily catching situations where e.g. the
|
||||
test architecture was not warned about asynchronous operations.
|
||||
|
||||
.. note::
|
||||
|
||||
Asynchronous test cases also have a 2 seconds timeout: if the test
|
||||
does not finish within 2 seconds, it will be considered
|
||||
failed. This pretty much always means the test will not
|
||||
resolve. This timeout *only* applies to the test itself, not to
|
||||
the setup and teardown processes.
|
||||
|
||||
.. note::
|
||||
|
||||
If the returned deferred is rejected, the test will be failed
|
||||
unless :js:attr:`~TestOptions.fail_on_rejection` is set to
|
||||
``false``.
|
||||
|
||||
RPC
|
||||
---
|
||||
|
||||
An important subset of asynchronous test cases is test cases which
|
||||
need to perform (and chain, to an extent) RPC calls.
|
||||
|
||||
.. note::
|
||||
|
||||
Because they are a subset of asynchronous cases, RPC cases must
|
||||
also provide a valid :js:attr:`assertions count
|
||||
<TestOptions.asserts>`.
|
||||
|
||||
By default, test cases will fail when trying to perform an RPC
|
||||
call. The ability to perform RPC calls must be explicitly requested by
|
||||
a test case (or its containing test suite) through
|
||||
:js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or
|
||||
``rpc``.
|
||||
|
||||
Mock RPC
|
||||
++++++++
|
||||
|
||||
The preferred (and fastest from a setup and execution time point of
|
||||
view) way to do RPC during tests is to mock the RPC calls: while
|
||||
setting up the test case, provide what the RPC responses "should" be,
|
||||
and only test the code between the "user" (the test itself) and the
|
||||
RPC call, before the call is effectively done.
|
||||
|
||||
To do this, set the :js:attr:`rpc option <TestOptions.rpc>` to
|
||||
``mock``. This will add a third parameter to the test case callback:
|
||||
|
||||
.. js:function:: mock(rpc_spec, handler)
|
||||
|
||||
Can be used in two different ways depending on the shape of the
|
||||
first parameter:
|
||||
|
||||
* If it matches the pattern ``model:method`` (if it contains a
|
||||
colon, essentially) the call will set up the mocking of an RPC
|
||||
call straight to the OpenERP server (through XMLRPC) as
|
||||
performed via e.g. :js:func:`openerp.web.Model.call`.
|
||||
|
||||
In that case, ``handler`` should be a function taking two
|
||||
arguments ``args`` and ``kwargs``, matching the corresponding
|
||||
arguments on the server side and should simply return the value
|
||||
as if it were returned by the Python XMLRPC handler::
|
||||
|
||||
test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) {
|
||||
// set up mocking
|
||||
mock('people.famous:name_search', function (args, kwargs) {
|
||||
strictEqual(kwargs.name, 'bob');
|
||||
return [
|
||||
[1, "Microsoft Bob"],
|
||||
[2, "Bob the Builder"],
|
||||
[3, "Silent Bob"]
|
||||
];
|
||||
});
|
||||
|
||||
// actual test code
|
||||
return new instance.web.Model('people.famous')
|
||||
.call('name_search', {name: 'bob'}).then(function (result) {
|
||||
strictEqual(result.length, 3, "shoud return 3 people");
|
||||
strictEqual(result[0][1], "Microsoft Bob",
|
||||
"the most famous bob should be Microsoft Bob");
|
||||
});
|
||||
});
|
||||
|
||||
* Otherwise, if it matches an absolute path (e.g. ``/a/b/c``) it
|
||||
will mock a JSON-RPC call to a web client controller, such as
|
||||
``/web/webclient/translations``. In that case, the handler takes
|
||||
a single ``params`` argument holding all of the parameters
|
||||
provided over JSON-RPC.
|
||||
|
||||
As previously, the handler should simply return the result value
|
||||
as if returned by the original JSON-RPC handler::
|
||||
|
||||
test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) {
|
||||
var fetched_dbs = false, fetched_langs = false;
|
||||
mock('/web/database/get_list', function () {
|
||||
fetched_dbs = true;
|
||||
return ['foo', 'bar', 'baz'];
|
||||
});
|
||||
mock('/web/session/get_lang_list', function () {
|
||||
fetched_langs = true;
|
||||
return [['vo_IS', 'Hopelandic / Vonlenska']];
|
||||
});
|
||||
|
||||
// widget needs that or it blows up
|
||||
instance.webclient = {toggle_bars: openerp.testing.noop};
|
||||
var dbm = new instance.web.DatabaseManager({});
|
||||
return dbm.appendTo($s).then(function () {
|
||||
ok(fetched_dbs, "should have fetched databases");
|
||||
ok(fetched_langs, "should have fetched languages");
|
||||
deepEqual(dbm.db_list, ['foo', 'bar', 'baz']);
|
||||
});
|
||||
});
|
||||
|
||||
.. note::
|
||||
|
||||
Mock handlers can contain assertions, these assertions should be
|
||||
part of the assertions count (and if multiple calls are made to a
|
||||
handler containing assertions, it multiplies the effective number
|
||||
of assertions).
|
||||
|
||||
.. _testing-rpc-rpc:
|
||||
|
||||
Actual RPC
|
||||
++++++++++
|
||||
|
||||
A more realistic (but significantly slower and more expensive) way to
|
||||
perform RPC calls is to perform actual calls to an actually running
|
||||
OpenERP server. To do this, set the :js:attr:`rpc option
|
||||
<~TestOptions.rpc>` to ``rpc``, it will not provide any new parameter
|
||||
but will enable actual RPC, and the automatic creation and destruction
|
||||
of databases (from a specified source) around tests.
|
||||
|
||||
First, create a basic model we can test stuff with:
|
||||
|
||||
.. code-block:: javascript
|
||||
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
class TestObject(orm.Model):
|
||||
_name = 'web_tests_demo.model'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char("Name", required=True),
|
||||
'thing': fields.char("Thing"),
|
||||
'other': fields.char("Other", required=True)
|
||||
}
|
||||
_defaults = {
|
||||
'other': "bob"
|
||||
}
|
||||
|
||||
then the actual test::
|
||||
|
||||
test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) {
|
||||
var Model = new instance.web.Model('web_tests_demo.model');
|
||||
return Model.call('create', [{name: "Bob"}])
|
||||
.then(function (id) {
|
||||
return Model.call('read', [[id]]);
|
||||
}).then(function (records) {
|
||||
strictEqual(records.length, 1);
|
||||
var record = records[0];
|
||||
strictEqual(record.name, "Bob");
|
||||
strictEqual(record.thing, false);
|
||||
// default value
|
||||
strictEqual(record.other, 'bob');
|
||||
});
|
||||
});
|
||||
|
||||
This test looks like a "mock" RPC test but for the lack of mock
|
||||
response (and the different ``rpc`` type), however it has further
|
||||
ranging consequences in that it will copy an existing database to a
|
||||
new one, run the test in full on that temporary database and destroy
|
||||
the database, to simulate an isolated and transactional context and
|
||||
avoid affecting other tests. One of the consequences is that it takes
|
||||
a *long* time to run (5~10s, most of that time being spent waiting for
|
||||
a database duplication).
|
||||
|
||||
Furthermore, as the test needs to clone a database, it also has to ask
|
||||
which database to clone, the database/super-admin password and the
|
||||
password of the ``admin`` user (in order to authenticate as said
|
||||
user). As a result, the first time the test runner encounters an
|
||||
``rpc: "rpc"`` test configuration it will produce the following
|
||||
prompt:
|
||||
|
||||
.. image:: ./images/db-query.png
|
||||
:align: center
|
||||
|
||||
and stop the testing process until the necessary information has been
|
||||
provided.
|
||||
|
||||
The prompt will only appear once per test run, all tests will use the
|
||||
same "source" database.
|
||||
|
||||
.. note::
|
||||
|
||||
The handling of that information is currently rather brittle and
|
||||
unchecked, incorrect values will likely crash the runner.
|
||||
|
||||
.. note::
|
||||
|
||||
The runner does not currently store this information (for any
|
||||
longer than a test run that is), the prompt will have to be filled
|
||||
every time.
|
||||
|
||||
Testing API
|
||||
-----------
|
||||
|
||||
.. js:function:: openerp.testing.section(name[, options], body)
|
||||
|
||||
A test section, serves as shared namespace for related tests (for
|
||||
constants or values to only set up once). The ``body`` function
|
||||
should contain the tests themselves.
|
||||
|
||||
Note that the order in which tests are run is essentially
|
||||
undefined, do *not* rely on it.
|
||||
|
||||
:param String name:
|
||||
:param TestOptions options:
|
||||
:param body:
|
||||
:type body: Function<:js:func:`~openerp.testing.case`, void>
|
||||
|
||||
.. js:function:: openerp.testing.case(name[, options], callback)
|
||||
|
||||
Registers a test case callback in the test runner, the callback
|
||||
will only be run once the runner is started (or maybe not at all,
|
||||
if the test is filtered out).
|
||||
|
||||
:param String name:
|
||||
:param TestOptions options:
|
||||
:param callback:
|
||||
:type callback: Function<instance, $, Function<String, Function, void>>
|
||||
|
||||
.. js:class:: TestOptions
|
||||
|
||||
the various options which can be passed to
|
||||
:js:func:`~openerp.testing.section` or
|
||||
:js:func:`~openerp.testing.case`. Except for
|
||||
:js:attr:`~TestOptions.setup` and
|
||||
:js:attr:`~TestOptions.teardown`, an option on
|
||||
:js:func:`~openerp.testing.case` will overwrite the corresponding
|
||||
option on :js:func:`~openerp.testing.section` so
|
||||
e.g. :js:attr:`~TestOptions.rpc` can be set for a
|
||||
:js:func:`~openerp.testing.section` and then differently set for
|
||||
some :js:func:`~openerp.testing.case` of that
|
||||
:js:func:`~openerp.testing.section`
|
||||
|
||||
.. js:attribute:: TestOptions.asserts
|
||||
|
||||
An integer, the number of assertions which should run during a
|
||||
normal execution of the test. Mandatory for asynchronous tests.
|
||||
|
||||
.. js:attribute:: TestOptions.setup
|
||||
|
||||
Test case setup, run right before each test case. A section's
|
||||
:js:func:`~TestOptions.setup` is run before the case's own, if
|
||||
both are specified.
|
||||
|
||||
.. js:attribute:: TestOptions.teardown
|
||||
|
||||
Test case teardown, a case's :js:func:`~TestOptions.teardown`
|
||||
is run before the corresponding section if both are present.
|
||||
|
||||
.. js:attribute:: TestOptions.fail_on_rejection
|
||||
|
||||
If the test is asynchronous and its resulting promise is
|
||||
rejected, fail the test. Defaults to ``true``, set to
|
||||
``false`` to not fail the test in case of rejection::
|
||||
|
||||
// test/demo.js
|
||||
test('unfail rejection', {
|
||||
asserts: 1,
|
||||
fail_on_rejection: false
|
||||
}, function () {
|
||||
var d = $.Deferred();
|
||||
setTimeout(function () {
|
||||
ok(true);
|
||||
d.reject();
|
||||
}, 100);
|
||||
return d;
|
||||
});
|
||||
|
||||
.. js:attribute:: TestOptions.rpc
|
||||
|
||||
RPC method to use during tests, one of ``"mock"`` or
|
||||
``"rpc"``. Any other value will disable RPC for the test (if
|
||||
they were enabled by the suite for instance).
|
||||
|
||||
.. js:attribute:: TestOptions.templates
|
||||
|
||||
Whether the current module (and its dependencies)'s templates
|
||||
should be loaded into QWeb before starting the test. A
|
||||
boolean, ``false`` by default.
|
||||
|
||||
The test runner can also use two global configuration values set
|
||||
directly on the ``window`` object:
|
||||
|
||||
* ``oe_all_dependencies`` is an ``Array`` of all modules with a web
|
||||
component, ordered by dependency (for a module ``A`` with
|
||||
dependencies ``A'``, any module of ``A'`` must come before ``A`` in
|
||||
the array)
|
||||
|
||||
* ``oe_db_info`` is an object with 3 keys ``source``, ``supadmin`` and
|
||||
``password``. It is used to pre-configure :ref:`actual RPC
|
||||
<testing-rpc-rpc>` tests, to avoid a prompt being displayed
|
||||
(especially for headless situations).
|
||||
|
||||
Running through Python
|
||||
----------------------
|
||||
|
||||
The web client includes the means to run these tests on the
|
||||
command-line (or in a CI system), but while actually running it is
|
||||
pretty simple the setup of the pre-requisite parts has some
|
||||
complexities.
|
||||
|
||||
1. Install unittest2_ and QUnitSuite_ in your Python environment. Both
|
||||
can trivially be installed via `pip <http://pip-installer.org>`_ or
|
||||
`easy_install
|
||||
<http://packages.python.org/distribute/easy_install.html>`_.
|
||||
|
||||
The former is the unit-testing framework used by OpenERP, the
|
||||
latter is an adapter module to run qunit_ test suites and convert
|
||||
their result into something unittest2_ can understand and report.
|
||||
|
||||
2. Install PhantomJS_. It is a headless
|
||||
browser which allows automating running and testing web
|
||||
pages. QUnitSuite_ uses it to actually run the qunit_ test suite.
|
||||
|
||||
The PhantomJS_ website provides pre-built binaries for some
|
||||
platforms, and your OS's package management probably provides it as
|
||||
well.
|
||||
|
||||
If you're building PhantomJS_ from source, I recommend preparing
|
||||
for some knitting time as it's not exactly fast (it needs to
|
||||
compile both `Qt <http://qt-project.org/>`_ and `Webkit
|
||||
<http://www.webkit.org/>`_, both being pretty big projects).
|
||||
|
||||
.. note::
|
||||
|
||||
Because PhantomJS_ is webkit-based, it will not be able to test
|
||||
if Firefox, Opera or Internet Explorer can correctly run the
|
||||
test suite (and it is only an approximation for Safari and
|
||||
Chrome). It is therefore recommended to *also* run the test
|
||||
suites in actual browsers once in a while.
|
||||
|
||||
.. note::
|
||||
|
||||
The version of PhantomJS_ this was build through is 1.7,
|
||||
previous versions *should* work but are not actually supported
|
||||
(and tend to just segfault when something goes wrong in
|
||||
PhantomJS_ itself so they're a pain to debug).
|
||||
|
||||
3. Set up :ref:`OpenERP Command <openerpcommand:openerp-command>`,
|
||||
which will be used to actually run the tests: running the qunit_
|
||||
test suite requires a running server, so at this point OpenERP
|
||||
Server isn't able to do it on its own during the building/testing
|
||||
process.
|
||||
|
||||
4. Install a new database with all relevant modules (all modules with
|
||||
a web component at least), then restart the server
|
||||
|
||||
.. note::
|
||||
|
||||
For some tests, a source database needs to be duplicated. This
|
||||
operation requires that there be no connection to the database
|
||||
being duplicated, but OpenERP doesn't currently break
|
||||
existing/outstanding connections, so restarting the server is
|
||||
the simplest way to ensure everything is in the right state.
|
||||
|
||||
5. Launch ``oe run-tests -d $DATABASE -mweb`` with the correct
|
||||
addons-path specified (and replacing ``$DATABASE`` by the source
|
||||
database you created above)
|
||||
|
||||
.. note::
|
||||
|
||||
If you leave out ``-mweb``, the runner will attempt to run all
|
||||
the tests in all the modules, which may or may not work.
|
||||
|
||||
If everything went correctly, you should now see a list of tests with
|
||||
(hopefully) ``ok`` next to their names, closing with a report of the
|
||||
number of tests run and the time it took:
|
||||
|
||||
.. literalinclude:: test-report.txt
|
||||
:language: text
|
||||
|
||||
Congratulation, you have just performed a successful "offline" run of
|
||||
the OpenERP Web test suite.
|
||||
|
||||
.. note::
|
||||
|
||||
Note that this runs all the Python tests for the ``web`` module,
|
||||
but all the web tests for all of OpenERP. This can be surprising.
|
||||
|
||||
.. _qunit: http://qunitjs.com/
|
||||
|
||||
.. _qunit assertions: http://api.qunitjs.com/category/assert/
|
||||
|
||||
.. _unittest2: http://pypi.python.org/pypi/unittest2
|
||||
|
||||
.. _QUnitSuite: http://pypi.python.org/pypi/QUnitSuite/
|
||||
|
||||
.. _PhantomJS: http://phantomjs.org/
|
||||
@@ -458,6 +458,16 @@ class DisableCacheMiddleware(object):
|
||||
start_response(status, new_headers)
|
||||
return self.app(environ, start_wrapped)
|
||||
|
||||
def session_path():
|
||||
try:
|
||||
username = getpass.getuser()
|
||||
except Exception:
|
||||
username = "unknown"
|
||||
path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path, 0700)
|
||||
return path
|
||||
|
||||
class Root(object):
|
||||
"""Root WSGI application for the OpenERP Web Client.
|
||||
"""
|
||||
@@ -469,13 +479,7 @@ class Root(object):
|
||||
self.dispatch = DisableCacheMiddleware(app)
|
||||
|
||||
# Setup http sessions
|
||||
try:
|
||||
username = getpass.getuser()
|
||||
except Exception:
|
||||
username = "unknown"
|
||||
path = os.path.join(tempfile.gettempdir(), "oe-sessions-" + username)
|
||||
if not os.path.exists(path):
|
||||
os.mkdir(path, 0700)
|
||||
path = session_path()
|
||||
self.session_store = werkzeug.contrib.sessions.FilesystemSessionStore(path)
|
||||
self.session_lock = threading.Lock()
|
||||
_logger.debug('HTTP sessions stored in: %s', path)
|
||||
@@ -561,7 +565,7 @@ class Root(object):
|
||||
:rtype: ``Controller | None``
|
||||
"""
|
||||
if l:
|
||||
ps = '/' + '/'.join(l)
|
||||
ps = '/' + '/'.join(filter(None, l))
|
||||
method_name = 'index'
|
||||
while ps:
|
||||
c = controllers_path.get(ps)
|
||||
|
||||
@@ -3028,12 +3028,57 @@ div.ui-widget-overlay {
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.resolution table {
|
||||
width: 100%;
|
||||
line-height: 20px;
|
||||
.resolution {
|
||||
width: 350px;
|
||||
background-color: white;
|
||||
margin-bottom: 15px;
|
||||
margin-left: 5px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
.resolution table td {
|
||||
valign: middle;
|
||||
.resolution .res {
|
||||
display: table;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
div.res {
|
||||
border: 1px solid;
|
||||
}
|
||||
|
||||
.resolution .res > div:not(.simtext) {
|
||||
border-bottom: 1px solid;
|
||||
height: 70px;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.res .simtext {
|
||||
border-bottom: 0px;
|
||||
padding: 5px;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
.simtext span {
|
||||
font-size: 8px;
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.resolution .res div div {
|
||||
display: inline;
|
||||
position: absolute;
|
||||
padding-top: 30px;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
||||
.res img {
|
||||
width: 150px;
|
||||
height: 40px;
|
||||
padding-top: 20px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
.res span a {
|
||||
font-size: 10px;
|
||||
padding-right: 5px;
|
||||
>>>>>>> MERGE-SOURCE
|
||||
}
|
||||
|
||||
@media print {
|
||||
|
||||
@@ -2400,11 +2400,49 @@ div.ui-widget-overlay
|
||||
@include radius(3px)
|
||||
// }}}
|
||||
|
||||
.resolution table
|
||||
width: 100%
|
||||
line-height: 20px
|
||||
td
|
||||
valign: middle
|
||||
.resolution
|
||||
width: 350px
|
||||
background-color: white
|
||||
margin-bottom: 15px
|
||||
margin-left: 5px
|
||||
position: relative
|
||||
z-index: 10
|
||||
.res
|
||||
display: table
|
||||
width: 100%
|
||||
|
||||
div.res
|
||||
border: 1px solid
|
||||
|
||||
.resolution .res > div:not(.simtext)
|
||||
border-bottom: 1px solid
|
||||
height: 70px
|
||||
clear: both
|
||||
|
||||
.res .simtext
|
||||
border-bottom: 0px
|
||||
padding: 5px
|
||||
height: auto
|
||||
|
||||
.simtext span
|
||||
font-size: 8px
|
||||
color: grey
|
||||
|
||||
.resolution .res div div
|
||||
display: inline
|
||||
position: absolute
|
||||
padding-top: 30px
|
||||
padding-left: 10px
|
||||
|
||||
.res
|
||||
img
|
||||
width: 150px
|
||||
height: 40px
|
||||
padding-top: 20px
|
||||
padding-left: 5px
|
||||
span a
|
||||
font-size: 10px
|
||||
padding-right: 5px
|
||||
|
||||
@media print
|
||||
.openerp
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
width="808.39862"
|
||||
height="160.13882"
|
||||
id="svg2"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.0 r9654"
|
||||
sodipodi:docname="openerp_slogan_2011.svg"><metadata
|
||||
id="metadata37"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1366"
|
||||
inkscape:window-height="717"
|
||||
id="namedview35"
|
||||
showgrid="false"
|
||||
inkscape:zoom="1.1287411"
|
||||
inkscape:cx="366.36036"
|
||||
inkscape:cy="42.587126"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0" /><defs
|
||||
id="defs6" /><g
|
||||
id="g3066"
|
||||
transform="translate(-53.15667,-272.78409)"><text
|
||||
sodipodi:linespacing="125%"
|
||||
id="text3062"
|
||||
y="424.81061"
|
||||
x="195.13553"
|
||||
style="font-size:39px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#999999;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
|
||||
xml:space="preserve"><tspan
|
||||
y="424.81061"
|
||||
x="195.13553"
|
||||
id="tspan3064"
|
||||
sodipodi:role="line">Source Business Applications </tspan></text>
|
||||
<g
|
||||
transform="matrix(0.125,0,0,-0.125,53.156566,432.78409)"
|
||||
id="g14"><path
|
||||
d="m 936.855,65.9766 c -2.363,3.8281 0.926,24.3281 7.317,45.5544 16.215,53.879 137.058,580.692 147.888,644.688 4.89,28.906 7.73,66.707 6.32,84 -2.31,28.222 -4.61,31.219 -22.49,29.203 -10.96,-1.238 -32.76,-11.137 -48.43,-22 -33.925,-23.508 -37.581,-24.016 -41.413,-5.754 -3.59,17.094 112.043,106.23 176.523,136.078 34.98,16.188 46.27,18.199 62,11.031 24.31,-11.074 24.75,-34.379 2.62,-137.109 -30.45,-141.328 -30.75,-139.957 15.49,-69.859 72.12,109.328 169.17,188.429 252.36,205.699 81.03,16.822 108.77,-14.793 108.77,-123.922 0,-116.191 -43.5,-255.977 -100.63,-323.41 -30.36,-35.821 -141.45,-118.36 -187.37,-139.199 -27.58,-12.524 -52.26,-16.293 -105.59,-16.129 l -69.58,0.211 -24.56,-101.516 c -13.5,-55.832 -27.19,-122.535 -30.41,-148.227 l -5.86,-46.7144 -54.26,-10.0078 C 995.711,73.0859 964.512,66.4297 956.227,63.8008 947.938,61.168 939.223,62.1484 936.855,65.9766 z M 1346.66,471.574 c 52.86,47.758 108.42,200.867 117.54,323.906 7.61,102.622 -23.4,127.825 -96.68,78.575 -79.08,-53.153 -158.04,-176.297 -186.2,-290.387 -29.39,-119.063 -30.21,-106.648 8.27,-124.113 20.91,-9.493 52.11,-15.606 80.2,-15.711 41.4,-0.16 49.05,2.605 76.87,27.73 z M 283.418,387.727 c -24.418,3.832 -65.816,14.968 -92,24.753 -65.555,24.493 -138.168,96.891 -162.5,162.008 -51.2188,137.078 -33.22659,319.461 44.6836,452.942 64.4374,110.4 180.4144,195.12 314.2104,229.53 60.903,15.66 192.704,17.51 251.079,3.52 202.371,-48.5 296.117,-220.27 248.394,-455.148 C 880.391,771.418 860.137,713.066 842.273,675.668 815.594,619.816 797.465,595.48 740.801,539.461 638.582,438.402 537.984,393.801 391.812,384.734 c -35.199,-2.183 -83.976,-0.836 -108.394,2.993 z m 227.184,71.808 c 74.336,35.715 143.003,125.078 181.019,235.574 41.453,120.493 50.453,302.95 19.348,392.281 -17.606,50.56 -75.008,109.11 -120.086,122.5 -52.723,15.66 -139.766,12.29 -192.524,-7.45 C 278.254,1157.5 193.234,997.875 172.461,778.324 156.203,606.477 194.312,498.582 286.875,454.41 c 36.105,-17.23 49.434,-19.18 112.937,-16.523 54.489,2.277 81.434,7.543 110.79,21.648 z M 1807.26,386.848 c -70.7,17.875 -107.45,68.386 -107.45,147.683 0,94.422 41.04,236.883 87.83,304.895 62.36,90.629 235.23,171.114 319.04,148.547 60.25,-16.223 91.25,-77.039 73.28,-143.758 -20.64,-76.653 -119.11,-143.781 -261.5,-178.274 -69.11,-16.742 -73.62,-19.113 -78,-41.019 -13.02,-65.098 2.03,-128.215 36.29,-152.207 40.12,-28.102 135.34,-9.328 217.73,42.926 20.84,13.214 39.14,24.027 40.68,24.027 1.53,0 4.54,-6.715 6.69,-14.922 3.08,-11.797 -11.38,-24.23 -69.07,-59.383 -40.13,-24.453 -91.1,-51.586 -113.26,-60.289 -47.34,-18.597 -117.56,-27 -152.26,-18.226 z m 121.96,312.015 c 76.66,29.575 133.89,89.364 138.65,144.867 5.31,61.887 -13.58,87.938 -63.78,87.938 -59.06,0 -106.91,-62.43 -137.19,-178.977 -8.15,-31.363 -14.88,-61.593 -14.95,-67.175 -0.16,-11.516 23.35,-7.457 77.27,13.347 z m 700.59,-306.922 c -26.89,18.875 -23.17,74.243 14.5,215.727 17.58,66 38.07,147.859 45.53,181.91 12.79,58.305 12.79,62.703 -0.07,75.555 -12.68,12.687 -15.56,12.734 -40.87,0.664 -44.06,-21.008 -82.4,-59.617 -129.47,-130.367 -54.02,-81.188 -79.91,-143.239 -103.35,-247.762 l -17.95,-80 -49.42,-5.543 c -27.18,-3.051 -56.2,-7.695 -64.49,-10.328 -8.28,-2.629 -16.79,-1.934 -18.91,1.547 -2.12,3.476 11.91,61.246 31.19,128.375 43.41,151.234 68.87,274.105 65.71,317.172 -2.1,28.652 -4.67,32.535 -20.44,30.863 -9.92,-1.051 -32.7,-11.613 -50.61,-23.473 -27.09,-17.918 -33.81,-19.621 -39.84,-10.086 -4,6.309 -7.24,13.274 -7.21,15.473 0.09,8.66 152.88,113.422 188.2,129.043 30.8,13.629 41.13,14.961 57.62,7.449 19,-8.656 19.82,-11.64 15.17,-54.824 -2.71,-25.117 -17.33,-90.652 -32.48,-145.633 -15.15,-54.976 -26.58,-100.933 -25.39,-102.121 1.19,-1.187 16,20.262 32.91,47.66 40.86,66.196 138.67,167.524 201.73,208.981 41.24,31.488 78.49,42.199 93.83,46.433 31.29,8.641 54.62,0.219 67.85,-24.496 10.24,-19.137 2.96,-58.43 -44.58,-240.492 -65.25,-249.918 -63.01,-270.895 23.14,-216.266 34.98,22.188 37.93,22.789 45.19,9.211 6.6,-12.316 -0.97,-20.613 -49.85,-54.648 -103.55,-72.086 -156.52,-91.86 -187.64,-70.024"
|
||||
id="path16"
|
||||
style="fill:#db2925;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 4036.6,551.477 c 17.5,0 28.98,2.461 34.45,7.382 6.02,5.469 10.94,16.407 14.77,32.813 l 21.33,0 -2.67,-198.953 c 0,0 -51.48,0.437 -67.88,0.437 l -801.44,0 0,22.149 c 17.5,4.375 28.71,9.57 33.63,15.586 5.47,6.562 8.2,17.5 8.2,32.812 l 0,740.747 c 0,16.4 -2.73,27.61 -8.2,33.63 -5.47,6.56 -16.68,11.76 -33.63,15.58 l 0,21.33 791.6,0 69.6,0.29 0.94,-197.98 -22.14,0 c -3.84,16.4 -9.03,27.07 -15.59,31.99 -6.57,5.47 -17.5,8.2 -32.81,8.2 l -556.17,0 0,-193.592 354.37,0 c 17.5,0 28.99,2.461 34.45,7.383 5.47,4.922 10.39,15.86 14.77,32.813 l 21.33,0 0,-223.125 -21.33,0 c -3.28,15.859 -8.2,26.523 -14.77,31.992 -6.01,5.469 -17.5,8.203 -34.45,8.203 l -354.37,0 0,-229.687 566.01,0 m 343.71,-158.321 0,22.149 c 16.96,3.281 28.17,8.203 33.64,14.765 5.46,6.563 8.2,17.774 8.2,33.633 l 0,740.747 c 0,15.31 -2.74,26.25 -8.2,32.81 -4.93,6.56 -16.14,12.03 -33.64,16.4 l 0,21.33 554.53,0 c 114.85,0 203.99,-22.42 267.43,-67.26 63.43,-44.85 95.15,-107.46 95.15,-187.85 0,-66.177 -19.69,-120.864 -59.06,-164.068 -38.83,-42.656 -98.98,-74.921 -180.47,-96.796 L 5244.1,498.977 c 10.94,-15.86 23.24,-29.805 36.92,-41.836 14.21,-11.485 36.63,-25.43 67.26,-41.836 l 0,-22.149 -324.02,0 0,22.149 c 12.03,1.64 21.05,4.922 27.07,9.843 6.56,4.922 9.84,10.938 9.84,18.047 0,1.641 -2.19,7.11 -6.56,16.407 -4.38,9.296 -9.02,17.5 -13.95,24.609 l -184.57,269.883 -240.35,0 0,-290.391 c 0,-16.406 2.46,-27.617 7.38,-33.633 5.47,-6.015 16.96,-10.937 34.46,-14.765 l 0,-22.149 -277.27,0 m 501.21,730.894 -265.78,0 0,-241.988 272.35,0 c 80.39,0 137.53,9.571 171.44,28.711 34.45,19.688 51.68,51.68 51.68,95.977 0,42.66 -16.68,72.73 -50.04,90.23 -33.36,18.05 -93.24,27.07 -179.65,27.07 m 680.04,-730.894 0,22.149 c 16.96,3.281 28.17,8.203 33.64,14.765 5.46,6.563 8.2,17.774 8.2,33.633 l 0,740.747 c 0,15.31 -2.74,26.25 -8.2,32.81 -4.93,6.56 -16.14,12.03 -33.64,16.4 l 0,21.33 543.05,0 c 114.84,0 203.98,-22.42 267.42,-67.26 63.44,-44.85 95.15,-107.46 95.16,-187.85 -0.01,-82.036 -30.35,-146.841 -91.06,-194.419 -60.7,-47.578 -143.55,-71.367 -248.55,-71.367 l -330.59,0 0,-290.391 c 0,-16.406 2.46,-27.617 7.39,-33.633 5.46,-6.015 16.95,-10.937 34.45,-14.765 l 0,-22.149 -277.27,0 m 488.91,734.184 -253.48,0 0,-223.129 260.04,0 c 77.11,0 133.71,9.023 169.81,27.07 36.09,18.594 54.14,47.578 54.14,86.949 0,38.83 -17.5,66.72 -52.5,83.68 -35,16.95 -94.34,25.43 -178.01,25.43"
|
||||
id="path18"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 2683.12,988.758 c -8.82,2.086 -16.08,12.122 -23.88,33.032 -14.04,37.63 -33.6,47.17 -67.6,32.96 -15.46,-6.45 -33.27,-8.3 -60.93,-6.32 l -39.09,2.79 -9.03,-19.03 c -4.97,-10.47 -9.12,-21.26 -9.22,-23.98 -0.31,-8.448 -28.78,-26.253 -38.85,-24.3 -17.57,3.406 -14.27,15.254 6.13,21.99 14.1,4.65 23.12,12.86 29.96,27.26 5.37,11.33 8.89,21.14 7.82,21.79 -38.82,23.36 -60.64,22.62 -166.11,-5.68 -198.05,-53.122 -221.21,-56.754 -315.59,-49.5 -4.09,0.32 -10.14,7.69 -13.44,16.39 -12.12,31.88 33.94,125.28 82.12,166.52 72.51,62.06 176.61,49.13 286.94,-35.64 43.24,-33.22 72.91,-40.86 66.72,-17.19 -5.55,21.21 8.22,62.48 27.75,83.19 20.2,21.43 62.98,36.84 152.84,55.05 73.31,14.86 94.8,5.1 104.39,-47.43 6.59,-36.05 15.78,-37.8 43.47,-8.26 30.5,32.54 50.14,40.8 89.36,37.55 36.44,-3.02 74.35,-20.15 107.62,-48.63 l 23.99,-20.54 12.28,27.86 c 6.75,15.32 19.04,37.64 27.3,49.61 l 15.02,21.75 18.23,-12.55 c 10.04,-6.9 47.1,-41.62 82.38,-77.16 35.28,-35.54 80.54,-79.28 100.58,-97.19 31.42,-28.07 36.45,-35.35 36.45,-52.75 0,-20.95 -8.41,-34.18 -21.73,-34.18 -4.25,0 -17.88,16.05 -30.28,35.67 -24.58,38.87 -174.17,183.86 -181.54,175.95 -2.38,-2.54 -10.21,-18.52 -17.41,-35.5 l -13.1,-30.88 18.32,-35.54 c 19.69,-38.17 21.47,-48.2 12.67,-71.35 l -5.66,-14.9 -20.82,14.12 c -29.7,20.16 -63.86,31.16 -110.41,35.57 -33.54,3.18 -50.98,9.3 -101.36,35.61 l -60.86,31.77 -19.74,-21.55 c -10.86,-11.86 -19.03,-22.02 -18.17,-22.58 0.86,-0.56 13.51,-5.44 28.1,-10.84 21.75,-8.05 29.66,-15.31 43.91,-40.27 9.77,-17.12 24.96,-34.33 34.69,-39.32 9.53,-4.88 18.46,-9.57 19.85,-10.43 1.39,-0.85 0.01,-4.063 -3.06,-7.134 -3.22,-3.222 -12.91,-3.621 -22.92,-0.945 -13.35,3.57 -19.42,10.289 -26.41,29.179 -14.27,38.65 -33.01,53.35 -79.12,62.05 -25.74,4.85 -43.77,5.62 -50.32,2.14 -13.42,-7.14 -12.87,-10.24 2.86,-16.05 7.18,-2.66 19.64,-17.66 27.69,-33.34 8.05,-15.68 20.54,-31.1 27.76,-34.27 7.22,-3.16 13.12,-7.545 13.12,-9.732 0,-2.188 -1.66,-8.61 -23.67,-4.84"
|
||||
id="path20"
|
||||
style="fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 124.984,258.281 c -17.875,0 -31.7379,-6.601 -41.5895,-19.804 -9.8515,-13.204 -14.7773,-31.789 -14.7773,-55.758 0,-23.867 4.9258,-42.403 14.7773,-55.606 9.8516,-13.203 23.7145,-19.804 41.5895,-19.804 17.977,0 31.891,6.601 41.743,19.804 9.851,13.203 14.777,31.739 14.777,55.606 0,23.969 -4.926,42.554 -14.777,55.758 -9.852,13.203 -23.766,19.804 -41.743,19.804 m 0,42.504 c 36.563,0 65.204,-10.461 85.922,-31.383 20.719,-20.922 31.078,-49.816 31.078,-86.683 0,-36.766 -10.359,-65.61 -31.078,-86.5315 C 190.188,75.2656 161.547,64.8047 124.984,64.8047 88.5234,64.8047 59.8828,75.2656 39.0625,96.1875 18.3438,117.109 7.98438,145.953 7.98438,182.719 c 0,36.867 10.35942,65.761 31.07812,86.683 20.8203,20.922 49.4609,31.383 85.9215,31.383"
|
||||
id="path22"
|
||||
style="fill:#969696;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 338.266,93.9023 0,-89.57808 -54.539,0 0,235.52378 54.539,0 0,-24.985 c 7.515,9.953 15.843,17.266 24.984,21.938 9.141,4.773 19.652,7.16 31.535,7.16 21.024,0 38.289,-8.379 51.797,-25.137 13.508,-16.656 20.262,-38.136 20.262,-64.441 0,-26.305 -6.754,-47.836 -20.262,-64.5939 -13.508,-16.6563 -30.773,-24.9844 -51.797,-24.9844 -11.883,0 -22.394,2.3359 -31.535,7.0078 -9.141,4.7734 -17.469,12.1367 -24.984,22.0898 m 36.257,110.4497 c -11.679,0 -20.668,-4.317 -26.964,-12.95 -6.196,-8.531 -9.293,-20.871 -9.293,-37.019 0,-16.149 3.097,-28.539 9.293,-37.172 6.296,-8.531 15.285,-12.797 26.964,-12.797 11.68,0 20.567,4.266 26.661,12.797 6.195,8.531 9.293,20.922 9.293,37.172 0,16.25 -3.098,28.64 -9.293,37.172 -6.094,8.531 -14.981,12.797 -26.661,12.797"
|
||||
id="path24"
|
||||
style="fill:#969696;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 677.688,154.992 0,-15.539 -127.512,0 c 1.32,-12.797 5.941,-22.394 13.863,-28.793 7.922,-6.398 18.992,-9.598 33.211,-9.598 11.477,0 23.207,1.676 35.191,5.028 12.086,3.453 24.477,8.633 37.172,15.539 l 0,-42.047 c -12.898,-4.875 -25.797,-8.5312 -38.695,-10.9687 -12.898,-2.5391 -25.797,-3.8086 -38.695,-3.8086 -30.875,0 -54.895,7.8203 -72.059,23.4609 -17.062,15.7424 -25.594,37.7814 -25.594,66.1174 0,27.828 8.379,49.715 25.137,65.66 16.859,15.945 40.016,23.918 69.469,23.918 26.812,0 48.242,-8.074 64.289,-24.223 16.148,-16.148 24.223,-37.73 24.223,-64.746 m -56.063,18.129 c 0,10.359 -3.047,18.688 -9.141,24.984 -5.992,6.399 -13.863,9.598 -23.613,9.598 -10.562,0 -19.144,-2.996 -25.746,-8.988 -6.602,-5.891 -10.715,-14.422 -12.34,-25.594 l 70.84,0"
|
||||
id="path26"
|
||||
style="fill:#969696;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
d="m 890.359,173.121 0,-103.8983 -54.843,0 0,79.5233 c 0,14.727 -0.356,24.883 -1.067,30.469 -0.609,5.586 -1.726,9.699 -3.351,12.34 -2.133,3.554 -5.028,6.297 -8.684,8.226 -3.656,2.031 -7.82,3.047 -12.492,3.047 -11.375,0 -20.313,-4.418 -26.813,-13.254 -6.5,-8.734 -9.75,-20.871 -9.75,-36.41 l 0,-83.9413 -54.539,0 0,170.6253 54.539,0 0,-24.985 c 8.227,9.953 16.961,17.266 26.203,21.938 9.243,4.773 19.45,7.16 30.622,7.16 19.703,0 34.632,-6.043 44.789,-18.129 10.257,-12.086 15.386,-29.656 15.386,-52.711"
|
||||
id="path28"
|
||||
style="fill:#969696;fill-opacity:1;fill-rule:nonzero;stroke:none"
|
||||
inkscape:connector-curvature="0" /></g></g><text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="16.832809"
|
||||
y="194.55176"
|
||||
id="text3044"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3046"
|
||||
x="16.832809"
|
||||
y="194.55176" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:40px;font-style:normal;font-weight:normal;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;font-family:Sans"
|
||||
x="2.6577258"
|
||||
y="199.86743"
|
||||
id="text3048"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3050"
|
||||
x="2.6577258"
|
||||
y="199.86743" /></text>
|
||||
<text
|
||||
xml:space="preserve"
|
||||
style="font-size:36px;font-style:normal;font-weight:bold;line-height:125%;letter-spacing:0px;word-spacing:0px;fill:#999999;fill-opacity:1;stroke:none;font-family:Sans;-inkscape-font-specification:Sans Bold"
|
||||
x="334.00031"
|
||||
y="185.69235"
|
||||
id="text3056"
|
||||
sodipodi:linespacing="125%"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan3058"
|
||||
x="334.00031"
|
||||
y="185.69235" /><tspan
|
||||
sodipodi:role="line"
|
||||
x="334.00031"
|
||||
y="230.69235"
|
||||
id="tspan3060" /></text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 15 KiB |
|
After Width: | Height: | Size: 3.9 KiB |
|
After Width: | Height: | Size: 17 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1,97 @@
|
||||
<?xml version="1.0" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
|
||||
"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
|
||||
width="852.000000pt" height="196.000000pt" viewBox="0 0 852.000000 196.000000"
|
||||
preserveAspectRatio="xMidYMid meet">
|
||||
<metadata>
|
||||
Created by potrace 1.10, written by Peter Selinger 2001-2011
|
||||
</metadata>
|
||||
<g transform="translate(0.000000,196.000000) scale(0.100000,-0.100000)"
|
||||
fill="#000000" stroke="none">
|
||||
<path d="M3928 1761 l-32 -58 -50 36 c-41 29 -60 36 -110 39 -59 4 -64 2 -106
|
||||
-33 l-45 -37 -12 33 c-23 59 -28 64 -73 67 -50 4 -168 -22 -221 -49 -39 -19
|
||||
-69 -69 -69 -113 0 -35 -13 -33 -84 13 -138 90 -239 110 -321 63 -49 -28 -108
|
||||
-106 -130 -173 -20 -60 -11 -76 43 -81 37 -3 36 -3 -23 -21 -146 -45 -256
|
||||
-132 -306 -243 -65 -142 -91 -342 -55 -411 34 -67 106 -99 198 -89 68 7 134
|
||||
33 231 90 86 51 112 75 99 88 -7 7 -29 0 -68 -22 -72 -40 -136 -60 -196 -60
|
||||
-53 0 -81 19 -99 68 -12 32 -14 142 -2 152 4 5 60 24 123 44 216 67 319 167
|
||||
296 288 -10 52 -45 88 -101 102 l-48 13 59 6 c32 4 104 18 159 33 55 14 129
|
||||
32 164 39 114 24 164 -4 101 -57 -19 -15 -31 -31 -27 -34 4 -4 -12 -18 -35
|
||||
-32 -85 -47 -188 -127 -188 -144 0 -24 9 -23 68 8 28 14 56 23 63 19 21 -14 3
|
||||
-130 -56 -364 -31 -123 -54 -225 -52 -228 3 -2 41 1 84 7 l79 12 28 111 c31
|
||||
129 83 243 156 340 78 104 180 158 188 100 2 -12 -19 -116 -47 -230 -65 -268
|
||||
-69 -325 -28 -344 37 -17 97 5 197 72 62 41 90 66 90 80 0 25 -3 24 -59 -8
|
||||
-30 -16 -55 -24 -66 -19 -24 9 -19 36 50 323 30 126 55 237 55 246 0 9 -9 26
|
||||
-20 37 -11 11 -20 22 -20 23 0 7 -116 122 -133 132 -16 9 -15 12 1 33 l19 24
|
||||
71 -36 c40 -20 104 -43 142 -51 39 -8 89 -24 112 -36 33 -17 42 -18 49 -7 14
|
||||
21 10 44 -13 93 l-22 45 21 42 21 43 131 -133 c73 -73 135 -130 140 -128 5 3
|
||||
11 16 15 28 5 20 -16 45 -140 166 -80 78 -149 142 -154 142 -5 0 -24 -26 -42
|
||||
-59z m-331 -206 c12 -8 30 -30 39 -48 9 -17 21 -35 27 -38 5 -4 -7 -12 -26
|
||||
-18 -89 -30 -245 -168 -338 -301 -24 -33 -44 -59 -45 -57 -1 1 13 65 32 142
|
||||
42 171 44 212 10 221 -24 6 -25 6 -9 40 15 30 21 34 57 34 23 0 64 3 93 6 l51
|
||||
7 22 -42 c20 -40 44 -60 57 -48 3 3 -15 30 -41 60 -25 30 -46 58 -46 62 0 12
|
||||
91 -4 117 -20z m-843 -197 c9 -13 16 -43 16 -69 0 -79 -63 -148 -179 -195 -71
|
||||
-30 -81 -30 -81 0 0 37 39 156 67 204 35 60 67 82 119 82 33 0 46 -5 58 -22z"/>
|
||||
<path d="M4230 1802 c0 -9 10 -22 23 -27 l22 -10 3 -497 2 -497 -25 -17 c-14
|
||||
-9 -25 -23 -25 -30 0 -12 87 -14 545 -14 l545 0 0 125 c0 104 -2 125 -15 125
|
||||
-8 0 -15 -4 -15 -9 0 -5 -7 -17 -16 -25 -13 -14 -62 -16 -380 -16 l-364 0 0
|
||||
140 0 140 240 0 240 0 12 -25 c24 -52 33 -20 36 123 2 123 0 142 -13 142 -9 0
|
||||
-20 -11 -25 -25 l-10 -25 -240 0 -240 0 0 115 0 115 365 0 365 0 12 -25 c6
|
||||
-14 17 -25 25 -25 10 0 13 28 13 130 l0 130 -540 0 c-509 0 -540 -1 -540 -18z"/>
|
||||
<path d="M5660 1803 c0 -10 10 -23 23 -28 l22 -10 3 -503 2 -502 -25 -10 c-14
|
||||
-5 -25 -16 -25 -25 0 -13 25 -15 175 -15 142 0 175 3 175 14 0 7 -11 21 -25
|
||||
30 l-25 16 0 195 0 195 148 0 149 0 60 -87 c154 -224 193 -285 193 -299 0 -8
|
||||
-12 -19 -26 -24 -14 -6 -24 -16 -21 -23 3 -9 55 -13 205 -15 190 -2 202 -1
|
||||
202 16 0 11 -15 27 -37 39 -21 12 -50 34 -64 50 -53 57 -251 345 -243 352 5 4
|
||||
32 16 59 26 133 48 212 145 223 271 13 164 -97 294 -283 335 -29 6 -218 13
|
||||
-457 16 -393 5 -408 4 -408 -14z m792 -194 c37 -8 63 -22 87 -46 32 -32 33
|
||||
-36 29 -93 -3 -45 -10 -66 -28 -85 -43 -46 -101 -55 -352 -55 l-228 0 0 145 0
|
||||
145 220 0 c125 0 242 -5 272 -11z"/>
|
||||
<path d="M7140 1801 c0 -12 6 -21 15 -21 8 0 19 -9 25 -19 6 -13 10 -190 10
|
||||
-505 l0 -486 -25 -16 c-14 -9 -25 -23 -25 -30 0 -11 33 -14 175 -14 150 0 175
|
||||
2 175 15 0 9 -11 20 -25 25 l-25 10 0 200 0 200 221 0 c254 0 340 10 426 51
|
||||
244 116 246 442 2 553 -95 44 -136 48 -551 53 l-398 5 0 -21z m702 -181 c141
|
||||
-14 188 -44 188 -122 0 -118 -85 -147 -437 -148 l-153 0 0 140 0 140 153 0
|
||||
c83 0 196 -5 249 -10z"/>
|
||||
<path d="M730 1801 c-126 -18 -246 -78 -348 -175 -60 -57 -81 -86 -117 -160
|
||||
-57 -119 -80 -229 -72 -351 6 -87 23 -159 48 -207 84 -157 280 -234 509 -198
|
||||
153 24 251 76 372 196 81 80 107 121 150 235 30 79 32 92 32 219 1 161 -17
|
||||
217 -91 301 -88 97 -182 138 -333 144 -52 2 -120 0 -150 -4z m215 -80 c52 -24
|
||||
98 -74 127 -136 21 -45 23 -65 23 -190 -1 -169 -20 -265 -76 -380 -80 -165
|
||||
-174 -235 -324 -243 -101 -5 -144 8 -201 60 -82 75 -110 222 -80 415 38 248
|
||||
137 421 270 472 70 27 205 28 261 2z"/>
|
||||
<path d="M1625 1432 c-123 -68 -241 -172 -196 -172 5 0 32 12 59 26 28 14 55
|
||||
23 61 19 30 -18 -1 -193 -131 -738 -33 -141 -59 -260 -55 -263 3 -3 43 2 89
|
||||
11 l85 17 17 92 c9 50 27 132 38 182 l21 91 93 5 c111 6 151 24 274 118 87 68
|
||||
118 107 154 197 42 101 58 194 54 300 -3 91 -4 96 -32 120 -26 22 -36 25 -78
|
||||
20 -97 -12 -219 -103 -321 -239 -28 -39 -53 -65 -55 -60 -2 6 6 54 17 106 42
|
||||
192 20 231 -94 168z m385 -122 c39 -93 -51 -411 -140 -497 -30 -30 -40 -33
|
||||
-92 -33 -68 0 -138 25 -138 49 1 41 43 183 74 246 71 144 188 265 257 265 20
|
||||
0 30 -7 39 -30z"/>
|
||||
<path d="M4276 485 c24 -52 44 -99 44 -105 0 -6 -24 -56 -52 -113 -29 -56 -54
|
||||
-105 -56 -109 -2 -5 906 -8 2018 -8 1112 0 2020 3 2018 8 -2 4 -27 53 -56 109
|
||||
-28 57 -52 107 -52 113 0 6 20 53 44 105 l45 95 -1999 0 -1999 0 45 -95z
|
||||
m1144 -34 c0 -16 -8 -20 -42 -23 -43 -3 -43 -3 -43 -43 0 -36 3 -40 28 -43 28
|
||||
-3 38 15 12 24 -30 12 -16 34 20 34 35 0 35 0 35 -44 0 -31 -5 -46 -16 -50
|
||||
-32 -12 -82 -5 -108 15 -21 16 -26 29 -26 64 0 56 32 85 96 85 37 0 44 -3 44
|
||||
-19z m179 -7 c46 -59 10 -144 -61 -144 -62 1 -98 55 -78 116 14 41 33 53 82
|
||||
54 28 0 41 -6 57 -26z m346 1 c27 -26 32 -60 14 -98 -14 -31 -48 -47 -99 -47
|
||||
l-38 0 -4 81 c-2 44 -1 83 1 85 2 2 26 4 53 4 39 0 54 -5 73 -25z m229 9 c33
|
||||
-33 7 -94 -41 -94 -19 0 -23 -5 -23 -30 0 -25 -4 -30 -25 -30 -25 0 -25 1 -25
|
||||
85 l0 85 49 0 c32 0 55 -6 65 -16z m162 -69 c13 -44 23 -81 24 -82 0 -2 -11
|
||||
-3 -24 -3 -16 0 -27 7 -31 20 -4 11 -15 20 -27 20 -11 0 -22 -8 -25 -20 -4
|
||||
-13 -14 -20 -30 -20 -18 0 -23 4 -19 18 3 9 12 44 22 77 21 78 21 77 56 73 29
|
||||
-3 32 -7 54 -83z m169 69 c11 -11 14 -24 10 -38 -10 -29 -10 -56 -1 -88 7 -24
|
||||
5 -28 -13 -28 -15 0 -25 9 -32 30 -14 38 -37 40 -35 3 1 -22 -4 -29 -21 -31
|
||||
-22 -3 -23 -1 -23 82 l0 86 49 0 c33 0 55 -6 66 -16z m293 -34 l22 -44 0 47
|
||||
c0 40 3 47 20 47 18 0 20 -7 20 -85 0 -82 -1 -85 -23 -85 -18 0 -29 12 -49 53
|
||||
l-27 52 0 -52 c-1 -46 -4 -53 -21 -53 -18 0 -20 7 -20 86 l0 85 28 -3 c21 -2
|
||||
32 -13 50 -48z m210 33 c-2 -12 -14 -19 -36 -21 -40 -4 -42 -22 -2 -22 23 0
|
||||
30 -4 30 -20 0 -16 -7 -20 -30 -20 -20 0 -30 -5 -30 -15 0 -10 11 -15 35 -15
|
||||
29 0 35 -4 35 -20 0 -19 -5 -21 -57 -18 l-58 3 -3 83 -4 82 62 0 c53 0 61 -2
|
||||
58 -17z m150 5 c15 -15 16 -50 2 -64 -7 -7 -6 -22 5 -47 19 -47 19 -47 -10
|
||||
-47 -20 0 -27 6 -31 30 -9 40 -34 40 -34 -1 0 -26 -3 -30 -22 -27 -21 3 -23 9
|
||||
-26 86 l-3 82 54 0 c29 0 58 -5 65 -12z"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 29 KiB |
|
After Width: | Height: | Size: 28 KiB |
@@ -19,12 +19,14 @@
|
||||
/**
|
||||
* OpenERP instance constructor
|
||||
*
|
||||
* @param {Array} modules list of modules to initialize
|
||||
* @param {Array|String} modules list of modules to initialize
|
||||
*/
|
||||
init: function(modules) {
|
||||
// By default only web will be loaded, the rest will be by loaded
|
||||
// by openerp.web.Session on the first session_authenticate
|
||||
modules = _.union(['web'], modules || []);
|
||||
if (modules === "fuck your shit, don't load anything you cunt") {
|
||||
modules = [];
|
||||
} else {
|
||||
modules = _.union(['web'], modules || []);
|
||||
}
|
||||
var new_instance = {
|
||||
// links to the global openerp
|
||||
_openerp: openerp,
|
||||
|
||||
@@ -422,7 +422,7 @@ instance.web.DatabaseManager = instance.web.Widget.extend({
|
||||
self.db_list = null;
|
||||
});
|
||||
var fetch_langs = this.rpc("/web/session/get_lang_list", {}).done(function(result) {
|
||||
self.lang_list = result.lang_list;
|
||||
self.lang_list = result;
|
||||
});
|
||||
return $.when(fetch_db, fetch_langs).done(self.do_render);
|
||||
},
|
||||
@@ -1052,7 +1052,7 @@ instance.web.UserMenu = instance.web.Widget.extend({
|
||||
on_menu_settings: function() {
|
||||
var self = this;
|
||||
if (!this.getParent().has_uncommitted_changes()) {
|
||||
self.rpc("/web/action/load", { action_id: "base.action_res_users_my" }, function(result) {
|
||||
self.rpc("/web/action/load", { action_id: "base.action_res_users_my" }).done(function(result) {
|
||||
result.res_id = instance.session.uid;
|
||||
self.getParent().action_manager.do_action(result);
|
||||
});
|
||||
@@ -1148,21 +1148,65 @@ instance.web.WebClient = instance.web.Client.extend({
|
||||
},
|
||||
start: function() {
|
||||
var self = this;
|
||||
|
||||
return $.when(this._super()).pipe(function() {
|
||||
self.$el.on('contextmenu','.oe_logo',function(e) {
|
||||
instance.web.dialog($(QWeb.render('Resolution')),{
|
||||
title: "OpenERP Resolution" });
|
||||
|
||||
self.$el.find('.resolution').remove();
|
||||
self.$el.find('.oe_logo').after(QWeb.render('Resolution'))
|
||||
self.$el.find('.oe_leftbar').css('display','inline-block');
|
||||
$(self.$el).click(function(){
|
||||
$('.resolution').dialog('close');
|
||||
})
|
||||
$('.resolution a').click(function() {
|
||||
self.$el.find('.oe_logo').css('width', $(this).attr('awidth')+"px");
|
||||
self.$el.find('.oe_logo').css('height', $(this).attr('aheight')+"px");
|
||||
self.$el.find('.oe_logo img').css('width', $(this).attr('imgw')+"px");
|
||||
self.$el.find('.oe_logo img').css('height', $(this).attr('imgh')+"px");
|
||||
})
|
||||
})
|
||||
self.$el.find('.resolution').hide();
|
||||
self.$el.find('.oe_leftbar').css('display','table-cell');
|
||||
});
|
||||
$('.resolution .res div[class]').each(function(){
|
||||
$(this).find('a').click(function(){
|
||||
if($(this).attr('id') == "freeto"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/logo.png')
|
||||
}
|
||||
if($(this).attr('id') == "readyto"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_partner_ready.png')
|
||||
}
|
||||
if($(this).attr('id') == "silverto"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_partner_silver.png')
|
||||
}
|
||||
if($(this).attr('id') == "goldto"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_partner_gold.png')
|
||||
}
|
||||
if($(this).attr('id') == "community"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_community.png')
|
||||
}
|
||||
self.$el.find('.oe_logo').find('img').removeAttr("style");
|
||||
});
|
||||
$(this).find('div a').click(function(){
|
||||
if($(this).parent().attr('id') == "free"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/logo.png')
|
||||
}
|
||||
if($(this).parent().attr('id') == "ready"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_partner_ready.png')
|
||||
}
|
||||
if($(this).parent().attr('id') == "silver"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_partner_silver.png')
|
||||
}
|
||||
if($(this).parent().attr('id') == "gold"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_partner_gold.png')
|
||||
}
|
||||
if($(this).parent().attr('id') == "community"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/openerp_community.png')
|
||||
}
|
||||
if($(this).attr('id') == "vec"){
|
||||
self.$el.find('.oe_logo').find('img').attr('src','web/static/src/img/logo1.png')
|
||||
}
|
||||
if($(this).attr('id') == "low"){
|
||||
self.$el.find('.oe_logo').find('img').css('width','150px')
|
||||
self.$el.find('.oe_logo').find('img').css('height','40px')
|
||||
}
|
||||
else if($(this).attr('id') == "high"){
|
||||
self.$el.find('.oe_logo').find('img').css('width','185px')
|
||||
self.$el.find('.oe_logo').find('img').css('height','50px')
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
self.$el.on('click', '.oe_logo', function(e) {
|
||||
self.action_manager.do_action('home');
|
||||
});
|
||||
|
||||
@@ -774,10 +774,10 @@ instance.web.Widget = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
||||
}
|
||||
return false;
|
||||
},
|
||||
rpc: function(url, data, success, error) {
|
||||
var def = $.Deferred().done(success).fail(error);
|
||||
rpc: function(url, data, options) {
|
||||
var def = $.Deferred();
|
||||
var self = this;
|
||||
instance.session.rpc(url, data).done(function() {
|
||||
instance.session.rpc(url, data, options).done(function() {
|
||||
if (!self.isDestroyed())
|
||||
def.resolve.apply(def, arguments);
|
||||
}).fail(function() {
|
||||
@@ -1231,12 +1231,14 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
||||
*
|
||||
* @param {String} url RPC endpoint
|
||||
* @param {Object} params call parameters
|
||||
* @param {Object} options additional options for rpc call
|
||||
* @param {Function} success_callback function to execute on RPC call success
|
||||
* @param {Function} error_callback function to execute on RPC call failure
|
||||
* @returns {jQuery.Deferred} jquery-provided ajax deferred
|
||||
*/
|
||||
rpc: function(url, params) {
|
||||
rpc: function(url, params, options) {
|
||||
var self = this;
|
||||
options = options || {};
|
||||
// url can be an $.ajax option object
|
||||
if (_.isString(url)) {
|
||||
url = { url: url };
|
||||
@@ -1251,10 +1253,12 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
||||
id: _.uniqueId('r')
|
||||
};
|
||||
var deferred = $.Deferred();
|
||||
this.trigger('request', url, payload);
|
||||
if (! options.shadow)
|
||||
this.trigger('request', url, payload);
|
||||
var request = this.rpc_function(url, payload).done(
|
||||
function (response, textStatus, jqXHR) {
|
||||
self.trigger('response', response);
|
||||
if (! options.shadow)
|
||||
self.trigger('response', response);
|
||||
if (!response.error) {
|
||||
if (url.url === '/web/session/eval_domain_and_context') {
|
||||
self.test_eval(params, response.result);
|
||||
@@ -1268,7 +1272,8 @@ instance.web.JsonRPC = instance.web.Class.extend(instance.web.PropertiesMixin, {
|
||||
}
|
||||
).fail(
|
||||
function(jqXHR, textStatus, errorThrown) {
|
||||
self.trigger('response_failed', jqXHR);
|
||||
if (! options.shadow)
|
||||
self.trigger('response_failed', jqXHR);
|
||||
var error = {
|
||||
code: -32098,
|
||||
message: "XmlHttpRequestError " + errorThrown,
|
||||
|
||||
@@ -22,9 +22,9 @@ instance.web.Session = instance.web.JsonRPC.extend( /** @lends instance.web.Sess
|
||||
this.name = instance._session_id;
|
||||
this.qweb_mutex = new $.Mutex();
|
||||
},
|
||||
rpc: function(url, params) {
|
||||
rpc: function(url, params, options) {
|
||||
params.session_id = this.session_id;
|
||||
return this._super(url, params);
|
||||
return this._super(url, params, options);
|
||||
},
|
||||
/**
|
||||
* Setup a sessionm
|
||||
|
||||
@@ -278,9 +278,10 @@ instance.web.Model = instance.web.Class.extend({
|
||||
* @param {String} method name of the method to call
|
||||
* @param {Array} [args] positional arguments
|
||||
* @param {Object} [kwargs] keyword arguments
|
||||
* @param {Object} [options] additional options for the rpc() method
|
||||
* @returns {jQuery.Deferred<>} call result
|
||||
*/
|
||||
call: function (method, args, kwargs) {
|
||||
call: function (method, args, kwargs, options) {
|
||||
args = args || [];
|
||||
kwargs = kwargs || {};
|
||||
if (!_.isArray(args)) {
|
||||
@@ -294,7 +295,7 @@ instance.web.Model = instance.web.Class.extend({
|
||||
method: method,
|
||||
args: args,
|
||||
kwargs: kwargs
|
||||
});
|
||||
}, options);
|
||||
},
|
||||
/**
|
||||
* Fetches a Query instance bound to this model, for searching
|
||||
|
||||
@@ -0,0 +1,393 @@
|
||||
// Test support structures and methods for OpenERP
|
||||
openerp.testing = {};
|
||||
(function (testing) {
|
||||
var dependencies = {
|
||||
corelib: [],
|
||||
coresetup: ['corelib'],
|
||||
data: ['corelib', 'coresetup'],
|
||||
dates: [],
|
||||
formats: ['coresetup', 'dates'],
|
||||
chrome: ['corelib', 'coresetup'],
|
||||
views: ['corelib', 'coresetup', 'data', 'chrome'],
|
||||
search: ['data', 'coresetup', 'formats'],
|
||||
list: ['views', 'data'],
|
||||
form: ['data', 'views', 'list', 'formats'],
|
||||
list_editable: ['list', 'form', 'data'],
|
||||
};
|
||||
|
||||
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
|
||||
*/
|
||||
testing.noop = function () { };
|
||||
/**
|
||||
* Alter provided instance's ``session`` attribute to make response
|
||||
* mockable:
|
||||
*
|
||||
* * The ``responses`` parameter can be used to provide a map of (RPC)
|
||||
* paths (e.g. ``/web/view/load``) to a function returning a response
|
||||
* to the query.
|
||||
* * ``instance.session`` grows a ``responses`` attribute which is
|
||||
* a map of the same (and is in fact initialized to the ``responses``
|
||||
* parameter if one is provided)
|
||||
*
|
||||
* Note that RPC requests to un-mocked URLs will be rejected with an
|
||||
* error message: only explicitly specified urls will get a response.
|
||||
*
|
||||
* Mocked sessions will *never* perform an actual RPC connection.
|
||||
*
|
||||
* @param instance openerp instance being initialized
|
||||
* @param {Object} [responses]
|
||||
*/
|
||||
testing.mockifyRPC = function (instance, responses) {
|
||||
var session = instance.session;
|
||||
session.responses = responses || {};
|
||||
session.rpc_function = function (url, payload) {
|
||||
var fn, params;
|
||||
var needle = payload.params.model + ':' + payload.params.method;
|
||||
if (url.url === '/web/dataset/call_kw'
|
||||
&& needle in this.responses) {
|
||||
fn = this.responses[needle];
|
||||
params = [
|
||||
payload.params.args || [],
|
||||
payload.params.kwargs || {}
|
||||
];
|
||||
} else {
|
||||
fn = this.responses[url.url];
|
||||
params = [payload];
|
||||
}
|
||||
|
||||
if (!fn) {
|
||||
return $.Deferred().reject({}, 'failed',
|
||||
_.str.sprintf("Url %s not found in mock responses, with arguments %s",
|
||||
url.url, JSON.stringify(payload.params))
|
||||
).promise();
|
||||
}
|
||||
try {
|
||||
return $.when(fn.apply(null, params)).then(function (result) {
|
||||
// Wrap for RPC layer unwrapper thingy
|
||||
return {result: result};
|
||||
});
|
||||
} catch (e) {
|
||||
// not sure why this looks like that
|
||||
return $.Deferred().reject({}, 'failed', String(e));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var StackProto = {
|
||||
execute: function (fn) {
|
||||
var args = [].slice.call(arguments, 1);
|
||||
// Warning: here be dragons
|
||||
var i = 0, setups = this.setups, teardowns = this.teardowns;
|
||||
var d = $.Deferred();
|
||||
|
||||
var succeeded, failed;
|
||||
var success = function () {
|
||||
succeeded = _.toArray(arguments);
|
||||
return teardown();
|
||||
};
|
||||
var failure = function () {
|
||||
// save first failure
|
||||
if (!failed) {
|
||||
failed = _.toArray(arguments);
|
||||
}
|
||||
// chain onto next teardown
|
||||
return teardown();
|
||||
};
|
||||
|
||||
var setup = function () {
|
||||
// if setup to execute
|
||||
if (i < setups.length) {
|
||||
var f = setups[i] || testing.noop;
|
||||
$.when(f.apply(null, args)).then(function () {
|
||||
++i;
|
||||
setup();
|
||||
}, failure);
|
||||
} else {
|
||||
$.when(fn.apply(null, args)).then(success, failure);
|
||||
}
|
||||
};
|
||||
var teardown = function () {
|
||||
// if teardown to execute
|
||||
if (i > 0) {
|
||||
var f = teardowns[--i] || testing.noop;
|
||||
$.when(f.apply(null, args)).then(teardown, failure);
|
||||
} else {
|
||||
if (failed) {
|
||||
d.reject.apply(d, failed);
|
||||
} else if (succeeded) {
|
||||
d.resolve.apply(d, succeeded);
|
||||
} else {
|
||||
throw new Error("Didn't succeed or fail?");
|
||||
}
|
||||
}
|
||||
};
|
||||
setup();
|
||||
|
||||
return d;
|
||||
},
|
||||
push: function (setup, teardown) {
|
||||
return _.extend(Object.create(StackProto), {
|
||||
setups: this.setups.concat([setup]),
|
||||
teardowns: this.teardowns.concat([teardown])
|
||||
});
|
||||
},
|
||||
unshift: function (setup, teardown) {
|
||||
return _.extend(Object.create(StackProto), {
|
||||
setups: [setup].concat(this.setups),
|
||||
teardowns: [teardown].concat(this.teardowns)
|
||||
});
|
||||
}
|
||||
};
|
||||
/**
|
||||
*
|
||||
* @param {Function} [setup]
|
||||
* @param {Function} [teardown]
|
||||
* @return {*}
|
||||
*/
|
||||
testing.Stack = function (setup, teardown) {
|
||||
return _.extend(Object.create(StackProto), {
|
||||
setups: setup ? [setup] : [],
|
||||
teardowns: teardown ? [teardown] : []
|
||||
});
|
||||
};
|
||||
|
||||
var db = window['oe_db_info'];
|
||||
testing.section = function (name, options, body) {
|
||||
if (_.isFunction(options)) {
|
||||
body = options;
|
||||
options = {};
|
||||
}
|
||||
_.defaults(options, {
|
||||
setup: testing.noop,
|
||||
teardown: testing.noop
|
||||
});
|
||||
|
||||
QUnit.module(testing.current_module + '.' + name, {_oe: options});
|
||||
body(testing.case);
|
||||
};
|
||||
testing.case = function (name, options, callback) {
|
||||
if (_.isFunction(options)) {
|
||||
callback = options;
|
||||
options = {};
|
||||
}
|
||||
|
||||
var module = testing.current_module;
|
||||
var module_index = _.indexOf(testing.dependencies, module);
|
||||
var module_deps = testing.dependencies.slice(
|
||||
// If module not in deps (because only tests, no JS) -> indexOf
|
||||
// returns -1 -> index becomes 0 -> replace with ``undefined`` so
|
||||
// Array#slice returns a full copy
|
||||
0, module_index + 1 || undefined);
|
||||
|
||||
// Serialize options for this precise test case
|
||||
// WARNING: typo is from jquery, do not fix!
|
||||
var env = QUnit.config.currentModuleTestEnviroment;
|
||||
// section setup
|
||||
// case setup
|
||||
// test
|
||||
// case teardown
|
||||
// section teardown
|
||||
var case_stack = testing.Stack()
|
||||
.push(env._oe.setup, env._oe.teardown)
|
||||
.push(options.setup, options.teardown);
|
||||
var opts = _.defaults({}, options, env._oe);
|
||||
// FIXME: if this test is ignored, will still query
|
||||
if (opts.rpc === 'rpc' && !db) {
|
||||
QUnit.config.autostart = false;
|
||||
db = {
|
||||
source: null,
|
||||
supadmin: null,
|
||||
password: null
|
||||
};
|
||||
var $msg = $('<form style="margin: 0 1em 1em;">')
|
||||
.append('<h3>A test needs to clone a database</h3>')
|
||||
.append('<h4>Please provide the source clone information</h4>')
|
||||
.append(' Source DB: ').append('<input name="source">').append('<br>')
|
||||
.append(' DB Password: ').append('<input name="supadmin">').append('<br>')
|
||||
.append('Admin Password: ').append('<input name="password">').append('<br>')
|
||||
.append('<input type="submit" value="OK"/>')
|
||||
.submit(function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
db.source = $msg.find('input[name=source]').val();
|
||||
db.supadmin = $msg.find('input[name=supadmin]').val();
|
||||
db.password = $msg.find('input[name=password]').val();
|
||||
QUnit.start();
|
||||
$.unblockUI();
|
||||
});
|
||||
$.blockUI({
|
||||
message: $msg,
|
||||
css: {
|
||||
fontFamily: 'monospace',
|
||||
textAlign: 'left',
|
||||
whiteSpace: 'pre-wrap',
|
||||
cursor: 'default'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QUnit.test(name, function () {
|
||||
var instance;
|
||||
if (!opts.dependencies) {
|
||||
instance = openerp.init(module_deps);
|
||||
} else {
|
||||
// empty-but-specified dependencies actually allow running
|
||||
// without loading any module into the instance
|
||||
|
||||
// TODO: clean up this mess
|
||||
var d = opts.dependencies.slice();
|
||||
// dependencies list should be in deps order, reverse to make
|
||||
// loading order from last
|
||||
d.reverse();
|
||||
var di = 0;
|
||||
while (di < d.length) {
|
||||
var m = /^web\.(\w+)$/.exec(d[di]);
|
||||
if (m) {
|
||||
d[di] = m[1];
|
||||
}
|
||||
d.splice.apply(d, [di+1, 0].concat(
|
||||
_(dependencies[d[di]]).reverse()));
|
||||
++di;
|
||||
}
|
||||
|
||||
instance = openerp.init("fuck your shit, don't load anything you cunt");
|
||||
_(d).chain()
|
||||
.reverse()
|
||||
.uniq()
|
||||
.each(function (module) {
|
||||
openerp.web[module](instance);
|
||||
});
|
||||
}
|
||||
if (_.isNumber(opts.asserts)) {
|
||||
expect(opts.asserts);
|
||||
}
|
||||
|
||||
if (opts.templates) {
|
||||
for(var i=0; i<module_deps.length; ++i) {
|
||||
var dep = module_deps[i];
|
||||
var templates = testing.templates[dep];
|
||||
if (_.isEmpty(templates)) { continue; }
|
||||
|
||||
for (var j=0; j < templates.length; ++j) {
|
||||
instance.web.qweb.add_template(templates[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var $fixture = $('#qunit-fixture');
|
||||
|
||||
var mock, async = false;
|
||||
switch (opts.rpc) {
|
||||
case 'mock':
|
||||
async = true;
|
||||
testing.mockifyRPC(instance);
|
||||
mock = function (spec, handler) {
|
||||
instance.session.responses[spec] = handler;
|
||||
};
|
||||
break;
|
||||
case 'rpc':
|
||||
async = true;
|
||||
(function () {
|
||||
// Bunch of random base36 characters
|
||||
var dbname = 'test_' + Math.random().toString(36).slice(2);
|
||||
// Add db setup/teardown at the start of the stack
|
||||
case_stack = case_stack.unshift(function (instance) {
|
||||
// FIXME hack: don't want the session to go through shitty loading process of everything
|
||||
instance.session.session_init = testing.noop;
|
||||
instance.session.load_modules = testing.noop;
|
||||
instance.session.session_bind();
|
||||
return instance.session.rpc('/web/database/duplicate', {
|
||||
fields: [
|
||||
{name: 'super_admin_pwd', value: db.supadmin},
|
||||
{name: 'db_original_name', value: db.source},
|
||||
{name: 'db_name', value: dbname}
|
||||
]
|
||||
}).then(function (result) {
|
||||
if (result.error) {
|
||||
return $.Deferred().reject(result.error).promise();
|
||||
}
|
||||
return instance.session.session_authenticate(
|
||||
dbname, 'admin', db.password, true);
|
||||
});
|
||||
}, function (instance) {
|
||||
return instance.session.rpc('/web/database/drop', {
|
||||
fields: [
|
||||
{name: 'drop_pwd', value: db.supadmin},
|
||||
{name: 'drop_db', value: dbname}
|
||||
]
|
||||
}).then(function (result) {
|
||||
if (result.error) {
|
||||
return $.Deferred().reject(result.error).promise();
|
||||
}
|
||||
return result;
|
||||
});
|
||||
});
|
||||
})();
|
||||
}
|
||||
|
||||
// Always execute tests asynchronously
|
||||
stop();
|
||||
var timeout;
|
||||
case_stack.execute(function () {
|
||||
var result = callback.apply(null, arguments);
|
||||
if (!(result && _.isFunction(result.then))) {
|
||||
if (async) {
|
||||
ok(false, "asynchronous test cases must return a promise");
|
||||
}
|
||||
} else {
|
||||
if (!_.isNumber(opts.asserts)) {
|
||||
ok(false, "asynchronous test cases must specify the "
|
||||
+ "number of assertions they expect");
|
||||
}
|
||||
}
|
||||
|
||||
return $.Deferred(function (d) {
|
||||
$.when(result).then(function () {
|
||||
d.resolve.apply(d, arguments)
|
||||
}, function () {
|
||||
d.reject.apply(d, arguments);
|
||||
});
|
||||
if (async || (result && result.then)) {
|
||||
// async test can be either implicit async (rpc) or
|
||||
// promise-returning
|
||||
timeout = setTimeout(function () {
|
||||
QUnit.config.semaphore = 1;
|
||||
d.reject({message: "Test timed out"});
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
}, instance, $fixture, mock).always(function () {
|
||||
if (timeout) { clearTimeout(timeout); }
|
||||
start();
|
||||
}).fail(function (error) {
|
||||
if (options.fail_on_rejection === false) {
|
||||
return;
|
||||
}
|
||||
var message;
|
||||
if (typeof error !== 'object'
|
||||
|| typeof error.message !== 'string') {
|
||||
message = JSON.stringify([].slice.apply(arguments));
|
||||
} else {
|
||||
message = error.message;
|
||||
if (error.data && error.data.debug) {
|
||||
message += '\n\n' + error.data.debug;
|
||||
}
|
||||
}
|
||||
|
||||
ok(false, message);
|
||||
});
|
||||
});
|
||||
};
|
||||
})(openerp.testing);
|
||||
@@ -660,6 +660,9 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||
return self._process_save(save_obj).then(function() {
|
||||
save_obj.ret = _.toArray(arguments);
|
||||
return iterate();
|
||||
|
||||
}, function() {
|
||||
save_obj.error = true;
|
||||
});
|
||||
}
|
||||
return $.when();
|
||||
@@ -843,6 +846,8 @@ instance.web.FormView = instance.web.View.extend(instance.web.form.FieldManagerM
|
||||
var save_obj = {prepend_on_create: prepend_on_create, ret: null};
|
||||
this.save_list.push(save_obj);
|
||||
return this._process_operations().then(function() {
|
||||
if (save_obj.error)
|
||||
return $.Deferred().reject();
|
||||
return $.when.apply($, save_obj.ret);
|
||||
});
|
||||
},
|
||||
@@ -3871,26 +3876,13 @@ instance.web.form.One2ManyListView = instance.web.ListView.extend({
|
||||
this._super.apply(this, arguments);
|
||||
},
|
||||
do_delete: function (ids) {
|
||||
var self = this;
|
||||
var next = $.when();
|
||||
var _super = this._super;
|
||||
// handle deletion of an item which does not exist
|
||||
// TODO: better handle that in the editable list?
|
||||
var false_id_index = _(ids).indexOf(false);
|
||||
if (false_id_index !== -1) {
|
||||
ids.splice(false_id_index, 1);
|
||||
next = this.cancel_edition(true);
|
||||
var confirm = window.confirm;
|
||||
window.confirm = function () { return true; };
|
||||
try {
|
||||
return this._super(ids);
|
||||
} finally {
|
||||
window.confirm = confirm;
|
||||
}
|
||||
return next.then(function () {
|
||||
// wheeee
|
||||
var confirm = window.confirm;
|
||||
window.confirm = function () { return true; };
|
||||
try {
|
||||
return _super.call(self, ids);
|
||||
} finally {
|
||||
window.confirm = confirm;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
instance.web.form.One2ManyGroups = instance.web.ListView.Groups.extend({
|
||||
@@ -5038,14 +5030,14 @@ instance.web.form.FieldBinaryImage = instance.web.form.FieldBinary.extend({
|
||||
* Options on attribute ; "blockui" {Boolean} block the UI or not
|
||||
* during the file is uploading
|
||||
*/
|
||||
instance.web.form.FieldOne2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend({
|
||||
instance.web.form.FieldMany2ManyBinaryMultiFiles = instance.web.form.AbstractField.extend({
|
||||
template: "FieldBinaryFileUploader",
|
||||
init: function(field_manager, node) {
|
||||
this._super(field_manager, node);
|
||||
this.field_manager = field_manager;
|
||||
this.node = node;
|
||||
if(this.field.type != "one2many" || this.field.relation != 'ir.attachment') {
|
||||
throw "The type of the field '"+this.field.string+"' must be a one2many field with a relation to 'ir.attachment' model.";
|
||||
if(this.field.type != "many2many" || this.field.relation != 'ir.attachment') {
|
||||
throw "The type of the field '"+this.field.string+"' must be a many2many field with a relation to 'ir.attachment' model.";
|
||||
}
|
||||
this.ds_file = new instance.web.DataSetSearch(this, 'ir.attachment');
|
||||
this.fileupload_id = _.uniqueId('oe_fileupload_temp');
|
||||
@@ -5375,7 +5367,7 @@ instance.web.form.widgets = new instance.web.Registry({
|
||||
'progressbar': 'instance.web.form.FieldProgressBar',
|
||||
'image': 'instance.web.form.FieldBinaryImage',
|
||||
'binary': 'instance.web.form.FieldBinaryFile',
|
||||
'one2many_binary': 'instance.web.form.FieldOne2ManyBinaryMultiFiles',
|
||||
'many2many_binary': 'instance.web.form.FieldMany2ManyBinaryMultiFiles',
|
||||
'statusbar': 'instance.web.form.FieldStatus',
|
||||
'monetary': 'instance.web.form.FieldMonetary',
|
||||
});
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
openerp.web.list = function (instance) {
|
||||
var _t = instance.web._t,
|
||||
_lt = instance.web._lt;
|
||||
_lt = instance.web._lt;
|
||||
var QWeb = instance.web.qweb;
|
||||
instance.web.views.add('list', 'instance.web.ListView');
|
||||
instance.web.ListView = instance.web.View.extend( /** @lends instance.web.ListView# */ {
|
||||
|
||||
@@ -77,6 +77,15 @@ openerp.web.list_editable = function (instance) {
|
||||
do_edit: function (index, id, dataset) {
|
||||
_.extend(this.dataset, dataset);
|
||||
},
|
||||
do_delete: function (ids) {
|
||||
var _super = this._super.bind(this);
|
||||
var next = this.editor.is_editing()
|
||||
? this.cancel_edition(true)
|
||||
: $.when();
|
||||
return next.then(function () {
|
||||
return _super(ids);
|
||||
});
|
||||
},
|
||||
editable: function () {
|
||||
return this.fields_view.arch.attrs.editable
|
||||
|| this._context_editable
|
||||
|
||||
@@ -25,7 +25,6 @@ instance.web.ActionManager = instance.web.Widget.extend({
|
||||
dialog_stop: function () {
|
||||
if (this.dialog) {
|
||||
this.dialog.destroy();
|
||||
this.dialog = null;
|
||||
}
|
||||
},
|
||||
/**
|
||||
@@ -790,8 +789,8 @@ instance.web.ViewManagerAction = instance.web.ViewManager.extend({
|
||||
name: "JS Tests",
|
||||
target: 'new',
|
||||
type : 'ir.actions.act_url',
|
||||
url: '/web/static/test/test.html'
|
||||
})
|
||||
url: '/web/tests?mod=*'
|
||||
});
|
||||
break;
|
||||
case 'perm_read':
|
||||
var ids = current_view.get_selected_ids();
|
||||
|
||||
@@ -12,23 +12,39 @@
|
||||
</t>
|
||||
<t t-name="Resolution">
|
||||
<div class="resolution">
|
||||
<table>
|
||||
<tr>
|
||||
<td colspan="2"><label>Resolution:</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a awidth="150" aheight="60" imgw="100" imgh="30">150 x 60</a></td>
|
||||
<td><a awidth="250" aheight="90" imgw="200" imgh="60">250 x 90</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a awidth="290" aheight="90" imgw="225" imgh="60">290 x 90</a></td>
|
||||
<td><a awidth="320" aheight="100" imgw="257" imgh="70">320 x 100</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td style="float:right;"><a awidth="220" aheight="70" imgw="157" imgh="40">Original</a></td>
|
||||
</tr>
|
||||
</table>
|
||||
<div class="res">
|
||||
<div class="simtext">
|
||||
Looking for the OpenERP logo? <br></br>
|
||||
<span>Thank you for using and promoting the OpenERP brand.Select<br></br>
|
||||
the logo that fits your need.
|
||||
</span>
|
||||
</div>
|
||||
<div class="freeto">
|
||||
<a id="freeto"><img alt="Test" src="/web/static/src/img/logo.png" width="45px" height="170px"></img></a>
|
||||
<div><span>Free to Use</span><br/>
|
||||
<span id="free"><a id="low" href="#">Low Res |</a><a id="high" href="#">High Res |</a><a id="vec" href="#">Vectorial</a></span></div>
|
||||
</div>
|
||||
<div class="readyto">
|
||||
<a id="readyto"><img alt="Test" src="/web/static/src/img/openerp_partner_ready.png"></img></a>
|
||||
<div><span>Official Ready Partners Only</span><br/>
|
||||
<span id="ready"><a id="low" href="#">Low Res |</a><a id="high" href="#">High Res</a></span></div>
|
||||
</div>
|
||||
<div class="silverto">
|
||||
<a id="silverto"><img alt="Test" src="/web/static/src/img/openerp_partner_silver.png"></img></a>
|
||||
<div><span>Official Silver Partners Only</span><br/>
|
||||
<span id="silver"><a id="low" href="#">Low Res |</a><a id="high" href="#">High Res</a></span></div>
|
||||
</div>
|
||||
<div class="goldto">
|
||||
<a id="goldto"><img alt="Test" src="/web/static/src/img/openerp_partner_gold.png"></img></a>
|
||||
<div><span>Official Golden Partners Only</span><br/>
|
||||
<span id="gold"><a id="low" href="#">Low Res |</a><a id="high" href="#">High Res</a></span></div>
|
||||
</div>
|
||||
<div class="community" style="border-bottom: 0px;">
|
||||
<a id="community"><img alt="Test" src="/web/static/src/img/openerp_community.png"></img></a>
|
||||
<div><span>Community Members Only</span><br/>
|
||||
<span id="community"><a id="low" href="#">Low Res |</a><a id="high" href="#">High Res</a></span></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<t t-name="Notification">
|
||||
@@ -406,7 +422,7 @@
|
||||
<t t-esc="menu.name"/>
|
||||
<t t-if="menu.needaction_enabled and menu.needaction_counter">
|
||||
<div class="oe_tag oe_tag_dark oe_menu_counter">
|
||||
<t t-esc="menu.needaction_counter"/>
|
||||
<t t-if="menu.needaction_counter > 99"> ∞ </t><t t-if="menu.needaction_counter lt= 99"> <t t-esc="menu.needaction_counter"/> </t>
|
||||
</div>
|
||||
</t>
|
||||
</a>
|
||||
|
||||
@@ -1,32 +1,7 @@
|
||||
$(document).ready(function () {
|
||||
var $fix = $('#qunit-fixture');
|
||||
var mod = {
|
||||
setup: function () {
|
||||
instance = window.openerp.init([]);
|
||||
window.openerp.web.corelib(instance);
|
||||
|
||||
instance.web.qweb = new QWeb2.Engine();
|
||||
instance.web.qweb.add_template(
|
||||
'<no>' +
|
||||
'<t t-name="test.widget.template">' +
|
||||
'<ol>' +
|
||||
'<li t-foreach="5" t-as="counter" ' +
|
||||
't-attf-class="class-#{counter}">' +
|
||||
'<input/>' +
|
||||
'<t t-esc="counter"/>' +
|
||||
'</li>' +
|
||||
'</ol>' +
|
||||
'</t>' +
|
||||
'<t t-name="test.widget.template-value">' +
|
||||
'<p><t t-esc="widget.value"/></p>' +
|
||||
'</t>' +
|
||||
'</no>');
|
||||
}
|
||||
};
|
||||
var instance;
|
||||
|
||||
module('Widget.proxy', mod);
|
||||
test('(String)', function () {
|
||||
openerp.testing.section('Widget.proxy', {
|
||||
dependencies: ['web.corelib']
|
||||
}, function (test) {
|
||||
test('(String)', function (instance) {
|
||||
var W = instance.web.Widget.extend({
|
||||
exec: function () {
|
||||
this.executed = true;
|
||||
@@ -37,7 +12,7 @@ $(document).ready(function () {
|
||||
fn();
|
||||
ok(w.executed, 'should execute the named method in the right context');
|
||||
});
|
||||
test('(String)(*args)', function () {
|
||||
test('(String)(*args)', function (instance) {
|
||||
var W = instance.web.Widget.extend({
|
||||
exec: function (arg) {
|
||||
this.executed = arg;
|
||||
@@ -49,7 +24,7 @@ $(document).ready(function () {
|
||||
ok(w.executed, "should execute the named method in the right context");
|
||||
equal(w.executed, 42, "should be passed the proxy's arguments");
|
||||
});
|
||||
test('(String), include', function () {
|
||||
test('(String), include', function (instance) {
|
||||
// the proxy function should handle methods being changed on the class
|
||||
// and should always proxy "by name", to the most recent one
|
||||
var W = instance.web.Widget.extend({
|
||||
@@ -67,23 +42,43 @@ $(document).ready(function () {
|
||||
equal(w.executed, 2, "should be lazily resolved");
|
||||
});
|
||||
|
||||
test('(Function)', function () {
|
||||
test('(Function)', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({ }));
|
||||
|
||||
var fn = w.proxy(function () { this.executed = true; });
|
||||
fn();
|
||||
ok(w.executed, "should set the function's context (like Function#bind)");
|
||||
});
|
||||
test('(Function)(*args)', function () {
|
||||
test('(Function)(*args)', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({ }));
|
||||
|
||||
var fn = w.proxy(function (arg) { this.executed = arg; });
|
||||
fn(42);
|
||||
equal(w.executed, 42, "should be passed the proxy's arguments");
|
||||
});
|
||||
|
||||
module('Widget.renderElement', mod);
|
||||
test('no template, default', function () {
|
||||
});
|
||||
openerp.testing.section('Widget.renderElement', {
|
||||
dependencies: ['web.corelib'],
|
||||
setup: function (instance) {
|
||||
instance.web.qweb = new QWeb2.Engine();
|
||||
instance.web.qweb.add_template(
|
||||
'<no>' +
|
||||
'<t t-name="test.widget.template">' +
|
||||
'<ol>' +
|
||||
'<li t-foreach="5" t-as="counter" ' +
|
||||
't-attf-class="class-#{counter}">' +
|
||||
'<input/>' +
|
||||
'<t t-esc="counter"/>' +
|
||||
'</li>' +
|
||||
'</ol>' +
|
||||
'</t>' +
|
||||
'<t t-name="test.widget.template-value">' +
|
||||
'<p><t t-esc="widget.value"/></p>' +
|
||||
'</t>' +
|
||||
'</no>');
|
||||
}
|
||||
}, function (test) {
|
||||
test('no template, default', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({ }));
|
||||
|
||||
var $original = w.$el;
|
||||
@@ -98,7 +93,7 @@ $(document).ready(function () {
|
||||
equal(w.el.attributes.length, 0, "should not have generated any attribute");
|
||||
ok(_.isEmpty(w.$el.html(), "should not have generated any content"));
|
||||
});
|
||||
test('no template, custom tag', function () {
|
||||
test('no template, custom tag', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
tagName: 'ul'
|
||||
}));
|
||||
@@ -106,7 +101,7 @@ $(document).ready(function () {
|
||||
|
||||
equal(w.el.nodeName, 'UL', "should have generated the custom element tag");
|
||||
});
|
||||
test('no template, @id', function () {
|
||||
test('no template, @id', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
id: 'foo'
|
||||
}));
|
||||
@@ -116,7 +111,7 @@ $(document).ready(function () {
|
||||
equal(w.$el.attr('id'), 'foo', "should have generated the id attribute");
|
||||
equal(w.el.id, 'foo', "should also be available via property");
|
||||
});
|
||||
test('no template, @className', function () {
|
||||
test('no template, @className', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
className: 'oe_some_class'
|
||||
}));
|
||||
@@ -125,7 +120,7 @@ $(document).ready(function () {
|
||||
equal(w.el.className, 'oe_some_class', "should have the right property");
|
||||
equal(w.$el.attr('class'), 'oe_some_class', "should have the right attribute");
|
||||
});
|
||||
test('no template, bunch of attributes', function () {
|
||||
test('no template, bunch of attributes', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
attributes: {
|
||||
'id': 'some_id',
|
||||
@@ -152,7 +147,7 @@ $(document).ready(function () {
|
||||
equal(w.$el.attr('spoiler'), 'snape kills dumbledore');
|
||||
});
|
||||
|
||||
test('template', function () {
|
||||
test('template', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template'
|
||||
}));
|
||||
@@ -162,9 +157,41 @@ $(document).ready(function () {
|
||||
equal(w.$el.children().length, 5);
|
||||
equal(w.el.textContent, '01234');
|
||||
});
|
||||
|
||||
module('Widget.$', mod);
|
||||
test('basic-alias', function () {
|
||||
test('repeated', { asserts: 4 }, function (instance, $fix) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template-value'
|
||||
}));
|
||||
w.value = 42;
|
||||
return w.appendTo($fix)
|
||||
.done(function () {
|
||||
equal($fix.find('p').text(), '42', "DOM fixture should contain initial value");
|
||||
equal(w.$el.text(), '42', "should set initial value");
|
||||
w.value = 36;
|
||||
w.renderElement();
|
||||
equal($fix.find('p').text(), '36', "DOM fixture should use new value");
|
||||
equal(w.$el.text(), '36', "should set new value");
|
||||
});
|
||||
});
|
||||
});
|
||||
openerp.testing.section('Widget.$', {
|
||||
dependencies: ['web.corelib'],
|
||||
setup: function (instance) {
|
||||
instance.web.qweb = new QWeb2.Engine();
|
||||
instance.web.qweb.add_template(
|
||||
'<no>' +
|
||||
'<t t-name="test.widget.template">' +
|
||||
'<ol>' +
|
||||
'<li t-foreach="5" t-as="counter" ' +
|
||||
't-attf-class="class-#{counter}">' +
|
||||
'<input/>' +
|
||||
'<t t-esc="counter"/>' +
|
||||
'</li>' +
|
||||
'</ol>' +
|
||||
'</t>' +
|
||||
'</no>');
|
||||
}
|
||||
}, function (test) {
|
||||
test('basic-alias', function (instance) {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template'
|
||||
}));
|
||||
@@ -173,9 +200,26 @@ $(document).ready(function () {
|
||||
ok(w.$('li:eq(3)').is(w.$el.find('li:eq(3)')),
|
||||
"should do the same thing as calling find on the widget root");
|
||||
});
|
||||
|
||||
module('Widget.events', mod);
|
||||
test('delegate', function () {
|
||||
});
|
||||
openerp.testing.section('Widget.events', {
|
||||
dependencies: ['web.corelib'],
|
||||
setup: function (instance) {
|
||||
instance.web.qweb = new QWeb2.Engine();
|
||||
instance.web.qweb.add_template(
|
||||
'<no>' +
|
||||
'<t t-name="test.widget.template">' +
|
||||
'<ol>' +
|
||||
'<li t-foreach="5" t-as="counter" ' +
|
||||
't-attf-class="class-#{counter}">' +
|
||||
'<input/>' +
|
||||
'<t t-esc="counter"/>' +
|
||||
'</li>' +
|
||||
'</ol>' +
|
||||
'</t>' +
|
||||
'</no>');
|
||||
}
|
||||
}, function (test) {
|
||||
test('delegate', function (instance) {
|
||||
var a = [];
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template',
|
||||
@@ -199,7 +243,7 @@ $(document).ready(function () {
|
||||
ok(a[i], "should pass test " + i);
|
||||
}
|
||||
});
|
||||
test('undelegate', function () {
|
||||
test('undelegate', function (instance) {
|
||||
var clicked = false, newclicked = false;
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template',
|
||||
@@ -218,22 +262,4 @@ $(document).ready(function () {
|
||||
ok(!clicked, "undelegate should unbind events delegated");
|
||||
ok(newclicked, "undelegate should only unbind events it created");
|
||||
});
|
||||
|
||||
module('Widget.renderElement', mod);
|
||||
asyncTest('repeated', 4, function () {
|
||||
var w = new (instance.web.Widget.extend({
|
||||
template: 'test.widget.template-value'
|
||||
}));
|
||||
w.value = 42;
|
||||
w.appendTo($fix)
|
||||
.always(start)
|
||||
.done(function () {
|
||||
equal($fix.find('p').text(), '42', "DOM fixture should contain initial value");
|
||||
equal(w.$el.text(), '42', "should set initial value");
|
||||
w.value = 36;
|
||||
w.renderElement();
|
||||
equal($fix.find('p').text(), '36', "DOM fixture should use new value");
|
||||
equal(w.$el.text(), '36', "should set new value");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,30 +1,25 @@
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
module('web-class', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
}
|
||||
});
|
||||
test('Basic class creation', function () {
|
||||
var C = openerp.web.Class.extend({
|
||||
openerp.testing.section('class', {
|
||||
dependencies: ['web.corelib']
|
||||
}, function (test) {
|
||||
test('Basic class creation', function (instance) {
|
||||
var C = instance.web.Class.extend({
|
||||
foo: function () {
|
||||
return this.somevar;
|
||||
}
|
||||
});
|
||||
var instance = new C();
|
||||
instance.somevar = 3;
|
||||
var i = new C();
|
||||
i.somevar = 3;
|
||||
|
||||
ok(instance instanceof C);
|
||||
strictEqual(instance.foo(), 3);
|
||||
ok(i instanceof C);
|
||||
strictEqual(i.foo(), 3);
|
||||
});
|
||||
test('Class initialization', function () {
|
||||
var C1 = openerp.web.Class.extend({
|
||||
test('Class initialization', function (instance) {
|
||||
var C1 = instance.web.Class.extend({
|
||||
init: function () {
|
||||
this.foo = 3;
|
||||
}
|
||||
});
|
||||
var C2 = openerp.web.Class.extend({
|
||||
var C2 = instance.web.Class.extend({
|
||||
init: function (arg) {
|
||||
this.foo = arg;
|
||||
}
|
||||
@@ -36,8 +31,8 @@ $(document).ready(function () {
|
||||
strictEqual(i1.foo, 3);
|
||||
strictEqual(i2.foo, 42);
|
||||
});
|
||||
test('Inheritance', function () {
|
||||
var C0 = openerp.web.Class.extend({
|
||||
test('Inheritance', function (instance) {
|
||||
var C0 = instance.web.Class.extend({
|
||||
foo: function () {
|
||||
return 1;
|
||||
}
|
||||
@@ -57,8 +52,8 @@ $(document).ready(function () {
|
||||
strictEqual(new C1().foo(), 2);
|
||||
strictEqual(new C2().foo(), 3);
|
||||
});
|
||||
test('In-place extension', function () {
|
||||
var C0 = openerp.web.Class.extend({
|
||||
test('In-place extension', function (instance) {
|
||||
var C0 = instance.web.Class.extend({
|
||||
foo: function () {
|
||||
return 3;
|
||||
},
|
||||
@@ -83,8 +78,8 @@ $(document).ready(function () {
|
||||
strictEqual(new C0().foo(), 5);
|
||||
strictEqual(new C0().qux(), 5);
|
||||
});
|
||||
test('In-place extension and inheritance', function () {
|
||||
var C0 = openerp.web.Class.extend({
|
||||
test('In-place extension and inheritance', function (instance) {
|
||||
var C0 = instance.web.Class.extend({
|
||||
foo: function () { return 1; },
|
||||
bar: function () { return 1; }
|
||||
});
|
||||
@@ -101,24 +96,24 @@ $(document).ready(function () {
|
||||
strictEqual(new C1().foo(), 4);
|
||||
strictEqual(new C1().bar(), 2);
|
||||
});
|
||||
test('In-place extensions alter existing instances', function () {
|
||||
var C0 = openerp.web.Class.extend({
|
||||
test('In-place extensions alter existing instances', function (instance) {
|
||||
var C0 = instance.web.Class.extend({
|
||||
foo: function () { return 1; },
|
||||
bar: function () { return 1; }
|
||||
});
|
||||
var instance = new C0();
|
||||
strictEqual(instance.foo(), 1);
|
||||
strictEqual(instance.bar(), 1);
|
||||
var i = new C0();
|
||||
strictEqual(i.foo(), 1);
|
||||
strictEqual(i.bar(), 1);
|
||||
|
||||
C0.include({
|
||||
foo: function () { return 2; },
|
||||
bar: function () { return 2 + this._super(); }
|
||||
});
|
||||
strictEqual(instance.foo(), 2);
|
||||
strictEqual(instance.bar(), 3);
|
||||
strictEqual(i.foo(), 2);
|
||||
strictEqual(i.bar(), 3);
|
||||
});
|
||||
test('In-place extension of subclassed types', function () {
|
||||
var C0 = openerp.web.Class.extend({
|
||||
test('In-place extension of subclassed types', function (instance) {
|
||||
var C0 = instance.web.Class.extend({
|
||||
foo: function () { return 1; },
|
||||
bar: function () { return 1; }
|
||||
});
|
||||
@@ -126,13 +121,13 @@ $(document).ready(function () {
|
||||
foo: function () { return 1 + this._super(); },
|
||||
bar: function () { return 1 + this._super(); }
|
||||
});
|
||||
var instance = new C1();
|
||||
strictEqual(instance.foo(), 2);
|
||||
var i = new C1();
|
||||
strictEqual(i.foo(), 2);
|
||||
C0.include({
|
||||
foo: function () { return 2; },
|
||||
bar: function () { return 2 + this._super(); }
|
||||
});
|
||||
strictEqual(instance.foo(), 3);
|
||||
strictEqual(instance.bar(), 4);
|
||||
strictEqual(i.foo(), 3);
|
||||
strictEqual(i.bar(), 4);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
|
||||
module("eval.contexts", {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
}
|
||||
});
|
||||
test('context_sequences', function () {
|
||||
openerp.testing.section('eval.contexts', {
|
||||
dependencies: ['web.coresetup']
|
||||
}, function (test) {
|
||||
test('context_sequences', function (instance) {
|
||||
// Context n should have base evaluation context + all of contexts
|
||||
// 0..n-1 in its own evaluation context
|
||||
var active_id = 4;
|
||||
var result = openerp.session.test_eval_contexts([
|
||||
var result = instance.session.test_eval_contexts([
|
||||
{
|
||||
"__contexts": [
|
||||
{
|
||||
@@ -55,8 +48,8 @@ $(document).ready(function () {
|
||||
record_id: active_id
|
||||
});
|
||||
});
|
||||
test('non-literal_eval_contexts', function () {
|
||||
var result = openerp.session.test_eval_contexts([{
|
||||
test('non-literal_eval_contexts', function (instance) {
|
||||
var result = instance.session.test_eval_contexts([{
|
||||
"__ref": "compound_context",
|
||||
"__contexts": [
|
||||
{"__ref": "context", "__debug": "{'type':parent.type}",
|
||||
@@ -133,17 +126,15 @@ $(document).ready(function () {
|
||||
}]);
|
||||
deepEqual(result, {type: 'out_invoice'});
|
||||
});
|
||||
module('eval.domains', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.testing.instanceFor('coresetup');
|
||||
window.openerp.web.dates(openerp);
|
||||
}
|
||||
});
|
||||
test('current_date', function () {
|
||||
var current_date = openerp.web.date_to_str(new Date());
|
||||
var result = openerp.session.test_eval_domains(
|
||||
});
|
||||
openerp.testing.section('eval.contexts', {
|
||||
dependencies: ['web.coresetup', 'web.dates']
|
||||
}, function (test) {
|
||||
test('current_date', function (instance) {
|
||||
var current_date = instance.web.date_to_str(new Date());
|
||||
var result = instance.session.test_eval_domains(
|
||||
[[],{"__ref":"domain","__debug":"[('name','>=',current_date),('name','<=',current_date)]","__id":"5dedcfc96648"}],
|
||||
openerp.session.test_eval_get_context());
|
||||
instance.session.test_eval_get_context());
|
||||
deepEqual(result, [
|
||||
['name', '>=', current_date],
|
||||
['name', '<=', current_date]
|
||||
|
||||
@@ -1,33 +1,21 @@
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
module("form.widget", {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.web.data(openerp);
|
||||
window.openerp.web.views(openerp);
|
||||
window.openerp.web.list(openerp);
|
||||
window.openerp.web.form(openerp);
|
||||
}
|
||||
});
|
||||
test("compute_domain", function () {
|
||||
openerp.testing.section('compute_domain', {
|
||||
dependencies: ['web.form']
|
||||
}, function (test) {
|
||||
test("basic", function (instance) {
|
||||
var fields = {
|
||||
'a': {value: 3},
|
||||
'group_method': {value: 'line'},
|
||||
'select1': {value: 'day'},
|
||||
'rrule_type': {value: 'monthly'}
|
||||
};
|
||||
ok(openerp.web.form.compute_domain(
|
||||
ok(instance.web.form.compute_domain(
|
||||
[['a', '=', 3]], fields));
|
||||
ok(openerp.web.form.compute_domain(
|
||||
ok(instance.web.form.compute_domain(
|
||||
[['group_method','!=','count']], fields));
|
||||
ok(openerp.web.form.compute_domain(
|
||||
ok(instance.web.form.compute_domain(
|
||||
[['select1','=','day'], ['rrule_type','=','monthly']], fields));
|
||||
});
|
||||
test("compute_domain or", function () {
|
||||
test("or", function (instance) {
|
||||
var web = {
|
||||
'section_id': {value: null},
|
||||
'user_id': {value: null},
|
||||
@@ -38,22 +26,22 @@ $(document).ready(function () {
|
||||
'|', ['user_id','=',3],
|
||||
['member_ids', 'in', [3]]];
|
||||
|
||||
ok(openerp.web.form.compute_domain(domain, _.extend(
|
||||
ok(instance.web.form.compute_domain(domain, _.extend(
|
||||
{}, web, {'section_id': {value: 42}})));
|
||||
ok(openerp.web.form.compute_domain(domain, _.extend(
|
||||
ok(instance.web.form.compute_domain(domain, _.extend(
|
||||
{}, web, {'user_id': {value: 3}})));
|
||||
|
||||
ok(openerp.web.form.compute_domain(domain, _.extend(
|
||||
ok(instance.web.form.compute_domain(domain, _.extend(
|
||||
{}, web, {'member_ids': {value: 3}})));
|
||||
});
|
||||
test("compute_domain not", function () {
|
||||
test("not", function (instance) {
|
||||
var fields = {
|
||||
'a': {value: 5},
|
||||
'group_method': {value: 'line'}
|
||||
};
|
||||
ok(openerp.web.form.compute_domain(
|
||||
ok(instance.web.form.compute_domain(
|
||||
['!', ['a', '=', 3]], fields));
|
||||
ok(openerp.web.form.compute_domain(
|
||||
ok(instance.web.form.compute_domain(
|
||||
['!', ['group_method','=','count']], fields));
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
|
||||
module('server-formats', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.dates(openerp);
|
||||
}
|
||||
});
|
||||
test('Parse server datetime', function () {
|
||||
var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
openerp.testing.section('server-formats', {
|
||||
dependencies: ['web.coresetup', 'web.dates']
|
||||
}, function (test) {
|
||||
test('Parse server datetime', function (instance) {
|
||||
var date = instance.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
deepEqual(
|
||||
[date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate(),
|
||||
date.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds()],
|
||||
@@ -20,92 +12,86 @@ $(document).ready(function () {
|
||||
date.getHours(), date.getMinutes(), date.getSeconds()],
|
||||
[2009, 5 - 1, 4, 12 - (date.getTimezoneOffset() / 60), 34, 23]);
|
||||
|
||||
var date2 = openerp.web.str_to_datetime('2011-12-10 00:00:00');
|
||||
var date2 = instance.web.str_to_datetime('2011-12-10 00:00:00');
|
||||
deepEqual(
|
||||
[date2.getUTCFullYear(), date2.getUTCMonth(), date2.getUTCDate(),
|
||||
date2.getUTCHours(), date2.getUTCMinutes(), date2.getUTCSeconds()],
|
||||
[2011, 12 - 1, 10, 0, 0, 0]);
|
||||
});
|
||||
test('Parse server date', function () {
|
||||
var date = openerp.web.str_to_date("2009-05-04");
|
||||
test('Parse server date', function (instance) {
|
||||
var date = instance.web.str_to_date("2009-05-04");
|
||||
deepEqual(
|
||||
[date.getFullYear(), date.getMonth(), date.getDate()],
|
||||
[2009, 5 - 1, 4]);
|
||||
});
|
||||
test('Parse server time', function () {
|
||||
var date = openerp.web.str_to_time("12:34:23");
|
||||
test('Parse server time', function (instance) {
|
||||
var date = instance.web.str_to_time("12:34:23");
|
||||
deepEqual(
|
||||
[date.getHours(), date.getMinutes(), date.getSeconds()],
|
||||
[12, 34, 23]);
|
||||
});
|
||||
|
||||
module('web-formats', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.dates(openerp);
|
||||
window.openerp.web.formats(openerp);
|
||||
}
|
||||
});
|
||||
test("format_datetime", function () {
|
||||
var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = openerp.web.format_value(date, {type:"datetime"});
|
||||
});
|
||||
openerp.testing.section('web-formats', {
|
||||
dependencies: ['web.formats']
|
||||
}, function (test) {
|
||||
test("format_datetime", function (instance) {
|
||||
var date = instance.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = instance.web.format_value(date, {type:"datetime"});
|
||||
equal(str, date.toString("MM/dd/yyyy HH:mm:ss"));
|
||||
});
|
||||
test("format_date", function () {
|
||||
var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = openerp.web.format_value(date, {type:"date"});
|
||||
test("format_date", function (instance) {
|
||||
var date = instance.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = instance.web.format_value(date, {type:"date"});
|
||||
equal(str, date.toString("MM/dd/yyyy"));
|
||||
});
|
||||
test("format_time", function () {
|
||||
var date = openerp.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = openerp.web.format_value(date, {type:"time"});
|
||||
test("format_time", function (instance) {
|
||||
var date = instance.web.str_to_datetime("2009-05-04 12:34:23");
|
||||
var str = instance.web.format_value(date, {type:"time"});
|
||||
equal(str, date.toString("HH:mm:ss"));
|
||||
});
|
||||
test("format_float_time", function () {
|
||||
test("format_float_time", function (instance) {
|
||||
strictEqual(
|
||||
openerp.web.format_value(1.0, {type:'float', widget:'float_time'}),
|
||||
instance.web.format_value(1.0, {type:'float', widget:'float_time'}),
|
||||
'01:00');
|
||||
strictEqual(
|
||||
openerp.web.format_value(0.9853, {type:'float', widget:'float_time'}),
|
||||
instance.web.format_value(0.9853, {type:'float', widget:'float_time'}),
|
||||
'00:59');
|
||||
strictEqual(
|
||||
openerp.web.format_value(0.0085, {type:'float', widget:'float_time'}),
|
||||
instance.web.format_value(0.0085, {type:'float', widget:'float_time'}),
|
||||
'00:01');
|
||||
strictEqual(
|
||||
openerp.web.format_value(-1.0, {type:'float', widget:'float_time'}),
|
||||
instance.web.format_value(-1.0, {type:'float', widget:'float_time'}),
|
||||
'-01:00');
|
||||
strictEqual(
|
||||
openerp.web.format_value(-0.9853, {type:'float', widget:'float_time'}),
|
||||
instance.web.format_value(-0.9853, {type:'float', widget:'float_time'}),
|
||||
'-00:59');
|
||||
strictEqual(
|
||||
openerp.web.format_value(-0.0085, {type:'float', widget:'float_time'}),
|
||||
instance.web.format_value(-0.0085, {type:'float', widget:'float_time'}),
|
||||
'-00:01');
|
||||
});
|
||||
test("format_float", function () {
|
||||
test("format_float", function (instance) {
|
||||
var fl = 12.1234;
|
||||
var str = openerp.web.format_value(fl, {type:"float"});
|
||||
var str = instance.web.format_value(fl, {type:"float"});
|
||||
equal(str, "12.12");
|
||||
equal(openerp.web.format_value(12.02, {type: 'float'}),
|
||||
equal(instance.web.format_value(12.02, {type: 'float'}),
|
||||
'12.02');
|
||||
equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 3]}),
|
||||
equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 3]}),
|
||||
'0.000');
|
||||
equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 4]}),
|
||||
equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 4]}),
|
||||
'0.0002');
|
||||
equal(openerp.web.format_value(0.0002, {type: 'float', digits: [1, 6]}),
|
||||
equal(instance.web.format_value(0.0002, {type: 'float', digits: [1, 6]}),
|
||||
'0.000200');
|
||||
equal(openerp.web.format_value(1, {type: 'float', digits: [1, 6]}),
|
||||
equal(instance.web.format_value(1, {type: 'float', digits: [1, 6]}),
|
||||
'1.000000');
|
||||
equal(openerp.web.format_value(1, {type: 'float'}),
|
||||
equal(instance.web.format_value(1, {type: 'float'}),
|
||||
'1.00');
|
||||
equal(openerp.web.format_value(-11.25, {type: 'float'}),
|
||||
equal(instance.web.format_value(-11.25, {type: 'float'}),
|
||||
"-11.25");
|
||||
openerp.web._t.database.parameters.grouping = [1, 2, -1];
|
||||
equal(openerp.web.format_value(1111111.25, {type: 'float'}),
|
||||
instance.web._t.database.parameters.grouping = [1, 2, -1];
|
||||
equal(instance.web.format_value(1111111.25, {type: 'float'}),
|
||||
"1111,11,1.25");
|
||||
openerp.web._t.database.parameters.grouping = [1, 0];
|
||||
equal(openerp.web.format_value(-11.25, {type: 'float'}),
|
||||
instance.web._t.database.parameters.grouping = [1, 0];
|
||||
equal(instance.web.format_value(-11.25, {type: 'float'}),
|
||||
"-1,1.25");
|
||||
});
|
||||
// test("parse_datetime", function () {
|
||||
@@ -123,29 +109,29 @@ $(document).ready(function () {
|
||||
// var res = openerp.web.parse_value(val.toString("HH:mm:ss"), {type:"time"});
|
||||
// equal(val.toString("HH:mm:ss"), res.toString("HH:mm:ss"));
|
||||
// });
|
||||
test('parse_integer', function () {
|
||||
var val = openerp.web.parse_value('123,456', {type: 'integer'});
|
||||
test('parse_integer', function (instance) {
|
||||
var val = instance.web.parse_value('123,456', {type: 'integer'});
|
||||
equal(val, 123456);
|
||||
openerp.web._t.database.parameters.thousands_sep = '|';
|
||||
var val2 = openerp.web.parse_value('123|456', {type: 'integer'});
|
||||
instance.web._t.database.parameters.thousands_sep = '|';
|
||||
var val2 = instance.web.parse_value('123|456', {type: 'integer'});
|
||||
equal(val2, 123456);
|
||||
});
|
||||
test("parse_float", function () {
|
||||
test("parse_float", function (instance) {
|
||||
var str = "134,112.1234";
|
||||
var val = openerp.web.parse_value(str, {type:"float"});
|
||||
var val = instance.web.parse_value(str, {type:"float"});
|
||||
equal(val, 134112.1234);
|
||||
var str = "-134,112.1234";
|
||||
var val = openerp.web.parse_value(str, {type:"float"});
|
||||
var val = instance.web.parse_value(str, {type:"float"});
|
||||
equal(val, -134112.1234);
|
||||
_.extend(openerp.web._t.database.parameters, {
|
||||
_.extend(instance.web._t.database.parameters, {
|
||||
decimal_point: ',',
|
||||
thousands_sep: '.'
|
||||
});
|
||||
var val3 = openerp.web.parse_value('123.456,789', {type: 'float'});
|
||||
var val3 = instance.web.parse_value('123.456,789', {type: 'float'});
|
||||
equal(val3, 123456.789);
|
||||
});
|
||||
test('intersperse', function () {
|
||||
var g = openerp.web.intersperse;
|
||||
test('intersperse', function (instance) {
|
||||
var g = instance.web.intersperse;
|
||||
equal(g("", []), "");
|
||||
equal(g("0", []), "0");
|
||||
equal(g("012", []), "012");
|
||||
@@ -176,60 +162,61 @@ $(document).ready(function () {
|
||||
equal(g("12345678", [3,3,3,3], '.'), '12.345.678');
|
||||
equal(g("12345678", [3,0], '.'), '12.345.678');
|
||||
});
|
||||
test('format_integer', function () {
|
||||
openerp.web._t.database.parameters.grouping = [3, 3, 3, 3];
|
||||
equal(openerp.web.format_value(1000000, {type: 'integer'}),
|
||||
test('format_integer', function (instance) {
|
||||
instance.web._t.database.parameters.grouping = [3, 3, 3, 3];
|
||||
equal(instance.web.format_value(1000000, {type: 'integer'}),
|
||||
'1,000,000');
|
||||
openerp.web._t.database.parameters.grouping = [3, 2, -1];
|
||||
equal(openerp.web.format_value(106500, {type: 'integer'}),
|
||||
instance.web._t.database.parameters.grouping = [3, 2, -1];
|
||||
equal(instance.web.format_value(106500, {type: 'integer'}),
|
||||
'1,06,500');
|
||||
openerp.web._t.database.parameters.grouping = [1, 2, -1];
|
||||
equal(openerp.web.format_value(106500, {type: 'integer'}),
|
||||
instance.web._t.database.parameters.grouping = [1, 2, -1];
|
||||
equal(instance.web.format_value(106500, {type: 'integer'}),
|
||||
'106,50,0');
|
||||
});
|
||||
test('format_float', function () {
|
||||
openerp.web._t.database.parameters.grouping = [3, 3, 3, 3];
|
||||
equal(openerp.web.format_value(1000000, {type: 'float'}),
|
||||
test('format_float', function (instance) {
|
||||
instance.web._t.database.parameters.grouping = [3, 3, 3, 3];
|
||||
equal(instance.web.format_value(1000000, {type: 'float'}),
|
||||
'1,000,000.00');
|
||||
openerp.web._t.database.parameters.grouping = [3, 2, -1];
|
||||
equal(openerp.web.format_value(106500, {type: 'float'}),
|
||||
instance.web._t.database.parameters.grouping = [3, 2, -1];
|
||||
equal(instance.web.format_value(106500, {type: 'float'}),
|
||||
'1,06,500.00');
|
||||
openerp.web._t.database.parameters.grouping = [1, 2, -1];
|
||||
equal(openerp.web.format_value(106500, {type: 'float'}),
|
||||
instance.web._t.database.parameters.grouping = [1, 2, -1];
|
||||
equal(instance.web.format_value(106500, {type: 'float'}),
|
||||
'106,50,0.00');
|
||||
|
||||
_.extend(openerp.web._t.database.parameters, {
|
||||
_.extend(instance.web._t.database.parameters, {
|
||||
grouping: [3, 0],
|
||||
decimal_point: ',',
|
||||
thousands_sep: '.'
|
||||
});
|
||||
equal(openerp.web.format_value(6000, {type: 'float'}),
|
||||
equal(instance.web.format_value(6000, {type: 'float'}),
|
||||
'6.000,00');
|
||||
});
|
||||
module('custom-date-formats', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.dates(openerp);
|
||||
window.openerp.web.formats(openerp);
|
||||
}
|
||||
});
|
||||
openerp.testing.section('web-formats', {
|
||||
dependencies: ['web.formats']
|
||||
}, function (test) {
|
||||
test('format stripper', function (instance) {
|
||||
strictEqual(instance.web.strip_raw_chars('%a, %Y %b %d'),
|
||||
'%a, %Y %b %d');
|
||||
strictEqual(instance.web.strip_raw_chars('%a, %Y.eko %bren %da'),
|
||||
'%a, %Y. %b %d');
|
||||
});
|
||||
test('format stripper', function () {
|
||||
strictEqual(openerp.web.strip_raw_chars('%a, %Y %b %d'), '%a, %Y %b %d');
|
||||
strictEqual(openerp.web.strip_raw_chars('%a, %Y.eko %bren %da'), '%a, %Y. %b %d');
|
||||
test('ES date format', function (instance) {
|
||||
instance.web._t.database.parameters.date_format = '%a, %Y %b %d';
|
||||
var date = instance.web.str_to_date("2009-05-04");
|
||||
strictEqual(instance.web.format_value(date, {type:"date"}),
|
||||
'Mon, 2009 May 04');
|
||||
strictEqual(instance.web.parse_value('Mon, 2009 May 04', {type: 'date'}),
|
||||
'2009-05-04');
|
||||
});
|
||||
test('ES date format', function () {
|
||||
openerp.web._t.database.parameters.date_format = '%a, %Y %b %d';
|
||||
var date = openerp.web.str_to_date("2009-05-04");
|
||||
strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009 May 04');
|
||||
strictEqual(openerp.web.parse_value('Mon, 2009 May 04', {type: 'date'}), '2009-05-04');
|
||||
});
|
||||
test('extended ES date format', function () {
|
||||
openerp.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da';
|
||||
var date = openerp.web.str_to_date("2009-05-04");
|
||||
strictEqual(openerp.web.format_value(date, {type:"date"}), 'Mon, 2009. May 04');
|
||||
strictEqual(openerp.web.parse_value('Mon, 2009. May 04', {type: 'date'}), '2009-05-04');
|
||||
test('extended ES date format', function (instance) {
|
||||
instance.web._t.database.parameters.date_format = '%a, %Y.eko %bren %da';
|
||||
var date = instance.web.str_to_date("2009-05-04");
|
||||
strictEqual(instance.web.format_value(date, {type:"date"}),
|
||||
'Mon, 2009. May 04');
|
||||
strictEqual(instance.web.parse_value('Mon, 2009. May 04', {type: 'date'}),
|
||||
'2009-05-04');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@@ -1,16 +1,13 @@
|
||||
$(document).ready(function () {
|
||||
var $fix = $('#qunit-fixture');
|
||||
|
||||
var instance;
|
||||
var baseSetup = function () {
|
||||
instance = openerp.testing.instanceFor('list_editable');
|
||||
|
||||
openerp.testing.loadTemplate(instance);
|
||||
|
||||
openerp.testing.mockifyRPC(instance);
|
||||
};
|
||||
|
||||
|
||||
openerp.testing.section('editor', {
|
||||
dependencies: ['web.list_editable'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
setup: function (instance, $s, mock) {
|
||||
mock('test.model:create', function () {
|
||||
return 42;
|
||||
});
|
||||
}
|
||||
}, function (test) {
|
||||
/**
|
||||
*
|
||||
* @param {String} name
|
||||
@@ -30,7 +27,7 @@ $(document).ready(function () {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array} fields
|
||||
* @param {Array} [fields]
|
||||
* @return {Object}
|
||||
*/
|
||||
function makeFormView(fields) {
|
||||
@@ -67,46 +64,37 @@ $(document).ready(function () {
|
||||
};
|
||||
}
|
||||
|
||||
module('editor', {
|
||||
setup: baseSetup
|
||||
});
|
||||
asyncTest('base-state', 2, function () {
|
||||
test('base-state', {asserts: 2}, function (instance, $fix) {
|
||||
var e = new instance.web.list.Editor({
|
||||
dataset: {ids: []},
|
||||
edition_view: function () {
|
||||
return makeFormView();
|
||||
}
|
||||
});
|
||||
e.appendTo($fix)
|
||||
.always(start)
|
||||
.fail(function (error) { ok(false, error && error.message); })
|
||||
return e.appendTo($fix)
|
||||
.done(function () {
|
||||
ok(!e.is_editing(), "should not be editing");
|
||||
ok(e.form instanceof instance.web.FormView,
|
||||
"should use default form type");
|
||||
});
|
||||
});
|
||||
asyncTest('toggle-edition-save', 4, function () {
|
||||
instance.session.responses['/web/dataset/call_kw:create'] = function () {
|
||||
return { result: 42 };
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_kw:read'] = function () {
|
||||
return { result: [{
|
||||
id: 42,
|
||||
a: false,
|
||||
b: false,
|
||||
c: false
|
||||
}]};
|
||||
};
|
||||
test('toggle-edition-save', {
|
||||
asserts: 4,
|
||||
setup: function (instance, $s, mock) {
|
||||
mock('test.model:read', function () {
|
||||
return [{id: 42, a: false, b: false, c: false}];
|
||||
});
|
||||
}
|
||||
}, function (instance, $fix) {
|
||||
var e = new instance.web.list.Editor({
|
||||
dataset: new instance.web.DataSetSearch(),
|
||||
dataset: new instance.web.DataSetSearch(null, 'test.model'),
|
||||
prepends_on_create: function () { return false; },
|
||||
edition_view: function () {
|
||||
return makeFormView([ field('a'), field('b'), field('c') ]);
|
||||
}
|
||||
});
|
||||
var counter = 0;
|
||||
e.appendTo($fix)
|
||||
return e.appendTo($fix)
|
||||
.then(function () {
|
||||
return e.edit({}, function () {
|
||||
++counter;
|
||||
@@ -117,26 +105,21 @@ $(document).ready(function () {
|
||||
equal(counter, 3, "should have configured all fields");
|
||||
return e.save();
|
||||
})
|
||||
.always(start)
|
||||
.fail(function (error) { ok(false, error && error.message); })
|
||||
.done(function (record) {
|
||||
ok(!e.is_editing(), "should have stopped editing");
|
||||
equal(record.id, 42, "should have newly created id");
|
||||
})
|
||||
});
|
||||
asyncTest('toggle-edition-cancel', 2, function () {
|
||||
instance.session.responses['/web/dataset/call_kw:create'] = function () {
|
||||
return { result: 42 };
|
||||
};
|
||||
test('toggle-edition-cancel', { asserts: 2 }, function (instance, $fix) {
|
||||
var e = new instance.web.list.Editor({
|
||||
dataset: new instance.web.DataSetSearch(),
|
||||
dataset: new instance.web.DataSetSearch(null, 'test.model'),
|
||||
prepends_on_create: function () { return false; },
|
||||
edition_view: function () {
|
||||
return makeFormView([ field('a'), field('b'), field('c') ]);
|
||||
}
|
||||
});
|
||||
var counter = 0;
|
||||
e.appendTo($fix)
|
||||
return e.appendTo($fix)
|
||||
.then(function () {
|
||||
return e.edit({}, function () {
|
||||
++counter;
|
||||
@@ -145,22 +128,20 @@ $(document).ready(function () {
|
||||
.then(function (form) {
|
||||
return e.cancel();
|
||||
})
|
||||
.always(start)
|
||||
.fail(function (error) { ok(false, error && error.message); })
|
||||
.done(function (record) {
|
||||
ok(!e.is_editing(), "should have stopped editing");
|
||||
ok(!record.id, "should have no id");
|
||||
})
|
||||
});
|
||||
asyncTest('toggle-save-required', 2, function () {
|
||||
instance.session.responses['/web/dataset/call_kw:create'] = function () {
|
||||
return { result: 42 };
|
||||
};
|
||||
test('toggle-save-required', {
|
||||
asserts: 2,
|
||||
fail_on_rejection: false
|
||||
}, function (instance, $fix) {
|
||||
var e = new instance.web.list.Editor({
|
||||
do_warn: function () {
|
||||
warnings++;
|
||||
},
|
||||
dataset: new instance.web.DataSetSearch(),
|
||||
dataset: new instance.web.DataSetSearch(null, 'test.model'),
|
||||
prepends_on_create: function () { return false; },
|
||||
edition_view: function () {
|
||||
return makeFormView([
|
||||
@@ -169,7 +150,7 @@ $(document).ready(function () {
|
||||
});
|
||||
var counter = 0;
|
||||
var warnings = 0;
|
||||
e.appendTo($fix)
|
||||
return e.appendTo($fix)
|
||||
.then(function () {
|
||||
return e.edit({}, function () {
|
||||
++counter;
|
||||
@@ -178,78 +159,73 @@ $(document).ready(function () {
|
||||
.then(function (form) {
|
||||
return e.save();
|
||||
})
|
||||
.always(start)
|
||||
.done(function () { ok(false, "cancel should not succeed"); })
|
||||
.fail(function () {
|
||||
equal(warnings, 1, "should have been warned");
|
||||
ok(e.is_editing(), "should have kept editing");
|
||||
})
|
||||
});
|
||||
});
|
||||
|
||||
module('list-edition', {
|
||||
setup: function () {
|
||||
baseSetup();
|
||||
|
||||
var records = {};
|
||||
_.extend(instance.session.responses, {
|
||||
'/web/view/load': function () {
|
||||
return {result: {
|
||||
type: 'tree',
|
||||
fields: {
|
||||
a: {type: 'char', string: "A"},
|
||||
b: {type: 'char', string: "B"},
|
||||
c: {type: 'char', string: "C"}
|
||||
},
|
||||
arch: {
|
||||
tag: 'tree',
|
||||
attrs: {},
|
||||
children: [
|
||||
{tag: 'field', attrs: {name: 'a'}},
|
||||
{tag: 'field', attrs: {name: 'b'}},
|
||||
{tag: 'field', attrs: {name: 'c'}}
|
||||
]
|
||||
}
|
||||
}};
|
||||
});
|
||||
openerp.testing.section('list.edition', {
|
||||
dependencies: ['web.list_editable'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
setup: function (instance, $s, mock) {
|
||||
var records = {};
|
||||
mock('demo:create', function (args) {
|
||||
records[42] = _.extend({}, args[0]);
|
||||
return 42;
|
||||
});
|
||||
mock('demo:read', function (args) {
|
||||
var id = args[0][0];
|
||||
if (id in records) {
|
||||
return [records[id]];
|
||||
}
|
||||
return [];
|
||||
});
|
||||
mock('/web/view/load', function () {
|
||||
return {
|
||||
type: 'tree',
|
||||
fields: {
|
||||
a: {type: 'char', string: "A"},
|
||||
b: {type: 'char', string: "B"},
|
||||
c: {type: 'char', string: "C"}
|
||||
},
|
||||
'/web/dataset/call_kw:create': function (params) {
|
||||
records[42] = _.extend({}, params.params.args[0]);
|
||||
return {result: 42};
|
||||
},
|
||||
'/web/dataset/call_kw:read': function (params) {
|
||||
var id = params.params.args[0][0];
|
||||
if (id in records) {
|
||||
return {result: [records[id]]};
|
||||
}
|
||||
return {result: []};
|
||||
arch: {
|
||||
tag: 'tree',
|
||||
attrs: {},
|
||||
children: [
|
||||
{tag: 'field', attrs: {name: 'a'}},
|
||||
{tag: 'field', attrs: {name: 'b'}},
|
||||
{tag: 'field', attrs: {name: 'c'}}
|
||||
]
|
||||
}
|
||||
})
|
||||
}
|
||||
});
|
||||
asyncTest('newrecord', 6, function () {
|
||||
};
|
||||
});
|
||||
}
|
||||
}, function (test) {
|
||||
test('newrecord', {asserts: 6}, function (instance, $fix, mock) {
|
||||
var got_defaults = false;
|
||||
instance.session.responses['/web/dataset/call_kw:default_get'] = function (params) {
|
||||
var fields = params.params.args[0];
|
||||
mock('demo:default_get', function (args) {
|
||||
var fields = args[0];
|
||||
deepEqual(
|
||||
fields, ['a', 'b', 'c'],
|
||||
"should ask defaults for all fields");
|
||||
got_defaults = true;
|
||||
return {result: {
|
||||
a: "qux",
|
||||
b: "quux"
|
||||
}};
|
||||
};
|
||||
return { a: "qux", b: "quux" };
|
||||
});
|
||||
|
||||
var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]);
|
||||
var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
|
||||
|
||||
l.appendTo($fix)
|
||||
return l.appendTo($fix)
|
||||
.then(l.proxy('reload_content'))
|
||||
.then(function () {
|
||||
return l.start_edition();
|
||||
})
|
||||
.always(start)
|
||||
.then(function () {
|
||||
ok(got_defaults, "should have fetched default values for form");
|
||||
|
||||
return l.save_edition();
|
||||
})
|
||||
.then(function (result) {
|
||||
@@ -260,45 +236,39 @@ $(document).ready(function () {
|
||||
"should have used default values");
|
||||
ok(!result.record.get('c'),
|
||||
"should have no value if there was no default");
|
||||
})
|
||||
.fail(function (e) { ok(false, e && e.message || e); });
|
||||
});
|
||||
|
||||
module('list-edition-events', {
|
||||
setup: function () {
|
||||
baseSetup();
|
||||
_.extend(instance.session.responses, {
|
||||
'/web/view/load': function () {
|
||||
return {result: {
|
||||
type: 'tree',
|
||||
fields: {
|
||||
a: {type: 'char', string: "A"},
|
||||
b: {type: 'char', string: "B"},
|
||||
c: {type: 'char', string: "C"}
|
||||
},
|
||||
arch: {
|
||||
tag: 'tree',
|
||||
attrs: {},
|
||||
children: [
|
||||
{tag: 'field', attrs: {name: 'a'}},
|
||||
{tag: 'field', attrs: {name: 'b'}},
|
||||
{tag: 'field', attrs: {name: 'c'}}
|
||||
]
|
||||
}
|
||||
}};
|
||||
},
|
||||
'/web/dataset/call_kw:read': function (params) {
|
||||
return {result: [{
|
||||
id: 1,
|
||||
a: 'foo',
|
||||
b: 'bar',
|
||||
c: 'baz'
|
||||
}]};
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
asyncTest('edition events', 4, function () {
|
||||
});
|
||||
openerp.testing.section('list.edition.events', {
|
||||
dependencies: ['web.list_editable'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
setup: function (instance, $s, mock) {
|
||||
mock('demo:read', function () {
|
||||
return [{ id: 1, a: 'foo', b: 'bar', c: 'baz' }];
|
||||
});
|
||||
mock('/web/view/load', function () {
|
||||
return {
|
||||
type: 'tree',
|
||||
fields: {
|
||||
a: {type: 'char', string: "A"},
|
||||
b: {type: 'char', string: "B"},
|
||||
c: {type: 'char', string: "C"}
|
||||
},
|
||||
arch: {
|
||||
tag: 'tree',
|
||||
attrs: {},
|
||||
children: [
|
||||
{tag: 'field', attrs: {name: 'a'}},
|
||||
{tag: 'field', attrs: {name: 'b'}},
|
||||
{tag: 'field', attrs: {name: 'c'}}
|
||||
]
|
||||
}
|
||||
};
|
||||
});
|
||||
}
|
||||
}, function (test) {
|
||||
test('edition events', {asserts: 4}, function (instance, $fix) {
|
||||
var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]);
|
||||
var o = {
|
||||
counter: 0,
|
||||
@@ -306,9 +276,8 @@ $(document).ready(function () {
|
||||
};
|
||||
var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
|
||||
l.on('edit:before edit:after', o, o.onEvent);
|
||||
l.appendTo($fix)
|
||||
return l.appendTo($fix)
|
||||
.then(l.proxy('reload_content'))
|
||||
.always(start)
|
||||
.then(function () {
|
||||
ok(l.options.editable, "should be editable");
|
||||
equal(o.counter, 0, "should have seen no event yet");
|
||||
@@ -317,11 +286,10 @@ $(document).ready(function () {
|
||||
.then(function () {
|
||||
ok(l.editor.is_editing(), "should be editing");
|
||||
equal(o.counter, 2, "should have seen two edition events");
|
||||
})
|
||||
.fail(function (e) { ok(false, e && e.message); });
|
||||
});
|
||||
});
|
||||
|
||||
asyncTest('edition events: cancelling', 3, function () {
|
||||
test('edition events: cancelling', {asserts: 3}, function (instance, $fix) {
|
||||
var edit_after = false;
|
||||
var ds = new instance.web.DataSetStatic(null, 'demo', null, [1]);
|
||||
var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
|
||||
@@ -331,9 +299,8 @@ $(document).ready(function () {
|
||||
l.on('edit:after', {}, function () {
|
||||
edit_after = true;
|
||||
});
|
||||
l.appendTo($fix)
|
||||
return l.appendTo($fix)
|
||||
.then(l.proxy('reload_content'))
|
||||
.always(start)
|
||||
.then(function () {
|
||||
ok(l.options.editable, "should be editable");
|
||||
return l.start_edition();
|
||||
@@ -343,19 +310,18 @@ $(document).ready(function () {
|
||||
ok(!l.editor.is_editing(), "should not be editing");
|
||||
ok(!edit_after, "should not have fired the edit:after event");
|
||||
return $.when();
|
||||
})
|
||||
.fail(function (e) { ok(false, e && e.message || e); });
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
module('list-edition-onwrite', {
|
||||
setup: function () {
|
||||
baseSetup();
|
||||
}
|
||||
});
|
||||
|
||||
asyncTest('record-to-read', 4, function () {
|
||||
instance.session.responses['/web/view/load'] = function () {
|
||||
return {result: {
|
||||
openerp.testing.section('list.edition.onwrite', {
|
||||
dependencies: ['web.list_editable'],
|
||||
rpc: 'mock',
|
||||
templates: true,
|
||||
}, function (test) {
|
||||
test('record-to-read', {asserts: 4}, function (instance, $fix, mock) {
|
||||
mock('/web/view/load', function () {
|
||||
return {
|
||||
type: 'tree',
|
||||
fields: {
|
||||
a: {type: 'char', string: "A"}
|
||||
@@ -367,35 +333,27 @@ $(document).ready(function () {
|
||||
{tag: 'field', attrs: {name: 'a'}}
|
||||
]
|
||||
}
|
||||
}};
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_kw:read'] = function (req) {
|
||||
if (_.isEmpty(req.params.args[0])) {
|
||||
return {result: []};
|
||||
} else if (_.isEqual(req.params.args[0], [1])) {
|
||||
return {result: [
|
||||
};
|
||||
});
|
||||
mock('demo:read', function (args, kwargs) {
|
||||
if (_.isEmpty(args[0])) {
|
||||
return [];
|
||||
} else if (_.isEqual(args[0], [1])) {
|
||||
return [
|
||||
{id: 1, a: 'some value'}
|
||||
]};
|
||||
} else if (_.isEqual(req.params.args[0], [42])) {
|
||||
return {result: [
|
||||
{id: 42, a: 'foo'}
|
||||
]};
|
||||
];
|
||||
} else if (_.isEqual(args[0], [42])) {
|
||||
return [ {id: 42, a: 'foo'} ];
|
||||
}
|
||||
throw new Error(JSON.stringify(req.params));
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_kw:default_get'] = function () {
|
||||
return {result: {}};
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_kw:create'] = function () {
|
||||
return {result: 1};
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_kw:on_write'] = function () {
|
||||
return {result: [42]};
|
||||
};
|
||||
throw new Error(JSON.stringify(_.toArray(arguments)));
|
||||
});
|
||||
mock('demo:default_get', function () { return {}; });
|
||||
mock('demo:create', function () { return 1; });
|
||||
mock('demo:on_write', function () { return [42]; });
|
||||
|
||||
var ds = new instance.web.DataSetStatic(null, 'demo', null, []);
|
||||
var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
|
||||
l.appendTo($fix)
|
||||
return l.appendTo($fix)
|
||||
.then(l.proxy('reload_content'))
|
||||
.then(function () {
|
||||
return l.start_edition();
|
||||
@@ -406,7 +364,6 @@ $(document).ready(function () {
|
||||
.then(function () {
|
||||
return l.save_edition();
|
||||
})
|
||||
.always(function () { start(); })
|
||||
.then(function () {
|
||||
strictEqual(ds.ids.length, 2,
|
||||
'should have id of created + on_write');
|
||||
@@ -418,8 +375,6 @@ $(document).ready(function () {
|
||||
strictEqual(
|
||||
$fix.find('tbody tr:eq(2)').css('color'), 'rgb(0, 0, 0)',
|
||||
'should have default color applied');
|
||||
}, function (e) {
|
||||
ok(false, e && e.message || e);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,45 +1,34 @@
|
||||
$(document).ready(function () {
|
||||
var openerp,
|
||||
create = function (o) {
|
||||
if (typeof Object.create === 'function') {
|
||||
return Object.create(o);
|
||||
}
|
||||
function Cls() {}
|
||||
Cls.prototype = o;
|
||||
return new Cls;
|
||||
};
|
||||
module('list-events', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.web.data(openerp);
|
||||
window.openerp.web.views(openerp);
|
||||
window.openerp.web.list(openerp);
|
||||
openerp.testing.section('list.events', {
|
||||
dependencies: ['web.list']
|
||||
}, function (test) {
|
||||
var create = function (o) {
|
||||
if (typeof Object.create === 'function') {
|
||||
return Object.create(o);
|
||||
}
|
||||
});
|
||||
test('Simple event triggering', function () {
|
||||
var e = create(openerp.web.list.Events), passed = false;
|
||||
function Cls() {}
|
||||
Cls.prototype = o;
|
||||
return new Cls;
|
||||
};
|
||||
test('Simple event triggering', function (instance) {
|
||||
var e = create(instance.web.list.Events), passed = false;
|
||||
e.bind('foo', function () { passed = true; });
|
||||
e.trigger('foo');
|
||||
ok(passed);
|
||||
});
|
||||
test('Bind all', function () {
|
||||
var e = create(openerp.web.list.Events), event = null;
|
||||
test('Bind all', function (instance) {
|
||||
var e = create(instance.web.list.Events), event = null;
|
||||
e.bind(null, function (ev) { event = ev; });
|
||||
e.trigger('foo');
|
||||
strictEqual(event, 'foo');
|
||||
});
|
||||
test('Propagate trigger params', function () {
|
||||
var e = create(openerp.web.list.Events), p = false;
|
||||
test('Propagate trigger params', function (instance) {
|
||||
var e = create(instance.web.list.Events), p = false;
|
||||
e.bind(null, function (_, param) { p = param });
|
||||
e.trigger('foo', true);
|
||||
strictEqual(p, true)
|
||||
});
|
||||
test('Bind multiple callbacks', function () {
|
||||
var e = create(openerp.web.list.Events), count;
|
||||
test('Bind multiple callbacks', function (instance) {
|
||||
var e = create(instance.web.list.Events), count;
|
||||
e.bind('foo', function () { count++; })
|
||||
.bind('bar', function () { count++; })
|
||||
.bind(null, function () { count++; })
|
||||
@@ -59,20 +48,20 @@ $(document).ready(function () {
|
||||
e.trigger('baz');
|
||||
strictEqual(count, 3);
|
||||
});
|
||||
test('Mixin events', function () {
|
||||
var cls = openerp.web.Class.extend({
|
||||
test('Mixin events', function (instance) {
|
||||
var cls = instance.web.Class.extend({
|
||||
method: function () { this.trigger('e'); }
|
||||
});
|
||||
cls.include(openerp.web.list.Events);
|
||||
var instance = new cls, triggered = false;
|
||||
cls.include(instance.web.list.Events);
|
||||
var i = new cls, triggered = false;
|
||||
|
||||
instance.bind('e', function () { triggered = true; });
|
||||
instance.method();
|
||||
i.bind('e', function () { triggered = true; });
|
||||
i.method();
|
||||
|
||||
ok(triggered);
|
||||
});
|
||||
test('Unbind all handlers', function () {
|
||||
var e = create(openerp.web.list.Events), passed = 0;
|
||||
test('Unbind all handlers', function (instance) {
|
||||
var e = create(instance.web.list.Events), passed = 0;
|
||||
e.bind('foo', function () { passed++; });
|
||||
e.trigger('foo');
|
||||
strictEqual(passed, 1);
|
||||
@@ -80,8 +69,8 @@ $(document).ready(function () {
|
||||
e.trigger('foo');
|
||||
strictEqual(passed, 1);
|
||||
});
|
||||
test('Unbind one handler', function () {
|
||||
var e = create(openerp.web.list.Events), p1 = 0, p2 = 0,
|
||||
test('Unbind one handler', function (instance) {
|
||||
var e = create(instance.web.list.Events), p1 = 0, p2 = 0,
|
||||
h1 = function () { p1++; }, h2 = function () { p2++; };
|
||||
e.bind('foo', h1);
|
||||
e.bind('foo', h2);
|
||||
@@ -93,29 +82,20 @@ $(document).ready(function () {
|
||||
strictEqual(p1, 1);
|
||||
strictEqual(p2, 2);
|
||||
});
|
||||
|
||||
module('list-records', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.web.data(openerp);
|
||||
window.openerp.web.views(openerp);
|
||||
window.openerp.web.list(openerp);
|
||||
}
|
||||
});
|
||||
test('Basic record initialization', function () {
|
||||
var r = new openerp.web.list.Record({qux: 3});
|
||||
});
|
||||
openerp.testing.section('list.records', {
|
||||
dependencies: ['web.list']
|
||||
}, function (test) {
|
||||
test('Basic record initialization', function (instance) {
|
||||
var r = new instance.web.list.Record({qux: 3});
|
||||
r.set('foo', 1);
|
||||
r.set('bar', 2);
|
||||
strictEqual(r.get('foo'), 1);
|
||||
strictEqual(r.get('bar'), 2);
|
||||
strictEqual(r.get('qux'), 3);
|
||||
});
|
||||
test('Change all the things', function () {
|
||||
var r = new openerp.web.list.Record(), changed = false, field;
|
||||
test('Change all the things', function (instance) {
|
||||
var r = new instance.web.list.Record(), changed = false, field;
|
||||
r.bind('change', function () { changed = true; });
|
||||
r.bind(null, function (e) { field = field || e.split(':')[1]});
|
||||
r.set('foo', 1);
|
||||
@@ -123,8 +103,8 @@ $(document).ready(function () {
|
||||
ok(changed);
|
||||
strictEqual(field, 'foo');
|
||||
});
|
||||
test('Change single field', function () {
|
||||
var r = new openerp.web.list.Record(), changed = 0;
|
||||
test('Change single field', function (instance) {
|
||||
var r = new instance.web.list.Record(), changed = 0;
|
||||
r.bind('change:foo', function () { changed++; });
|
||||
r.set('foo', 1);
|
||||
r.set('bar', 1);
|
||||
@@ -132,21 +112,12 @@ $(document).ready(function () {
|
||||
strictEqual(r.get('bar'), 1);
|
||||
strictEqual(changed, 1);
|
||||
});
|
||||
|
||||
module('list-collections', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.web.data(openerp);
|
||||
window.openerp.web.views(openerp);
|
||||
window.openerp.web.list(openerp);
|
||||
}
|
||||
});
|
||||
test('degenerate-fetch', function () {
|
||||
var c = new openerp.web.list.Collection();
|
||||
});
|
||||
openerp.testing.section('list.collections', {
|
||||
dependencies: ['web.list']
|
||||
}, function (test) {
|
||||
test('degenerate-fetch', function (instance) {
|
||||
var c = new instance.web.list.Collection();
|
||||
strictEqual(c.length, 0);
|
||||
c.add({id: 1, value: 2});
|
||||
c.add({id: 2, value: 3});
|
||||
@@ -155,16 +126,16 @@ $(document).ready(function () {
|
||||
strictEqual(c.length, 4);
|
||||
var r = c.at(2), r2 = c.get(1);
|
||||
|
||||
ok(r instanceof openerp.web.list.Record);
|
||||
ok(r instanceof instance.web.list.Record);
|
||||
strictEqual(r.get('id'), 3);
|
||||
strictEqual(r.get('value'), 5);
|
||||
|
||||
ok(r2 instanceof openerp.web.list.Record);
|
||||
ok(r2 instanceof instance.web.list.Record);
|
||||
strictEqual(r2.get('id'), 1);
|
||||
strictEqual(r2.get('value'), 2);
|
||||
});
|
||||
test('degenerate-indexed-add', function () {
|
||||
var c = new openerp.web.list.Collection([
|
||||
test('degenerate-indexed-add', function (instance) {
|
||||
var c = new instance.web.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
@@ -175,8 +146,8 @@ $(document).ready(function () {
|
||||
strictEqual(c.at(1).get('value'), 55);
|
||||
strictEqual(c.at(3).get('value'), 20);
|
||||
});
|
||||
test('degenerate-remove', function () {
|
||||
var c = new openerp.web.list.Collection([
|
||||
test('degenerate-remove', function (instance) {
|
||||
var c = new instance.web.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
@@ -188,9 +159,9 @@ $(document).ready(function () {
|
||||
equal(c.get(2), undefined);
|
||||
strictEqual(c.at(1).get('value'), 20);
|
||||
});
|
||||
test('degenerate-remove-bound', function () {
|
||||
test('degenerate-remove-bound', function (instance) {
|
||||
var changed = false,
|
||||
c = new openerp.web.list.Collection([ {id: 1, value: 5} ]);
|
||||
c = new instance.web.list.Collection([ {id: 1, value: 5} ]);
|
||||
c.bind('change', function () { changed = true; });
|
||||
var record = c.get(1);
|
||||
c.remove(record);
|
||||
@@ -198,8 +169,8 @@ $(document).ready(function () {
|
||||
ok(!changed, 'removed records should not trigger events in their ' +
|
||||
'parent collection');
|
||||
});
|
||||
test('degenerate-reset', function () {
|
||||
var event, obj, c = new openerp.web.list.Collection([
|
||||
test('degenerate-reset', function (instance) {
|
||||
var event, obj, c = new instance.web.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
@@ -218,9 +189,9 @@ $(document).ready(function () {
|
||||
strictEqual(c.length, 1);
|
||||
strictEqual(c.get(42).get('value'), 55);
|
||||
});
|
||||
test('degenerate-reset-bound', function () {
|
||||
test('degenerate-reset-bound', function (instance) {
|
||||
var changed = false,
|
||||
c = new openerp.web.list.Collection([ {id: 1, value: 5} ]);
|
||||
c = new instance.web.list.Collection([ {id: 1, value: 5} ]);
|
||||
c.bind('change', function () { changed = true; });
|
||||
var record = c.get(1);
|
||||
c.reset();
|
||||
@@ -229,9 +200,9 @@ $(document).ready(function () {
|
||||
'parent collection');
|
||||
});
|
||||
|
||||
test('degenerate-propagations', function () {
|
||||
test('degenerate-propagations', function (instance) {
|
||||
var values = [];
|
||||
var c = new openerp.web.list.Collection([
|
||||
var c = new instance.web.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
@@ -244,8 +215,8 @@ $(document).ready(function () {
|
||||
c.get(3).set('value', 21);
|
||||
deepEqual(values, [6, 11, 21]);
|
||||
});
|
||||
test('BTree', function () {
|
||||
var root = new openerp.web.list.Collection(),
|
||||
test('BTree', function (instance) {
|
||||
var root = new instance.web.list.Collection(),
|
||||
c = root.proxy('admin'),
|
||||
total = 0;
|
||||
c.add({id: 1, name: "Administrator", login: 'admin'});
|
||||
@@ -260,8 +231,8 @@ $(document).ready(function () {
|
||||
c.at(1).set('wealth', 5);
|
||||
strictEqual(total, 47);
|
||||
});
|
||||
test('degenerate-successor', function () {
|
||||
var root = new openerp.web.list.Collection([
|
||||
test('degenerate-successor', function (instance) {
|
||||
var root = new instance.web.list.Collection([
|
||||
{id: 1, value: 1},
|
||||
{id: 2, value: 2},
|
||||
{id: 3, value: 3},
|
||||
@@ -282,8 +253,8 @@ $(document).ready(function () {
|
||||
root.at(3).attributes,
|
||||
"wraparound should have no effect if not succ(last_record)");
|
||||
});
|
||||
test('successor', function () {
|
||||
var root = new openerp.web.list.Collection();
|
||||
test('successor', function (instance) {
|
||||
var root = new instance.web.list.Collection();
|
||||
root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]);
|
||||
root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]);
|
||||
root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]);
|
||||
@@ -298,8 +269,8 @@ $(document).ready(function () {
|
||||
root.get(3).attributes,
|
||||
"should wraparound within a collection");
|
||||
});
|
||||
test('degenerate-predecessor', function () {
|
||||
var root = new openerp.web.list.Collection([
|
||||
test('degenerate-predecessor', function (instance) {
|
||||
var root = new instance.web.list.Collection([
|
||||
{id: 1, value: 1},
|
||||
{id: 2, value: 2},
|
||||
{id: 3, value: 3},
|
||||
@@ -320,8 +291,8 @@ $(document).ready(function () {
|
||||
root.at(0).attributes,
|
||||
"wraparound should have no effect if not pred(first_record)");
|
||||
});
|
||||
test('predecessor', function () {
|
||||
var root = new openerp.web.list.Collection();
|
||||
test('predecessor', function (instance) {
|
||||
var root = new instance.web.list.Collection();
|
||||
root.proxy('first').add([{id: 1, value: 1}, {id: 2, value: 2}]);
|
||||
root.proxy('second').add([{id: 3, value: 3}, {id: 4, value: 5}]);
|
||||
root.proxy('third').add([{id: 5, value: 8}, {id: 6, value: 13}]);
|
||||
@@ -336,21 +307,12 @@ $(document).ready(function () {
|
||||
root.get(4).attributes,
|
||||
"should wraparound within a collection");
|
||||
});
|
||||
|
||||
module('list-hofs', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.web.data(openerp);
|
||||
window.openerp.web.views(openerp);
|
||||
window.openerp.web.list(openerp);
|
||||
}
|
||||
});
|
||||
test('each, degenerate', function () {
|
||||
var c = new openerp.web.list.Collection([
|
||||
});
|
||||
openerp.testing.section('list.collections.hom', {
|
||||
dependencies: ['web.list']
|
||||
}, function (test) {
|
||||
test('each, degenerate', function (instance) {
|
||||
var c = new instance.web.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
@@ -362,8 +324,8 @@ $(document).ready(function () {
|
||||
ids, [1, 2, 3],
|
||||
'degenerate collections should be iterated in record order');
|
||||
});
|
||||
test('each, deep', function () {
|
||||
var root = new openerp.web.list.Collection(),
|
||||
test('each, deep', function (instance) {
|
||||
var root = new instance.web.list.Collection(),
|
||||
ids = [];
|
||||
root.proxy('foo').add([
|
||||
{id: 1, value: 5},
|
||||
@@ -382,8 +344,8 @@ $(document).ready(function () {
|
||||
ids, [1, 2, 3, 10, 20, 30],
|
||||
'tree collections should be deeply iterated');
|
||||
});
|
||||
test('map, degenerate', function () {
|
||||
var c = new openerp.web.list.Collection([
|
||||
test('map, degenerate', function (instance) {
|
||||
var c = new instance.web.list.Collection([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
{id: 3, value: 20}
|
||||
@@ -395,8 +357,8 @@ $(document).ready(function () {
|
||||
ids, [1, 2, 3],
|
||||
'degenerate collections should be iterated in record order');
|
||||
});
|
||||
test('map, deep', function () {
|
||||
var root = new openerp.web.list.Collection();
|
||||
test('map, deep', function (instance) {
|
||||
var root = new instance.web.list.Collection();
|
||||
root.proxy('foo').add([
|
||||
{id: 1, value: 5},
|
||||
{id: 2, value: 10},
|
||||
@@ -414,29 +376,20 @@ $(document).ready(function () {
|
||||
ids, [1, 2, 3, 10, 20, 30],
|
||||
'tree collections should be deeply iterated');
|
||||
});
|
||||
|
||||
module("list-weirds", {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.chrome(openerp);
|
||||
// views loader stuff
|
||||
window.openerp.web.data(openerp);
|
||||
window.openerp.web.views(openerp);
|
||||
window.openerp.web.list(openerp);
|
||||
}
|
||||
});
|
||||
test('set-from-noid', function () {
|
||||
var root = new openerp.web.list.Collection();
|
||||
});
|
||||
openerp.testing.section('list.collection.weirdoes', {
|
||||
dependencies: ['web.list']
|
||||
}, function (test) {
|
||||
test('set-from-noid', function (instance) {
|
||||
var root = new instance.web.list.Collection();
|
||||
root.add({v: 3});
|
||||
root.at(0).set('id', 42);
|
||||
var record = root.get(42);
|
||||
equal(root.length, 1);
|
||||
equal(record.get('v'), 3, "should have fetched the original record");
|
||||
});
|
||||
test('set-from-previd', function () {
|
||||
var root = new openerp.web.list.Collection();
|
||||
test('set-from-previd', function (instance) {
|
||||
var root = new instance.web.list.Collection();
|
||||
root.add({id: 1, v: 2});
|
||||
root.get(1).set('id', 42);
|
||||
var record = root.get(42);
|
||||
|
||||
@@ -1,19 +1,11 @@
|
||||
$(document).ready(function () {
|
||||
var instance;
|
||||
var $fix = $('#qunit-fixture');
|
||||
|
||||
module('list.buttons', {
|
||||
setup: function () {
|
||||
instance = openerp.testing.instanceFor('list');
|
||||
|
||||
openerp.testing.loadTemplate(instance);
|
||||
|
||||
openerp.testing.mockifyRPC(instance);
|
||||
}
|
||||
});
|
||||
asyncTest('record-deletion', 2, function () {
|
||||
instance.session.responses['/web/view/load'] = function () {
|
||||
return {result: {
|
||||
openerp.testing.section('list.buttons', {
|
||||
dependencies: ['web.list', 'web.form'],
|
||||
rpc: 'mock',
|
||||
templates: true
|
||||
}, function (test) {
|
||||
test('record-deletion', {asserts: 2}, function (instance, $fix, mock) {
|
||||
mock('/web/view/load', function () {
|
||||
return {
|
||||
type: 'tree',
|
||||
fields: {
|
||||
a: {type: 'char', string: "A"}
|
||||
@@ -26,26 +18,25 @@ $(document).ready(function () {
|
||||
{tag: 'button', attrs: {type: 'object', name: 'foo'}}
|
||||
]
|
||||
}
|
||||
}};
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_kw:read'] = function (req) {
|
||||
var args = req.params.args[0];
|
||||
if (_.isEqual(args, [1, 2, 3])) {
|
||||
return {result: [
|
||||
};
|
||||
});
|
||||
mock('demo:read', function (args, kwargs) {
|
||||
if (_.isEqual(args[0], [1, 2, 3])) {
|
||||
return [
|
||||
{id: 1, a: 'foo'}, {id: 2, a: 'bar'}, {id: 3, a: 'baz'}
|
||||
]};
|
||||
} else if (_.isEqual(args, [2])) {
|
||||
];
|
||||
} else if (_.isEqual(args[0], [2])) {
|
||||
// button action virtually removed record
|
||||
return {result: []};
|
||||
return [];
|
||||
}
|
||||
throw new Error(JSON.stringify(req.params));
|
||||
};
|
||||
instance.session.responses['/web/dataset/call_button'] = function () {
|
||||
return {result: false};
|
||||
};
|
||||
throw new Error(JSON.stringify(_.toArray(arguments)));
|
||||
});
|
||||
mock('/web/dataset/call_button', function () { return false; });
|
||||
var ds = new instance.web.DataSetStatic(null, 'demo', null, [1, 2, 3]);
|
||||
var l = new instance.web.ListView({}, ds, false, {editable: 'top'});
|
||||
l.appendTo($fix)
|
||||
var l = new instance.web.ListView({
|
||||
do_action: openerp.testing.noop
|
||||
}, ds, false, {editable: 'top'});
|
||||
return l.appendTo($fix)
|
||||
.then(l.proxy('reload_content'))
|
||||
.then(function () {
|
||||
var d = $.Deferred();
|
||||
@@ -55,14 +46,11 @@ $(document).ready(function () {
|
||||
$fix.find('table tbody tr:eq(1) button').click();
|
||||
return d.promise();
|
||||
})
|
||||
.always(function () { start(); })
|
||||
.then(function () {
|
||||
strictEqual(l.records.length, 2,
|
||||
"should have 2 records left");
|
||||
strictEqual($fix.find('table tbody tr[data-id]').length, 2,
|
||||
"should have 2 rows left");
|
||||
}, function (e) {
|
||||
ok(false, e && e.message || e);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
openerp.testing.section('mutex', {
|
||||
dependencies: ['web.coresetup'],
|
||||
setup: function (instance) {
|
||||
}
|
||||
}, function (test) {
|
||||
test('simpleScheduling', function (instance) {
|
||||
var m = new $.Mutex();
|
||||
var def1 = $.Deferred();
|
||||
var def2 = $.Deferred();
|
||||
var p1 = m.exec(function() { return def1; });
|
||||
var p2 = m.exec(function() { return def2; });
|
||||
equal(p1.state(), "pending");
|
||||
equal(p2.state(), "pending");
|
||||
def1.resolve();
|
||||
equal(p1.state(), "resolved");
|
||||
equal(p2.state(), "pending");
|
||||
def2.resolve();
|
||||
equal(p1.state(), "resolved");
|
||||
equal(p2.state(), "resolved");
|
||||
});
|
||||
test('simpleScheduling2', function (instance) {
|
||||
var m = new $.Mutex();
|
||||
var def1 = $.Deferred();
|
||||
var def2 = $.Deferred();
|
||||
var p1 = m.exec(function() { return def1; });
|
||||
var p2 = m.exec(function() { return def2; });
|
||||
equal(p1.state(), "pending");
|
||||
equal(p2.state(), "pending");
|
||||
def2.resolve();
|
||||
equal(p1.state(), "pending");
|
||||
equal(p2.state(), "pending");
|
||||
def1.resolve();
|
||||
equal(p1.state(), "resolved");
|
||||
equal(p2.state(), "resolved");
|
||||
});
|
||||
test('reject', function (instance) {
|
||||
var m = new $.Mutex();
|
||||
var def1 = $.Deferred();
|
||||
var def2 = $.Deferred();
|
||||
var def3 = $.Deferred();
|
||||
var p1 = m.exec(function() {return def1;});
|
||||
var p2 = m.exec(function() {return def2;});
|
||||
var p3 = m.exec(function() {return def3;});
|
||||
equal(p1.state(), "pending");
|
||||
equal(p2.state(), "pending");
|
||||
equal(p3.state(), "pending");
|
||||
def1.resolve();
|
||||
equal(p1.state(), "resolved");
|
||||
equal(p2.state(), "pending");
|
||||
equal(p3.state(), "pending");
|
||||
def2.reject();
|
||||
equal(p1.state(), "resolved");
|
||||
equal(p2.state(), "rejected");
|
||||
equal(p3.state(), "pending");
|
||||
def3.resolve();
|
||||
equal(p1.state(), "resolved");
|
||||
equal(p2.state(), "rejected");
|
||||
equal(p3.state(), "resolved");
|
||||
});
|
||||
});
|
||||
@@ -1,58 +1,55 @@
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
module('Registry', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
openerp.web.Foo = {};
|
||||
openerp.web.Bar = {};
|
||||
openerp.web.Foo2 = {};
|
||||
}
|
||||
});
|
||||
test('key set', function () {
|
||||
var reg = new openerp.web.Registry();
|
||||
openerp.testing.section('registry', {
|
||||
dependencies: ['web.corelib'],
|
||||
setup: function (instance) {
|
||||
instance.web.Foo = {};
|
||||
instance.web.Bar = {};
|
||||
instance.web.Foo2 = {};
|
||||
}
|
||||
}, function (test) {
|
||||
test('key set', function (instance) {
|
||||
var reg = new instance.web.Registry();
|
||||
|
||||
reg.add('foo', 'openerp.web.Foo')
|
||||
.add('bar', 'openerp.web.Bar');
|
||||
strictEqual(reg.get_object('bar'), openerp.web.Bar);
|
||||
reg.add('foo', 'instance.web.Foo')
|
||||
.add('bar', 'instance.web.Bar');
|
||||
strictEqual(reg.get_object('bar'), instance.web.Bar);
|
||||
});
|
||||
test('extension', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
test('extension', function (instance) {
|
||||
var reg = new instance.web.Registry({
|
||||
foo: 'instance.web.Foo',
|
||||
bar: 'instance.web.Bar'
|
||||
});
|
||||
|
||||
var reg2 = reg.extend({ 'foo': 'openerp.web.Foo2' });
|
||||
strictEqual(reg.get_object('foo'), openerp.web.Foo);
|
||||
strictEqual(reg2.get_object('foo'), openerp.web.Foo2);
|
||||
var reg2 = reg.extend({ 'foo': 'instance.web.Foo2' });
|
||||
strictEqual(reg.get_object('foo'), instance.web.Foo);
|
||||
strictEqual(reg2.get_object('foo'), instance.web.Foo2);
|
||||
});
|
||||
test('remain-linked', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
test('remain-linked', function (instance) {
|
||||
var reg = new instance.web.Registry({
|
||||
foo: 'instance.web.Foo',
|
||||
bar: 'instance.web.Bar'
|
||||
});
|
||||
|
||||
var reg2 = reg.extend();
|
||||
reg.add('foo2', 'openerp.web.Foo2');
|
||||
strictEqual(reg.get_object('foo2'), openerp.web.Foo2);
|
||||
strictEqual(reg2.get_object('foo2'), openerp.web.Foo2);
|
||||
reg.add('foo2', 'instance.web.Foo2');
|
||||
strictEqual(reg.get_object('foo2'), instance.web.Foo2);
|
||||
strictEqual(reg2.get_object('foo2'), instance.web.Foo2);
|
||||
});
|
||||
test('multiget', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
test('multiget', function (instance) {
|
||||
var reg = new instance.web.Registry({
|
||||
foo: 'instance.web.Foo',
|
||||
bar: 'instance.web.Bar'
|
||||
});
|
||||
|
||||
strictEqual(reg.get_any(['qux', 'grault', 'bar', 'foo']),
|
||||
openerp.web.Bar);
|
||||
instance.web.Bar);
|
||||
});
|
||||
test('extended-multiget', function () {
|
||||
var reg = new openerp.web.Registry({
|
||||
foo: 'openerp.web.Foo',
|
||||
bar: 'openerp.web.Bar'
|
||||
test('extended-multiget', function (instance) {
|
||||
var reg = new instance.web.Registry({
|
||||
foo: 'instance.web.Foo',
|
||||
bar: 'instance.web.Bar'
|
||||
});
|
||||
var reg2 = reg.extend();
|
||||
strictEqual(reg2.get_any(['qux', 'grault', 'bar', 'foo']),
|
||||
openerp.web.Bar);
|
||||
instance.web.Bar);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,16 +1,8 @@
|
||||
$(document).ready(function () {
|
||||
var openerp;
|
||||
|
||||
module('Misordered resolution management', {
|
||||
setup: function () {
|
||||
openerp = window.openerp.init([]);
|
||||
window.openerp.web.corelib(openerp);
|
||||
window.openerp.web.coresetup(openerp);
|
||||
window.openerp.web.data(openerp);
|
||||
}
|
||||
});
|
||||
test('Resolve all correctly ordered, sync', function () {
|
||||
var dm = new openerp.web.DropMisordered(), flag = false;
|
||||
openerp.testing.section('misordered resolution managemeng', {
|
||||
dependencies: ['web.data']
|
||||
}, function (test) {
|
||||
test('Resolve all correctly ordered, sync', function (instance) {
|
||||
var dm = new instance.web.DropMisordered(), flag = false;
|
||||
|
||||
var d1 = $.Deferred(), d2 = $.Deferred(),
|
||||
r1 = dm.add(d1), r2 = dm.add(d2);
|
||||
@@ -23,8 +15,8 @@ $(document).ready(function () {
|
||||
|
||||
ok(flag);
|
||||
});
|
||||
test("Don't resolve mis-ordered, sync", function () {
|
||||
var dm = new openerp.web.DropMisordered(),
|
||||
test("Don't resolve mis-ordered, sync", function (instance) {
|
||||
var dm = new instance.web.DropMisordered(),
|
||||
done1 = false, done2 = false,
|
||||
fail1 = false, fail2 = false;
|
||||
|
||||
@@ -44,8 +36,8 @@ $(document).ready(function () {
|
||||
ok(done2);
|
||||
ok(!fail2);
|
||||
});
|
||||
test('Fail mis-ordered flag, sync', function () {
|
||||
var dm = new openerp.web.DropMisordered(true),
|
||||
test('Fail mis-ordered flag, sync', function (instance) {
|
||||
var dm = new instance.web.DropMisordered(true),
|
||||
done1 = false, done2 = false,
|
||||
fail1 = false, fail2 = false;
|
||||
|
||||
@@ -66,8 +58,8 @@ $(document).ready(function () {
|
||||
ok(!fail2);
|
||||
});
|
||||
|
||||
asyncTest('Resolve all correctly ordered, async', 1, function () {
|
||||
var dm = new openerp.web.DropMisordered();
|
||||
test('Resolve all correctly ordered, async', {asserts: 1}, function (instance) {
|
||||
var dm = new instance.web.DropMisordered();
|
||||
|
||||
var d1 = $.Deferred(), d2 = $.Deferred(),
|
||||
r1 = dm.add(d1), r2 = dm.add(d2);
|
||||
@@ -75,13 +67,12 @@ $(document).ready(function () {
|
||||
setTimeout(function () { d1.resolve(); }, 100);
|
||||
setTimeout(function () { d2.resolve(); }, 200);
|
||||
|
||||
$.when(r1, r2).done(function () {
|
||||
start();
|
||||
return $.when(r1, r2).done(function () {
|
||||
ok(true);
|
||||
});
|
||||
});
|
||||
asyncTest("Don't resolve mis-ordered, async", 4, function () {
|
||||
var dm = new openerp.web.DropMisordered(),
|
||||
test("Don't resolve mis-ordered, async", {asserts: 4}, function (instance) {
|
||||
var dm = new instance.web.DropMisordered(),
|
||||
done1 = false, done2 = false,
|
||||
fail1 = false, fail2 = false;
|
||||
|
||||
@@ -94,18 +85,20 @@ $(document).ready(function () {
|
||||
setTimeout(function () { d1.resolve(); }, 200);
|
||||
setTimeout(function () { d2.resolve(); }, 100);
|
||||
|
||||
var done = $.Deferred();
|
||||
setTimeout(function () {
|
||||
start();
|
||||
// d1 is in limbo
|
||||
ok(!done1);
|
||||
ok(!fail1);
|
||||
// d2 is resolved
|
||||
ok(done2);
|
||||
ok(!fail2);
|
||||
done.resolve();
|
||||
}, 400);
|
||||
return $.when(d1, d2, done);
|
||||
});
|
||||
asyncTest('Fail mis-ordered flag, async', 4, function () {
|
||||
var dm = new openerp.web.DropMisordered(true),
|
||||
test('Fail mis-ordered flag, async', {asserts: 4}, function (instance) {
|
||||
var dm = new instance.web.DropMisordered(true),
|
||||
done1 = false, done2 = false,
|
||||
fail1 = false, fail2 = false;
|
||||
|
||||
@@ -118,6 +111,7 @@ $(document).ready(function () {
|
||||
setTimeout(function () { d1.resolve(); }, 200);
|
||||
setTimeout(function () { d2.resolve(); }, 100);
|
||||
|
||||
var done = $.Deferred();
|
||||
setTimeout(function () {
|
||||
start();
|
||||
// d1 is failed
|
||||
@@ -126,6 +120,8 @@ $(document).ready(function () {
|
||||
// d2 is resolved
|
||||
ok(done2);
|
||||
ok(!fail2);
|
||||
done.resolve();
|
||||
}, 400);
|
||||
return $.when(d1, d2, done)
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,63 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html style="height: 100%">
|
||||
<head>
|
||||
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
|
||||
<title>OpenERP Web Test Suite</title>
|
||||
<link rel="shortcut icon" href="/web/static/src/img/favicon.ico" type="image/x-icon"/>
|
||||
|
||||
<link rel="stylesheet" href="/web/static/lib/qunit/qunit.css">
|
||||
<script src="/web/static/lib/qunit/qunit.js" type="text/javascript"></script>
|
||||
|
||||
<script src="/web/static/lib/underscore/underscore.js" type="text/javascript"></script>
|
||||
<script src="/web/static/lib/underscore/underscore.string.js" type="text/javascript"></script>
|
||||
<script src="/web/static/lib/backbone/backbone.js" type="text/javascript"></script>
|
||||
|
||||
<!-- jquery -->
|
||||
<script src="/web/static/lib/jquery/jquery-1.8.2.js"></script>
|
||||
<script src="/web/static/lib/jquery.ui/js/jquery-ui-1.9.1.custom.js"></script>
|
||||
<script src="/web/static/lib/jquery.ba-bbq/jquery.ba-bbq.js"></script>
|
||||
|
||||
<script src="/web/static/lib/datejs/globalization/en-US.js"></script>
|
||||
<script src="/web/static/lib/datejs/core.js"></script>
|
||||
<script src="/web/static/lib/datejs/parser.js"></script>
|
||||
<script src="/web/static/lib/datejs/sugarpak.js"></script>
|
||||
<script src="/web/static/lib/datejs/extras.js"></script>
|
||||
|
||||
<script src="/web/static/lib/qweb/qweb2.js"></script>
|
||||
|
||||
<script src="/web/static/lib/py.js/lib/py.js"></script>
|
||||
|
||||
<script src="/web/static/src/js/boot.js"></script>
|
||||
<script src="/web/static/src/js/corelib.js"></script>
|
||||
<script src="/web/static/src/js/coresetup.js"></script>
|
||||
<script src="/web/static/src/js/dates.js"></script>
|
||||
<script src="/web/static/src/js/formats.js"></script>
|
||||
<script src="/web/static/src/js/chrome.js"></script>
|
||||
<script src="/web/static/src/js/data.js"></script>
|
||||
<script src="/web/static/src/js/views.js"></script>
|
||||
<script src="/web/static/src/js/search.js"></script>
|
||||
<script src="/web/static/src/js/view_form.js"></script>
|
||||
<script src="/web/static/src/js/view_list.js"></script>
|
||||
<script src="/web/static/src/js/view_list_editable.js"></script>
|
||||
|
||||
<script src="/web/static/test/testing.js"></script>
|
||||
<script type="text/javascript">
|
||||
QUnit.config.testTimeout = 2000;
|
||||
</script>
|
||||
</head>
|
||||
<body id="oe" class="openerp">
|
||||
<div id="qunit"></div>
|
||||
<div id="qunit-fixture"></div>
|
||||
</body>
|
||||
<script type="text/javascript" src="/web/static/test/class.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/registry.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/form.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/list-utils.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/formats.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/rpc.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/evals.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/search.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/Widget.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/list.js"></script>
|
||||
<script type="text/javascript" src="/web/static/test/list-editable.js"></script>
|
||||
</html>
|
||||
@@ -1,97 +1,244 @@
|
||||
// Test support structures and methods for OpenERP
|
||||
openerp.testing = (function () {
|
||||
var xhr = QWeb2.Engine.prototype.get_xhr();
|
||||
xhr.open('GET', '/web/static/src/xml/base.xml', false);
|
||||
xhr.send(null);
|
||||
var doc = xhr.responseXML;
|
||||
|
||||
var dependencies = {
|
||||
corelib: [],
|
||||
coresetup: ['corelib'],
|
||||
data: ['corelib', 'coresetup'],
|
||||
dates: [],
|
||||
formats: ['coresetup', 'dates'],
|
||||
chrome: ['corelib', 'coresetup'],
|
||||
views: ['corelib', 'coresetup', 'data', 'chrome'],
|
||||
search: ['data', 'coresetup', 'formats'],
|
||||
list: ['views', 'data'],
|
||||
form: ['data', 'views', 'list', 'formats'],
|
||||
list_editable: ['list', 'form', 'data'],
|
||||
openerp.testing.section('testing.stack', function (test) {
|
||||
// I heard you like tests, so I put tests in your testing infrastructure,
|
||||
// so you can test what you test
|
||||
var reject = function () {
|
||||
// utility function, rejects a success
|
||||
var args = _.toArray(arguments);
|
||||
return $.Deferred(function (d) {
|
||||
d.reject.apply(d, ["unexpected success"].concat(args));
|
||||
});
|
||||
};
|
||||
test('direct, value, success', {asserts: 1}, function () {
|
||||
var s = openerp.testing.Stack();
|
||||
return s.execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
strictEqual(val, 42, "should return the handler value");
|
||||
});
|
||||
});
|
||||
test('direct, deferred, success', {asserts: 1}, function () {
|
||||
var s = openerp.testing.Stack();
|
||||
return s.execute(function () {
|
||||
return $.when(42);
|
||||
}).then(function (val) {
|
||||
strictEqual(val, 42, "should return the handler value")
|
||||
});
|
||||
});
|
||||
test('direct, deferred, failure', {asserts: 1}, function () {
|
||||
var s = openerp.testing.Stack();
|
||||
return s.execute(function () {
|
||||
return $.Deferred(function (d) {
|
||||
d.reject("failed");
|
||||
});
|
||||
}).then(reject, function (f) {
|
||||
strictEqual(f, "failed", "should propagate failure");
|
||||
return $.when();
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
/**
|
||||
* Function which does not do anything
|
||||
*/
|
||||
noop: function () { },
|
||||
/**
|
||||
* Loads 'base.xml' template file into qweb for the provided instance
|
||||
*
|
||||
* @param instance openerp instance being initialized, to load the template file in
|
||||
*/
|
||||
loadTemplate: function (instance) {
|
||||
instance.web.qweb.add_template(doc);
|
||||
},
|
||||
/**
|
||||
* Alter provided instance's ``session`` attribute to make response
|
||||
* mockable:
|
||||
*
|
||||
* * The ``responses`` parameter can be used to provide a map of (RPC)
|
||||
* paths (e.g. ``/web/view/load``) to a function returning a response
|
||||
* to the query.
|
||||
* * ``instance.session`` grows a ``responses`` attribute which is
|
||||
* a map of the same (and is in fact initialized to the ``responses``
|
||||
* parameter if one is provided)
|
||||
*
|
||||
* Note that RPC requests to un-mocked URLs will be rejected with an
|
||||
* error message: only explicitly specified urls will get a response.
|
||||
*
|
||||
* Mocked sessions will *never* perform an actual RPC connection.
|
||||
*
|
||||
* @param instance openerp instance being initialized
|
||||
* @param {Object} [responses]
|
||||
*/
|
||||
mockifyRPC: function (instance, responses) {
|
||||
var session = instance.session;
|
||||
session.responses = responses || {};
|
||||
session.rpc_function = function (url, payload) {
|
||||
var fn = this.responses[url.url + ':' + payload.params.method]
|
||||
|| this.responses[url.url];
|
||||
test('successful setup', {asserts: 2}, function () {
|
||||
var setup_done = false;
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(function () {
|
||||
return $.Deferred(function (d) {
|
||||
setTimeout(function () {
|
||||
setup_done = true;
|
||||
d.resolve(2);
|
||||
}, 50);
|
||||
});
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
ok(setup_done, "should have executed setup");
|
||||
strictEqual(val, 42, "should return executed function value (not setup)");
|
||||
});
|
||||
});
|
||||
test('successful teardown', {asserts: 2}, function () {
|
||||
var teardown = false;
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(null, function () {
|
||||
return $.Deferred(function (d) {
|
||||
setTimeout(function () {
|
||||
teardown = true;
|
||||
d.resolve(2);
|
||||
}, 50);
|
||||
});
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
ok(teardown, "should have executed teardown");
|
||||
strictEqual(val, 42, "should return executed function value (not setup)");
|
||||
});
|
||||
});
|
||||
test('successful setup and teardown', {asserts: 3}, function () {
|
||||
var setup = false, teardown = false;
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(function () {
|
||||
return $.Deferred(function (d) {
|
||||
setTimeout(function () {
|
||||
setup = true;
|
||||
d.resolve(2);
|
||||
}, 50);
|
||||
});
|
||||
}, function () {
|
||||
return $.Deferred(function (d) {
|
||||
setTimeout(function () {
|
||||
teardown = true;
|
||||
d.resolve(2);
|
||||
}, 50);
|
||||
});
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
ok(setup, "should have executed setup");
|
||||
ok(teardown, "should have executed teardown");
|
||||
strictEqual(val, 42, "should return executed function value (not setup)");
|
||||
});
|
||||
});
|
||||
|
||||
if (!fn) {
|
||||
return $.Deferred().reject({}, 'failed',
|
||||
_.str.sprintf("Url %s not found in mock responses, with arguments %s",
|
||||
url.url, JSON.stringify(payload.params))
|
||||
).promise();
|
||||
}
|
||||
return $.when(fn(payload));
|
||||
};
|
||||
},
|
||||
/**
|
||||
* Creates an openerp web instance loading the specified module after
|
||||
* all of its dependencies.
|
||||
*
|
||||
* @param {String} module
|
||||
* @returns OpenERP Web instance
|
||||
*/
|
||||
instanceFor: function (module) {
|
||||
var instance = openerp.init([]);
|
||||
this._load(instance, module);
|
||||
return instance;
|
||||
},
|
||||
_load: function (instance, module, loaded) {
|
||||
if (!loaded) { loaded = []; }
|
||||
test('multiple setups', {asserts: 2}, function () {
|
||||
var setups = 0;
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(function () {
|
||||
setups++;
|
||||
}).push(function () {
|
||||
setups++;
|
||||
}).push(function () {
|
||||
setups++;
|
||||
}).push(function () {
|
||||
setups++;
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
strictEqual(setups, 4, "should have executed all setups of stack");
|
||||
strictEqual(val, 42);
|
||||
});
|
||||
});
|
||||
test('multiple teardowns', {asserts: 2}, function () {
|
||||
var teardowns = 0;
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(null, function () {
|
||||
teardowns++;
|
||||
}).push(null, function () {
|
||||
teardowns++;
|
||||
}).push(null, function () {
|
||||
teardowns++;
|
||||
}).push(null, function () {
|
||||
teardowns++;
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
strictEqual(teardowns, 4, "should have executed all teardowns of stack");
|
||||
strictEqual(val, 42);
|
||||
});
|
||||
});
|
||||
test('holes in setups', {asserts: 2}, function () {
|
||||
var setups = [];
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(function () {
|
||||
setups.push(0);
|
||||
}).push().push().push(function () {
|
||||
setups.push(3);
|
||||
}).push(function () {
|
||||
setups.push(4);
|
||||
}).push().push(function () {
|
||||
setups.push(6);
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
deepEqual(setups, [0, 3, 4, 6],
|
||||
"should have executed setups in correct order");
|
||||
strictEqual(val, 42);
|
||||
});
|
||||
});
|
||||
test('holes in teardowns', {asserts: 2}, function () {
|
||||
var teardowns = [];
|
||||
var s = openerp.testing.Stack();
|
||||
return s.push(null, function () {
|
||||
teardowns.push(0);
|
||||
}).push().push().push(null, function () {
|
||||
teardowns.push(3);
|
||||
}).push(null, function () {
|
||||
teardowns.push(4);
|
||||
}).push().push(null, function () {
|
||||
teardowns.push(6);
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(function (val) {
|
||||
deepEqual(teardowns, [6, 4, 3, 0],
|
||||
"should have executed teardowns in correct order");
|
||||
strictEqual(val, 42);
|
||||
});
|
||||
|
||||
var deps = dependencies[module];
|
||||
if (!deps) { throw new Error("Unknown dependencies for " + module); }
|
||||
});
|
||||
|
||||
var to_load = _.difference(deps, loaded);
|
||||
while (!_.isEmpty(to_load)) {
|
||||
this._load(instance, to_load[0], loaded);
|
||||
to_load = _.difference(deps, loaded);
|
||||
}
|
||||
openerp.web[module](instance);
|
||||
loaded.push(module);
|
||||
}
|
||||
}
|
||||
})();
|
||||
test('failed setup', {asserts: 5}, function () {
|
||||
var setup, teardown, teardown2, code;
|
||||
return openerp.testing.Stack().push(function () {
|
||||
setup = true;
|
||||
}, function () {
|
||||
teardown = true;
|
||||
}).push(function () {
|
||||
return $.Deferred().reject("Fail!");
|
||||
}, function () {
|
||||
teardown2 = true;
|
||||
}).execute(function () {
|
||||
code = true;
|
||||
return 42;
|
||||
}).then(reject, function (m) {
|
||||
ok(setup, "should have executed first setup function");
|
||||
ok(teardown, "should have executed first teardown function");
|
||||
ok(!teardown2, "should not have executed second teardown function");
|
||||
strictEqual(m, "Fail!", "should return setup failure message");
|
||||
ok(!code, "should not have executed callback");
|
||||
return $.when();
|
||||
});
|
||||
});
|
||||
test('failed teardown', {asserts: 2}, function () {
|
||||
var teardowns = 0;
|
||||
return openerp.testing.Stack().push(null, function () {
|
||||
teardowns++;
|
||||
return $.Deferred().reject('Fail 1');
|
||||
}).push(null, function () {
|
||||
teardowns++;
|
||||
}).push(null, function () {
|
||||
teardowns++;
|
||||
return $.Deferred().reject('Fail 3');
|
||||
}).execute(function () {
|
||||
return 42;
|
||||
}).then(reject, function (m) {
|
||||
strictEqual(teardowns, 3,
|
||||
"should have tried executing all teardowns");
|
||||
strictEqual(m, "Fail 3", "should return first failure message");
|
||||
return $.when();
|
||||
});
|
||||
});
|
||||
test('failed call + teardown', {asserts: 2}, function () {
|
||||
var teardowns = 0;
|
||||
return openerp.testing.Stack().push(null, function () {
|
||||
teardowns++;
|
||||
}).push(null, function () {
|
||||
teardowns++;
|
||||
return $.Deferred().reject('Fail 2');
|
||||
}).execute(function () {
|
||||
return $.Deferred().reject("code");
|
||||
}).then(reject, function (m) {
|
||||
strictEqual(teardowns, 2,
|
||||
"should have tried executing all teardowns");
|
||||
strictEqual(m, "code", "should return first failure message");
|
||||
return $.when();
|
||||
});
|
||||
});
|
||||
|
||||
test('arguments passing', {asserts: 9}, function () {
|
||||
var asserter = function (a, b, c) {
|
||||
strictEqual(a, 1);
|
||||
strictEqual(b, "foo");
|
||||
deepEqual(c, {bar: "baz", qux: 42});
|
||||
};
|
||||
|
||||
return openerp.testing.Stack()
|
||||
.push(asserter, asserter)
|
||||
.execute(asserter, 1, "foo", {bar: 'baz', qux: 42});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import xmlrpclib
|
||||
from ..common.openerplib.main import Connector
|
||||
|
||||
execute_map = {}
|
||||
|
||||
class TestConnector(Connector):
|
||||
def db_list_lang(self):
|
||||
return [('en_US', u'Test Language')]
|
||||
|
||||
def common_authenticate(self, db, login, password, environment):
|
||||
return 87539319
|
||||
|
||||
def common_login(self, db, login, password):
|
||||
return self.common_authenticate(db, login, password, {})
|
||||
|
||||
def object_execute_kw(self, db, uid, password, model, method, args, kwargs):
|
||||
if model in execute_map and hasattr(execute_map[model], method):
|
||||
return getattr(execute_map[model], method)(*args, **kwargs)
|
||||
|
||||
raise xmlrpclib.Fault({
|
||||
'model': model,
|
||||
'method': method,
|
||||
'args': args,
|
||||
'kwargs': kwargs
|
||||
}, '')
|
||||
|
||||
def send(self, service_name, method, *args):
|
||||
method_name = '%s_%s' % (service_name, method)
|
||||
if hasattr(self, method_name):
|
||||
return getattr(self, method_name)(*args)
|
||||
|
||||
raise xmlrpclib.Fault({
|
||||
'service': service_name,
|
||||
'method': method,
|
||||
'args': args
|
||||
}, '')
|
||||
@@ -1,42 +0,0 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from ..common import http, nonliterals
|
||||
from ..controllers.main import Session
|
||||
|
||||
UID = 87539319
|
||||
DB = 'test_db'
|
||||
LOGIN = 'test_login'
|
||||
PASSWORD = 'test_password'
|
||||
CONTEXT = {'lang': 'en_US', 'tz': 'UTC', 'uid': UID}
|
||||
|
||||
def bind(session):
|
||||
session.bind(DB, UID, LOGIN, PASSWORD)
|
||||
session.context = CONTEXT
|
||||
session.build_connection().set_login_info(DB, LOGIN, PASSWORD, UID)
|
||||
|
||||
class TestController(http.Controller):
|
||||
_cp_path = '/tests'
|
||||
|
||||
@http.jsonrequest
|
||||
def add_nonliterals(self, req, domains, contexts):
|
||||
return {
|
||||
'domains': [nonliterals.Domain(req.session, domain)
|
||||
for domain in domains],
|
||||
'contexts': [nonliterals.Context(req.session, context)
|
||||
for context in contexts]
|
||||
}
|
||||
|
||||
class TestSession(Session):
|
||||
_cp_path = '/web/session'
|
||||
|
||||
def session_info(self, req):
|
||||
if not req.session._uid:
|
||||
bind(req.session)
|
||||
|
||||
return {
|
||||
"session_id": req.session_id,
|
||||
"uid": req.session._uid,
|
||||
"context": CONTEXT,
|
||||
"db": req.session._db,
|
||||
"login": req.session._login,
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from . import test_dataset, test_menu, test_serving_base, test_view
|
||||
from . import test_dataset, test_menu, test_serving_base, test_view, test_js
|
||||
|
||||
fast_suite = []
|
||||
checks = [
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import urlparse
|
||||
from openerp import sql_db, tools
|
||||
from qunitsuite.suite import QUnitSuite
|
||||
|
||||
class WebSuite(QUnitSuite):
|
||||
def __init__(self):
|
||||
url = urlparse.urlunsplit([
|
||||
'http',
|
||||
'localhost:{port}'.format(port=tools.config['xmlrpc_port']),
|
||||
'/web/tests',
|
||||
'mod=*&source={db}&supadmin={supadmin}&password={password}'.format(
|
||||
db=tools.config['db_name'],
|
||||
supadmin=tools.config['db_password'] or 'admin',
|
||||
password=tools.config['admin_passwd'] or 'admin'),
|
||||
''
|
||||
])
|
||||
super(WebSuite, self).__init__(url, 50000)
|
||||
def run(self, result):
|
||||
if sql_db._Pool is not None:
|
||||
sql_db._Pool.close_all(sql_db.dsn(tools.config['db_name']))
|
||||
return super(WebSuite, self).run(result)
|
||||
|
||||
def load_tests(loader, standard_tests, _):
|
||||
standard_tests.addTest(WebSuite())
|
||||
return standard_tests
|
||||
@@ -0,0 +1,141 @@
|
||||
# Gujarati translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
||||
"PO-Revision-Date: 2012-11-17 12:42+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Gujarati <gu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 16278)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:11
|
||||
msgid "Calendar"
|
||||
msgstr "કૅલેન્ડર"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:70
|
||||
msgid "Filter"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:144
|
||||
msgid "Today"
|
||||
msgstr "આજે"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:145
|
||||
msgid "Day"
|
||||
msgstr "દિવસ"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:146
|
||||
msgid "Week"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:147
|
||||
msgid "Month"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:148
|
||||
msgid "New event"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:149
|
||||
msgid "Save"
|
||||
msgstr "સંગ્રહો"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:150
|
||||
msgid "Cancel"
|
||||
msgstr "રદ કરો"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:151
|
||||
msgid "Details"
|
||||
msgstr "વિગતો"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:152
|
||||
msgid "Edit"
|
||||
msgstr "ફેરફાર કરો"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:153
|
||||
msgid "Delete"
|
||||
msgstr "કાઢી નાંખો"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:155
|
||||
msgid "Event will be deleted permanently, are you sure?"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:156
|
||||
#: addons/web_calendar/static/src/js/calendar.js:169
|
||||
msgid "Description"
|
||||
msgstr "વર્ણન"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:157
|
||||
msgid "Time period"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:158
|
||||
msgid "Full day"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:161
|
||||
msgid "Do you want to edit the whole set of repeated events?"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:162
|
||||
msgid "Repeat event"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:163
|
||||
msgid "Disabled"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:164
|
||||
msgid "Enabled"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:167
|
||||
#: addons/web_calendar/static/src/js/calendar.js:175
|
||||
msgid "Agenda"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:168
|
||||
msgid "Date"
|
||||
msgstr "તારીખ"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/js/calendar.js:172
|
||||
msgid "Year"
|
||||
msgstr "વર્ષ"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:5
|
||||
#: addons/web_calendar/static/src/xml/web_calendar.xml:6
|
||||
msgid " "
|
||||
msgstr " "
|
||||
@@ -0,0 +1,74 @@
|
||||
# Gujarati translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
||||
"PO-Revision-Date: 2012-11-17 11:58+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Gujarati <gu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 16278)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:11
|
||||
msgid "Diagram"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:165
|
||||
msgid "Are you sure?"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:195
|
||||
msgid ""
|
||||
"Deleting this node cannot be undone.\n"
|
||||
"It will also delete all connected transitions.\n"
|
||||
"\n"
|
||||
"Are you sure ?"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:213
|
||||
msgid ""
|
||||
"Deleting this transition cannot be undone.\n"
|
||||
"\n"
|
||||
"Are you sure ?"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:224
|
||||
#: addons/web_diagram/static/src/js/diagram.js:257
|
||||
msgid "Activity"
|
||||
msgstr "પ્રવૃત્તિ"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:232
|
||||
#: addons/web_diagram/static/src/js/diagram.js:296
|
||||
msgid "Open: "
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:262
|
||||
#: addons/web_diagram/static/src/js/diagram.js:314
|
||||
msgid "Create:"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/js/diagram.js:289
|
||||
#: addons/web_diagram/static/src/js/diagram.js:308
|
||||
msgid "Transition"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_diagram/static/src/xml/base_diagram.xml:6
|
||||
msgid "New Node"
|
||||
msgstr ""
|
||||
@@ -0,0 +1,28 @@
|
||||
# Gujarati translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
||||
"PO-Revision-Date: 2012-11-17 10:36+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Gujarati <gu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 16278)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_gantt/static/src/js/gantt.js:11
|
||||
msgid "Gantt"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_gantt/static/src/xml/web_gantt.xml:10
|
||||
msgid "Create"
|
||||
msgstr "બનાવો"
|
||||
@@ -0,0 +1,98 @@
|
||||
# Gujarati translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
||||
"PO-Revision-Date: 2012-11-17 10:34+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Gujarati <gu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 16278)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/js/graph.js:19
|
||||
msgid "Graph"
|
||||
msgstr "આલેખ"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:5
|
||||
msgid "Graph Options"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:7
|
||||
msgid "Graph Mode"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:11
|
||||
msgid "Pie"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:12
|
||||
msgid "Bars"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:14
|
||||
msgid "Lines"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:15
|
||||
msgid "Areas"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:18
|
||||
msgid "Radar"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:20
|
||||
msgid "Legend"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:24
|
||||
msgid "Hidden"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:25
|
||||
msgid "Inside"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:26
|
||||
msgid "Top"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:28
|
||||
msgid "Actions"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:32
|
||||
msgid "Switch Axis"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:33
|
||||
msgid "Show Data"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_graph/static/src/xml/web_graph.xml:34
|
||||
msgid "Download as PNG"
|
||||
msgstr ""
|
||||
@@ -9,9 +9,7 @@
|
||||
*/
|
||||
/*global module:true, define:true*/
|
||||
!function (name, context, definition) {
|
||||
if (typeof module !== 'undefined') module.exports = definition(name, context);
|
||||
else if (typeof define === 'function' && typeof define.amd === 'object') define(definition);
|
||||
else context[name] = definition(name, context);
|
||||
context[name] = definition(name, context);
|
||||
}('bean', this, function (name, context) {
|
||||
var win = window
|
||||
, old = context[name]
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
# Gujarati translation for openerp-web
|
||||
# Copyright (c) 2012 Rosetta Contributors and Canonical Ltd 2012
|
||||
# This file is distributed under the same license as the openerp-web package.
|
||||
# FIRST AUTHOR <EMAIL@ADDRESS>, 2012.
|
||||
#
|
||||
msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: openerp-web\n"
|
||||
"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"POT-Creation-Date: 2012-07-02 09:06+0200\n"
|
||||
"PO-Revision-Date: 2012-11-17 11:38+0000\n"
|
||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||
"Language-Team: Gujarati <gu@li.org>\n"
|
||||
"MIME-Version: 1.0\n"
|
||||
"Content-Type: text/plain; charset=UTF-8\n"
|
||||
"Content-Transfer-Encoding: 8bit\n"
|
||||
"X-Launchpad-Export-Date: 2012-11-18 04:47+0000\n"
|
||||
"X-Generator: Launchpad (build 16278)\n"
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/js/kanban.js:10
|
||||
msgid "Kanban"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/js/kanban.js:293
|
||||
msgid "Undefined"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/js/kanban.js:471
|
||||
msgid "Are you sure you want to delete this record ?"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/js/kanban.js:839
|
||||
msgid "Create: "
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/xml/web_kanban.xml:41
|
||||
msgid "Show more... ("
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/xml/web_kanban.xml:41
|
||||
msgid "remaining)"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/xml/web_kanban.xml:71
|
||||
msgid "Add"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/xml/web_kanban.xml:71
|
||||
msgid "or"
|
||||
msgstr ""
|
||||
|
||||
#. openerp-web
|
||||
#: addons/web_kanban/static/src/xml/web_kanban.xml:72
|
||||
msgid "Cancel"
|
||||
msgstr ""
|
||||
|
||||
#~ msgid "Create"
|
||||
#~ msgstr "બનાવો"
|
||||
@@ -0,0 +1,14 @@
|
||||
from openerp.osv import orm, fields
|
||||
|
||||
class TestObject(orm.Model):
|
||||
_name = 'web_tests_demo.model'
|
||||
|
||||
_columns = {
|
||||
'name': fields.char("Name", required=True),
|
||||
'thing': fields.char("Thing"),
|
||||
'other': fields.char("Other", required=True)
|
||||
}
|
||||
_defaults = {
|
||||
'other': "bob"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
{
|
||||
'name': "Demonstration of web/javascript tests",
|
||||
'category': 'Hidden',
|
||||
'depends': ['web'],
|
||||
'js': ['static/src/js/demo.js'],
|
||||
'test': ['static/test/demo.js'],
|
||||
'qweb': ['static/src/xml/demo.xml'],
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
// static/src/js/demo.js
|
||||
openerp.web_tests_demo = function (instance) {
|
||||
instance.web_tests_demo = {
|
||||
value_true: true,
|
||||
SomeType: instance.web.Class.extend({
|
||||
init: function (value) {
|
||||
this.value = value;
|
||||
}
|
||||
})
|
||||
};
|
||||
};
|
||||
@@ -0,0 +1,7 @@
|
||||
<templates id="template" xml:space="preserve">
|
||||
<div t-name="DemoTemplate">
|
||||
<t t-foreach="5" t-as="value">
|
||||
<p><t t-esc="value"/></p>
|
||||
</t>
|
||||
</div>
|
||||
</templates>
|
||||
@@ -0,0 +1,102 @@
|
||||
openerp.testing.section('basic section', function (test) {
|
||||
test('my first test', function () {
|
||||
ok(true, "this test has run");
|
||||
});
|
||||
test('module content', function (instance) {
|
||||
ok(instance.web_tests_demo.value_true, "should have a true value");
|
||||
var type_instance = new instance.web_tests_demo.SomeType(42);
|
||||
strictEqual(type_instance.value, 42, "should have provided value");
|
||||
});
|
||||
test('DOM content', function (instance, $scratchpad) {
|
||||
$scratchpad.html('<div><span class="foo bar">ok</span></div>');
|
||||
ok($scratchpad.find('span').hasClass('foo'),
|
||||
"should have provided class");
|
||||
});
|
||||
test('clean scratchpad', function (instance, $scratchpad) {
|
||||
ok(!$scratchpad.children().length, "should have no content");
|
||||
ok(!$scratchpad.text(), "should have no text");
|
||||
});
|
||||
|
||||
test('templates', {templates: true}, function (instance) {
|
||||
var s = instance.web.qweb.render('DemoTemplate');
|
||||
var texts = $(s).find('p').map(function () {
|
||||
return $(this).text();
|
||||
}).get();
|
||||
|
||||
deepEqual(texts, ['0', '1', '2', '3', '4']);
|
||||
});
|
||||
|
||||
test('asynchronous', {
|
||||
asserts: 1
|
||||
}, function () {
|
||||
var d = $.Deferred();
|
||||
setTimeout(function () {
|
||||
ok(true);
|
||||
d.resolve();
|
||||
}, 100);
|
||||
return d;
|
||||
});
|
||||
test('unfail rejection', {
|
||||
asserts: 1,
|
||||
fail_on_rejection: false
|
||||
}, function () {
|
||||
var d = $.Deferred();
|
||||
setTimeout(function () {
|
||||
ok(true);
|
||||
d.reject();
|
||||
}, 100);
|
||||
return d;
|
||||
});
|
||||
|
||||
test('XML-RPC', {rpc: 'mock', asserts: 3}, function (instance, $s, mock) {
|
||||
mock('people.famous:name_search', function (args, kwargs) {
|
||||
strictEqual(kwargs.name, 'bob');
|
||||
return [
|
||||
[1, "Microsoft Bob"],
|
||||
[2, "Bob the Builder"],
|
||||
[3, "Silent Bob"]
|
||||
];
|
||||
});
|
||||
return new instance.web.Model('people.famous')
|
||||
.call('name_search', {name: 'bob'}).then(function (result) {
|
||||
strictEqual(result.length, 3, "shoud return 3 people");
|
||||
strictEqual(result[0][1], "Microsoft Bob",
|
||||
"the most famous bob should be Microsoft Bob");
|
||||
});
|
||||
});
|
||||
test('JSON-RPC', {rpc: 'mock', asserts: 3, templates: true}, function (instance, $s, mock) {
|
||||
var fetched_dbs = false, fetched_langs = false;
|
||||
mock('/web/database/get_list', function () {
|
||||
fetched_dbs = true;
|
||||
return ['foo', 'bar', 'baz'];
|
||||
});
|
||||
mock('/web/session/get_lang_list', function () {
|
||||
fetched_langs = true;
|
||||
return [['vo_IS', 'Hopelandic / Vonlenska']];
|
||||
});
|
||||
|
||||
// widget needs that or it blows up
|
||||
instance.webclient = {toggle_bars: openerp.testing.noop};
|
||||
var dbm = new instance.web.DatabaseManager({});
|
||||
return dbm.appendTo($s).then(function () {
|
||||
ok(fetched_dbs, "should have fetched databases");
|
||||
ok(fetched_langs, "should have fetched languages");
|
||||
deepEqual(dbm.db_list, ['foo', 'bar', 'baz']);
|
||||
});
|
||||
});
|
||||
|
||||
test('actual RPC', {rpc: 'rpc', asserts: 4}, function (instance) {
|
||||
var Model = new instance.web.Model('web_tests_demo.model');
|
||||
return Model.call('create', [{name: "Bob"}])
|
||||
.then(function (id) {
|
||||
return Model.call('read', [[id]]);
|
||||
}).then(function (records) {
|
||||
strictEqual(records.length, 1);
|
||||
var record = records[0];
|
||||
strictEqual(record.name, "Bob");
|
||||
strictEqual(record.thing, false);
|
||||
// default value
|
||||
strictEqual(record.other, 'bob');
|
||||
});
|
||||
});
|
||||
});
|
||||