<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Vue3 + Vite + Pinia創(chuàng)建單頁(yè)面應(yīng)用

          共 30365字,需瀏覽 61分鐘

           ·

          2023-11-11 00:51

          原文鏈接:https://labs.pineview.io/learn-how-to-build-test-and-deploy-a-single-page-app-with-vue-3-vite-and-pinia/[1]

          作者:Andrei Rusu[2]

          正文從這開(kāi)始~

          介紹

          誕生于2014年的Vue.js,無(wú)疑是目前領(lǐng)先的前端框架之一,隨著社區(qū)的發(fā)展以及生態(tài)系統(tǒng)的壯大,在相當(dāng)一段時(shí)間內(nèi),它的低位都是穩(wěn)固的。幾年前我曾在個(gè)別項(xiàng)目中使用過(guò)Vue 2,那是一種令人愉快的體驗(yàn)。

          我覺(jué)得是時(shí)候把我的工具集升級(jí)到最新版本了。與此同時(shí),也要升級(jí)諸如VitePinia的新型工具。

          本篇指南將涵蓋詳盡的步驟,使用Vue 3來(lái)創(chuàng)建一個(gè)功能性的書(shū)店SPA實(shí)例,并使用Vite來(lái)運(yùn)行它。它還包括如何使用PiniaVuex的后繼者)添加狀態(tài)管理,以及如何使用Vue Router進(jìn)行路由管理的細(xì)節(jié)。

          將涵蓋的核心概念有:

          • 使用Vite創(chuàng)建Vue 3單頁(yè)應(yīng)用(SPA)
          • 使用Vue Router管理路由
          • 使用Pinia管理應(yīng)用狀態(tài)
          • 使用VIte運(yùn)行、構(gòu)建、發(fā)布應(yīng)用
          • 編寫、運(yùn)行Vue組件單元測(cè)試
          • 使用Nightwatch.js編寫、運(yùn)行自動(dòng)化的端到端測(cè)試

          這似乎看起來(lái)有很多內(nèi)容,但我認(rèn)為完全有可能在20分鐘內(nèi)完成所有。上面列出的一些概念可以擴(kuò)展成單獨(dú)的完整教程,但這里我只涵蓋了啟動(dòng)和運(yùn)行項(xiàng)目所必需的內(nèi)容。

          最后需要提到的是,本教程不涉及到后端。盡管數(shù)據(jù)是使用瀏覽器的Fetch API(XHR的后繼者)加載的,但本身是沒(méi)有服務(wù)端組件的。也就是說(shuō),可以很容易地添加一個(gè)后端組件。

          總體而言,我們即將在這里構(gòu)建的應(yīng)用程序可以作為一個(gè)靜態(tài)網(wǎng)站部署。如果你渴望馬上開(kāi)始編程,并立刻投入其中,你可以直接使用以下方法來(lái)啟動(dòng)和運(yùn)行該項(xiàng)目:

          git clone <https://github.com/beatfactor/middlemarch>
          npm install
          npm run dev

          或者在Github上fork本項(xiàng)目: https://github.com/beatfactor/middlemarch[3]

          步驟一:使用create-vite腳手架工具設(shè)置應(yīng)用程序

          我們將要使用官方腳手架工具create-vite來(lái)設(shè)置項(xiàng)目架構(gòu),因此你要確保已經(jīng)安裝了Node 12+NPM 6+。腳手架工具也支持YarnPNPM作為包管理器,但這里我們只涉及NPM

          create-vite會(huì)為你創(chuàng)建項(xiàng)目文件夾,所以首先要確保使用cd命令進(jìn)入到符父文件夾:

          cd /workspace

          使用以下命令安裝Vite并初始化項(xiàng)目:

          $ npm init vite@latest

          然后你會(huì)被提示輸入項(xiàng)目名稱并選擇你想要使用的庫(kù)。我們從列表中選擇vue:

          ~/workspace % npm init vite@latest
          npx: installed 6 in 1.051s
          ? Project name: … vue-bookstore
          ? Select a framework: ? - Use arrow-keys. Return to submit.
              vanilla
          ?   vue
              react
              preact
              lit
              svelte

          然后選擇vue作為變量,因?yàn)槲覀冞@里不使用TypeScript

          ? Select a variant: ? - Use arrow-keys. Return to submit.
          ?   vue
              vue-ts

          你應(yīng)該會(huì)看到如下輸出:

          npx: installed 6 in 1.051s
          ? Project name: … vue-bookstore
          ? Select a framework: ? vue
          ? Select a variant: ? vue

          Scaffolding project in /Users/andrei/workspace/vue-bookstore...

          Done. Now run:

            cd vue-bookstore
            npm install
            npm run dev

          一旦我們按照上述說(shuō)明進(jìn)行操作,我們將從Vite得到以下輸出,來(lái)告訴我們?cè)搼?yīng)用正在運(yùn)行。

          vite v2.7.7 dev server running at:

          > Local: <http://localhost:3000/>
          > Network: use `--host` to expose

          ready in 611ms.

          訪問(wèn)localhost:3000[4],歡迎頁(yè)面會(huì)像下面這樣:

          welcome.png

          步驟二:添加路由和狀態(tài)管理

          我們先來(lái)看下由create-vite創(chuàng)建的項(xiàng)目目錄結(jié)構(gòu):

          vue-bookstore/
           ├── public/
           |    ├── favicon.ico
           ├── src/
           |    ├── assets/
           |    |    └── logo.png
           |    ├── components/
           |    |    └── HelloWorld.vue
           |    ├── App.vue
           |    └── main.js
           ├─── package.json
           ├─── README.md
           └─── vite.config.js

          在本篇指南的本節(jié)中,將要為我們的項(xiàng)目添加兩個(gè)新的依賴:vue-router 和 pinia 。首先使用NPM來(lái)安裝他們。

          Vue Router

          vue-routerVue.js官方的路由管理工具。我們需要安裝v4來(lái)兼容Vue 3:

          $ npm install vue-router@4 --save

          Pinia

          PiniaVue生態(tài)系統(tǒng)中新涌現(xiàn)的項(xiàng)目之一,它是Vue.js應(yīng)用程序最新的官方狀態(tài)管理工具。它的API與Vuex(其前身)非常相似,它被設(shè)計(jì)得更快速、更輕量。

          可以使用NPM來(lái)安裝Pinia

          $ npm install pinia --save

          設(shè)置路由

          如果你不熟悉在SPA中使用路由或者狀態(tài)管理工具,不要擔(dān)心;這兩個(gè)概念都非常容易理解,一旦你看到它是如何工作的,他們就會(huì)自行解釋。

          另外請(qǐng)謹(jǐn)記,在這里我們只是創(chuàng)建一個(gè)教程,目標(biāo)是在20分鐘內(nèi)完成所有工作并運(yùn)行。這并不要求我們學(xué)習(xí)Vue.js所有的相關(guān)知識(shí)。

          什么是單頁(yè)面應(yīng)用(SPA)?

          既然我們?cè)谶@里構(gòu)建的是SPA,那么考慮一下這意味著什么,以及什么是單頁(yè)面,這也許是有用的。

          單頁(yè)面應(yīng)用只是一個(gè)web應(yīng)用,當(dāng)你導(dǎo)航到另一個(gè)子頁(yè)面時(shí),它不會(huì)重新加載頁(yè)面。不過(guò)瀏覽器的url會(huì)被修改,就好像頁(yè)面被重新加載一樣,這是使用HTML5History API做到的。

          在Vite中使用Vue組件

          使用create-vite腳手架工具創(chuàng)建的項(xiàng)目,默認(rèn)添加了一個(gè)非常基礎(chǔ)的vue組件,位于src/components/HelloWorld.vue 。然后它被用在位于src/App.vue的主應(yīng)用組件中。

          這里還有另外兩個(gè)很重要的文件:

          • 「index.html」
          • 「src/main.js」

          index.html文件是當(dāng)瀏覽器導(dǎo)航到我們應(yīng)用程序頁(yè)面時(shí)看到的內(nèi)容,main.js是Vue.js應(yīng)用程序的入口。

          下面是這些文件的內(nèi)容:

          「index.html」

          <!DOCTYPE html>
          <html lang="en">
            <head>
              <meta charset="UTF-8" />
              <link rel="icon" href="/favicon.ico" />
              <meta name="viewport" content="width=device-width, initial-scale=1.0" />
              <title>Vite App</title>
            </head>
            <body>
              <div id="app"></div>
              <script type="module" src="/src/main.js"></script>
            </body>
          </html>

          「src/main.js」

          import { createApp } from 'vue'
          import App from './App.vue'

          createApp(App).mount('#app')

          添加路由

          現(xiàn)在是時(shí)候創(chuàng)建我們應(yīng)用程序的主路由了。在Vue中,每一個(gè)路由必須與一個(gè)組件相對(duì)應(yīng)。在當(dāng)前應(yīng)用程序中,我們將考慮每個(gè)子頁(yè)面的一個(gè)組件,就像這樣:

          • 「Homepage」 - 我們的書(shū)店主頁(yè)面
          • 「Cart」 - 購(gòu)物車和結(jié)算頁(yè)面
          • 「Sign-In」 - 用戶登錄頁(yè)面

          既然這只是一個(gè)示例,像用戶注冊(cè)、產(chǎn)品詳情等其他頁(yè)面,將會(huì)被忽略。而且,登錄頁(yè)面只包含一個(gè)模擬登錄。

          對(duì)于基礎(chǔ)的HTMLCSS,我使用Bootstrap 5做了一些事情,比如UI下拉菜單和表單。當(dāng)然你可以使用任何你想用的UI庫(kù)。

          我們將暫時(shí)創(chuàng)建空的頁(yè)面組件,好讓我們可以設(shè)置路由。新的src目錄結(jié)構(gòu)將會(huì)長(zhǎng)這樣(稍后將移除樣板代碼):

          src/
            ├── components/
            |    └── TopNavbar.js
            ├── lib/
            |    ├── router.js   
            |    └── store.js
            ├── pages/
            |    ├── cart/
            |    |    ├── cart.css
            |    |    ├── cart.html
            |    |    └── Cart.vue
            |    ├── home/
            |    |    ├── home.css
            |    |    ├── home.html
            |    |    └── Home.vue
            |    ├── sign-in/
            |    |    ├── sign-in.css
            |    |    ├── sign-in.html
            |    |    └── SignIn.vue
            |    └── routes.js
            ├── App.vue
            └── main.js

          我們添加了三個(gè)頁(yè)面,每一個(gè)頁(yè)面都非常基礎(chǔ)。我們將添加TobNavbar 組件,使得路由導(dǎo)航生效,而不需要重新加載頁(yè)面。

          src/pages/cart/Cart.vuesrc/pages/home/Home.vuesrc/pages/sign-in/SignIn.vue添加如下內(nèi)容:

          <script setup>
          import TopNavbar from '../../components/TopNavbar.vue';
          </script>

          <template>
            <TopNavbar /
          >
          </template>
          <style></
          style>

          <script>
          export default {
            components: {
              TopNavbar
            },

            computed: {},
            
            mounted() {
            },
            
            data() {
              return {
              };
            },
          };
          </script>

          TobNavbar 組件位于src/components ,只包含了路由導(dǎo)航鏈接。需要注意的是,router-link組件是vue-router的一部分:

          <template>
            <router-link to="/">Home</router-link>
            <router-link to="/cart/">Cart</router-link>
            <router-link to="/sign-in/">Sign In</router-link>
          </template>

          pages/routes.js文件包含了應(yīng)用程序中所有的路由聲明。如下所示:

          import {createRouter} from 'vue-router'
          import Homepage from './home/Home.vue';
          import SignIn from './sign-in/SignIn.vue';
          import Cart from './cart/Cart.vue';

          const routes = [
            {
              path'/',
              component: Homepage
            },

            {
              path'/sign-in/',
              component: SignIn
            },

            {
              path'/cart/',
              component: Cart
            },
          ]

          export default function (history{
            return createRouter({
              history,
              routes
            })
          }

          在我們準(zhǔn)備看到vue-router成功運(yùn)行之前,我們只需要再做兩件事:

          1)創(chuàng)建路由并將其添加到src/main.js里的Vue應(yīng)用程序?qū)嵗校?/p>

          import { createApp } from 'vue'
          import { createWebHistory } from 'vue-router'

          import createRouter from './pages/routes.js'
          import App from './App.vue'

          const router = createRouter(createWebHistory())
          const app = createApp(App)
          app.use(router).mount('#app')

          2)在src/App.vue里添加<router-view>組件:

          <template>
            <router-view></router-view>
          </template>

          如果需要的話,我們重新運(yùn)行npm run dev ,然后導(dǎo)航到http://localhost:3000 。你將擁有一個(gè)啟用了路由的Vue 3應(yīng)用程序。

          使用Pinia設(shè)置狀態(tài)管理

          我們繼續(xù)。現(xiàn)在我們需要為我們的app設(shè)置Pinia storestore(倉(cāng)庫(kù))是應(yīng)用程序維護(hù)狀態(tài)(state)的地方。

          Pinia是Vue.js核心團(tuán)隊(duì)的一個(gè)新項(xiàng)目,現(xiàn)在是使用應(yīng)用程序狀態(tài)的推薦方法。如果你已經(jīng)很熟悉vuex,那么適應(yīng)Pinia將會(huì)非常簡(jiǎn)單。事實(shí)上,Pinia的API比vuex稍微簡(jiǎn)單一點(diǎn),也更加簡(jiǎn)潔明了。

          在vue3中使用Pinia,將會(huì)有一個(gè)根store以及任意數(shù)量的獨(dú)立store。針對(duì)我們的書(shū)店app,我們將只使用兩個(gè)store

          • 目錄 store: 可用的書(shū)單
          • 購(gòu)物車 store: 用戶想要訂購(gòu)的書(shū)籍

          創(chuàng)建Pinia

          我們需要?jiǎng)?chuàng)建第一個(gè)根store,并傳遞給vue實(shí)例。在src/main.js文件中進(jìn)行代碼更新,如下所示:

          import { createApp } from 'vue'
          import { createWebHistory } from 'vue-router'
          import { createPinia } from 'pinia'

          import createRouter from './pages/routes.js'
          import App from './App.vue'

          const store = createPinia()
          const router = createRouter(createWebHistory())
          const app = createApp(App)

          app.use(router).use(store).mount('#app')

          接下來(lái)我們需要?jiǎng)?chuàng)建獨(dú)立的目錄store 以及購(gòu)物車store,并在組件中使用他們。

          添加目錄store

          創(chuàng)建一個(gè)Pinia store意味著兩件主要的事情:

          1. 定義store
          2. 在一個(gè)或多個(gè)組件中使用store

          「定義store」

          Vuex一樣,Pinia store包含狀態(tài)(state)以及兩種類型的方法:「getters」 和 「actions」

          關(guān)于一個(gè)store需要考慮的事情:

          • Getters是一個(gè)同步方法,用來(lái)從狀態(tài)中獲取數(shù)據(jù)
          • Actions 可以是一個(gè)異步的方法,用來(lái)更新?tīng)顟B(tài)
          • state被定義為一個(gè)返回初始狀態(tài)的函數(shù)

          是時(shí)候在src/stores/catalog.js里面創(chuàng)建目錄store了:

          import { defineStore } from 'pinia'

          export const useCatalog = defineStore('catalog-store', {
            state() => {
              return {
                newArrivals: [],
                fetchingfalse
              }
            },

            getters: {
              results(state) {
                return state.newArrivals;
              },

              isFetching(state) {
                return state.fetching;
              }
            },

            actions: {
              async fetchNewArrivals() {
                this.fetching = true;
                const response = await fetch('/data/new-arrivals.json');
                try {
                  const result = await response.json();
                  this.newArrivals = result.books;
                } catch (err) {
                  this.newArrivals = [];
                  console.error('Error loading new arrivals:', err);
                  return err;
                }

                this.fetching = false;
              }
            }
          })

          查看上面的源碼,你可以注意到我們有兩個(gè)getters和一個(gè)actions。我們沒(méi)有真正的后端,只有一個(gè)位于/data/new-arrivals.jsonjson文件。其中包含一些書(shū)籍,我們將把它們作為我們的目錄。

          你也可以注意到,我們的getters沒(méi)有對(duì)數(shù)據(jù)做任何特殊的處理,導(dǎo)致他們有一點(diǎn)多余。但我認(rèn)為用來(lái)展示如何定義他們也是不錯(cuò)的。

          在模板文件中使用store

          將上面的定義鏈接到模板文件也非常的簡(jiǎn)單。

          讓我們?cè)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">src/components/NewArrivals.vue中創(chuàng)建一個(gè)叫做NewArrivals的新組件,我們將在Home.vue頁(yè)面組件中使用它。

          <script setup>
          import {useCatalog} from '../../store/catalog.js'
          </script>

          <template>

          </
          template>

          <style scoped></style>
          <script>
          import { mapState, mapActions } from 'pinia'

          export default {
            computed: {
              ...mapState(useCatalog, {newArrivals'results'})
            },

            methods: {
              ...mapActions(useCatalog, ['fetchNewArrivals']),

              addToCart() {
                // we'll populate this later
              }
            },

            created() {
              // when the template is created, we call this action
              this.fetchNewArrivals();
            }
          };
          </script>

          Home.vue 組件將會(huì)變成:

          <script setup>
          import TopNavbar from '../../components/TopNavbar.vue';
          import NewArrivals from '../../components/NewArrivals.vue';
          </script>

          <template>
            <TopNavbar /
          >
            <NewArrivals />
          </template>

          <style></
          style>

          <script>
          export default {
            components: {
              TopNavbar,
              NewArrivals
            },
            computed: {},
            mounted() {},
            data() {
              return {};
            },
          };
          </script>

          下面是store和組件如何在應(yīng)用程序中協(xié)同工作的圖示:

          vue-pinia.001.png

          我還為購(gòu)物車寫了一個(gè)store和一個(gè)組件,但我不會(huì)把它包含在教程中,因?yàn)闄C(jī)制是相似的。你可以在倉(cāng)庫(kù)中檢查源代碼,它包括了所有東西,甚至包括了一些樣式。

          步驟三:測(cè)試Vue.js組件

          組件測(cè)試是UI測(cè)試中的一種。在這種測(cè)試中,組件被獨(dú)立地進(jìn)行渲染,沒(méi)有其他的應(yīng)用組件,目的是為了驗(yàn)證其功能。它通常是發(fā)生在端到端測(cè)試步驟之前的一種測(cè)試策略,我們將在下一小節(jié)進(jìn)行闡述。

          我們需要安裝Vue Test Utils ,它是Vue.js的官方單元測(cè)試庫(kù)。我們需要的是針對(duì)于Vue 3的那個(gè)版本。你可以從NPM上面進(jìn)行安裝:

          npm install @vue/test-utils@next --save-dev

          安裝Nightwatch.js和ChromeDriver

          我們將使用Nightwatch.js ,用于組件測(cè)試和端到端測(cè)試。Nightwatch已經(jīng)是Vue.js團(tuán)隊(duì)推薦的測(cè)試框架之一,與Vue同一時(shí)間發(fā)布。

          它最近通過(guò)vite-plugin-nightwatch[5]獲得了對(duì)Vue組件測(cè)試的支持。我們將繼續(xù)安裝Nightwatch v2.0

          npm install nightwatch --save-dev

          我們還需要安裝剛才提到的插件vite-plugin-nightwatch

          npm install vite-plugin-nightwatch --save-dev

          Nightwatchs使用 W3C WebDriver API[6] 進(jìn)行瀏覽器自動(dòng)化任務(wù),我們也需要安裝chromedriver NPM包。因?yàn)槲覀儗⒁褂肅hrome來(lái)運(yùn)行我們的測(cè)試用例。

          npm install chromedriver --save-dev

          測(cè)試<NewArrivals>組件

          vite-plugin-nightwatch包含了一個(gè)測(cè)試渲染頁(yè)面,Nightwatch已經(jīng)包含了為我們的組件運(yùn)行初始化測(cè)試所需的一切。

          創(chuàng)建test文件夾,里面包含兩個(gè)子文件:

          • component - 這將進(jìn)行組件測(cè)試
          • e2e - 這將進(jìn)行端到端測(cè)試

          我們還需要nightwatch.conf.js配置文件,但是我們可以直接運(yùn)行Nightwatch ,將會(huì)自動(dòng)為我們創(chuàng)建配置文件。因此只需要確保chromedriver已經(jīng)被安裝。

          確保當(dāng)前的工作目錄是項(xiàng)目的根目錄,然后簡(jiǎn)單地運(yùn)行一個(gè)與Nightwatch捆綁的測(cè)試實(shí)例。我們將選擇duckDuckGo測(cè)試,因?yàn)樗亲羁斓模?/p>

          npx nightwatch examples/tests/duckDuckGo.js

          現(xiàn)在項(xiàng)目結(jié)構(gòu)看起來(lái)長(zhǎng)這樣:

          vue-bookstore/
           ├── public/
           |    ├── data/
           |    └── favicon.ico
           ├── src/
           ├── ...
           |    └── main.js
           ├── test/
           |    ├── component/
           |    └── e2e/
           ├─── nightwatch.conf.js
           ├─── package.json
           ├─── README.md
           └─── vite.config.js

          我們?cè)?code style="overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;color: rgb(145, 109, 213);font-weight: bolder;background-image: none;background-position: initial;background-size: initial;background-repeat: initial;background-attachment: initial;background-origin: initial;background-clip: initial;">test/component目錄里面創(chuàng)建一個(gè)新文件叫做newArrivalsTest.js 。在這個(gè)js文件里,我們將添加一個(gè)基礎(chǔ)的掛載組件的測(cè)試用例,檢查返回的元素是否可以在頁(yè)面中找到。

          describe('New Arrivals Component Test'function({

            it('checks if the component has been mounted'async (browser) => {
              const component = await browser.mountVueComponent('/src/components/new-arrivals/NewArrivals.vue', {
                plugins: {
                  router'/src/lib/router.js'
                }
           });
              
              expect(component).to.be.present; 
            });
          });

          NightwatchMocha一樣,使用相同的describe() 語(yǔ)法。如果你已經(jīng)很熟悉Mocha,你甚至可以使用它作為測(cè)試運(yùn)行器,但我們現(xiàn)在不打算這么做。

          是時(shí)候運(yùn)行上述測(cè)試用例了,為此我們將使用Chrome瀏覽器運(yùn)行Nightwatch,就像這樣:

          npx nightwatch test/component/newArrivalsTest.js --env chrome

          這將打開(kāi)Chrome瀏覽器,并且渲染這個(gè)組件,然后執(zhí)行測(cè)試用例。如果你不喜歡在測(cè)試過(guò)程中看到彈出的瀏覽器窗口,你可以傳入--headless參數(shù),就像這樣。

          npx nightwatch test/component/newArrivalsTest.js --env chrome --headless

          測(cè)試的輸出如下所示:

          [New Arrivals Component Test] Test Suite
          ──────────────────────────────────────────────────────────────
          ? Connected to ChromeDriver on port 9515 (652ms).
            Using: chrome (97.0.4692.99) on MAC OS X.

            Running tests the component:
          ──────────────────────────────────────────────────────────────
            ? Expected element <web element{e53f9b1e-11d3-4dc4-8728-4d3cd077343e}> to be present (1ms)

          OK. 1 assertions passed. (781ms)

          當(dāng)然,你可以通過(guò)以下方式來(lái)查閱Nightwatch運(yùn)行器提供的所有CLI選項(xiàng):訪問(wèn)文檔頁(yè)面[7]或運(yùn)行以下命令:

          npx nightwatch --help

          擴(kuò)展<NewArrivals>測(cè)試

          你可能已經(jīng)注意到,我們的組件測(cè)試并沒(méi)有測(cè)試很多東西,這意味著該測(cè)試并不像它能提供的那樣有用。所以我們要繼續(xù)對(duì)它進(jìn)行一點(diǎn)點(diǎn)的擴(kuò)展。

          我們只需要檢查NewArrivals 組件,并檢查是否有一個(gè)叫做newArrivals的屬性。該屬性在HTML中被用來(lái)渲染結(jié)果。

          現(xiàn)在測(cè)試用例看起來(lái)是這樣的。我們重構(gòu)了組件掛載到before鉤子中,因此我們只能在測(cè)試內(nèi)部進(jìn)行檢查,也就是it代碼塊。expect(斷言)庫(kù)是由Nightwatch提供的,它是基于流行的、多功能的Chai.js斷言庫(kù)。關(guān)于如何使用 expect 的更多信息,詳見(jiàn) Nightwatch docs[8] 網(wǎng)站。

          describe('New Arrivals Component Test'function({

            let component;

            before(async () => {
              component = await browser.mountVueComponent('/src/components/new-arrivals/NewArrivals.vue', {
                plugins: {
                  router'/src/lib/router.js'
                }
           })
            });

            it('checks if the component has been mounted'function(browser{
              expect(component).to.be.present;
              expect(component).to.have.property('newArrivals');
           expect(component).text.toContain('The Memory Police')

              expect.elements('div.col-md-6').count.toEqual(4);       expect(component.property('newArrivals')).to.be.an('array').with.length(1);   
            });
          });

          步驟四:添加端到端測(cè)試

          我們已經(jīng)接近本教程的尾聲,在我們認(rèn)為擁有一個(gè)可以運(yùn)行的Vue.js app之前,我們需要添加對(duì)端到端測(cè)試的支持,并在Github Actions上設(shè)置一個(gè)CI pipeline

          幸運(yùn)的是,我們不需要安裝、配置任何其他工具,除非是一些花里胡哨的報(bào)告器。但現(xiàn)在我們可以從Nightwatch中獲得我們所需要的一切端到端的自動(dòng)化測(cè)試。除了Chrome瀏覽器,Nightwatch也內(nèi)置支持所有主流瀏覽器,包括 Firefox、Edge、Safari。這都要?dú)w功于它與W3C Webdriver APISelenium的整合。它還允許你使用分布式云測(cè)試平臺(tái),比如BrowserStack[9]SauceLabs[10]CrossBrowserTesting[11]LambdaTest[12]等等。

          編寫Homepage端到端測(cè)試

          我們從homepage端到端測(cè)試開(kāi)始。創(chuàng)建一個(gè)新文件,位于test/e2e/homePageTest.js 。語(yǔ)法和組件測(cè)試的語(yǔ)法相同,但為了運(yùn)行端到端測(cè)試,我們將使用應(yīng)用程序的編譯版本。

          我們當(dāng)然可以在開(kāi)發(fā)環(huán)境中運(yùn)行這些測(cè)試。但據(jù)我所知,軟件開(kāi)發(fā)中約定俗成的做法是,在一個(gè)盡可能模擬生產(chǎn)的環(huán)境中運(yùn)行端到端測(cè)試。這也是為什么它們被稱為端到端測(cè)試。

          運(yùn)行生產(chǎn)構(gòu)建

          為了運(yùn)行生產(chǎn)構(gòu)建,我們有幾個(gè)選項(xiàng),每個(gè)選項(xiàng)都涉及到運(yùn)行Vite命令,它被含在NPM任務(wù)中。

          1. npm run build - 這將生成index.html以及其他靜態(tài)資源。如果你已經(jīng)有本地配置好的web server,你可以使用這個(gè)選項(xiàng)。
          2. npm run preview - 這將生成生產(chǎn)構(gòu)建版本,并使用內(nèi)置的dev server運(yùn)行它。默認(rèn)地址是http://localhost:5000/[13]

          第二個(gè)選項(xiàng)更加簡(jiǎn)單直接,所以我們直接運(yùn)行preview命令,看看會(huì)發(fā)生什么:

          $ npm run preview

          [email protected] preview /Users/andrei/workspace/vue-bookstore
          > vite preview

            > Local: <http://localhost:5000/>
            > Network: use `--host` to expose

          編寫測(cè)試腳本

          現(xiàn)在,我們有一個(gè)生產(chǎn)就緒的構(gòu)建版本正在運(yùn)行,我們可以在test/e2e/homePageTest.js中開(kāi)始編寫真正的測(cè)試用例。我們從小處著手,只寫以下內(nèi)容:

          describe('Homepage End-to-end Test', () => {

            it('tests if homepage is loaded', browser => {
              browser
                .navigateTo('<http://localhost:3000>')
                .assert.visible('#app .new-arrivals-panel')
                .expect.elements('#app .new-arrivals-panel .col-md-6').count.toEqual(4)
            });

            it('adds 2 volumes of "Rhinoceros and Other Plays" to cart', browser => {
              browser
                .click('.new-arrivals-panel .col-md-6:nth-child(2) button.add-to-cart')
                .click('.new-arrivals-panel .col-md-6:nth-child(2) button.add-to-cart')
                .assert.textEquals('.shopping-cart .badge''2');
            });

            after(browser => browser.end());
          });

          該測(cè)試驗(yàn)證了New Arrivals面板是否顯示在頁(yè)面中,以及它是否包含我們已經(jīng)看到的4個(gè)入口。

          在Chrome中運(yùn)行測(cè)試腳本

          在Chrome中運(yùn)行測(cè)試腳本的命令,與運(yùn)行組件測(cè)試用例的命令非常相似:

          npx nightwatch test/e2e/homePageTest.js --env chrome

          輸出如下所示:

          [Homepage End-to-end Test] Test Suite
          ──────────────────────────────────────────────────────────────
          ? Connected to ChromeDriver on port 9515 (2454ms).
            Using: chrome (97.0.4692.99) on MAC OS X.

            Running tests the homepage:
          ──────────────────────────────────────────────────────────────
            ? Testing if element <#app .new-arrivals-panel> is visible (157ms)
            ? Expected elements <#app .new-arrivals-panel .col-md-6> count to equal: "4" (18ms)

          OK. 2 assertions passed. (765ms)

          在Firefox中運(yùn)行測(cè)試腳本

          如果我們想要在Firefox瀏覽器中運(yùn)行端到端測(cè)試,我們只需要安裝GeckoDriver[14]。除非你想進(jìn)一步定制,否則不需要其他配置就可以工作。

          讓我們繼續(xù),使用NPM來(lái)進(jìn)行安裝:

          npm i geckodriver --save-dev

          然后使用下面的命令運(yùn)行Nightwatch

          npx nightwatch test/e2e/homePageTest.js --env firefox

          輸出如下所示:

          [Homepage End-to-end Test] Test Suite
          ──────────────────────────────────────────────────────────────
          ? Connected to GeckoDriver on port 4444 (1737ms).
            Using: firefox (96.0.2) on MAC (20.6.0).

            Running tests the homepage:
          ──────────────────────────────────────────────────────────────
            ? Testing if element <#app .new-arrivals-panel> is visible (54ms)
            ? Expected elements <#app .new-arrivals-panel .col-md-6> count to equal: "4" (6ms)

          OK. 2 assertions passed. (612ms)

          在Safari中運(yùn)行測(cè)試腳本

          如果你在使用Mac,那么safaridriver可能已經(jīng)安裝了,這取決于你的Safari版本。

          可以使用下面命令進(jìn)行檢查:

          safaridriver --help

          輸出可能長(zhǎng)這樣:

          Usage: safaridriver [options]
           -h, --help                Prints out this usage information.
           --version                 Prints out version information and exits.
           -p, --port                Port number the driver should use. If the server is already running, the port cannot be changed. If port 0 is specified, a default port will be used.
           --enable                  Applies configuration changes so that subsequent WebDriver                           sessions will run without further authentication.
           --diagnose                Causes safaridriver to log diagnostic information for all sessions hosted by this instance. See the safaridriver(1) man page for more details about diagnostic logging.

          Safari中運(yùn)行你的第一個(gè)測(cè)試之前,你只需要通過(guò)以下命令啟用自動(dòng)化:

          safaridriver --enable

          然后使用下面命令簡(jiǎn)單的運(yùn)行Nightwatch測(cè)試:

          npx nightwatch test/e2e/homePageTest.js --env safari

          在多個(gè)瀏覽器中并行運(yùn)行

          如果你需要在一個(gè)以上的瀏覽器中運(yùn)行Nightwatch測(cè)試,你可以在多個(gè)瀏覽器中并行運(yùn)行。

          只需將瀏覽器作為逗號(hào)分隔的列表(沒(méi)有空格)進(jìn)行傳遞。

          「在Firefox+Chrome中運(yùn)行」

          npx nightwatch test/e2e/homePageTest.js --env firefox,chrome

          「在Firefox+Chrome+Safari中運(yùn)行」

          npx nightwatch test/e2e/homePageTest.js --env firefox,chrome,safari

          更多關(guān)于并行測(cè)試的內(nèi)容,請(qǐng)查看Nightwatch docs[15]網(wǎng)站。

          步驟五:使用Github Actions啟用持續(xù)集成(CI)

          是時(shí)候進(jìn)行收尾工作,將他們放在一起了。在Github Actions中啟用持續(xù)部署(CD)之前,我們需要?jiǎng)?chuàng)建npm test任務(wù)。

          創(chuàng)建npm test任務(wù)

          現(xiàn)在我們已經(jīng)在示例項(xiàng)目中具備組件測(cè)試和端到端測(cè)試。當(dāng)然這只是一個(gè)最低水平,所以它沒(méi)有涵蓋所有內(nèi)容,但我認(rèn)為這是一個(gè)良好的開(kāi)端。

          告訴Nightwatch運(yùn)行測(cè)試文件夾中的所有測(cè)試的最簡(jiǎn)單方法是,將文件夾作為第二個(gè)CLI參數(shù)。我們將要添加該命令到作為一個(gè)新的被稱為test的NPM任務(wù)中。讓我們編輯package.json文件,在 "scripts "字段中添加以下內(nèi)容:

          "test""nightwatch ./test"

          我們可以像這樣來(lái)運(yùn)行NPM任務(wù),并傳遞Nightwatch相關(guān)的CLI參數(shù):

          npm test -- --env chrome --headless

          為了能在Github Actions中運(yùn)行測(cè)試用例,我們將使用--headless模式。

          添加Github Actions工作流

          最后,我們可以添加Github Actions工作流。這樣我們的測(cè)試就可以運(yùn)行在每個(gè)推送和每個(gè)拉動(dòng)請(qǐng)求上。

          想要做到上述流程非常簡(jiǎn)單。我們將使用Node.js模板,在列表中添加幾個(gè)新的步驟(step),比如:

          • 在后臺(tái)啟動(dòng)dev server
          • 在后臺(tái)構(gòu)建項(xiàng)目并在預(yù)覽模式下啟動(dòng)dev server
          • 在Chrome中使用無(wú)頭模式運(yùn)行組件以及端到端測(cè)試

          創(chuàng)建Github Actions工作流程意味著,在.github/workflows文件夾中添加一個(gè)名為node.js.yml的新文件,內(nèi)容如下所示。當(dāng)你從Github項(xiàng)目導(dǎo)航到Actions部分并選擇Node.js模板時(shí),其中大部分內(nèi)容都是自動(dòng)生成的。

          name: Node.js CI

          on:
            push:
              branches: [ main ]

            pull_request:
              branches: [ main ]

          jobs:
            build:
              runs-on: ubuntu-latest
              strategy:
                matrix:
                  node-version: [12.x, 14.x]
              steps:
                - uses: actions/checkout@v2
                - name: Use Node.js ${{ matrix.node-version }}
                  uses: actions/setup-node@v2
                  with:
                    node-version: ${{ matrix.node-version }}

                - run: npm ci

                - name: Start vite dev server
                  run: npm run dev &

                - name: Build the app
                  run: npm run build
                  
                - name: Start vite dev server in preview
                  run: npm run preview &
                  
                - name: Run Nightwatch tests
                  run: npm test

          這樣就可以了。每當(dāng)有新的git推送或新的PR被發(fā)送時(shí),就會(huì)運(yùn)行一個(gè)新的構(gòu)建。構(gòu)建將在2個(gè)獨(dú)立的環(huán)境中運(yùn)行,一個(gè)是Node 12,另一個(gè)是Node 14,如工作流中定義的那樣。

          今后的發(fā)展方向

          該項(xiàng)目在Github上的網(wǎng)址是:https://github.com/beatfactor/middlemarch[16]。這里涵蓋了所有的代碼,還有一些樣式和圖片。它還包含了購(gòu)物車的代碼和一個(gè)模擬的結(jié)賬頁(yè)面。

          homepage.png

          你可以通過(guò)常規(guī)步驟讓它在你的本地機(jī)器上運(yùn)行:

          git clone <https://github.com/beatfactor/middlemarch>
          npm install
          npm run dev

          歡迎發(fā)送PR或報(bào)告問(wèn)題。

          參考資料

          [1]

          https://labs.pineview.io/learn-how-to-build-test-and-deploy-a-single-page-app-with-vue-3-vite-and-pinia/: https://labs.pineview.io/learn-how-to-build-test-and-deploy-a-single-page-app-with-vue-3-vite-and-pinia/

          [2]

          Andrei Rusu: https://labs.pineview.io/author/andrei/

          [3]

          https://github.com/beatfactor/middlemarch: https://github.com/beatfactor/middlemarch

          [4]

          localhost:3000: http://localhost:3000

          [5]

          vite-plugin-nightwatch: https://www.npmjs.com/package/vite-plugin-nightwatch

          [6]

          W3C WebDriver API: https://w3c.github.io/webdriver/

          [7]

          文檔頁(yè)面: https://nightwatchjs.org/guide/running-tests/command-line-options.html

          [8]

          Nightwatch docs: https://nightwatchjs.org/api/expect/

          [9]

          BrowserStack: https://www.browserstack.com/

          [10]

          SauceLabs: https://saucelabs.com/

          [11]

          CrossBrowserTesting: https://crossbrowsertesting.com/

          [12]

          LambdaTest: https://www.lambdatest.com/

          [13]

          http://localhost:5000/: http://localhost:5000/

          [14]

          GeckoDriver: https://github.com/mozilla/geckodriver

          [15]

          Nightwatch docs: https://v2.nightwatchjs.org/guide/running-tests/parallel-running.html

          [16]

          https://github.com/beatfactor/middlemarch: https://github.com/beatfactor/middlemarch


          瀏覽 866
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  7777奇米影视四色 | 国产精品MV视频 | 美女露出粉嫩的尿囗桶爽 | 美日韩黄色一级视频 | 亚洲热视频在线 |