網站開發的過程或部署前若能結合測試將能大大的降低網站出錯的可能性,這篇文章因為官方的測試相關工具尚未完善,故主要針對錯誤處理做講解,處理錯誤固然重要,但能在故障發生之前降低錯誤發生的可能性,測試是必然的,所以還是得稍微簡單提一下。網站上線之後,難免會遇到一些 Bug 導致網站異常,更要命的是一段未被攔截到的錯誤,將導致整個 JavaScript 無法繼續運作,網站也無法繼續互動,使用者全然不知道發生了什麼事情。當然不是所有情況都是自己的鍋,有可能是使用者輸入不合法的參數或瀏覽不存在的頁面,如何的捕獲錯誤並給予適當的提示及引導,也是網站開發相當重要的一環。
Nuxt 3 目前的測試工具仍在開發當中,API 和處理行為可能會發生變化,官方也提到,測試工具目前處於預覽階段,尚未準備好可以測試正式環境中的專案,但如果是模組的開發者,可以參考模組作者指南。
在 Nuxt 3 中重寫了 @nuxt/test-utils
,目前發佈在 @nuxt/test-utils,可以用來支援 Vitest 與 Jest 的 Test runner。
使用 NPM 安裝套件
npm install -D @nuxt/test-utils-edge vitest
在每一個 describe
區塊中,你需要在開始測試之前使用 @nuxt/test-utils-edge
提供的輔助函數,來取得並設置 Test Context,範例程式如下。
import { describe, test } from 'vitest'
import { setup, $fetch } from '@nuxt/test-utils-edge'
describe('My test', async () => {
await setup({
// test context options
})
test('my test', () => {
// ...
})
})
更多的測試 API 、參數選項與使用方式可以參考最新的官方文件。
當我們啟用 SSR 時,也就是包含了在後端由 Vue 渲染生命週期中,發生的錯誤,可以使用 Vue.js 提供的 onErrorCaptured()
函數來註冊一個 hook,用以捕獲子元件所發生的錯誤。
舉例,新增一個 ButtonOOPS
元件,並添加一個點擊事件程式碼如下:
const onClick = () => {
throw new Error('由 ButtonOOPS 元件,拋出一個錯誤!')
}
建立一個頁面 ./pages/vue/onErrorCaptured.vue
來使用 ButtonOOPS
按鈕元件,我們使用 onErrorCaptured()
來捕獲程式碼如下:
<template>
<div class="flex flex-col items-center bg-white py-24">
<ButtonOOPS />
<div class="mt-4 text-red-500">
{{ errorMessage }}
</div>
</div>
</template>
<script setup>
import { onErrorCaptured } from 'vue'
const errorMessage = ref()
onErrorCaptured((err) => {
console.error('[捕獲錯誤]', err.message)
errorMessage.value = err.message
return false
})
</script>
我們可以在 SFC 中使用 onErrorCaptured()
來捕獲子元件
所發生的錯誤,當我們處理完錯誤可以使用 return false
來阻止錯誤冒泡 (Bubbling)。
vueApp.config.errorHandler
我們可以自訂一個插件來接收 Vue 所有的錯誤。
建立 ./plugins/vueErrorHandle.js
內容如下:
export default defineNuxtPlugin((nuxtApp) => {
nuxtApp.vueApp.config.errorHandler = (error) => {
console.error('[由 vueErrorHandle 插件捕獲的錯誤]', error)
}
})
建立一個頁面 ./pages/vue/thowError.vue
來使用 ButtonOOPS
按鈕元件程式碼如下,但不捕獲錯誤,將錯誤繼續冒泡:
<template>
<div class="flex flex-col items-center bg-white py-24">
<ButtonOOPS />
</div>
</template>
元件中所發生的錯誤,不論是否有被處理,只要錯誤冒泡至頂層,就會被 vueErrorHandle
插件所定義的 vue:error
的 hook 所捕獲。
useError
參數類型:
function useError (): Ref<Error | { url, statusCode, statusMessage, message, description, data }>
此方法將回傳 Nuxt 正在處理的全域錯誤。
使用範例:
const error = useError()
clearError
參數類型:
function clearError (options?: { redirect?: string }): Promise<void>
此函數將清除目前 Nuxt 處理中的錯誤,函數可以傳入一個路徑來進行重導向,例如清除錯誤後,可以導向至首頁或其他安全
的頁面。
使用範例:
clearError()
// or
clearError({ redirect: '/safe' })
createError
參數類型:
function createError (err: { cause, data, message, name, stack, statusCode, statusMessage, fatal }): Error
此函數可以建立一個帶有附加錯誤資訊的物件,它可以在 Vue 或 Nitro 中使用,並且可以使用 throw
拋出這個錯誤物件。
如果我們使用 createError
建立一個錯誤物件,在伺服器端或客戶端會有不同的效果。
在伺服器端拋出 createError()
建立的錯誤物件時,它將觸發一個全螢幕的錯誤,你可以使用 clearError()
來清除這個錯誤。
使用範例:
<script setup>
throw createError({
statusCode: 500,
statusMessage: 'Internal Server Error'
})
</script>
若是在客戶端拋出 createError()
建立的錯誤物件,它將會拋出一個非致命的錯誤提供處理,如果想觸發全螢幕的錯誤頁面,可以設定 fatal
屬性為 true
。
使用範例:
<script setup>
import { onErrorCaptured } from 'vue'
onErrorCaptured((err) => {
console.error('[捕獲錯誤]', err.message)
throw createError({
statusCode: 400,
statusMessage: 'Bad Request',
fatal: true
})
})
</script>
showError
參數類型:
function showError (err: string | Error | { statusCode, statusMessage }): Error
你可以在客戶端的任何地方呼叫此函數,伺服器端則可以在中間件、插件或 setup()
函數中呼叫。它將觸發一個全螢幕的錯誤頁面,你可以使用 clearError()
來清除錯誤。
因為錯誤頁面與 createError()
觸發的頁面相同,官方也建議改為使用 throw createError()
來建立與拋出錯誤。
使用範例:
showError("? Oh no, an error has been thrown.")
showError({ statusCode: 404, statusMessage: "Page Not Found" })
測試
與錯誤處理
在網站開發過程與上線後都非常的重要,Nuxt 3 提供了許多方便的組合式函數,可以來處理與拋出錯誤,建議在建立頁面、元件或 Server API 時能盡量攔截捕捉錯誤,並使用 createError
來建立適當的 HTTP Status Code 與錯誤訊息,相信使用者也會降低遇到網站喪失互動性,或莫名需要重新整理才能繼續的使用體驗。
感謝大家的閱讀,這是我第一次參加 iThome 鐵人賽,請鞭小力一些,也歡迎大家給予建議 :)
如果對這個 Nuxt 3 系列感興趣,可以訂閱接收通知,也歡迎分享給喜歡或正在學習 Nuxt 3 的夥伴。
哈囉Ryan~
請問今年,您有在nuxt3用vitest寫測試嗎?
有沒有打算今年寫測試相關的文章呢~~(敲碗
或加碼一篇關於nuxt官網的testing,寫一篇比較白話的說明文章XD
關於測試時都要將.vue中的相關套件都mock
為了針對.vue中的函式邏輯做測試,
但mock寫法有些微差異,例如有引入i18n或axios的.vue,就要mock
測試的套件也好多,@nuxt/test-utils vitest(or jest) @vue/test-utils happy-dom(or jsdom) playwright-core,都不知道測什麼要用哪個套件的哪個方法
您有收集這類專案或文章可以參考嗎~