SBTUITestTunnel
SBTUITestTunnel copied to clipboard
Monitored requests have no httpBody
Hi, I have this UITest that was previously working in iOS 16.4 simulator. We've moved now to use iOS 17.2 simulator. We're using latest version 10.0.0. I'm monitoring a request and debugging I can see we send a body. However, when I peek the requests:
app.monitoredRequestsPeekAll()
I see my requests have no httpBody
somehow whereas if I run the same test on iOS 16.4 I can see the body. This is a regular request using URLSession.dataTask(with:completionHandler)
.
Any ideas what's wrong?
Hi there! I just tried running the library's test suite on an iOS 17.2 simulator, and tests are passing including a few that also verify the httpBody. Moreover we have several tests in the codebase @Subito that monitor requests and checks the httpBody. Did you try to replicate the issue in a separate project that can be shared? It would make debugging the issue easier.
Hey @tcamin, I have the same problem. The issue doesn't seem to reproduce on a small body.
Try to change httpBody in this test to String(repeatElement("a", count: 20000))
and you will see this error in the console:
Dropping oversized protocol property key SBTUITunneledNSURLProtocolHTTPBodyKey in <NSMutableURLRequest: 0x60000000c1e0> { URL: https://httpbin.org/post }
That's interesting! I'll try to take a look as soon as I can.
I've have this open branch to test out hotfix/large_body
. I still need to investigate some issues when running in CI but locally it seems to be working. If you try it out let me know!
hey @tcamin thanks for the quick fix. I just tried and whereas now the request has an httpBody
it seems that the ObjC casting is off:
Could not cast value of type '__NSCFString' (0x1f1d04258) to 'NSData' (0x1f1d09130).
httpBody
is supposed to have NSData
type. I've seen this before while working in ObjC
I'm checking the diff:
+ (void)setProperty:(id)property forKey:(nonnull NSString *)key inRequest:(nonnull NSMutableURLRequest *)request
{
if ([property isKindOfClass:[NSData class]] && ((NSData *)property).length > 16834) { ... }
else { ... }
}
+ (id)propertyForKey:(NSString *)key inRequest:(NSURLRequest *)request;
{
id property = [NSURLProtocol propertyForKey:key inRequest:request];
return [storage objectForKey:property] ?: property;
}
it seems that storage
is always storing NSData
but propertyForKey
returns anything. And there's also a collision of types. If I'm not wrong, [storage objectForKey:property]
should return NSData
whereas ?: property
returns NSString
Yeah so the original body is something like this:
{
"foo": <very_long_text>
"bar": <something_of_interest_for_the_test>
}
and what I get in the monitored [request HTTPBody]
is a UUID
: D68DD094-EAB4-4CEA-B401-AB1FA21BB34A
The logic should be right, I've slightly modified the implementation which should address the issue you are experiencing. Let me know if it works now.
Thanks @tcamin . I've updated my dependency to point at 985d63ec9a6080aeacbc2ca9d76b86cf2cea189e
but unfortunately I still see the same issue.
What is it that you tweaked?
Same issue as in getting UUID
or empty body
?
Same issue as in
getting UUID
orempty body
?
Getting UUID
Could you try again on e5c0f7f4bd343627e55aecc39b76c39b32c8b444?
hey same issue on e5c0f7f4bd343627e55aecc39b76c39b32c8b444
, I'm getting a UUID
:
(lldb) po _originalRequest.HTTPBody
E8A5F5B2-65EF-432D-B7C4-F26E44E8DFA3
@tcamin it seems that the properties saved in SBTRequestPropertyStorage
from the app process are not visible in the UI Tests process.
@tcamin we have the same issue, any updates about the fix
Hi! Sorry for the late reply. It would help if you could provide a way to replicate this locally, ideally by adding a failing test to the libary.
@tcamin We appreciate your support and adding this test will help reproduce the issue locally. Please add the following test to DownloadUploadTests
:
func testMonitorPostRequestWithHTTPLargeBodyInAppProcess() {
let largeBody = String(repeating: "a", count: 20000)
let matchingRequest = SBTRequestMatch(url: "httpbin.org", method: "POST")
app.monitorRequests(matching: matchingRequest)
XCTAssertTrue(app.tables.firstMatch.staticTexts["executePostDataTaskRequestWithLargeHTTPBody"].waitForExistence(timeout: 5))
app.tables.firstMatch.staticTexts["executePostDataTaskRequestWithLargeHTTPBody"].tap()
XCTAssertTrue(app.waitForMonitoredRequests(matching: matchingRequest, timeout: 10))
let requests = app.monitoredRequestsFlushAll()
XCTAssertEqual(requests.count, 1)
print(requests.map(\.debugDescription))
for request in requests {
guard let httpBody = request.request?.httpBody else {
XCTFail("Missing http body")
continue
}
XCTAssertEqual(String(data: httpBody, encoding: .utf8), largeBody)
XCTAssert((request.responseString()!).contains("httpbin.org"))
XCTAssert(request.timestamp > 0.0)
XCTAssert(request.requestTime > 0.0)
}
XCTAssert(app.stubRequestsRemoveAll())
XCTAssert(app.monitorRequestRemoveAll())
}
and add in SBTTableViewController
@objc func executePostDataTaskRequestWithLargeHTTPBody() {
let largeBody = String(repeating: "a", count: 20000)
dataTaskNetwork(urlString: "https://httpbin.org/post", httpMethod: "POST", httpBody: largeBody)
}
The issue is that the request being fired is from the app process and not from the UITest process. As a result, we are unable to obtain the original request body.
@fermoya @magauran Try this.
this is working @AhmedAshraf605 , thanks for the contribution 🙌
@tcamin will you cut a new version soon?
Hi! If everything works on our tests suites for a few days I will release a new version in the coming week.