Skip to content
Merged
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
70 changes: 70 additions & 0 deletions .github/workflows/accessibility.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: Accessibility

on:
pull_request:
branches: [main]
workflow_dispatch:

concurrency:
group: accessibility-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true

jobs:
axe:
name: Axe accessibility checks
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v7

- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.12'

- name: Install uv
uses: astral-sh/setup-uv@v7
with:
version: latest

- name: Install Python dependencies
working-directory: efile_app
run: uv sync --group dev

- name: Set up Node.js
uses: actions/setup-node@v7
with:
node-version: 22
cache: npm
cache-dependency-path: efile_app/package-lock.json

- name: Install browser dependencies
working-directory: efile_app
run: |
npm ci
npx playwright install --with-deps chromium

- name: Seed the local accessibility fixture
working-directory: efile_app
run: |
uv run python manage.py migrate --noinput
uv run python manage.py seed_accessibility_session --output playwright/.auth/a11y.json

- name: Run Axe checks
working-directory: efile_app
env:
A11Y_STORAGE_STATE: playwright/.auth/a11y.json
run: |
uv run python manage.py runserver 127.0.0.1:8000 > /tmp/litefile-a11y-server.log 2>&1 &
curl --retry 30 --retry-connrefused --retry-delay 1 --fail http://127.0.0.1:8000/choose-jurisdiction
npm run test:a11y

- name: Upload accessibility results
if: always()
uses: actions/upload-artifact@v4
with:
name: axe-accessibility-results
path: |
efile_app/test-results/
/tmp/litefile-a11y-server.log
if-no-files-found: warn
4 changes: 4 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ jobs:
working-directory: efile_app
run: npm run format:js:check

- name: Stylelint accessibility rules
working-directory: efile_app
run: npm run lint:css

- name: JavaScript unit tests
working-directory: efile_app
run: npm run test:unit
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ docs/.docusaurus/

# Playwright
test-results/
efile_app/playwright/.auth/
efile_app/screenshots
efile_app/playwright-report
efile_app/tmp
Expand Down
11 changes: 11 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,17 @@ repos:
uv run --directory "$ROOT_DIR/efile_app" css-beautify -r "${files[@]}"
- --

- id: stylelint
name: Stylelint accessibility rules
entry: bash -c
language: system
files: ^efile_app/efile/.*\.css$
args:
- |
ROOT_DIR=$(git rev-parse --show-toplevel)
cd "$ROOT_DIR/efile_app" && npm exec -- stylelint "efile/**/*.css"
- --

- id: js-beautify
name: js-beautify (format)
entry: bash -c
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
padding: 0.5rem 0.75rem;
font-size: 0.95rem;
width: 260px;
outline: none;
outline: 2px solid transparent;
transition: border-color 0.15s;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@
.review-field textarea:focus,
.review-field select:focus,
.lookup-controls select:focus {
outline: none;
outline: 2px solid transparent;
border-color: #1a6b3c;
box-shadow: 0 0 0 3px rgba(26, 107, 60, 0.12);
}
Expand Down
129 changes: 129 additions & 0 deletions efile_app/efile/management/commands/seed_accessibility_session.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
"""Create deterministic, local-only data for browser accessibility checks."""

import json
from pathlib import Path

from django.conf import settings
from django.core.management.base import BaseCommand
from django.test import Client

from efile.models import FilingDocument, FilingDraft, FilingParty, FilingPlan
from efile.services.current_drafts import CURRENT_DRAFT_SESSION_KEY
from efile.workflow import ExistingCase, WorkflowStepKey


class Command(BaseCommand):
help = "Seed a local browser session for the Axe accessibility suite."

def add_arguments(self, parser):
parser.add_argument("--output", required=True, help="Path for Playwright storage state JSON.")
parser.add_argument("--origin", default="http://127.0.0.1:8000", help="Origin served to Playwright.")

def handle(self, *args, **options):
user_model = settings.AUTH_USER_MODEL
from django.apps import apps

user_class = apps.get_model(user_model)
user, _ = user_class.objects.update_or_create(
username="accessibility-checker",
defaults={
"email": "accessibility-checker@example.com",
"tyler_jurisdiction": "illinois",
"tyler_username": "accessibility-checker@example.com",
"first_name": "Avery",
"last_name": "Checker",
},
)
user.set_unusable_password()
user.save()

FilingDraft.objects.filter(user=user).delete()
FilingPlan.objects.filter(user=user).delete()
plan = FilingPlan.objects.create(user=user, jurisdiction="illinois", title="Accessibility test filing")
draft = FilingDraft.objects.create(
user=user,
plan=plan,
jurisdiction="illinois",
workflow_version=2,
existing_case=ExistingCase.NEW,
current_step=WorkflowStepKey.REVIEW,
court_code="cook:cvd1",
court_name="Cook County",
case_category_code="6198",
case_category_name="Small Claims",
case_type_code="183541",
case_type_name="Contract",
filing_type_code="143132",
filing_type_name="Complaint",
document_checklist_acknowledged=True,
selected_payment_account_id="a11y-payment-account",
selected_payment_account_name="Accessibility payment account",
quoted_fee_total="0.00",
)
FilingDocument.objects.create(
draft=draft,
role=FilingDocument.Role.LEAD,
name="Accessibility complaint.pdf",
original_filename="Accessibility complaint.pdf",
filing_type_code="143132",
filing_type_name="Complaint",
document_type_code="public",
document_type_name="Public",
)
FilingParty.objects.create(
draft=draft,
role="filer",
sort_order=0,
first_name="Avery",
last_name="Checker",
address_line_1="100 Main Street",
city="Chicago",
state="IL",
zip_code="60601",
email=user.email,
party_type="plaintiff",
party_type_name="Plaintiff",
is_filing_party=True,
)
other_party = FilingParty.objects.create(
draft=draft,
role="other",
sort_order=1,
first_name="Jordan",
last_name="Example",
)

# Let Django's own test client construct the authenticated session. This
# tracks framework changes to session-auth details without duplicating
# private authentication keys in this browser-only fixture command.
client = Client()
client.force_login(user)
session = client.session
session[CURRENT_DRAFT_SESSION_KEY] = draft.pk
session["jurisdiction"] = "illinois"
session["auth_tokens"] = {"TYLER-TOKEN-ILLINOIS": "accessibility-test-token"}
session.save()

output = Path(options["output"])
output.parent.mkdir(parents=True, exist_ok=True)
output.write_text(
json.dumps(
{
"cookies": [
{
"name": settings.SESSION_COOKIE_NAME,
"value": session.session_key,
"domain": "127.0.0.1",
"path": "/",
"expires": -1,
"httpOnly": True,
"secure": False,
"sameSite": "Lax",
}
],
"origins": [],
},
indent=2,
)
)
self.stdout.write(self.style.SUCCESS(f"Seeded accessibility session for party {other_party.pk}."))
25 changes: 25 additions & 0 deletions efile_app/efile/static/css/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,31 @@ h2 {
--bs-btn-active-border-color: var(--brand-blue-active);
}

/* Bootstrap's default secondary outline is too faint on several light
surfaces, especially in compact controls. */
.btn-outline-secondary {
--bs-btn-color: #343a40;
--bs-btn-border-color: #343a40;
--bs-btn-hover-bg: #343a40;
--bs-btn-hover-border-color: #343a40;
--bs-btn-active-bg: #212529;
--bs-btn-active-border-color: #212529;
}

/* Respect a person's system setting even when an individual component's
motion has not opted into the no-preference media query yet. */
@media (prefers-reduced-motion: reduce) {

*,
*::before,
*::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
scroll-behavior: auto !important;
transition-duration: 0.01ms !important;
}
}

/* Persistent, in-flow feedback shared by account, dashboard, list, and
workflow screens. Messages stay available to zoom and assistive-technology
users until they navigate or correct the problem. */
Expand Down
21 changes: 21 additions & 0 deletions efile_app/efile/static/css/reorganized-flow.css
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,27 @@
margin-top: 0;
}

/* Bootstrap's secondary outline is too light against the warning panel used
for this alternative action. Keep its text and border legible at AA. */
#claim-party-instead-filing-for,
#claim-party-cancel {
--bs-btn-color: #343a40;
--bs-btn-border-color: #343a40;
--bs-btn-hover-bg: #343a40;
--bs-btn-hover-border-color: #343a40;
--bs-btn-active-bg: #212529;
--bs-btn-active-border-color: #212529;
}

.document-plan__save {
--bs-btn-color: #343a40;
--bs-btn-border-color: #343a40;
--bs-btn-hover-bg: #343a40;
--bs-btn-hover-border-color: #343a40;
--bs-btn-active-bg: #212529;
--bs-btn-active-border-color: #212529;
}

.claim-party-dialog .workflow-actions {
display: flex;
gap: 0.75rem;
Expand Down
1 change: 1 addition & 0 deletions efile_app/efile/templates/efile/choose_jurisdiction.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ <h1>{{ the_title }}</h1>
{% for value in jurisdiction_details %}
<div class="option-card" style="position:relative">
<a href="{% url 'jurisdiction_homepage' jurisdiction=value.jurisdiction.code %}"
aria-label="{% blocktranslate with name=value.jurisdiction.display_name %}Choose {{ name }}{% endblocktranslate %}"
style="position:absolute;
width:100%;
height:100%;
Expand Down
8 changes: 5 additions & 3 deletions efile_app/efile/templates/efile/extraction_review.html
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ <h1>{% translate "Tell us about your case" %}</h1>
<div class="review-field"
data-field="case_category"
data-guess-key="case category">
<span>{{ case_category_label }}</span>
<label for="case_category_code">{{ case_category_label }}</label>
<div class="review-field__display" hidden>
<div class="review-field__found">
<i class="fa-solid fa-circle-check" aria-hidden="true"></i>
Expand All @@ -156,7 +156,7 @@ <h1>{% translate "Tell us about your case" %}</h1>
<div class="review-field"
data-field="case_type"
data-guess-key="case type">
<span>{% translate "Case type" %}</span>
<label for="case_type_code">{% translate "Case type" %}</label>
<div class="review-field__display" hidden>
<div class="review-field__found">
<i class="fa-solid fa-circle-check" aria-hidden="true"></i>
Expand All @@ -181,7 +181,9 @@ <h1>{% translate "Tell us about your case" %}</h1>
<div class="review-field"
data-field="filing_type"
data-guess-key="filing type">
<span>{% translate "Filing type" %} <em>{% translate "if known" %}</em></span>
<label for="filing_type_code">
{% translate "Filing type" %} <em>{% translate "if known" %}</em>
</label>
<div class="review-field__display" hidden>
<div class="review-field__found">
<i class="fa-solid fa-circle-check" aria-hidden="true"></i>
Expand Down
4 changes: 2 additions & 2 deletions efile_app/efile/templates/efile/filing_plans.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
</head>
<body>
{% include "efile/components/profile_header.html" %}
<div class="container">
<main class="container">
<h1>{% translate "My filing plans" %}</h1>
<div class="row justify-content-center">
<div class="col-xl-7">
Expand Down Expand Up @@ -156,7 +156,7 @@ <h2 id="plan-{{ entry.plan.pk }}-title">{{ entry.plan.title }}</h2>
class="btn btn-outline-secondary mb-3">{% translate "Go back" %}</a>
</div>
</div>
</div>
</main>
{% comment %}
Forms that act on a whole plan live outside the checklist form: HTML
does not allow a form inside a form, and the buttons above reach these
Expand Down
4 changes: 2 additions & 2 deletions efile_app/efile/templates/efile/my_drafts.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</head>
<body>
{% include "efile/components/profile_header.html" %}
<div class="container">
<main class="container">
<h1>{% translate "My draft e-filings" %}</h1>
<div class="row justify-content-center">
<div class="col-xl-7">
Expand Down Expand Up @@ -91,7 +91,7 @@ <h2 id="draft-{{ entry.draft.pk }}-title">
class="btn btn-outline-secondary mb-3">{% translate "Go back" %}</a>
</div>
</div>
</div>
</main>
{% include "efile/components/footer.html" %}
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.3.0/js/bootstrap.bundle.min.js"></script>
<script src="{% url 'javascript-catalog' %}"></script>
Expand Down
2 changes: 1 addition & 1 deletion efile_app/eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export default [
}
},
{
files: ["js-tests/**/*.js", "tests/**/*.js", "playwright.config.js"],
files: ["js-tests/**/*.js", "tests/**/*.js", "playwright*.config.js"],
languageOptions: {
ecmaVersion: "latest",
sourceType: "commonjs",
Expand Down
Loading
Loading