diff --git a/addons/web/doc/module.rst b/addons/web/doc/module.rst index 138a8e91a4c..7971a919780 100644 --- a/addons/web/doc/module.rst +++ b/addons/web/doc/module.rst @@ -385,12 +385,53 @@ which for us means going to query the user's times. We don't have any records to get in our test, and we don't want to test the initialization yet! So let's cheat a bit: we can manually -:js:func:`set a widget's DOM `, let's create a basic DOM matching what each method expects then call the method: .. patch:: +The next group of patches (in terms of setup/complexity) is RPC tests: +testing components/methods which perform network calls (RPC +requests). In our module, ``start`` and ``watch_stop`` are in that +case: ``start`` fetches the user's recorded times and ``watch_stop`` +creates a new record with the current watch. + +By default, tests don't allow RPC requests and will generate an error +when trying to perform one: + +.. image:: module/testing_1.png + :align: center + +To allow them, the test case (or the test suite) has to explicitly opt +into :js:attr:`rpc support ` by adding the ``rpc: +'mock'`` option to the test case, and providing its own "rpc +responses": + +.. patch:: + +.. note:: + + By defaut, tests cases don't load templates either. We had not + needed to perform any template rendering before here, so we must + now enable templates loading via :js:attr:`the corresponding + option `. + +Our final test requires altering the module's code: asynchronous tests +use :doc:`deferred ` to know when a test ends and the other +one can start (otherwise test content will execute non-linearly and +the assertions of a test will be executed during the next test or +worse), but although ``watch_stop`` performs an asynchronous +``create`` operation it doesn't return a deferred we can synchronize +on. We simply need to return its result: + +.. patch:: + +This makes no difference to the original code, but allows us to write +our test: + +.. patch:: + .. [#DOM-building] they are not alternative solutions: they work very well together. Templates are used to build "just DOM", sub-widgets are used to build DOM subsections diff --git a/addons/web/doc/module/26 b/addons/web/doc/module/26 index 4085350db24..ec0b345a908 100644 --- a/addons/web/doc/module/26 +++ b/addons/web/doc/module/26 @@ -2,7 +2,7 @@ Index: web_example/static/src/tests/timer.js =================================================================== --- web_example.orig/static/src/tests/timer.js +++ web_example/static/src/tests/timer.js -@@ -42,4 +42,25 @@ openerp.testing.section('timer', functio +@@ -42,4 +42,33 @@ openerp.testing.section('timer', functio w.format_time(84092336), '23:21:32'); }); @@ -18,13 +18,21 @@ Index: web_example/static/src/tests/timer.js + w.update_counter(22733958); + // And check the DOM matches + strictEqual($fixture.text(), '06:18:53'); -+ ++ + w.update_counter(73451828) + strictEqual($fixture.text(), '20:24:11'); + }); + test('display_record', function (instance, $fixture) { + var w = new instance.web_example.Action(); + $fixture.append('
    ') -+ ok(false, "test display records"); ++ w.setElement($fixture); ++ ++ w.display_record({time: 41676639}); ++ w.display_record({time: 84092336}); ++ ++ var $lis = $fixture.find('li'); ++ strictEqual($lis.length, 2, "should have printed 2 records"); ++ strictEqual($lis[0].textContent, '11:34:36'); ++ strictEqual($lis[1].textContent, '23:21:32'); + }); }); diff --git a/addons/web/doc/module/27 b/addons/web/doc/module/27 new file mode 100644 index 00000000000..2061b7007e6 --- /dev/null +++ b/addons/web/doc/module/27 @@ -0,0 +1,28 @@ +Index: web_example/static/src/tests/timer.js +=================================================================== +--- web_example.orig/static/src/tests/timer.js ++++ web_example/static/src/tests/timer.js +@@ -71,4 +71,23 @@ openerp.testing.section('timer', functio + strictEqual($lis[0].textContent, '11:34:36'); + strictEqual($lis[1].textContent, '23:21:32'); + }); ++ test('start', {templates: true, rpc: 'mock', asserts: 3}, function (instance, $fixture, mock) { ++ // Rather odd-looking shortcut for search+read in a single RPC call ++ mock('/web/dataset/search_read', function () { ++ // ignore parameters, just return a pair of records. ++ return {records: [ ++ {time: 22733958}, ++ {time: 84092336} ++ ]}; ++ }); ++ ++ var w = new instance.web_example.Action(); ++ return w.appendTo($fixture) ++ .then(function () { ++ var $lis = $fixture.find('li'); ++ strictEqual($lis.length, 2); ++ strictEqual($lis[0].textContent, '06:18:53'); ++ strictEqual($lis[1].textContent, '23:21:32'); ++ }); ++ }); + }); diff --git a/addons/web/doc/module/28 b/addons/web/doc/module/28 new file mode 100644 index 00000000000..800e7a6f084 --- /dev/null +++ b/addons/web/doc/module/28 @@ -0,0 +1,13 @@ +Index: web_example/static/src/js/first_module.js +=================================================================== +--- web_example.orig/static/src/js/first_module.js ++++ web_example/static/src/js/first_module.js +@@ -66,7 +66,7 @@ openerp.web_example = function (instance + user_id: instance.session.uid, + time: time, + }; +- this.model.call('create', [record]).done(function () { ++ return this.model.call('create', [record]).done(function () { + self.display_record(record); + }); + }, diff --git a/addons/web/doc/module/29 b/addons/web/doc/module/29 new file mode 100644 index 00000000000..509d4b78662 --- /dev/null +++ b/addons/web/doc/module/29 @@ -0,0 +1,37 @@ +Index: web_example/static/src/tests/timer.js +=================================================================== +--- web_example.orig/static/src/tests/timer.js ++++ web_example/static/src/tests/timer.js +@@ -90,4 +90,32 @@ openerp.testing.section('timer', functio + strictEqual($lis[1].textContent, '23:21:32'); + }); + }); ++ test('watch_stop', {templates: true, rpc: 'mock', asserts: 3}, function (instance, $fix, mock) { ++ var created = false; ++ mock('web_example.stopwatch:create', function (args, kwargs) { ++ created = true; ++ // return a fake id (unused) ++ return 42; ++ }); ++ mock('/web/dataset/search_read', function () { ++ return {records: []}; ++ }); ++ ++ var w = new instance.web_example.Action(); ++ return w.appendTo($fix) ++ .then(function () { ++ // Virtual start point 5s before 'now' ++ w._start = new Date() - 5000; ++ return w.watch_stop(); ++ }) ++ .done(function () { ++ ok(created, "should have called create()"); ++ strictEqual($fix.find('.oe_web_example_timer').text(), ++ '00:00:05', ++ "should have updated the timer"); ++ strictEqual($fix.find('li')[0].textContent, ++ '00:00:05', ++ "should have added the new time to the list"); ++ }); ++ }); + }); diff --git a/addons/web/doc/module/series b/addons/web/doc/module/series index 491e7dc3c59..ff1a909a6af 100644 --- a/addons/web/doc/module/series +++ b/addons/web/doc/module/series @@ -22,3 +22,6 @@ 24 25 26 +27 +28 +29 diff --git a/addons/web/doc/module/testing_1.png b/addons/web/doc/module/testing_1.png new file mode 100644 index 00000000000..40cf32497eb Binary files /dev/null and b/addons/web/doc/module/testing_1.png differ diff --git a/addons/web/doc/testing.rst b/addons/web/doc/testing.rst index 600d379aa02..7ecf64288e1 100644 --- a/addons/web/doc/testing.rst +++ b/addons/web/doc/testing.rst @@ -327,6 +327,8 @@ a test case (or its containing test suite) through :js:attr:`~TestOptions.rpc`, and can be one of two modes: ``mock`` or ``rpc``. +.. _testing-rpc-mock: + Mock RPC ++++++++