Fix custom choices not being used

This commit is contained in:
Tobias Kunze 2025-11-06 15:55:27 +01:00
parent b3bb41b322
commit 089dbb663a
3 changed files with 326 additions and 0 deletions

View file

@ -216,3 +216,244 @@ def test_form_config_schema_validates_full_config():
]
}
jsonschema.validate(instance=full_config, schema=schema)
def test_choice_field_uses_custom_choices_from_form_config():
"""Test that choice fields use custom choices when provided in form_config"""
class TestModel(models.Model):
name = models.CharField(max_length=100)
environment = models.CharField(
max_length=20,
choices=[
("dev", "Development"),
("staging", "Staging"),
("prod", "Production"),
("test", "Testing"),
],
)
class Meta:
app_label = "test"
form_config = {
"fieldsets": [
{
"title": "General",
"fields": [
{
"type": "text",
"label": "Name",
"controlplane_field_mapping": "name",
"required": True,
},
{
"type": "choice",
"label": "Environment",
"controlplane_field_mapping": "environment",
"required": True,
"choices": [["dev", "Development"], ["prod", "Production"]],
},
],
}
]
}
form_class = generate_custom_form_class(form_config, TestModel)
form = form_class()
environment_field = form.fields["environment"]
assert list(environment_field.choices) == [
("dev", "Development"),
("prod", "Production"),
]
assert hasattr(environment_field, "_controlplane_choices")
assert len(environment_field._controlplane_choices) == 5 # 4 choices + empty choice
def test_choice_field_uses_control_plane_choices_when_no_custom_choices():
class TestModel(models.Model):
name = models.CharField(max_length=100)
environment = models.CharField(
max_length=20,
choices=[
("dev", "Development"),
("staging", "Staging"),
("prod", "Production"),
],
)
class Meta:
app_label = "test"
form_config = {
"fieldsets": [
{
"title": "General",
"fields": [
{
"type": "text",
"label": "Name",
"controlplane_field_mapping": "name",
"required": True,
},
{
"type": "choice",
"label": "Environment",
"controlplane_field_mapping": "environment",
"required": True,
},
],
}
]
}
form_class = generate_custom_form_class(form_config, TestModel)
form = form_class()
environment_field = form.fields["environment"]
choices_list = list(environment_field.choices)
assert len(choices_list) == 4 # 3 choices + empty choice
assert ("dev", "Development") in choices_list
def test_choice_field_validates_against_control_plane_choices():
class TestModel(models.Model):
name = models.CharField(max_length=100)
environment = models.CharField(
max_length=20,
choices=[
("dev", "Development"),
("staging", "Staging"),
("prod", "Production"),
],
)
class Meta:
app_label = "test"
form_config = {
"fieldsets": [
{
"title": "General",
"fields": [
{
"type": "text",
"label": "Name",
"controlplane_field_mapping": "name",
"required": True,
},
{
"type": "choice",
"label": "Environment",
"controlplane_field_mapping": "environment",
"required": True,
"choices": [["dev", "Development"], ["prod", "Production"]],
},
],
}
]
}
form_class = generate_custom_form_class(form_config, TestModel)
form = form_class(data={"name": "test-service", "environment": "dev"})
form.fields["context"].required = False # Skip context validation
assert form.is_valid(), f"Form should be valid but has errors: {form.errors}"
form = form_class(data={"name": "test-service", "environment": "prod"})
form.fields["context"].required = False # Skip context validation
assert form.is_valid(), f"Form should be valid but has errors: {form.errors}"
form = form_class(data={"name": "test-service", "environment": "invalid"})
form.fields["context"].required = False # Skip context validation
assert not form.is_valid()
assert "environment" in form.errors
def test_admin_form_validates_choice_values_against_schema():
from servala.core.forms import ServiceDefinitionAdminForm
form = ServiceDefinitionAdminForm()
mock_crd = Mock()
mock_crd.resource_schema = {
"properties": {
"spec": {
"properties": {
"environment": {
"type": "string",
"enum": ["dev", "staging", "prod"],
}
}
}
}
}
valid_form_config = {
"fieldsets": [
{
"fields": [
{
"type": "text",
"label": "Name",
"controlplane_field_mapping": "name",
},
{
"type": "choice",
"label": "Environment",
"controlplane_field_mapping": "spec.environment",
"choices": [["dev", "Development"], ["prod", "Production"]],
},
]
}
]
}
spec_schema = mock_crd.resource_schema["properties"]["spec"]
errors = []
for field in valid_form_config["fieldsets"][0]["fields"]:
if field.get("type") == "choice":
form._validate_choice_field(
field, field["controlplane_field_mapping"], spec_schema, "spec", errors
)
assert len(errors) == 0, f"Expected no errors but got: {errors}"
invalid_form_config = {
"fieldsets": [
{
"fields": [
{
"type": "text",
"label": "Name",
"controlplane_field_mapping": "name",
},
{
"type": "choice",
"label": "Environment",
"controlplane_field_mapping": "spec.environment",
"choices": [
["dev", "Development"],
["invalid", "Invalid Environment"],
],
},
]
}
]
}
errors = []
for field in invalid_form_config["fieldsets"][0]["fields"]:
if field.get("type") == "choice":
form._validate_choice_field(
field, field["controlplane_field_mapping"], spec_schema, "spec", errors
)
assert len(errors) > 0, "Expected validation errors but got none"
error_message = str(errors[0])
assert "invalid" in error_message.lower()
assert "Environment" in error_message