現在日常的 JavaScript 已經完全離不開 TypeScript 了,在強型別的保護下,不但不容易寫出錯誤的代碼,還能透過開發工具提供的 IntelliSense 提高開發速度。但是如果手邊的程式碼只能使用 JS 來撰寫,那該怎麼辦呢?像是 Protractor 的設定檔 protractor.conf.js
就是一個典型的例子,本篇文章我將分享如何在現有 JavaScript 檔案下使用 TypeScript 的型別檢查提示。
從一個最簡單的 Angular CLI 專案開始
我先示範 Protractor 手動執行的過程:
-
建立全新 Angular 專案
ng new demo1 --routing --style css
cd demo1
-
先更新 WebDriver 的驅動程式
npx webdriver-manager update
-
啟動 Angular Live Development Server 開發伺服器
npm start
-
最後則是啟動 Protractor 程式,執行預設的 E2E 測試
npx protractor .\e2e\protractor.conf.js
上述步驟,除了第一步是建立 Angular 專案外,其餘的 2, 3, 4 步,其實可以透過一個命令來完成,那就是:npm run e2e
或 ng e2e
即可包含以上最後三個步驟。如果可以自動完成 3 個步驟,為什麼還要寫出手動執行的步驟呢?原因只有一個:效率!
你可以想想,如果每次執行 ng e2e
都要等他 Build/Update/Run 不是很浪費時間嗎?所以建議你調整一下 package.json
的 scripts
設定,將 e2e
項目內容從 ng e2e
改為 ng e2e --dev-server-target= --webdriver-update=false
,如此一來,下次你要執行 npm run e2e
的時候,就不會自動啟動 npm start
與更新 WebDriver 驅動程式了!(不過前提是你要自己先手動更新一遍)
ng e2e --dev-server-target= --webdriver-update=false
關於 protractor.conf.js
設定檔
我們從上述手動步驟就可以看出 Protractor 其實會先載入一個 protractor.conf.js
設定檔,然後依據設定檔的內容,決定 Protractor 要載入哪些 *.e2e-spec.ts
檔案?執行哪個瀏覽器?使用什麼測試框架?等等!
透過 Angular CLI 建立的專案中,所有 Protractor 的 E2E 測試檔 (./src/**/*.e2e-spec.ts
),都已經調整為 TypeScript 檔案了,所以撰寫 E2E 測試的過程,可以享用 TypeScript 帶來的好處。即便如此,唯讀一個 JS 檔案沒有用到 TypeScript 型別輔助,那就是 protractor.conf.js
設定檔自己!
上網查找資料,你會看見有人硬把 protractor.conf.js
設定檔改為 protractor.conf.ts
(只改副檔名),所以在執行 Protractor 之前,要先透過 tsc protractor.conf.js
才能開始跑 Protractor,我覺得這個解決方案太髒了,不太理想,我則是選用另一種途徑。
對現有的 JavaScript 檔案進行型別檢查
我們都知道學習 TypeScript 是有一點進入門檻的,畢竟從一個「弱型別」的 JavaScript,換成一個「強型別」的 TypeScript,除了要學習一些新語法之外,還要熟悉一些相關工具,否則就會變得綁走綁腳,覺得不實用。
因此,TypeScript 設計出一種機制,可以讓你不改變 JavaScript 原有程式的情況下,立刻開始使用「強型別」來開發程式!
你可以從 Type Checking JavaScript Files 看見完整的說明!
以下是將 protractor.conf.js
設定檔調整為「部分強型別」的步驟:
-
請在該檔案的第一行加入以下註解,加入後該檔案就進入了 TypeScript 的世界!
// @ts-check
設定完成之後,只要有型別錯誤出現,在 VSCode 中就會立刻發現!如果有未知的型別,也會自動標示為 any
任意型別,所以對開發上完全沒影響,也不會因為缺乏型別定義而顯示過多的錯誤訊息!
我認為這種狀態應該是最適合初學者入門的設定方法!
-
接著將 exports.config
這個變數宣告為 Config
型別
一樣是透過加入註解的方式進行宣告,因此不影響原有程式的任何行為!
/**
* @type { import("protractor").Config }
*/
exports.config = {
此時,整份檔案的設定已經是完全強型別了,所有已知的屬性,都能享有 型別檢查 (Type Checking) 與 IntelliSense 功能。
除此之外,當你把滑鼠移動到任何一個 屬性 (Property) 上面,還會出現完整的文件,實在相當便利!
-
在 onPrepare()
加入 browser.waitForAngularEnabled(false);
因為 Protractor 是為 Angular 量身打造的工具之一,預設的情況下,當你進入某個頁面後,Protractor 會先尋找該頁面是否有 AngularJS 或 Angular 應用程式在執行中,如果有找到的話,才會繼續執行。
不過,當你想測試的網站/網頁不是用 Angular 所開發的時候,就必須加入這段程式碼。如果你想要測試的網站完全不是 Angular 所開發的,那你很有可能就會在 onPrepare()
加入 browser.waitForAngularEnabled(false);
程式碼!但加入之後,就會立刻出現 TypeScript 的型別提示:
就一個相當基本的常識,尚未宣告的變數 browser
直接使用,原本就是程式碼的壞味道,這時出現提示其實也是相當合理的。但是對 Protractor 來說,他是跑在 Node.js 底下的,這裡的 browser
其實是一個全域變數 (其實是 global
全域變數下的一個 browser
屬性)。
這個時候,你就必須在相同的函式範圍內,額外用 var
/ let
或 const
宣告一個 browser
區域變數。不過,直接宣告變數是不行的,因為宣告下去之後,在此範圍內存取該變數,就會得到 undefined
的值。因此,你應該用以下程式碼片段來宣告,才是正確用法:
const browser = global['browser'];
加入之後的變數,其型別為 any
:
比較好的做法,當然是把 browser 變成具有型別的變數,我們可以用以下程式碼片段來宣告正確的型別:
/**
* @type { import("protractor").ProtractorBrowser }
*/
const browser = global['browser'];
如此一來,整份 protractor.conf.js
設定檔就都是具有型別的變數了,是不是很棒呢!
相關連結