feat(testing): add template validation suite and fix HTML structure issues

This commit is contained in:
matt 2025-11-04 10:08:49 -08:00
parent 40023e93b8
commit e17dcf6283
6 changed files with 34 additions and 29 deletions

View file

@ -9,6 +9,11 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning
## [Unreleased]
### Added
- **Template Validation Tests**: Comprehensive test suite for HTML/Jinja2 templates
- Validates Jinja2 syntax across all templates
- Checks HTML structure (balanced tags, unique IDs, proper attributes)
- Basic accessibility validation (alt text, form labels, button types)
- Regression prevention thresholds to maintain code quality
- **Code Quality Tools**: Enhanced development tooling for maintainability
- Automated utilities for code cleanup
- Improved type checking configuration
@ -81,6 +86,10 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning
- Optimized linting rules for development workflow
### Fixed
- **Template Quality**: Resolved HTML structure issues found by validation tests
- Fixed duplicate ID attributes in build wizard and theme picker templates
- Removed erroneous block tags from component documentation
- Corrected template structure for HTMX fragments
- **Code Quality**: Resolved type checking warnings and improved code maintainability
- Fixed type annotation inconsistencies
- Cleaned up redundant code quality suppressions

View file

@ -3,9 +3,14 @@
## [Unreleased]
### Summary
Web UI improvements with Tailwind CSS migration, TypeScript conversion, component library, enhanced code quality tools, and optional card image caching for faster performance and better maintainability.
Web UI improvements with Tailwind CSS migration, TypeScript conversion, component library, template validation tests, enhanced code quality tools, and optional card image caching for faster performance and better maintainability.
### Added
- **Template Validation Tests**: Comprehensive test suite ensuring HTML/template quality
- Validates Jinja2 syntax and structure
- Checks for common HTML issues (duplicate IDs, balanced tags)
- Basic accessibility validation
- Prevents regression in template quality
- **Code Quality Tools**: Enhanced development tooling for maintainability
- Automated utilities for code cleanup
- Improved type checking configuration
@ -78,6 +83,10 @@ Web UI improvements with Tailwind CSS migration, TypeScript conversion, componen
_None_
### Fixed
- **Template Quality**: Resolved HTML structure issues
- Fixed duplicate ID attributes in templates
- Removed erroneous template block tags
- Corrected structure for HTMX fragments
- **Code Quality**: Resolved type checking warnings and improved code maintainability
- Fixed type annotation inconsistencies
- Cleaned up redundant code quality suppressions

View file

@ -66,8 +66,8 @@
{% endif %}
{% if (query is defined and query and (not candidates or (candidates|length == 0))) and not inspect %}
<div id="candidate-grid" class="muted" style="margin-top:.5rem;" aria-live="polite">
No results for “{{ query }}”. Try a shorter name or a different spelling.
<div id="no-results-message" class="muted" style="margin-top:.5rem;" aria-live="polite">
No results for "{{ query }}". Try a shorter name or a different spelling.
</div>
{% endif %}

View file

@ -33,7 +33,6 @@
<!-- BUTTONS -->
<section id="buttons" class="section-spacing">
{% call panel(title='Buttons', padding='lg') %}
{% block body %}
<h4 style="margin-top: 0;">Button Variants</h4>
<div class="btn-group content-spacing-lg">
@ -76,16 +75,14 @@
<div class="btn-group">
{{ button('Go Home', href='/', variant='ghost') }}
{{ button('Build Deck', href='/build', variant='primary') }}
</div>
</code></pre>
{% endblock %}
{% endcall %}
</section>
<!-- MODALS -->
<section id="modals" style="margin-top: 2rem;">
{% call panel(title='Modals', padding='lg') %}
{% block body %}
<p style="margin-top: 0; color: var(--muted);">Click buttons to see modal examples</p>
@ -104,14 +101,12 @@
{{ button('XLarge (960px)', onclick='showSizedModal("xl")') }}
</div>
{% endblock %}
{% endcall %}
</section>
<!-- FORMS -->
<section id="forms" style="margin-top: 2rem;">
{% call panel(title='Form Components', padding='lg') %}
{% block body %}
<form onsubmit="event.preventDefault(); alert('Form submitted!');" style="max-width: 600px;">
@ -147,14 +142,12 @@
</div>
</form>
{% endblock %}
{% endcall %}
</section>
<!-- CARD DISPLAY -->
<section id="cards" style="margin-top: 2rem;">
{% call panel(title='Card Display Components', padding='lg') %}
{% block body %}
<h4 style="margin-top: 0;">Card Thumbnail Sizes</h4>
<div style="display: flex; gap: 1rem; flex-wrap: wrap; align-items: flex-start; margin-bottom: 2rem;">
@ -179,14 +172,12 @@
{'name': 'Birds of Paradise', 'role': 'ramp', 'tags': ['Ramp', 'Creature']}
], size='medium', columns=3) }}
{% endblock %}
{% endcall %}
</section>
<!-- PANELS -->
<section id="panels" style="margin-top: 2rem;">
{% call panel(title='Panel Components', padding='lg') %}
{% block body %}
<h4 style="margin-top: 0;">Panel Variants</h4>
{{ simple_panel(title='Default Panel', content='<p>This is a default panel with standard background.</p>', variant='default') }}
@ -232,14 +223,12 @@
<h4 style="margin-top: 2rem;">Collapsible Panel</h4>
{% call collapsible_panel(title='Advanced Options', expanded=False) %}
{% block body %}
<p>These are advanced settings that are hidden by default.</p>
<ul>
<li>Option 1: Enable feature X</li>
<li>Option 2: Adjust threshold Y</li>
<li>Option 3: Configure behavior Z</li>
</ul>
{% endblock %}
{% endcall %}
<h4 style="margin-top: 2rem;">Empty State</h4>
@ -254,7 +243,6 @@
<h4 style="margin-top: 2rem;">Loading State</h4>
{{ loading_panel(message='Building deck...', spinner=True) }}
{% endblock %}
{% endcall %}
</section>

View file

@ -17,9 +17,9 @@
Examples:
{% call form_field('Email', 'email', required=True) %}
{% block body %}
<input type="email" name="email" />
{% endblock %}
{% endcall %}
#}
{% macro form_field(label='', name='', required=False, help_text='', error='', classes='') %}
@ -72,7 +72,7 @@
#}
{% macro text_input(name, label='', type='text', value='', placeholder='', required=False, disabled=False, readonly=False, help_text='', error='', classes='', attrs='') %}
{% call form_field(label, name, required, help_text, error, classes) %}
{% block body %}
<input type="{{ type }}"
id="{{ name }}"
name="{{ name }}"
@ -83,7 +83,7 @@
{% if disabled %}disabled{% endif %}
{% if readonly %}readonly{% endif %}
{{ attrs|safe }} />
{% endblock %}
{% endcall %}
{% endmacro %}
@ -110,7 +110,7 @@
#}
{% macro textarea(name, label='', value='', placeholder='', rows=4, required=False, disabled=False, readonly=False, help_text='', error='', classes='', attrs='') %}
{% call form_field(label, name, required, help_text, error, classes) %}
{% block body %}
<textarea id="{{ name }}"
name="{{ name }}"
class="form-textarea"
@ -120,7 +120,7 @@
{% if disabled %}disabled{% endif %}
{% if readonly %}readonly{% endif %}
{{ attrs|safe }}>{{ value }}</textarea>
{% endblock %}
{% endcall %}
{% endmacro %}
@ -148,7 +148,7 @@
#}
{% macro select(name, label='', options=[], value='', required=False, disabled=False, help_text='', error='', classes='', attrs='') %}
{% call form_field(label, name, required, help_text, error, classes) %}
{% block body %}
<select id="{{ name }}"
name="{{ name }}"
class="form-select"
@ -163,7 +163,7 @@
</option>
{% endfor %}
</select>
{% endblock %}
{% endcall %}
{% endmacro %}
@ -295,7 +295,7 @@
#}
{% macro number_input(name, label='', value='', min='', max='', step=1, placeholder='', required=False, disabled=False, help_text='', error='', classes='', attrs='') %}
{% call form_field(label, name, required, help_text, error, classes) %}
{% block body %}
<input type="number"
id="{{ name }}"
name="{{ name }}"
@ -308,7 +308,7 @@
{% if required %}required{% endif %}
{% if disabled %}disabled{% endif %}
{{ attrs|safe }} />
{% endblock %}
{% endcall %}
{% endmacro %}
@ -333,7 +333,7 @@
#}
{% macro file_input(name, label='', accept='', multiple=False, required=False, disabled=False, help_text='', error='', classes='', attrs='') %}
{% call form_field(label, name, required, help_text, error, classes) %}
{% block body %}
<input type="file"
id="{{ name }}"
name="{{ name }}"
@ -343,7 +343,7 @@
{% if required %}required{% endif %}
{% if disabled %}disabled{% endif %}
{{ attrs|safe }} />
{% endblock %}
{% endcall %}
{% endmacro %}

View file

@ -77,7 +77,6 @@
{% endif %}
</div>
<div id="theme-preview-host"></div>
<div id="filter-chips" class="filter-chips" aria-label="Active filters"></div>
</div>
<style>
.theme-picker-controls { display:flex; flex-wrap:wrap; gap:.5rem; margin-bottom:.75rem; }