mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-01 16:12:02 +00:00
fix: keep an empty draft subject empty so send still warns #1189
This commit is contained in:
@@ -1773,7 +1773,7 @@ function handleEmailSet(args: MethodArgs, callId: string): MethodResult {
|
||||
from: (data.from as MockEmail['from']) || [{ name: 'Dev User', email: 'dev@localhost' }],
|
||||
to: (data.to as MockEmail['to']) || [],
|
||||
cc: (data.cc as MockEmail['cc']) || [],
|
||||
subject: (data.subject as string) || '(no subject)',
|
||||
subject: typeof data.subject === 'string' ? data.subject : '',
|
||||
preview: (previewText || (data.subject as string) || '').slice(0, 120),
|
||||
hasAttachment: false,
|
||||
textBody: [],
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
||||
import { render, screen, fireEvent, waitFor, act, within } from '@testing-library/react';
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import React from 'react';
|
||||
import { EmailComposer } from '../email-composer';
|
||||
import { useAuthStore } from '@/stores/auth-store';
|
||||
|
||||
// ─── Heavy component mocks (mirrors reply-addressing.test.tsx) ────────────────
|
||||
|
||||
@@ -146,6 +147,7 @@ vi.mock('@/lib/plugin-hooks', () => ({
|
||||
getRecipientSuggestions: { call: async () => [] },
|
||||
onRecipientChipsChange: { transform: async (chips: unknown) => chips },
|
||||
onDraftChange: { emit: () => {} },
|
||||
onBeforeDraftAutoSave: { transform: async (draft: unknown) => draft },
|
||||
onBeforeEmailSend: { intercept: async () => true },
|
||||
onComposeSend: { intercept: async () => true },
|
||||
onTransformOutgoingEmail: { transform: async (email: unknown) => email },
|
||||
@@ -272,4 +274,37 @@ describe('composer empty subject warning', () => {
|
||||
await waitFor(() => expect(onSend).toHaveBeenCalledTimes(1));
|
||||
expect(screen.queryByText('empty_subject.title')).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
// A draft saved with a "(No Subject)" placeholder came back with that as
|
||||
// its subject, so sending the resumed draft skipped the warning (#1189).
|
||||
it('saves a draft without a subject as an empty subject', async () => {
|
||||
const createDraft = vi.fn().mockResolvedValue('draft-8');
|
||||
useAuthStore.setState({
|
||||
client: {
|
||||
createDraft,
|
||||
getEmail: vi.fn().mockResolvedValue({ id: 'draft-8', attachments: [] }),
|
||||
hasDelayedSend: () => false,
|
||||
getMaxDelayedSend: () => 0,
|
||||
} as never,
|
||||
activeAccountId: 'acct-A' as never,
|
||||
});
|
||||
|
||||
const requestCloseRef = { current: null } as React.MutableRefObject<((afterClose?: () => void) => void) | null>;
|
||||
render(
|
||||
<EmailComposer
|
||||
initialData={{ ...DRAFT_WITHOUT_SUBJECT, subject: 'Lunch' }}
|
||||
requestCloseRef={requestCloseRef}
|
||||
onClose={vi.fn()}
|
||||
/>
|
||||
);
|
||||
fireEvent.change(screen.getByDisplayValue('Lunch'), { target: { value: '' } });
|
||||
|
||||
act(() => requestCloseRef.current!(vi.fn()));
|
||||
const dialog = await screen.findByRole('alertdialog');
|
||||
fireEvent.click(within(dialog).getByText('save'));
|
||||
|
||||
await waitFor(() => expect(createDraft).toHaveBeenCalled());
|
||||
expect(createDraft.mock.calls[0][1]).toBe('');
|
||||
useAuthStore.setState({ client: null, activeAccountId: null });
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2038,7 +2038,10 @@ export function EmailComposer({
|
||||
const previousDraftId = draftIdRef.current;
|
||||
let savedDraft : AlmostSavedDraft = {
|
||||
to: toAddresses,
|
||||
subject: subject || t('no_subject'),
|
||||
// Save an empty subject as empty. A "(No Subject)" placeholder here
|
||||
// came back as a real subject on reopen, and Send then skipped the
|
||||
// empty-subject warning (#1189).
|
||||
subject,
|
||||
body: draftTextBody,
|
||||
cc: ccAddresses,
|
||||
bcc: bccAddresses,
|
||||
|
||||
@@ -2039,7 +2039,9 @@ export function MailApp({ linkSegments: routeSegments }: MailAppProps = {}) {
|
||||
to: draft.to?.map(a => a.email).filter(Boolean).join(', ') || '',
|
||||
cc: draft.cc?.map(a => a.email).filter(Boolean).join(', ') || '',
|
||||
bcc: draft.bcc?.map(a => a.email).filter(Boolean).join(', ') || '',
|
||||
subject: draft.subject || '',
|
||||
// Drafts saved before #1189 stored an empty subject as the composer's
|
||||
// "(No Subject)" placeholder; reopen those with an empty field.
|
||||
subject: draft.subject && draft.subject !== t('email_composer.no_subject') ? draft.subject : '',
|
||||
body: htmlBody || bodyText,
|
||||
// Re-open in the format the draft was written in: a text-only draft
|
||||
// used to land raw in the rich-text editor (newlines collapsed) and an
|
||||
|
||||
@@ -347,7 +347,9 @@ export function ProEmailView({ emailId, client: clientOverride, accountId, onLoa
|
||||
to: email.to?.map((a) => a.email).filter(Boolean).join(', ') || '',
|
||||
cc: email.cc?.map((a) => a.email).filter(Boolean).join(', ') || '',
|
||||
bcc: email.bcc?.map((a) => a.email).filter(Boolean).join(', ') || '',
|
||||
subject: email.subject || '',
|
||||
// Drafts saved before #1189 stored an empty subject as the composer's
|
||||
// "(No Subject)" placeholder; reopen those with an empty field.
|
||||
subject: email.subject && email.subject !== t('email_composer.no_subject') ? email.subject : '',
|
||||
body: htmlBody || bodyText,
|
||||
showCc: (email.cc?.length || 0) > 0,
|
||||
showBcc: (email.bcc?.length || 0) > 0,
|
||||
|
||||
Reference in New Issue
Block a user