1414- Tours (see `Integration Testing `_): tours simulate a real situation. They ensures that the
1515 python and the javascript parts properly talk to each other.
1616
17+ .. _testing/python :
18+
1719Testing Python code
1820===================
1921
2830.. code-block :: text
2931
3032 your_module
31- |-- ...
32- `-- tests
33- |-- __init__.py
34- |-- test_bar.py
35- `-- test_foo.py
33+ ├── ...
34+ ├── tests
35+ | ├── __init__.py
36+ | ├── test_bar.py
37+ | └── test_foo.py
3638
3739 and ``__init__.py `` contains::
3840
@@ -124,7 +126,7 @@ Subclasses of :class:`odoo.tests.common.BaseCase` (usually through
124126``standard `` and ``at_install `` by default.
125127
126128Invocation
127- ^^^^^^^^^^
129+ ~~~~~~~~~~
128130
129131:option: `--test-tags <odoo-bin --test-tags> ` can be used to select/filter tests
130132to run on the command-line. It implies :option: `--test-enable <odoo-bin --test-enable> `,
@@ -230,7 +232,7 @@ can be specified at once separated by a `,` like with regular tags.
230232.. _reference/testing/tags :
231233
232234Special tags
233- ^^^^^^^^^^^^
235+ ~~~~~~~~~~~~
234236
235237- ``standard ``: All Odoo tests that inherit from
236238 :class: `~odoo.tests.common.BaseCase ` are implicitly tagged standard.
@@ -248,7 +250,7 @@ Special tags
248250 ``-at_install `` when tagging a test class.
249251
250252Examples
251- ^^^^^^^^
253+ ~~~~~~~~
252254
253255.. important ::
254256
@@ -533,15 +535,175 @@ Tips
533535Integration Testing
534536===================
535537
536- Testing Python code and JS code separately is very useful, but it does not prove
537- that the web client and the server work together. In order to do that, we can
538- write another kind of test: tours. A tour is a mini scenario of some interesting
539- business flow. It explains a sequence of steps that should be followed. The
540- test runner will then create a Chrome headless browser, point it to the proper url
541- and simulate the click and inputs, according to the scenario.
538+ Testing Python code and JS code separately is very useful, but it does not prove that the web client
539+ and the server work together. In order to do that, we can write another kind of test: tours. A
540+ tour is a mini scenario of some interesting business flow. It explains a sequence of steps that
541+ should be followed. The test runner will then create a PhantomJs browser, point it to the proper
542+ url and simulate the click and inputs, according to the scenario.
543+
544+ Writing a test tour
545+ -------------------
546+
547+ Structure
548+ ~~~~~~~~~
549+
550+ To write a test tour for `your_module `, start with creating the required files:
551+
552+ .. code-block :: text
553+
554+ your_module
555+ ├── ...
556+ ├── static
557+ | └── tests
558+ | └── tours
559+ | └── your_tour.js
560+ ├── tests
561+ | ├── __init__.py
562+ | └── test_calling_the_tour.py
563+ └── __manifest__.py
564+
565+ You can then:
566+
567+ - update :file: `__manifest__.py ` to add :file: `your_tour.js ` in the assets.
568+
569+ .. code-block :: python
570+
571+ ' assets' : {
572+ ' web.assets_tests' : [
573+ ' your_module/static/tests/tours/your_tour.js' ,
574+ ],
575+ },
576+
577+ - update :file: `__init__.py ` in the folder :file: `tests ` to import :file: `test_calling_the_tour `.
578+
579+ .. seealso ::
580+ - :ref: `Assets Bundle <reference/assets_bundle >`
581+ - :ref: `testing/python `
582+
583+ Javascript
584+ ~~~~~~~~~~
585+
586+ #. Setup your tour by registering it.
587+
588+ .. code-block :: javascript
589+
590+ /** @odoo-module **/
591+ import tour from ' web_tour.tour' ;
592+ tour .register (' rental_product_configurator_tour' , {
593+ url: ' /web' , // Here, you can specify any other starting url
594+ test: true ,
595+ }, [
596+ // Your sequence of steps
597+ ]);
598+
599+ #. Add any step you want.
600+
601+ Every step contains at least a trigger. You can either use the `predefined steps
602+ <https://github.com/odoo/odoo/blob/15.0/addons/web_tour/static/src/js/tour_step_utils.js> `_ or write
603+ your own personalized step.
604+
605+ Here are some example of steps:
606+
607+ .. example ::
608+
609+ .. code-block :: javascript
610+
611+ // First step
612+ tour .stepUtils .showAppsMenuItem (),
613+ // Second step
614+ {
615+ trigger: ' .o_app[data-menu-xmlid="your_module.maybe_your_module_menu_root"]' ,
616+ edition: ' community' // Optional
617+ }, {
618+ // Third step
619+ },
620+
621+ .. example ::
622+
623+ .. code-block :: javascript
624+
625+ {
626+ trigger: ' .js_product:has(strong:contains(Chair floor protection)) .js_add' ,
627+ extra_trigger: ' .oe_advanced_configurator_modal' , // This ensure we are in the wizard
628+ },
629+
630+ .. example ::
631+
632+ .. code-block :: javascript
633+
634+ {
635+ trigger: ' a:contains("Add a product")' ,
636+ // Extra-trigger to make sure a line is added before trying to add another one
637+ extra_trigger: ' .o_field_many2one[name="product_template_id"] .o_external_button' ,
638+ },
639+
640+ Here are some possible arguments for your personalized steps:
641+
642+ - **trigger **: selector/element/jQuery you want to trigger
643+ - **extra-trigger **: optional selector/element/jQuery that needs to be present before the next
644+ step begins. This is especially useful when the tour needs to wait for a wizard to open, a
645+ line added to a list view...
646+ - **run **: optional action to run, defaults either to `click ` or `text Test ` if you are triggering
647+ an input. A multitude of actions are possible. Here are some of them: `click `, `dbclick `,
648+ `tripleclick `, `text Example `, `drag_and_drop selector1 selector2 `...
649+ - **edition **: optional,
650+
651+ - If you don't specify an edition, the step will be active in both community and enterprise.
652+ - Sometimes, a step will be different in enterprise or in community. You can then write two
653+ steps, one for the enterprise edition and one for the community one.
654+ - Generally, you want to specify an edition for steps that use the main menu as the main
655+ menus are different in community and enterprise.
656+ - **position **: optional
657+ - **id **: optional
658+ - **auto **: optional
659+ - **in_modal **: optional
660+
661+ .. tip ::
662+ Your browser's developer tools are your best tool to find the element your tour needs to use as a
663+ trigger/extra-trigger.
664+
665+ .. seealso ::
666+ - `jQuery documentation about find <https://api.jquery.com/find/ >`_
667+
668+ Python
669+ ~~~~~~
670+
671+ To start a tour from a python test, make the class inherit from
672+ :class: `~odoo.tests.common.HTTPCase `, and call `start_tour `:
673+
674+ .. code-block :: python
675+
676+ def test_your_test (self ):
677+ # Optional Setup
678+ self .start_tour(" /web" , ' your_module.your_tour_name' , login = " admin" )
679+ # Optional verifications
680+
681+ Debugging tips
682+ --------------
683+
684+ Running the tour in debug mode
685+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
686+
687+ First, activate the :doc: `developer mode </applications/general/developer_mode >` with
688+ `?debug=tests `. Then, open your debug menu and click on **Start Tour **. You can now launch your tour
689+ from there with the button `Test `.
690+
691+ You can also add this step in your tour to stop it right where you want it to:
692+
693+ .. code-block :: javascript
694+
695+ {
696+ trigger: " body" ,
697+ run : () => {debugger }
698+ }
699+
700+ .. caution ::
701+ Be aware that when running the tour, any data added to the setup of your python test won't be
702+ present in the tour unless you launched the test calling the tour with a breakpoint.
703+
542704
543705Screenshots and screencasts during browser_js tests
544- ---------------------------------------------------
706+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
545707
546708When running tests that use HttpCase.browser_js from the command line, the Chrome
547709browser is used in headless mode. By default, if a test fails, a PNG screenshot is
@@ -602,7 +764,7 @@ To specify this feature for a given model, the following methods and attributes
602764 on the model to enable database population.
603765
604766Example model
605- ^^^^^^^^^^^^^
767+ ~~~~~~~~~~~~~
606768
607769.. code-block :: python
608770
@@ -646,7 +808,7 @@ Example model
646808 return records
647809
648810 Population tools
649- ^^^^^^^^^^^^^^^^
811+ ~~~~~~~~~~~~~~~~
650812
651813Multiple population tools are available to easily create
652814the needed data generators.
0 commit comments