blob: 91df5480e35e4782104b13c2397c63f7d935aaa3 [file] [log] [blame]
Ankush Menat76dd6e92021-05-23 16:19:48 +05301# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
Rushabh Mehta982be9f2017-01-17 17:57:19 +05302# License: GNU General Public License v3. See license.txt
3
Ankush Menat76dd6e92021-05-23 16:19:48 +05304import copy
Ankush Menat06fa35a2021-09-14 20:05:16 +05305import unittest
Ankush Menat76dd6e92021-05-23 16:19:48 +05306from contextlib import contextmanager
Ankush Menat70c203d2021-09-15 19:24:35 +05307from typing import Any, Dict, NewType, Optional
Rushabh Mehta982be9f2017-01-17 17:57:19 +05308
9import frappe
Ankush Menat70c203d2021-09-15 19:24:35 +053010from frappe.core.doctype.report.report import get_report_module_dotted_path
11
12ReportFilters = Dict[str, Any]
13ReportName = NewType("ReportName", str)
Rushabh Mehta982be9f2017-01-17 17:57:19 +053014
Chillar Anand915b3432021-09-02 16:44:59 +053015
Ankush Menat06fa35a2021-09-14 20:05:16 +053016class ERPNextTestCase(unittest.TestCase):
17 """A sane default test class for ERPNext tests."""
18
Ankush Menatacdb26a2021-10-12 14:45:29 +053019
20 @classmethod
21 def setUpClass(cls) -> None:
Ankush Menat06fa35a2021-09-14 20:05:16 +053022 frappe.db.commit()
Ankush Menatacdb26a2021-10-12 14:45:29 +053023 return super().setUpClass()
Ankush Menat06fa35a2021-09-14 20:05:16 +053024
Ankush Menatacdb26a2021-10-12 14:45:29 +053025 @classmethod
26 def tearDownClass(cls) -> None:
Ankush Menat06fa35a2021-09-14 20:05:16 +053027 frappe.db.rollback()
Ankush Menatacdb26a2021-10-12 14:45:29 +053028 return super().tearDownClass()
Ankush Menat06fa35a2021-09-14 20:05:16 +053029
30
Rushabh Mehta982be9f2017-01-17 17:57:19 +053031def create_test_contact_and_address():
Rushabh Mehtaa0c41b72017-01-18 14:14:20 +053032 frappe.db.sql('delete from tabContact')
Nabin Hait1aa8c2e2020-03-26 13:15:31 +053033 frappe.db.sql('delete from `tabContact Email`')
34 frappe.db.sql('delete from `tabContact Phone`')
Rushabh Mehtaa0c41b72017-01-18 14:14:20 +053035 frappe.db.sql('delete from tabAddress')
36 frappe.db.sql('delete from `tabDynamic Link`')
Rushabh Mehta982be9f2017-01-17 17:57:19 +053037
Himanshu25ab1e42019-09-30 10:08:15 +053038 frappe.get_doc({
39 "doctype": "Address",
40 "address_title": "_Test Address for Customer",
41 "address_type": "Office",
42 "address_line1": "Station Road",
43 "city": "_Test City",
44 "state": "Test State",
45 "country": "India",
46 "links": [
47 {
48 "link_doctype": "Customer",
49 "link_name": "_Test Customer"
50 }
51 ]
52 }).insert()
Rushabh Mehtaa0c41b72017-01-18 14:14:20 +053053
Himanshu25ab1e42019-09-30 10:08:15 +053054 contact = frappe.get_doc({
55 "doctype": 'Contact',
56 "first_name": "_Test Contact for _Test Customer",
57 "links": [
58 {
59 "link_doctype": "Customer",
60 "link_name": "_Test Customer"
61 }
62 ]
63 })
64 contact.add_email("test_contact_customer@example.com", is_primary=True)
65 contact.add_phone("+91 0000000000", is_primary_phone=True)
66 contact.insert()
Ankush Menat76dd6e92021-05-23 16:19:48 +053067
68
69@contextmanager
70def change_settings(doctype, settings_dict):
71 """ A context manager to ensure that settings are changed before running
72 function and restored after running it regardless of exceptions occured.
73 This is useful in tests where you want to make changes in a function but
74 don't retain those changes.
75 import and use as decorator to cover full function or using `with` statement.
76
77 example:
78 @change_settings("Stock Settings", {"item_naming_by": "Naming Series"})
79 def test_case(self):
80 ...
81 """
82
83 try:
84 settings = frappe.get_doc(doctype)
85 # remember setting
86 previous_settings = copy.deepcopy(settings_dict)
87 for key in previous_settings:
88 previous_settings[key] = getattr(settings, key)
89
90 # change setting
91 for key, value in settings_dict.items():
92 setattr(settings, key, value)
93 settings.save()
94 yield # yield control to calling function
95
96 finally:
97 # restore settings
98 settings = frappe.get_doc(doctype)
99 for key, value in previous_settings.items():
100 setattr(settings, key, value)
101 settings.save()
Ankush Menat70c203d2021-09-15 19:24:35 +0530102
103
104def execute_script_report(
105 report_name: ReportName,
106 module: str,
107 filters: ReportFilters,
108 default_filters: Optional[ReportFilters] = None,
109 optional_filters: Optional[ReportFilters] = None
110 ):
111 """Util for testing execution of a report with specified filters.
112
113 Tests the execution of report with default_filters + filters.
114 Tests the execution using optional_filters one at a time.
115
116 Args:
117 report_name: Human readable name of report (unscrubbed)
118 module: module to which report belongs to
119 filters: specific values for filters
120 default_filters: default values for filters such as company name.
121 optional_filters: filters which should be tested one at a time in addition to default filters.
122 """
123
124 if default_filters is None:
125 default_filters = {}
126
127 report_execute_fn = frappe.get_attr(get_report_module_dotted_path(module, report_name) + ".execute")
128 report_filters = frappe._dict(default_filters).copy().update(filters)
129
130 report_data = report_execute_fn(report_filters)
131
132 if optional_filters:
133 for key, value in optional_filters.items():
134 filter_with_optional_param = report_filters.copy().update({key: value})
135 report_execute_fn(filter_with_optional_param)
136
137 return report_data