snapshot of https://github.com/frappe/crm.git (develop, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1m13s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 6s
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
This commit is contained in:
106
frontend/tests/unit/documentSaveErrorToast.test.js
Normal file
106
frontend/tests/unit/documentSaveErrorToast.test.js
Normal file
@@ -0,0 +1,106 @@
|
||||
// useDocument pulls in stores, composables and a live createDocumentResource
|
||||
// that aren't wired up for vitest — stub them so this test exercises only the
|
||||
// save-error toast selection in setValue.onError (regression for #1703).
|
||||
vi.mock('@/data/script', () => ({
|
||||
getScript: () => ({ setupScript: vi.fn(), scripts: {} }),
|
||||
}))
|
||||
vi.mock('@/stores/global', () => ({ globalStore: () => ({}) }))
|
||||
vi.mock('@/stores/meta', () => ({ getMeta: () => ({}) }))
|
||||
vi.mock('@/composables/useAttachments', () => ({
|
||||
useAttachments: () => ({
|
||||
trackOldFile: vi.fn(),
|
||||
processPendingDeletions: vi.fn(),
|
||||
}),
|
||||
}))
|
||||
vi.mock('@/composables/settings', () => ({
|
||||
showSettings: { value: false },
|
||||
activeSettingsPage: { value: '' },
|
||||
}))
|
||||
vi.mock('@/utils', () => ({
|
||||
runSequentially: vi.fn(),
|
||||
parseAssignees: (d) => d,
|
||||
sanitizeText: (t) => t,
|
||||
}))
|
||||
vi.mock('@/utils/fieldTransforms', () => ({ findMissingMandatory: () => [] }))
|
||||
vi.mock('@/utils/fetchFrom', () => ({
|
||||
getFetchSource: vi.fn(),
|
||||
getFieldsToFetch: vi.fn(),
|
||||
getPendingFetchFields: vi.fn(),
|
||||
getSourceFieldnames: vi.fn(),
|
||||
}))
|
||||
|
||||
const { toast, captured } = vi.hoisted(() => ({
|
||||
toast: { error: vi.fn(), success: vi.fn() },
|
||||
captured: { options: null },
|
||||
}))
|
||||
|
||||
vi.mock('frappe-ui', () => ({
|
||||
call: vi.fn(),
|
||||
toast,
|
||||
createResource: () => ({}),
|
||||
createDocumentResource: (options) => {
|
||||
captured.options = options
|
||||
return { doc: {}, save: { submit: vi.fn() } }
|
||||
},
|
||||
}))
|
||||
|
||||
import { useDocument } from '@/data/document'
|
||||
|
||||
describe('useDocument setValue.onError toasts', () => {
|
||||
let onError
|
||||
|
||||
// useDocument caches the resource per docname, so set it up once and
|
||||
// reuse the captured handler across tests.
|
||||
beforeAll(() => {
|
||||
useDocument('CRM Lead', 'CRM-LEAD-TEST')
|
||||
onError = captured.options.setValue.onError
|
||||
})
|
||||
|
||||
beforeEach(() => {
|
||||
toast.error.mockClear()
|
||||
vi.spyOn(console, 'error').mockImplementation(() => {})
|
||||
})
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('shows one toast per server message', () => {
|
||||
onError({ messages: ['Editing this lead is not allowed.'] })
|
||||
|
||||
expect(toast.error).toHaveBeenCalledTimes(1)
|
||||
expect(toast.error).toHaveBeenCalledWith(
|
||||
'Editing this lead is not allowed.',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows the generic toast when messages is an empty array', () => {
|
||||
onError({ messages: [] })
|
||||
|
||||
expect(toast.error).toHaveBeenCalledTimes(1)
|
||||
expect(toast.error).toHaveBeenCalledWith(
|
||||
'An error occurred while updating the document',
|
||||
)
|
||||
})
|
||||
|
||||
it('shows the generic toast when messages is missing', () => {
|
||||
onError({})
|
||||
|
||||
expect(toast.error).toHaveBeenCalledTimes(1)
|
||||
expect(toast.error).toHaveBeenCalledWith(
|
||||
'An error occurred while updating the document',
|
||||
)
|
||||
})
|
||||
|
||||
it('collapses mandatory errors into a single toast', () => {
|
||||
onError({
|
||||
exc_type: 'MandatoryError',
|
||||
messages: ['Missing: first_name', 'Missing: email'],
|
||||
})
|
||||
|
||||
expect(toast.error).toHaveBeenCalledTimes(1)
|
||||
expect(toast.error).toHaveBeenCalledWith(
|
||||
'Mandatory field error: first_name, email',
|
||||
)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user