527e47d822
- PDF : cartouche bordé en haut à droite avec le type (Client/Fournisseur/Autre) et le nom du tiers (getCounterpartyName + getCounterpartyTypeLabel). - Écran ticket : listes Client/Fournisseur filtrées sur le site courant (param siteId[]) et rechargées au changement de site ; reset du tiers sélectionné s'il sort du périmètre du nouveau site.
112 lines
5.0 KiB
TypeScript
112 lines
5.0 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { mount, flushPromises } from '@vue/test-utils'
|
|
import { defineComponent, h, ref, reactive, Suspense } from 'vue'
|
|
|
|
// ── Mocks des composables modules (le form RÉEL est conservé). ────────────────
|
|
const mockPost = vi.hoisted(() => vi.fn())
|
|
const mockPatch = vi.hoisted(() => vi.fn())
|
|
const mockPush = vi.hoisted(() => vi.fn())
|
|
const mockOpen = vi.hoisted(() => vi.fn())
|
|
const mockRefLoad = vi.hoisted(() => vi.fn())
|
|
|
|
vi.mock('~/modules/logistique/composables/useWeighingTicketReferentials', () => ({
|
|
useWeighingTicketReferentials: () => ({ clients: ref([]), suppliers: ref([]), load: mockRefLoad }),
|
|
}))
|
|
vi.mock('~/modules/logistique/composables/useWeighbridge', () => ({
|
|
useWeighbridge: () => ({ triggerAuto: vi.fn(), triggerManual: vi.fn(), extractWeighbridgeError: () => 'err' }),
|
|
}))
|
|
|
|
// ── Auto-imports Nuxt stubbés globalement ───────────────────────────────────
|
|
vi.stubGlobal('useI18n', () => ({ t: (key: string) => key }))
|
|
vi.stubGlobal('useHead', () => undefined)
|
|
vi.stubGlobal('useApi', () => ({ get: vi.fn(), post: mockPost, patch: mockPatch }))
|
|
vi.stubGlobal('useRouter', () => ({ push: mockPush }))
|
|
vi.stubGlobal('usePermissions', () => ({ can: () => true }))
|
|
vi.stubGlobal('navigateTo', vi.fn())
|
|
vi.stubGlobal('useFormErrors', () => ({ errors: reactive({}), setError: vi.fn(), clearErrors: vi.fn(), handleApiError: vi.fn() }))
|
|
// Site courant (ERP-208) : id 7 → les référentiels doivent être chargés filtrés sur ce site.
|
|
vi.stubGlobal('useCurrentSite', () => ({ currentSite: ref({ id: 7, name: 'Site 7', color: '#000000' }) }))
|
|
globalThis.open = mockOpen
|
|
|
|
const NewPage = (await import('../weighing-tickets/new.vue')).default
|
|
|
|
const ButtonStub = defineComponent({
|
|
props: { label: { type: String, default: '' }, disabled: { type: Boolean, default: false } },
|
|
emits: ['click'],
|
|
setup(props, { emit }) {
|
|
return () => h('button', { 'data-label': props.label, onClick: () => emit('click') }, props.label)
|
|
},
|
|
})
|
|
const InputStub = defineComponent({
|
|
props: { label: { type: String, default: '' }, modelValue: { default: null } },
|
|
setup(props) { return () => h('input', { 'data-label': props.label, 'value': props.modelValue as string }) },
|
|
})
|
|
const BlockStub = defineComponent({ setup() { return () => h('div', { 'data-testid': 'block' }) } })
|
|
const ModalStub = defineComponent({
|
|
props: { modelValue: { type: Boolean, default: false } },
|
|
setup(_, { slots }) { return () => h('div', {}, [slots.header?.(), slots.default?.(), slots.footer?.()]) },
|
|
})
|
|
|
|
const stubs = {
|
|
MalioButtonIcon: ButtonStub,
|
|
MalioButton: ButtonStub,
|
|
MalioInputText: InputStub,
|
|
MalioSelect: InputStub,
|
|
MalioDateTime: InputStub,
|
|
MalioCheckbox: InputStub,
|
|
MalioModal: ModalStub,
|
|
WeighingBlock: BlockStub,
|
|
}
|
|
|
|
async function mountPage() {
|
|
const wrapper = mount(defineComponent({
|
|
components: { NewPage },
|
|
setup: () => () => h(Suspense, null, { default: () => h(NewPage) }),
|
|
}), { global: { stubs } })
|
|
await flushPromises()
|
|
return wrapper
|
|
}
|
|
|
|
describe('Écran Ajouter ticket de pesée (page /weighing-tickets/new)', () => {
|
|
beforeEach(() => {
|
|
mockPost.mockReset().mockResolvedValue({ id: 42 })
|
|
mockPatch.mockReset().mockResolvedValue({})
|
|
mockPush.mockReset()
|
|
mockOpen.mockReset()
|
|
mockRefLoad.mockReset().mockResolvedValue(undefined)
|
|
})
|
|
|
|
it('charge les référentiels filtrés sur le site courant au montage (ERP-208)', async () => {
|
|
await mountPage()
|
|
expect(mockRefLoad).toHaveBeenCalledWith(7)
|
|
})
|
|
|
|
it('un seul bouton « Valider » (pas de « Enregistrer » séparé)', async () => {
|
|
const wrapper = await mountPage()
|
|
expect(wrapper.find('[data-label="logistique.weighingTickets.form.validate"]').exists()).toBe(true)
|
|
expect(wrapper.find('[data-label="logistique.weighingTickets.form.save"]').exists()).toBe(false)
|
|
})
|
|
|
|
it('« Valider » : POST brouillon (création) puis PATCH /validate, PDF + retour liste', async () => {
|
|
const wrapper = await mountPage()
|
|
await wrapper.find('[data-label="logistique.weighingTickets.form.validate"]').trigger('click')
|
|
await flushPromises()
|
|
|
|
// 1. Création du brouillon (POST) → récupère l'id.
|
|
expect(mockPost).toHaveBeenCalledWith(
|
|
'/weighing_tickets',
|
|
expect.any(Object),
|
|
expect.objectContaining({ toast: false }),
|
|
)
|
|
// 2. Validation (back autoritaire) sur l'id retourné.
|
|
expect(mockPatch).toHaveBeenCalledWith(
|
|
'/weighing_tickets/42/validate',
|
|
expect.any(Object),
|
|
expect.objectContaining({ toast: false }),
|
|
)
|
|
// 3. Ouverture du bon de pesée PDF + retour à la liste.
|
|
expect(mockOpen).toHaveBeenCalledWith('/api/weighing_tickets/42/print.pdf', '_blank')
|
|
expect(mockPush).toHaveBeenCalledWith('/weighing-tickets')
|
|
})
|
|
})
|