Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions forms_pro/api/submission/test_submission_validation.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,41 @@ def test_required_data_field_still_validated_when_heading_present(self):
def test_display_only_fieldtypes_contains_all_heading_levels(self):
for fieldtype in ("Heading 1", "Heading 2", "Heading 3"):
self.assertIn(fieldtype, _DISPLAY_ONLY_FIELDTYPES)


class TestPageBreakValidation(unittest.TestCase):
def test_page_break_in_display_only_fieldtypes(self):
self.assertIn("Page Break", _DISPLAY_ONLY_FIELDTYPES)

def test_page_break_skipped_even_when_required(self):
"""reqd=1 Page Break must never trigger a validation error."""
form = _form(_field("pb", fieldtype="Page Break", reqd=1))
_validate_form_response(form, {}) # must not raise

def test_required_data_field_still_validated_when_page_break_present(self):
"""Page Break being skipped must not suppress validation of adjacent required fields."""
import frappe

form = _form(
_field("step_two", fieldtype="Page Break"),
_field("full_name", fieldtype="Data", reqd=1),
)
with self.assertRaises(frappe.ValidationError) as ctx:
_validate_form_response(form, {})
self.assertIn("Full Name", str(ctx.exception))


class TestPageBreakProperties(unittest.TestCase):
def test_page_break_stores_value_is_false(self):
"""Page Break maps to Tab Break which is a no_value_field — stores_value must be False."""
from frappe.model import no_value_fields

from forms_pro.forms_pro.doctype.form_field.form_field import FORM_TO_FRAPPE_FIELDTYPE

mapped = FORM_TO_FRAPPE_FIELDTYPE["Page Break"]
self.assertIn(mapped["fieldtype"], no_value_fields)

def test_page_break_frappe_fieldtype_is_tab_break(self):
from forms_pro.forms_pro.doctype.form_field.form_field import FORM_TO_FRAPPE_FIELDTYPE

self.assertEqual(FORM_TO_FRAPPE_FIELDTYPE["Page Break"]["fieldtype"], "Tab Break")
2 changes: 1 addition & 1 deletion forms_pro/forms_pro/doctype/form_field/form_field.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Fieldtype",
"options": "Attach\nData\nNumber\nEmail\nDate\nDate Time\nDate Range\nTime Picker\nPassword\nSelect\nSwitch\nTextarea\nText Editor\nLink\nCheckbox\nRating\nPhone\nTable\nMultiselect\nHeading 1\nHeading 2\nHeading 3",
"options": "Attach\nData\nNumber\nEmail\nDate\nDate Time\nDate Range\nTime Picker\nPassword\nSelect\nSwitch\nTextarea\nText Editor\nLink\nCheckbox\nRating\nPhone\nTable\nMultiselect\nHeading 1\nHeading 2\nHeading 3\nPage Break",
"reqd": 1
},
{
Expand Down
16 changes: 8 additions & 8 deletions forms_pro/forms_pro/doctype/form_field/form_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@
"Heading 1": {"fieldtype": "HTML"},
"Heading 2": {"fieldtype": "HTML"},
"Heading 3": {"fieldtype": "HTML"},
"Page Break": {"fieldtype": "Tab Break"},
}


_DISPLAY_ONLY_FIELDTYPES = {"Heading 1", "Heading 2", "Heading 3"}
_DISPLAY_ONLY_FIELDTYPES = {"Heading 1", "Heading 2", "Heading 3", "Page Break"}


class FormField(Document):
Expand Down Expand Up @@ -114,13 +115,12 @@ def to_frappe_field(self) -> dict:
}

def get_options(self) -> str | None:
if self.fieldtype in _DISPLAY_ONLY_FIELDTYPES:
HEADING_MAP = {
"Heading 1": "h1",
"Heading 2": "h2",
"Heading 3": "h3",
}
tag = HEADING_MAP.get(self.fieldtype, "h2")
HEADING_MAP = {
"Heading 1": "h1",
"Heading 2": "h2",
"Heading 3": "h3",
}
if tag := HEADING_MAP.get(self.fieldtype):
return f"<{tag}>{escape_html(self.label or '')}</{tag}>"

return self.options
71 changes: 71 additions & 0 deletions forms_pro/tests/test_page_break.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import frappe
from frappe.tests import IntegrationTestCase

from forms_pro.tests.factories.form_factory import FormFactory


class TestPageBreakIntegration(IntegrationTestCase):
def test_form_with_page_break_saves(self):
form = FormFactory.create()
form.append(
"fields",
{
"label": "Your Name",
"fieldname": "your_name",
"fieldtype": "Data",
"reqd": 0,
"row_index": 0,
"column_index": 0,
"cell_index": 0,
},
)
form.append(
"fields",
{
"label": "Step 2",
"fieldname": "step_2",
"fieldtype": "Page Break",
"reqd": 0,
"row_index": 1,
"column_index": 0,
"cell_index": 0,
},
)
form.append(
"fields",
{
"label": "Your Email",
"fieldname": "your_email",
"fieldtype": "Email",
"reqd": 0,
"row_index": 2,
"column_index": 0,
"cell_index": 0,
},
)
form.save()

form.reload()
fieldtypes = [f.fieldtype for f in form.fields]
self.assertIn("Page Break", fieldtypes)

def test_page_break_syncs_as_tab_break_to_linked_doctype(self):
form = FormFactory.create()
form.append(
"fields",
{
"label": "Step 2",
"fieldname": "step_2",
"fieldtype": "Page Break",
"reqd": 0,
"row_index": 0,
"column_index": 0,
"cell_index": 0,
},
)
form.save()

doctype_doc = frappe.get_doc("DocType", form.linked_doctype)
synced = {f.fieldname: f for f in doctype_doc.fields}
self.assertIn("step_2", synced)
self.assertEqual(synced["step_2"].fieldtype, "Tab Break")
1 change: 1 addition & 0 deletions frontend/src/types/FormsPro/form_field.types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export enum Fieldtype {
"HEADING_1" = "Heading 1",
"HEADING_2" = "Heading 2",
"HEADING_3" = "Heading 3",
"PAGE_BREAK" = "Page Break",
}

export interface FormField {
Expand Down
Loading