继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

【九月打卡】第6天 TDD方式给上传组件编写自定义模板

flask
关注TA
已关注
手记 45
粉丝 2
获赞 1

课程名称:web前端架构师

课程章节:第11周 第五章

主讲老师:张轩

课程内容:TDD方式给上传组件编写自定义模板

上传模板

之前测试 mock 组件使,使用的是。global.components

  let wrapper: VueWrapper<any>
  beforeAll(() => {
    wrapper = mount(UserProfile, {
      global: {
        components: globalComponents
      }
    })
  })

如果要 mock 在组件中注册的组件,需要设置 global.components.stubs。 参考文档地址 https://test-utils.vuejs.org/api/#global

const mockComponents = {
  'DeleteOutlined': mockComponent,
  'LoadingOutlined': mockComponent,
  'FileOutlined': mockComponent
}
let wrapper: VueWrapper<any>
beforeAll(() => {
  wrapper = mount(UserProfile, {
    global: {
      // 组件中注册的组件 
      stubs: mockComponents
    }
  })
})

接下来编写自定义模板的测试

  • 支持用户传入的自定义上传状态显示
    • 上传中slot 值为loading
    • 上传完成为uploaded
    • 默认状态为 default

要实现自定义模板的测试代码,我们需要对 vue.js 的插槽功能有所了解,文档地址[https://cn.vuejs.org/guide/components/slots.html#named-slots]

下面定义自定义模板上传插槽的名称

  • 上传。loading ,默认为一个上传按钮
  • 上传成功。uploaded,默认为一个上传按钮
  • 上传中 loading。默认为一个正在上传按钮

下面编写测试代码

t.only('should show the correct interface when using custom slot', async () => {
    const url = 'test.url'
    request.mockResolvedValueOnce({ data: { url } })

    wrapper = mount(UploadFile, {
      slots: {
        default: '<button>Custom button</button>',
        loading: '<div class="loading">custom loading</div>',
        uploaded: `<template #uploaded="{uploadedData}">
        <div class="custom-loaded">{{uploadedData.status}}</div>
        </template>`
      }
    })
    // 默认状态为 slot default 的内容
    expect(wrapper.get('button').text()).toBe('Custom button')
    const fileInput = wrapper.get('input').element as HTMLInputElement
    // 点击上传文件,为 loading 状态
    setInputVal(fileInput)
    await wrapper.get('input').trigger('change')
    expect(wrapper.get('.loading').text()).toBe('custom loading')
    await flushPromises()
    // 上传成功
    expect(wrapper.get('.custom-loaded').text()).toBe('success')
  })

然后根据测试编写代码,跑通每一项测试

<script setup lang="ts">
import { reactive, ref, computed } from 'vue'
import request from '@/utils/request'
type UploadStatus = 'ready' | 'loading' | 'success' | 'fail'
interface FileItem {
  id: string
  name: string
  size: number
  status:UploadStatus
  raw: File
  res?: any
}
const fileRef = ref<HTMLInputElement | null>(null)
// const uploadStatus = ref<UploadStatus>('ready')
const uploadFiles = reactive<FileItem[]>([])
const isUploading = computed(() => uploadFiles.some(file => file.status === 'loading'))
const loadStatus = ref<UploadStatus>('ready')
async function uploadFile (e: Event) {
  const target = e.target as HTMLInputElement
  const files = target.files
  if (files) {
    const uploadFile = files[0]
    const formData = new FormData()
    console.log(formData, target.name)
    formData.append(target.name, uploadFile)
    const fileObj = reactive<FileItem>({
      id: '' + Date.now(),
      name: uploadFile.name,
      size: uploadFile.size,
      status: 'loading',
      raw: uploadFile
    })
    uploadFiles.push(fileObj)
    try {
      fileObj.status = 'loading'
      loadStatus.value = 'loading'
      const res = await request(formData)
      fileObj.status = 'success'
      loadStatus.value = 'success'
      // fileObj.res = res.data
      console.log(res)
    } catch (e) {
      fileObj.status = 'fail'
      loadStatus.value = 'fail'
    } finally {
      (fileRef.value as HTMLInputElement).value = ''
    }
  }
}
function triggerUpload () {
  fileRef.value?.click()
}
function delFile (index: number) {
  uploadFiles.splice(index, 1)
}
</script>

<template>
  <input
    type="file"
    name="file"
    ref="fileRef"
    :style="{display: 'none'}"
    @change="uploadFile"
  >
  <div
    @click="triggerUpload"
  >
    <slot
      v-if="isUploading"
      name="loading"
    >
      <button>正在上传</button>
    </slot>
    <slot
      v-else-if="loadStatus==='success'"
      name="uploaded"
      :uploaded-data="{status: loadStatus}"
    >
      <button>点击1上传</button>
    </slot>
    <slot v-else>
      <button>点击上传</button>
    </slot>
  </div>
  <ul>
    <li
      v-for="(file,index) in uploadFiles"
      :key="file.id"
      :class="'upload-'+ file.status"
    >
      <span class="filename">{{ file.name }}</span>
      <button
        class="delete-icon"
        @click="delFile(index)"
      >
        del
      </button>
    </li>
  </ul>
</template>

今天再次通过 TDD 的方式来编写组件,再次体会到了 TDD 开发所带来的方便。编写完测试跑通后,基本上就可以就可以确定实现的功能已经没问题了,非常方便。过去到浏览器一步一步操作进行测试,每次修改完都需要跑完整个流程,而TDD开发每次修改完,都会自动测试之前的模块有没有问题,只要跑通测试就基本上可以确定没问题,还不容易出错。

打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP