Ctrl K
ComunidadGuías…

frontend/tests/pages/asset-uploads.test.ts

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { mountSuspended, mockNuxtImport } from '@nuxt/test-utils/runtime'
import { flushPromises } from '@vue/test-utils'
import { ref } from 'vue'
import AssetPage from '../../app/pages/assets/[id]/index.vue'

const { api, toast, refreshAsset, refreshAttachments } = vi.hoisted(() => ({
  api: vi.fn(), toast: vi.fn(), refreshAsset: vi.fn(), refreshAttachments: vi.fn()
}))
mockNuxtImport('useApi', () => api)
mockNuxtImport('useToast', () => () => ({ add: toast }))
mockNuxtImport('useRoute', () => () => ({ params: { id: 'asset' }, query: {} }))
mockNuxtImport('useFeatures', () => () => ({ features: ref({ warranties: false }) }))

describe('Asset attachment uploads', () => {
  const upload = vi.fn()
  beforeEach(() => {
    vi.clearAllMocks()
    vi.stubGlobal('fetch', upload)
    upload.mockReset().mockResolvedValue({ ok: true })
    api.mockImplementation((url: () => string) => {
      const path = url()
      return {
        data: ref(path.endsWith('/attachments')
          ? []
          : path.endsWith('/warranty')
            ? null
            : {
                id: 'asset', name: 'Desk', quantity: 1
              }),
        refresh: path.endsWith('/attachments') ? refreshAttachments : refreshAsset,
        status: ref('success'), error: ref(null)
      }
    })
  })
  afterEach(() => vi.unstubAllGlobals())

  const mountPage = () => mountSuspended(AssetPage, {
    global: { stubs: { AssetHistory: true, UModal: true } }
  })
  const file = (name: string) => new File([name], name, { type: 'text/plain' })
  const sentNames = () => upload.mock.calls.map(([, options]) => options.body.get('file').name)

  it('retains failed and unattempted files across new batches and retries only those files', async () => {
    const wrapper = await mountPage()
    const input = wrapper.get('input[type="file"]')
    expect(input.attributes()).toHaveProperty('multiple')
    upload.mockResolvedValueOnce({ ok: true }).mockResolvedValueOnce({ ok: false, status: 500 })
    Object.defineProperty(input.element, 'files', {
      configurable: true, value: [file('first.txt'), file('failed.txt'), file('remaining.txt')]
    })
    await input.trigger('change')
    await flushPromises()
    expect(sentNames()).toEqual(['first.txt', 'failed.txt'])
    expect(wrapper.text()).toContain('2 files not uploaded')
    expect(refreshAttachments).toHaveBeenCalledOnce()
    expect(refreshAsset).toHaveBeenCalledOnce()
    expect(toast).toHaveBeenCalledWith({ title: 'Uploaded 1 of 3 files', color: 'warning' })

    const section = input.element.closest('section')!
    section.dispatchEvent(Object.assign(new Event('drop', { bubbles: true, cancelable: true }), {
      dataTransfer: { files: [file('new.txt')] }
    }))
    await flushPromises()
    expect(wrapper.text()).toContain('2 files not uploaded')
    Array.from(section.querySelectorAll('button')).find(button => button.textContent?.trim() === 'Retry')!.click()
    await flushPromises()
    expect(sentNames()).toEqual(['first.txt', 'failed.txt', 'new.txt', 'failed.txt', 'remaining.txt'])
    expect(wrapper.text()).not.toContain('not uploaded')
    wrapper.unmount()
  })

  it('queues a second drop while an upload is in progress', async () => {
    const wrapper = await mountPage()
    let complete!: (response: { ok: boolean }) => void
    upload.mockImplementationOnce(() => new Promise((resolve) => {
      complete = resolve
    }))
    const section = wrapper.get('input[type="file"]').element.closest('section')!
    const drop = (name: string) => section.dispatchEvent(Object.assign(new Event('drop', { bubbles: true, cancelable: true }), {
      dataTransfer: { files: [file(name)] }
    }))
    drop('first.txt')
    drop('queued.txt')
    expect(sentNames()).toEqual(['first.txt'])
    complete({ ok: true })
    await flushPromises()
    expect(sentNames()).toEqual(['first.txt', 'queued.txt'])
    wrapper.unmount()
  })
})