(null);
@@ -149,7 +150,10 @@ export function ScoreView({ song, projectId, onSongUpdate }: ScoreViewProps) {
{!projectId && (
-
+
{t("scoreRequiresProject")}
)}
@@ -185,6 +189,7 @@ export function ScoreView({ song, projectId, onSongUpdate }: ScoreViewProps) {
type="button"
onClick={projectId ? () => void openAttachment(projectId, attachment) : undefined}
aria-disabled={!projectId ? true : undefined}
+ aria-describedby={!projectId ? scoreRequiresProjectId : undefined}
title={!projectId ? t("scoreNavDisabledHint") : undefined}
aria-current={selected?.id === attachment.id ? "true" : undefined}
aria-label={`${t("scoreOpen")}: ${attachment.fileName}`}
From 93b03bca68190babaed84b8f51a13bec89bb2fd6 Mon Sep 17 00:00:00 2001
From: Seongho Bae
Date: Mon, 3 Aug 2026 11:30:19 +0900
Subject: [PATCH 3/4] test(a11y): bind disabled score controls to visible
reason
---
.../score/ScoreView.accessibility.test.tsx | 70 +++++++++++++++++++
1 file changed, 70 insertions(+)
create mode 100644 apps/desktop/src/features/score/ScoreView.accessibility.test.tsx
diff --git a/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx b/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx
new file mode 100644
index 00000000..242194fd
--- /dev/null
+++ b/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx
@@ -0,0 +1,70 @@
+"";
+import { render, screen } from "@testing-library/react";
+import { describe, expect, it, vi } from "vitest";
+import type { RehearsalSong } from "@bandscope/shared-types";
+import { ScoreView } from "./ScoreView";
+
+vi.mock("@tauri-apps/api/core", () => ({
+ invoke: vi.fn()
+}));
+
+vi.mock("./ScoreViewer", () => ({
+ ScoreViewer: () =>
+}));
+
+vi.mock("../../i18n", () => ({
+ createTranslator: () => (key: string) =>
+ ({
+ scoreViewTitle: "Score",
+ scoreViewSubtitle: "Attach validated PDF scores to the current song.",
+ scoreListTitle: "Attached scores",
+ scoreAttach: "Add score",
+ scoreRemove: "Remove",
+ scoreOpen: "Open score",
+ scoreRequiresProject: "Scores attach to the active analysis project.",
+ scoreNavDisabledHint: "Analyze or open a song first"
+ })[key] ?? key,
+ detectPreferredLocale: () => "en"
+}));
+
+const song = {
+ id: "song-a11y",
+ title: "Accessible Set",
+ sections: [],
+ exportSummary: { format: "cue-sheet", headline: "", focusSections: [] },
+ scoreAttachments: [
+ {
+ id: "score-a11y",
+ fileName: "opener.pdf"
+ }
+ ]
+} as RehearsalSong;
+
+describe("ScoreView disabled-score accessibility", () => {
+ it("references the visible disabled reason from each unavailable score button", () => {
+ render();
+
+ const reason = screen.getByText("Scores attach to the active analysis project.");
+ const openButton = screen.getByRole("button", { name: "Open score: opener.pdf" });
+ const descriptionId = openButton.getAttribute("aria-describedby");
+
+ expect(openButton).toHaveAttribute("aria-disabled", "true");
+ expect(openButton).toHaveAttribute("title", "Analyze or open a song first");
+ expect(descriptionId).toBe(reason.id);
+ expect(descriptionId).not.toBe("");
+ expect(document.getElementById(descriptionId ?? "")).toBe(reason);
+ });
+
+ it("removes disabled-only semantics when a project workspace is available", () => {
+ render();
+
+ const openButton = screen.getByRole("button", { name: "Open score: opener.pdf" });
+
+ expect(openButton).not.toHaveAttribute("aria-disabled");
+ expect(openButton).not.toHaveAttribute("aria-describedby");
+ expect(openButton).not.toHaveAttribute("title");
+ expect(
+ screen.queryByText("Scores attach to the active analysis project.")
+ ).not.toBeInTheDocument();
+ });
+});
From a1fbd1941b5a5b42cb37aa2b1beea325ef63bec1 Mon Sep 17 00:00:00 2001
From: Seongho Bae
Date: Mon, 3 Aug 2026 11:30:51 +0900
Subject: [PATCH 4/4] test(a11y): clean accessibility regression fixture
---
apps/desktop/src/features/score/ScoreView.accessibility.test.tsx | 1 -
1 file changed, 1 deletion(-)
diff --git a/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx b/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx
index 242194fd..b960456c 100644
--- a/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx
+++ b/apps/desktop/src/features/score/ScoreView.accessibility.test.tsx
@@ -1,4 +1,3 @@
-"";
import { render, screen } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import type { RehearsalSong } from "@bandscope/shared-types";