├── .gitattributes ├── Info.plist ├── LICENSE ├── README.md ├── activity ├── activity.swift ├── appointmentActivity.swift ├── callActivity.swift └── commentActivity.swift ├── address └── address.swift ├── addressBook ├── addressBookList.swift ├── contact.swift ├── customer.swift └── relatedContacts.swift ├── extensions └── XCUIElement+TCEExt.swift ├── home ├── home.swift └── siderBar.swift ├── lead ├── lead.swift ├── leadsFilter.swift └── leadsList.swift ├── login └── login.swift ├── opportunity ├── opportunitiesFilter.swift ├── opportunitiesList.swift └── opportunity.swift ├── product ├── product.swift ├── productFilter.swift └── productList.swift ├── profile └── profile.swift ├── reports ├── outlook.swift ├── overview.swift ├── reportsList.swift └── summary.swift ├── settings └── settings.swift ├── story.swift └── utilis ├── SnapshotHelper.swift ├── XCUIElement+ext.swift └── utils.swift /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto -------------------------------------------------------------------------------- /Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 luis lu 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XCUITest-Library 2 | XCUITest-Library is an example project of page object in swift implementation for XCUITest. You can refer to it and then restruct your iOS test cases. 3 | -------------------------------------------------------------------------------- /activity/activity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // activity.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 09/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class activity: NSObject{ 13 | 14 | let app = utils().app 15 | 16 | //header 17 | var backBtnOnCreateView: XCUIElement { 18 | return app.navigationBars["Add Activity"].buttons.element(boundBy: 0) 19 | } 20 | 21 | var doneBtnOnCreateView: XCUIElement { 22 | return app.buttons["create_confirm_btn"] 23 | } 24 | 25 | var backBtnOnEditView: XCUIElement { 26 | return app.buttons["edit_cancel_btn"] 27 | } 28 | 29 | var doneBtnOnEditView: XCUIElement { 30 | return app.buttons["edit_confirm_btn"] 31 | } 32 | 33 | var currentType: XCUIElement { 34 | return app.tables.cells.containing(.staticText, identifier: "Type").staticTexts.element(boundBy: 1) 35 | 36 | } 37 | 38 | func switchType(_ type:String){ 39 | currentType.tap() 40 | app.pickerWheels.element.adjust(toPickerWheelValue: type) 41 | app.toolbars.buttons.element.tap() 42 | } 43 | 44 | func typeDetails(_ comments: String){ 45 | app.tables.element(boundBy: 0).swipeUp() 46 | let textView = app.tables.cells.containing(.staticText, identifier: "Details").textViews.element 47 | textView.clearAndEnterText(comments, tapType: "forceTap", vector: CGVector.init(dx: 0.9, dy: 0.9)) 48 | utils().handleKeyboard("Done") 49 | } 50 | 51 | func verifyType(_ type: String) { 52 | XCTAssertTrue(type == currentType.label, "Current type \(type) is not correct") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /activity/appointmentActivity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // appointmentActivity.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 09/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class appointmentActivity: activity{ 13 | 14 | var subjectField: XCUIElement { 15 | return app.tables.cells.containing(.staticText, identifier: "Subject").textFields.element 16 | } 17 | 18 | var startDateSelector:XCUIElement{ 19 | return app.tables.cells.containing(.staticText, identifier: "Start Date").staticTexts.element(boundBy: 1) 20 | } 21 | 22 | var endDatesSelector:XCUIElement{ 23 | return app.tables.cells.containing(.staticText, identifier: "End Date").staticTexts.element(boundBy: 1) 24 | } 25 | 26 | var reminderMeSelector:XCUIElement{ 27 | return app.tables.cells.containing(.staticText, identifier: "Remeber me").staticTexts.element(boundBy: 1) 28 | } 29 | 30 | var addAttendeeBtn:XCUIElement{ 31 | return app.tables.buttons["Add Attendee"] 32 | } 33 | 34 | var confirmAddressBtn:XCUIElement{ 35 | return app.buttons["confirm_address"] 36 | } 37 | 38 | var addLocationBtn:XCUIElement{ 39 | return app.tables.buttons["Add Location"] 40 | } 41 | 42 | func typeSubject(_ subjectInfo:String){ 43 | utils().swipeUp() 44 | subjectField.tap() 45 | subjectField.typeText(subjectInfo) 46 | utils().handleKeyboard("Done") 47 | } 48 | 49 | func selectReminderMe(_ reminderRule:String){ 50 | reminderMeSelector.tap() 51 | app.pickerWheels.element.adjust(toPickerWheelValue: reminderRule) 52 | } 53 | 54 | func addAttendee(_ attendeeList:Array){ 55 | addAttendeeBtn.tap() 56 | if (!app.textFields["anwSearchField"].exists) { 57 | addAttendeeBtn.tap() 58 | } 59 | for attendee in attendeeList{ 60 | app.textFields["anwSearchField"].clearAndEnterText(attendee) 61 | app.tables.cells.containing(.staticText, identifier: attendee).element.forceTap() 62 | } 63 | addressBook().createBtn.tap() 64 | snapshot("addAttendeeScreen") 65 | verifyAttendeeDisplays(attendeeList) 66 | } 67 | 68 | func addLocation(_ locationInfo:String){ 69 | app.tables.element.swipeUp() 70 | addLocationBtn.tap() 71 | 72 | if (!app.textFields["Enter the location"].exists) { 73 | addLocationBtn.tap() 74 | } 75 | app.textFields["Enter the location"].tap() 76 | app.textFields["Enter the location"].typeText(locationInfo) 77 | //utils().handleKeyboard("Done") 78 | confirmAddressBtn.tap() 79 | verifyLocationDisplays(locationInfo) 80 | } 81 | 82 | func add(_ subject:String, _ details:String, startDate:String?=nil, endDate:String?=nil, reminderMeRule:String?=nil, attendeeList:Array?=nil, location:String?=nil){ 83 | self.switchType("Appointment") 84 | snapshot("addAppointmentActivityScreen1") 85 | typeSubject(subject) 86 | if startDate != nil { 87 | utils().handleDateTimePicker(startDateSelector, dateTime: startDate!) 88 | } 89 | if endDate != nil { 90 | utils().handleDateTimePicker(endDatesSelector,dateTime: endDate!) 91 | } 92 | if reminderMeRule != nil { 93 | selectReminderMe(reminderMeRule!) 94 | } 95 | if attendeeList != nil { 96 | utils().swipeDown() 97 | addAttendee(attendeeList!) 98 | } 99 | if let realLocation=location { 100 | addLocation(realLocation) 101 | } 102 | self.typeDetails(details) 103 | snapshot("addAppointmentActivityScreen2") 104 | self.doneBtnOnCreateView.tap() 105 | app.navigationBars.element.tap() // workaround to interact with the app again for the alert handler to fire 106 | } 107 | 108 | /** 109 | - parameter attendeeList: attendee list need verify in activity page 110 | */ 111 | func verifyAttendeeDisplays(_ attendeeList:Array){ 112 | for attendee in attendeeList{ 113 | let attendeePartialValue = NSPredicate(format: "label CONTAINS[CD] %@",attendee) 114 | app.tables.staticTexts.matching(attendeePartialValue).element.verifyExists("Can't found expected \(attendee) attendee "); 115 | } 116 | } 117 | 118 | func verifyLocationDisplays(_ location:String){ 119 | let locationPartialValue = NSPredicate(format: "label CONTAINS[CD] %@",location) 120 | app.tables.staticTexts.matching(locationPartialValue).element.verifyExists("Can't found expected \(location) location ") 121 | } 122 | 123 | } 124 | -------------------------------------------------------------------------------- /activity/callActivity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // callActivity.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 09/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class callActivity: activity{ 13 | 14 | var durationField: XCUIElement { 15 | return app.tables.cells.containing(.staticText, identifier: "Duration").textFields.element 16 | } 17 | 18 | var dateSelector: XCUIElement { 19 | return app.tables.cells.containing(.staticText, identifier: "Date").staticTexts.element(boundBy: 1) 20 | } 21 | 22 | func create(_ details:String, dateTime:String?=nil, durationTime:String="15"){ 23 | self.switchType("Call") 24 | self.input(details, dateTime: dateTime, durationTime: durationTime) 25 | self.doneBtnOnCreateView.tap() 26 | } 27 | 28 | func verifyType() { 29 | self.verifyType("Call") 30 | } 31 | 32 | func edit(_ details:String, dateTime:String?=nil, durationTime:String="15") { 33 | self .input(details, dateTime: dateTime, durationTime: durationTime) 34 | self.doneBtnOnEditView.tap() 35 | } 36 | 37 | func input(_ details:String, dateTime:String?=nil, durationTime:String="15") { 38 | if dateTime != nil{ 39 | utils().handleDateTimePicker(dateSelector, dateTime: dateTime!) 40 | } 41 | if durationTime != "15"{ 42 | durationField.clearAndEnterText(durationTime) 43 | } 44 | self.typeDetails(details) 45 | snapshot("addCallActivityScreen") 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /activity/commentActivity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // activity.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 08/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class commentActivity: activity{ 13 | 14 | var date: XCUIElement { 15 | return app.tables.cells.containing(.staticText, identifier: "Date").staticTexts.element(boundBy: 1) 16 | } 17 | 18 | func create(_ details:String, dateTime:String?=nil){ 19 | self.input(details, dateTime: dateTime) 20 | self.doneBtnOnCreateView.tap() 21 | } 22 | 23 | func edit(_ details:String, dateTime:String?=nil){ 24 | self.input(details, dateTime: dateTime) 25 | self.doneBtnOnEditView.tap() 26 | } 27 | 28 | func input(_ details:String, dateTime:String?=nil){ 29 | if dateTime != nil{ 30 | // utils().handleDateTimePicker(date, dateTime: dateTime!) 31 | } 32 | self.typeDetails(details) 33 | snapshot("commentActivityScreen") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /address/address.swift: -------------------------------------------------------------------------------- 1 | // 2 | // address.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class address: NSObject { 13 | let app = utils().app 14 | 15 | var doneBtnOnCreateView : XCUIElement { 16 | return app.navigationBars["Add Address"].buttons.element(boundBy: 1) 17 | } 18 | 19 | var doneBtnOnEditView : XCUIElement { 20 | return app.buttons["edit_confirm_btn"] 21 | } 22 | 23 | var recipient : XCUIElement { 24 | return app.tables.cells.containing(.staticText, identifier: "Recipient").textFields.element 25 | } 26 | 27 | var street1 : XCUIElement { 28 | return app.tables.cells.containing(.staticText, identifier: "Street 1").textFields.element 29 | } 30 | 31 | var street2 : XCUIElement { 32 | return app.tables.cells.containing(.staticText, identifier: "Street 2").textFields.element 33 | } 34 | 35 | var city : XCUIElement { 36 | return app.tables.cells.containing(.staticText, identifier: "City").textFields.element 37 | } 38 | 39 | var state : XCUIElement { 40 | return app.tables.cells.containing(.staticText, identifier: "State/Province/Region").staticTexts.element(boundBy: 2) 41 | } 42 | 43 | var zipCode : XCUIElement { 44 | return app.tables.cells.containing(.staticText, identifier: "Zip Code").textFields.element 45 | } 46 | 47 | var country : XCUIElement { 48 | return app.tables.cells.containing(.staticText, identifier: "Country/Region").staticTexts.element(boundBy: 2) 49 | } 50 | 51 | var cellphone : XCUIElement { 52 | return app.tables.cells.containing(.staticText, identifier: "Cellphone").textFields.element 53 | } 54 | 55 | var telephone : XCUIElement { 56 | return app.tables.cells.containing(.staticText, identifier: "Telephone").textFields.element 57 | } 58 | 59 | var type : XCUIElement { 60 | return app.tables.cells.containing(.staticText, identifier: "Type").textFields.element 61 | } 62 | 63 | func createAddress(recipient: String?=nil, street1:String?=nil, street2:String?=nil, city:String?=nil, state:String?=nil, zipCode:String?=nil, country:String?=nil, cellphone:String?=nil, telephone:String?=nil, type:String?=nil) { 64 | self .inputAddress(recipient: recipient, street1: street1, street2: street2, city: city, state: state, zipCode: zipCode, country: country, cellphone: cellphone, telephone: telephone, type: type) 65 | self.doneBtnOnCreateView.tap() 66 | } 67 | 68 | func editAddress(recipient: String?=nil, street1:String?=nil, street2:String?=nil, city:String?=nil, state:String?=nil, zipCode:String?=nil, country:String?=nil, cellphone:String?=nil, telephone:String?=nil, type:String?=nil) { 69 | self .inputAddress(recipient: recipient, street1: street1, street2: street2, city: city, state: state, zipCode: zipCode, country: country, cellphone: cellphone, telephone: telephone, type: type) 70 | self.doneBtnOnEditView.tap() 71 | } 72 | 73 | func inputAddress(recipient: String?=nil, street1:String?=nil, street2:String?=nil, city:String?=nil, state:String?=nil, zipCode:String?=nil, country:String?=nil, cellphone:String?=nil, telephone:String?=nil, type:String?=nil) { 74 | if (recipient != nil) { 75 | self.recipient.inputText(recipient!) 76 | } 77 | 78 | if (street1 != nil) { 79 | self.street1.inputText(street1!) 80 | } 81 | 82 | if (street2 != nil) { 83 | self.street2.inputText(street2!) 84 | } 85 | 86 | if (city != nil) { 87 | self.city.inputText(city!) 88 | } 89 | 90 | if (country != nil) { 91 | self.country.tap() 92 | app.pickerWheels.element.adjust(toPickerWheelValue: country!) 93 | app.toolbars.buttons.element.tap() 94 | } 95 | 96 | if (state != nil) { 97 | self.state.tap() 98 | app.pickerWheels.element.adjust(toPickerWheelValue: state!) 99 | app.toolbars.buttons.element.tap() 100 | } 101 | 102 | if (zipCode != nil) { 103 | self.zipCode.inputText(zipCode!) 104 | } 105 | 106 | if (cellphone != nil) { 107 | self.cellphone.inputText(cellphone!) 108 | } 109 | 110 | if (telephone != nil) { 111 | self.telephone.inputText(telephone!) 112 | } 113 | 114 | if (type != nil) { 115 | utils().swipeUp() 116 | self.type.inputText(type!) 117 | } 118 | } 119 | 120 | func verifyDisplay (recipient: String?=nil, street1:String?=nil, street2:String?=nil, city:String?=nil, state:String?=nil, zipCode:String?=nil, country:String?=nil, cellphone:String?=nil, telephone:String?=nil, type:String?=nil) { 121 | if (recipient != nil) { 122 | self.recipient.verifyTextValue(value: recipient!) 123 | } 124 | 125 | if (street1 != nil) { 126 | self.street1.verifyTextValue(value: street1!) 127 | } 128 | 129 | if (street2 != nil) { 130 | self.street2.verifyTextValue(value: street2!) 131 | } 132 | 133 | if (city != nil) { 134 | self.city.verifyTextValue(value: city!) 135 | } 136 | 137 | if (state != nil) { 138 | self.state.verifyLabel(label: state!) 139 | } 140 | 141 | if (zipCode != nil) { 142 | self.zipCode.verifyTextValue(value: zipCode!) 143 | } 144 | 145 | if (country != nil) { 146 | self.country.verifyLabel(label: country!) 147 | } 148 | 149 | if (cellphone != nil) { 150 | self.cellphone.verifyTextValue(value: cellphone!) 151 | } 152 | 153 | if (telephone != nil) { 154 | self.telephone.verifyTextValue(value: telephone!) 155 | } 156 | 157 | if (type != nil) { 158 | self.type.verifyTextValue(value: type!) 159 | } 160 | } 161 | } 162 | -------------------------------------------------------------------------------- /addressBook/addressBookList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // addressBookList.swift 3 | // anwstream 4 | // 5 | // on 2/8/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class addressBook : NSObject { 13 | 14 | static let ADDRESS_BOOK_LIST_NAME : String = "Address Book" 15 | 16 | let app = utils().app; 17 | 18 | var leftMenuBtn : XCUIElement { 19 | return app.navigationBars.element.buttons.element(boundBy: 0) 20 | } 21 | 22 | var createBtn : XCUIElement { 23 | return app.navigationBars.matching(identifier: addressBook.ADDRESS_BOOK_LIST_NAME).buttons.element(boundBy: 1) 24 | } 25 | 26 | var createCorporateBtn : XCUIElement { 27 | return self.btnWithText("Corporate") 28 | } 29 | 30 | var createIndividualBtn : XCUIElement { 31 | return self.btnWithText("Individual") 32 | } 33 | 34 | var createContactBtn : XCUIElement { 35 | return self.btnWithText("Contact") 36 | } 37 | 38 | var cancelBtn : XCUIElement { 39 | return self.btnWithText("Cancel") 40 | } 41 | 42 | var searchField : XCUIElement { 43 | return app.searchFields.element 44 | } 45 | 46 | func cellWithText(_ identifier: String) -> XCUIElement{ 47 | return app.tables.cells.staticTexts[identifier] 48 | } 49 | 50 | func cellWithTextField(_ identifier: String) -> XCUIElement{ 51 | return app.tables.cells.textFields[identifier] 52 | } 53 | 54 | func btnWithText(_ text: String) -> XCUIElement { 55 | return app.buttons[text] 56 | } 57 | 58 | func selectCell(_ identifier: String) { 59 | let cell = self.cellWithText(identifier) 60 | cell.tap() 61 | } 62 | 63 | func searchAndGoToDetail(_ identifier:String) { 64 | self.searchField.tap() 65 | self.searchField.typeText(identifier) 66 | utils().handleKeyboard("Search") 67 | self.cellWithText(identifier).tap() 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /addressBook/contact.swift: -------------------------------------------------------------------------------- 1 | // 2 | // contact.swift 3 | // anwstream 4 | // 5 | // on 2/9/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class contact : NSObject { 13 | static let FIRST_NAME_LABEL : String = "First Name" 14 | static let LAST_NAME_LABEL : String = "Last Name" 15 | static let POSITION_LABEL : String = "Position" 16 | static let CELLPHONE_LABEL : String = "Cellphone" 17 | static let OFFICEPHONE_LABEL : String = "Phone" 18 | static let EMAIL_LABEL : String = "Email" 19 | static let STATUS_LABEL : String = "Status" 20 | 21 | let app = utils().app 22 | 23 | var leftMenuBtn : XCUIElement { 24 | return app.navigationBars.element.buttons.element(boundBy: 0) 25 | } 26 | 27 | var rightMenuBtn : XCUIElement { 28 | return app.navigationBars.matching(identifier: "Address Book").buttons.element(boundBy: 1) 29 | } 30 | 31 | var addAddressBtn : XCUIElement { 32 | return app.tables.buttons["Add Address"] 33 | } 34 | 35 | func cell(_ identifier: String, tableIdentifier:String? = nil) -> XCUIElement { 36 | let predicate = NSPredicate(format: "label CONTAINS[CD] %@",identifier) 37 | var table : XCUIElement; 38 | if (tableIdentifier == nil) { 39 | table = app.tables.element 40 | } else { 41 | table = app.tables[tableIdentifier!] 42 | } 43 | return table.staticTexts.matching(predicate).element 44 | } 45 | 46 | func btnWithText(_ text: String) -> XCUIElement{ 47 | return app.buttons[text] 48 | } 49 | 50 | func swipeToAddAddress(){ 51 | utils().swipeUpUntilElementVisible(element: contact().addAddressBtn) 52 | utils().swipeUp() 53 | } 54 | } 55 | 56 | class contactEdit: contact { 57 | var callBtn : XCUIElement { 58 | return self.btnWithText("Call") 59 | } 60 | 61 | var emailBtn : XCUIElement { 62 | return self.btnWithText("Email") 63 | } 64 | 65 | var locateBtn : XCUIElement { 66 | return self.btnWithText("Locate") 67 | } 68 | 69 | var contactInfoNavBtn : XCUIElement { 70 | return app.buttons["basicInfo-editBtn"] 71 | } 72 | 73 | var addActivityBtn : XCUIElement { 74 | return app.tables.buttons["Add Activity"] 75 | } 76 | 77 | var detailsNavBtn : XCUIElement { 78 | return app.otherElements["creationInfo"].buttons.element 79 | } 80 | 81 | var firstName : XCUIElement { 82 | return self.textWithLabel(contact.FIRST_NAME_LABEL) 83 | } 84 | 85 | var status : XCUIElement { 86 | return self.textWithLabel(contact.STATUS_LABEL) 87 | } 88 | 89 | var infoPickerCancelView : XCUIElement { 90 | return app.otherElements["infoPickerCancelView"] 91 | } 92 | 93 | func textWithLabel(_ label:String) -> XCUIElement { 94 | return app.tables.cells.containing(.staticText, identifier: label).staticTexts.element(boundBy: 1) 95 | } 96 | 97 | func verifyActivityDisplay(_ activityText:String) { 98 | let predicate = NSPredicate(format: "label CONTAINS[CD] %@",activityText) 99 | app.tables.staticTexts.matching(predicate).element.verifyExists("Can't found expected \(activityText) contact ") 100 | } 101 | 102 | func tapOnActivity(_ identifier: String) { 103 | app.tables.staticTexts[identifier].tap() 104 | } 105 | 106 | func editContactInformation(firstName:String?=nil, lastName:String?=nil, position:String?=nil, cellPhone:String?=nil, officePhone:String?=nil, email:String?=nil) { 107 | self.contactInfoNavBtn.tap() 108 | 109 | if ((firstName) != nil) { 110 | let field = app.tables.cells.containing(.staticText, identifier: contact.FIRST_NAME_LABEL).textFields.element 111 | field.tap() 112 | field.clearAndEnterText(firstName!) 113 | utils().handleKeyboard("Done") 114 | } 115 | 116 | if ((lastName) != nil) { 117 | let field = app.tables.cells.containing(.staticText, identifier: contact.LAST_NAME_LABEL).textFields.element 118 | field.tap() 119 | field.clearAndEnterText(lastName!) 120 | utils().handleKeyboard("Done") 121 | } 122 | 123 | if ((position) != nil) { 124 | // let field = app.tables.cells.containing(.staticText, identifier: "Last Name").textFields.element 125 | // field.tap() 126 | // field.typeText(lastName!) 127 | // utils().handleKeyboard("Done") 128 | } 129 | 130 | if ((cellPhone) != nil) { 131 | let field = app.tables.cells.containing(.staticText, identifier: contact.CELLPHONE_LABEL).textFields.element 132 | field.tap() 133 | field.clearAndEnterText(cellPhone!) 134 | utils().handleKeyboard("Done") 135 | } 136 | 137 | if ((officePhone) != nil) { 138 | let field = app.tables.cells.containing(.staticText, identifier: contact.OFFICEPHONE_LABEL).textFields.element 139 | field.tap() 140 | field.clearAndEnterText(officePhone!) 141 | utils().handleKeyboard("Done") 142 | } 143 | 144 | if ((email) != nil) { 145 | let field = app.tables.cells.containing(.staticText, identifier: contact.EMAIL_LABEL).textFields.element 146 | field.tap() 147 | field.clearAndEnterText(email!) 148 | utils().handleKeyboard("Done") 149 | } 150 | 151 | //save change 152 | app.buttons.element(boundBy: 1).tap() 153 | } 154 | 155 | func editStatus(_ status: String) { 156 | self.contactInfoNavBtn.tap() 157 | 158 | let statusSwitch = app.tables.cells.containing(.staticText, identifier: contact.STATUS_LABEL).staticTexts.element(boundBy: 1) 159 | statusSwitch.tap() 160 | app.pickerWheels.element.adjust(toPickerWheelValue: status) 161 | app.buttons["edit_confirm_btn"].tap() 162 | 163 | //save change 164 | app.buttons.element(boundBy: 1).tap() 165 | } 166 | 167 | func cellOnInfoPickerView(_ identifier: String) -> XCUIElement { 168 | return self.cell(identifier, tableIdentifier: "infoPickerTable") 169 | } 170 | } 171 | 172 | class contactCreate: contact { 173 | 174 | var lastName : XCUIElement { 175 | return self.textFieldWithLabel("Last Name") 176 | } 177 | 178 | override var rightMenuBtn : XCUIElement { 179 | return app.navigationBars.matching(identifier: "Add Contact").buttons.element(boundBy: 1) 180 | } 181 | 182 | func textFieldWithLabel(_ label:String) -> XCUIElement { 183 | return app.tables.cells.containing(.staticText, identifier: label).textFields.element 184 | } 185 | 186 | func selectCompany(_ identifier: String) { 187 | self.cell("Choose or add company").tap() 188 | addressBook().selectCell(identifier) 189 | } 190 | 191 | } 192 | -------------------------------------------------------------------------------- /addressBook/customer.swift: -------------------------------------------------------------------------------- 1 | // 2 | // corporateCustomer.swift 3 | // anwstream 4 | // 5 | // on 2/9/17. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class customer: NSObject { 13 | static let CORPORATE_NAME = "Corporate Name" 14 | static let OFFICE_PHONE = "Office Phone" 15 | static let EMAIL = "Email" 16 | static let WEBSITE = "Website" 17 | static let STATUS = "Status" 18 | static let FIRST_NAME = "First Name" 19 | static let LAST_NAME = "Last Name" 20 | static let POSITION = "Position" 21 | static let COMPANY = "Company" 22 | static let CELLPHONE = "Cellphone" 23 | 24 | let app = utils().app 25 | 26 | var leftMenuBtn: XCUIElement { 27 | return app.navigationBars.element.buttons.element(boundBy: 0) 28 | } 29 | 30 | var rightMenuBtn: XCUIElement { 31 | return app.navigationBars.element.buttons.element(boundBy: 1) 32 | } 33 | 34 | var addAddressBtn : XCUIElement { 35 | return app.tables.buttons["Add Address"] 36 | } 37 | 38 | var status: XCUIElement { 39 | return app.tables.cells.containing(.staticText, identifier: customer.STATUS).staticTexts.element(boundBy: 1) 40 | } 41 | 42 | func cell(_ identifier: String, tableIdentifier:String? = nil) -> XCUIElement { 43 | let predicate = NSPredicate(format: "label CONTAINS[CD] %@",identifier) 44 | var table : XCUIElement; 45 | if (tableIdentifier == nil) { 46 | table = app.tables.element 47 | } else { 48 | table = app.tables[tableIdentifier!] 49 | } 50 | return table.staticTexts.matching(predicate).element(boundBy: 0) 51 | } 52 | 53 | func textWithLabel(_ label:String) -> XCUIElement { 54 | return app.tables.cells.containing(.staticText, identifier: label).staticTexts.element(boundBy: 1) 55 | } 56 | 57 | func deleteCell(_ identifier:String) { 58 | self.cell(identifier).swipeLeft() 59 | snapshot("deleteCell") 60 | app.tables.cells.containing(.staticText, identifier: identifier).buttons["Delete"].tap() 61 | } 62 | 63 | func textFieldWithLabel(_ label:String) -> XCUIElement { 64 | return app.tables.cells.containing(.staticText, identifier: label).textFields.element 65 | } 66 | 67 | func swipeToActivity(){ 68 | utils().swipeUpUntilElementVisible(element: customerEdit().addActivityBtn) 69 | utils().swipeUp() 70 | } 71 | 72 | func swipeToAddress(){ 73 | utils().swipeUpUntilElementVisible(element: customerEdit().addAddressBtn) 74 | utils().swipeUp() 75 | } 76 | } 77 | 78 | class customerEdit: customer { 79 | 80 | var callBtn : XCUIElement { 81 | return self.btnWithText("Call") 82 | } 83 | 84 | var emailBtn : XCUIElement { 85 | return self.btnWithText("Email") 86 | } 87 | 88 | var locateBtn : XCUIElement { 89 | return self.btnWithText("Locate") 90 | } 91 | 92 | var relatedContactsCell : XCUIElement { 93 | return app.tables.staticTexts["Related Contacts"] 94 | } 95 | 96 | var generalInfoNavBtn : XCUIElement { 97 | return app.buttons["split1-editBtn"] 98 | } 99 | 100 | var contactInfoNavBtn : XCUIElement { 101 | return app.buttons["split2-editBtn"] 102 | } 103 | 104 | var addActivityBtn : XCUIElement { 105 | return app.tables.buttons["Add Activity"] 106 | } 107 | 108 | var detailsNavBtn : XCUIElement { 109 | return app.otherElements["creationInfo"].buttons.element 110 | } 111 | 112 | var infoPickerCancelView : XCUIElement { 113 | return app.otherElements["infoPickerCancelView"] 114 | } 115 | 116 | func mainContactCell(_ identifier:String) -> XCUIElement { 117 | let predicate = NSPredicate(format: "label CONTAINS[CD] %@",identifier) 118 | return app.tables.staticTexts.matching(predicate).element 119 | } 120 | 121 | func btnWithText(_ text: String) -> XCUIElement{ 122 | return app.buttons[text] 123 | } 124 | 125 | func changeMainContactTo(_ identifier:String) { 126 | // self.relatedContactsCell.tap() 127 | // relatedContacts().setMainContact(identifier) 128 | // relatedContacts().leftMenuBtn.tap() 129 | self.rightMenuBtn.tap() 130 | app.buttons["Change Main Contact"].tap() 131 | relatedContacts().contactCell(identifier).tap() 132 | } 133 | 134 | func editCorporateContactInfo(name:String?=nil, officePhone:String?=nil, email:String?=nil, website:String?=nil) { 135 | self.generalInfoNavBtn.tap() 136 | 137 | if ((name) != nil) { 138 | let field = self.textFieldWithLabel(customer.CORPORATE_NAME) 139 | field.inputText(name!) 140 | } 141 | 142 | if ((officePhone) != nil) { 143 | let field = self.textFieldWithLabel(customer.OFFICE_PHONE) 144 | field.inputText(officePhone!) 145 | } 146 | 147 | if ((email) != nil) { 148 | let field = self.textFieldWithLabel(customer.EMAIL) 149 | field.inputText(email!) 150 | } 151 | 152 | if ((website) != nil) { 153 | let field = self.textFieldWithLabel(customer.WEBSITE) 154 | field.inputText(website!) 155 | } 156 | 157 | //save change 158 | app.buttons.element(boundBy: 1).tap() 159 | } 160 | 161 | func editIndividualGeneralInfo(firstName:String?=nil, lastName:String?=nil, position:String?=nil, company:String?=nil) { 162 | self.generalInfoNavBtn.tap() 163 | 164 | if ((firstName) != nil) { 165 | let field = self.textFieldWithLabel(customer.FIRST_NAME) 166 | field.inputText(firstName!) 167 | } 168 | 169 | if ((lastName) != nil) { 170 | let field = self.textFieldWithLabel(customer.LAST_NAME) 171 | field.inputText(lastName!) 172 | } 173 | 174 | if (position != nil) { 175 | 176 | } 177 | 178 | if ((company) != nil) { 179 | let field = self.textFieldWithLabel(customer.COMPANY) 180 | field.inputText(company!) 181 | } 182 | 183 | //save change 184 | app.buttons.element(boundBy: 1).tap() 185 | } 186 | 187 | func editIndividualContactInfo(cellPhone:String?=nil, officePhone:String?=nil, email:String?=nil, website:String?=nil) { 188 | self.contactInfoNavBtn.tap() 189 | 190 | if ((cellPhone) != nil) { 191 | let field = self.textFieldWithLabel(customer.CELLPHONE) 192 | field.inputText(cellPhone!) 193 | } 194 | 195 | if ((officePhone) != nil) { 196 | let field = self.textFieldWithLabel(customer.OFFICE_PHONE) 197 | field.inputText(officePhone!) 198 | } 199 | 200 | if ((email) != nil) { 201 | let field = self.textFieldWithLabel(customer.EMAIL) 202 | field.inputText(email!) 203 | } 204 | 205 | if ((website) != nil) { 206 | let field = self.textFieldWithLabel(customer.WEBSITE) 207 | field.inputText(website!) 208 | } 209 | 210 | //save change 211 | app.buttons.element(boundBy: 1).tap() 212 | } 213 | 214 | func editStatus(_ status: String) { 215 | self.generalInfoNavBtn.tap() 216 | 217 | let statusSwitch = app.tables.cells.containing(.staticText, identifier: customer.STATUS).staticTexts.element(boundBy: 1) 218 | statusSwitch.tap() 219 | app.pickerWheels.element.adjust(toPickerWheelValue: status) 220 | app.buttons["picker_confirm"].tap() 221 | 222 | //save change 223 | app.buttons["edit_confirm_btn"].tap() 224 | } 225 | 226 | func createOpportunity() { 227 | self.rightMenuBtn.tap() 228 | self.btnWithText("Create Opportunity").tap() 229 | } 230 | 231 | func cellOnInfoPickerView(_ identifier: String) -> XCUIElement { 232 | return self.cell(identifier, tableIdentifier: "infoPickerTable") 233 | } 234 | } 235 | 236 | class customerCreate : customer { 237 | var corporateName : XCUIElement { 238 | return self.textFieldWithLabel(customer.CORPORATE_NAME) 239 | } 240 | } 241 | 242 | 243 | -------------------------------------------------------------------------------- /addressBook/relatedContacts.swift: -------------------------------------------------------------------------------- 1 | // 2 | // relatedContacts.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class relatedContacts: NSObject { 13 | let app = utils().app 14 | 15 | var leftMenuBtn : XCUIElement { 16 | return app.navigationBars.element.buttons.element(boundBy: 0) 17 | } 18 | 19 | var rightMenuBtn : XCUIElement { 20 | return app.navigationBars.element.buttons.element(boundBy: 1) 21 | } 22 | 23 | func contactCell(_ identifier: String) -> XCUIElement { 24 | return app.tables.cells.staticTexts[identifier] 25 | } 26 | 27 | func setMainContact(_ identifier:String) { 28 | self.contactCell(identifier).tap() 29 | contactEdit().rightMenuBtn.tap() 30 | contactEdit().btnWithText("Set as Main Contact").tap() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /extensions/XCUIElement+TCEExt.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCUIElement+TCEExt.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | extension XCUIElement { 13 | /** 14 | Removes any current text in the field before typing in the new value 15 | - Parameter text: the text to enter into the field 16 | */ 17 | func clearAndEnterText(_ text: String, tapType: String?=nil, vector:CGVector? = nil) -> Void { 18 | guard let stringValue = self.value as? String else { 19 | XCTFail("Tried to clear and enter text into a non string value") 20 | return 21 | } 22 | if tapType == "forceTap"{ 23 | self.forceTap(vector) 24 | } else { 25 | self.tap() 26 | } 27 | let deleteString = stringValue.characters.map { _ in XCUIKeyboardKeyDelete }.joined(separator: "") 28 | self.typeText(deleteString) 29 | self.typeText(text) 30 | } 31 | 32 | func forceTap(_ vector:CGVector? = nil){ 33 | let coordinate = self.coordinate(withNormalizedOffset: ((vector == nil) ? CGVector(dx: 0, dy: 0) : vector!)) 34 | coordinate.tap() 35 | } 36 | 37 | func smartTap(){ 38 | self.tap(); 39 | if(self.visible()){ 40 | self.tap() 41 | } 42 | } 43 | 44 | func verifyExists(_ message: String = "Can not find related element") { 45 | XCTAssert(self.exists,message) 46 | } 47 | 48 | func verifyNotExists(_ message: String = "Related element still appears") { 49 | XCTAssertTrue(!self.exists, message) 50 | } 51 | 52 | func verifyEnabled(_ message: String = "Element disabled") { 53 | XCTAssert(self.isEnabled, message) 54 | } 55 | 56 | func verifyDisabled(_ message: String = "Element enabled") { 57 | XCTAssert(!self.isEnabled, message) 58 | } 59 | 60 | func verifyLabel(label : String, message: String = "Do not match text") { 61 | XCTAssertTrue(label == self.label, message) 62 | } 63 | 64 | func verifyTextValue(value : String, message: String = "Do not match text") { 65 | XCTAssertTrue(value == self.value as! String) 66 | } 67 | 68 | func inputText(_ text:String) { 69 | self.tap() 70 | self.clearAndEnterText(text) 71 | utils().handleKeyboard("Done") 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /home/home.swift: -------------------------------------------------------------------------------- 1 | // 2 | // home.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 08/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class home: NSObject{ 13 | let app = utils().app 14 | 15 | var searchButton: XCUIElement { 16 | return app.navigationBars.buttons.element(boundBy: 1) 17 | //return app.buttons["search_button"] 18 | } 19 | 20 | var homeTitle: XCUIElement { 21 | return app.navigationBars["home_nav_bar"] 22 | } 23 | 24 | func waitForViewDisplays(_ xcTestCase:XCTestCase) { 25 | utils().waitForElementToAppear(xcTestCase, homeTitle, timeout: 10) 26 | snapshot("homeScreen") 27 | } 28 | 29 | func verifyCardExisting(_ label: String) { 30 | let card = app.staticTexts[label]; 31 | XCTAssertNotNil(card); 32 | } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /home/siderBar.swift: -------------------------------------------------------------------------------- 1 | // 2 | // siderBar.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 10/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | 13 | class siderBar: NSObject{ 14 | 15 | let app = utils().app 16 | 17 | var homeMenuBtn: XCUIElement { 18 | return app.navigationBars.buttons.element(boundBy: 0) 19 | } 20 | 21 | var homeMenuBtnInHome: XCUIElement { 22 | return app.buttons["home_menu"] 23 | } 24 | 25 | /** 26 | - parameter boName: Home, Contacts, Products, Opportunities, Activities, Pipeline Overview, Sales Outlook, Settings, Sync, Logout 27 | */ 28 | func navigateToBO(_ boName: String) { 29 | homeMenuBtn.forceTap() 30 | snapshot("siderBarMenuScreen") 31 | app.tables.staticTexts[boName].tap() 32 | } 33 | 34 | func logout(){ 35 | navigateToBO("Settings") 36 | settings().navigate("My Profile") 37 | settings().btnWithText("Log Out") 38 | app.tap() // workaround to interact with the app again for the alter handler to fire 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /lead/lead.swift: -------------------------------------------------------------------------------- 1 | // 2 | // lead.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class lead: NSObject { 13 | static let STATUS = "Status" 14 | static let DESCRIPTION = "Description" 15 | static let SOURCE = "Source" 16 | static let QUALIFICATION = "Qualification" 17 | static let REMARKS = "Remarks" 18 | static let PHONE = "Phone" 19 | static let CELLPHONE = "Cellphone" 20 | static let EMAIL = "Email" 21 | 22 | let app = utils().app 23 | 24 | var leftMenuBtn: XCUIElement { 25 | return app.navigationBars.element.buttons.element(boundBy: 0) 26 | } 27 | 28 | var rightMenuBtn: XCUIElement { 29 | return app.navigationBars.element.buttons.element(boundBy: 1) 30 | } 31 | 32 | var contactEmail: XCUIElement { 33 | return self.buttonWithText("Email") 34 | } 35 | 36 | var contactCall: XCUIElement { 37 | return self.buttonWithText("Call") 38 | } 39 | 40 | var contactLocate: XCUIElement { 41 | return self.buttonWithText("Locate") 42 | } 43 | 44 | var addActivityBtn: XCUIElement { 45 | return self.buttonWithText("Add Activity") 46 | } 47 | 48 | var addAddressBtn : XCUIElement { 49 | return self.buttonWithText("Add Address") 50 | } 51 | 52 | var generalInfoNavBtn : XCUIElement { 53 | return self.buttonWithText("split1-editBtn") 54 | } 55 | 56 | var contactInfoNavBtn : XCUIElement { 57 | return self.buttonWithText("split2-editBtn") 58 | } 59 | 60 | var infoPickerCancelView : XCUIElement { 61 | return app.otherElements["infoPickerCancelView"] 62 | } 63 | 64 | var status: XCUIElement { 65 | return self.cell(lead.STATUS).staticTexts.element(boundBy: 2) 66 | } 67 | 68 | var descriptionField: XCUIElement { 69 | return self.textFieldWithLabel(lead.DESCRIPTION) 70 | } 71 | 72 | func textFieldWithLabel(_ identifier: String, index: UInt = 0) -> XCUIElement { 73 | return self.cell(identifier).textFields.element(boundBy: index) 74 | } 75 | 76 | func buttonWithText(_ identifier: String) -> XCUIElement { 77 | return app.buttons[identifier] 78 | } 79 | 80 | func swipeToActivity(){ 81 | utils().swipeUpUntilElementVisible(element: lead().addActivityBtn) 82 | utils().swipeUp() 83 | } 84 | 85 | func swipeToAddress(){ 86 | utils().swipeUpUntilElementVisible(element: lead().addAddressBtn) 87 | utils().swipeUp() 88 | } 89 | 90 | func cell(_ identifier: String, tableIdentifier:String? = nil) -> XCUIElement { 91 | let predicate = NSPredicate(format: "label CONTAINS[CD] %@",identifier) 92 | var table : XCUIElement; 93 | if (tableIdentifier == nil) { 94 | table = app.tables.element 95 | } else { 96 | table = app.tables[tableIdentifier!] 97 | } 98 | return table.cells.containing(predicate).element(boundBy: 0) 99 | } 100 | 101 | func deleteCell(_ identifier:String) { 102 | self.cell(identifier).swipeLeft() 103 | snapshot("deleteCell") 104 | self.cell(identifier).buttons["Delete"].tap() 105 | } 106 | 107 | func cellOnInfoPickerView(_ identifier: String) -> XCUIElement { 108 | return self.cell(identifier, tableIdentifier: "infoPickerTable") 109 | } 110 | 111 | func changeStatus(_ status: String) { 112 | self.status.tap() 113 | utils().handleSelectorPicker(status) 114 | } 115 | 116 | func textWithLabel(_ label:String) -> XCUIElement { 117 | return self.cell(label).staticTexts.element(boundBy: 1) 118 | } 119 | 120 | func editGeneralInfo(source: String?=nil, qualification: String?=nil, remarks: String?=nil 121 | ){ 122 | self.generalInfoNavBtn.tap() 123 | if (source != nil) { 124 | self.cell(lead.STATUS).tap() 125 | utils().handleSelectorPicker(source!) 126 | } 127 | 128 | if (qualification != nil) { 129 | self.cell(lead.QUALIFICATION).tap() 130 | utils().handleSelectorPicker(qualification!) 131 | } 132 | 133 | if (remarks != nil) { 134 | let remarkTextView = self.cell(lead.REMARKS).textViews.element(boundBy: 0) 135 | remarkTextView.clearAndEnterText(remarks!, tapType: "forceTap", vector: CGVector.init(dx: 0.9, dy: 0.9)) 136 | utils().handleKeyboard("Done") 137 | } 138 | 139 | //save change 140 | app.buttons.element(boundBy: 1).tap() 141 | } 142 | 143 | func editContactInfo(phone: String? = nil, cellPhone: String? = nil, email: String? = nil) { 144 | self.contactInfoNavBtn.tap() 145 | if (phone != nil) { 146 | let field = self.cell(lead.PHONE).textFields.element 147 | field.inputText(phone!) 148 | } 149 | 150 | if (cellPhone != nil) { 151 | let field = self.cell(lead.CELLPHONE).textFields.element 152 | field.inputText(cellPhone!) 153 | } 154 | 155 | if (email != nil) { 156 | let field = self.cell(lead.EMAIL).textFields.element 157 | field.inputText(email!) 158 | } 159 | 160 | //save change 161 | app.buttons.element(boundBy: 1).tap() 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /lead/leadsFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // leadsFilter.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class leadsFilter : NSObject { 13 | let app = utils().app 14 | 15 | var filterBtn : XCUIElement { 16 | return app.buttons["Filter"] 17 | } 18 | 19 | var sortTabBtn : XCUIElement { 20 | return app.buttons["Sort"] 21 | } 22 | 23 | var filterTable : XCUIElement { 24 | return app.tables["filterTable"] 25 | } 26 | 27 | var sortTable : XCUIElement { 28 | return app.tables["sortTable"] 29 | } 30 | 31 | var resetBtn : XCUIElement { 32 | return app.buttons["Reset"] 33 | } 34 | 35 | var applyBtn : XCUIElement { 36 | return app.buttons["Apply"] 37 | } 38 | 39 | func filterValue(_ categoryName: String, value: String) -> XCUIElement { 40 | return self.filterTable.cells.containing(.staticText, identifier: categoryName).staticTexts[value] 41 | } 42 | 43 | func applyFilter(owner: String?=nil, statuses: NSArray?=nil, qualification: String?=nil) { 44 | if (owner != nil) { 45 | filterValue("Owner", value: owner!).tap() 46 | } 47 | 48 | if (statuses != nil) { 49 | for statusValue in statuses! { 50 | filterValue("Status", value: statusValue as! String).tap() 51 | } 52 | } 53 | 54 | if (qualification != nil) { 55 | filterValue("Qualification", value: qualification!).tap() 56 | } 57 | 58 | self.applyBtn.tap() 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /lead/leadsList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // leadsList.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class leadsList : NSObject { 13 | let app = utils().app 14 | static let LIST_TITLE = "Leads" 15 | 16 | var leftMenuBtn : XCUIElement { 17 | return app.navigationBars.element.buttons.element(boundBy: 0) 18 | } 19 | 20 | var openQuickFilterBtn: XCUIElement { 21 | return app.buttons["Open"] 22 | } 23 | 24 | var newQuickFilterBtn: XCUIElement { 25 | return app.buttons["New"] 26 | } 27 | 28 | var allQuickFilterBtn : XCUIElement { 29 | return app.buttons["All"] 30 | } 31 | 32 | var filterBtn : XCUIElement { 33 | return app.navigationBars[leadsList.LIST_TITLE].buttons["filterBtn"]; 34 | } 35 | 36 | var createBtn : XCUIElement { 37 | return app.navigationBars[leadsList.LIST_TITLE].buttons["createBtn"]; 38 | } 39 | 40 | var searchField : XCUIElement { 41 | return app.searchFields.element 42 | } 43 | 44 | func cellWithText(_ identifier: String) -> XCUIElement{ 45 | return app.tables.cells.staticTexts[identifier] 46 | } 47 | 48 | func searchAndGoToDetail(_ identifier:String) { 49 | self.searchField.tap() 50 | self.searchField.typeText(identifier) 51 | utils().handleKeyboard("Search") 52 | self.cellWithText(identifier).tap() 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /login/login.swift: -------------------------------------------------------------------------------- 1 | // 2 | // login.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 07/11/2016. 6 | // 7 | // 8 | 9 | 10 | import Foundation 11 | import XCTest 12 | 13 | class login: NSObject{ 14 | let app = utils().app 15 | 16 | var userNameField: XCUIElement { 17 | //return app.otherElements.matching(identifier: "user_email").children(matching: .textField).element 18 | return app.textFields.element 19 | } 20 | 21 | var passwordField: XCUIElement { 22 | //return app.otherElements.matching(identifier: "user_password").children(matching: .secureTextField).element 23 | return app.secureTextFields.element 24 | } 25 | 26 | var loginButton: XCUIElement { 27 | return app.buttons["Login"] 28 | } 29 | 30 | var switchServerLink: XCUIElement { 31 | return app.buttons["switch environment"] 32 | } 33 | 34 | func typeUserName(_ userName: String) { 35 | userNameField.clearAndEnterText(userName) 36 | } 37 | 38 | func typePassword(_ password: String) { 39 | passwordField.clearAndEnterText(password) 40 | } 41 | 42 | func switchServer(_ serverAddress: String){ 43 | switchServerLink.tap() 44 | app.cells.staticTexts[serverAddress].tap() 45 | } 46 | 47 | func submitLogin(){ 48 | loginButton.tap() 49 | } 50 | 51 | func normalLogin(_ serverAddress: String, _ userName: String?=nil, _ password: String?=nil){ 52 | switchServer(serverAddress) 53 | snapshot("loginScreen") 54 | if serverAddress != "Test"{ 55 | typeUserName(userName!) 56 | typePassword(password!) 57 | } 58 | submitLogin() 59 | } 60 | 61 | func waitForViewDisplays(_ xcTestCase:XCTestCase){ 62 | utils().waitForElementToAppear(xcTestCase,userNameField) 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /opportunity/opportunitiesFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // opportunitiesFilter.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 05/12/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class opportunitiesFilter: NSObject{ 13 | let app = utils().app 14 | 15 | func selectStages(_ stagesList:Array){ 16 | //expand stags section if needed 17 | // var btn = app.tables.cells.containing(.staticText, identifier: "Stage").buttons.element(boundBy: 0).tap() 18 | for stage in stagesList{ 19 | app.tables.cells.containing(.staticText, identifier: "Stage").staticTexts[stage].tap() 20 | } 21 | } 22 | 23 | // func selectStatus(_ status:String){ 24 | // app.tables.cells.staticTexts[status].tap() 25 | // } 26 | // 27 | func selectCustomer(_ customer:String){ 28 | app.tables.cells.containing(.staticText, identifier: "Customer").staticTexts[customer].tap() 29 | } 30 | 31 | func selectPotentialAmountRange(_ minMaxPotentialAmount:Array){ 32 | app.tables.cells.containing(.staticText, identifier: "Potential Amount").textFields.element(boundBy: 0).tap() 33 | app.tables.cells.containing(.staticText, identifier: "Potential Amount").textFields.element(boundBy: 0).typeText(minMaxPotentialAmount[0]) 34 | app.tables.cells.containing(.staticText, identifier: "Potential Amount").textFields.element(boundBy: 1).tap() 35 | app.tables.cells.containing(.staticText, identifier: "Potential Amount").textFields.element(boundBy: 1).typeText(minMaxPotentialAmount[1]) 36 | utils().handleKeyboard("Done") 37 | } 38 | 39 | func clickResetBtn(){ 40 | app.buttons["resetBtn"].tap() 41 | } 42 | 43 | func clickApplyBtn(){ 44 | app.buttons["applyBtn"].tap() 45 | } 46 | 47 | func apply(_ stageList:Array?=nil,_ customer:String?=nil,_ minMaxPotentialAmount:Array?=nil ) { 48 | if stageList != nil { 49 | selectStages(stageList!) 50 | } 51 | // if status != nil { 52 | // selectStatus(status!) 53 | // } 54 | if customer != nil { 55 | selectCustomer(customer!) 56 | } 57 | if minMaxPotentialAmount != nil { 58 | selectPotentialAmountRange(minMaxPotentialAmount!) 59 | } 60 | clickApplyBtn() 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /opportunity/opportunitiesList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // opportunitiesList.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 08/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class opportunitiesList: NSObject{ 13 | let app = utils().app 14 | 15 | var createOppBtn: XCUIElement { 16 | //return app.navigationBars["Opportunities"].buttons.element(boundBy: 1) 17 | return app.navigationBars["Opportunities"].buttons["opportunityCreateBtn"] 18 | } 19 | 20 | var oppFilterBtn: XCUIElement { 21 | //return app.navigationBars["Opportunities"].buttons.element(boundBy: 1) 22 | return app.navigationBars["Opportunities"].buttons["opportunityFilterBtn"] 23 | } 24 | 25 | var opportunitiesTitle: XCUIElement { 26 | return app.staticTexts["Opportunities"] 27 | } 28 | 29 | 30 | func clickCreateOppBtn(){ 31 | createOppBtn.tap() 32 | } 33 | 34 | func clickOppFilterBtn(){ 35 | oppFilterBtn.tap() 36 | } 37 | 38 | /** 39 | - parameter timeOption: Week, Month, All 40 | */ 41 | func switchTimeInterval(_ timeOption:String){ 42 | app.buttons[timeOption].tap() 43 | } 44 | 45 | func waitForViewDisplays(_ xcTestCase:XCTestCase) { 46 | utils().waitForElementToAppear(xcTestCase, opportunitiesTitle, timeout: 10) 47 | snapshot("opportunitiesListScreen") 48 | } 49 | 50 | /** 51 | - parameter identifier: partial matching any value displays in opportunity card 52 | */ 53 | func goToDetailedView(_ identifier: String){ 54 | let oppPartialValue = NSPredicate(format: "label CONTAINS[CD] %@",identifier) 55 | app.tables.cells.containing(.staticText, identifier: "Stage updated today").staticTexts.matching(oppPartialValue).element.tap() 56 | snapshot("opportunityDetailsScreen") 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /opportunity/opportunity.swift: -------------------------------------------------------------------------------- 1 | // 2 | // opportunitiesDetails.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 08/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class opportunity: NSObject{ 13 | let app = utils().app 14 | 15 | var leftMenuBtn: XCUIElement { 16 | return app.navigationBars.element.buttons.element(boundBy: 0) 17 | } 18 | 19 | var rightMenuBtn: XCUIElement { 20 | return app.navigationBars.element.buttons.element(boundBy: 1) 21 | } 22 | 23 | var contactEmail: XCUIElement { 24 | return app.buttons["Email"] 25 | } 26 | var contactCall: XCUIElement { 27 | return app.buttons["Call"] 28 | } 29 | var contactLocate: XCUIElement { 30 | return app.buttons["Locate"] 31 | } 32 | 33 | var addActivityBtn: XCUIElement { 34 | return app.tables.buttons["Add Activity"] 35 | } 36 | 37 | var addProductBtn: XCUIElement { 38 | return app.tables.buttons["Add Product"] 39 | } 40 | var status: XCUIElement { 41 | return app.tables.cells.containing(.staticText, identifier: "Status").staticTexts.element(boundBy: 2) 42 | } 43 | 44 | var stage: XCUIElement { 45 | return app.tables.cells.containing(.staticText, identifier: "Stage").staticTexts.element(boundBy: 2) 46 | } 47 | 48 | var oppInformationNavBtn: XCUIElement { 49 | return app.otherElements.containing(.staticText, identifier: "Basic Information").children(matching: .button).element 50 | } 51 | 52 | var infoPickerCancelView : XCUIElement { 53 | return app.otherElements["infoPickerCancelView"] 54 | } 55 | 56 | func changeStage(_ stage:String){ 57 | self.stage.tap() 58 | if (!app.tables.staticTexts.matching(identifier: stage).element.exists) { 59 | self.stage.tap() 60 | } 61 | app.tables.staticTexts.matching(identifier: stage).element(boundBy: 0).tap() 62 | app.buttons.element(boundBy: 1).tap() 63 | } 64 | 65 | func changeStatus(_ status:String, reason:String){ 66 | self.status.tap() 67 | if (!app.tables.staticTexts.matching(identifier: status).element.exists) { 68 | self.status.tap() 69 | } 70 | app.tables.staticTexts.matching(identifier: status).element(boundBy: 0).tap() 71 | app.buttons.element(boundBy: 1).tap() 72 | app.tables.staticTexts.matching(identifier: reason).element(boundBy: 0).tap() 73 | app.buttons.element(boundBy: 1).tap() 74 | } 75 | 76 | func editInformation(_ potentialAmount:String?=nil, startDate:String?=nil, closingPercentage:String?=nil){ 77 | self.oppInformationNavBtn.tap() 78 | if startDate != nil { 79 | utils().handleDatePicker(app.tables.cells.containing(.staticText, identifier: "Start Date").staticTexts.element(boundBy: 1) , date: startDate!) 80 | } 81 | if potentialAmount != nil { 82 | app.tables.cells.containing(.staticText, identifier: "Potential Amount").textFields.element.tap() 83 | app.tables.cells.containing(.staticText, identifier: "Potential Amount").textFields.element.typeText(potentialAmount!) 84 | utils().handleKeyboard("Done") 85 | } 86 | 87 | if closingPercentage != nil { 88 | app.tables.cells.containing(.staticText, identifier: "Closing Percentage").textFields.element.tap() 89 | app.tables.cells.containing(.staticText, identifier: "Closing Percentage").textFields.element.typeText(closingPercentage!) 90 | utils().handleKeyboard("Done") 91 | } 92 | app.buttons.element(boundBy: 1).tap() 93 | } 94 | 95 | 96 | func delActivity(_ activityList:Array){ 97 | opportunity().scrollToCreateActivity() 98 | for oneActivity in activityList { 99 | let activity = app.tables.cells.staticTexts[oneActivity] 100 | activity.swipeLeft() 101 | snapshot("deleteActivityScreen1") 102 | // let start = activity.coordinate(withNormalizedOffset:CGVector(dx: 0, dy: 0)) 103 | // let finish = activity.coordinate(withNormalizedOffset:CGVector(dx: -60, dy: 0)) 104 | // start.press(forDuration: 0, thenDragTo: finish) 105 | app.tables.cells.containing(.staticText, identifier: oneActivity).buttons["Delete"].tap() 106 | } 107 | } 108 | 109 | func delProduct(_ productList:Array){ 110 | for oneProduct in productList { 111 | let product = app.tables.cells.staticTexts[oneProduct] 112 | product.swipeLeft() 113 | app.tables.cells.containing(.staticText, identifier: oneProduct).buttons["Delete"].tap() 114 | } 115 | } 116 | 117 | 118 | 119 | func addProduct(_ productName:String, unitPrice:String?=nil, quantity:String?=nil, discount:String?=nil){ 120 | addProductBtn.tap() 121 | //app.searchFields["Search"].forceTap() 122 | //app.searchFields["Search"].typeText(productName) 123 | //utils().handleKeyboard("Search") 124 | app.tables.cells.staticTexts[productName].forceTap() 125 | // 126 | // if unitPrice != nil { 127 | // app.textFields["unitPriceField"].clearAndEnterText(unitPrice!, tapType: "forceTap") 128 | // utils().handleKeyboard("Done") 129 | // } 130 | // 131 | // if quantity != nil { 132 | // app.textFields["quantityField"].forceTap() 133 | // app.textFields["quantityField"].clearAndEnterText(quantity!) 134 | // utils().handleKeyboard("Done") 135 | // } 136 | // 137 | // if discount != nil { 138 | // app.textFields["discountField"].forceTap() 139 | // app.textFields["discountField"].clearAndEnterText(discount!) 140 | // utils().handleKeyboard("Done") 141 | // } 142 | // 143 | // let expectedTotal:String = app.textFields["unitPriceField"].value as! String 144 | // XCTAssertTrue(expectedTotal == app.staticTexts["totalMoney"].label, "Total money \(status) is not correct") 145 | 146 | app.buttons["Add to Opportunity"].tap() 147 | app.navigationBars.buttons.element(boundBy: 0).tap() 148 | app.navigationBars.buttons.element(boundBy: 0).tap() 149 | () 150 | } 151 | 152 | 153 | 154 | /** 155 | - parameter SKUsArrayList: format sku name + total as one array record in a multidimensional arrays. 156 | e.g [["abc","¥100"],["ddd","¥200"]] 157 | */ 158 | func verifySKUsDisplay(_ SKUsArrayList:Array>){ 159 | for sku in SKUsArrayList { 160 | for item in sku { 161 | app.tables.cells.staticTexts[item].verifyExists() 162 | } 163 | } 164 | } 165 | 166 | func verifySKUsDisapper(_ SKUList:Array){ 167 | for sku in SKUList{ 168 | app.tables.staticTexts[sku].verifyNotExists("SKU \(sku) should not exists ") 169 | } 170 | 171 | } 172 | 173 | func verifySKUTotal(_ total:String){ 174 | app.tables.cells.containing(.staticText, identifier: "Total").staticTexts[total].verifyExists("Total \(total) money is not correct ") 175 | } 176 | 177 | /** 178 | - parameter identifier: partial matching any value displays in opportunity detailed view 179 | */ 180 | func verifyActivityDisplays(_ activityText:String){ 181 | let activityPartialValue = NSPredicate(format: "label CONTAINS[CD] %@",activityText) 182 | app.tables.staticTexts.matching(activityPartialValue).element.verifyExists("Can't found expected \(activityText) opportunity ") 183 | } 184 | 185 | func verifyActivityDisappers(_ activityText:String){ 186 | let activityPartialValue = NSPredicate(format: "label CONTAINS[CD] %@",activityText) 187 | app.tables.staticTexts.matching(activityPartialValue).element.verifyNotExists("Activity \(activityText) should not exists ") 188 | } 189 | 190 | 191 | func verifyWeightAmount(_ weightAmount:String){ 192 | app.tables.cells.containing(.staticText, identifier: "Weighted Amount").staticTexts[weightAmount].verifyExists("WeightAmount \(weightAmount) is not correct") 193 | } 194 | 195 | 196 | func verifyStatus(_ status:String){ 197 | XCTAssertTrue(status==self.status.label, "Current status \(status) is not correct") 198 | } 199 | 200 | func verifyStage(_ stage:String){ 201 | XCTAssertTrue(stage==self.stage.label, "Current stage \(stage) is not correct") 202 | 203 | } 204 | 205 | private func cellOnInfoPickerView(_ identifier: String) -> XCUIElement { 206 | return self.cell(identifier, tableIdentifier: "infoPickerTable") 207 | } 208 | 209 | private func cell(_ identifier: String, tableIdentifier:String? = nil) -> XCUIElement { 210 | let predicate = NSPredicate(format: "label CONTAINS[CD] %@",identifier) 211 | var table : XCUIElement; 212 | if (tableIdentifier == nil) { 213 | table = app.tables.element 214 | } else { 215 | table = app.tables[tableIdentifier!] 216 | } 217 | return table.staticTexts.matching(predicate).element 218 | } 219 | 220 | func verifyContactCall(_ callList:Array?=nil){ 221 | if self.contactCall.isEnabled == true && callList != nil { 222 | self.contactCall.tap() 223 | for call in callList!{ 224 | self.cellOnInfoPickerView(call).verifyExists("Call \(call) doesn't display") 225 | } 226 | } 227 | self.infoPickerCancelView.tap() 228 | } 229 | 230 | func verifyContactEmail(_ email:String?=nil){ 231 | if self.contactEmail.isEnabled == true && email != nil { 232 | self.contactEmail.tap() 233 | self.cellOnInfoPickerView(email!).verifyExists("Email \(email) doesn't display") 234 | } 235 | self.infoPickerCancelView.tap() 236 | } 237 | 238 | func verifyContactLocate(_ locate:String?=nil){ 239 | if self.contactLocate.isEnabled == true && locate != nil { 240 | self.contactLocate.tap() 241 | self.cellOnInfoPickerView(locate!).verifyExists("Locate \(locate) doesn't display") 242 | } 243 | self.infoPickerCancelView.tap() 244 | } 245 | 246 | func scrollToCreateActivity(){ 247 | utils().swipeUpUntilElementVisible(element: opportunity().addActivityBtn) 248 | utils().swipeUp() 249 | } 250 | 251 | 252 | } 253 | -------------------------------------------------------------------------------- /product/product.swift: -------------------------------------------------------------------------------- 1 | // 2 | // product.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class product : NSObject { 13 | 14 | let app = utils().app; 15 | 16 | func waitForViewDisplays(_ xcTestCase:XCTestCase, _ label: String) { 17 | let labelControl = app.staticTexts[label]; 18 | utils().waitForElementToAppear(xcTestCase, labelControl, timeout: 10); 19 | } 20 | 21 | /** 22 | * verify cell value, layout structure should like below 23 | * [Cell] 24 | * [StaticText] - cellName 25 | * [StaticText] - value 26 | */ 27 | func verifyCellValue(_ cellName:String, _ value: String) { 28 | app.tables.cells.containing(.staticText, identifier: cellName).staticTexts[value].verifyExists("\(cellName) value \(value) is not correct"); 29 | } 30 | 31 | } 32 | 33 | -------------------------------------------------------------------------------- /product/productFilter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // productFilter.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class productFilter: NSObject{ 13 | let app = utils().app; 14 | 15 | func clickResetBtn(){ 16 | app.buttons["resetBtn"].tap() 17 | } 18 | 19 | func clickApplyBtn(){ 20 | app.buttons["applyBtn"].tap() 21 | } 22 | 23 | func apply(_ category:String?=nil, _ brand:String?=nil, _ priceRange:Array?=nil) { 24 | if category != nil { 25 | selectCategory(category!); 26 | } 27 | if brand != nil { 28 | selectBrand(brand!); 29 | } 30 | if priceRange != nil { 31 | setPriceRange(priceRange!); 32 | } 33 | clickApplyBtn(); 34 | } 35 | 36 | func selectCategory(_ category:String) { 37 | app.tables.cells.containing(.staticText, identifier: "Category").staticTexts[category].tap(); 38 | } 39 | 40 | func selectBrand(_ brand:String) { 41 | app.tables.cells.containing(.staticText, identifier: "Brand").staticTexts[brand].tap(); 42 | } 43 | 44 | func setPriceRange(_ priceRange:Array){ 45 | app.tables.cells.containing(.staticText, identifier: "Price Range").textFields.element(boundBy: 0).tap(); 46 | app.tables.cells.containing(.staticText, identifier: "Price Range").textFields.element(boundBy: 0).typeText(priceRange[0]); 47 | app.tables.cells.containing(.staticText, identifier: "Price Range").textFields.element(boundBy: 1).tap(); 48 | app.tables.cells.containing(.staticText, identifier: "Price Range").textFields.element(boundBy: 1).typeText(priceRange[1]); 49 | utils().handleKeyboard("Done"); 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /product/productList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // productList 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class productList : NSObject { 13 | 14 | let app = utils().app; 15 | 16 | var leftMenuBtn : XCUIElement { 17 | return app.navigationBars.element.buttons.element(boundBy: 0) 18 | } 19 | 20 | var filterBtn: XCUIElement { 21 | return app.navigationBars["Products"].buttons["productFilterBtn"]; 22 | } 23 | 24 | func clickFilterBtn(){ 25 | filterBtn.tap(); 26 | } 27 | 28 | func findProductCell(_ identifier: String) -> XCUIElementQuery { 29 | return app.tables.cells.containing(.staticText, identifier: identifier); 30 | } 31 | 32 | func goToDetailedView(_ name: String) { 33 | app.staticTexts[name].forceTap(); 34 | } 35 | 36 | func verifyProductExisting(_ identifier:String, _ isExisting:Bool) { 37 | let productCell = productList().findProductCell(identifier); 38 | if(isExisting == true){ 39 | XCTAssertNotEqual(productCell.count, 0); 40 | }else{ 41 | XCTAssertEqual(productCell.count, 0); 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /profile/profile.swift: -------------------------------------------------------------------------------- 1 | // 2 | // profile.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class profile: NSObject{ 13 | 14 | let app = utils().app 15 | 16 | var editBtn: XCUIElement { 17 | return app.navigationBars.buttons["profile_edit"]; 18 | } 19 | var saveBtn: XCUIElement { 20 | return app.buttons["edit_confirm_btn"]; 21 | } 22 | 23 | var backBtn: XCUIElement { 24 | return app.navigationBars.element.buttons.element(boundBy: 0) 25 | } 26 | 27 | func textWithLabel(_ label:String) -> XCUIElement { 28 | return app.tables.cells.containing(.staticText, identifier: label).staticTexts.element(boundBy: 1) 29 | } 30 | 31 | func textFieldWithLabel(_ label:String) -> XCUIElement { 32 | return app.tables.cells.containing(.staticText, identifier: label).textFields.element 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /reports/outlook.swift: -------------------------------------------------------------------------------- 1 | // 2 | // outlook.swift 3 | // anwstream 4 | // 5 | // on 2017/8/2. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class outlook : NSObject { 13 | 14 | let app = utils().app 15 | 16 | static let OPPORTUNITIES_OUTLOOK_TITLE :String = "Opportunities Outlook" 17 | 18 | func pullDownMenu(_ itemName: String){ 19 | app.buttons[itemName].tap() 20 | } 21 | 22 | func tapRow(_ text: String){ 23 | app.buttons[text].tap() 24 | } 25 | 26 | func setFilter(_ itemName: String, _ text: String){ 27 | self.pullDownMenu(itemName) 28 | self.tapRow(text) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /reports/overview.swift: -------------------------------------------------------------------------------- 1 | // 2 | // overview.swift 3 | // anwstream 4 | // 5 | // on 2017/8/2. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class overview : NSObject { 13 | 14 | let app = utils().app 15 | 16 | static let PIPELINE_OVERVIEW_TITLE :String = "Pipeline Overview" 17 | 18 | func pullDownMenu(_ itemName: String){ 19 | app.buttons[itemName].tap() 20 | } 21 | 22 | func tapRow(_ text: String){ 23 | app.buttons[text].tap() 24 | } 25 | 26 | func setFilter(_ itemName: String, _ text: String){ 27 | self.pullDownMenu(itemName) 28 | self.tapRow(text) 29 | } 30 | 31 | } 32 | -------------------------------------------------------------------------------- /reports/reportsList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // reportsList.swift 3 | // anwstream 4 | // 5 | // on 2017/8/1. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class reportsList : NSObject { 13 | 14 | let app = utils().app 15 | 16 | static let REPORTS_LIST_TITLE :String = "Reports" 17 | 18 | var leftMenuBtn : XCUIElement { 19 | return app.navigationBars.element.buttons.element(boundBy: 0) 20 | } 21 | 22 | func navigate(_ itemName: String){ 23 | app.tables.cells.containing(.staticText, identifier:itemName).element.tap() 24 | } 25 | 26 | var backBtn: XCUIElement { 27 | return app.navigationBars.element.buttons.element(boundBy: 0) 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /reports/summary.swift: -------------------------------------------------------------------------------- 1 | // 2 | // summary.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class summary : NSObject { 13 | 14 | let app = utils().app 15 | 16 | static let SALES_SUMMARY_TITLE :String = "Sales Summary" 17 | 18 | func pullDownMenu(_ itemName: String){ 19 | app.buttons[itemName].tap() 20 | } 21 | 22 | func tapRow(_ text: String){ 23 | app.buttons[text].tap() 24 | } 25 | 26 | func unselectAll(_ unselectAll:String){ 27 | app.buttons["multi_option_select_all"].tap() 28 | } 29 | 30 | func select(_ text: String){ 31 | app.buttons[text].tap() 32 | } 33 | 34 | func setFilter(_ itemName: String, _ text: String){ 35 | self.pullDownMenu(itemName) 36 | self.tapRow(text) 37 | } 38 | 39 | func multiSelect(_ unselectText: String, _ selectBtn: Array){ 40 | self.unselectAll(unselectText) 41 | 42 | for text: String in selectBtn { 43 | self.select(text) 44 | } 45 | 46 | } 47 | 48 | var applyBtn : XCUIElement { 49 | return app.buttons["Apply"] 50 | } 51 | 52 | } 53 | -------------------------------------------------------------------------------- /settings/settings.swift: -------------------------------------------------------------------------------- 1 | // 2 | // settings.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class settings: NSObject{ 13 | 14 | let app = utils().app 15 | 16 | var backBtn:XCUIElement{ 17 | return app.buttons["setting_form_back"] 18 | } 19 | 20 | func navigate(_ itemName: String){ 21 | app.tables.cells.containing(.staticText, identifier:itemName).element.tap() 22 | } 23 | 24 | func toggleSwitch(key: String){ 25 | // NSLog("%@", app.tables.checkBoxes.element(boundBy: 0)) 26 | app.tables.cells.containing(.staticText, identifier:key).switches.element(boundBy: 0).tap() 27 | } 28 | 29 | func tapRow(_ text: String){ 30 | app.tables.cells.containing(.staticText, identifier:text).element.tap() 31 | } 32 | 33 | func btnWithText(_ text: String){ 34 | app.buttons[text].tap() 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /story.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Story.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 07/11/2016. 6 | // 7 | // 8 | 9 | import XCTest 10 | 11 | class story: XCTestCase { 12 | 13 | var systemAlertMonitorToken: NSObjectProtocol? = nil 14 | 15 | override func setUp() { 16 | super.setUp() 17 | 18 | // Put setup code here. This method is called before the invocation of each test method in the class. 19 | 20 | // In UI tests it is usually best to stop immediately when a failure occurs. 21 | continueAfterFailure = false 22 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 23 | let app = utils().app 24 | app.launchArguments = ["UI-TESTING"] 25 | setupSnapshot(app) 26 | print(app.launchArguments) 27 | app.launch() 28 | systemAlertMonitorToken = self.addUIInterruptionMonitor(withDescription: "HandleAlert") { (alert) -> Bool in 29 | if alert.buttons["OK"].exists { 30 | alert.buttons["OK"].tap() 31 | return true 32 | } else if alert.buttons["Ok"].exists { 33 | alert.buttons["Ok"].tap() 34 | return true 35 | } else { 36 | return false 37 | } 38 | } 39 | } 40 | 41 | override func tearDown() { 42 | if let systemAlertMonitorToken = self.systemAlertMonitorToken { 43 | removeUIInterruptionMonitor(systemAlertMonitorToken) 44 | } 45 | // Put teardown code here. This method is called after the invocation of each test method in the class. 46 | super.tearDown() 47 | } 48 | 49 | private func loginAndGoToList(_ listName:String) { 50 | //login 51 | login().normalLogin("Test") 52 | home().waitForViewDisplays(self) 53 | 54 | //navigate to list 55 | if(!listName.isEmpty){ 56 | siderBar().navigateToBO(listName); 57 | } 58 | } 59 | 60 | private func logout() { 61 | siderBar().logout() 62 | login().waitForViewDisplays(self) 63 | } 64 | 65 | func testOpportunity() { 66 | self.loginAndGoToList("Opportunities") 67 | 68 | opportunitiesList().waitForViewDisplays(self) 69 | opportunitiesList().switchTimeInterval("All") 70 | opportunitiesList().clickOppFilterBtn() 71 | opportunitiesFilter().apply(["评估销售机会"], "James Leung", ["0","100"]) 72 | opportunitiesList().goToDetailedView("James Leung") 73 | 74 | // Verify customer information in opportunity 75 | opportunity().verifyContactCall(["234567","123456"]) 76 | opportunity().verifyContactEmail("test@126.com") 77 | opportunity().verifyContactLocate("chenhui road 1001") 78 | 79 | // Edit opportunity information 80 | opportunity().editInformation("10000", closingPercentage: "95") 81 | utils().app.tables.element.swipeUp() 82 | opportunity().verifyWeightAmount("¥9,500.00") 83 | 84 | // // Add one product 85 | // utils().app.tables.element.swipeUp() 86 | // opportunity().addProduct("abc", unitPrice: "10", quantity: "20", discount: "5") 87 | // opportunity().verifySKUsDisplay([["abc-Green","¥100"]]) 88 | // opportunity().verifySKUTotal("¥100") 89 | // 90 | // // delete one product 91 | // opportunity().delProduct(["abc-Green"]) 92 | // opportunity().verifySKUsDisapper(["abc-Green"]) 93 | 94 | //Add one comment activity 95 | opportunity().scrollToCreateActivity() 96 | opportunity().addActivityBtn.tap() 97 | commentActivity().create("commentTest") 98 | opportunity().verifyActivityDisplays("commentTest") 99 | 100 | //Add one call activity 101 | opportunity().scrollToCreateActivity() 102 | opportunity().addActivityBtn.tap() 103 | callActivity().create("CallTest") 104 | opportunity().verifyActivityDisplays("CallTest") 105 | 106 | //Add one appointment activity 107 | opportunity().addActivityBtn.tap() 108 | appointmentActivity().add("11.11 meeting", "AppointmentTest",attendeeList:["Doe Jane"],location:"PVG03 B1.1") 109 | opportunity().verifyActivityDisplays("11.11 meeting") 110 | 111 | // Delete one activity 112 | opportunity().delActivity(["11.11 meeting"]) 113 | opportunity().verifyActivityDisappers("11.11") 114 | 115 | //Edit opportunity stage, status 116 | utils().app.tables.element.swipeDown() 117 | opportunity().changeStage("销售订单") 118 | opportunity().verifyStage("销售订单") 119 | opportunity().changeStatus("Won", reason: "None") 120 | opportunity().verifyStatus("Won") 121 | 122 | //Logout 123 | opportunity().leftMenuBtn.tap() 124 | self.logout() 125 | } 126 | 127 | 128 | /** 129 | * equals /api/mobile/Employees/v1/me => get me 130 | * equals /api/mobile/Employees/v1 => get all employees, for sync employee coredate 131 | * startsWith /api/mobile/Employees/v1/{10086} => get single employee by id, used by user 132 | */ 133 | func testSettings() { 134 | self.loginAndGoToList("Settings") 135 | 136 | //change profile 137 | settings().navigate("My Profile"); 138 | profile().editBtn.tap(); 139 | profile().textFieldWithLabel("Position").inputText("UI Tester"); 140 | let cellPhone = "123"; 141 | profile().textFieldWithLabel("Cellphone").inputText(cellPhone); 142 | profile().saveBtn.tap() 143 | profile().textWithLabel("Cellphone").verifyLabel(label: cellPhone); 144 | profile().backBtn.tap() 145 | 146 | //change device sync settings 147 | //Navigate to settings view 148 | settings().navigate("Device Sync Settings"); 149 | settings().toggleSwitch(key: "Sync appointments") 150 | settings().toggleSwitch(key: "Sync opportunities") 151 | settings().toggleSwitch(key: "Sync reminders") 152 | settings().backBtn.tap() 153 | 154 | //change default reminder time 155 | //verify in activity form 156 | settings().navigate("Default Reminder Time"); 157 | settings().tapRow("30 minutes before"); 158 | settings().backBtn.tap() 159 | 160 | //logout 161 | self.logout() 162 | } 163 | 164 | func testEditContact() { 165 | self.loginAndGoToList(addressBook.ADDRESS_BOOK_LIST_NAME) 166 | 167 | //search and navigate to contact detail form 168 | utils().swipeDown() 169 | addressBook().searchAndGoToDetail("Contact A") 170 | 171 | //click call btn 172 | contactEdit().callBtn.tap() 173 | contactEdit().cellOnInfoPickerView("23456789").tap() 174 | // //check if activity with type call generated 175 | // utils().app.tables.element.swipeUp() 176 | // let callMsg = "Called 23456789." 177 | // contactEdit().verifyActivityDisplay(callMsg) 178 | // //click to open activity to check activity type 179 | // contactEdit().tapOnActivity(callMsg) 180 | // //verify activity type 181 | // callActivity().verifyType() 182 | // callActivity().backBtnOnEditView.tap() 183 | // 184 | // //swipe up to click email btn 185 | // utils().swipeDown() 186 | contactEdit().emailBtn.tap() 187 | let emailCell = contactEdit().cellOnInfoPickerView("a.contact@126.com") 188 | emailCell.verifyExists("Email btn existed"); 189 | contactEdit().infoPickerCancelView.tap() 190 | 191 | //check status of locate btn 192 | contactEdit().locateBtn.verifyDisabled() 193 | 194 | //go to company cell 195 | let companyCell = contactEdit().cell("xd@xd.com") 196 | companyCell.verifyExists("Company exists") 197 | companyCell.tap() 198 | customerEdit().leftMenuBtn.tap() 199 | 200 | //edit contact information 201 | let firstNameStr = "FirstNAME" 202 | contactEdit().editContactInformation(firstName: firstNameStr) 203 | contactEdit().firstName.verifyLabel(label: firstNameStr, message: "Firstname not match \(firstNameStr)") 204 | 205 | //add address 206 | contact().swipeToAddAddress() 207 | contact().addAddressBtn.smartTap() 208 | let recipient = "ABC" 209 | let street1 = "Street1" 210 | let street2 = "Street2" 211 | let city = "City" 212 | let state = "Beijing" 213 | let zipCode = "0" 214 | let country = "China" 215 | let cellphone = "1" 216 | let telephone = "2" 217 | let type = "Test" 218 | address().createAddress(recipient: recipient, street1: street1, street2: street2, city: city, state: state, zipCode: zipCode, country: country, cellphone: cellphone, telephone: telephone, type: type) 219 | contact().cell(type).verifyExists("New address added.") 220 | //open this address 221 | contact().cell(type).tap() 222 | address().verifyDisplay(recipient: recipient, street1: street1, street2: street2, city: city, state: state, zipCode: zipCode, country: country, cellphone: cellphone, telephone: telephone, type: type) 223 | //edit address 224 | let newType = "NEW" 225 | address().editAddress(type: newType) 226 | contact().cell(newType).verifyExists("Address editted.") 227 | 228 | // utils().swipeUp() 229 | // 230 | // //add activity 231 | // contactEdit().addActivityBtn.tap() 232 | // let commentDetail = "COMMENT" 233 | // commentActivity().create(commentDetail) 234 | // contactEdit().verifyActivityDisplay(commentDetail) 235 | 236 | //swipe down for 5 times 237 | utils().swipeDown(time: 5); 238 | 239 | //edit contact details 240 | // contactEdit().editStatus("Inactive") 241 | // contactEdit().status.verifyLabel(label: "Inactive") 242 | 243 | contact().leftMenuBtn.tap() 244 | addressBook().leftMenuBtn.tap() 245 | //logout 246 | self.logout() 247 | } 248 | 249 | func testCreateContact() { 250 | self.loginAndGoToList(addressBook.ADDRESS_BOOK_LIST_NAME) 251 | 252 | //click create contact btn 253 | addressBook().createBtn.tap() 254 | addressBook().createContactBtn.tap() 255 | 256 | //cannot save, stay on this view 257 | contactCreate().rightMenuBtn.tap() 258 | contactCreate().lastName.verifyExists() 259 | 260 | //select company 261 | contactCreate().selectCompany("XD") 262 | contactCreate().cell("XD").verifyExists() 263 | 264 | //cannot save, stay on this view 265 | contactCreate().rightMenuBtn.tap() 266 | contactCreate().lastName.verifyExists() 267 | 268 | //create address 269 | contact().swipeToAddAddress() 270 | contactCreate().addAddressBtn.smartTap() 271 | address().createAddress(recipient: "AAA", street1: "1", street2: "2",state: "Beijing", country: "China") 272 | 273 | utils().swipeUp() 274 | contactCreate().cell("Beijing").verifyExists("New address created.") 275 | 276 | //edit address 277 | contactCreate().cell("Beijing").tap() 278 | address().editAddress(type: "CreateContact") 279 | utils().swipeUp() 280 | contactCreate().cell("CreateContact").verifyExists("Address editted.") 281 | 282 | utils().swipeDown() 283 | //input last name 284 | let newContactLastName = "LastName" 285 | contactCreate().lastName.inputText(newContactLastName) 286 | addressBook().cellWithTextField(newContactLastName).verifyExists() 287 | 288 | contactCreate().rightMenuBtn.tap() 289 | contactEdit().leftMenuBtn.tap() 290 | 291 | //click create btn 292 | self.logout() 293 | } 294 | 295 | func testEditCorporate() { 296 | self.loginAndGoToList(addressBook.ADDRESS_BOOK_LIST_NAME) 297 | 298 | //search and go to detail 299 | utils().swipeDown() 300 | addressBook().searchAndGoToDetail("XD") 301 | 302 | //click call btn 303 | customerEdit().callBtn.tap() 304 | customerEdit().cellOnInfoPickerView("123123").tap() 305 | //check if activity with type call generated 306 | customer().swipeToActivity() 307 | let msg = "Called 123123." 308 | customerEdit().cell(msg).verifyExists() 309 | //click to open activity to check activity type 310 | customerEdit().cell(msg).smartTap() 311 | //verify activity type 312 | callActivity().verifyType() 313 | callActivity().backBtnOnEditView.tap() 314 | 315 | customerEdit().emailBtn.tap() 316 | let emailCell = customerEdit().cellOnInfoPickerView("xd@xd.com") 317 | emailCell.verifyExists("Email btn existed"); 318 | customerEdit().infoPickerCancelView.tap() 319 | 320 | //check status of locate btn 321 | customerEdit().locateBtn.verifyDisabled() 322 | 323 | //check main contact cell 324 | customerEdit().mainContactCell("Contact A").verifyExists() 325 | //navigate to main contact cell 326 | customerEdit().mainContactCell("Contact A").smartTap() 327 | contactEdit().leftMenuBtn.tap() 328 | //navigate to related contects list 329 | customerEdit().relatedContactsCell.tap() 330 | relatedContacts().contactCell("Contact B").tap() 331 | contactEdit().leftMenuBtn.tap() 332 | relatedContacts().leftMenuBtn.tap() 333 | 334 | //change main contact 335 | customerEdit().changeMainContactTo("Contact B") 336 | customerEdit().mainContactCell("Contact B").verifyExists() 337 | 338 | //edit contact information 339 | customerEdit().editCorporateContactInfo(name: "NEW_NAME") 340 | customerEdit().textWithLabel(customer.CORPORATE_NAME).verifyLabel(label: "NEW_NAME") 341 | 342 | customerEdit().swipeToAddress() 343 | 344 | //add address 345 | let addressType = "testEditCorporate" 346 | customerEdit().addAddressBtn.smartTap() 347 | address().createAddress(type: addressType) 348 | customerEdit().cell(addressType).verifyExists() 349 | 350 | //edit address 351 | customerEdit().cell(addressType).smartTap() 352 | let addressNewType = "testEditCorporate_new" 353 | address().editAddress(type: addressNewType) 354 | customerEdit().cell(addressNewType).verifyExists() 355 | 356 | //delete address 357 | customerEdit().swipeToAddress() 358 | customerEdit().deleteCell(addressNewType) 359 | customerEdit().cell(addressNewType).verifyNotExists() 360 | 361 | customerEdit().swipeToActivity() 362 | 363 | //add activity 364 | customerEdit().addActivityBtn.smartTap() 365 | let commentDetail = "COMMENT" 366 | commentActivity().create(commentDetail) 367 | customerEdit().cell(commentDetail).verifyExists() 368 | 369 | //edit activity 370 | customerEdit().cell(commentDetail).smartTap() 371 | let newCommentDetail = "newCommentDetail" 372 | commentActivity().edit(newCommentDetail) 373 | snapshot("Edit activity") 374 | customerEdit().cell(newCommentDetail).verifyExists() 375 | 376 | customerEdit().swipeToActivity() 377 | 378 | //delete activity 379 | customerEdit().deleteCell(newCommentDetail) 380 | customerEdit().cell(newCommentDetail).verifyNotExists() 381 | 382 | //create opportunity 383 | customerEdit().createOpportunity() 384 | opportunity().leftMenuBtn.tap() 385 | 386 | //edit details 387 | // customerEdit().editStatus("Inactive") 388 | // customerEdit().textWithLabel(customer.STATUS).verifyLabel(label: "Inactive") 389 | 390 | //back and logout 391 | customerEdit().leftMenuBtn.tap() 392 | addressBook().leftMenuBtn.tap() 393 | self.logout() 394 | } 395 | 396 | func testCreateCorporate() { 397 | self.loginAndGoToList(addressBook.ADDRESS_BOOK_LIST_NAME) 398 | 399 | //click create corporate btn 400 | addressBook().createBtn.tap() 401 | addressBook().createCorporateBtn.tap() 402 | 403 | //input corporate name 404 | let corproateName = "ACorporateName" 405 | customerCreate().corporateName.inputText(corproateName) 406 | 407 | //add address 408 | customerCreate().swipeToAddress() 409 | customerCreate().addAddressBtn.tap() 410 | let addressType = "testCreateCorporate" 411 | address().createAddress(type: addressType) 412 | customerCreate().cell(addressType).verifyExists() 413 | 414 | //edit address 415 | customerCreate().cell(addressType).tap() 416 | let addressNewType = "testCreateCorporate_new" 417 | address().editAddress(type: addressNewType) 418 | customerCreate().cell(addressNewType).verifyExists() 419 | 420 | //delete address 421 | customerCreate().deleteCell(addressNewType) 422 | customerCreate().cell(addressNewType).verifyNotExists() 423 | 424 | //click save btn 425 | customerCreate().rightMenuBtn.tap() 426 | //check go to edit form 427 | customerEdit().cell(corproateName).verifyExists() 428 | 429 | addressBook().cellWithText(corproateName).verifyExists() 430 | 431 | //logout 432 | addressBook().leftMenuBtn.tap() 433 | self.logout() 434 | } 435 | 436 | func testEditIndividual() { 437 | self.loginAndGoToList(addressBook.ADDRESS_BOOK_LIST_NAME) 438 | 439 | //search and go to detail 440 | utils().swipeDown() 441 | addressBook().searchAndGoToDetail("James Leung") 442 | 443 | //click call btn 444 | customerEdit().callBtn.tap() 445 | customerEdit().cellOnInfoPickerView("234567").tap() 446 | //check if activity with type call generated 447 | customerEdit().swipeToActivity() 448 | let msg = "Called 234567." 449 | customerEdit().cell(msg).verifyExists() 450 | //click to open activity to check activity type 451 | customerEdit().cell(msg).tap() 452 | //verify activity type 453 | callActivity().verifyType() 454 | callActivity().backBtnOnEditView.tap() 455 | 456 | //swipe up to click email btn 457 | customerEdit().emailBtn.tap() 458 | let emailCell = customerEdit().cellOnInfoPickerView("test@126.com") 459 | emailCell.verifyExists("Email btn existed"); 460 | customerEdit().infoPickerCancelView.tap() 461 | 462 | //click locate btn 463 | customerEdit().locateBtn.tap() 464 | customerEdit().infoPickerCancelView.tap() 465 | 466 | utils().swipeDown(time: 8) 467 | //edit contact information 468 | let lastName = "NEW_NAME" 469 | customerEdit().editIndividualGeneralInfo(lastName: lastName) 470 | customerEdit().textWithLabel(customer.LAST_NAME).verifyLabel(label: lastName) 471 | 472 | customerEdit().swipeToAddress() 473 | 474 | //verify existed address 475 | customerEdit().cell("chenhui road 1001").verifyExists() 476 | //add address 477 | let addressType = "testEditIndividual" 478 | customerEdit().addAddressBtn.smartTap() 479 | address().createAddress(type: addressType) 480 | customerEdit().cell(addressType).verifyExists() 481 | 482 | //edit address 483 | sleep(1) 484 | customerEdit().cell(addressType).tap() 485 | snapshot("TapOnAddress") 486 | let addressNewType = "testEditIndividual_new" 487 | address().editAddress(type: addressNewType) 488 | customerEdit().cell(addressNewType).verifyExists() 489 | 490 | customerEdit().swipeToAddress() 491 | //delete address 492 | customerEdit().deleteCell(addressNewType) 493 | customerEdit().cell(addressNewType).verifyNotExists() 494 | 495 | customerEdit().swipeToActivity() 496 | 497 | //add activity 498 | customerEdit().addActivityBtn.tap() 499 | let commentDetail = "COMMENT" 500 | commentActivity().create(commentDetail) 501 | customerEdit().cell(commentDetail).verifyExists() 502 | 503 | //edit activity 504 | customerEdit().cell(commentDetail).tap() 505 | let newCommentDetail = "newCommentDetail" 506 | commentActivity().edit(newCommentDetail) 507 | customerEdit().cell(newCommentDetail).verifyExists() 508 | 509 | customerEdit().swipeToActivity() 510 | //delete activity 511 | customerEdit().deleteCell(newCommentDetail) 512 | customerEdit().cell(newCommentDetail).verifyNotExists() 513 | 514 | //create opportunity 515 | customerEdit().createOpportunity() 516 | opportunity().leftMenuBtn.tap() 517 | 518 | utils().swipeDown(time:8) 519 | //edit details 520 | customerEdit().editStatus("Inactive") 521 | utils().swipeUp() 522 | customerEdit().status.verifyLabel(label: "Inactive") 523 | 524 | //back and logout 525 | customerEdit().leftMenuBtn.tap() 526 | addressBook().leftMenuBtn.tap() 527 | self.logout() 528 | } 529 | 530 | func testCreateIndividual() { 531 | self.loginAndGoToList(addressBook.ADDRESS_BOOK_LIST_NAME) 532 | 533 | //click create corporate btn 534 | addressBook().createBtn.tap() 535 | addressBook().createIndividualBtn.tap() 536 | 537 | //input corporate name 538 | let lastName = "ALastName" 539 | customerCreate().textFieldWithLabel(customer.LAST_NAME).inputText(lastName) 540 | 541 | customerCreate().swipeToAddress() 542 | //add address 543 | customerCreate().addAddressBtn.tap() 544 | //add address 545 | let addressType = "testCreateIndividual" 546 | address().createAddress(type: addressType) 547 | utils().swipeUp() 548 | customerCreate().cell(addressType).verifyExists() 549 | 550 | //edit address 551 | customerCreate().cell(addressType).tap() 552 | let addressNewType = "testCreateIndividual_new" 553 | address().editAddress(type: addressNewType) 554 | utils().swipeUp() 555 | customerCreate().cell(addressNewType).verifyExists() 556 | 557 | //delete address 558 | customerCreate().deleteCell(addressNewType) 559 | customerCreate().cell(addressNewType).verifyNotExists() 560 | 561 | //click save btn 562 | customerCreate().rightMenuBtn.tap() 563 | addressBook().cellWithText(lastName).verifyExists() 564 | 565 | //logout 566 | addressBook().leftMenuBtn.tap() 567 | self.logout() 568 | } 569 | 570 | func testHomeCards() { 571 | self.loginAndGoToList(""); 572 | 573 | //verify card 574 | home().verifyCardExisting("Opportunity Due"); 575 | home().verifyCardExisting("Your Current Pipeline"); 576 | 577 | //logout 578 | siderBar().homeMenuBtnInHome.forceTap(); 579 | self.logout(); 580 | } 581 | 582 | func testProductList() { 583 | self.loginAndGoToList("Products"); 584 | 585 | //play filter 586 | productList().clickFilterBtn(); 587 | productFilter().apply("MyCategory", "MyBrand", ["0","100"]); 588 | productList().verifyProductExisting("MyCategory", false); //doesn't existing 589 | 590 | productList().clickFilterBtn(); 591 | productFilter().apply(nil, nil, ["1","86"]); // 1 to 10086 592 | productList().verifyProductExisting("MyCategory", true); 593 | productList().goToDetailedView("abc"); //product name abc 594 | 595 | //verify product 596 | product().waitForViewDisplays(self, "abc"); //abc is title 597 | product().verifyCellValue("Product Category", "MyCategory"); 598 | utils().swipeUp() 599 | product().verifyCellValue("Brand", "MyBrand"); 600 | 601 | //logout 602 | productList().leftMenuBtn.tap(); 603 | self.logout(); 604 | } 605 | 606 | func testLeadsList() { 607 | self.loginAndGoToList("Leads") 608 | 609 | //filter and sort 610 | leadsList().filterBtn.tap() 611 | leadsFilter().applyFilter(owner: "All", statuses: ["Qualified", "Unqualified"], qualification: "Hot") 612 | leadsList().filterBtn.tap() 613 | leadsFilter().sortTabBtn.tap() 614 | leadsFilter().sortTable.cells.element(boundBy: 1).tap() 615 | leadsList().cellWithText("D C").tap() 616 | 617 | lead().leftMenuBtn.tap() 618 | 619 | //search 620 | leadsList().searchAndGoToDetail("James Leung"); 621 | 622 | lead().cell("James Leung").verifyExists() 623 | } 624 | 625 | func testEditLead() { 626 | self.loginAndGoToList("Leads") 627 | 628 | leadsList().newQuickFilterBtn.tap() 629 | 630 | leadsList().cellWithText("A B").tap() 631 | 632 | //check header action btn 633 | lead().contactCall.tap() 634 | lead().cellOnInfoPickerView("Cellphone").tap() 635 | //check if activity with type call generated 636 | lead().swipeToActivity() 637 | let msg = "Called" 638 | lead().cell(msg).verifyExists() 639 | //click to open activity to check activity type 640 | lead().cell(msg).smartTap() 641 | //verify activity type 642 | callActivity().verifyType() 643 | callActivity().backBtnOnEditView.tap() 644 | 645 | lead().contactEmail.tap() 646 | lead().cellOnInfoPickerView("a@nelson.com").verifyExists() 647 | lead().infoPickerCancelView.tap() 648 | 649 | //click locate btn 650 | lead().contactLocate.verifyDisabled() 651 | 652 | //change status 653 | lead().changeStatus("In Process") 654 | lead().status.verifyLabel(label: "In Process") 655 | 656 | lead().descriptionField.inputText("New Lead Description") 657 | 658 | let newQualification = "Cold" 659 | let newRemark = "Edit Lead Remark" 660 | lead().editGeneralInfo(qualification: newQualification, remarks: newRemark) 661 | lead().textWithLabel(lead.QUALIFICATION).verifyLabel(label: newQualification) 662 | lead().textWithLabel(lead.REMARKS).verifyLabel(label: newRemark) 663 | 664 | utils().swipeUp() 665 | let newPhone = "1" 666 | let newEmail = "2@test.com" 667 | lead().editContactInfo(phone: newPhone, email: newEmail) 668 | lead().textWithLabel(lead.PHONE).verifyLabel(label: newPhone) 669 | lead().textWithLabel(lead.EMAIL).verifyLabel(label: newEmail) 670 | 671 | utils().swipeUpUntilElementVisible(element: lead().addAddressBtn) 672 | //create address 673 | lead().addAddressBtn.smartTap() 674 | let newAddress = "street1" 675 | address().createAddress(street1: newAddress) 676 | lead().cell(newAddress).verifyExists() 677 | lead().addAddressBtn.verifyNotExists() 678 | //edit address 679 | lead().cell(newAddress).tap() 680 | let editAddress = "edit_street1" 681 | address().editAddress(street1: editAddress) 682 | lead().cell(editAddress).verifyExists() 683 | //delete address 684 | lead().deleteCell(newAddress) 685 | lead().addAddressBtn.verifyExists() 686 | 687 | utils().swipeUpUntilElementVisible(element: lead().addActivityBtn) 688 | //add activity 689 | lead().addActivityBtn.smartTap() 690 | let commentDetail = "COMMENT" 691 | commentActivity().create(commentDetail) 692 | lead().cell(commentDetail).verifyExists() 693 | //edit activity 694 | lead().cell(commentDetail).tap() 695 | let newCommentDetail = "newCommentDetail" 696 | commentActivity().edit(newCommentDetail) 697 | lead().cell(newCommentDetail).verifyExists() 698 | //delete activity 699 | lead().deleteCell(newCommentDetail) 700 | lead().cell(newCommentDetail).verifyNotExists() 701 | 702 | //convert to customer 703 | lead().rightMenuBtn.tap() 704 | lead().buttonWithText("Cancel").tap() 705 | lead().changeStatus("Copied") 706 | customerEdit().leftMenuBtn.tap() 707 | 708 | lead().leftMenuBtn.tap() 709 | leadsList().leftMenuBtn.tap() 710 | self.logout() 711 | } 712 | 713 | func testCreateLead() { 714 | self.loginAndGoToList("Leads") 715 | 716 | leadsList().createBtn.tap() 717 | 718 | let newDesc = "Create Lead" 719 | lead().descriptionField.inputText(newDesc) 720 | var newPhone = "a" 721 | var newEmail = "1" 722 | lead().textFieldWithLabel(lead.PHONE).inputText(newPhone) 723 | lead().textFieldWithLabel(lead.EMAIL).inputText(newEmail) 724 | lead().rightMenuBtn.tap() 725 | newPhone = "1" 726 | newEmail = "1@126.com" 727 | lead().textFieldWithLabel(lead.PHONE).inputText(newPhone) 728 | lead().textFieldWithLabel(lead.EMAIL).inputText(newEmail) 729 | 730 | lead().rightMenuBtn.tap() 731 | 732 | leadsList().cellWithText(newEmail).verifyExists() 733 | 734 | leadsList().leftMenuBtn.tap() 735 | self.logout() 736 | 737 | } 738 | 739 | func testReports() { 740 | self.loginAndGoToList("Reports") 741 | 742 | reportsList().navigate("Pipeline Overview") 743 | 744 | overview().setFilter("Weighted", "Weighted amount") 745 | overview().setFilter("Mine", "My opportunities") 746 | 747 | reportsList().backBtn.tap() 748 | 749 | reportsList().navigate("Opportunities Outlook") 750 | 751 | outlook().setFilter("Weighted", "Potential amount") 752 | outlook().setFilter("Weekly", "Monthly") 753 | outlook().setFilter("Mine", "All opportunities") 754 | 755 | reportsList().backBtn.tap() 756 | 757 | reportsList().navigate("Sales Summary") 758 | 759 | summary().pullDownMenu("Channels(3)") 760 | summary().multiSelect("Unselect All", ["Central_Park", "默认渠道"]) 761 | summary().applyBtn.tap() 762 | 763 | summary().setFilter("Weekly", "Monthly") 764 | summary().setFilter("Mine", "My Sales Orders") 765 | 766 | reportsList().backBtn.tap() 767 | 768 | self.logout() 769 | } 770 | 771 | func testSalesOrders() { 772 | self.loginAndGoToList("Sales Orders") 773 | 774 | salesOrdersList().filterBtn.tap() 775 | salesOrdersFilter().applyFilter(owner: "All", customerTypes: ["Individual", "Corporate"]) 776 | 777 | salesOrders().goToDetailedView("21") //product name 21 778 | salesOrders().navigate("Amount") 779 | utils().swipeDown() 780 | utils().swipeUp() 781 | 782 | //click call btn 783 | salesOrders().callBtn.tap() 784 | salesOrders().cellOnInfoPickerView("234567").tap() 785 | 786 | //click email btn 787 | salesOrders().emailBtn.tap() 788 | salesOrders().cellOnInfoPickerView("test@126.com").tap() 789 | 790 | //click locate btn 791 | salesOrders().locateBtn.tap() 792 | salesOrders().infoPickerCancelView.tap() 793 | salesOrdersList().backBtn.tap() 794 | 795 | salesOrdersList().filterBtn.tap() 796 | salesOrdersFilter().sortTabBtn.tap() 797 | salesOrdersFilter().sortTable.cells.element(boundBy: 1).tap() 798 | 799 | self.logout() 800 | } 801 | } 802 | -------------------------------------------------------------------------------- /utilis/SnapshotHelper.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SnapshotHelper.swift 3 | // Example 4 | // 5 | 6 | // 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | var deviceLanguage = "en-US" 12 | var locale = "en-US" 13 | var index = 1 14 | 15 | @available(*, deprecated, message: "use setupSnapshot: instead") 16 | func setLanguage(_ app: XCUIApplication) { 17 | setupSnapshot(app) 18 | } 19 | 20 | func setupSnapshot(_ app: XCUIApplication) { 21 | Snapshot.setupSnapshot(app) 22 | } 23 | 24 | func snapshot(_ name: String, waitForLoadingIndicator: Bool = true) { 25 | let indexName:String 26 | if index < 10 { 27 | indexName = "0\(index)_\(name)" 28 | }else{ 29 | indexName = "\(index)_\(name)" 30 | } 31 | index += 1 32 | Snapshot.snapshot(indexName, waitForLoadingIndicator: waitForLoadingIndicator) 33 | } 34 | 35 | open class Snapshot: NSObject { 36 | 37 | open class func setupSnapshot(_ app: XCUIApplication) { 38 | setLanguage(app) 39 | setLocale(app) 40 | setLaunchArguments(app) 41 | } 42 | 43 | class func setLanguage(_ app: XCUIApplication) { 44 | guard let prefix = pathPrefix() else { 45 | return 46 | } 47 | 48 | let path = prefix.appendingPathComponent("language.txt") 49 | 50 | do { 51 | let trimCharacterSet = CharacterSet.whitespacesAndNewlines 52 | deviceLanguage = try NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue).trimmingCharacters(in: trimCharacterSet) as String 53 | app.launchArguments += ["-AppleLanguages", "(\(deviceLanguage))"] 54 | } catch { 55 | print("Couldn't detect/set language...") 56 | } 57 | } 58 | 59 | class func setLocale(_ app: XCUIApplication) { 60 | guard let prefix = pathPrefix() else { 61 | return 62 | } 63 | 64 | let path = prefix.appendingPathComponent("locale.txt") 65 | 66 | do { 67 | let trimCharacterSet = CharacterSet.whitespacesAndNewlines 68 | locale = try NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue).trimmingCharacters(in: trimCharacterSet) as String 69 | } catch { 70 | print("Couldn't detect/set locale...") 71 | } 72 | if locale.isEmpty { 73 | locale = Locale(identifier: deviceLanguage).identifier 74 | } 75 | app.launchArguments += ["-AppleLocale", "\"\(locale)\""] 76 | } 77 | 78 | class func setLaunchArguments(_ app: XCUIApplication) { 79 | guard let prefix = pathPrefix() else { 80 | return 81 | } 82 | 83 | let path = prefix.appendingPathComponent("snapshot-launch_arguments.txt") 84 | app.launchArguments += ["-FASTLANE_SNAPSHOT", "YES", "-ui_testing"] 85 | 86 | do { 87 | let launchArguments = try NSString(contentsOfFile: path, encoding: String.Encoding.utf8.rawValue) as String 88 | let regex = try NSRegularExpression(pattern: "(\\\".+?\\\"|\\S+)", options: []) 89 | let matches = regex.matches(in: launchArguments, options: [], range: NSRange(location:0, length:launchArguments.characters.count)) 90 | let results = matches.map { result -> String in 91 | (launchArguments as NSString).substring(with: result.range) 92 | } 93 | app.launchArguments += results 94 | } catch { 95 | print("Couldn't detect/set launch_arguments...") 96 | } 97 | } 98 | 99 | open class func snapshot(_ name: String, waitForLoadingIndicator: Bool = true) { 100 | if waitForLoadingIndicator { 101 | waitForLoadingIndicatorToDisappear() 102 | } 103 | 104 | print("snapshot: \(name)") // more information about this, check out https://github.com/fastlane/fastlane/tree/master/snapshot#how-does-it-work 105 | 106 | sleep(1) // Waiting for the animation to be finished (kind of) 107 | 108 | #if os(tvOS) 109 | XCUIApplication().childrenMatchingType(.Browser).count 110 | #else 111 | XCUIDevice.shared().orientation = .unknown 112 | #endif 113 | } 114 | 115 | class func waitForLoadingIndicatorToDisappear() { 116 | #if os(tvOS) 117 | return 118 | #endif 119 | 120 | let query = XCUIApplication().statusBars.children(matching: .other).element(boundBy: 1).children(matching: .other) 121 | 122 | while (0.. NSString? { 129 | if let path = ProcessInfo().environment["SIMULATOR_HOST_HOME"] as NSString? { 130 | return path.appendingPathComponent("Library/Caches/tools.fastlane") as NSString? 131 | } 132 | print("Couldn't find Snapshot configuration files at ~/Library/Caches/tools.fastlane") 133 | return nil 134 | } 135 | } 136 | 137 | extension XCUIElement { 138 | var isLoadingIndicator: Bool { 139 | return self.frame.size == CGSize(width: 10, height: 20) 140 | } 141 | } 142 | 143 | // Please don't remove the lines below 144 | // They are used to detect outdated configuration files 145 | // SnapshotHelperVersion [1.2] 146 | -------------------------------------------------------------------------------- /utilis/XCUIElement+ext.swift: -------------------------------------------------------------------------------- 1 | // 2 | // XCUIElement+ext.swift 3 | // anwstream 4 | // 5 | // 6 | // 7 | 8 | import Foundation 9 | import XCTest 10 | 11 | extension XCUIElement { 12 | func scrollUpToElement(element: XCUIElement) { 13 | while !element.visible() { 14 | swipeUp() 15 | } 16 | } 17 | 18 | func scrollDownToElement(element: XCUIElement) { 19 | while !element.visible() { 20 | swipeDown() 21 | } 22 | } 23 | 24 | func visible() -> Bool { 25 | guard self.exists && !self.frame.isEmpty && self.isHittable else { return false } 26 | return XCUIApplication().windows.element(boundBy: 0).frame.contains(self.frame) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /utilis/utils.swift: -------------------------------------------------------------------------------- 1 | // 2 | // utils.swift 3 | // anwstream 4 | // 5 | // Created by Lu, Luis on 07/11/2016. 6 | // 7 | // 8 | 9 | import Foundation 10 | import XCTest 11 | 12 | class utils: NSObject{ 13 | 14 | 15 | let app = XCUIApplication() 16 | 17 | /** 18 | - parameter dateElement: locate dateTime element 19 | - parameter dateTime: match specified format like Dec 12-10-10-PM 20 | */ 21 | func handleDateTimePicker(_ dateElement:XCUIElement, dateTime:String) { 22 | dateElement.tap() 23 | let dateTimeArray = dateTime.components(separatedBy: "-") 24 | app.pickerWheels.element(boundBy: 0).adjust(toPickerWheelValue: dateTimeArray[0]) 25 | app.pickerWheels.element(boundBy: 1).adjust(toPickerWheelValue: dateTimeArray[1]) 26 | app.pickerWheels.element(boundBy: 2).adjust(toPickerWheelValue: dateTimeArray[2]) 27 | app.pickerWheels.element(boundBy: 3).adjust(toPickerWheelValue: dateTimeArray[3]) 28 | app.toolbars.buttons.element(boundBy: 0).tap() 29 | } 30 | 31 | 32 | 33 | /** 34 | - parameter dateElement: locate dateTime element 35 | - parameter date: match specified format like December-12-2018 36 | */ 37 | func handleDatePicker(_ dateElement:XCUIElement, date:String) { 38 | dateElement.tap() 39 | let dateArray = date.components(separatedBy: "-") 40 | app.pickerWheels.element(boundBy: 0).adjust(toPickerWheelValue: dateArray[0]) 41 | app.pickerWheels.element(boundBy: 1).adjust(toPickerWheelValue: dateArray[1]) 42 | app.pickerWheels.element(boundBy: 2).adjust(toPickerWheelValue: dateArray[2]) 43 | app.toolbars.buttons.element(boundBy: 0).tap() 44 | } 45 | 46 | func handleSelectorPicker(_ identifier:String) { 47 | app.pickerWheels.element.adjust(toPickerWheelValue: identifier) 48 | app.toolbars.buttons.element(boundBy: 0).tap() 49 | } 50 | 51 | func handleKeyboard(_ key:String){ 52 | if app.keyboards.buttons[key].exists { 53 | app.keyboards.buttons[key].tap() 54 | } else if app.keyboards.keys[key].exists { 55 | app.keyboards.keys[key].tap() 56 | } else { 57 | app.toolbars.buttons["Done"].tap() 58 | } 59 | } 60 | 61 | // func handleAlert(_ actionIdentifier:String){ 62 | // let actionElement = app.alerts.buttons[actionIdentifier] 63 | // actionElement.tap() 64 | // } 65 | 66 | // func handleSystemAlert(_ xcTestCase:XCTestCase, _ actionIdentifier:String){ 67 | // let monitorToken = xcTestCase.addUIInterruptionMonitor(withDescription: "Calender permission") { (alert) -> Bool in 68 | // alert.buttons[actionIdentifier].tap() 69 | // return true 70 | // } 71 | // app.tap() // need to interact with the app for the handler to fire 72 | // } 73 | 74 | // func verifyElementExists(_ element: XCUIElement, message: String = "Can not find related element"){ 75 | //// XCTAssert(element.exists,message) 76 | // element.verifyExists(message) 77 | // } 78 | // 79 | // func verifyElementDisappers(_ element: XCUIElement, message: String = "Related element still appears"){ 80 | // XCTAssertTrue(!element.exists, message) 81 | // } 82 | 83 | func waitForElementToAppear(_ xcTestCase:XCTestCase, _ element: XCUIElement, timeout : Double = 5) { 84 | let existsPredicate = NSPredicate(format: "exists == true") 85 | xcTestCase.expectation(for: existsPredicate, evaluatedWith: element, handler: nil) 86 | xcTestCase.waitForExpectations(timeout: timeout) { (error) -> Void in 87 | XCTAssert(error == nil, "Failed to find \(element) after \(timeout) seconds.") 88 | } 89 | } 90 | // func waitForElementToAppear(_ element: XCUIElement, timeout : Double = 5, file: String = #file, line: UInt = #line) { 91 | // let existsPredicate = NSPredicate(format: "exists == true") 92 | // expectation(for: existsPredicate, evaluatedWith: element, handler: nil) 93 | // waitForExpectations(timeout: timeout) { (error) -> Void in 94 | // if (error != nil) { 95 | // let message = "Failed to find \(element) after \(timeout) seconds." 96 | // self.recordFailure(withDescription: message, inFile: file, atLine: line, expected: true) 97 | // } 98 | // } 99 | // } 100 | 101 | func swipeUp() { 102 | self.app.tables.element(boundBy: 0).swipeUp() 103 | } 104 | 105 | func swipeUpUntilElementVisible(element: XCUIElement) { 106 | self.app.tables.element(boundBy: 0).scrollUpToElement(element: element) 107 | } 108 | 109 | func swipeDown() { 110 | self.app.tables.element(boundBy: 0).swipeDown() 111 | } 112 | 113 | func swipeDownUntilElementVisible(element: XCUIElement) { 114 | self.app.tables.element(boundBy: 0).scrollDownToElement(element: element) 115 | } 116 | 117 | func swipeDown(time: Int){ 118 | for _ in 0 ..< time { 119 | utils().swipeDown() 120 | } 121 | } 122 | } 123 | 124 | 125 | --------------------------------------------------------------------------------