surpher / surpher/PactSwift

Question: Is it possible to use generators in requests?

Open
#104 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

question
Dominant language
Swift
Stars
56
Forks
21
PR merge metrics
No merged PRs in 30d

Description

❔ Question

I want to use generators in requests like this:

    func testSubscription() throws {
        
        mockService
            .uponReceiving("Dx subscription")
            .given("good state")
            .withRequest(
                method: PactHTTPMethod.POST,
                path: "/api/v1/subscription",
                headers: [
                    "Content-Type": "application/json"
                ],
                body: [
                    "application": ExampleGenerator.RandomString(size: 20),
                    "token": ExampleGenerator.RandomString(size: 20),
                    "applicationVersion": ExampleGenerator.RandomString(size: 20),
                    "deviceName": ExampleGenerator.RandomString(size: 20),
                    "platform": ExampleGenerator.RandomString(size: 20),
                    "platformVersion": ExampleGenerator.RandomString(size: 20),
                    "language": ExampleGenerator.RandomString(size: 20),
                ]
            )
            .willRespondWith(
                status: 200,
                headers: [
                    "Content-Type": "application/json"
                ],
                body: Matcher.EachLike(
                    [
                        "errors": Matcher.MatchNull(),
                        "success": Matcher.SomethingLike(true)
                    ],
                    min: 1
                )
            )
        
        let request = DxSubscriptionRequest(
            application: "com.our.company",
            token: "some_token",
            applicationVersion: "1.0.0",
            deviceName: "iPhone 14 pro",
            platform: "iOS",
            platformVersion: "16.1",
            language: "en"
        )
        
        mockService.run { baseURL, done in
                        
            let config = APIConfiguration(
                baseURL: baseURL,
                channel: "",
                userAgent: "",
                appVersion: request.applicationVersion,
                referer: "",
                xchannel: "MOBILE_NATIVE_IOS",
                token: "",
                accountId: "")
            
            let subscription = DxSubscription.request(r: request, config: config)
            
            // Run POST /api/v1/subscription
            NetworkClient()
                .request(endpoint: subscription) { (response: [DxSubscriptionResponse]?, error) in
                    guard error == nil else {
                        XCTFail("Failed with \(String(describing: error))")
                        done()
                        return
                    }
                    
                    do {
                        let dxResponse = try XCTUnwrap(response)
                        
                        XCTAssertNil(dxResponse.first?.errors)
                        XCTAssertTrue(dxResponse.first?.success ?? false)
                    } catch {
                        XCTFail("Expected DxSubscriptionResponse")
                    }
                    
                    done()
                }
        }
    }

but the test fails with errors like:

Expected 'RGpibFlTHTnV1ywjejkA' to be equal to 'com.our.company' - Body does not match the expected body definition

To fix that I had to replace

                body: [
                    "application": ExampleGenerator.RandomString(size: 20),
                    "token": ExampleGenerator.RandomString(size: 20),
                    "applicationVersion": ExampleGenerator.RandomString(size: 20),
                    "deviceName": ExampleGenerator.RandomString(size: 20),
                    "platform": ExampleGenerator.RandomString(size: 20),
                    "platformVersion": ExampleGenerator.RandomString(size: 20),
                    "language": ExampleGenerator.RandomString(size: 20),
                ]

with

                    "application": Matcher.SomethingLike("string"),
                    "token": Matcher.SomethingLike("string"),
                    "applicationVersion": Matcher.SomethingLike("string"),
                    "deviceName": Matcher.SomethingLike("string"),
                    "platform": Matcher.SomethingLike("string"),
                    "platformVersion": Matcher.SomethingLike("string"),
                    "language": Matcher.SomethingLike("string"),

Is it possible to use generators like in JVM version?

@ExtendWith(PactConsumerTestExt::class)
@PactTestFor(providerName = "dx_provider", pactVersion = PactSpecVersion.V3)
class DxTest {
    @Pact(provider = "dx_provider", consumer = "dx_android_consumer")
    fun httpInteraction(builder: PactDslWithProvider): RequestResponsePact {
        return builder
            .given("good state")
            .uponReceiving("Dx subscription")
            .path("/api/v1/subscription")
            .method("POST")
            .headers(mapOf("Content-Type" to "application/json"))
            .body(
                LambdaDsl.newJsonBody { b ->
                    b.stringType("application")
                    b.stringType("token")
                    b.stringType("applicationVersion")
                    b.stringType("deviceName")
                    b.stringType("platform")
                    b.stringType("platformVersion")
                    b.stringType("language")
                }.build()
            )
            .willRespondWith()
            .status(200)
            .headers(mapOf("Content-Type" to "application/json"))
            .body(
                LambdaDsl.newJsonBody { b ->
                    b.nullValue("errors")
                    b.booleanType("success", true)
                }.build()
            )
            .toPact()
    }

Compare generated pacts:

PactSwift:

      "request": {
        "body": {
          "application": "string",
          "applicationVersion": "string",
          "deviceName": "string",
          "language": "string",
          "platform": "string",
          "platformVersion": "string",
          "token": "string"
        },
        "headers": {
          "Content-Type": "application/json"
        },
        "matchingRules": {
          "body": {
            "$.application": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "type"
                }
              ]
            },
...
        },

JVM:

     "request": {
        "body": {
          "application": "string",
          "applicationVersion": "string",
          "deviceName": "string",
          "language": "string",
          "platform": "string",
          "platformVersion": "string",
          "token": "string"
        },
        "generators": {
          "body": {
            "$.application": {
              "size": 20,
              "type": "RandomString"
            },
            "$.applicationVersion": {
              "size": 20,
              "type": "RandomString"
            },
            "$.deviceName": {
              "size": 20,
              "type": "RandomString"
            },
            "$.language": {
              "size": 20,
              "type": "RandomString"
            },
            "$.platform": {
              "size": 20,
              "type": "RandomString"
            },
            "$.platformVersion": {
              "size": 20,
              "type": "RandomString"
            },
            "$.token": {
              "size": 20,
              "type": "RandomString"
            }
          }
        },
        "headers": {
          "Content-Type": "application/json"
        },
        "matchingRules": {
          "body": {
            "$.application": {
              "combine": "AND",
              "matchers": [
                {
                  "match": "type"
                }
              ]
            },
...

💬 Context

Xcode 14.2

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the Swift request body passed to withRequest and compare the generated PactSwift request with the JVM pact shown in the issue. Trace how matchingRules are produced and determine where the request generators section would need to appear. Done means generated pacts preserve the example body, include the requested RandomString generator entries, and continue matching the actual request.

Written by the indexing model from the issue text.

Assessment

Tech stack
swift
Domain
testing-qa
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.