import pytest from myfasthtml.core.testclient import TestableForm @pytest.fixture def mock_client(): """Mock client for testing purposes.""" return None class TestableFormUpdateFieldMapping: def test_i_can_map_label_with_explicit_for_attribute(self, mock_client): """ Test that labels with explicit 'for' attribute are correctly mapped. This is the most reliable association method (priority 1). """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Username": "username"} def test_i_can_map_label_containing_input(self, mock_client): """ Test that labels containing inputs are correctly mapped. This tests implicit association by nesting (priority 2). """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Username": "username"} def test_i_can_map_label_and_input_as_siblings_with_for_id(self, mock_client): """ Test that sibling labels and inputs with for/id are correctly mapped. This tests parent-level association with explicit for/id (priority 3). """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Username": "username"} def test_i_can_map_label_and_input_as_siblings_by_proximity(self, mock_client): """ Test that sibling labels and inputs are mapped by proximity. This tests association by proximity without for/id (priority 4). """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Username": "username"} def test_i_can_map_input_without_label_using_name(self, mock_client): """ Test that inputs without labels use their name attribute as key. This tests the fallback mechanism (priority 5). """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"csrf_token": "csrf_token"} def test_i_can_map_input_without_name_using_id(self, mock_client): """ Test that inputs without name attribute fallback to id attribute. This ensures inputs without name can still be identified. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"submit_btn": "submit_btn"} def test_i_can_map_input_without_name_and_id_using_unnamed(self, mock_client): """ Test that inputs without name or id get a generated unnamed key. This ensures all inputs are tracked even without identifiers. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"unnamed_0": "unnamed_0"} def test_i_can_handle_multiple_unnamed_inputs(self, mock_client): """ Test that multiple unnamed inputs get incrementing counters. This ensures each unnamed input has a unique identifier. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"unnamed_0": "unnamed_0", "unnamed_1": "unnamed_1"} def test_i_can_strip_whitespace_from_label_text(self, mock_client): """ Test that whitespace and newlines are stripped from label text. This ensures clean, consistent label keys in the mapping. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Username": "username"} def test_i_can_extract_text_from_complex_labels(self, mock_client): """ Test that text from nested elements in labels is extracted. This ensures labels with spans, emphasis, etc. are handled correctly. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Username*": "username"} def test_i_can_handle_mixed_scenarios_in_same_form(self, mock_client): """ Test that all association priorities work together in one form. This is a comprehensive test ensuring the priority system works correctly. """ html = '''
''' form = TestableForm(mock_client, html) expected = { "Email": "email", "Password": "password", "Phone": "phone", "Address": "address", "csrf_token": "csrf_token", "submit_btn": "submit_btn", "unnamed_0": "unnamed_0" } assert form.fields_mapping == expected def test_i_can_handle_empty_form(self, mock_client): """ Test that an empty form doesn't cause errors. This ensures robustness when dealing with minimal forms. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {} def test_i_can_handle_form_with_only_labels(self, mock_client): """ Test that labels without associated inputs don't cause errors. This ensures the code handles malformed or incomplete forms gracefully. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {} def test_i_can_handle_label_with_invalid_for_attribute(self, mock_client): """ Test that labels with invalid 'for' attributes fallback correctly. This ensures the priority system cascades properly when higher priorities fail to find a match. """ html = '
' form = TestableForm(mock_client, html) assert form.fields_mapping == {"Test": "field"} class TestableFormUpdateFieldValues: def test_i_can_handle_checkbox_checked(self, mock_client): """ Test that a checked checkbox is converted to True. This ensures proper boolean handling for checked checkboxes. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"agree": True}, \ f"Expected {{'agree': True}}, got {form.fields}" def test_i_can_handle_checkbox_unchecked(self, mock_client): """ Test that an unchecked checkbox is converted to False. This ensures proper boolean handling for unchecked checkboxes. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"agree": False}, \ f"Expected {{'agree': False}}, got {form.fields}" def test_i_can_handle_radio_button_checked(self, mock_client): """ Test that a checked radio button returns its value as string. This ensures radio buttons store their value attribute. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"size": "large"}, \ f"Expected {{'size': 'large'}}, got {form.fields}" def test_i_can_handle_multiple_radio_buttons_with_one_checked(self, mock_client): """ Test that only the checked radio button value is returned. This ensures correct handling of radio button groups. """ html = '''
''' form = TestableForm(mock_client, html) assert form.fields == {"size": "medium"}, \ f"Expected {{'size': 'medium'}}, got {form.fields}" def test_i_can_handle_radio_buttons_with_none_checked(self, mock_client): """ Test that no value is set when no radio button is checked. This ensures proper handling of unchecked radio button groups. """ html = '''
''' form = TestableForm(mock_client, html) assert "size" not in form.fields, \ f"Expected 'size' not in fields, got {form.fields}" def test_i_can_handle_number_input_with_integer(self, mock_client): """ Test that a number input with integer value becomes int. This ensures proper type conversion for integer numbers. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"age": 25}, \ f"Expected {{'age': 25}}, got {form.fields}" assert isinstance(form.fields["age"], int), \ f"Expected int type, got {type(form.fields['age'])}" def test_i_can_handle_number_input_with_float(self, mock_client): """ Test that a number input with decimal value becomes float. This ensures proper type conversion for floating point numbers. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"price": 19.99}, \ f"Expected {{'price': 19.99}}, got {form.fields}" assert isinstance(form.fields["price"], float), \ f"Expected float type, got {type(form.fields['price'])}" def test_i_can_handle_text_input_with_string_value(self, mock_client): """ Test that a text input with string value remains str. This ensures text values are not converted unnecessarily. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"username": "john_doe"}, \ f"Expected {{'username': 'john_doe'}}, got {form.fields}" assert isinstance(form.fields["username"], str), \ f"Expected str type, got {type(form.fields['username'])}" def test_i_can_handle_text_input_with_integer_value(self, mock_client): """ Test that a text input with numeric value is converted to int. This ensures automatic type detection for text inputs. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"code": 123}, \ f"Expected {{'code': 123}}, got {form.fields}" assert isinstance(form.fields["code"], int), \ f"Expected int type, got {type(form.fields['code'])}" def test_i_can_handle_text_input_with_float_value(self, mock_client): """ Test that a text input with decimal value is converted to float. This ensures automatic float detection for text inputs. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"rate": 3.14}, \ f"Expected {{'rate': 3.14}}, got {form.fields}" assert isinstance(form.fields["rate"], float), \ f"Expected float type, got {type(form.fields['rate'])}" def test_i_can_handle_text_input_with_boolean_true(self, mock_client): """ Test that a text input with 'true' is converted to bool. This ensures boolean keyword detection for text inputs. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"flag": True}, \ f"Expected {{'flag': True}}, got {form.fields}" assert isinstance(form.fields["flag"], bool), \ f"Expected bool type, got {type(form.fields['flag'])}" def test_i_can_handle_text_input_with_boolean_false(self, mock_client): """ Test that a text input with 'false' is converted to bool. This ensures boolean keyword detection for false values. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"flag": False}, \ f"Expected {{'flag': False}}, got {form.fields}" assert isinstance(form.fields["flag"], bool), \ f"Expected bool type, got {type(form.fields['flag'])}" def test_i_can_handle_hidden_input_with_auto_conversion(self, mock_client): """ Test that hidden inputs benefit from automatic type conversion. This ensures hidden fields are processed like text fields. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"id": 42}, \ f"Expected {{'id': 42}}, got {form.fields}" assert isinstance(form.fields["id"], int), \ f"Expected int type, got {type(form.fields['id'])}" def test_i_can_handle_empty_input_value(self, mock_client): """ Test that an empty input value remains an empty string. This ensures empty values are not converted to None or other types. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"optional": ""}, \ f"Expected {{'optional': ''}}, got {form.fields}" assert isinstance(form.fields["optional"], str), \ f"Expected str type, got {type(form.fields['optional'])}" def test_i_can_extract_select_options(self, mock_client): """ Test that select options are correctly extracted. This ensures proper population of select_fields dictionary. """ html = '''
''' form = TestableForm(mock_client, html) expected_options = [ {"value": "FR", "text": "France"}, {"value": "US", "text": "USA"} ] assert form.select_fields == {"country": expected_options}, \ f"Expected {{'country': {expected_options}}}, got {form.select_fields}" def test_i_can_handle_select_with_selected_option(self, mock_client): """ Test that the selected option is stored in fields. This ensures proper detection of selected options. """ html = '''
''' form = TestableForm(mock_client, html) assert form.fields == {"country": "US"}, \ f"Expected {{'country': 'US'}}, got {form.fields}" def test_i_can_handle_select_without_selected_option(self, mock_client): """ Test that the first option is used by default. This ensures proper default value handling for select fields. """ html = '''
''' form = TestableForm(mock_client, html) assert form.fields == {"country": "FR"}, \ f"Expected {{'country': 'FR'}}, got {form.fields}" def test_i_can_handle_select_option_without_value_attribute(self, mock_client): """ Test that option text is used when value attribute is missing. This ensures fallback to text content for options without value. """ html = '''
''' form = TestableForm(mock_client, html) expected_options = [ {"value": "France", "text": "France"}, {"value": "USA", "text": "USA"} ] assert form.select_fields == {"country": expected_options}, \ f"Expected {{'country': {expected_options}}}, got {form.select_fields}" def test_i_can_handle_mixed_input_types_in_same_form(self, mock_client): """ Test that all input types work together correctly. This is a comprehensive test ensuring type handling is consistent. """ html = '''
''' form = TestableForm(mock_client, html) expected_fields = { "username": "john", "age": 30, "subscribe": True, "gender": "male", "token": 123, "country": "FR" } assert form.fields == expected_fields, \ f"Expected {expected_fields}, got {form.fields}" assert "country" in form.select_fields, \ f"Expected 'country' in select_fields, got {form.select_fields}" def test_i_can_handle_input_without_name_attribute(self, mock_client): """ Test that inputs without name attribute are ignored. This ensures proper handling of unnamed inputs. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {}, \ f"Expected empty dict, got {form.fields}" def test_i_can_handle_select_without_name_attribute(self, mock_client): """ Test that select elements without name attribute are ignored. This ensures proper handling of unnamed select fields. """ html = '
' form = TestableForm(mock_client, html) assert form.select_fields == {}, \ f"Expected empty dict, got {form.select_fields}" assert form.fields == {}, \ f"Expected empty dict, got {form.fields}" def test_i_can_handle_number_input_with_empty_value(self, mock_client): """ Test that a number input with empty value remains empty string. This ensures empty values are not converted to 0 or None. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"count": ""}, \ f"Expected {{'count': ''}}, got {form.fields}" def test_i_can_handle_select_with_empty_options(self, mock_client): """ Test behavior with a select element without options. This ensures robustness when dealing with empty selects. """ html = '
' form = TestableForm(mock_client, html) assert form.select_fields == {"empty": []}, \ f"Expected {{'empty': []}}, got {form.select_fields}" assert "empty" not in form.fields, \ f"Expected 'empty' not in fields, got {form.fields}" def test_i_can_handle_case_insensitive_boolean_values(self, mock_client): """ Test that boolean values are case-insensitive. This ensures 'TRUE', 'True', 'FALSE', 'False' are all converted properly. """ html = '
' form = TestableForm(mock_client, html) assert form.fields == {"flag": True}, \ f"Expected {{'flag': True}}, got {form.fields}" assert isinstance(form.fields["flag"], bool), \ f"Expected bool type, got {type(form.fields['flag'])}"