You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

452 lines
17 KiB

// Copyright © 2015 Abhishek Banthia
import XCTest
class PreferencesTest: XCTestCase {
var app: XCUIApplication!
override func setUp() {
super.setUp()
continueAfterFailure = false
app = XCUIApplication()
app.launchArguments.append(CLUITestingLaunchArgument)
app.launch()
if app.tables["FloatingTableView"].exists {
app.tapMenubarIcon()
app.buttons["FloatingPin"].click()
}
}
func testRemovingButtonVisibility() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
let predicate = NSPredicate(format: "identifier BEGINSWITH 'DeleteTimezone'", "")
let beforeTimezoneSelected = app.windows["Clocker"].checkBoxes.matching(predicate).firstMatch
XCTAssertFalse(beforeTimezoneSelected.isEnabled)
if app.tables["TimezoneTableView"].tableRows.count <= 0 {
XCTFail("There are no timezones.")
return
}
app.windows["Clocker"].tables["TimezoneTableView"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)).click()
XCTAssertTrue(app.checkBoxes["DeleteTimezone"].isEnabled)
}
func testAddingATimezone() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
if app.sheets.count == 0 {
app.windows["Clocker"].checkBoxes["AddTimezone"].click()
}
addAPlace(place: "UTC", to: app)
let matchPredicate = NSPredicate(format: "value contains %@", "UTC")
let matchingFields = app.tables["TimezoneTableView"].textFields.matching(matchPredicate)
XCTAssertTrue(matchingFields.count > 0, "Matching Fields count was zero")
deleteAPlace(place: "UTC", for: app)
}
func testSortingCitiesByTimezoneDifference() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
deleteAllPlaces(app: app)
addAPlace(place: "New Zealand", to: app)
addAPlace(place: "San Francisco", to: app)
addAPlace(place: "Florida", to: app, shouldSleep: false) // Last elements don't need to sleep
XCTAssertTrue(app.windows["Clocker"].checkBoxes["Sort by Time Difference".localizedString()].exists)
app.windows["Clocker"].checkBoxes["Sort by Time Difference".localizedString()].click()
var actualLabels: [String] = []
let newFormattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< newFormattedAddressQuery.count {
if let currentValue = newFormattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 0 {
actualLabels.append(currentValue)
}
}
XCTAssertEqual(actualLabels,
["New Zealand".localizedString(),
"Florida".localizedString(),
"San Francisco".localizedString()])
app.windows["Clocker"].checkBoxes["Sort by Time Difference".localizedString()].click()
var actualReversedLabels: [String] = []
let newReversedQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< newReversedQuery.count {
if let currentValue = newReversedQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 0 {
actualReversedLabels.append(currentValue)
}
}
XCTAssertEqual(actualReversedLabels, ["San Francisco".localizedString(),
"Florida".localizedString(),
"New Zealand".localizedString()])
addAPlace(place: "Omaha", to: app)
addAPlace(place: "Mumbai", to: app)
}
func testSortingCitiesByTimezoneName() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
XCTAssertTrue(app.windows["Clocker"].checkBoxes["Sort by Time Difference".localizedString()].exists)
XCTAssertTrue(app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].exists)
XCTAssertTrue(app.windows["Clocker"].checkBoxes["Sort by Name".localizedString()].exists)
var formattedAddress: [String] = []
let formattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< formattedAddressQuery.count {
if let currentValue = formattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 0 {
formattedAddress.append(currentValue)
}
}
formattedAddress.sort()
if let value = app.windows["Clocker"].checkBoxes["Sort by Name".localizedString()].value as? Int, value == 0 {
app.windows["Clocker"].checkBoxes["Sort by Name".localizedString()].click()
}
var newformattedAddress: [String] = []
let newFormattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< newFormattedAddressQuery.count {
if let currentValue = newFormattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 0 {
newformattedAddress.append(currentValue)
}
}
XCTAssertEqual(newformattedAddress, formattedAddress)
}
func testSortingCitiesByCustomLabel() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
addAPlace(place: "Aurangabad", to: app)
addAPlace(place: "Zimbabwe", to: app)
addAPlace(place: "Portland", to: app, shouldSleep: false)
addAPlace(place: "Asia/Calcutta", to: app)
addAPlace(place: "Anywhere on Earth", to: app, shouldSleep: false)
XCTAssertTrue(app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].exists)
var expectedLabels: [String] = []
let formattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< formattedAddressQuery.count {
if let currentValue = formattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 1 {
expectedLabels.append(currentValue)
}
}
expectedLabels.sort()
if let value = app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].value as? Int, value == 0 {
app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].click()
}
var actualLabels: [String] = []
let newFormattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< newFormattedAddressQuery.count {
if let currentValue = newFormattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 1 {
actualLabels.append(currentValue)
}
}
XCTAssertEqual(actualLabels, expectedLabels)
deleteAPlace(place: "Aurangabad", for: app)
deleteAPlace(place: "Zimbabwe", for: app)
deleteAPlace(place: "Portland", for: app)
deleteAPlace(place: "Asia/Calcutta", for: app)
deleteAPlace(place: "Anywhere on Earth", for: app, shouldSleep: false)
}
func testSortingTimezonesByCustomLabel() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
addAPlace(place: "Europe/Lisbon", to: app)
addAPlace(place: "Asia/Calcutta", to: app)
addAPlace(place: "Anywhere on Earth", to: app, shouldSleep: false)
XCTAssertTrue(app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].exists)
var expectedLabels: [String] = []
let formattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< formattedAddressQuery.count {
if let currentValue = formattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 1 {
expectedLabels.append(currentValue)
}
}
expectedLabels.sort()
if let value = app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].value as? Int, value == 0 {
app.windows["Clocker"].checkBoxes["Sort by Label".localizedString()].click()
}
var actualLabels: [String] = []
let newFormattedAddressQuery = app.windows["Clocker"].textFields
for elementIndex in 0 ..< newFormattedAddressQuery.count {
if let currentValue = newFormattedAddressQuery.element(boundBy: elementIndex).value as? String, elementIndex % 2 == 1 {
actualLabels.append(currentValue)
}
}
XCTAssertEqual(actualLabels, expectedLabels)
deleteAPlace(place: "Europe/Lisbon", for: app)
deleteAPlace(place: "Asia/Calcutta", for: app)
deleteAPlace(place: "Anywhere on Earth", for: app, shouldSleep: false)
}
func testSearchingWithMisspelledName() {
app.tapMenubarIcon()
app.tables["mainTableView"].typeKey(",", modifierFlags: .command)
if app.sheets.count == 0 {
app.windows["Clocker"].checkBoxes["AddTimezone"].click()
}
let searchField = app.searchFields["AvailableSearchField"]
searchField.reset(text: "StuJjlqh7AcJFnBuOdgNa2dQ4WrIajP9Mo8R83FV7fIZ3B8zE2n")
sleep(2)
let maxCharacterCountPredicate = NSPredicate(format: "value like %@", "Max Search Characters".localizedString())
let currentSheets = app.sheets.firstMatch.staticTexts
let maxCharacterQuery = currentSheets.matching(maxCharacterCountPredicate)
XCTAssertTrue(maxCharacterQuery.count > 0)
addAPlace(place: "asdakjhdasdahsdasd", to: app, shouldSleep: false)
XCTAssertTrue(app.sheets.staticTexts["No Timezone Selected".localizedString()].exists)
let informativeLabelPredicate = NSPredicate(format: "placeholderValue like %@", "No results! 😔 Try entering the exact name.")
let sheets = app.sheets.firstMatch.staticTexts
let query = sheets.matching(informativeLabelPredicate)
XCTAssertTrue(query.count > 0)
addAPlace(place: "Cambodia", to: app)
let newInformativeLabelPredicate = NSPredicate(format: "placeholderValue like %@", "No results! 😔 Try entering the exact name.")
let newSheets = app.sheets.firstMatch.staticTexts
let newQuery = newSheets.matching(newInformativeLabelPredicate)
XCTAssertTrue(newQuery.count == 0, "New Query returned \(newQuery.count)")
XCTAssertFalse(app.sheets.staticTexts["Please select a timezone!"].exists)
deleteAPlace(place: "Cambodia", for: app, shouldSleep: false)
}
func testNoTimezone() {
app.tapMenubarIcon()
app.buttons["Preferences"].click()
deleteAllTimezones()
XCTAssertTrue(app.staticTexts["NoTimezoneEmoji"].exists)
XCTAssertTrue(app.staticTexts["NoTimezoneMessage"].exists)
app.tapMenubarIcon()
XCTAssertTrue(app.buttons["EmptyAddTimezone"].exists)
addAPlace(place: "Omaha", to: app)
addAPlace(place: "Mumbai", to: app)
deleteAllTimezones()
XCTAssertTrue(app.staticTexts["NoTimezoneEmoji"].exists)
XCTAssertTrue(app.staticTexts["NoTimezoneMessage"].exists)
addAPlace(place: "Omaha", to: app)
addAPlace(place: "Mumbai", to: app)
}
func testWarningIfMoreThanOneMenubarIsSelected() {
app.tapMenubarIcon()
app.buttons["Preferences"].click()
let preferencesTable = app.tables["TimezoneTableView"]
XCTAssertTrue(preferencesTable.exists)
// Let's reset all checkboxes
let favouritedMenubarsQuery = preferencesTable.checkBoxes.matching(NSPredicate(format: "value == 1", ""))
if favouritedMenubarsQuery.count > 1 {
for _ in 0 ..< favouritedMenubarsQuery.count {
let checkbox = favouritedMenubarsQuery.element(boundBy: 0)
checkbox.click()
}
}
// Let's make sure we have > 1 timezones first
let favourites = preferencesTable.tableRows
XCTAssertTrue(favourites.count > 1)
// Select two timezones
let unfavouritedMenubarsQuery = preferencesTable.checkBoxes.matching(NSPredicate(format: "value == 0", ""))
if unfavouritedMenubarsQuery.count > 1 {
for _ in 0 ..< 2 {
let checkbox = unfavouritedMenubarsQuery.element(boundBy: 0)
checkbox.click()
}
}
XCTAssertTrue(app.dialogs.count > 0)
let compactModeButton = app.dialogs.buttons["Enable Compact Mode"]
if compactModeButton.isHittable {
compactModeButton.click()
XCTAssertTrue(app.dialogs.count == 0)
}
}
private func deleteAllTimezones() {
let clockerWindow = app.windows["Clocker"]
let rowQueryCount = clockerWindow.tables["TimezoneTableView"].tableRows.count
if rowQueryCount > 0 {
// Table Rows aren't hittable in Xcode 12.0 (10/7/20) and so we need to find a closer co-ordinate and perform click()
let currentElement = clockerWindow.tables["TimezoneTableView"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
currentElement.click()
for _ in 0 ..< rowQueryCount {
clockerWindow.typeKey(XCUIKeyboardKey.delete,
modifierFlags: XCUIElement.KeyModifierFlags())
}
}
}
}
extension XCUIApplication {
func tapMenubarIcon() {
if menuBars.count < 2 {
XCTFail("Unable to find menubar options")
return
}
statusItems.firstMatch.click()
}
}
extension XCTestCase {
func inverseWaiterFor(element: XCUIElement, time: TimeInterval = 25) {
let spinnerPredicate = NSPredicate(format: "exists == false")
let spinnerExpectation = expectation(for: spinnerPredicate, evaluatedWith: element, handler: nil)
let spinnerResult = XCTWaiter().wait(for: [spinnerExpectation], timeout: time)
if spinnerResult != .completed {
XCTFail("Still seeing Spinner after 25 seconds. Something's wrong")
return
}
}
func addAPlace(place: String, to app: XCUIApplication, shouldSleep: Bool = true) {
// Let's first check if the place is already present in the list
let matchPredicate = NSPredicate(format: "value contains %@", place)
let matchingFields = app.windows["Clocker"].tables["TimezoneTableView"].textFields.matching(matchPredicate)
if matchingFields.count > 0 {
return
}
if app.sheets.count == 0 {
app.windows["Clocker"].checkBoxes["AddTimezone"].click()
}
let searchField = app.searchFields["AvailableSearchField"]
if searchField.isHittable {
searchField.reset(text: place)
}
let results = app.tables["AvailableTimezoneTableView"].cells.staticTexts.matching(matchPredicate)
let waiter = XCTWaiter()
let isHittable = NSPredicate(format: "exists == true", "")
let addExpectation = expectation(for: isHittable,
evaluatedWith: results.firstMatch) { () -> Bool in
Logger.info("Handler called")
return true
}
waiter.wait(for: [addExpectation], timeout: 5)
if results.count > 0 {
results.firstMatch.click()
}
if app.buttons["AddAvailableTimezone"].exists {
app.buttons["AddAvailableTimezone"].click()
}
if shouldSleep {
sleep(2)
}
}
func deleteAllPlaces(app: XCUIApplication) {
var rowQueryCount = app.windows["Clocker"].tables["TimezoneTableView"].tableRows.count
if rowQueryCount == 0 {
return
}
let currentElement = app.windows["Clocker"].tableRows.firstMatch.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0))
currentElement.click()
while rowQueryCount > 0 {
app.windows["Clocker"].typeKey(XCUIKeyboardKey.delete, modifierFlags: XCUIElement.KeyModifierFlags())
rowQueryCount -= 1
}
}
func deleteAPlace(place: String, for app: XCUIApplication, shouldSleep: Bool = true) {
let userPrefferedLanguage = Locale.preferredLanguages.first ?? "en-US"
if !userPrefferedLanguage.lowercased().contains("en") {
// We're testing in a different user language. We can't do string matching here.
// Delete the last row
let rowCount = app.tables["TimezoneTableView"].tableRows.count
let rowToDelete = app.tables["TimezoneTableView"].tableRows.element(boundBy: rowCount - 1)
deleteAtRow(rowToDelete, for: app, shouldSleep: shouldSleep)
return
}
let matchPredicate = NSPredicate(format: "value contains %@", place)
let row = app.tables["TimezoneTableView"].textFields.matching(matchPredicate).firstMatch
deleteAtRow(row, for: app, shouldSleep: shouldSleep)
}
private func deleteAtRow(_ rowToDelete: XCUIElement, for _: XCUIApplication, shouldSleep: Bool) {
rowToDelete.coordinate(withNormalizedOffset: CGVector(dx: 0, dy: 0)).click()
rowToDelete.typeKey(XCUIKeyboardKey.delete, modifierFlags: XCUIElement.KeyModifierFlags())
if shouldSleep {
sleep(2)
}
}
}