mirror of
https://github.com/mwisnowski/mtg_python_deckbuilder.git
synced 2025-12-16 07:30:13 +01:00
feat(testing): add template validation suite and fix HTML structure issues
This commit is contained in:
parent
40023e93b8
commit
e17dcf6283
6 changed files with 34 additions and 29 deletions
|
|
@ -9,6 +9,11 @@ This format follows Keep a Changelog principles and aims for Semantic Versioning
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
### Added
|
### 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
|
- **Code Quality Tools**: Enhanced development tooling for maintainability
|
||||||
- Automated utilities for code cleanup
|
- Automated utilities for code cleanup
|
||||||
- Improved type checking configuration
|
- 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
|
- Optimized linting rules for development workflow
|
||||||
|
|
||||||
### Fixed
|
### 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
|
- **Code Quality**: Resolved type checking warnings and improved code maintainability
|
||||||
- Fixed type annotation inconsistencies
|
- Fixed type annotation inconsistencies
|
||||||
- Cleaned up redundant code quality suppressions
|
- Cleaned up redundant code quality suppressions
|
||||||
|
|
|
||||||
|
|
@ -3,9 +3,14 @@
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
### Summary
|
### 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
|
### 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
|
- **Code Quality Tools**: Enhanced development tooling for maintainability
|
||||||
- Automated utilities for code cleanup
|
- Automated utilities for code cleanup
|
||||||
- Improved type checking configuration
|
- Improved type checking configuration
|
||||||
|
|
@ -78,6 +83,10 @@ Web UI improvements with Tailwind CSS migration, TypeScript conversion, componen
|
||||||
_None_
|
_None_
|
||||||
|
|
||||||
### Fixed
|
### 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
|
- **Code Quality**: Resolved type checking warnings and improved code maintainability
|
||||||
- Fixed type annotation inconsistencies
|
- Fixed type annotation inconsistencies
|
||||||
- Cleaned up redundant code quality suppressions
|
- Cleaned up redundant code quality suppressions
|
||||||
|
|
|
||||||
|
|
@ -66,8 +66,8 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% if (query is defined and query and (not candidates or (candidates|length == 0))) and not inspect %}
|
{% 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">
|
<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.
|
No results for "{{ query }}". Try a shorter name or a different spelling.
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,6 @@
|
||||||
<!-- BUTTONS -->
|
<!-- BUTTONS -->
|
||||||
<section id="buttons" class="section-spacing">
|
<section id="buttons" class="section-spacing">
|
||||||
{% call panel(title='Buttons', padding='lg') %}
|
{% call panel(title='Buttons', padding='lg') %}
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<h4 style="margin-top: 0;">Button Variants</h4>
|
<h4 style="margin-top: 0;">Button Variants</h4>
|
||||||
<div class="btn-group content-spacing-lg">
|
<div class="btn-group content-spacing-lg">
|
||||||
|
|
@ -76,16 +75,14 @@
|
||||||
<div class="btn-group">
|
<div class="btn-group">
|
||||||
{{ button('Go Home', href='/', variant='ghost') }}
|
{{ button('Go Home', href='/', variant='ghost') }}
|
||||||
{{ button('Build Deck', href='/build', variant='primary') }}
|
{{ button('Build Deck', href='/build', variant='primary') }}
|
||||||
</div>
|
</code></pre>
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- MODALS -->
|
<!-- MODALS -->
|
||||||
<section id="modals" style="margin-top: 2rem;">
|
<section id="modals" style="margin-top: 2rem;">
|
||||||
{% call panel(title='Modals', padding='lg') %}
|
{% call panel(title='Modals', padding='lg') %}
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<p style="margin-top: 0; color: var(--muted);">Click buttons to see modal examples</p>
|
<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")') }}
|
{{ button('XLarge (960px)', onclick='showSizedModal("xl")') }}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- FORMS -->
|
<!-- FORMS -->
|
||||||
<section id="forms" style="margin-top: 2rem;">
|
<section id="forms" style="margin-top: 2rem;">
|
||||||
{% call panel(title='Form Components', padding='lg') %}
|
{% call panel(title='Form Components', padding='lg') %}
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<form onsubmit="event.preventDefault(); alert('Form submitted!');" style="max-width: 600px;">
|
<form onsubmit="event.preventDefault(); alert('Form submitted!');" style="max-width: 600px;">
|
||||||
|
|
||||||
|
|
@ -147,14 +142,12 @@
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- CARD DISPLAY -->
|
<!-- CARD DISPLAY -->
|
||||||
<section id="cards" style="margin-top: 2rem;">
|
<section id="cards" style="margin-top: 2rem;">
|
||||||
{% call panel(title='Card Display Components', padding='lg') %}
|
{% call panel(title='Card Display Components', padding='lg') %}
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<h4 style="margin-top: 0;">Card Thumbnail Sizes</h4>
|
<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;">
|
<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']}
|
{'name': 'Birds of Paradise', 'role': 'ramp', 'tags': ['Ramp', 'Creature']}
|
||||||
], size='medium', columns=3) }}
|
], size='medium', columns=3) }}
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<!-- PANELS -->
|
<!-- PANELS -->
|
||||||
<section id="panels" style="margin-top: 2rem;">
|
<section id="panels" style="margin-top: 2rem;">
|
||||||
{% call panel(title='Panel Components', padding='lg') %}
|
{% call panel(title='Panel Components', padding='lg') %}
|
||||||
{% block body %}
|
|
||||||
|
|
||||||
<h4 style="margin-top: 0;">Panel Variants</h4>
|
<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') }}
|
{{ 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>
|
<h4 style="margin-top: 2rem;">Collapsible Panel</h4>
|
||||||
{% call collapsible_panel(title='Advanced Options', expanded=False) %}
|
{% call collapsible_panel(title='Advanced Options', expanded=False) %}
|
||||||
{% block body %}
|
|
||||||
<p>These are advanced settings that are hidden by default.</p>
|
<p>These are advanced settings that are hidden by default.</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>Option 1: Enable feature X</li>
|
<li>Option 1: Enable feature X</li>
|
||||||
<li>Option 2: Adjust threshold Y</li>
|
<li>Option 2: Adjust threshold Y</li>
|
||||||
<li>Option 3: Configure behavior Z</li>
|
<li>Option 3: Configure behavior Z</li>
|
||||||
</ul>
|
</ul>
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
|
|
||||||
<h4 style="margin-top: 2rem;">Empty State</h4>
|
<h4 style="margin-top: 2rem;">Empty State</h4>
|
||||||
|
|
@ -254,7 +243,6 @@
|
||||||
<h4 style="margin-top: 2rem;">Loading State</h4>
|
<h4 style="margin-top: 2rem;">Loading State</h4>
|
||||||
{{ loading_panel(message='Building deck...', spinner=True) }}
|
{{ loading_panel(message='Building deck...', spinner=True) }}
|
||||||
|
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,9 @@
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
{% call form_field('Email', 'email', required=True) %}
|
{% call form_field('Email', 'email', required=True) %}
|
||||||
{% block body %}
|
|
||||||
<input type="email" name="email" />
|
<input type="email" name="email" />
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
#}
|
#}
|
||||||
{% macro form_field(label='', name='', required=False, help_text='', error='', classes='') %}
|
{% 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='') %}
|
{% 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) %}
|
{% call form_field(label, name, required, help_text, error, classes) %}
|
||||||
{% block body %}
|
|
||||||
<input type="{{ type }}"
|
<input type="{{ type }}"
|
||||||
id="{{ name }}"
|
id="{{ name }}"
|
||||||
name="{{ name }}"
|
name="{{ name }}"
|
||||||
|
|
@ -83,7 +83,7 @@
|
||||||
{% if disabled %}disabled{% endif %}
|
{% if disabled %}disabled{% endif %}
|
||||||
{% if readonly %}readonly{% endif %}
|
{% if readonly %}readonly{% endif %}
|
||||||
{{ attrs|safe }} />
|
{{ attrs|safe }} />
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
#}
|
#}
|
||||||
{% macro textarea(name, label='', value='', placeholder='', rows=4, required=False, disabled=False, readonly=False, help_text='', error='', classes='', attrs='') %}
|
{% 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) %}
|
{% call form_field(label, name, required, help_text, error, classes) %}
|
||||||
{% block body %}
|
|
||||||
<textarea id="{{ name }}"
|
<textarea id="{{ name }}"
|
||||||
name="{{ name }}"
|
name="{{ name }}"
|
||||||
class="form-textarea"
|
class="form-textarea"
|
||||||
|
|
@ -120,7 +120,7 @@
|
||||||
{% if disabled %}disabled{% endif %}
|
{% if disabled %}disabled{% endif %}
|
||||||
{% if readonly %}readonly{% endif %}
|
{% if readonly %}readonly{% endif %}
|
||||||
{{ attrs|safe }}>{{ value }}</textarea>
|
{{ attrs|safe }}>{{ value }}</textarea>
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
@ -148,7 +148,7 @@
|
||||||
#}
|
#}
|
||||||
{% macro select(name, label='', options=[], value='', required=False, disabled=False, help_text='', error='', classes='', attrs='') %}
|
{% 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) %}
|
{% call form_field(label, name, required, help_text, error, classes) %}
|
||||||
{% block body %}
|
|
||||||
<select id="{{ name }}"
|
<select id="{{ name }}"
|
||||||
name="{{ name }}"
|
name="{{ name }}"
|
||||||
class="form-select"
|
class="form-select"
|
||||||
|
|
@ -163,7 +163,7 @@
|
||||||
</option>
|
</option>
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</select>
|
</select>
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endmacro %}
|
{% 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='') %}
|
{% 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) %}
|
{% call form_field(label, name, required, help_text, error, classes) %}
|
||||||
{% block body %}
|
|
||||||
<input type="number"
|
<input type="number"
|
||||||
id="{{ name }}"
|
id="{{ name }}"
|
||||||
name="{{ name }}"
|
name="{{ name }}"
|
||||||
|
|
@ -308,7 +308,7 @@
|
||||||
{% if required %}required{% endif %}
|
{% if required %}required{% endif %}
|
||||||
{% if disabled %}disabled{% endif %}
|
{% if disabled %}disabled{% endif %}
|
||||||
{{ attrs|safe }} />
|
{{ attrs|safe }} />
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
@ -333,7 +333,7 @@
|
||||||
#}
|
#}
|
||||||
{% macro file_input(name, label='', accept='', multiple=False, required=False, disabled=False, help_text='', error='', classes='', attrs='') %}
|
{% 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) %}
|
{% call form_field(label, name, required, help_text, error, classes) %}
|
||||||
{% block body %}
|
|
||||||
<input type="file"
|
<input type="file"
|
||||||
id="{{ name }}"
|
id="{{ name }}"
|
||||||
name="{{ name }}"
|
name="{{ name }}"
|
||||||
|
|
@ -343,7 +343,7 @@
|
||||||
{% if required %}required{% endif %}
|
{% if required %}required{% endif %}
|
||||||
{% if disabled %}disabled{% endif %}
|
{% if disabled %}disabled{% endif %}
|
||||||
{{ attrs|safe }} />
|
{{ attrs|safe }} />
|
||||||
{% endblock %}
|
|
||||||
{% endcall %}
|
{% endcall %}
|
||||||
{% endmacro %}
|
{% endmacro %}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,7 +77,6 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
<div id="theme-preview-host"></div>
|
<div id="theme-preview-host"></div>
|
||||||
<div id="filter-chips" class="filter-chips" aria-label="Active filters"></div>
|
|
||||||
</div>
|
</div>
|
||||||
<style>
|
<style>
|
||||||
.theme-picker-controls { display:flex; flex-wrap:wrap; gap:.5rem; margin-bottom:.75rem; }
|
.theme-picker-controls { display:flex; flex-wrap:wrap; gap:.5rem; margin-bottom:.75rem; }
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue