(System Under Test)搭建指南:URL 驅(qū)動的端到端測試與 onPrepare 全局準(zhǔn)備實(shí)戰(zhàn))
測試【免費(fèi)下載鏈接】protractorE2E test framework for Angular apps項(xiàng)目地址https://gitcode.com/gh_mirrors/pr/protractor點(diǎn)擊查看免費(fèi)下載本文基于本倉庫 docs/system-setup.md 展開系統(tǒng)講解 Protractor 端到端測試中被測系統(tǒng)的選擇與準(zhǔn)備方式為什么只需一個 URL 即可測試任意環(huán)境本地開發(fā)、內(nèi)網(wǎng)預(yù)發(fā)布乃至公網(wǎng)生產(chǎn)、手動 bootstrap 與輪詢型頁面兩類特殊場景的規(guī)避方案以及通過onPrepare完成登錄等全局預(yù)置的正確姿勢。讀完本文你將能夠?yàn)槿我?Protractor 項(xiàng)目正確配置被測系統(tǒng)并寫出同步可靠、無競態(tài)條件的測試啟動流程。一、被測系統(tǒng)的本質(zhì)真實(shí)瀏覽器 一個 URLProtractor 與許多基于 mock 的單元測試框架最大的不同在于它使用真實(shí)瀏覽器執(zhí)行測試。瀏覽器能訪問什么Protractor 就能測試什么因此你在決定測什么這件事上擁有極大的自由度一個跑在localhost上的本地開發(fā)服務(wù)器內(nèi)網(wǎng)中的預(yù)發(fā)布staging服務(wù)器甚至公網(wǎng)上直接面向用戶的正式production服務(wù)器。對 Protractor 而言它唯一真正需要的東西就是URL。測試啟動時通過browser.get(url)加載被測頁面后續(xù)所有查找元素、斷言、點(diǎn)擊等操作都發(fā)生在真實(shí)瀏覽器渲染出的頁面中。這一點(diǎn)也讓 Protractor 與 WebDriver 生態(tài)天然對齊底層連接的可以是本地 Selenium Server、遠(yuǎn)程 Selenium 服務(wù)或直連瀏覽器驅(qū)動具體連接方式由配置文件中的seleniumAddress、seleniumServerJar、directConnect等選項(xiàng)決定詳見 lib/config.ts。不過在只要給 URL 就行的寬松背后文檔明確警告了三類必須小心的情況下面逐一展開。二、注意事項(xiàng)一手動 bootstrap 的頁面 —— 請使用browser.driver.get正常情況下browser.get會在頁面加載后主動等待 Angular 完成引導(dǎo)bootstrap并進(jìn)入穩(wěn)定狀態(tài)。但如果你的頁面不是由 Angular 自動引導(dǎo)而是采用手動 bootstrap例如在代碼中顯式調(diào)用angular.bootstrap()或使用ngUpgrade之外的定制引導(dǎo)流程Protractor 將無法識別并加載該頁面。文檔給出的解決方案是放棄browser.get改用基礎(chǔ) WebDriver 實(shí)例browser.driver.get// 手動 bootstrap 頁面無法用 browser.get 加載 // browser.get(/ng1/login.html); // ? 不可靠 // 改用基礎(chǔ) webdriver 實(shí)例 await browser.driver.get(http://localhost:8080/login.html);browser.driver是 Protractor 對外暴露的原生WebDriver實(shí)例在 lib/browser.ts 中構(gòu)造它完全繞過 Angular 同步機(jī)制直接把命令交給瀏覽器執(zhí)行。這帶來一個連鎖后果Protractor 不再知道頁面何時加載完成你需要自行添加wait語句否則測試容易產(chǎn)生競態(tài)條件race condition——元素尚未渲染就開始點(diǎn)擊/斷言導(dǎo)致偶發(fā)失敗。這正是倉庫登錄測試配置 spec/withLoginConf.js 中的做法登錄頁是非 Angular 手動引導(dǎo)頁面因此先用browser.driver.get打開再配合browser.driver.wait顯式等待登錄跳轉(zhuǎn)完成詳見下文第四節(jié)。何時用browser.driver.get的經(jīng)驗(yàn)法則頁面完全不依賴 Angular或 Angular 引導(dǎo)由自定義邏輯觸發(fā)頁面是純 WebDriver 流程的一部分如測試前的登錄頁只要使用了browser.driver.get就應(yīng)當(dāng)配套顯式等待邏輯不能依賴 Protractor 的自動同步。三、注意事項(xiàng)二用$timeout輪詢的頁面 —— 改用$intervalProtractor 的核心同步機(jī)制是執(zhí)行任何操作前它會等待 Angular 應(yīng)用沒有待處理pending的異步任務(wù)。如果你在 AngularJS 應(yīng)用中使用$timeout做持續(xù)輪詢那么同一時刻永遠(yuǎn)有未完成的異步任務(wù)Protractor 會一直等待下去直到觸發(fā)超時。文檔明確給出建議把輪詢用的$timeout換成$interval。// ? 持續(xù)輪詢 $timeoutProtractor 永遠(yuǎn)等不到穩(wěn)定 // $timeout(poll, 1000); // ? 持續(xù)輪詢請使用 $intervalAngularJS 1.2rc3 起提供 $interval(poll, 1000);這一論斷在 docs/timeouts.md 中有更詳細(xì)的佐證如果 AngularJS 應(yīng)用持續(xù)輪詢$timeout或$httpProtractor 會無限等待并超時輪詢場景應(yīng)使用$interval。對于使用 Zone.js 的 Angular2應(yīng)用類似的思路是把長期運(yùn)行的異步任務(wù)放到 Angular Zone 之外執(zhí)行避免阻塞測試?yán)^續(xù)。從底層看Protractor 通過注入腳本裝飾$timeout/$interval來追蹤待處理任務(wù)配置項(xiàng)untrackOutstandingTimeouts與此相關(guān)見 lib/config.ts。因此被測應(yīng)用能否被正確同步本質(zhì)上取決于應(yīng)用側(cè)異步 API 的選擇——這也是設(shè)置被測系統(tǒng)環(huán)節(jié)需要重點(diǎn)審查的代碼層面因素。四、注意事項(xiàng)三全局測試準(zhǔn)備 ——onPrepare的三種形態(tài)如果測試前需要做全局準(zhǔn)備最典型的場景是登錄文檔要求你把它放進(jìn)配置文件的onPrepare屬性中。onPrepare是一個多態(tài)polymorphic屬性既可以是函數(shù)也可以是文件名函數(shù)形態(tài)直接內(nèi)聯(lián)在配置文件里例如 spec/onPrepareConf.jsexports.config { framework: jasmine, specs: [onPrepare/*_spec.js], baseUrl: env.baseUrl /ng1/, onPrepare: () { browser.params.password 12345; // 預(yù)設(shè)一個全局參數(shù) } };文件形態(tài)傳入相對路徑字符串Protractor 會用 Node.js 的require加載該文件并執(zhí)行其內(nèi)容。例如 spec/onPrepareFileConf.js 與對應(yīng)的 spec/onPrepare/startup.js// onPrepareFileConf.js exports.config { specs: [onPrepare/*_spec.js], baseUrl: env.baseUrl /ng1/, onPrepare: onPrepare/startup.js // 字符串 → 文件路徑 };// onPrepare/startup.js —— 文件內(nèi)容即為要執(zhí)行的準(zhǔn)備邏輯 browser.params.password 12345;文件形態(tài)下路徑是相對于配置文件所在目錄解析的——這一點(diǎn)在 lib/configParser.ts 中有明確實(shí)現(xiàn)onPrepare與其他文件路徑類配置如seleniumServerJar、chromeDriver、firefoxPath一起被統(tǒng)一轉(zhuǎn)換為相對于當(dāng)前配置文件的路徑。驗(yàn)證這兩種形態(tài)等價性的測試見 spec/onPrepare/onPrepare_spec.js其中的斷言expect(browser.params.password).toEqual(12345)證明onPrepare中寫入的browser.params確實(shí)在測試用例中生效。4.1onPrepare可以返回 Promise —— 時序保證的關(guān)鍵文檔強(qiáng)調(diào)了一個容易被忽略但至關(guān)重要的細(xì)節(jié)onPrepare可以返回一個 PromiseProtractor 會等待它完成后再繼續(xù)執(zhí)行。當(dāng)準(zhǔn)備過程涉及異步調(diào)用例如與瀏覽器交互時必須這樣做否則 Protractor 無法保證執(zhí)行順序可能在準(zhǔn)備完成前就開始跑測試。也就是說如果onPrepare里有異步操作卻不返回 Promise測試與準(zhǔn)備之間就會出現(xiàn)競態(tài)。正確寫法是讓onPrepare變成async函數(shù)或顯式返回 Promise例如 spec/onPreparePromiseConf.jsonPrepare: async() { browser.params.password 12345; return await new Promise(resolve { setTimeout(resolve, 1000); // 模擬耗時準(zhǔn)備 }); }文件形態(tài)同樣支持返回 Promise——文件導(dǎo)出一個async函數(shù)即可見 spec/onPreparePromiseFileConf.js 對應(yīng)的 spec/onPrepare/asyncstartup.jsmodule.exports async() { browser.params.password 12345; return await new Promise((resolve) { setTimeout(resolve, 1000); }); }4.2 源碼級驗(yàn)證onPrepare到底怎么被執(zhí)行的onPrepare的函數(shù)或文件名二選一語義由 lib/util.ts 中的內(nèi)部助手runFilenameOrFn_統(tǒng)一實(shí)現(xiàn)若傳入的是字符串則以configDir為基準(zhǔn)執(zhí)行require(path.resolve(configDir, filenameOrFn))加載文件加載結(jié)果若為函數(shù)則await filenameOrFn.apply(null, args)調(diào)用它await保證了返回的 Promise 會被等待——這正是Protractor 會等 onPrepare 的 Promise 完成這一行為的技術(shù)根基。調(diào)用鏈上lib/runner.ts 在setTestPreparer(config.onPrepare)約 L61注冊準(zhǔn)備函數(shù)隨后在真正執(zhí)行用例前先運(yùn)行插件準(zhǔn)備、再執(zhí)行runFilenameOrFn_(this.config_.configDir, this.preparer_)約 L92-L94。結(jié)合 lib/config.ts 對onPrepare的注釋還可以確認(rèn)當(dāng)使用 multiCapabilities 并行跑多個瀏覽器時onPrepare會對每個 capability 各執(zhí)行一次且此時 Protractor 全局對象與測試框架全局如 Jasmine都可用你可以利用browser.getProcessedConfig()讀取當(dāng)前正在執(zhí)行的 capability。五、實(shí)戰(zhàn)案例用onPrepare完成登錄完整可復(fù)制倉庫在 spec/withLoginConf.js 中提供了一個完整的測試前登錄配置是系統(tǒng)設(shè)置文檔直接推薦的范例。完整解讀如下const env require(./environment.js); exports.config { seleniumAddress: env.seleniumAddress, // 連接已運(yùn)行的 Selenium Server SELENIUM_PROMISE_MANAGER: false, // 關(guān)閉 WebDriver 控制流改用 async/await framework: jasmine, specs: [login/login_spec.js], // 待運(yùn)行的測試 capabilities: env.capabilities, // 瀏覽器能力 baseUrl: env.baseUrl /ng1/, // 被測應(yīng)用基地址 onPrepare: async() { // 1) 登錄頁是非 Angular 手動 bootstrap 頁面必須用 browser.driver.get await browser.driver.get(env.baseUrl /ng1/login.html); // 2) 直接通過 WebDriver 原生 API 填寫表單 await browser.driver.findElement(by.id(username)).sendKeys(Jane); await browser.driver.findElement(by.id(password)).sendKeys(1234); await browser.driver.findElement(by.id(clickme)).click(); // 3) 登錄需要時間顯式等待跳轉(zhuǎn)到 index.html 才繼續(xù) return await browser.driver.wait(async() { const url await browser.driver.getCurrentUrl(); return /index/.test(url); }, 10000); } };這個例子把本文第二、四節(jié)的要點(diǎn)全部落地登錄頁不可用browser.get→ 用browser.driver.get打開并全程使用browser.driver.findElement而非element(...)操作表單準(zhǔn)備是異步的→onPrepare聲明為async并返回 Promisereturn await browser.driver.wait(...)顯式等待消除競態(tài)→ 用browser.driver.wait輪詢當(dāng)前 URL 是否包含index超時上限 10 秒確認(rèn)登錄跳轉(zhuǎn)完成后才放行測試。配套的測試用例見 spec/login/login_spec.js登錄態(tài)通過 cookie 保持測試直接browser.get(baseUrl /ng1/index.html)進(jìn)入主頁面斷言登錄后的 cookietestcookie值為Jane-1234從而驗(yàn)證onPrepare建立的會話確實(shí)在整個測試過程中有效。六、為被測系統(tǒng)補(bǔ)齊配套配置除了onPrepare與baseUrl搭建被測系統(tǒng)時通常還會涉及以下配置均出自 lib/config.ts 的完整注釋配置項(xiàng)作用說明baseUrl被測應(yīng)用基地址browser.get()傳入相對路徑時會基于它解析url.resolve語義見 lib/config.tsgetPageTimeout頁面加載超時毫秒默認(rèn) 10 秒超時錯誤形如Timed out waiting for page to load after 10000ms可全局配置或按次傳參browser.get(address, timeout)見 docs/timeouts.mdallScriptsTimeoutAngular 同步超時毫秒默認(rèn)約 11 秒若應(yīng)用異步任務(wù)遲遲不結(jié)束會觸發(fā)見 docs/timeouts.mdcapabilities/multiCapabilities單/多瀏覽器能力可附加count、shardTestFiles、maxInstances等并行參數(shù)見 lib/config.tsspecs/suites指定要跑的測試specs為相對當(dāng)前配置文件的路徑模式見 lib/config.ts兩個直接的工程建議為被測應(yīng)用準(zhǔn)備多種環(huán)境地址由于被測系統(tǒng)只需 URL可在配置中按環(huán)境切換baseUrl如http://localhost:4200與https://staging.example.com配合params甚至命令行參數(shù)--params.xxx見 lib/config.ts實(shí)現(xiàn)一套配置多環(huán)境復(fù)用把頁面是否由 Angular 引導(dǎo)、是否持續(xù)輪詢當(dāng)作被測系統(tǒng)的驗(yàn)收標(biāo)準(zhǔn)上線測試前先檢查應(yīng)用側(cè)這兩類代碼特征能從根本上避免同步超時與競態(tài)遠(yuǎn)比在測試側(cè)打補(bǔ)丁可靠。小結(jié)設(shè)置被測系統(tǒng)對 Protractor 來說本質(zhì)是回答三個問題被測頁面能不能被browser.get正常加載應(yīng)用會不會讓 Protractor 永遠(yuǎn)等不到穩(wěn)定進(jìn)入主流程前需要做什么全局準(zhǔn)備本文從 docs/system-setup.md 出發(fā)結(jié)合倉庫源碼與配置示例給出了完整答案手動 bootstrap 頁面用browser.driver.get 顯式等待輪詢用$interval替代$timeout登錄等全局準(zhǔn)備放進(jìn)onPrepare函數(shù)或文件皆可異步時必須返回 Promise。沿著這三條主線即可在任意環(huán)境上搭建出穩(wěn)定、可復(fù)現(xiàn)的端到端測試被測系統(tǒng)。贊分享測試【免費(fèi)下載鏈接】protractorE2E test framework for Angular apps項(xiàng)目地址https://gitcode.com/gh_mirrors/pr/protractor點(diǎn)擊查看免費(fèi)下載相關(guān)推薦微信QQ防撤回補(bǔ)丁教程4步裝好補(bǔ)丁讓對方撤回?zé)o效微信QQ防撤回補(bǔ)丁教程4步裝好補(bǔ)丁讓對方撤回?zé)o效 晚上十一點(diǎn)四十客戶在群里發(fā)來發(fā)票金額沒錯按這個走幾秒后這條消息變成一行灰字。第二天早上你追問時桌面應(yīng)用即時通訊STF 測試指南基于 Karma 與 Protractor 的前端單元測試和端到端測試實(shí)戰(zhàn)STF 測試指南基于 Karma 與 Protractor 的前端單元測試和端到端測試實(shí)戰(zhàn) 本文以 Smartphone Test FarmSTF倉庫的測試后端前端json.lua 錯誤處理完全指南如何精準(zhǔn)定位 JSON 解析問題json.lua 錯誤處理完全指南如何精準(zhǔn)定位 JSON 解析問題 JSON 解析是應(yīng)用開發(fā)中常見的任務(wù)但錯誤處理往往被忽視。本文將深入探討 Lua 輕量級序列化上一篇ComfyUI Florence2模型加載深度解析與實(shí)戰(zhàn)指南下一篇Haystack 與 MongoDB Atlas 集成實(shí)戰(zhàn)MongoDBAtlasDocumentStore 與雙檢索器Embedding / Full-Text完全指南創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考