## 一個開發人員對于Appium的概述
在閱讀這個此文檔之前,請確保你已經閱讀并理解了關于[Appium的基本概念](../about-appium/intro.md),
以及關于如何參與[Appium貢獻說明](https://github.com/appium/appium/blob/master/CONTRIBUTING.md)
### 技術愿景
Appium致力于成為一個移動JSONWP前端,實現最佳的應用自動化技術。僅此而已。我們想要采用所有不同的
但自帶亮點的自動化引擎,通過制作Appium驅動程序來平滑它們的差異和瑕疵,同時將它們納入Appium。這與
Selenium項目有異曲同工之妙。對于我們而言,我們想要每一個驅動都是一個獨立的實體(單獨的repo, 測試,
等等)即便它們使用共享庫,這一舉措會使Appium驅動程序的開發變得盡可能簡單,而且不拘泥于樣板。我們之所以
使用現今流行的JavaScript,因為它們無處不在,而且對于很多開發人員而言容易理解并易于貢獻。
### 開發者社區
歡迎任何人成為Appium開發人員,你僅需要閱讀此指南并把你的一些代碼合并進來,那么你就成為了我們一員。
如果你堅持不懈并且廣施善緣,我們將會把你升級為一名提交者,這樣你能繼續幫助社區發展而且省去很多紛繁復雜。
如果你在開發Appium的時候遇到疑問,請前往我們的開發人員社區`appium-developers@googlegroups.com`.
請注意,這是一個為_開發_疑問而設的郵件列表,而不是關于_使用_疑問或bug提交。 有關使用問題請前往[discuss.appium.io](https://discuss.appium.io)
Github問題跟蹤只是用于bug提交和功能需求。
### 敏捷開發工作流程
Appium團隊根據輕量化的scrum版本來運行開發。每兩個星期我們開始一個新的“sprint”,或者每一段時間,我們
會決定團隊下一階段需要完成的事情。我們歡迎任何熟悉Appium代碼庫的人參加我們的sprint計劃,并將視作SCRUM參與團隊成員。
參與者無需是代碼長期提交者。sprint期間,我們將在[Appium slack 團隊](https://appium.slack.com)的
`#standup` 聊天室更新我們每個人的進程(沒有實時的每天站立會議)。sprint結束時,我們將舉行“回顧”活動,以此來
慶祝我們取得的成就并總結活動進展如何,這可能會生成一個關于如何進行不同嘗試又或者如何做的更好的總結列表。
最終,我們的目標是在每一個sprint結束時發布一個Appium版本,也就是說每兩個星期一個周期。我們還沒有實現這個目標,但希望
我們能很快達成。
當前會議時間:
* sprint計劃: 每兩個周一 10:00 AM - 10:45 AM (太平洋時間)
* sprint回顧: 每三個周五 1:00 PM - 1:30 PM(太平洋時間)
我們使用[Zoom](https://zoom.us)視訊來舉行會議
關于項目管理,我們使用[ZenHub](http://zenhub.com) 瀏覽器插件,它向GitHub接口提供了例如
Kanban boards 和 Epics 這些功能。要完全參與到Appium SCRUM,你需要安裝上述的這些瀏覽器插件。
如果你有意參加sprint,你可以在Appium Slack群組里聯系`@jlipps` 或者 `@isaac`,又或者直接在推特
上聯系`@jlipps`,我們將會在下一次sprint里分享如何加入視頻聊天。
### 構造
Appium主要是一個[node.js](http://nodejs.org)包的集合,以此組合形成一個運行的node.js服務器。
這些包都被單獨維護并擁有各自的GitHub repo, CI和發布流程。一些軟件包(比如 `appium-ios-driver`)
很大,并且給Appinum添加了很重要的功能。相比而言,其他軟件包則扮演著一個輔助的角色,而且高度曝光其某個
特定并被反復使用的功能。
有關軟件包的層次結構和每一個包所起的作用,請前往我們[包的概述](../contributing-to-appium/appium-packages.md)文檔。
### 轉化
Appium是用JavaScript的新形式編寫的,稱為ES6(或現在的ES2015)。因為這個版本的語言尚未被老版本
node.js的原生支持,Appium代碼是_被移植_到ES5(JS更為廣泛支持的版本)。這個轉化過程必須發生在所有
代碼運行之前。除了ES6的新語言特性,我們也從JS的_后續_版本中采用了很重要的關鍵詞,`async` 和 `await`,
這有助于編寫整潔的異步代碼。因為這個代換的步驟,Appium軟件包囊括了觀察代碼變化和重新編排代碼的工具。
通常而言,同樣的工具會自動運行單元測試,同時確保沒有任何小的紕漏。大多Appium軟件包在運行`gulp`的時候
把上述過程當做默認行為。
### 排查和代碼風格
對于所有Appium的JS而言,代碼外觀和使用感覺同樣重要。這包括樣式常規,編碼模式以及我們解決各種問題時使用的
庫。你應該熟悉我們新的[ES2015 風格指南](../contributing-to-appium/style-guide.md)。
當轉化時,Appium包將自動運行ESHint或其他lint工具,并在代碼不符合我們規范的時候提供警告或錯誤反饋。
這些工具不一定能顧全我們關心的種種風格問題,所以我們在review代碼的時候也應該注意代碼規范問題。這不是
吹毛求疵,而是為了有一個整潔,一致并且可讀的代碼庫。
### 提交代碼
將你的代碼提交到Appium很容易:你只需要提交一個pull請求到我們的repos并在代碼review的過程中與我們的
維護者進行互動。我們對代碼提交有一系列的要求(但是不用擔心!如果下面所列的太過繁復,我們將會為你一一道來)。
那我們就從你提交PR的那一步開始吧:
* 參考其他代碼的樣式和我們的樣式指南
* Atomic 提交 -- 每個邏輯變化進行一次提交(例如:確保你的提交不用進入組論即可以正常運行,而且它在任何指定提交下都應該正常運行)這通常意味著每個PR一個提交。你將想要非常熟悉的`git rebase -i` 和壓縮。
* 沒有合并提交:在提交你的PR之前,通常在最新的master之上進行rebase(或者其它你想要merge進去的branch)。
* 幾乎所有的更改都應該有測試。關于漏洞修復,至少應該有單元測試以證明這個bug已被修復。新功能應該有單元測試,并且在大多數情況下進行e2e測試,以證明該功能正常工作。我們將樂意帶你瀏覽測試的創建過程。閱讀其他的測試代碼會是一個很好的開始。我們的CI系統通常運行測試覆蓋率統計,而且我們不大可能去合并那些會降低測試覆蓋率的代碼。
如果你在提交之前做了所有這些事情,你的代碼將可能很快被接受。當然,如果你打算對Appium進行大量的改造工作,你可以聯系開發人員,以確保這些改變符合我們的理念,這樣在你開動之前確保我們會接受這些改動。
### 測試
始終確保你的更改已經被測試過! 除了單測試和e2e測試,請確保在你開始進行更改和提交review之前,所有現有測試都被運行。
我們有為每一個Appium repo設置CI作為安全網,這樣便于審閱者知曉代碼是否已經通過測試。在任何Appium包運行測試都很容易!
以下是你可以做的事情(除非README另有說明):
```
npm run lint # 在代碼里運行 eslint
npm run watch # 監測目錄下重編譯代碼更改,lint 以及運行單元測試
npm run test # 同上,當不提供監測
npm run e2e-test # 轉化以及運行端到端/功能測試
_FORCE_LOGS=1 <command> # 顯示測試運行期間的模塊日志輸出
```
請注意,單元測試的文件后綴通常為 `-specs.js` ,而e2e測試文件后綴則為`-e2e-specs.js`.
### 發布
任何非Appium主包的發布流程都是非常簡潔明了的(請注意:如果你想要發布它,你需要成為一個NPM的所有者。
所有權由Appium提交者管理; 如果你對所有者有任何疑問,請聯系@jlipps 或者 @imurchie)。
1. `rm -rf node_modules && rm -rf package-lock.json && npm install` 并運行測試以確保全新安裝正常工作
1. 根據[SemVer](http://semver.org/) 規則決定我們是否需要發布一個補丁(漏洞修復),微調(功能)或者是主要(迭代)(請參考 [how SemVer works with NPM](https://docs.npmjs.com/getting-started/semantic-versioning).
1. 通過任何適當的更改和提交來更新 CHANGELOG 和/或 README文件。大多數子包沒有CHANGELOG。
1. 通過適當的版本類型運行 `npm version <version-type>`
1. 將適當的分支推送到GitHub, 不要忘記加入`--tags` 來標記剛由 `npm version`創建的標志.
1. 運行 `npm publish` (如果不是正式版, 請使用`--tag beta`).
對于Appium的主包發布,上述步驟必須執行,但有以下改變。一個原因是對于主包,我們使用NPM收縮包裝
以確保依賴在安裝的時候不更改。另一個原因是我們在master上開發和各種分支上發布。它的工作方式
如下:我們經常在master上開發和增加新的代碼。 當我們準備好了做一個新的次要或主要版本(例如`1.5.0`
或`2.0.0`),我們創建一個發布分支(分別為`1.5`或`2.0`)。然后我們發布該分支。 一旦我們認為需要修復補丁,
我們首先將補丁拉到master中,然后將單個補丁挑選到發布分支(甚至是多個發布分支)。 然后我們再次
從這些分支發布更新的補丁版本(例如`1.5.1`或`2.0.1`)。
每次正式版本發布前至少有一個候選版本,例如,如果準備發布 1.12.0,這樣我們需要切換到分支 `1.12`,然后先發布 `1.12.0-rc.0`。
我們會持續發布最新的候選版本直到滿意為止,然后就會更新正式版本。正式版本會有相同的代碼和 shrinkwrap,成為下次的候選版本。
唯一的區別在于版本,體現在 package.json 和 npm-shrinkwrap.json文件上面。
**關于 `npm shrinkwrap`的注釋:** 我們使用[npm shrinkwrap](https://docs.npmjs.com/cli/shrinkwrap)是為了在發布時鎖定依賴關系。
沒有它,任何依賴包上的開發將在安裝Appium時反應出來,這可能會導致問題。 由于配置文件`npm-shrinkwrap.json`僅存在于發布分支上,
因此有必要在發布過程中手動管理它。 它需要與對`package.json`的更改一起提交到GitHub。npm 5+ 還會產生一個 `package-lock.json` 文件,在收縮過程中轉化成 `npm-shrinkwrap.json` 文件。
1. 如果 npm-shrinkwrap.json 和 package-lock.json文件存在,請移除.
1. `rm -rf node_modules && npm install` 并運行測試以確保全新安裝正常工作
1. 根據SemVer來決定我們是否需要發布一個補丁(漏洞修復),微調(功能)或者是主要(迭代)
1. 用合適的新版本信息來更新`package.json`
1. 對CHANGELOG/README進行合適的更改,同shrinkwrap 和 `package.json`的改變一起以PR的形式進行提交審核。待它被合并之后,把它`pull`進`release`分支。
1. 運行`npm shrinkwrap` 生成`npm-shrinkwrap.json`文件
1. 在發布分支(通常是一個小分支,如`1.5`或`1.4`)上創建一個形式為`v <version>`的標簽:`git tag -av <version>`,例如`git tag -a 1.5.0`, `git tag -a v1.5.0-rc.1`。 這對測試版本不是必需的。
1. 把標簽推送到上游分支: `git push --tags <remote> <branch>`
1. 運行`npm publish`(如果這不是正式版本,請使用`--tag beta` )。
1. 從Git里刪除npm-shrinkwrap.json文件,并把這個改動push到Git.
1. 在 https://github.com/appium/appium.io/pulls 更新網站文檔,然后合并 Triager bot 最近提交的 Open 狀態的 PR 代碼,并關閉他的其他已打開的 PR。
1. 在GitHub上創建一個新版本:轉到`https://github.com/appium/appium/releases/tag/v <VERSION>`并點擊“編輯標簽”。 輸入發布名稱為`<VERSION>`(例如,`2.0.5`),然后粘貼到更改日志(但不是此版本的changelog標題)。 如果是試用版,請標記為預發布。
1. 在 discuss.appium.io 創建新的帖子來宣布release. 請創建于 "News"類別. 粘貼在changelog和任何可選的評論。 置頂當前帖子并取消置頂上一個release帖子。
1. 開始發布`appium-desktop`。
1. 請告知 @jlipps,以便他可以發布一個鏈接到討論帖子。
本文由 [ZhaoC](https://github.com/ZhaoC) 翻譯,由 [oscarxie](https://github.com/oscarxie) 校驗。
- 關于TesterHome和MTSC
- 關于Appium
- 簡介
- Appium 客戶端
- 入門指南
- 已支持的平臺
- API 文檔
- Appium驅動
- XCUITest (iOS)
- XCUITest Real Devices (iOS)
- UIAutomation (iOS)
- UIAutomation Safari Launcher (iOS)
- UIAutomator (Android)
- UIAutomator2 (Android)
- Espresso (Android)
- Windows
- Mac
- Appium命令
- Status
- Execute Mobile Command
- Session
- Create
- End
- Get Session Capabilities
- Go Back
- Screenshot
- Source
- Timeouts
- Timeouts
- Implicit Wait
- Async Script
- Orientation
- Get Orientation
- Set Orientation
- Geolocation
- Get Geolocation
- Set Geolocation
- Logs
- Get Log Types
- Get Logs
- Events
- Log event
- Get events
- Settings
- Update Settings
- Get Device Settings
- Settings
- Update Settings
- Get Device Settings
- Execute Driver Script
- Device
- Activity
- Start Activity
- Current Activity
- Current Package
- App
- Install App
- Is App Installed
- Launch App
- Background App
- Close App
- Reset App
- Remove App
- Activate App
- Terminate App
- Get App State
- Get App Strings
- End Test Coverage
- Clipboard
- Get Clipboard
- Set Clipboard
- Emulator
- Power AC
- Power Capacity
- Files
- Push File
- Pull File
- Pull Folder
- Interactions
- Shake
- Lock
- Unlock
- Is Locked
- Rotate
- Keys
- Press keycode
- Long press keycode
- Hide Keyboard
- Is Keyboard Shown
- Network
- Toggle Airplane Mode
- Toggle Data
- Toggle WiFi
- Toggle Location Services
- Send SMS
- GSM Call
- GSM Signal
- GSM Voice
- Network Speed
- Performance Data
- Get Performance Data
- Performance Data Types
- Screen Recording
- Start Screen Recording
- Stop Screen Recording
- Simulator
- Perform Touch ID
- Toggle Touch ID Enrollment
- System
- Open Notifications
- System Bars
- System Time
- Display density
- Authentication
- Finger Print
- Element
- Find Element
- Find Elements
- Actions
- Click
- Send Keys
- Clear
- Attributes
- Text
- Name
- Attribute
- Selected
- Enabled
- Displayed
- Location
- Size
- Rect
- CSS Property
- Location in View
- Other
- Submit
- Active Element
- Equals Element
- Context
- Get Context
- Get All Contexts
- Set Context
- Interactions
- Mouse
- Move To
- Click
- Double Click
- Button Down
- Button Up
- Touch
- Single Tap
- Double Tap
- Move
- Touch Down
- Touch Up
- Long Press
- Scroll
- Flick
- Multi Touch Perform
- Touch Perform
- W3C Actions
- Web
- Window
- Set Window
- Close Window
- Get Handle
- Get Handles
- Get Title
- Get Window Size
- Set Window Size
- Get Window Position
- Set Window Position
- Maximize Window
- Navigation
- Go to URL
- Get URL
- Back
- Forward
- Refresh
- Storage
- Get All Cookies
- Set Cookie
- Delete Cookie
- Delete All Cookies
- Frame
- Switch to Frame
- Switch to Parent Frame
- Execute Async
- Execute
- 編寫 & 運行Appium腳本
- Running Tests
- Desired Capabilities
- The --default-capabilities flag
- Finding Elements
- Touch Actions
- CLI Arguments
- Server Security
- Web/Web Views
- Mobile Web Testing
- Automating Hybrid Apps
- Using ios-webkit-debug-proxy
- Using Chromedriver
- Image Comparison
- iOS
- Low-Level Insights on iOS Input Events
- XCUITest Mobile Gestures
- XCUITest Mobile App Management
- iOS Pasteboard Guide
- iOS Predicate Guide
- iOS Touch ID Guide
- iOS Install Certificate
- tvOS support
- Pushing/Pulling files
- Audio Capture
- Android
- Low-Level Insights on Android Input Events
- UiSelector Guide
- Espresso Datamatcher Guide
- Android Code Coverage Guide
- Activities Startup Troubleshooting Guide
- How To Execute Shell Commands On The Remote Device
- Android Device Screen Streaming
- How To Emulate IME Actions Generation
- How To Test Android App Bundle
- Other
- Reset Strategies
- Network Connection Guide
- Using Unicode with Appium
- Troubleshooting
- Tutorial
- Swipe Tutorial
- Screen
- Element
- Partial screen
- Simple
- Multiple scroll views
- Add scroll layout
- Tricks and Tips
- Screen
- Element
- Element search
- Fast
- Slow
- Guide
- 進階概念
- 定位圖像中的元素
- 使用定位元素的插件
- 遷移到 XCUITest
- 在 Appium 中使用 Selenium Grid
- Appium Logs Filtering
- 跨域 iframes
- 使用自定義 WDA 服務器
- 使用不同版本的 Xcode 運行
- The Event Timings API
- 并行測試的設置
- The Settings API
- Memory Collection
- 向Appium項目做貢獻
- 從源代碼運行 Appium
- 開發者概述
- 標準開發命令
- Appium 風格指南
- 如何編寫文檔
- Appium 包結構
- 鳴謝