mirror of
https://github.com/bulwarkmail/native.git
synced 2026-11-01 00:07:01 +00:00
fix: tell the user when a queued message gives up after unconfirmed attempts
This commit is contained in:
@@ -154,6 +154,39 @@ describe('offline send queue', () => {
|
||||
expect(useOutboxStore.getState().sends).toEqual([]);
|
||||
});
|
||||
|
||||
it('says so when a message fails after too many unconfirmed attempts, as for a refused one', async () => {
|
||||
useNetworkStore.setState({ online: true, connected: true });
|
||||
runQueuedSend.mockRejectedValueOnce(new Error('Invalid envelope'));
|
||||
useOutboxStore.getState().enqueueSend(payload('refused'));
|
||||
await flushed();
|
||||
await flushed();
|
||||
expect(toast.error).toHaveBeenCalledTimes(1);
|
||||
expect(toast.error.mock.calls[0][1]).toEqual({ message: 'refused: Invalid envelope' });
|
||||
|
||||
toast.error.mockClear();
|
||||
const id = useOutboxStore.getState().enqueueSend(payload('unconfirmed'))!;
|
||||
useOutboxStore.setState({ sends: useOutboxStore.getState().sends.map((s) => (s.id === id ? { ...s, attempts: 2 } : s)) });
|
||||
runQueuedSend.mockRejectedValueOnce(named('SendUnconfirmedError', 'Send confirmation was not received'));
|
||||
useOutboxStore.setState({ flushing: false });
|
||||
await useOutboxStore.getState().flush();
|
||||
await flushed();
|
||||
expect(useOutboxStore.getState().sends.find((s) => s.id === id)).toMatchObject({ status: 'failed', attempts: 3 });
|
||||
expect(toast.error).toHaveBeenCalledTimes(1);
|
||||
expect(toast.error.mock.calls[0]).toEqual([
|
||||
'A message in the Outbox could not be sent', { message: 'unconfirmed: Send confirmation was not received' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('does not report an unconfirmed attempt that will be tried again', async () => {
|
||||
useNetworkStore.setState({ online: true, connected: true });
|
||||
runQueuedSend.mockRejectedValueOnce(named('SendUnconfirmedError', 'Send confirmation was not received'));
|
||||
useOutboxStore.getState().enqueueSend(payload());
|
||||
await flushed();
|
||||
await flushed();
|
||||
expect(useOutboxStore.getState().sends[0]).toMatchObject({ status: 'queued', attempts: 1 });
|
||||
expect(toast.error).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('stops after an expired session without failing the message', async () => {
|
||||
useNetworkStore.setState({ online: true, connected: true });
|
||||
runQueuedSend.mockRejectedValueOnce(named('AuthenticationError', 'Session expired'));
|
||||
|
||||
@@ -690,14 +690,17 @@ async function flushSends(accountId: string): Promise<'done' | 'transient'> {
|
||||
} catch (err) {
|
||||
const kind = classifySendFailure(err, isTransientNetworkError);
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
updateSend(accountId, afterFailure(started, kind, message));
|
||||
const next = afterFailure(started, kind, message);
|
||||
updateSend(accountId, next);
|
||||
// Refused, or unconfirmed too often: it waits for the user now, and
|
||||
// nothing retries it, so say so whatever the reason.
|
||||
if (next.status === 'failed') void notifyQueuedSendFailed(started, message);
|
||||
if (kind === 'auth') {
|
||||
useOutboxStore.setState({ paused: true });
|
||||
break;
|
||||
}
|
||||
if (kind === 'offline' || kind === 'unconfirmed') return 'transient';
|
||||
// Refused: this one waits for the user; the others go on.
|
||||
void notifyQueuedSendFailed(started, message);
|
||||
// Refused: the others go on.
|
||||
}
|
||||
}
|
||||
return 'done';
|
||||
|
||||
Reference in New Issue
Block a user