Skip to content

Commit 816ea6e

Browse files
Refactor interlinearizer WebView for accessibility and update tests
- Change role from 'group' to 'radiogroup' for JSON view mode buttons to improve accessibility. - Update button roles to 'radio' and aria attributes to 'aria-checked' for better semantic meaning. - Modify tests to reflect the updated roles and ensure proper functionality of the JSON view mode switch.
1 parent 47d4140 commit 816ea6e

4 files changed

Lines changed: 24 additions & 24 deletions

File tree

src/__tests__/interlinearizer.web-view.test.tsx

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -107,11 +107,11 @@ describe('InterlinearizerWebView', () => {
107107
it('renders the JSON view mode switch (InterlinearData / Interlinearization / Analyses)', () => {
108108
render(<InterlinearizerWebView {...testWebViewProps} />);
109109

110-
const group = screen.getByRole('group', { name: /json view mode/i });
111-
expect(group).toBeInTheDocument();
112-
expect(screen.getByRole('button', { name: /^interlineardata$/i })).toBeInTheDocument();
113-
expect(screen.getByRole('button', { name: /^interlinearization$/i })).toBeInTheDocument();
114-
expect(screen.getByRole('button', { name: /^analyses$/i })).toBeInTheDocument();
110+
const radiogroup = screen.getByRole('radiogroup', { name: /json view mode/i });
111+
expect(radiogroup).toBeInTheDocument();
112+
expect(screen.getByRole('radio', { name: /^interlineardata$/i })).toBeInTheDocument();
113+
expect(screen.getByRole('radio', { name: /^interlinearization$/i })).toBeInTheDocument();
114+
expect(screen.getByRole('radio', { name: /^analyses$/i })).toBeInTheDocument();
115115
expect(screen.getByText(/view json as:/i)).toBeInTheDocument();
116116
});
117117

@@ -150,7 +150,7 @@ describe('InterlinearizerWebView', () => {
150150
it('switching to Interlinearization shows converted model JSON', () => {
151151
render(<InterlinearizerWebView {...testWebViewProps} />);
152152

153-
fireEvent.click(screen.getByRole('button', { name: /^interlinearization$/i }));
153+
fireEvent.click(screen.getByRole('radio', { name: /^interlinearization$/i }));
154154

155155
expect(screen.getByText(/^Interlinearization \(JSON\):$/)).toBeInTheDocument();
156156
expect(screen.getByText(/analysisLanguages/i)).toBeInTheDocument();
@@ -161,10 +161,10 @@ describe('InterlinearizerWebView', () => {
161161
it('switching back to InterlinearData shows PT9 structure JSON', () => {
162162
render(<InterlinearizerWebView {...testWebViewProps} />);
163163

164-
fireEvent.click(screen.getByRole('button', { name: /^interlinearization$/i }));
164+
fireEvent.click(screen.getByRole('radio', { name: /^interlinearization$/i }));
165165
expect(screen.getByText(/^Interlinearization \(JSON\):$/)).toBeInTheDocument();
166166

167-
fireEvent.click(screen.getByRole('button', { name: /^interlineardata$/i }));
167+
fireEvent.click(screen.getByRole('radio', { name: /^interlineardata$/i }));
168168

169169
expect(screen.getByText(/^InterlinearData \(JSON\):$/)).toBeInTheDocument();
170170
expect(screen.getByText(/glossLanguage/i)).toBeInTheDocument();
@@ -174,7 +174,7 @@ describe('InterlinearizerWebView', () => {
174174
it('switching to Analyses shows analysis map JSON from test data', () => {
175175
render(<InterlinearizerWebView {...testWebViewProps} />);
176176

177-
fireEvent.click(screen.getByRole('button', { name: /^analyses$/i }));
177+
fireEvent.click(screen.getByRole('radio', { name: /^analyses$/i }));
178178

179179
expect(screen.getByText(/^Analyses \(JSON\):$/)).toBeInTheDocument();
180180
expect(mockCreateAnalyses).toHaveBeenCalledWith(stubInterlinearData);
@@ -187,7 +187,7 @@ describe('InterlinearizerWebView', () => {
187187
mockConvert.mockReturnValueOnce(undefined);
188188

189189
const { container } = render(<InterlinearizerWebView {...testWebViewProps} />);
190-
fireEvent.click(screen.getByRole('button', { name: /^interlinearization$/i }));
190+
fireEvent.click(screen.getByRole('radio', { name: /^interlinearization$/i }));
191191

192192
const jsonPre = container.querySelector('pre');
193193
expect(jsonPre).toBeInTheDocument();

src/__tests__/parsers/paratext-9/paratext9Converter.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ describe('convertParatext9ToInterlinearization', () => {
212212
};
213213
const result = convertParatext9ToInterlinearization(data);
214214

215+
expect(result.books[0].textVersion).toBe('H1');
215216
expect(result.books[0].segments[0].occurrences[0].assignments[0].status).toBe('approved');
216217
});
217218
});

src/interlinearizer.web-view.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,42 +91,45 @@ globalThis.webViewComponent = function InterlinearizerWebView() {
9191
<span className="tw-text-sm tw-font-medium tw-text-foreground">View JSON as:</span>
9292
<div
9393
className="tw-inline-flex tw-rounded-md tw-border tw-border-border tw-bg-muted tw-p-0.5"
94-
role="group"
94+
role="radiogroup"
9595
aria-label="JSON view mode"
9696
>
9797
<button
9898
type="button"
99+
role="radio"
99100
onClick={() => setJsonViewMode('interlinear-data')}
100101
className={`tw-rounded tw-px-3 tw-py-1.5 tw-text-sm tw-font-medium tw-transition-colors ${
101102
jsonViewMode === 'interlinear-data'
102103
? 'tw-bg-background tw-text-foreground tw-shadow-sm'
103104
: 'tw-text-muted-foreground hover:tw-text-foreground'
104105
}`}
105-
aria-pressed={jsonViewMode === 'interlinear-data'}
106+
aria-checked={jsonViewMode === 'interlinear-data'}
106107
>
107108
InterlinearData
108109
</button>
109110
<button
110111
type="button"
112+
role="radio"
111113
onClick={() => setJsonViewMode('interlinearization')}
112114
className={`tw-rounded tw-px-3 tw-py-1.5 tw-text-sm tw-font-medium tw-transition-colors ${
113115
jsonViewMode === 'interlinearization'
114116
? 'tw-bg-background tw-text-foreground tw-shadow-sm'
115117
: 'tw-text-muted-foreground hover:tw-text-foreground'
116118
}`}
117-
aria-pressed={jsonViewMode === 'interlinearization'}
119+
aria-checked={jsonViewMode === 'interlinearization'}
118120
>
119121
Interlinearization
120122
</button>
121123
<button
122124
type="button"
125+
role="radio"
123126
onClick={() => setJsonViewMode('analyses')}
124127
className={`tw-rounded tw-px-3 tw-py-1.5 tw-text-sm tw-font-medium tw-transition-colors ${
125128
jsonViewMode === 'analyses'
126129
? 'tw-bg-background tw-text-foreground tw-shadow-sm'
127130
: 'tw-text-muted-foreground hover:tw-text-foreground'
128131
}`}
129-
aria-pressed={jsonViewMode === 'analyses'}
132+
aria-checked={jsonViewMode === 'analyses'}
130133
>
131134
Analyses
132135
</button>

src/parsers/paratext-9/paratext9Converter.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -134,23 +134,19 @@ function convertVerseToSegment(
134134
const segmentId = generateSegmentId(verseRef);
135135

136136
const wordOccurrences = verseData.clusters.map((cluster, clusterIndex): Occurrence => {
137+
const occurrenceId = generateOccurrenceIdFromCluster(segmentId, cluster.id, clusterIndex);
137138
const assignments = cluster.lexemes.map((lexeme): AnalysisAssignment => {
138139
const analysisId = generateAnalysisId(lexeme.lexemeId, lexeme.senseId, glossLanguage);
139-
const assignmentId = generateAssignmentId(
140-
generateOccurrenceIdFromCluster(segmentId, cluster.id, clusterIndex),
141-
analysisId,
142-
);
140+
const assignmentId = generateAssignmentId(occurrenceId, analysisId);
143141

144142
return {
145143
id: assignmentId,
146-
occurrenceId: generateOccurrenceIdFromCluster(segmentId, cluster.id, clusterIndex),
144+
occurrenceId,
147145
analysisId,
148146
status: verseData.hash ? AssignmentStatus.Approved : AssignmentStatus.Suggested,
149147
};
150148
});
151149

152-
const occurrenceId = generateOccurrenceIdFromCluster(segmentId, cluster.id, clusterIndex);
153-
154150
return {
155151
id: occurrenceId,
156152
segmentId,
@@ -258,9 +254,9 @@ export function convertParatext9ToInterlinearization(
258254
return convertVerseToSegment(verseRef, verseData, glossLanguage);
259255
});
260256

261-
const verseDataArray = Object.values(verses);
262-
const verseWithHash = verseDataArray.find((verseData) => verseData.hash);
263-
const textVersion = verseWithHash?.hash || '';
257+
const sortedVerseRefs = Object.keys(verses).sort();
258+
const firstVerseRefWithHash = sortedVerseRefs.find((ref) => verses[ref].hash);
259+
const textVersion = firstVerseRefWithHash !== undefined ? verses[firstVerseRefWithHash].hash : '';
264260

265261
const analyzedBook: AnalyzedBook = {
266262
id: analyzedBookId,

0 commit comments

Comments
 (0)