Skip to content

Commit 185d894

Browse files
committed
Added regression doctest
1 parent 88f21c2 commit 185d894

1 file changed

Lines changed: 107 additions & 0 deletions

File tree

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
DEXTERITY INHERITED FIELDS
2+
--------------------------
3+
4+
Regression test for multi-schema Dexterity types.
5+
6+
When the searched object is a Dexterity (DX) type whose schema interface
7+
inherits from another schema interface, the fields declared by the *parent*
8+
schema must be returned too. The previous implementation relied on
9+
``schema.names()``, which only returns the fields declared directly on the
10+
interface (inherited fields require ``names(all=True)``), so inherited fields
11+
were silently dropped from the API response.
12+
13+
``senaite.core.content.supplier.Supplier`` is a good example of a multi-schema
14+
DX type: its schema ``ISupplierSchema`` inherits from ``IOrganizationSchema``.
15+
16+
Running this test from the buildout directory:
17+
18+
bin/test test_doctests -t dexterity_inherited_fields
19+
20+
21+
Test Setup
22+
~~~~~~~~~~
23+
24+
Needed Imports:
25+
26+
>>> import json
27+
>>> import transaction
28+
>>> from plone.app.testing import setRoles
29+
>>> from plone.app.testing import TEST_USER_ID
30+
31+
>>> from bika.lims import api
32+
>>> from senaite.jsonapi import api as japi
33+
34+
Functional Helpers:
35+
36+
>>> def get(url):
37+
... browser.open("{}/{}".format(api_url, url))
38+
... return browser.contents
39+
40+
Variables:
41+
42+
>>> portal = self.portal
43+
>>> setup = portal.setup
44+
>>> portal_url = portal.absolute_url()
45+
>>> api_url = "{}/@@API/senaite/v1".format(portal_url)
46+
>>> browser = self.getBrowser()
47+
>>> setRoles(portal, TEST_USER_ID, ["LabManager", "Manager"])
48+
>>> transaction.commit()
49+
50+
Create a Supplier (DX type with an inherited schema):
51+
52+
>>> supplier = api.create(setup.suppliers, "Supplier", Name="Naralabs")
53+
>>> uid = api.get_uid(supplier)
54+
>>> transaction.commit()
55+
56+
57+
The DX type is genuinely multi-schema
58+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
59+
60+
The schema interface inherits from a parent schema interface:
61+
62+
>>> from senaite.core.content.supplier import ISupplierSchema
63+
>>> from senaite.core.content.organization import IOrganizationSchema
64+
>>> IOrganizationSchema in ISupplierSchema.__bases__
65+
True
66+
67+
``tax_number`` is declared by the *parent* ``IOrganizationSchema``, while
68+
``lab_account_number`` is declared *directly* on ``ISupplierSchema``:
69+
70+
>>> "tax_number" in IOrganizationSchema.names()
71+
True
72+
>>> "tax_number" in ISupplierSchema.names()
73+
False
74+
>>> "lab_account_number" in ISupplierSchema.names()
75+
True
76+
77+
78+
Inherited fields are returned by get_fields
79+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
80+
81+
The fields mapping must contain both the directly declared field and the
82+
inherited one:
83+
84+
>>> fields = japi.get_fields(supplier)
85+
>>> "lab_account_number" in fields
86+
True
87+
>>> "tax_number" in fields
88+
True
89+
90+
``get_field`` resolves the inherited field too (it previously returned the
91+
default because the field was missing from the mapping):
92+
93+
>>> japi.get_field(supplier, "tax_number") is not None
94+
True
95+
96+
97+
Inherited fields are present in the API response
98+
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
99+
100+
End to end, fetching the object exposes the inherited field as a key:
101+
102+
>>> response = get(uid)
103+
>>> data = json.loads(response)
104+
>>> "lab_account_number" in data
105+
True
106+
>>> "tax_number" in data
107+
True

0 commit comments

Comments
 (0)