在前面的實作中我們將前端跟後端分別獨立進行開發,這是很常見的一種方式。然而在 Rails 7 的生態系裡面,透過 jsbundling-rails 可以很輕鬆的整合在一起,接下來我們會使用類似基礎的 ViteRuby 把前端的 Cucumber 測試搬移到 Rails 上重現一次性整合完畢的實作。
安裝 Vite Ruby
要安裝 ViteRuby 非常簡單,開發團隊已經準備好了 vite_rails 可以直接套用到 Rails 專案中,關於 Rails 中設定 Cucumber 等開發環境的部分,可以直接使用我預先製作好的樣板 rails-developer-foundation-template 來進行開發。
首先,我們基於樣板建立新的專案,然後運行以下命令加入 ViteRails 套件。
1bundle add vite_rails
2bundle exec vite install
執行完畢後會自動將原有的 jsbundling-rails
做一些更新,我們只需要驗證 bin/vite dev
是否可以正確運行即可。
安裝 Vue
Vite 的定位是簡化前端開發的工具,因此預設不會有 Vue 的環境存在,我們需要在 ViteRuby 生成的基礎下手動將 Vue 加入到專案中。
所需的設定可以參考前面純前端版本的實作複製設定,我們在這邊只會做必要的調整。
運行以下命令把 Vue 和 Vite 的外掛安裝進去。
1yarn add vue vite-plugin-ruby
接下來修改自動生成的 vite.config.ts
加入 Vue 的外掛,大致上會呈現這個樣子。
1import { defineConfig } from 'vite'
2import RubyPlugin from 'vite-plugin-ruby'
3import Vue from '@vitejs/plugin-vue'
4
5export default defineConfig({
6 plugins: [
7 RubyPlugin(),
8 Vue(),
9 ],
10})
這樣一來我們就可以在專案中使用 Vue 來進行開發,然而目前會把 jsbundling-rails
和 ViteRuby 的設定混在一起,因此我們還需要清理一下 Rails 的 Layout。
修改 app/views/layout/application.html.erb
把 jsbundling 相關的部分清除掉,留下 ViteRuby 的引用,並且加入 Vue 要附加的 Div 元素。
1<!DOCTYPE html>
2<html>
3 <head>
4 <title>DeveloperFoundation</title>
5 <meta name="viewport" content="width=device-width,initial-scale=1">
6 <%= csrf_meta_tags %>
7 <%= csp_meta_tag %>
8
9 <%= vite_client_tag %>
10 <%= vite_typescript_tag 'application', "data-turbo-track": "reload", defer: true %>
11 </head>
12
13 <body>
14 <div id="app">
15 <%= yield %>
16 </div>
17 </body>
18</html>
這裡只加入最低限度的 JavaScript 實際專案中使用可以根據情況調整,並且我們預設所有頁面都會被 Vue 替換掉,因此將 <%= yield %>
用 <div>
標籤包覆起來。
因為預設採用 TypeScript 的關係,別忘記將
app/javascript/entrypoints/application.js
的副檔名替換為.ts
用 Cucumber 驗證環境
最後,我們要驗證我們可以用 Cucumber 來對前端做測試,加入 features/products.feature
和以下內容,先用於確認 Vue 正確的被載入。
1#language:zh-TW
2@javascript
3功能: 商品列表
4 場景: 當開啟網站時,可以看到 Hello, ViteRuby
5 當 開啟網站
6 那麼 可以看見 "Hello, ViteRuby"
這裡會發現我們額外加入了 @javascript
的標籤,這會讓 Cucumber 意識到需要呼叫 Capybara 使用真實的瀏覽器運行去模擬,關於對應的設定可以參考樣板中 features/support/env.rb
的內容,以及 cucumber-rails 的文件。
接著加入 feature/step_definitions/common.rb
來定義步驟,雖然我們可以沿用 .feature
文件,然而在不同語言跟環境中,會需要用對應的語言重新實作步驟定義。
1# frozen_string_literal: true
2
3When('開啟網站') do
4 visit root_path
5end
6
7Then('可以看見 {string}') do |text|
8 expect(page).to have_text(text)
9end
這邊使用 Capybara 的匹配器(Matcher)來檢查畫面上有出現的文字。
接下來我們修改 app/javascript/entrypoints/application.ts
的內容從預設的樣板,改為初始化 Vue 的實作。
1import { createApp } from 'vue'
2import App from '@/App.vue'
3
4const app = createApp(App)
5app.mount('#app')
再將 app/javascript/App.vue
補到專案裡面,寫上 Hello, ViteRuby
來配合我們的第一個測試。
1<template>
2 <div>Hello, ViteRuby</div>
3</template>
最後補上一個空的 Controller 和 View 讓我們可以將畫面渲染出來。
1Rails.application.routes.draw do
2 root 'stores#index'
3end
1# app/controllers/stores_controller.rb
2
3class StoresController < ApplicationController
4end
1mkdir -p app/views/stores
2touch app/views/stores/index.html.erb
接下來運行 bundle exec cucumber
確認是否能正常通過測試,如果遇到 JavaScript 檔案不存在的話,可以運行 ./bin/dev
或者 bundle exec rake assets:precompile
來生成,在 Rails 專案樣板中預設使用 Chrome Headless 模式,如果是自己安裝 Cucumber 的話要可以看到跳出瀏覽器開啟畫面的樣子。
接下來,就要把前端的實作轉移到 Rails 上來重現相同的功能。
如果對這篇文章有興趣,可以透過以下連結繼續閱讀這系列的其他文章。
- 同時完成測試與文件 - Cucumber 的文件測試法
- 基本語法:功能描述 - Cucumber 的文件測試法
- 基本語法:驗證行為 - Cucumber 的文件測試法
- 基本語法:步驟定義 - Cucumber 的文件測試法
- 基本語法:輔助設定 - Cucumber 的文件測試法
- 前端環境:Vite 與 Cucumber - Cucumber 的文件測試法
- 商品列表與加入購物車 - Cucumber 的文件測試法
- 重構與移出購物車 - Cucumber 的文件測試法
- 商品資料與總價 - Cucumber 的文件測試法
- 結帳與結果 - Cucumber 的文件測試法
- 整理前端實作 - Cucumber 的文件測試法
- 初始化後端專案 - Cucumber 的文件測試法
- 商品資料 API - Cucumber 的文件測試法
- 更新購物車 API - Cucumber 的文件測試法
- 加入資料模型 - Cucumber 的文件測試法
- 持久化保存 - Cucumber 的文件測試法
- 結帳處理 - Cucumber 的文件測試法
- 在 Rails 的前後端分離 - Cucumber 的文件測試法
- 匯入前端實作 - Cucumber 的文件測試法
- 重現後端實作 - Cucumber 的文件測試法
- 累積價值 - Cucumber 的文件測試法