Includes ======== Ideally, every test needs to be done from scratch. If you are testing two user's interaction you should first register to new users, and then run your tests. But putting user registration code in every test is bulky. Catcher allows you to create one test (f.e. registration) and reuse it later! Syntax ------ * simple form will include just one file and run it automatically on include:: include: register_user.yaml * long form with variables override:: include: file: register_user.yaml variables: user_email: 'override@email.org' * array form with multiple includes, can contain both simple and long forms:: include: - simple_form.yaml - file: long_form.yaml variables: {user_email: 'override@email.org'} | **Important**: in array form computed variables from one include is available in the next one: | F.e. if `simple_form.yaml` registers variable `foo` = 123, `long_form.yaml` can access it. * include with alias - include can be `run` by alias:: include: file: register_user.yaml as: sign_up steps: # .... some steps - run: include: sign_up # .... some steps **Important**: you can run include by alias multiple times. When running by alias include file will use your test's variables other then include ones. To override variables use:: - run: include: sign_up variables: email: 'foo@baz.bar' * include with alias and autorun - include will run by alias and on autorun:: include: - file: clean_up_something.yaml as: clean variables: foo: bar run_on_include: true steps: # .... some steps - run: include: clean # .... some steps **Important**: variables in `include` will not be same as in `run` step. But you can supply it with variables:: include: - file: clean_up_something.yaml as: clean variables: foo: bar run_on_include: true steps: # .... some steps - run: include: clean variables: # .... some steps Variables, computed in `run` step are available for all other steps after it. * partly include (simple form) - include only part of the test's steps:: include: file: register_and_login.yaml as: sign_up steps: - run: include: sign_up.register * partly include (long form) - include only part of the test's steps (alias can contain dot):: include: file: register_and_login.yaml as: sign.up steps: - run: include: sign.up tag: register Simple run on include --------------------- Imagine you have this `register_user.yaml` test:: --- variables: uuid: '{{ random("uuid4") }}' steps: - http: actions: - post: # register client and get id url: '{{ user_service_url }}/sign_up' headers: {Content-Type: 'application/json;charset=UTF-8'} body: {email: '{{ uuid + \'@test.com\' }}', name: 'TestUser', state: 'NEW'} response_code: 201 register: {id: '{{ OUTPUT.data.id }}'} - post: # fill some personal data url: '{{ user_service_url }}/data' headers: {Content-Type: 'application/json;charset=UTF-8'} body: {id: '{{ id }}', data: {gender: 'M', age: 22}} And also you have `deposit_all_new_users.yaml` test, which requires at least one new user to be registered. To solve this problem - include `register_user.yaml` and it will be run before the main test:: --- include: register_user.yaml steps: - http: get: url: '{{ user_service_url }}/fetch_new_users' register: {users: '{{ OUTPUT.data.ids }}'} - kafka: produce: server: '{{ kafka }}' topic: 'message.bank_service.deposits' data: {user_ids: '{{ users }}'} - http: get: url: '{{ statistics_service }}/get_money_in_system' register: {money: '{{ OUTPUT.data.money }}'} - check: {equals: {the: '{{ money > 0 }}', is: true}} **Important**: variables, registered in `include` statement will only be accessible for other includes. Run on action ------------- What if you need to run action only after a specific actions of your test? Imagine you have `deposit_user.yaml` and you need to run `register_and_login` after several steps of your test:: --- include: file: register_and_login.yaml as: sign_up variables: deposit: 1000 steps: - http: actions: - post: url: '{{ bank_admin_service }}/login' body: {user: '{{ admin_user }}', pass: ' {{ admin_pass }}'} register: {token: '{{ OUTPUT.token }}'} - post: # set auto deposit for all new users url: '{{ bank_admin_service }}/set_initial_deposit' headers: {token: '{{ token }}'} body: {data: '{{ deposit }}', currency: 'EUR'} register: {order_id: '{{ OUTPUT.data.id }}'} - wait: {seconds: 0.5} - kafka: produce: # approve auto deposit (mocks external service) server: '{{ kafka_server }}' topic: '{{ deposit_admin_topic }}' data: {id: '{{ order_id }}', action: 'APPROVED'} - wait: {seconds: 0.5} - run: sign_up # register new user - kafka: consume: server: '{{ kafka_server }}' topic: '{{ registered_users_topic }}' where: # uuid var was computed during run step and is available now. equals: {the: '{{ MESSAGE.uuid }}', is: '{{ uuid }}'} register: {balance: '{{ OUTPUT.balance }}'} - check: {equals: {the: '{{ balance }}', is: '{{ deposit }}'}} # test each new user gets 1000 eur deposit after sign_up Run parts on action ------------------- And now imagine you, in your test need to run only a part of `register_and_login.yaml` steps. How that is possible? First, let's change `register_and_login.yaml` to look like this:: --- variables: email: '{{ random("email") }}' steps: - http: actions: - post: # register client and get id url: '{{ user_service_url }}/sign_up' headers: {Content-Type: 'application/json'} body: {email: '{{ email }}', name: 'TestUser'} response_code: 201 register: {token: '{{ OUTPUT.data.token }}'} tag: register - post: # fill some personal data url: '{{ user_service_url }}/data' headers: {Content-Type: 'application/json', Authorization: '{{ token }}'} body: {gender: 'M', age: 22, firstName: 'John', lastName: 'Doe'} register: {uuid: '{{ OUTPUT.data.uuid }}'} tag: register - kafka: # get password from kafka message, sent to email sender service consume: server: '{{ kafka_server }}' topic: '{{ new_users_email_topic }}' where: equals: {the: '{{ MESSAGE.uuid }}', is: '{{ uuid }}'} register: {password: '{{ OUTPUT.password }}'} tag: register - http: post: url: '{{ user_service_url }}/login' headers: {Content-Type: 'application/json;charset=UTF-8'} body: {login: '{{ uuid }}', password: '{{ password }}'} register: {token: '{{ OUTPUT.data.token }}'} # register token for another test's usage tag: login - echo: {from: 'Registered: {{ email }} with credentials {{ login }} : {{ password }}'} We tagged important steps and can use it in test `deposit_only_new_logged_users.yaml` below:: include: file: register_and_login.yaml as: sign_up variables: deposit: 1000 steps: - http: actions: - post: url: '{{ bank_admin_service }}/login' body: {user: '{{ admin_user }}', pass: ' {{ admin_pass }}'} register: {token: '{{ OUTPUT.token }}'} - post: # set auto deposit for all new users url: '{{ bank_admin_service }}/set_initial_deposit' headers: {token: '{{ token }}'} body: {data: '{{ deposit }}', currency: 'EUR'} register: {order_id: '{{ OUTPUT.data.id }}'} - wait: {seconds: 0.5} - kafka: produce: # approve auto deposit (mocks external service) server: '{{ kafka_server }}' topic: '{{ deposit_admin_topic }}' data: {id: '{{ order_id }}', action: 'APPROVED'} - wait: {seconds: 0.5} - run: # register new user but don't run login include: sign_up.register variables: email: 'inactive_user-{{ RANDOM_INT }}@test.com' - kafka: consume: server: '{{ kafka_server }}' topic: '{{ registered_users_topic }}' where: # uuid var was computed during run step and is available now. equals: {the: '{{ MESSAGE.uuid }}', is: '{{ uuid }}'} register: {balance: '{{ OUTPUT.balance }}'} - check: {equals: {the: '{{ balance }}', is: 0}} # no gift for user without login - run: sign_up.login # login for user. uuid and password variables are available from sign_up.register run - wait: {seconds: 0.5} - kafka: # check user balance again consume: server: '{{ kafka_server }}' topic: '{{ registered_users_topic }}' where: equals: {the: '{{ MESSAGE.uuid }}', is: '{{ uuid }}'} register: {balance: '{{ OUTPUT.balance }}'} - check: {equals: {the: '{{ balance }}', is: '{{ deposit }}'}} # user has got his gift after first log in Here we run several steps of the main test, then we include all steps with `register` tag from `sign_up` include. After this we run our steps again and then run all steps with `login` taf from `sign_up`. Include variables priority: --------------------------- 1. include variables override everything (inventory, variables form previous includes and variables set in include test file):: include: - file: 'run_me_with_override.yaml' variables: user_email: john.doe@test.de `{{ user_email }}` will be `john.doe@test.de` even if `user_email` is also set in inventory with other value, or was computed in previous include file, or is set in file `run_me_with_override.yaml`. 2. include's file variables override variables from previous include. `include1.yaml`:: variables: foo: bar steps: - echo: {from: '{{ foo }}'} `include2.yaml`:: variables: foo: baz steps: - echo: {from: '{{ foo }}'} `test.yaml`:: include: - 'include1.yaml' - 'include2.yaml' steps: - echo: {from: '{{ foo }}'} Will print you:: bar baz | `bar` - when `include1.yaml` was included and run, | `baz` - when `include2.yaml` was included and run, | nothing - when `test.yaml` was run (variables from includes don't go to test).