使用Vue3 + Vite + Pinia创建SPA

2022-08-19 15:08:55 浏览数 (1)

原文链接: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]

正文从这开始~

介绍

诞生于2014年的Vue.js,无疑是目前领先的前端框架之一,随着社区的发展以及生态系统的壮大,在相当一段时间内,它的低位都是稳固的。几年前我曾在个别项目中使用过Vue 2,那是一种令人愉快的体验。

我觉得是时候把我的工具集升级到最新版本了。与此同时,也要升级诸如VitePinia的新型工具。

本篇指南将涵盖详尽的步骤,使用Vue 3来创建一个功能性的书店SPA实例,并使用Vite来运行它。它还包括如何使用PiniaVuex的后继者)添加状态管理,以及如何使用Vue Router进行路由管理的细节。

将涵盖的核心概念有:

  • 使用Vite创建Vue 3单页应用(SPA)
  • 使用Vue Router管理路由
  • 使用Pinia管理应用状态
  • 使用VIte运行、构建、发布应用
  • 编写、运行Vue组件单元测试
  • 使用Nightwatch.js编写、运行自动化的端到端测试

这似乎看起来有很多内容,但我认为完全有可能在20分钟内完成所有。上面列出的一些概念可以扩展成单独的完整教程,但这里我只涵盖了启动和运行项目所必需的内容。

最后需要提到的是,本教程不涉及到后端。尽管数据是使用浏览器的Fetch API(XHR的后继者)加载的,但本身是没有服务端组件的。也就是说,可以很容易地添加一个后端组件。

总体而言,我们即将在这里构建的应用程序可以作为一个静态网站部署。如果你渴望马上开始编程,并立刻投入其中,你可以直接使用以下方法来启动和运行该项目:

代码语言:javascript复制
git clone <https://github.com/beatfactor/middlemarch>
npm install
npm run dev

或者在Github上fork本项目: https://github.com/beatfactor/middlemarch[3]

步骤一:使用create-vite脚手架工具设置应用程序

我们将要使用官方脚手架工具create-vite来设置项目架构,因此你要确保已经安装了Node 12 NPM 6 。脚手架工具也支持YarnPNPM作为包管理器,但这里我们只涉及NPM

create-vite会为你创建项目文件夹,所以首先要确保使用cd命令进入到符父文件夹:

代码语言:javascript复制
cd /workspace

使用以下命令安装Vite并初始化项目:

代码语言:javascript复制
$ npm init vite@latest

然后你会被提示输入项目名称并选择你想要使用的库。我们从列表中选择vue:

代码语言:javascript复制
~/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作为变量,因为我们这里不使用TypeScript

代码语言:javascript复制
? Select a variant: › - Use arrow-keys. Return to submit.
❯   vue
    vue-ts

你应该会看到如下输出:

代码语言:javascript复制
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

一旦我们按照上述说明进行操作,我们将从Vite得到以下输出,来告诉我们该应用正在运行。

代码语言:javascript复制
vite v2.7.7 dev server running at:

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

ready in 611ms.

访问localhost:3000[4],欢迎页面会像下面这样:

welcome.png

步骤二:添加路由和状态管理

我们先来看下由create-vite创建的项目目录结构:

代码语言:javascript复制
vue-bookstore/
 ├── public/
 |    ├── favicon.ico
 ├── src/
 |    ├── assets/
 |    |    └── logo.png
 |    ├── components/
 |    |    └── HelloWorld.vue
 |    ├── App.vue
 |    └── main.js
 ├─── package.json
 ├─── README.md
 └─── vite.config.js

在本篇指南的本节中,将要为我们的项目添加两个新的依赖:vue-routerpinia 。首先使用NPM来安装他们。

Vue Router

vue-routerVue.js官方的路由管理工具。我们需要安装v4来兼容Vue 3:

代码语言:javascript复制
$ npm install vue-router@4 --save

Pinia

PiniaVue生态系统中新涌现的项目之一,它是Vue.js应用程序最新的官方状态管理工具。它的API与Vuex(其前身)非常相似,它被设计得更快速、更轻量。

可以使用NPM来安装Pinia

代码语言:javascript复制
$ npm install pinia --save

设置路由

如果你不熟悉在SPA中使用路由或者状态管理工具,不要担心;这两个概念都非常容易理解,一旦你看到它是如何工作的,他们就会自行解释。

另外请谨记,在这里我们只是创建一个教程,目标是在20分钟内完成所有工作并运行。这并不要求我们学习Vue.js所有的相关知识。

什么是单页面应用(SPA)?

既然我们在这里构建的是SPA,那么考虑一下这意味着什么,以及什么是单页面,这也许是有用的。

单页面应用只是一个web应用,当你导航到另一个子页面时,它不会重新加载页面。不过浏览器的url会被修改,就好像页面被重新加载一样,这是使用HTML5History API做到的。

在Vite中使用Vue组件

使用create-vite脚手架工具创建的项目,默认添加了一个非常基础的vue组件,位于src/components/HelloWorld.vue 。然后它被用在位于src/App.vue的主应用组件中。

这里还有另外两个很重要的文件:

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

index.html文件是当浏览器导航到我们应用程序页面时看到的内容,main.js是Vue.js应用程序的入口。

下面是这些文件的内容:

「index.html」

代码语言:javascript复制
<!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」

代码语言:javascript复制
import { createApp } from 'vue'
import App from './App.vue'

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

添加路由

现在是时候创建我们应用程序的主路由了。在Vue中,每一个路由必须与一个组件相对应。在当前应用程序中,我们将考虑每个子页面的一个组件,就像这样:

  • 「Homepage」 - 我们的书店主页面
  • 「Cart」 - 购物车和结算页面
  • 「Sign-In」 - 用户登录页面

既然这只是一个示例,像用户注册、产品详情等其他页面,将会被忽略。而且,登录页面只包含一个模拟登录。

对于基础的HTMLCSS,我使用Bootstrap 5做了一些事情,比如UI下拉菜单和表单。当然你可以使用任何你想用的UI库。

我们将暂时创建空的页面组件,好让我们可以设置路由。新的src目录结构将会长这样(稍后将移除样板代码):

代码语言:javascript复制
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

我们添加了三个页面,每一个页面都非常基础。我们将添加TobNavbar 组件,使得路由导航生效,而不需要重新加载页面。

src/pages/cart/Cart.vuesrc/pages/home/Home.vuesrc/pages/sign-in/SignIn.vue添加如下内容:

代码语言:javascript复制
<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 ,只包含了路由导航链接。需要注意的是,router-link组件是vue-router的一部分:

代码语言:javascript复制
<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文件包含了应用程序中所有的路由声明。如下所示:

代码语言:javascript复制
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
  })
}

在我们准备看到vue-router成功运行之前,我们只需要再做两件事:

1)创建路由并将其添加到src/main.js里的Vue应用程序实例中:

代码语言:javascript复制
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>组件:

代码语言:javascript复制
<template>
  <router-view></router-view>
</template>

如果需要的话,我们重新运行npm run dev ,然后导航到http://localhost:3000 。你将拥有一个启用了路由的Vue 3应用程序。

使用Pinia设置状态管理

我们继续。现在我们需要为我们的app设置Pinia storestore(仓库)是应用程序维护状态(state)的地方。

Pinia是Vue.js核心团队的一个新项目,现在是使用应用程序状态的推荐方法。如果你已经很熟悉vuex,那么适应Pinia将会非常简单。事实上,Pinia的API比vuex稍微简单一点,也更加简洁明了。

在vue3中使用Pinia,将会有一个根store以及任意数量的独立store。针对我们的书店app,我们将只使用两个store

  • 目录 store: 可用的书单
  • 购物车 store: 用户想要订购的书籍

创建Pinia

我们需要创建第一个根store,并传递给vue实例。在src/main.js文件中进行代码更新,如下所示:

代码语言:javascript复制
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')

接下来我们需要创建独立的目录store 以及购物车store,并在组件中使用他们。

添加目录store

创建一个Pinia store意味着两件主要的事情:

  1. 定义store
  2. 在一个或多个组件中使用store

「定义store」

Vuex一样,Pinia store包含状态(state)以及两种类型的方法:「getters」「actions」

关于一个store需要考虑的事情:

  • Getters是一个同步方法,用来从状态中获取数据
  • Actions 可以是一个异步的方法,用来更新状态
  • state被定义为一个返回初始状态的函数

是时候在src/stores/catalog.js里面创建目录store了:

代码语言:javascript复制
import { defineStore } from 'pinia'

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

  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;
    }
  }
})

查看上面的源码,你可以注意到我们有两个getters和一个actions。我们没有真正的后端,只有一个位于/data/new-arrivals.jsonjson文件。其中包含一些书籍,我们将把它们作为我们的目录。

你也可以注意到,我们的getters没有对数据做任何特殊的处理,导致他们有一点多余。但我认为用来展示如何定义他们也是不错的。

在模板文件中使用store

将上面的定义链接到模板文件也非常的简单。

让我们在src/components/NewArrivals.vue中创建一个叫做NewArrivals的新组件,我们将在Home.vue页面组件中使用它。

代码语言:javascript复制
<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 组件将会变成:

代码语言:javascript复制
<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和组件如何在应用程序中协同工作的图示:

vue-pinia.001.png

我还为购物车写了一个store和一个组件,但我不会把它包含在教程中,因为机制是相似的。你可以在仓库中检查源代码,它包括了所有东西,甚至包括了一些样式。

步骤三:测试Vue.js组件

组件测试是UI测试中的一种。在这种测试中,组件被独立地进行渲染,没有其他的应用组件,目的是为了验证其功能。它通常是发生在端到端测试步骤之前的一种测试策略,我们将在下一小节进行阐述。

我们需要安装Vue Test Utils ,它是Vue.js的官方单元测试库。我们需要的是针对于Vue 3的那个版本。你可以从NPM上面进行安装:

代码语言:javascript复制
npm install @vue/test-utils@next --save-dev

安装Nightwatch.js和ChromeDriver

我们将使用Nightwatch.js ,用于组件测试和端到端测试。Nightwatch已经是Vue.js团队推荐的测试框架之一,与Vue同一时间发布。

它最近通过vite-plugin-nightwatch[5]获得了对Vue组件测试的支持。我们将继续安装Nightwatch v2.0

代码语言:javascript复制
npm install nightwatch --save-dev

我们还需要安装刚才提到的插件vite-plugin-nightwatch

代码语言:javascript复制
npm install vite-plugin-nightwatch --save-dev

Nightwatchs使用 W3C WebDriver API[6] 进行浏览器自动化任务,我们也需要安装chromedriver NPM包。因为我们将要使用Chrome来运行我们的测试用例。

代码语言:javascript复制
npm install chromedriver --save-dev

测试<NewArrivals>组件

vite-plugin-nightwatch包含了一个测试渲染页面,Nightwatch已经包含了为我们的组件运行初始化测试所需的一切。

创建test文件夹,里面包含两个子文件:

  • component - 这将进行组件测试
  • e2e - 这将进行端到端测试

我们还需要nightwatch.conf.js配置文件,但是我们可以直接运行Nightwatch ,将会自动为我们创建配置文件。因此只需要确保chromedriver已经被安装。

确保当前的工作目录是项目的根目录,然后简单地运行一个与Nightwatch捆绑的测试实例。我们将选择duckDuckGo测试,因为它是最快的:

代码语言:javascript复制
npx nightwatch examples/tests/duckDuckGo.js

现在项目结构看起来长这样:

代码语言:javascript复制
vue-bookstore/
 ├── public/
 |    ├── data/
 |    └── favicon.ico
 ├── src/
 ├── ...
 |    └── main.js
 ├── test/
 |    ├── component/
 |    └── e2e/
 ├─── nightwatch.conf.js
 ├─── package.json
 ├─── README.md
 └─── vite.config.js

我们在test/component目录里面创建一个新文件叫做newArrivalsTest.js 。在这个js文件里,我们将添加一个基础的挂载组件的测试用例,检查返回的元素是否可以在页面中找到。

代码语言:javascript复制
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() 语法。如果你已经很熟悉Mocha,你甚至可以使用它作为测试运行器,但我们现在不打算这么做。

是时候运行上述测试用例了,为此我们将使用Chrome浏览器运行Nightwatch,就像这样:

代码语言:javascript复制
npx nightwatch test/component/newArrivalsTest.js --env chrome

这将打开Chrome浏览器,并且渲染这个组件,然后执行测试用例。如果你不喜欢在测试过程中看到弹出的浏览器窗口,你可以传入--headless参数,就像这样。

代码语言:javascript复制
npx nightwatch test/component/newArrivalsTest.js --env chrome --headless

测试的输出如下所示:

代码语言:javascript复制
[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)

当然,你可以通过以下方式来查阅Nightwatch运行器提供的所有CLI选项:访问文档页面[7]或运行以下命令:

代码语言:javascript复制
npx nightwatch --help

扩展<NewArrivals>测试

你可能已经注意到,我们的组件测试并没有测试很多东西,这意味着该测试并不像它能提供的那样有用。所以我们要继续对它进行一点点的扩展。

我们只需要检查NewArrivals 组件,并检查是否有一个叫做newArrivals的属性。该属性在HTML中被用来渲染结果。

现在测试用例看起来是这样的。我们重构了组件挂载到before钩子中,因此我们只能在测试内部进行检查,也就是it代码块。expect(断言)库是由Nightwatch提供的,它是基于流行的、多功能的Chai.js断言库。关于如何使用 expect 的更多信息,详见 Nightwatch docs[8] 网站。

代码语言:javascript复制
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);   
  });
});

步骤四:添加端到端测试

我们已经接近本教程的尾声,在我们认为拥有一个可以运行的Vue.js app之前,我们需要添加对端到端测试的支持,并在Github Actions上设置一个CI pipeline

幸运的是,我们不需要安装、配置任何其他工具,除非是一些花里胡哨的报告器。但现在我们可以从Nightwatch中获得我们所需要的一切端到端的自动化测试。除了Chrome浏览器,Nightwatch也内置支持所有主流浏览器,包括 Firefox、Edge、Safari。这都要归功于它与W3C Webdriver APISelenium的整合。它还允许你使用分布式云测试平台,比如BrowserStack[9]、SauceLabs[10]、 CrossBrowserTesting[11] 、LambdaTest[12]等等。

编写Homepage端到端测试

我们从homepage端到端测试开始。创建一个新文件,位于test/e2e/homePageTest.js 。语法和组件测试的语法相同,但为了运行端到端测试,我们将使用应用程序的编译版本。

我们当然可以在开发环境中运行这些测试。但据我所知,软件开发中约定俗成的做法是,在一个尽可能模拟生产的环境中运行端到端测试。这也是为什么它们被称为端到端测试。

运行生产构建

为了运行生产构建,我们有几个选项,每个选项都涉及到运行Vite命令,它被含在NPM任务中。

  1. npm run build - 这将生成index.html以及其他静态资源。如果你已经有本地配置好的web server,你可以使用这个选项。
  2. npm run preview - 这将生成生产构建版本,并使用内置的dev server运行它。默认地址是http://localhost:5000/[13]。

第二个选项更加简单直接,所以我们直接运行preview命令,看看会发生什么:

代码语言:javascript复制
$ npm run preview

> vue-bookstore@0.0.0 preview /Users/andrei/workspace/vue-bookstore
> vite preview

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

编写测试脚本

现在,我们有一个生产就绪的构建版本正在运行,我们可以在test/e2e/homePageTest.js中开始编写真正的测试用例。我们从小处着手,只写以下内容:

代码语言:javascript复制
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());
});

该测试验证了New Arrivals面板是否显示在页面中,以及它是否包含我们已经看到的4个入口。

在Chrome中运行测试脚本

在Chrome中运行测试脚本的命令,与运行组件测试用例的命令非常相似:

代码语言:javascript复制
npx nightwatch test/e2e/homePageTest.js --env chrome

输出如下所示:

代码语言:javascript复制
[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中运行测试脚本

如果我们想要在Firefox浏览器中运行端到端测试,我们只需要安装GeckoDriver[14]。除非你想进一步定制,否则不需要其他配置就可以工作。

让我们继续,使用NPM来进行安装:

代码语言:javascript复制
npm i geckodriver --save-dev

然后使用下面的命令运行Nightwatch

代码语言:javascript复制
npx nightwatch test/e2e/homePageTest.js --env firefox

输出如下所示:

代码语言:javascript复制
[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中运行测试脚本

如果你在使用Mac,那么safaridriver可能已经安装了,这取决于你的Safari版本。

可以使用下面命令进行检查:

代码语言:javascript复制
safaridriver --help

输出可能长这样:

代码语言:javascript复制
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中运行你的第一个测试之前,你只需要通过以下命令启用自动化:

代码语言:javascript复制
safaridriver --enable

然后使用下面命令简单的运行Nightwatch测试:

代码语言:javascript复制
npx nightwatch test/e2e/homePageTest.js --env safari

在多个浏览器中并行运行

如果你需要在一个以上的浏览器中运行Nightwatch测试,你可以在多个浏览器中并行运行。

只需将浏览器作为逗号分隔的列表(没有空格)进行传递。

「在Firefox Chrome中运行」

代码语言:javascript复制
npx nightwatch test/e2e/homePageTest.js --env firefox,chrome

「在Firefox Chrome Safari中运行」

代码语言:javascript复制
npx nightwatch test/e2e/homePageTest.js --env firefox,chrome,safari

更多关于并行测试的内容,请查看Nightwatch docs[15]网站。

步骤五:使用Github Actions启用持续集成(CI)

是时候进行收尾工作,将他们放在一起了。在Github Actions中启用持续部署(CD)之前,我们需要创建npm test任务。

创建npm test任务

现在我们已经在示例项目中具备组件测试和端到端测试。当然这只是一个最低水平,所以它没有涵盖所有内容,但我认为这是一个良好的开端。

告诉Nightwatch运行测试文件夹中的所有测试的最简单方法是,将文件夹作为第二个CLI参数。我们将要添加该命令到作为一个新的被称为test的NPM任务中。让我们编辑package.json文件,在 "scripts "字段中添加以下内容:

代码语言:javascript复制
"test": "nightwatch ./test"

我们可以像这样来运行NPM任务,并传递Nightwatch相关的CLI参数:

代码语言:javascript复制
npm test -- --env chrome --headless

为了能在Github Actions中运行测试用例,我们将使用--headless模式。

添加Github Actions工作流

最后,我们可以添加Github Actions工作流。这样我们的测试就可以运行在每个推送和每个拉动请求上。

想要做到上述流程非常简单。我们将使用Node.js模板,在列表中添加几个新的步骤(step),比如:

  • 在后台启动dev server
  • 在后台构建项目并在预览模式下启动dev server
  • 在Chrome中使用无头模式运行组件以及端到端测试

创建Github Actions工作流程意味着,在.github/workflows文件夹中添加一个名为node.js.yml的新文件,内容如下所示。当你从Github项目导航到Actions部分并选择Node.js模板时,其中大部分内容都是自动生成的。

代码语言:javascript复制
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

这样就可以了。每当有新的git推送或新的PR被发送时,就会运行一个新的构建。构建将在2个独立的环境中运行,一个是Node 12,另一个是Node 14,如工作流中定义的那样。

今后的发展方向

该项目在Github上的网址是:https://github.com/beatfactor/middlemarch[16]。这里涵盖了所有的代码,还有一些样式和图片。它还包含了购物车的代码和一个模拟的结账页面。

homepage.png

你可以通过常规步骤让它在你的本地机器上运行:

代码语言:javascript复制
git clone <https://github.com/beatfactor/middlemarch>
npm install
npm run dev

欢迎发送PR或报告问题。

参考资料

[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]

文档页面: 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

0 人点赞