diff --git a/Tests/ApolloTests/Interceptors/MultipartResponseSubscriptionParserTests.swift b/Tests/ApolloTests/Interceptors/MultipartResponseSubscriptionParserTests.swift index c960bf5f1..b63964f8b 100644 --- a/Tests/ApolloTests/Interceptors/MultipartResponseSubscriptionParserTests.swift +++ b/Tests/ApolloTests/Interceptors/MultipartResponseSubscriptionParserTests.swift @@ -10,7 +10,7 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { // MARK: - Error tests - func test__error__givenChunk_withIncorrectContentType_shouldReturnError() throws { + func test__error__givenIncorrectContentType_shouldReturnError() throws { let subject = InterceptorTester(interceptor: MultipartResponseParsingInterceptor()) let expectation = expectation(description: "Received callback") @@ -46,7 +46,7 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { wait(for: [expectation], timeout: defaultTimeout) } - func test__error__givenChunk_withTransportError_shouldReturnError() throws { + func test__error__givenTransportError_shouldReturnError() throws { let subject = InterceptorTester(interceptor: MultipartResponseParsingInterceptor()) let expectation = expectation(description: "Received callback") @@ -84,7 +84,7 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { wait(for: [expectation], timeout: defaultTimeout) } - func test__error__givenUnrecognizableChunk_shouldReturnError() throws { + func test__error__givenTransportErrorWithNullPayload_shouldReturnError() throws { let subject = InterceptorTester(interceptor: MultipartResponseParsingInterceptor()) let expectation = expectation(description: "Received callback") @@ -97,7 +97,14 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { --graphql content-type: application/json - not_a_valid_json_object + { + "payload": null, + "errors" : [ + { + "message" : "forced test failure!" + } + ] + } --graphql """.crlfFormattedData() ) @@ -108,7 +115,51 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { expect(result).to(beFailure { error in expect(error).to( - matchError(MultipartResponseSubscriptionParser.ParsingError.cannotParseChunkData) + matchError(MultipartResponseSubscriptionParser.ParsingError.irrecoverableError(message: "forced test failure!")) + ) + }) + } + + wait(for: [expectation], timeout: defaultTimeout) + } + + func test__error__givenTransportErrorWithValidPayload_errorShouldTakePrecendenceAndReturnError() throws { + let subject = InterceptorTester(interceptor: MultipartResponseParsingInterceptor()) + + let expectation = expectation(description: "Received callback") + + subject.intercept( + request: .mock(operation: MockSubscription.mock()), + response: .mock( + headerFields: ["Content-Type": "multipart/mixed;boundary=graphql;subscriptionSpec=1.0"], + data: """ + --graphql + content-type: application/json + + { + "payload": { + "data": { + "__typename": "Time", + "ticker": 1 + } + }, + "errors" : [ + { + "message" : "forced test failure!" + } + ] + } + --graphql + """.crlfFormattedData() + ) + ) { result in + defer { + expectation.fulfill() + } + + expect(result).to(beFailure { error in + expect(error).to( + matchError(MultipartResponseSubscriptionParser.ParsingError.irrecoverableError(message: "forced test failure!")) ) }) } @@ -116,7 +167,7 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { wait(for: [expectation], timeout: defaultTimeout) } - func test__error__givenChunk_withMissingPayload_shouldReturnError() throws { + func test__error__givenTransportErrorIncludingUnknownKeys_shouldReturnErrorWithMessageOnly() throws { let subject = InterceptorTester(interceptor: MultipartResponseParsingInterceptor()) let expectation = expectation(description: "Received callback") @@ -130,7 +181,15 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { content-type: application/json { - "key": "value" + "errors" : [ + { + "message" : "forced test failure!", + "path": [ + "hello" + ], + "foo": "bar" + } + ] } --graphql """.crlfFormattedData() @@ -142,7 +201,39 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { expect(result).to(beFailure { error in expect(error).to( - matchError(MultipartResponseSubscriptionParser.ParsingError.cannotParsePayloadData) + matchError(MultipartResponseSubscriptionParser.ParsingError.irrecoverableError(message: "forced test failure!")) + ) + }) + } + + wait(for: [expectation], timeout: defaultTimeout) + } + + func test__error__givenMalformedJSON_shouldReturnError() throws { + let subject = InterceptorTester(interceptor: MultipartResponseParsingInterceptor()) + + let expectation = expectation(description: "Received callback") + + subject.intercept( + request: .mock(operation: MockSubscription.mock()), + response: .mock( + headerFields: ["Content-Type": "multipart/mixed;boundary=graphql;subscriptionSpec=1.0"], + data: """ + --graphql + content-type: application/json + + not_a_valid_json_object + --graphql + """.crlfFormattedData() + ) + ) { result in + defer { + expectation.fulfill() + } + + expect(result).to(beFailure { error in + expect(error).to( + matchError(MultipartResponseSubscriptionParser.ParsingError.cannotParseChunkData) ) }) } @@ -188,38 +279,114 @@ final class MultipartResponseSubscriptionParserTests: XCTestCase { --graphql content-type: application/json + { + "payload": { + "data": { + "__typename": "Time", + "ticker": 1 + } + } + } + --graphql + content-type: application/json + {} --graphql + content-type: application/json + + { + "payload": { + "data": { + "__typename": "Time", + "ticker": 2 + } + } + } + --graphql """.crlfFormattedData() ) let expectation = expectation(description: "Heartbeat ignored") - expectation.isInverted = true + expectation.expectedFulfillmentCount = 2 _ = network.send(operation: MockSubscription