Skip to content

Commit a1648f5

Browse files
Align stub with actual implementation, send notification when save/submission fails, docs adjustments
1 parent ed53cb0 commit a1648f5

7 files changed

Lines changed: 55 additions & 14 deletions

File tree

src/__tests__/components/CreateProjectModal.test.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ describe('CreateProjectModal', () => {
210210
expect(onClose).not.toHaveBeenCalled();
211211
});
212212

213-
it('does not call onProjectCreated, onClose, or send a notification when sendCommand returns undefined', async () => {
213+
it('does not call onProjectCreated or onClose when sendCommand returns undefined', async () => {
214214
jest.mocked(papi.commands.sendCommand).mockResolvedValue(undefined);
215215
const onProjectCreated = jest.fn();
216216
const onClose = jest.fn();
@@ -227,7 +227,20 @@ describe('CreateProjectModal', () => {
227227
await waitFor(() => expect(papi.commands.sendCommand).toHaveBeenCalled());
228228
expect(onProjectCreated).not.toHaveBeenCalled();
229229
expect(onClose).not.toHaveBeenCalled();
230-
expect(papi.notifications.send).not.toHaveBeenCalled();
230+
});
231+
232+
it('sends an error notification when sendCommand returns undefined', async () => {
233+
jest.mocked(papi.commands.sendCommand).mockResolvedValue(undefined);
234+
render(<CreateProjectModal projectId={testProjectId} onClose={jest.fn()} />);
235+
236+
await userEvent.click(screen.getByRole('button', { name: /^create$/i }));
237+
238+
await waitFor(() =>
239+
expect(papi.notifications.send).toHaveBeenCalledWith({
240+
message: '%interlinearizer_error_create_project_failed%',
241+
severity: 'error',
242+
}),
243+
);
231244
});
232245

233246
it('defaults analysis language to ["und"] when the language input contains only whitespace', async () => {

src/__tests__/components/InterlinearizerLoader.test.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ jest.mock('../../components/ProjectModals', () => ({
140140
data-testid="create-modal-created"
141141
onClick={() => {
142142
setActiveProject(STUB_ACTIVE_PROJECT);
143-
setModal('select');
143+
setModal('none');
144144
}}
145145
>
146146
Created
@@ -624,7 +624,7 @@ describe('InterlinearizerLoader', () => {
624624
expect(screen.queryByTestId('create-modal')).not.toBeInTheDocument();
625625
});
626626

627-
it('returns to the select modal after a project is created from the select modal', async () => {
627+
it('closes all modals after a project is created from the select modal', async () => {
628628
render(
629629
<InterlinearizerLoader
630630
projectId={testProjectId}
@@ -638,7 +638,7 @@ describe('InterlinearizerLoader', () => {
638638
await userEvent.click(screen.getByTestId('create-modal-created'));
639639

640640
expect(screen.queryByTestId('create-modal')).not.toBeInTheDocument();
641-
expect(screen.getByTestId('select-modal')).toBeInTheDocument();
641+
expect(screen.queryByTestId('select-modal')).not.toBeInTheDocument();
642642
});
643643

644644
it('sets the active project and closes the select modal when a project is selected', async () => {

src/__tests__/components/ProjectMetadataModal.test.tsx

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -219,7 +219,7 @@ describe('ProjectMetadataModal', () => {
219219
);
220220
});
221221

222-
it('does not call onProjectSaved, onClose, or send a notification when save sendCommand resolves with a falsy value', async () => {
222+
it('does not call onProjectSaved or onClose when save sendCommand resolves with a falsy value', async () => {
223223
mockSendCommand.mockResolvedValue(undefined);
224224
const onProjectSaved = jest.fn();
225225
const onClose = jest.fn();
@@ -232,7 +232,20 @@ describe('ProjectMetadataModal', () => {
232232
await waitFor(() => expect(mockSendCommand).toHaveBeenCalled());
233233
expect(onProjectSaved).not.toHaveBeenCalled();
234234
expect(onClose).not.toHaveBeenCalled();
235-
expect(papi.notifications.send).not.toHaveBeenCalled();
235+
});
236+
237+
it('sends an error notification when save sendCommand resolves with a falsy value', async () => {
238+
mockSendCommand.mockResolvedValue(undefined);
239+
render(<ProjectMetadataModal {...testProps} />);
240+
241+
await userEvent.click(screen.getByRole('button', { name: /^save$/i }));
242+
243+
await waitFor(() =>
244+
expect(papi.notifications.send).toHaveBeenCalledWith({
245+
message: '%interlinearizer_error_save_metadata_failed%',
246+
severity: 'error',
247+
}),
248+
);
236249
});
237250

238251
it('does not call onProjectSaved, onClose, or send a notification when save sendCommand rejects', async () => {

src/__tests__/components/ProjectModals.test.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ jest.mock('../../components/CreateProjectModal', () => ({
8181
<button
8282
type="button"
8383
data-testid="create-created"
84-
onClick={() => onProjectCreated(MOCK_PROJECT)}
84+
onClick={() => {
85+
onProjectCreated(MOCK_PROJECT);
86+
onClose();
87+
}}
8588
>
8689
Created
8790
</button>

src/components/CreateProjectModal.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,13 @@ export function CreateProjectModal({
8080
name.trim() || undefined,
8181
description.trim() || undefined,
8282
);
83-
if (!projectJson) return;
83+
if (!projectJson) {
84+
await papi.notifications.send({
85+
message: '%interlinearizer_error_create_project_failed%',
86+
severity: 'error',
87+
});
88+
return;
89+
}
8490
const parsed: unknown = JSON.parse(projectJson);
8591
if (!isInterlinearProjectSummary(parsed)) {
8692
await papi.notifications.send({

src/components/ProjectMetadataModal.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,13 @@ export function ProjectMetadataModal({
117117
newLanguages,
118118
targetProjectId,
119119
);
120-
if (!updatedProjectJson) return;
120+
if (!updatedProjectJson) {
121+
await papi.notifications.send({
122+
message: '%interlinearizer_error_save_metadata_failed%',
123+
severity: 'error',
124+
});
125+
return;
126+
}
121127
onProjectSaved?.({
122128
name: newName,
123129
description: newDescription,

src/types/interlinearizer.d.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ declare module 'papi-shared-types' {
5353
* and to decide whether to show "create new" vs "select existing" on first open.
5454
*
5555
* @param sourceProjectId Platform.Bible project ID of the source text to query.
56-
* @returns A JSON string containing an `InterlinearProjectSummary[]`; `"[]"` when none exist.
56+
* @returns A JSON string containing an `InterlinearProject[]`; `"[]"` when none exist.
5757
*/
5858
'interlinearizer.getProjectsForSource': (sourceProjectId: string) => Promise<string>;
5959

@@ -574,7 +574,7 @@ declare module 'interlinearizer' {
574574
/** The `Analysis.id` for the linked analysis payload record. */
575575
analysisId: string;
576576

577-
/** Required review status. */
577+
/** Review status of this analysis assignment. */
578578
status: AssignmentStatus;
579579

580580
/** How much to trust this analysis assignment. */
@@ -792,8 +792,8 @@ declare module 'interlinearizer' {
792792

793793
/** Links one `PhraseAnalysis` payload record to one or more token snapshots. */
794794
export interface PhraseAnalysisLink extends AnalysisLink {
795-
/** Ordered snapshots of tokens that compose this phrase. */
796-
tokens: [TokenSnapshot, ...TokenSnapshot[]];
795+
/** Ordered snapshots of tokens that compose this phrase (one or more). */
796+
tokens: TokenSnapshot[];
797797
}
798798

799799
/**

0 commit comments

Comments
 (0)