diff --git a/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.constants.ts b/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.constants.ts index f129e3fb283..d052e059801 100644 --- a/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.constants.ts +++ b/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.constants.ts @@ -1,3 +1,5 @@ +export const STORED_SECRET_PLACEHOLDER = '••••••••••••••••' + export const defaultDisabledSmtpFormValues = { SMTP_ADMIN_EMAIL: null, SMTP_SENDER_NAME: null, diff --git a/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.test.tsx b/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.test.tsx new file mode 100644 index 00000000000..595b4a4a78b --- /dev/null +++ b/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.test.tsx @@ -0,0 +1,69 @@ +import { screen } from '@testing-library/react' +import userEvent from '@testing-library/user-event' +import { HttpResponse } from 'msw' +import { describe, expect, test, vi } from 'vitest' + +import { SmtpForm } from './SmtpForm' +import type { components } from '@/data/api' +import { customRender } from '@/tests/lib/custom-render' +import { addAPIMock } from '@/tests/lib/msw' + +type AuthConfigResponse = components['schemas']['GoTrueConfigResponse'] + +vi.mock('@/lib/constants', async (importOriginal) => { + const actual = await importOriginal() + return { ...actual, IS_PLATFORM: true } +}) + +vi.mock('@/hooks/misc/useSelectedProject', () => ({ + useSelectedProjectQuery: () => ({ data: { ref: 'default', inserted_at: null } }), +})) + +vi.mock('@/hooks/misc/useCheckPermissions', () => ({ + useAsyncCheckPermissions: () => ({ can: true, isLoading: false, isSuccess: true }), +})) + +const SMTP_CONFIGURED_CONFIG = { + SMTP_ADMIN_EMAIL: 'admin@example.com', + SMTP_SENDER_NAME: 'Example', + SMTP_USER: 'smtp-user', + SMTP_HOST: 'smtp.example.com', + SMTP_PASS: 'stored-password-marker', + SMTP_PORT: '587', + SMTP_MAX_FREQUENCY: 60, +} + +function mockAuthConfig(overrides: Partial) { + addAPIMock({ + method: 'get', + path: '/platform/auth/:ref/config', + response: () => HttpResponse.json({ ...overrides } as AuthConfigResponse), + }) +} + +describe('SmtpForm', () => { + test('shows a hidden-password placeholder when a password is already saved', async () => { + mockAuthConfig(SMTP_CONFIGURED_CONFIG) + + customRender() + + expect( + await screen.findByText('Stored password is hidden. Enter a new password to replace it.') + ).toBeInTheDocument() + expect(screen.getByPlaceholderText('••••••••••••••••')).toBeInTheDocument() + }) + + test('does not show the hidden-password copy or placeholder for a fresh, never-configured setup', async () => { + mockAuthConfig({}) + + customRender() + + await userEvent.click(await screen.findByLabelText('Toggle SMTP')) + + expect(await screen.findByText('Password for your SMTP server.')).toBeInTheDocument() + expect(screen.queryByPlaceholderText('••••••••••••••••')).not.toBeInTheDocument() + expect( + screen.queryByText('Stored password is hidden. Enter a new password to replace it.') + ).not.toBeInTheDocument() + }) +}) diff --git a/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.tsx b/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.tsx index 4984ad5ea8a..afbc5c6f3dc 100644 --- a/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.tsx +++ b/apps/studio/components/interfaces/Auth/SmtpForm/SmtpForm.tsx @@ -20,7 +20,6 @@ import { Switch, } from 'ui' import { Admonition } from 'ui-patterns/Admonition' -import { Input as PasswordInput } from 'ui-patterns/DataInputs/Input' import { FormItemLayout } from 'ui-patterns/form/FormItemLayout/FormItemLayout' import { PageSection, PageSectionContent } from 'ui-patterns/PageSection' import * as z from 'zod' @@ -29,7 +28,7 @@ import { urlRegex } from '../Auth.constants' import { AUTH_TEMPLATE_RESET_TYPES } from '../EmailTemplates/EmailTemplates.constants' import { isBeforeFreeTierTemplateBlockCutoff } from '../EmailTemplates/EmailTemplates.utils' import { SmtpDisableConfirmationDialog } from './SmtpDisableConfirmationDialog' -import { defaultDisabledSmtpFormValues } from './SmtpForm.constants' +import { defaultDisabledSmtpFormValues, STORED_SECRET_PLACEHOLDER } from './SmtpForm.constants' import { generateFormValues, isSmtpEnabled } from './SmtpForm.utils' import { AlertError } from '@/components/ui/AlertError' import { InlineLink } from '@/components/ui/InlineLink' @@ -474,10 +473,28 @@ export const SmtpForm = () => { render={({ field }) => ( - + )}