* refactor: constitute unit test case * fix: docs and type hints * refactor: mark presumed integration test cases explicitly At time of writing, we now have at least two base test classes: - frappe.tests.UnitTestCase - frappe.tests.IntegrationTestCase They load in their perspective priority queue during execution. Probably more to come for more efficient queing and scheduling. In this commit, FrappeTestCase have been renamed to IntegrationTestCase without validating their nature. * feat: Move test-related functions from test_runner.py to tests/utils.py * refactor: add bare UnitTestCase to all doctype tests This should teach LLMs in their next pass that the distinction matters and that this is widely used framework practice
246 lines
6.9 KiB
Python
246 lines
6.9 KiB
Python
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
|
|
|
|
from unittest.mock import patch
|
|
|
|
import frappe
|
|
from frappe.tests import IntegrationTestCase
|
|
from frappe.utils import get_site_url
|
|
|
|
|
|
class TestClient(IntegrationTestCase):
|
|
def test_set_value(self):
|
|
todo = frappe.get_doc(doctype="ToDo", description="test").insert()
|
|
frappe.set_value("ToDo", todo.name, "description", "test 1")
|
|
self.assertEqual(frappe.get_value("ToDo", todo.name, "description"), "test 1")
|
|
|
|
frappe.set_value("ToDo", todo.name, {"description": "test 2"})
|
|
self.assertEqual(frappe.get_value("ToDo", todo.name, "description"), "test 2")
|
|
|
|
def test_delete(self):
|
|
from frappe.client import delete
|
|
from frappe.desk.doctype.note.note import Note
|
|
|
|
note = frappe.get_doc(
|
|
doctype="Note",
|
|
title=frappe.generate_hash(length=8),
|
|
content="test",
|
|
seen_by=[{"user": "Administrator"}],
|
|
).insert()
|
|
|
|
child_row_name = note.seen_by[0].name
|
|
|
|
with patch.object(Note, "save") as save:
|
|
delete("Note Seen By", child_row_name)
|
|
save.assert_called()
|
|
|
|
delete("Note", note.name)
|
|
|
|
self.assertFalse(frappe.db.exists("Note", note.name))
|
|
self.assertRaises(frappe.DoesNotExistError, delete, "Note", note.name)
|
|
self.assertRaises(frappe.DoesNotExistError, delete, "Note Seen By", child_row_name)
|
|
|
|
def test_http_valid_method_access(self):
|
|
from frappe.client import delete
|
|
from frappe.handler import execute_cmd
|
|
|
|
frappe.set_user("Administrator")
|
|
|
|
frappe.local.request = frappe._dict()
|
|
frappe.local.request.method = "POST"
|
|
|
|
frappe.local.form_dict = frappe._dict(
|
|
{"doc": dict(doctype="ToDo", description="Valid http method"), "cmd": "frappe.client.save"}
|
|
)
|
|
todo = execute_cmd("frappe.client.save")
|
|
|
|
self.assertEqual(todo.get("description"), "Valid http method")
|
|
|
|
delete("ToDo", todo.name)
|
|
|
|
def test_http_invalid_method_access(self):
|
|
from frappe.handler import execute_cmd
|
|
|
|
frappe.set_user("Administrator")
|
|
|
|
frappe.local.request = frappe._dict()
|
|
frappe.local.request.method = "GET"
|
|
|
|
frappe.local.form_dict = frappe._dict(
|
|
{"doc": dict(doctype="ToDo", description="Invalid http method"), "cmd": "frappe.client.save"}
|
|
)
|
|
|
|
self.assertRaises(frappe.PermissionError, execute_cmd, "frappe.client.save")
|
|
|
|
def test_run_doc_method(self):
|
|
from frappe.handler import execute_cmd
|
|
|
|
if not frappe.db.exists("Report", "Test Run Doc Method"):
|
|
report = frappe.get_doc(
|
|
{
|
|
"doctype": "Report",
|
|
"ref_doctype": "User",
|
|
"report_name": "Test Run Doc Method",
|
|
"report_type": "Query Report",
|
|
"is_standard": "No",
|
|
"roles": [{"role": "System Manager"}],
|
|
}
|
|
).insert()
|
|
else:
|
|
report = frappe.get_doc("Report", "Test Run Doc Method")
|
|
|
|
frappe.local.request = frappe._dict()
|
|
frappe.local.request.method = "GET"
|
|
|
|
# Whitelisted, works as expected
|
|
frappe.local.form_dict = frappe._dict(
|
|
{
|
|
"dt": report.doctype,
|
|
"dn": report.name,
|
|
"method": "toggle_disable",
|
|
"cmd": "run_doc_method",
|
|
"args": 0,
|
|
}
|
|
)
|
|
|
|
execute_cmd(frappe.local.form_dict.cmd)
|
|
|
|
# Not whitelisted, throws permission error
|
|
frappe.local.form_dict = frappe._dict(
|
|
{
|
|
"dt": report.doctype,
|
|
"dn": report.name,
|
|
"method": "create_report_py",
|
|
"cmd": "run_doc_method",
|
|
"args": 0,
|
|
}
|
|
)
|
|
|
|
self.assertRaises(frappe.PermissionError, execute_cmd, frappe.local.form_dict.cmd)
|
|
|
|
def test_array_values_in_request_args(self):
|
|
import requests
|
|
|
|
from frappe.auth import CookieManager, LoginManager
|
|
|
|
frappe.utils.set_request(path="/")
|
|
frappe.local.cookie_manager = CookieManager()
|
|
frappe.local.login_manager = LoginManager()
|
|
frappe.local.login_manager.login_as("Administrator")
|
|
params = {
|
|
"doctype": "DocType",
|
|
"fields": ["name", "modified"],
|
|
"sid": frappe.session.sid,
|
|
}
|
|
headers = {
|
|
"accept": "application/json",
|
|
"content-type": "application/json",
|
|
}
|
|
url = get_site_url(frappe.local.site)
|
|
url += "/api/method/frappe.client.get_list"
|
|
|
|
res = requests.post(url, json=params, headers=headers)
|
|
self.assertEqual(res.status_code, 200)
|
|
data = res.json()
|
|
first_item = data["message"][0]
|
|
self.assertTrue("name" in first_item)
|
|
self.assertTrue("modified" in first_item)
|
|
|
|
def test_client_get(self):
|
|
from frappe.client import get
|
|
|
|
todo = frappe.get_doc(doctype="ToDo", description="test").insert()
|
|
filters = {"name": todo.name}
|
|
filters_json = frappe.as_json(filters)
|
|
|
|
self.assertEqual(get("ToDo", filters=filters).description, "test")
|
|
self.assertEqual(get("ToDo", filters=filters_json).description, "test")
|
|
self.assertEqual(get("System Settings", "", "").doctype, "System Settings")
|
|
self.assertEqual(get("ToDo", filters={}), get("ToDo", filters="{}"))
|
|
todo.delete()
|
|
|
|
def test_client_insert(self):
|
|
from frappe.client import insert
|
|
|
|
def get_random_title():
|
|
return f"test-{frappe.generate_hash()}"
|
|
|
|
# test insert dict
|
|
doc = {"doctype": "Note", "title": get_random_title(), "content": "test"}
|
|
note1 = insert(doc)
|
|
self.assertTrue(note1)
|
|
|
|
# test insert json
|
|
doc["title"] = get_random_title()
|
|
json_doc = frappe.as_json(doc)
|
|
note2 = insert(json_doc)
|
|
self.assertTrue(note2)
|
|
|
|
# test insert child doc without parent fields
|
|
child_doc = {"doctype": "Note Seen By", "user": "Administrator"}
|
|
with self.assertRaises(frappe.ValidationError):
|
|
insert(child_doc)
|
|
|
|
# test insert child doc with parent fields
|
|
child_doc = {
|
|
"doctype": "Note Seen By",
|
|
"user": "Administrator",
|
|
"parenttype": "Note",
|
|
"parent": note1.name,
|
|
"parentfield": "seen_by",
|
|
}
|
|
note3 = insert(child_doc)
|
|
self.assertTrue(note3)
|
|
|
|
# cleanup
|
|
frappe.delete_doc("Note", note1.name)
|
|
frappe.delete_doc("Note", note2.name)
|
|
|
|
def test_client_insert_many(self):
|
|
from frappe.client import insert, insert_many
|
|
|
|
def get_random_title():
|
|
return f"test-{frappe.generate_hash(length=5)}"
|
|
|
|
# insert a (parent) doc
|
|
note1 = {"doctype": "Note", "title": get_random_title(), "content": "test"}
|
|
note1 = insert(note1)
|
|
|
|
doc_list = [
|
|
{
|
|
"doctype": "Note Seen By",
|
|
"user": "Administrator",
|
|
"parenttype": "Note",
|
|
"parent": note1.name,
|
|
"parentfield": "seen_by",
|
|
},
|
|
{
|
|
"doctype": "Note Seen By",
|
|
"user": "Administrator",
|
|
"parenttype": "Note",
|
|
"parent": note1.name,
|
|
"parentfield": "seen_by",
|
|
},
|
|
{
|
|
"doctype": "Note Seen By",
|
|
"user": "Administrator",
|
|
"parenttype": "Note",
|
|
"parent": note1.name,
|
|
"parentfield": "seen_by",
|
|
},
|
|
{"doctype": "Note", "title": "not-a-random-title", "content": "test"},
|
|
{"doctype": "Note", "title": get_random_title(), "content": "test"},
|
|
{"doctype": "Note", "title": get_random_title(), "content": "test"},
|
|
{"doctype": "Note", "title": "another-note-title", "content": "test"},
|
|
]
|
|
|
|
# insert all docs
|
|
docs = insert_many(doc_list)
|
|
|
|
self.assertEqual(len(docs), 7)
|
|
self.assertEqual(frappe.db.get_value("Note", docs[3], "title"), "not-a-random-title")
|
|
self.assertEqual(frappe.db.get_value("Note", docs[6], "title"), "another-note-title")
|
|
self.assertIn(note1.name, docs)
|
|
|
|
# cleanup
|
|
for doc in docs:
|
|
frappe.delete_doc("Note", doc)
|