Skip to content

Commit d113425

Browse files
Get analysis language from platform, improve docs
1 parent 17a7ecd commit d113425

11 files changed

Lines changed: 135 additions & 68 deletions

src/__tests__/components/AnalysisStore.test.tsx

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
* Builds a minimal `TextAnalysis` with a single approved `TokenAnalysis` for the given token.
2121
*
2222
* @param tokenRef - Token reference string.
23-
* @param gloss - Gloss value for the `'en'` language key.
23+
* @param gloss - Gloss value for the `'und'` language key.
2424
* @param surfaceText - Surface text of the token.
2525
* @returns A `TextAnalysis` seeded with one approved token analysis.
2626
*/
@@ -32,7 +32,7 @@ function makeAnalysisWithGloss(
3232
const ta: TokenAnalysis = {
3333
id: `${tokenRef}-analysis`,
3434
surfaceText,
35-
gloss: { en: gloss },
35+
gloss: { und: gloss },
3636
};
3737
const link: TokenAnalysisLink = {
3838
analysisId: ta.id,
@@ -109,7 +109,7 @@ function GlossWriter({
109109
describe('useGloss', () => {
110110
it('returns an empty string for an unknown token', () => {
111111
render(
112-
<AnalysisStoreProvider>
112+
<AnalysisStoreProvider analysisLanguage="und">
113113
<GlossReader tokenRef="tok-1" />
114114
</AnalysisStoreProvider>,
115115
);
@@ -118,7 +118,10 @@ describe('useGloss', () => {
118118

119119
it('returns the approved gloss from initialAnalysis', () => {
120120
render(
121-
<AnalysisStoreProvider initialAnalysis={makeAnalysisWithGloss('tok-1', 'hello')}>
121+
<AnalysisStoreProvider
122+
initialAnalysis={makeAnalysisWithGloss('tok-1', 'hello')}
123+
analysisLanguage="und"
124+
>
122125
<GlossReader tokenRef="tok-1" />
123126
</AnalysisStoreProvider>,
124127
);
@@ -141,7 +144,7 @@ describe('useGloss', () => {
141144
phraseAnalysisLinks: [],
142145
};
143146
render(
144-
<AnalysisStoreProvider initialAnalysis={analysis}>
147+
<AnalysisStoreProvider initialAnalysis={analysis} analysisLanguage="und">
145148
<GlossReader tokenRef="tok-1" />
146149
</AnalysisStoreProvider>,
147150
);
@@ -150,7 +153,7 @@ describe('useGloss', () => {
150153

151154
it('updates when the subscribed token is glossed via dispatch', async () => {
152155
render(
153-
<AnalysisStoreProvider>
156+
<AnalysisStoreProvider analysisLanguage="und">
154157
<GlossReader tokenRef="tok-1" />
155158
<GlossWriter tokenRef="tok-1" surfaceText="word" value="world" />
156159
</AnalysisStoreProvider>,
@@ -170,7 +173,7 @@ describe('useGloss', () => {
170173
}
171174

172175
render(
173-
<AnalysisStoreProvider>
176+
<AnalysisStoreProvider analysisLanguage="und">
174177
<CountingGlossReader tokenRef="tok-1" />
175178
<GlossWriter tokenRef="tok-2" surfaceText="other" value="other" />
176179
</AnalysisStoreProvider>,
@@ -214,7 +217,7 @@ describe('useGloss', () => {
214217
describe('useAnalysis', () => {
215218
it('returns an empty analysis when no initialAnalysis is provided', () => {
216219
render(
217-
<AnalysisStoreProvider>
220+
<AnalysisStoreProvider analysisLanguage="und">
218221
<AnalysisReader />
219222
</AnalysisStoreProvider>,
220223
);
@@ -226,7 +229,7 @@ describe('useAnalysis', () => {
226229
it('returns seeded analyses from initialAnalysis', () => {
227230
const seed = makeAnalysisWithGloss('tok-1', 'hi');
228231
render(
229-
<AnalysisStoreProvider initialAnalysis={seed}>
232+
<AnalysisStoreProvider initialAnalysis={seed} analysisLanguage="und">
230233
<AnalysisReader />
231234
</AnalysisStoreProvider>,
232235
);
@@ -237,15 +240,15 @@ describe('useAnalysis', () => {
237240

238241
it('updates after a gloss write', async () => {
239242
render(
240-
<AnalysisStoreProvider>
243+
<AnalysisStoreProvider analysisLanguage="und">
241244
<AnalysisReader />
242245
<GlossWriter tokenRef="tok-1" surfaceText="word" value="world" />
243246
</AnalysisStoreProvider>,
244247
);
245248
await userEvent.click(screen.getByRole('button', { name: 'write' }));
246249
const analysis: TextAnalysis = JSON.parse(screen.getByTestId('analysis').textContent ?? '');
247250
expect(analysis.tokenAnalyses).toHaveLength(1);
248-
expect(analysis.tokenAnalyses[0].gloss).toStrictEqual({ en: 'world' });
251+
expect(analysis.tokenAnalyses[0].gloss).toStrictEqual({ und: 'world' });
249252
expect(analysis.tokenAnalysisLinks[0].status).toBe('approved');
250253
});
251254

@@ -260,7 +263,7 @@ describe('useAnalysis', () => {
260263
describe('useGlossDispatch', () => {
261264
it('creates a new approved TokenAnalysis on each write', async () => {
262265
render(
263-
<AnalysisStoreProvider>
266+
<AnalysisStoreProvider analysisLanguage="und">
264267
<AnalysisReader />
265268
<GlossWriter tokenRef="tok-1" surfaceText="word" value="hi" />
266269
</AnalysisStoreProvider>,
@@ -293,7 +296,7 @@ describe('useGlossDispatch', () => {
293296
phraseAnalysisLinks: [],
294297
};
295298
render(
296-
<AnalysisStoreProvider initialAnalysis={seed}>
299+
<AnalysisStoreProvider initialAnalysis={seed} analysisLanguage="und">
297300
<AnalysisReader />
298301
<GlossWriter tokenRef="tok-1" surfaceText="word" value="new" />
299302
</AnalysisStoreProvider>,
@@ -310,7 +313,7 @@ describe('useGlossDispatch', () => {
310313
it('calls the onGlossChange spy with tokenRef and value', async () => {
311314
const spy = jest.fn();
312315
render(
313-
<AnalysisStoreProvider onGlossChange={spy}>
316+
<AnalysisStoreProvider analysisLanguage="und" onGlossChange={spy}>
314317
<GlossWriter tokenRef="tok-1" surfaceText="word" value="hi" />
315318
</AnalysisStoreProvider>,
316319
);
@@ -322,14 +325,14 @@ describe('useGlossDispatch', () => {
322325
it('calls onSave with the updated TextAnalysis', async () => {
323326
const onSave = jest.fn();
324327
render(
325-
<AnalysisStoreProvider onSave={onSave}>
328+
<AnalysisStoreProvider analysisLanguage="und" onSave={onSave}>
326329
<GlossWriter tokenRef="tok-1" surfaceText="word" value="hi" />
327330
</AnalysisStoreProvider>,
328331
);
329332
await userEvent.click(screen.getByRole('button', { name: 'write' }));
330333
expect(onSave).toHaveBeenCalledTimes(1);
331334
const saved: TextAnalysis = onSave.mock.calls[0][0];
332-
expect(saved.tokenAnalyses[0].gloss).toStrictEqual({ en: 'hi' });
335+
expect(saved.tokenAnalyses[0].gloss).toStrictEqual({ und: 'hi' });
333336
});
334337

335338
it('throws when called outside an AnalysisStoreProvider', () => {

src/__tests__/components/ContinuousView.test.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,19 @@ import { AnalysisStoreProvider } from '../../components/AnalysisStore';
1515

1616
jest.mock('../../components/AnalysisStore', () => ({
1717
__esModule: true,
18-
AnalysisStoreProvider({ children }: Readonly<{ children: ReactNode }>) {
18+
AnalysisStoreProvider({ children }: Readonly<{ children: ReactNode; analysisLanguage: string }>) {
1919
return children;
2020
},
2121
useGloss: () => '',
2222
useGlossDispatch: () => () => {},
2323
}));
2424

2525
/** Render options that wrap every test render in a `AnalysisStoreProvider`. */
26-
const withAnalysisStore = { wrapper: AnalysisStoreProvider };
26+
const withAnalysisStore = {
27+
wrapper({ children }: Readonly<{ children: ReactNode }>) {
28+
return <AnalysisStoreProvider analysisLanguage="und">{children}</AnalysisStoreProvider>;
29+
},
30+
};
2731

2832
jest.mock('../../components/TokenChip', () => ({
2933
__esModule: true,

src/__tests__/components/Interlinearizer.test.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,7 @@ function renderInterlinearizer({
171171
continuousScroll={continuousScroll}
172172
scrRef={scrRef}
173173
setScrRef={setScrRef}
174+
analysisLanguage="und"
174175
/>,
175176
);
176177
}
@@ -304,6 +305,7 @@ describe('Interlinearizer', () => {
304305
continuousScroll
305306
scrRef={defaultScrRef}
306307
setScrRef={() => {}}
308+
analysisLanguage="und"
307309
/>,
308310
);
309311

@@ -349,6 +351,7 @@ describe('Interlinearizer', () => {
349351
continuousScroll
350352
scrRef={defaultScrRef}
351353
setScrRef={() => {}}
354+
analysisLanguage="und"
352355
/>,
353356
);
354357

@@ -380,6 +383,7 @@ describe('Interlinearizer', () => {
380383
continuousScroll={false}
381384
scrRef={defaultScrRef}
382385
setScrRef={() => {}}
386+
analysisLanguage="und"
383387
/>,
384388
);
385389

@@ -406,6 +410,7 @@ describe('Interlinearizer', () => {
406410
continuousScroll={false}
407411
scrRef={{ book: 'GEN', chapterNum: 1, verseNum: 1 }}
408412
setScrRef={() => {}}
413+
analysisLanguage="und"
409414
/>,
410415
);
411416

@@ -438,6 +443,7 @@ describe('Interlinearizer', () => {
438443
continuousScroll
439444
scrRef={defaultScrRef}
440445
setScrRef={() => {}}
446+
analysisLanguage="und"
441447
/>,
442448
);
443449

@@ -450,6 +456,7 @@ describe('Interlinearizer', () => {
450456
continuousScroll={false}
451457
scrRef={defaultScrRef}
452458
setScrRef={() => {}}
459+
analysisLanguage="und"
453460
/>,
454461
);
455462

@@ -504,6 +511,7 @@ describe('Interlinearizer', () => {
504511
continuousScroll={false}
505512
scrRef={{ book: 'GEN', chapterNum: 1, verseNum: 99 }}
506513
setScrRef={() => {}}
514+
analysisLanguage="und"
507515
/>,
508516
);
509517

src/__tests__/components/InterlinearizerLoader.test.tsx

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ jest.mock('../../components/ContinuousView', () => ({
4949

5050
type CapturedInterlinearizerProps = {
5151
continuousScroll: boolean;
52+
analysisLanguage: string | undefined;
5253
};
5354
let capturedInterlinearizerProps: CapturedInterlinearizerProps | undefined;
5455

@@ -271,6 +272,25 @@ function mockOptimisticSetting(
271272
return onChange;
272273
}
273274

275+
/**
276+
* Configures `useSetting` to return per-key values for the two settings consumed by
277+
* `InterlinearizerLoader`: `platform.interfaceMode` and `platform.interfaceLanguage`.
278+
*
279+
* @param interfaceMode - Value for `platform.interfaceMode`; defaults to `'simple'`.
280+
* @param interfaceLanguage - Value for `platform.interfaceLanguage`; defaults to `[]`.
281+
*/
282+
function mockSettings(
283+
interfaceMode: 'simple' | 'power' = 'simple',
284+
interfaceLanguage: string[] = [],
285+
): void {
286+
jest.mocked(useSetting).mockImplementation((key: string) => {
287+
if (key === 'platform.interfaceMode') return [interfaceMode, jest.fn(), jest.fn(), false];
288+
if (key === 'platform.interfaceLanguage')
289+
return [interfaceLanguage, jest.fn(), jest.fn(), false];
290+
throw new Error(`useSetting mock: unexpected key "${key}"`);
291+
});
292+
}
293+
274294
describe('InterlinearizerLoader', () => {
275295
beforeEach(() => {
276296
capturedInterlinearizerProps = undefined;
@@ -282,11 +302,11 @@ describe('InterlinearizerLoader', () => {
282302
new Proxy({}, { get: () => jest.fn().mockReturnValue([undefined, jest.fn(), false]) }),
283303
);
284304
jest.mocked(useLocalizedStrings).mockReturnValue([{}, false]);
285-
jest.mocked(useSetting).mockReturnValue(['simple', jest.fn(), jest.fn(), false]);
305+
mockSettings();
286306
});
287307

288308
it('shows nav controls when interface mode is power', () => {
289-
jest.mocked(useSetting).mockReturnValue(['power', jest.fn(), jest.fn(), false]);
309+
mockSettings('power');
290310
render(
291311
<InterlinearizerLoader
292312
projectId={testProjectId}
@@ -429,6 +449,31 @@ describe('InterlinearizerLoader', () => {
429449
expect(screen.getByTestId('interlinearizer')).toBeInTheDocument();
430450
});
431451

452+
it('passes the first interfaceLanguage tag to Interlinearizer as analysisLanguage', () => {
453+
mockSettings('simple', ['fr', 'en']);
454+
render(
455+
<InterlinearizerLoader
456+
projectId={testProjectId}
457+
useWebViewScrollGroupScrRef={makeScrollGroupHook()}
458+
useWebViewState={makeWebViewState()}
459+
/>,
460+
);
461+
462+
expect(capturedInterlinearizerProps?.analysisLanguage).toBe('fr');
463+
});
464+
465+
it('passes "und" to Interlinearizer as analysisLanguage when interfaceLanguage is empty', () => {
466+
render(
467+
<InterlinearizerLoader
468+
projectId={testProjectId}
469+
useWebViewScrollGroupScrRef={makeScrollGroupHook()}
470+
useWebViewState={makeWebViewState()}
471+
/>,
472+
);
473+
474+
expect(capturedInterlinearizerProps?.analysisLanguage).toBe('und');
475+
});
476+
432477
describe('modal interactions', () => {
433478
it('opens the select modal when the project menu selectProject item is clicked', async () => {
434479
render(

0 commit comments

Comments
 (0)