Liquid testing YAML syntax
YAML basics
YAML Ain't Markup Language (YAML) is a serialization language that has steadily increased in popularity over the last few years. It's often used as a format for configuration files, but its object serialization abilities make it a viable replacement for languages like JSON. YAML has broad language support and maps easily into native data structures. It's also easy for humans to read, which is why it's a good choice for configuration. The YAML acronym was shorthand for Yet Another Markup Language. But the maintainers renamed it to YAML Ain't Markup Language to place more emphasis on its data-oriented features.
General
Whitespace and indentation
Whitespace is part of YAML's formatting. Unless otherwise indicated, newlines indicate the end of a field. You structure a YAML document with indentation. Indentation in YAML is set by 2 spaces per level of nesting. Standard YAML does not support tabs, copy pasting tabs may lead to YAML errors.
my_minimal_test:
context:
period: 2021-12-31
data:
periods:
2021-12-31:
expectation:
results:
some_result: 123
Comments
Comments begin with a pound sign. They can appear after a document value or take up an entire line.
# what follows is our second test scenario
my_elaborate_test:
YAML datatypes
The key-value pair is YAML's basic building block. Every item in a YAML document is a member of at least one dictionary. The key is always a string. The value is a scalar so that it can be any datatype. So, the value can be a string, a number, or another dictionary.
Numeric values
YAML recognizes numeric types such as floating point, integer, decimal, hexadecimal or octal.
people:
ted_123: # external_id
amount_of_shares: 150
amount_of_votes: 50
expectation:
reconciled: true
results:
negative_non_deductible_taxes: 0
code_1201_D0: 10000.0
Strings
YAML strings are Unicode. In most situations, you don't have to specify them in quotes (see specifics below).
data:
# company data
company:
name: Acme Corporation
city: Gent
street: Lippenslaan 51
String values can span more than one line. With the fold (greater than) character, you can specify a string in a block. The pipe character has a similar function, but YAML interprets the field exactly as is.
# configuration
configuration: |
{% assign text = "something" %}
{% assign number = 123 %}
Boolean
YAML indicates boolean values with the keywords true
. False is indicated with false
.
# reconciliation data
reconciliations:
a_handle:
starred: true
Arrays
You can specify arrays or lists on a single line between brackets and separated by a comma sign.
data:
periods:
2021-09-30:
reconciliations:
recon:
results:
an_array: [null, false, 123, "123"]
Null
You enter nulls with unquoted null string literal or by leaving the result empty. However, as a best practice we would recommend the use of null.
expectation:
results:
test_null: null
NaN or infinity
Also NaN (not a number) or infinity elements are supported in YAML.
expectation:
reconciled: true
results:
# both work
test_inf: .NaN
test_inf_2: .inf
Anchors and aliases
If you have repeated sections in your .yml file, you might like to use YAML anchors. They can reduce effort and make updating in bulk easier.
There are 3 parts to this:
- The anchor
&
which defines a chunk of code - The alias
*
used to refer to that chunk elsewhere - You can use overrides with the characters
<<:
to add more values, or override existing ones.
periods:
2020-12-31: &period_blueprint
# account data
accounts:
"4000000":
name_en: "Customers"
name_nl: "Klanten"
id: 123456
value: 500
custom:
some_array.some_array_1: "foo"
2021-12-31:
<<: *period_blueprint
accounts: # override account value, but merge name, id and custom value
"4000000":
value: 666
Silverfin specific YAML basics
Code base
# unique tests in test suite
my_minimal_test:
context:
# end date of the period for which the code will be run
period: 2021-12-31
data:
periods:
2021-12-31:
expectation:
reconciled: false
excluded_results: [iXBRL]
results:
some_result: 123
# second unique tests in test suite
my_elaborate_test:
context:
# end date of the period for which the code will be run
period: 2021-12-31
# end date of the period to which data will be rollforwarded
rollforward_period: 2022-12-31
# UI language
locale: "nl"
# configuration
show_original_accounts_in_reconciliations: true
configuration: |
{% assign text = "something" %}
{% assign number = 123 %}
{% assign validate_account_drop = true %}
data:
# company data
company:
name: "Acme Corporation"
company_type: "consolidation"
company_form: "N.V."
currency: "EUR"
country: "BE"
city: "Gent"
street: "Lippenslaan 51"
vat_identifier: "BE-0844.568.333"
file_code: "12345"
sync_reference: "ref"
periods_per_year: 4
# Special book years
year_end: 2019-12-31
#personal company type
company_type: personal
first_name: "Jan"
last_name: "Van Testen"
national_insurance_number: 97.09.16-123.45
# analytical company type
analytical_dimensions:
1: #1-4 but stored as 0-3
BSO: #reference
code: 1234 #optional dimension ID
periods:
2024-12-31:
accounts:
140901:
value: 500
special_book_years:
2019-01-01: 2019-12-31
2020-01-01: 2020-12-31
periods:
# previous period exists
2019-12-31:
# populate data for current period
2020-12-31: &period_blueprint
# period custom input
custom:
some.thing: 50
# account data
accounts:
"4000000":
name_en: "Customers"
name_nl: "Klanten"
id: 123456 # only once, should be set on the first definition of an account in a company
value: 500
starred: true
mapped_number: "221000.000"
custom:
some_array.some_array_1: "foo"
"221000":
value: 1000
starred: true
name: "Buildings"
mapped_number: "221000.000"
results:
acc_example_result: "whatevs"
"173000":
value: -1000
starred: false
name: "Debt - long term"
mapped_number: "173000.000"
account_mapping_list:
name: "Customised mapping Company XYZ"
id: 123
marketplace_template_id: 321
adjustments:
internal:
100: # uuid (Universally unique identifier) should be a positive integer
transactions:
test_1: # NOTE should be unique per uuid
value: 100
account: 221000
test_2:
value: -100
account: 173000
purpose: testing #Purpose attribute allows to create an adjustment that belongs to a unique purpose
type: null
# reconciliation data
reconciliations:
a_handle:
starred: true
# regular custom drop
custom:
some.thing: "foo"
other.thing: "555"
# namespace as account.id
custom:
123456.thing: "some value"
# account collection
custom:
account.selector: "#123456789,#234567890"
# as:date input
custom:
some.date: "2020-12-31"
# fori input / custom collection
custom:
non_deduct_taxes.non_deduct_tax_1:
value: "10000"
py_value: "9000"
non_deduct_taxes.non_deduct_tax_2:
value: "11000"
py_value: "8000"
non_deduct_taxes.non_deduct_tax_3:
value: "12000"
py_value: "7000"
# as:boolean input
custom:
some.bool: true
# results from other templates
a_different_handle:
results:
a_null: null
a_bool: true
a_number: 123
a_string: "123"
an_array: [null, false, 123, "123"]
# custom from other templates
custom:
some_custom.input_from_other: "template
# people drop
people:
ted_123: # external_id
name: "Ted"
address_1: "some address line"
shareholder: "true"
director: "true"
amount_of_shares: 150
amount_of_votes: 50
director_start_date: "2013-01-11"
director_end_date: "2014-01-01"
payload: # custom methods
description: "a description"
payroll_id: 1111
phone: "555-1234"
2021-12-31:
<<: *period_blueprint
accounts: # override accounts, but merge reconciliations
"4000000":
value: 666
starred: true
reports:
balance_sheet_and_result: # NOTE handle of the report
name: "Balans + Resultaat + Verwerking"
results:
fixed_assets: 1000
2022-12-31: # added for rollforward purposes
# expected results
expectation:
reconciled: true
rollforward:
# regular input
123456.thing: "foo"
# fori
non_deduct_taxes.non_deduct_tax_1:
value: "10000"
py_value: "9000"
excluded_results: [iXBRL,result_abc,result_123]
results:
test_null: null
test_bool: true
test_number: 123
test_string: "123"
test_array: [null, false, 123, "123"]
test_date: "2021-31-12"
mapping_name: "Customised mapping Company XYZ"
mapping_id: 123
mapping_marketplace_template_id: 321
period_custom_some_thing: 50
#results for adjustments and transactions
internal_100_1_number: "221000"
internal_100_1_value: 100
internal_100_2_number: "173000"
internal_100_2_value: -100
fixed_assets_from_report: 1000
#results for personal companies
company_type: personal
company_first_name: "Jan"
company_last_name: "Van Testen"
company_national_insurance_number: 97.09.16-123.45
#results for analytical companies
analytical_accounts: 600.0
analytical_companies: 0
analytical_companies_codes: '1234'
analytical_companies_options: 'BSO'
Whitespace
As indicated, whitespace is part of YAML's formatting and you should structure a YAML document with indentation. Furthermore, YAML does not support tabs. However, our Ace editor inserts spaces when you press the TAB key, so when writing YAML code in our Silverfin editor you can use the tab key. Just be careful when storing or copy pasting the code elsewhere.
data:
periods:
2021-12-31:
# account data
accounts:
"4000000":
name_en: "Customers"
name_nl: "Klanten"
id: 123456 # only once, must be given early
value: 500
custom:
some_array.some_array_1: "foo"
Minimal requirements
Test name
, context period
, data period
, at least one expected result
and reconciliation status
should be provided to run a minimal test.
Note that in some cases, rollforward elements could also be mandatory (see below).
my_minimal_test:
context:
period: 2021-12-31
data:
periods:
2021-12-31:
expectation:
reconciled: true
results:
some_result: 123
Custom inputs
Even though YAML is Unicode and you don’t have to specify quotes to indicate string values in most cases, you will have to do this for all custom inputs (as:integer, as:currency,, as:accountcollection, etc.) _except for booleans. For boolean inputs the general rule applies (i.e. true or false without quotation marks).
Note that this is Silverfin specific behavior in YAML because of the way we store text property payloads.
Liquid code:
{% input custom.some.value as:currency %}
{% assign value = custom.some.value %}
{% result 'value' value %}
{% input custom.some.bool as:boolean %}
{% result 'boolean' custom.some.bool %}
Test suit:
reconciliations:
test_robin:
custom:
some.value: "300"
custom:
some.bool: true
Period custom inputs
Period.custom inputs often contain useful or even crucial information for your liquid tests. Period custom inputs hold the same attributes as local custom inputs.
{% input period.custom.some.thing as:currency assign:period_custom_some_thing %}
{% result 'period_custom_some_thing' period_custom_some_thing %}
These customs can be accessed directly on the custom drop and thus need to be defined on that specific drop and not on the reconciliations drop like local customs do.
Test suit:
data:
periods:
2021-12-31:
custom:
some.thing: 50
expectation:
results:
period_custom_some_thing: 50
For/fori loops
Within YAML each for/fori-loop should have a unique map-key, which consists of a namespace and namekey.
The nested custom-collection can hold multiple iterations for one/multiple iterations within the parent custom-collection. To ensure all map-keys remain unique on all collections, we define the elements of the parent custom-collection on the level of the nested custom-collection.
e.g.: For each iteration within the patrimony collection, we can define the kind and the location. Through the nested fori-loop, we can also define additional costs within the categories collection. To avoid nonunique map-keys, we build the YAML as follows:
Liquid code:
{% for building in custom.patrimony %}
{% input building.kind %}
{% input building.location %}
{% fori cost in custom.categories %}
{% input cost.name %}
{% endfori %}
{% endfor %}
Test suit:
reconciliations:
template_handle:
custom:
# define input-fields for-loop 1 "patrimony" --> name-keys should be unique
patrimony.patrimony_1:
kind: "Bungalow"
location: "Oostende"
# define inputfields for-loop 2 "patrimony" --> name-keys should be unique
patrimony.patrimony_2:
kind: "Appartment"
location: "Ghent"
# define inputfields (nested) fori loops "categories" --> name-keys should be unique
categories.categories_1:
patrimony_1_cost_1: "Cost 1: Maintenance Bungalow Oostende"
patrimony_2_cost_1: "Cost 1: Maintenance Appartment Ghent"
categories.categories_2:
patrimony_1_cost_2: "Cost 2: Renovation Bungalow Oostende"
patrimony_2_cost_2: "Cost 2: Renovation Appartment Ghent"
Use of account id and account name
As soon as an account is created, the id and/or name can’t be overwritten in following periods/rows.
If you create an account with elements id and/or name in one period/row, you should note that the elements id and name are the same for other periods/rows and these cannot be overwritten. This also means that if you create an account without id and/or name in one period/row, you cannot add an id and/or name in the next period/row.
data:
periods:
2017-12-31:
accounts:
"400000":
name: "Customers"
value: 500
id: 982597
2018-12-31:
accounts:
"400000":
name: "Customers"
value: 600
id: 982597
# id and name should be repeated from previous period and cannot be overwritten!
Company, account and people data
General rule applies, you don’t have to specify quotes to indicate string values (but you can if you want). Note that integer inputs need to be added without quotation marks (such as account value, amount of shares, etc.).
# both work
company:
name: "Acme Corporation"
company:
name: Acme Corporation
# custom inputs need quotes (except booleans)
custom:
reserves.text: "Hello"
reserves.value: "200"
reserves.boolean: true
accounts:
"4000000":
# both work
name_en: Customers
name_nl: "Klanten"
id: 123456 # only once, must be given early
value: 500
The people
drop is a bit different from the rest. For all methods already defined on the drop such as name, email, address_1, director_end_date, director_start_date... it follows the same structure as other drops (indented under the legal_person external id).
Custom methods, however, need to go under a block called payload
as seen in the example below:
people:
# both work
ted_123: # external_id
name: "Ted"
address_1: "Some address line"
director: true
amount_of_shares: 150
amount_of_votes: 50
director_start_date: 2016-01-01
director_end_date: 2023-12-31
payload: # custom methods (e.g. person.custom.payroll_id)
payroll_id: 001
robin_456: # external_id
name: "Robin the great"
address_1: "Biggest house of the street 12"
director: true
amount_of_shares: 150
amount_of_votes: 50
director_start_date: 2015-01-01
director_end_date: 2022-12-31
payload: # custom methods (e.g. person.custom.payroll_id)
payroll_id: 002
Company type
The key company_type
under the company
data can contain four values: regular, analytical, consolidation, personal.
data:
company:
company_type: "regular"
This relates to the following dropdown in the company data in the UI:
Important to know is that for the company_type
personal, this company drop only contains information about the first_name
, last_name
and national_insurance_number
:
simple_sample_test:
context:
period: 2021-12-31
data:
periods:
2021-12-31:
company:
company_type: personal
first_name: "Jan"
last_name: "Van Testen"
national_insurance_number: 97.09.16-123.45
expectation:
reconciled: false
results:
company_type: personal
company_first_name: "Jan"
company_last_name: "Van Testen"
company_national_insurance_number: 97.09.16-123.45
Analytical company type
Analytical reporting allows you to break down the figures by dimensions (e.g., country, branch, business unit, etc.). Silverfin supports up to four dimensions, each of which can have subdivisions. (see analytical type codes)
When writing liquid tests for an analytical company, you will need to define these dimensions in the data section.
Analytical dimensions refer to the analytical_type_x_codes
drop and thus should always be numbered 1 to 4 (note that these dimension are stored as 0 to 3). The reference can be any descriptive string of your choice.
Note that we currently only support the accounts-drop on the analytical_dimensions
.
Liquid code:
{% assign analytical_companies = company.analytical_type_1_codes %}
{% assign analytical_companies_options = consolidation_companies | map:"reference" | join:"|" %}
{% assign analytical_companies_codes = consolidation_companies | map:"code" | join:"|" %}
{% assign analytical_accounts = period.accounts | analytical_code:analytical_companies | range:140901 %}
YAML:
validate_analytical_company_type:
context:
period: 2024-12-31
data:
company:
name: "Analytical Company Type"
periods:
2024-12-31:
accounts:
140901:
value: 600
name: "Equity"
analytical_dimensions:
1: #1-4 but stored as 0-3
BSO: #reference
code: 1234 #optional dimension ID
periods:
2024-12-31:
accounts:
140901:
value: 500
expectation:
reconciled: false
results:
analytical_accounts: 600.0
analytical_companies: 0
analytical_companies_codes: '1234'
analytical_companies_options: 'BSO'
Locales
When writing your liquid test, you can access the locales
from our database. The key company.locales
under the company
data can contain different languages, depending on which languages were selected in the advanced settings (can only be done by an Admin user):
On the level of your client type, you can see all the supported languagues:
my_basic_test:
context:
period: 2021-12-31
data:
company:
name: Silverfin
locales: ['en']
periods:
2021-12-31:
expectation:
reconciled: false
results:
test_en: true
Results
- String results should be defined with quotation marks
- integer results should be defined without quotation marks
{% input custom.some.value as:currency %}
{% assign value = custom.some.value %}
{% result 'value' value %}
reconciliations:
test_robin:
custom:
some.value: "300"
expectation:
reconciled: true
results:
value: 300
Excluded results
Fed up with irrelevant results - such as the following iXBRL item - polluting your liquid tests?
The functionality excluded_results
now allows you to exclude these for your unit test. This block is defined as an array.
unit_1_test_1_debtors_note:
context:
period: 2024-12-31
data:
periods:
2024-12-31:
reconciliations:
debtors_note:
custom:
debtors.view: "minimal"
expectation:
reconciled: true
excluded_results: [iXBRL, result_abc, result_123]
results:
to_display_table_total_long_term_debtors: true
debtors_format_full: true
current_period_short_term_debtors: 2669850.0
previous_period_short_term_debtors: 2669850.0
Good to know:
- usage in combination with an alias is not accepted. Aliases will always render all the results from the respective anchor without taking the
excluded_results
into consideration.
- All results will be rendered unless specifically excluded in the respective array.
- We can only exclude results that are rendered by default, otherwise the test will fail:
As useful as the functionality is, we need to be equally careful. Due diligence is required when excluding items. We can only use this functionality when we are certain that these are absolutely irrelevant for the unit test and exclusion won’t impact future changes.
Reconciled
Like mentioned, the reconciliation status of the template is a mandatory expectation that should be provided in the minimal test scenario. Note that there is a slight difference in the reconciliation status calculation for liquid tests purposes compared to the reconciliation status of a template in input view. For liquid testing purposes, we do not take into consideration reconciliation type (i.e. reconciliation necessary but also valid without data, no reconciliation necessary, or reconciliation necessary and invalid without data), we simply look for the sum of all the unreconciled
tags.
In case there are no unreconciled
tags in the code, the reconciled status will be true
for liquid testing purposes.
As a best practice and to improve readability, we would recommend to always have reconciled
before results
in the test suite.
reconciled: true
results:
key: :value
Rollforward
Another element that should be added to the expectation section is the rollforward in case there is rollforward logic in your template (i.e. there are rollforward parameters in debug mode).
Related to the rollforward expectation, in the context section the rollforward_period can be defined. The rollforward_period identifies to which period data is being rollforwarded. This is not a mandatory element, so if it's not explicitly defined in the context section a default rollforward_period will be set (i.e. the current period). Note that in case a rollforward_period is specifically added to the context section, that particular period should then also be included in the data section.
Note that in case of fori rollforwards, also the last loop is being rollforwarded to nill and should therefore also be specifically added to the expectation section.
Finally, as for results, string values should be defined with quotation marks, integer values should be defined without quotation marks for the rollforward expectation section.
my_test:
context:
period: 2020-12-31
rollforward_period: 2021-12-31
data:
periods:
2020-12-31:
reconciliations:
silverfin_testing:
custom:
lines.line_1:
item_1: "foo"
item_2: "300"
2021-12-31:
expectation:
reconciled: true
rollforward:
lines.line_1:
item_1: "foo"
item_2: 300
lines.line_2:
item_1:
item_2:
results:
name: true
Account collection
There are three ways to populate an input as:account_collection :
- Account number
- Account id (as documented in debug section, e.g.: #982597)
- Full number (e.g.: 1000123$)
We would recommend to use either account number or account id when writing liquid tests.
data:
periods:
2017-12-31:
# account data
accounts:
"110100.000":
name_en: "Customers"
value: 500
id: 982597
reconciliations:
bank_recon:
# custom drop as account collection
custom:
account.selector: "110100.000"
reconciliations:
bank_recon:
# custom drop as account collection
custom:
account.selector: "#982597"
Locked and re-mapped accounts
When writting your liquid test, you can access the locked and re-mapped accounts from our database. This can come in handy when you want to access the mapping numbers from locked periods, and check the re-mapped accounts.
data:
periods:
2021-12-31:
accounts:
221000:
value: 1000
name: "Buildings"
mapped_number: "221000.000"
2022-12-31:
accounts:
221000:
value: 1000
name: "Buildings"
mapped_number: "221001.000"
This would mean that in our example, an account with original number 221000 would have a mapped number of 221001.000 in period 2022. For the locked period "2021", the locked mapped number is 221000.000.
Mapping list
Accessing the mapping list might be useful in different scenarios and thus different liquid tests. You can fetch the name, the id on firm level and the id of the mapping list on Marketplace. These values are all available on the period drop.
data:
periods:
2021-12-31:
account_mapping_list:
name: "Customised mapping Company XYZ"
id: 123
marketplace_template_id: 321
Show original number in accounts
In the 'Advanced' settings on firm level, there is a setting that only Silverfin admin users can configure. By activating the show original numbers in accounts, the original account numbers will be shown in your environment, instead of mapped account numbers.
You can access the settings of show_original_accounts_in_reconciliations
via liquid. The YAML syntax will look like this:
my_test:
context:
period: 2021-12-31
show_original_accounts_in_reconciliations: true
configuration: |
{% assign validate_account_drop = true %}
data:
periods:
2021-12-31:
accounts: &accounts_blueprint
221009:
value: -1000
starred: false
name: "Buildings - depreciations"
mapped_number: "221009.000"
results:
acc_example_result: "testing"
221000:
value: 1000
starred: true
name: "Buildings"
mapped_number: "221000.000"
results:
acc_example_result: "Building A"
expectation:
reconciled: false
results:
starred_account_name: "Buildings"
starred_account_number: "221000"
starred_account_original_number: "221000"
starred_account_mapped_number: "221000.000"
starred_account_result: "Building A"
Database data from other template
Whenever a custom drop is accessed from another template, this must be defined in the test, e.g.:
{% assign some_value = period.reconciliations.other_template.custom.specific.resident
| default:"Resident" %}
You should always include the handle of the template in the data section of your test to create a dependency. Even when in the liquid code a default value is assigned or when the custom drop is not relevant for your liquid tests. If you don’t do this you will get a (liquid) error. Which makes sense, as the liquid code is run as if the other template is not included in the company.
# data from other templates
other_template:
If a reconciliation text is missing in your liquid test, you will notice a liquid error. This liquid error will provide you some additional information about which reconciliation text is missing in your liquid test, by providing the exact handle
.
Results from other reconciliation templates
When your liquid code fetches results from other template, these results should be defined in your liquid test if no default is added in the liquid code (because otherwise it’s just empty).
{% assign value = period.reconciliations.other_template.results.value %}
reconciliations:
other_template:
results:
value: "300"
Adjustments and transactions
There are a few rules that should be applied when defining adjustments and their transactions in YAML:
- It is important to always define the accounts in the accounts-drop before calling on them in the adjustments-drop,
- We differentiate between internal and external items,
- The uuid (universally unique id) of adjustments should always be a positive integer.
- Each booking on an account is a unique transaction which means that the note (id) should also be unique.
Adjustment and underlying transactions:
Test suite:
data:
periods:
2021-12-31:
accounts:
221009:
value: -1000
starred: false
name: "Buildings - depreciations"
mapped_number: "221009.000"
results:
acc_example_result: "building A deprec"
221000:
value: 1000
starred: true
name: "Buildings"
mapped_number: "221000.000"
results:
acc_example_result: "building A cost"
173000:
value: -1000
starred: false
name: "Debt - long term"
mapped_number: "173000.000"
adjustments:
internal:
100: # uuid (Universally unique identifier) should be a positive integer
transactions:
test_1: # NOTE should be unique per uuid
value: 100
account: 221000
test_2:
value: -100
account: 173000
purpose: testing #Purpose attribute allows to create an adjustment that belongs to a unique purpose
type: null
external:
200:
transactions:
test_1: # NOTE should be unique per uuid
value: 100
account: 221000
test_2:
value: -100
account: 173000
purpose: testing
type: null
300:
transactions:
test_1: # NOTE should be unique per uuid
value: 300
account: 221000
test_2:
value: -100
account: 173000
test_3:
value: -200
account: 221009
purpose: testing
type: null
expectation:
reconciled: true
results:
internal_100: internal_100
external_200: external_200
external_300: external_300
internal_100_1_number: "221000"
internal_100_1_value: 100
internal_100_2_number: "173000"
internal_100_2_value: -100
external_200_1_number: "221000"
external_200_1_value: 100
external_200_2_number: "173000"
external_200_2_value: -100
external_300_1_number: "221000"
external_300_1_value: 300
external_300_2_number: "173000"
external_300_2_value: -100
external_300_3_number: "221009"
external_300_3_value: -200
Reports
Accessing information from reports might be useful in different scenarios and thus different liquid tests. You can fetch the name, handle and results. These values are all available on the report drop.
data:
periods:
2021-12-31:
reports:
balance_sheet_and_result:
name: "Balans + Resultaat + Verwerking"
results:
fixed_assets: 1000
expectation:
reconciled: true
results:
fixed_assets_from_report: 1000
The handle of the report can be found on admin level (in the general overview) or in the report itself:
Special book years
In case you want to run tests for broken or prolonged book years you should make use of the year_end and special_book_years element as such:
data:
company:
year_end: 2019-12-31
special_book_years:
2019-01-01: 2019-12-31
2020-01-01: 2022-09-30
periods:
2022-09-30:
As our database does not store period.year_start_dates, we have to mimic the calculation that happens in the backend, based on the values provided here:
- The
year_end
key equals the value mentioned in “Select the client’s end of first bookkeeping year” and bookyears consisting of 12 months will automatically be calculated based on this date. In the UI, these automatic bookyears are mentioned in “Fiscal years“ in light grey text. - If you need to define an irregular bookyear (bookyear != 12 months), you can define these using the
special_book_years
key. In the UI, aspecial_book_year
is the same as a bookyear in black text in “Fiscal years”. - If you need to define the
start_date
of your broken book year (irregular or regular length), we can also make use of thespecial_book_years
element.
A periods key with a date is also always required when defining bookyears, otherwise no ledgers are created.
As a best practice when using these special bookyears, make sure year_end
matches the end of the first bookyear.
Date format
In general, all places where you set a date the date format should be yyyy-mm-dd
. However, for custom inputs also other date formats are allowed like: dd-mm-yyyy
, dd/mm/yyyy
and yyyy/mm/dd
.
In order to avoid confusion and to make sure the YAML code is uniform, we would prefer to use the date format yyyy-mm-dd
in all situations. When used in custom inputs or in results, always use quotation marks as date objects are always converted as a string.
my_elaborate_test:
context:
# period for which the code will be run
period: 2021-12-31
data:
company:
year_end: 2021-12-31
periods:
2021-12-31:
reconciliations:
handle:
custom:
some.date: "2020-12-31"
expectation:
reconciled: true
results:
test_date: "2021-12-31"
Previous period
To make sure data from previous period(s) is included or to simply make sure the liquid method exists on the period drop returns true, you should just include the previous period in the data section.
data:
company:
year_end: 2021-12-31
periods:
2020-12-31:
2021-12-31:
reconciliations:
handle:
Future period
To make sure rollforward logic can be tested the future period should be included in the data section.
context:
# period for which the code will be run
period: 2021-12-31
rollforward_period: 2022-12-31
data:
company:
year_end: 2021-12-31
periods:
2021-12-31:
reconciliations:
handle:
custom:
some.date: "2020-12-31"
2022-12-31:
expectation:
reconciled: true
rollforward:
some.date: "2020-12-31"
results:
test_date: "2021-12-31"
Extra information
More information and basis for this document can be found here
Updated 12 days ago