Skip to content
This repository was archived by the owner on Feb 24, 2025. It is now read-only.

Commit 51995b0

Browse files
authored
vastly simplfiy the atb ui tests (#835)
1 parent 43f0ad0 commit 51995b0

1 file changed

Lines changed: 28 additions & 190 deletions

File tree

‎AtbUITests/AtbIntegrationTests.swift‎

Lines changed: 28 additions & 190 deletions
Original file line numberDiff line numberDiff line change
@@ -27,32 +27,16 @@ class AtbIntegrationTests: XCTestCase {
2727
// 5 should be good enough. 10 for some padding
2828
static let defaultTimeout: Double = 10
2929

30-
static let initialAtb = "v100-1"
31-
static let searchRetentionAtb = "v102-7"
32-
static let appRetentionAtb = "v102-6"
33-
3430
static let devmode = "test"
3531
static let atbParam = "atb"
3632
static let setAtbParam = "set_atb"
3733
static let activityType = "at"
3834
}
39-
40-
enum StatisticsRequestType {
41-
case atb
42-
case exti
43-
}
44-
45-
struct StatisticsRequest {
46-
let type: StatisticsRequestType
47-
let httpRequest: HttpRequest
48-
}
49-
35+
5036
let app = XCUIApplication()
5137
let server = HttpServer()
52-
var statisticsRequests = [StatisticsRequest]()
53-
var searchRequests = [HttpRequest]()
54-
var atbToSet = Constants.initialAtb
55-
38+
var requests = 0
39+
5640
override func setUp() {
5741
super.setUp()
5842
continueAfterFailure = false
@@ -73,134 +57,39 @@ class AtbIntegrationTests: XCTestCase {
7357
} catch {
7458
fatalError("Could not start server")
7559
}
76-
60+
61+
requests = 0
7762
app.launch()
7863
}
7964

8065
override func tearDown() {
8166
super.tearDown()
8267
server.stop()
83-
statisticsRequests.removeAll()
84-
searchRequests.removeAll()
85-
}
86-
87-
func test() throws {
88-
try assertWhenAppIsInstalledAndLaunchedThenExtiIsCalledAndInitialAtbIsRetrieved()
89-
clearRequests()
90-
91-
assertWhenAppLaunchedAgainThenAppAtbIsUpdated()
92-
clearRequests()
93-
94-
assertWhenUserSearchesWithOldAtbThenAtbIsUpdated()
95-
clearRequests()
96-
97-
try assertWhenSearchPerformedThenAtbIsAddedToRequest()
98-
clearRequests()
99-
100-
assertWhenUserEntersSearchDirectlyThenAtbIsAddedToRequest()
101-
clearRequests()
10268
}
103-
104-
func assertWhenAppIsInstalledAndLaunchedThenExtiIsCalledAndInitialAtbIsRetrieved() throws {
105-
106-
waitFor(searchRequestsCount: 0, statisticRequestsCount: 3, timeout: 30)
107-
108-
assertSearchRequestCount(count: 0)
109-
assertStatisticsRequestCount(count: 3)
110-
assertAtb(expectedAtb: nil, expectedSetAtb: nil, expectedType: nil)
111-
assertExti()
112-
assertAtb(expectedAtb: Constants.initialAtb, expectedSetAtb: Constants.initialAtb, expectedType: "app_use")
113-
}
114-
115-
func assertWhenSearchPerformedThenAtbIsAddedToRequest() throws {
116-
search(forText: "oranges")
11769

118-
assertSearchRequestCount(count: 1)
119-
assertSearch(text: "oranges", atb: Constants.initialAtb)
70+
func testAppUsageCausesAtbRequests() {
71+
waitForRequests()
12072
}
12173

122-
func assertWhenUserSearchesWithOldAtbThenAtbIsUpdated() {
123-
atbToSet = Constants.searchRetentionAtb
124-
74+
func testSearchCausesAtbRequests() {
75+
requests = 0 // Reset to ensure test launch of the app doesn't register as a false positive
12576
search(forText: "lemons")
126-
search(forText: "pears")
127-
128-
waitFor(searchRequestsCount: 2, statisticRequestsCount: 0, timeout: 30)
129-
assertSearchRequestCount(count: 2)
130-
assertSearch(text: "lemons", atb: Constants.initialAtb)
131-
assertSearch(text: "pears", atb: Constants.initialAtb)
132-
133-
waitFor(searchRequestsCount: 0, statisticRequestsCount: 2, timeout: 30)
134-
assertStatisticsRequestCount(count: 2)
135-
assertAtb(expectedAtb: Constants.initialAtb, expectedSetAtb: Constants.initialAtb, expectedType: nil)
136-
assertAtb(expectedAtb: Constants.initialAtb, expectedSetAtb: Constants.searchRetentionAtb, expectedType: nil)
77+
waitForRequests()
13778
}
138-
139-
func assertWhenUserEntersSearchDirectlyThenAtbIsAddedToRequest() {
140-
search(forText: "http://localhost:8080?q=beagles")
141-
142-
assertSearchRequestCount(count: 1)
143-
assertSearch(text: "beagles", atb: Constants.initialAtb)
144-
}
145-
146-
func assertWhenAppLaunchedAgainThenAppAtbIsUpdated() {
147-
atbToSet = Constants.appRetentionAtb
148-
149-
backgroundRelaunch() // this launch gets new atb
150-
backgroundRelaunch() // this launch sends it
15179

152-
waitFor(searchRequestsCount: 0, statisticRequestsCount: 2, timeout: 30)
153-
assertSearchRequestCount(count: 0)
154-
assertStatisticsRequestCount(count: 2)
155-
assertAtb(expectedAtb: Constants.initialAtb, expectedSetAtb: Constants.initialAtb, expectedType: "app_use")
156-
assertAtb(expectedAtb: Constants.initialAtb, expectedSetAtb: Constants.appRetentionAtb, expectedType: "app_use")
80+
func testRelaunchCausesAtbRequests() {
81+
requests = 0 // Reset to ensure test launch of the app doesn't register as a false positive
82+
backgroundRelaunch()
83+
waitForRequests()
15784
}
158-
159-
func clearRequests() {
160-
statisticsRequests.removeAll()
161-
searchRequests.removeAll()
162-
}
163-
85+
16486
func backgroundRelaunch() {
16587
XCUIDevice.shared.press(.home)
16688
app.activate()
16789
if !app.searchFields["searchEntry"].waitForExistence(timeout: Constants.defaultTimeout) {
16890
fatalError("Can not find search field. Has the app launched?")
16991
}
17092
}
171-
172-
func assertStatisticsRequestCount(count: Int, file: StaticString = #file, line: UInt = #line) {
173-
XCTAssertEqual(count, statisticsRequests.count, file: file, line: line)
174-
}
175-
176-
func assertExti(file: StaticString = #file, line: UInt = #line) {
177-
let request = statisticsRequests.removeFirst()
178-
XCTAssertEqual(StatisticsRequestType.exti, request.type, file: file, line: line)
179-
XCTAssertEqual(Constants.initialAtb, request.httpRequest.queryParam(Constants.atbParam), file: file, line: line)
180-
}
181-
182-
func assertAtb(expectedAtb: String? = nil, expectedSetAtb: String? = nil, expectedType: String? = nil,
183-
file: StaticString = #file, line: UInt = #line) {
184-
let request = statisticsRequests.removeFirst()
185-
XCTAssertEqual(StatisticsRequestType.atb, request.type, file: file, line: line)
186-
187-
let httpRequest = request.httpRequest
188-
XCTAssertEqual(expectedAtb, httpRequest.queryParam(Constants.atbParam), file: file, line: line)
189-
XCTAssertEqual(expectedSetAtb, httpRequest.queryParam(Constants.setAtbParam), file: file, line: line)
190-
XCTAssertEqual(expectedType, httpRequest.queryParam(Constants.activityType), file: file, line: line)
191-
XCTAssertEqual("1", httpRequest.queryParam(Constants.devmode), file: file, line: line)
192-
}
193-
194-
func assertSearchRequestCount(count: Int, file: StaticString = #file, line: UInt = #line) {
195-
XCTAssertEqual(count, searchRequests.count, file: file, line: line)
196-
}
197-
198-
func assertSearch(text: String, atb: String, file: StaticString = #file, line: UInt = #line) {
199-
let request = searchRequests.removeFirst()
200-
201-
XCTAssertEqual(text, request.queryParam("q"), file: file, line: line)
202-
XCTAssertEqual(atb, request.queryParam(Constants.atbParam), file: file, line: line)
203-
}
20493

20594
private func search(forText text: String) {
20695

@@ -211,40 +100,32 @@ class AtbIntegrationTests: XCTestCase {
211100
Snapshot.waitForLoadingIndicatorToDisappear(within: Constants.defaultTimeout)
212101

213102
}
214-
215-
private func waitFor(searchRequestsCount: Int, statisticRequestsCount: Int, timeout: TimeInterval) {
103+
104+
/// We don't care which requests, as long as it's one of the expected endpoints. The actual logic is tested in
105+
/// the StatisticsLoader tests
106+
private func waitForRequests(timeout: TimeInterval = Constants.defaultTimeout) {
216107
let start = Date()
217-
218108
while (start.timeIntervalSinceNow * -1) < timeout {
219109
_ = app.buttons["_wait_"].waitForExistence(timeout: 1)
220-
if searchRequests.count >= searchRequestsCount && statisticsRequests.count >= statisticRequestsCount {
110+
if requests > 0 {
221111
return
222112
}
223113
}
224-
225-
if searchRequests.count != searchRequests.count || statisticRequestsCount != statisticsRequests.count {
226-
XCTFail("\(searchRequests.count) vs \(searchRequestsCount), \(statisticRequestsCount) vs \(statisticsRequests.count)")
227-
}
114+
115+
XCTFail("No requests detected")
228116
}
229117

230118
private func addRequestHandlers() {
231-
232-
server["/"] = {
233-
self.searchRequests.append($0)
119+
120+
server["/exti/"] = { _ in
121+
self.requests += 1
234122
return .accepted
235123
}
236124

237-
server["/exti/"] = {
238-
self.statisticsRequests.append(StatisticsRequest(type: StatisticsRequestType.exti, httpRequest: $0))
125+
server["/atb.js"] = { _ in
126+
self.requests += 1
239127
return .accepted
240128
}
241-
242-
server["/atb.js"] = {
243-
self.statisticsRequests.append(StatisticsRequest(type: StatisticsRequestType.atb, httpRequest: $0))
244-
return .ok(.json([
245-
"version": self.atbToSet
246-
] as AnyObject))
247-
}
248129
}
249130

250131
private func waitForButtonThenTap(_ named: String) {
@@ -258,52 +139,9 @@ class AtbIntegrationTests: XCTestCase {
258139
}
259140

260141
fileprivate extension HttpRequest {
261-
142+
262143
func queryParam(_ named: String) -> String? {
263144
return queryParams.first(where: { $0.0 == named })?.1
264145
}
265-
266-
}
267146

268-
// from: https://stackoverflow.com/a/36168101/73479
269-
class Springboard {
270-
271-
static let springboard = XCUIApplication(bundleIdentifier: "com.apple.springboard")
272-
273-
/**
274-
Terminate and delete the app via springboard
275-
*/
276-
class func deleteMyApp() {
277-
XCUIApplication().terminate()
278-
279-
// Resolve the query for the springboard rather than launching it
280-
springboard.activate()
281-
282-
// Force delete the app from the springboard
283-
let icon = springboard.icons["DuckDuckGo"]
284-
if icon.exists {
285-
let iconFrame = icon.frame
286-
let springboardFrame = springboard.frame
287-
icon.press(forDuration: 1.3)
288-
289-
let rearrangeButton = springboard.buttons["Rearrange Apps"]
290-
if rearrangeButton.waitForExistence(timeout: 2) {
291-
rearrangeButton.tap()
292-
293-
sleep(1)
294-
// Tap the little "X" button at approximately where it is. The X is not exposed directly
295-
296-
springboard.coordinate(withNormalizedOffset: CGVector(dx: (iconFrame.minX + 3) / springboardFrame.maxX,
297-
dy: (iconFrame.minY + 3) / springboardFrame.maxY)).tap()
298-
} else {
299-
// Buttons have been rearranged for iOS 13.1+ version
300-
let deleteButton = springboard.buttons["Delete App"]
301-
deleteButton.tap()
302-
}
303-
304-
let deleteButton = springboard.alerts.buttons["Delete"]
305-
_ = deleteButton.waitForExistence(timeout: AtbIntegrationTests.Constants.defaultTimeout)
306-
deleteButton.tap()
307-
}
308-
}
309147
}

0 commit comments

Comments
 (0)