Giter VIP home page Giter VIP logo

pact-consumer-swift's Introduction

Pact Consumer Swift

Build Codecov Carthage compatible Swift Package Manager Swift Badge w/ CocoaPod Version Badge w/ Supported Platforms License: MIT Twitter

โ„น
A new version featuring Pact Specification v3, a simplified installation and better management of the mock server processes is in active development and can be found at PactSwift. We are currently looking for people to try it out and provide feedback.

This library provides a Swift / Objective C DSL for creating Consumer Pacts. It provides support for Consumer Driven Contract Testing between dependent systems where the integration is based on HTTP (or message queues for some of the implementations).

But why? To test communication boundaries between your app and services. You can view a presentation on how Pact can work in a mobile context here: Yow! Connected 2016 Andrew Spinks - Increasing The Confidence In Your Service Integrations.

Implements Pact Specification v2, including flexible matching.

This DSL relies on the Ruby pact-ruby-standalone (brew tap) to provide the mock service for the tests.

Installation

Note: see Upgrading for notes on upgrading from 0.2 to 0.3

Install Pact Mock Service

Homebrew

brew tap pact-foundation/pact-ruby-standalone
brew install pact-ruby-standalone

This will install the following tools:

pact
pact-broker
pact-message
pact-mock-service
pact-provider-verifier
pact-publish
pact-stub-service

Manually

Alternatively you can download and install the pact-ruby-standalone archives for your platform and install as per installation instructions written in Pact Ruby Standalone release notes.

Xcode Setup

In Xcode, edit your scheme and add pre- and post-actions to Test to start and stop pact-mock-service. Make sure you select your target in Provide build settings from the drop down menu.

# Pre-actions
PATH=/path/to/your/standalone/pact/bin:$PATH
pact-mock-service start --pact-specification-version 2.0.0 --log "${SRCROOT}/tmp/pact.log" --pact-dir "${SRCROOT}/tmp/pacts" -p 1234

# Post-actions
PATH=/path/to/your/standalone/pact/bin:$PATH
pact-mock-service stop

Note: your generated Pact files will be dropped into "${SRCROOT}/tmp/pacts" folder.

Xcode Scheme Test Pre-actions

Add the PactConsumerSwift library to your project

Using Carthage

  • See the PactSwiftExample Swift, Carthage Example - Build Status for an example project using pact-consumer-swift with Carthage for an iOS target.
  • See the PactMacOSExample Build for an example project using pact-consumer-swift through Carthage for a macOS target.

Using CocoaPods

  • See the PactObjectiveCExample Build Status for an example project using pact-consumer-swift with CocoaPods for an iOS target.
  • See the PactSwiftPMExample Build for an example project using pact-consumer-swift library through Swift Package Manager for an executable that runs in terminal.

Writing Pact Tests

Testing with Swift

Write a Unit test similar to the following (NB: this example is using the Quick test framework)

import PactConsumerSwift

...
  beforeEach {
    animalMockService = MockService(provider: "Animal Service", consumer: "Animal Consumer Swift")
    animalServiceClient = AnimalServiceClient(baseUrl: animalMockService!.baseUrl)
  }

  it("gets an alligator") {
    animalMockService!.given("an alligator exists")
                      .uponReceiving("a request for an alligator")
                      .withRequest(method:.GET, path: "/alligator")
                      .willRespondWith(status:200,
                                       headers: ["Content-Type": "application/json"],
                                       body: ["name": "Mary"])

    //Run the tests
    animalMockService!.run { (testComplete) -> Void in
      animalServiceClient!.getAlligator { (alligator) in
        expect(alligator.name).to(equal("Mary"))
        testComplete()
      }
    }
  }

An optional timeout (seconds) parameter can be included on the run function. This defaults to 30 seconds.

...
    animalMockService!.run(timeout: 60) { (testComplete) -> Void in
      animalServiceClient!.getAlligator { (alligator) in
        expect(alligator.name).to(equal("Mary"))
        testComplete()
      }
    }

Testing with Objective-C

Write a Unit test similar to the following

@import PactConsumerSwift;
...
- (void)setUp {
  [super setUp];
  self.animalMockService = [[MockService alloc] initWithProvider:@"Animal Provider"
                                                        consumer:@"Animal Service Client Objective-C"];
  self.animalServiceClient = [[OCAnimalServiceClient alloc] initWithBaseUrl:self.animalMockService.baseUrl];
}

- (void)testGetAlligator {
  typedef void (^CompleteBlock)();

  [[[[self.animalMockService given:@"an alligator exists"]
                             uponReceiving:@"oc a request for an alligator"]
                             withRequestHTTPMethod:PactHTTPMethodGET
                                              path:@"/alligator"
                                             query:nil headers:nil body:nil]
                             willRespondWithHTTPStatus:200
                                               headers:@{@"Content-Type": @"application/json"}
                                                  body: @"{ \"name\": \"Mary\"}" ];

  [self.animalMockService run:^(CompleteBlock testComplete) {
      Animal *animal = [self.animalServiceClient getAlligator];
      XCTAssertEqualObjects(animal.name, @"Mary");
      testComplete();
  }];
}

An optional timeout (seconds) parameter can be included on the run function. This defaults to 30 seconds.

...
  [self.animalMockService run:^(CompleteBlock testComplete) {
      Animal *animal = [self.animalServiceClient getAlligator];
      XCTAssertEqualObjects(animal.name, @"Mary");
      testComplete();
  } timeout:60];
}

Testing with XCTest

Write a Unit Test similar to the following:

import PactConsumerSwift
...
  var animalMockService: MockService?
  var animalServiceClient: AnimalServiceClient?

  override func setUp() {
    super.setUp()

    animalMockService = MockService(provider: "Animal Provider", consumer: "Animal Service Client")
    animalServiceClient = AnimalServiceClient(baseUrl: animalMockService!.baseUrl)
  }

  func testItGetsAlligator() {
    // Prepare the expecated behaviour using pact's MockService
    animalMockService!
      .given("an alligator exists")
      .uponReceiving("a request for alligator")
      .withRequest(method: .GET, path: "/alligator")
      .willRespondWith(status: 200,
                       headers: ["Content-Type": "application/json"],
                       body: [ "name": "Mary" ])

    // Run the test
    animalMockService!.run(timeout: 60) { (testComplete) -> Void in
      self.animalServiceClient!.getAlligator { (response) -> in
        XCTAssertEqual(response.name, "Mary")
        testComplete()
      }
    }
  }
  ...

An optional timeout (seconds) parameter can be included on the run function. Defaults to 30 seconds.

...
    // Run the test
    animalMockService!.run(timeout: 60) { (testComplete) -> Void in
      self.animalServiceClient!.getAlligator { (response) -> in
        XCTAssertEqual(response.name, "Mary")
        testComplete()
      }
    }

For an example on how to test over https see PactSSLSpec.swift.

Matching

In addition to verbatim value matching, you have 3 useful matching functions in the Matcher class that can increase expressiveness and reduce brittle test cases.

  • Matcher.term(matcher, generate) - tells Pact that the value should match using a given regular expression, using generate in mock responses. generate must be a string.
  • Matcher.somethingLike(content) - tells Pact that the value itself is not important, as long as the element type (valid JSON number, string, object etc.) itself matches.
  • Matcher.eachLike(content, min) - tells Pact that the value should be an array type, consisting of elements like those passed in. min must be >= 1. content may be a valid JSON value: e.g. strings, numbers and objects.

NOTE: One caveat to note, is that you will need to use valid Ruby regular expressions and double escape backslashes.

See the PactSpecs.swift, PactObjectiveCTests.m for examples on how to expect error responses, how to use query params, and Matchers.

For more on request / response matching, see [Matching][getting_started/matching].

Using in your CI

Xcode's pre-actions and post-actions do not honour non-zero script exits and therefore would not fail your build if publishing to a Pact Broker would fail. If you would like to upload your Pact files to a Pact Broker as part of your CI, we would suggest that you create a separate step in your CI workflow with that responsibility.

See pact-ruby-standalone page for installation instructions and how to use pact-broker client.

Verifying your client against the service you are integrating with

If your setup is correct and your tests run against the pack mock server, then you should see a log file here: $YOUR_PROJECT/tmp/pact.log And the generated pacts here: $YOUR_PROJECT/tmp/pacts/...

Publish your generated pact file(s) to your Pact Broker or a Hosted Pact Broker so your API provider can always retrieve them from one location, even when pacts change. Or even just by simply sending the pact file to your API provider devs so they can used them in their tests of their API responses. See Verifying pacts for more information. For an end-to-end example with a ruby back end service, have a look at the KatKit example.

Also, check out this article on using a dockerized Node.js service that uses provider states.

More reading

  • The Pact website Pact
  • The pact mock server that the Swift library uses under the hood Pact mock service
  • A pact broker for managing the generated pact files (so you don't have to manually copy them around!) Pact broker

Contributing

Please read CONTRIBUTING.md

pact-consumer-swift's People

Contributors

alannichols avatar alexbasson avatar amitojduggal avatar andrewspinks avatar angelolloqui avatar erikackermann avatar garie avatar georgescumihai avatar giginet avatar huwr avatar macblazer avatar marturi avatar mmysliwiec avatar rajatvig avatar rbobbins avatar richardpfisk avatar rubencagnie avatar sebskuse avatar stephengroat avatar surpher avatar tomaslinhart avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

pact-consumer-swift's Issues

Won't compile under Xcode 7 with iOS 8 deployment target

Repro steps:

  • Integrate PactConsumerSwift into project with iOS 8 set as deployment target
  • Build and run

Result:

  • Numerous swift language errors. Example from Interaction.swift:
    '#' has been removed from Swift; double up 'method method' to make the argument label the same as the parameter name
  • Similar errors in AlamoFire and BrightFutures dependencies

Expected Result:

  • Compiles with Xcode 7 / Swift 2 compiler without errors

Pre/post script with non-zero exit does not fail build

Setup

Running pact tests from an iOS build.
Using pre-actions and post-actions of the scheme in the Xcode project to start/stop the pact mock service and then upload to the Pact broker.

pre-actions

"${PACT_BIN}/pact-mock-service" start --pact-specification-version 2.0.0 --log "${SRCROOT}/tmp/pact.log" --pact-dir "${SRCROOT}/tmp/pacts" -p 1234

post-actions

"${PACT_BIN}/pact-mock-service" stop
"${PACT_BIN}/pact-broker" publish "${SRCROOT}/tmp/pacts" --consumer-app-version=1.0.1 --tag master

Expected result:

Non-zero exit of these scripts should fail the CI.

Actual result:

Non-zero exit codes from pre/post test scripts don't result in the actual build being marked as an error or failure by Xcode, so it won't actually fail CI.

Chore: migrate away from TravisCI

TravisCI (org) is dropping support for OSS builds at the end of this month, meaning they must be transferred to travis-ci.com, which uses a credit system. Builds may fail (and already are) if the number of credits is exhausted within the month.

We are recommending switching to GH Actions, but the choice of CI provider is up to the project maintainer.

See also:

https://mailchi.mp/3d439eeb1098/travis-ciorg-is-moving-to-travis-cicom
https://travis-ci.community/t/org-com-migration-unexpectedly-comes-with-a-plan-change-for-oss-what-exactly-is-the-new-deal/10567/5

Include binaries of depending tools in the repo

When running in CI/CD (TravisCI) in our case, it is not encouraged to update tools on the Build machine to the latest as the may break the version dependency (eg: brew update, carthage update). These updates might update the dependencies or behaviour that might not be compatible with the codebase. By bundling these binaries we can be sure the environment on developers machine and CI are the same.

Suggesting to bundle the following binaries of tools into the repo:

  • Carthage
  • Swiftlint
  • Pact-Mock-Service

- Carthage dependencies

Scripts and steps that use these tools need to be updated to use these specific binaries instead of tools installed on developer's machine or CI agents.

Remove Nimble dependency

Almost every new Xcode and swift version breaks due to downstream dependencies.
Reducing number of dependencies will reduce unnecessary breakages and reduce maintenance work.

This issue focuses on removing hard dependency on Quick/Nimble in the main framework.
Move dependency into test targets only so it's not propagated to end users of this Framework.

JSON pact file not generated after the test passes

Hi,

I am testing a swift2 app, I've setup the MockService and run my test successfully--I can see the mock-service Webrick log being populated--but there is no pacts directory with the json pact file!

The server starts/stops successfully via the scheme pre/post test scripts.

Has anyone seen this before? Any idea to where to look at what's going wrong?

Thanks

MockService's testFunction should `rethrows`

Hi,

It'd be great if the testFunction from the MockService could be marked as rethrows.

This will allow us to call throwing functions inside testFunction, and for that error to be thrown in turn by the XCTest function. Errors thrown from XCTest funcs fail the test. It is likely that an exception inside the testFunction would be a good enough reason to fail the test. This means we won't have to catch the error if all we wanted to do was fail the test.

Example of usage would be:

    //Run the tests
    animalMockService.run { (testComplete) -> Void in
      let animals = try animalServiceClient.getAlligators()
      XCTAssertTrue(animals.count > 0)
      testComplete()
    }

Also means we don't need to use try!, which would crash the test.

The standard library uses rethrows inside sequence algorithms for things like flatMap: https://github.com/apple/swift/blob/master/stdlib/public/core/SequenceAlgorithms.swift#L756

More on rethrows: https://docs.swift.org/swift-book/ReferenceManual/Declarations.html and https://www.hackingwithswift.com/example-code/language/how-to-use-the-rethrows-keyword

extend run to include timeout

I am running UI tests that utilize the mock services, but in a couple of cases the tests take longer than the default timeout for Nimble. Currently, I am having to set

Nimble.AsyncDefaults.Timeout = 30

but I'd prefer to either pass in a timeout value to run, or do the assert myself for testComplete
Thoughts?

Thanks

Remove unnecessary dependencies

Every new xcode and swift version breaks due to downstream dependencies. Reducing number of dependencies will reduce unnecessary breakages and reduce maintenance work.

Deps:

  • BrightFutures
  • Alamofire
  • Nimble (would probably need to duplicate nimbles' xcode reporting functions)

Improve swiftlint reporting

When there is a linting issue while running in travis-ci, the output is hidden in the build log file. This makes it hard to identify what went wrong and can make it confusing and frustrating for contributors.

Tests fail

Hi,

It seems like testItSaysHello() fails for me on timeout. Actually, all the methods do. Do you have any idea what could be the problem here? I installed everything needed, at least I believe so.

Thanks!

Brightfutures crashes on Xcode 11.2.1, Swift 5.1, iOS 13.2 - EXC_BAD_ACCESS

Hello,

Currently we are trying to get Pact.IO running for our iOS app. However we are unable to execute a MockService.run() without it crashing.

The application keeps throwing a "Thread 1: EXC_BAD_ACCESS (code=2, address=0x1)"

#2 0x0000000108391853 in AsyncType<>.onSuccess(_:callback:) at /$PROJECT/SourcePackages/checkouts/BrightFutures/Sources/BrightFutures/AsyncType+ResultType.swift:33

It seems that the problem is with Brightfutures. We could provide with a short Demo Project in order to reproduce the issue.

Thanks

Error messages from mock server no longer returned

After merging #53 errors are no longer being returned from the mock server. This means verification errors are not returned in test failures in XCode.

Verification errors before change:
verification-failure-before

Verification errors after change:
verification-failure-after

Test fails in physical device

Hi, Can we run the pact tests in physical device? I am getting below errors

"Verification error (check build log for mismatches): Error"
"Waited more than 1.0 seconds"

Even tested with PactSwiftExample project & getting same error.

Matcher.eachLike(_:min) not generating examples in Pact file

New Issue Checklist

  • Updated pact-consumer-swift to latest version
  • Searched for existing GitHub issues

Issue description

When writing Pact tests with Matcher.eachLike(_ value: Any, min: Int) and using 0 for min,
the generated Pact file does not include the provided example value.

Given Pact test:

myProvider!
.given("some values")
.uponReceiving("a request to get a list of values")
.withRequest(method: .GET, path: "/some/endpoint")
.willRespondWith(status: 200,  
                 body: ["someArray": Matcher.eachLike(["date": Matcher.term(matcher: "\\d{4}-\\d{2}-\\d{2}", generate: "2018-04-12"), 
                                                       "description": Matcher.somethingLike("Some description")], min: 0))

In Pact file:

{
      "description": "a request to get a list of values",
      "providerState": "some values",
      "request": {
        "method": "get",
        "path": "/some/endpoint"
      },
      "response": {
        "status": 200,
        "headers": {
        },
        "body": {
          "someArray": [
            {

            }
          ]
        },
        "matchingRules": {
          "$.body.someArray": {
            "min": 0
          },
          "$.body.someArray[*].*": {
            "match": "type"
          },
          "$.body.transactions[*].description": {
            "match": "type"
          },
          "$.body.transactions[*].date": {
            "match": "regex",
            "regex": "\\d{4}-\\d{2}-\\d{2}"
          }
        }
      }
    }

Expected behaviour

Pact file should include the provided example description and date:

...
        "body": {
          "someArray": [
            {
              "description": "Some description",
              "date": "2018-04-04",
            }
          ]
        }
...

Improvement

eachLike(_ value: Any, min: Int = default, examples: Int = default) -> [String : Any]

Providing 2 for examples value would generate 2 entries in the Pact file.

...
        "body": {
          "someArray": [
            {
              "description": "Some description",
              "date": "2018-04-04",
            },
            {
              "description": "lasjkdhfclakushdcfmahsdlfchm",
              "date": "8731-49-62",
            }
          ]
        },
...

Remove BrightFutures dependency

Almost every new Xcode and swift version breaks due to downstream dependencies.
Reducing number of dependencies will reduce unnecessary breakages and reduce maintenance work.

This issue focuses on removing BrightFutures dependency.

How can I serve a byte array as a response body?

I am trying to mock a call to get an image from our image service. I have so far been unable to successfully provide an image to my app.

This is the service code to serve up the image (C#):

private async Task<dynamic> GetThumbnail(dynamic parameters, CancellationToken ct)
{
    string token = Request.Query["token"].ToString();

    byte[] thumbnail = await _service.GetThumbnail(token, ct);
    
    return thumbnail == null 
        ? HttpStatusCode.NotFound 
        : new ByteArrayResponse(thumbnail, "image/jpeg");
}

public ByteArrayResponse(byte[] body, string contentType)
{
    ContentType = contentType;

    Contents = stream =>
    {
        using (var writer = new BinaryWriter(stream))
        {
            writer.Write(body);
        }
    };
}

This is the pact I have written to mock the image response:

mockService
    .uponReceiving("a request for getting a thumbnail for image \(imageId)")
    .withRequest(method: .GET, path: req, query: ["token": token])
    .willRespondWith(status: 200,
                     headers: ["Content-Type": "image/jpeg",
                               "Transfer-Encoding": "chunked"],
                     body: image)

I have so far been unable to get the body to be correct. In my code, I am calling UIImage(data: body), which works fine when hitting the actual service, but returns null anytime I have used this pact.

I am using Alamofire for my requests.

I have tried the following for the body:

  1. crashes with "Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (Foundation._SwiftNSData)'"
let image = UIImageJPEGRepresentation(myUIImage, 1.0)!
  1. does not create a UIImage
let image = UIImageJPEGRepresentation(myUIImage, 1.0)!.base64EncodedString()
  1. does not create a UIImage
let image = NSKeyedUnarchiver.unarchiveObject(with: UIImageJPEGRepresentation(myUIImage, 1.0)!)
  1. does not create a UIImage
let image = getArrayOfBytesFromImage(imageData: UIImageJPEGRepresentation(myUIImage, 1.0)!)
func getArrayOfBytesFromImage(imageData: Data) -> NSMutableArray {
    let count = imageData.count / MemoryLayout<UInt8>.size
    var bytes = [UInt8](repeating: 0, count: count)
    imageData.copyBytes(to: &bytes, count:count * MemoryLayout<UInt8>.size)
    let byteArray:NSMutableArray = NSMutableArray()
    for i in 0..<count {
        byteArray.add(NSNumber(value: bytes[i]))
    }
    return byteArray
}

I am not sure what else to try to serve up the image. Any suggestions?

Extract out all the configuration options into .xcconfig files

To avoid various merge conflicts due to configuration option changes
The configuration options should be pulled into manageable .xcconfig files

Include swiftlint.sh input parameters for swiftlint binary location and configuration file in .xcconfig file and remove from the script.

Enable Matcher for path

I have a PUT request that takes uses a UUID as part of the path, but since the path argument is a String, I can't pass it a Matcher [String: AnyObject]

example of what I'd like to do:

let putReq = Matcher.term(matcher: "/^\\/v1\\/start\\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i",
                                  generate: "/v1/start/\(uuid)/")

mockService.given("a record exists")
            .uponReceiving("a request to invoke start action for new instance")
            .withRequest(method:.PUT, path: putReq)
            .willRespondWith(status:200)

Update to new pact-mock_service

Newer versions don't seem to write pacts at the end of the test by default. May need to do a POST /pact at the end of a test.

Won't compile with Xcode 10.2

Because the versions for Nimble and Quick do not compile with Xcode 10.2, also pact doesn't compile with Xcode 10.2.
I created a PR to fix that #44

Error when using somethingLike in provider response

I'm trying to use the somethingLike matcher in provider response. Doing something like the following:

func testItSaysHello() {
    var hello = "not Goodbye"
    helloProvider!.uponReceiving("a request for hello")
                  .withRequest(method:.GET, path: "/sayHello")
                  .willRespondWith(status: 200, 
                      headers: ["Content-Type": "application/json"], 
                      body: [
                          "id": Matcher.somethingLike(NSString),
                          "name": Matcher.somethingLike(NSString)
                      ]
                  )

    //Run the tests
    helloProvider!.run{ (testComplete) -> Void in
      self.helloClient!.sayHello { (response) in
        XCTAssertNonNil(response["id"])
        XCTAssertNonNil(response["name"])
        testComplete()
      }
    }

    waitForExpectationsWithTimeout(10) { (error) in }
}

When I do this, I get a crash with:

Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Invalid type in JSON write (NSString)'

(crash is on L128 in ParameterEncoding.swift in Alamofire)

Is this not the correct way to use the somethingLike matcher? How can I create a pact that just verifies the existence (and type) of a few fields in a response?

Pact tests not working with OpenCombine and Combine code

Hi, The Pact tests are not working with Combine and OpenCombine code
I have written code to download the data using OpenCombine (Tried the same using Combine). But the pact tests are not working with that code. I am getting Timeout error. On executing the Pact tests, code control never reaches the tryMap block (Code Below)

Error : "failed - test did not complete within 30.0 second timeout"
Error persists even after increasing the timeout interval

Code :

 var dataPublisher: AnyPublisher<URLSession.DataTaskPublisher.Output, URLSession.DataTaskPublisher.Failure>
       dataPublisher = URLSession.shared.dataTaskPublisher(for: url!)
            .eraseToAnyPublisher()
        return dataPublisher
            .tryMap { output in
                guard let httpResponse = output.response as? HTTPURLResponse else {
                    throw APIError.invalidResponse
                }
                guard (200..<300).contains(httpResponse.statusCode) else {
                    throw APIError.statusCode(httpResponse.statusCode)
                }
                return output.data
                
            }

(If I try to rewrite the code in imperative way, the tests works fine)

Only for Tests?

Hi,

I tried to setup using this framework in the main bundle as well. The purpose is to establish the possibility of using same mocks also in the main bundle in cases some of the API's were not implemented yet, but the app still needs to work, although only with stubbed responses.
Of course, I saw the MockService importing Nimble and rest of the frameworks that rely on XCTest. Are you considering changing this and opening functionality to the main bundle as well?

XCode 6.3

Has anyone got pact-consumer-swift working with carthage using XCode 6.3?

I've tried a few different combinations of dependencies with a forked repo changing the Cartfile but without success yet.

The carthage log is complaining about the parameters of responseString on master where the Alamofire dependency is explicitly "master" (where Alamofire has merged its branch 'xcode-6.3').

Support for writing pacts in swift with cocoapods

Hey @andrewspinks , I am trying to integrate this framework with my iOS project written in Swift 2 with Cocoapods as dependency manager.Since I wanted to avoid adding another DM with Carthage, I tried to use Cocoapods support instructions and then write tests using Swift? Not sure if it's not legitimate here? Also if I add this to my podfile , pod 'PactConsumerSwift' , it grabs older PactConsumerSwift (0.1.3) which has downstream dependency on older versions of Alamofire and BrightFutures( which is conflicting with my existing dependencies).However, I saw commits where you have updated their versions on master with framework version bumped to 0.1.5, 7971431 .
Any idea why I am not able to fetch latest framework version with cocoapods on master?

pact.io framework is not building with Xcode 11.4

Both Carthage and Xcode (11.4) can't build the current 0.8.0 version of pact-consumer-swift framework. I can see linker issues:

ld: warning: Could not find or use auto-linked library 'XCTestSwiftSupport'
ld: warning: Could not find or use auto-linked framework 'XCTest'

Update for Swift 4.2

Hi, I was wondering if there was any plan to update this repo to Swift 4.2 / XCode 10.

I am using this library in my project, which I tried to upgrade to Swift 4.2 / XCode 10. I am getting an error in the Pact Consumer Swift module saying "No such module BrightFutures". I think this is due to BrightFutures having upgraded to 4.2 but this repo has not.

`Matcher.somethingLike` not working according to the docs?

We are in the process of covering our mobile apps with contract testing using Pact tests.
After successful initial setup and tests, we started to take a step further and start testing type matching instead of strict value matching but have hit a roadblock as we cannot find swift documentation on how to use this feature and any sample codes we could find followed the same pattern as our code

this is how we are setting up helloProvider (we tested on top of the sayHello sample code):

helloProvider!.uponReceiving("a request for hello")
              .withRequest(method:.GET, path: "/sayHello")
              .willRespondWith(status: 200,
                               headers: ["Content-Type": "application/json"],
                               body: ["reply": "Hello",
                                      "user": Matcher.somethingLike("Me")])

Pact tests target compiles fine but then fails when running:
.../Pact Tests/Pact_Tests.swift:27: error: -[Pact_Tests.Pact_Tests testItSaysHello] : Error setting up pact: Error

This is obviously related to "user": Matcher.somethingLike("Me") as when we replace it with "user": "Me" the test runs fine, but we could not find any way to make it work with type matching as we need to

I assume Matcher.somethingLike works fine and its our implementation that is not ideal, but honestly speaking we did our best to search for solution across your docs but found very little regarding type matching in swift.

Thanks in advance for any support, we promise to do our best to spread the knowledge

Remove WatchOS scheme from Project

It is still not possible to run Unit Tests for WatchOS specific target/platform.

Proposing to remove the WatchOS scheme and clean up/avoid building any dependencies that are not used on/by WatchOS target.

Benefiting in build times on local machines and on CI.

Self signed SSL certificates do not work

starting the pact-mock-service with --ssl will create a self signed certificate, which will be discarded by PactVerificationService, because it is using a session without a delegate, so it is not handling didReceiveAuthenticationChallenge.
To reproduce the issue,

  • change the start script to use --ssl option
  • change the base URL of the mockService to "https://localhost"
  • run the tests.

Possible solution will be to expose the authentication challenge or just a simple bool on the PactVerificationService to allow all insecure certificates.

PactVerificationService


var allowInsecureCertificates: Bool = false


public func urlSession(_ session: URLSession,
                           didReceive challenge: URLAuthenticationChallenge,
                           completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {

        guard allowInsecureCertificates,
             challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust,
            let serverTrust = challenge.protectionSpace.serverTrust else {
                completionHandler(.performDefaultHandling, nil)
        }

        let proposedCredential = URLCredential(trust: serverTrust)
        completionHandler(URLSession.AuthChallengeDisposition.useCredential, proposedCredential)
    }

Not supporting with Swift 5.0 version

I am not able to update the carthage with Swift 5.0 (XCode 10.2).

error: compiling for iOS 9.0, but module 'Alamofire' has a minimum deployment target of iOS 10.0: $(SRCROOT)/Carthage/Checkouts/pact-consumer-swift/Carthage/Build/iOS/Alamofire.framework/Modules/Alamofire.swiftmodule/armv7.swiftmodule
import Alamofire
^

** ARCHIVE FAILED **

The following build commands failed:
CompileSwift normal arm64
CompileSwiftSources normal arm64 com.apple.xcode.tools.swift.compiler
CompileSwift normal armv7
CompileSwiftSources normal armv7 com.apple.xcode.tools.swift.compiler
(4 failures)

Remove gradle dependency from release process.

There is a release script that was largely based off another project and makes it easier to create consistent releases (especially with the cocoapods workflow). However, as its written in groovy it is a pain for other people to install and get to work. Converting it to something installed by default on osx would be ideal.

You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. file

HI!
I've been trying to build and run an application which Test target depends on PactConsumerSwift (via CocoaPods) on a real device and encountered this error:

ld: '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework/XCTest' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from the vendor, or disable bitcode for this target. file '/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/Library/Frameworks/XCTest.framework/XCTest' for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)

Apparently, this happens due to enabled bitcode (although it shouldn't be). PactConsumerSwift's dependency (Nimble) had the same issue, which was successfully resolved.

So in order to fix it we should set 'ENABLE_BITCODE' to 'NO' in the podspec.

I will try to fix this on my own if I'll have some time. If you face this problem too, the workaround is to put this to your Podfile:

post_install do |installer|
            if target.name == 'PactConsumerSwift'
              target.build_configurations.each do |config|
                   config.build_settings['ENABLE_BITCODE'] = 'NO'
              end
          end
end

Connection Error when working with pact mock service enabling ssl

Hello!

Trying to setup a PoC for a Swift project, enabling ssl in the pact-mock-service lead us to the error message shown in the below image:
Captura de pantalla 2021-01-27 a las 22 12 04

The server is launched using:
pact-mock-service start --ssl --pact-specification-version 2.0.0 --log "${SRCROOT}/tmp/pact-ssl.log" --pact-dir "${SRCROOT}/tmp/pacts-ssl" -p 1234

The PactVerificationService is instantiated allowing insecure certificates:
Captura de pantalla 2021-01-27 a las 22 19 42

Yet it seems it is not to accept the self signed certificate:

Captura de pantalla 2021-01-27 a las 22 19 24

Have you guys faced this kind of issue?

Thanks in advance.

Remove the need for manually verifying the interactions were met on every test

At the moment in all test setup we require the verification result to be checked. e.g.

MockService(provider: "Animal Service", consumer: "Animal Consumer Swift", done: { result in
      expect(result).to(equal(PactVerificationResult.Passed))
})

Now that swift supports exceptions, we should be able to just throw an exception if PactVerificationResult is not successful.

Quick dependency causing conflict.

Steps to reproduce:

  • Add the LaunchDarkly library with Swift Package Manager (version 5.2.0)
  • Add the pact-consumer-swift latest.

I get the error bellow:
image

Have you folks foreseen any action/work around for that version conflict on SPM? this can be a big issue since many libraries have Quick as dependency.

Thanks!

Cocaopods support

Can this project include a podspec so that it can be included via Cocoapods?

ATS blocking mockserver interaction

I was setting up pact-consumer-swift following your guide but struggling currently during the execution of my contract test.

By default my test is failing due to an ATS error:

Error Domain=NSURLErrorDomain Code=-1022 "The resource could not be loaded because the App Transport Security policy requires the use of a secure connection." UserInfo={NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection., NSErrorFailingURLStringKey=http://localhost:1234/interactions/verification, NSErrorFailingURLKey=http://localhost:1234/interactions/verification
[...]
Verification error (check build log for mismatches): The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.

Also setting the following settings to my TestTarget's Info.plist does not work:

<key>NSExceptionDomains</key>
	<dict>
		<key>localhost</key>
		<dict>
			<key>NSExceptionAllowsInsecureHTTPLoads</key>
			<true/>
		</dict>
	</dict>

It does work though when setting it to the actual App-Target's plist, where I am then able to successfully run my contract test.
But setting it on the App generally is not what I want, also when looking at it from a security point of view or regarding a potential AppStore review.

How are you guys dealing with it normally?
I haven't found anything related to ATS in the docs here or in any example project.

Separate Pact providers generated files contain all the pacts

General
Setting different providers in same tests run (provider when creating MockServer instance) doesn't generate correct output (pact json files). All the pacts are generated for every provider file. This is an issue because we need to generate (and later upload) separate pacts files for different providers.

Example Issue
There are two providers: provider1 and provider2. MockService instance is created for each pact test. Provider for each test is set in initialiser:

public init(
    provider: String,
    consumer: String,
    pactVerificationService: PactVerificationService,
    errorReporter: ErrorReporter
  )

in test it looks:

class Pact1Tests: XCTestCase {
  func testPact1() {
    let mockServer = MockService(
        provider: "provider1",
        consumer: "consumer",
        pactVerificationService: PactVerificationService(url: <url>, port: 1234),
        errorReporter: Errors()
    )
    ...
  }
}

Remark: if you do it in override func setUp() - issue is still there.

After all tests finished, two pact files are generated: consumer-provider1.json and consumer-provider2.json.
If generated file is opened, you can see that all the tests, even if created MockServer instance for specific test had different provider name, are in that json.

Workaround
If you run tests separately for just provider1 and when just for provider2 (e.g. using test plans) files are generated correctly.

Summary
Probably the issue is with provider parameter propagation and file generation.

I hope this information is enough. I can try to provide more info if needed.

P.S. when we run pact ruby mock server we do not specify consumer and provider as we do it in code when we are creating MockServer instance.
pact-mock-service start --pact-specification-version $PACT_SPEC_VERSION --log $LOG --pact-dir $PACTS -p $PORT

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.