Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Content type of expected request isn't honoured #963

Closed
4 of 5 tasks
gruntster opened this issue Oct 20, 2022 · 3 comments
Closed
4 of 5 tasks

Content type of expected request isn't honoured #963

gruntster opened this issue Oct 20, 2022 · 3 comments
Labels
bug Indicates an unexpected problem or unintended behavior

Comments

@gruntster
Copy link

Software versions

  • OS: Ubuntu 22.04.1 LTS
  • Consumer Pact library: 10.1.4
  • Node Version: 16.18.0

Issue Checklist

Please confirm the following:

  • I have upgraded to the latest
  • I have the read the FAQs in the Readme
  • I have triple checked, that there are no unhandled promises in my code and have read the section on intermittent test failures
  • I have set my log level to debug and attached a log file showing the complete request/response cycle
  • For bonus points and virtual high fives, I have created a reproduceable git repository (see below) to illustrate the problem

Expected behaviour

The content type of the consumer's request is matched against the corresponding content type of the registered Interaction (v2). Substituting the Pact library with version 9.18.1 works as expected.

Actual behaviour

The content type of the consumer's request is expected to be application/json regardless of Interaction's content type.

  Mock server failed with the following mismatches:

        0) The following request was incorrect:

                PUT /dogs

                         1.0 Expected body with content type application/json but was application/vnd.dog.farm+json

Steps to reproduce

package.json

{
  "dependencies": {
    "@pact-foundation/pact": "10.1.4",
    "got": "11.8.5",
    "ts-node": "10.9.1"
  }
}

test.ts

import { Interaction, Pact } from "@pact-foundation/pact";
import got from "got";
import * as path from "node:path";

async function test(): Promise<void> {
    const provider = new Pact({
        dir: path.resolve(process.cwd(), "pacts"),
        consumer: "MyConsumer",
        provider: "MyProvider",
        logLevel: "debug"
    });

    await provider.setup();

    await provider.addInteraction(
        new Interaction()
            .given("I have a list of dogs")
            .uponReceiving("a request to replace the list")
            .withRequest({
                method: "PUT",
                path: "/dogs",
                headers: { "content-type": "application/vnd.dog.farm+json" },
                body: { dog: "poodle" }
            })
            .willRespondWith({ status: 200 }));

    try {
        await got.put(
            `${provider.mockService.baseUrl}/dogs`, {
                headers: { "content-type": "application/vnd.dog.farm+json" },
                json: { dog: "poodle" },
                retry: 0
            });
    }
    catch (error) { }

    await provider.verify();
    await provider.finalize();
}

void test();

Steps

  1. npm i
  2. npx ts-node test.ts

Relevant log files

test.txt

@gruntster gruntster added the bug Indicates an unexpected problem or unintended behavior label Oct 20, 2022
@mefellows
Copy link
Member

I've just reproduced this, thanks for raising. It seems that it's a problem for any json type that isn't application/json (with any parameters).

I can also see that Pact JS is passing on the correct content type to the core, and it is storing the correct content type in the Pact Handle.

2022-10-20T11:03:18.049033Z TRACE ThreadId(01) pactffi_create_mock_server_for_pact{pact=PactHandle { pact_ref: 1 } addr_str=0x16d380e48 tls=false}: pact_ffi::mock_server::handles: with_pact after - ref = 1, inner = RefCell { value: PactHandleInner { pact: V4Pact { consumer: Consumer { name: "e2e Consumer Example" }, provider: Provider { name: "e2e Provider Example" }, interactions: [SynchronousHttp { id: None, key: None, description: "a request to create a new mate", provider_states: [ProviderState { name: "is authenticated", params: {} }], request: HttpRequest { method: "POST", path: "/animals", query: None, headers: Some({"Content-Type": ["application/foo.json"], "Authorization": ["Bearer token"]}), body: Present(b"{\"value\":{\"id\":2,\"available_from\":\"2017-12-04T14:47:18.582Z\",\"first_name\":\"Nanny\",\"animal\":\"goat\",\"last_name\":\"Doe\",\"age\":27,\"gender\":\"F\",\"location\":{\"description\":\"Werribee Zoo\",\"country\":\"Australia\",\"post_code\":3000},\"eligibility\":{\"available\":true,\"previously_married\":true},\"interests\":[\"walks in the garden/meadow\",\"parkour\"]},\"pact:matcher:type\":\"type\"}", None, None), matching_rules: MatchingRules { rules: {HEADER: MatchingRuleCategory { name: HEADER, rules: {DocPath { path_tokens: [Root, Field("Authorization")], expr: "$.Authorization" }: RuleList { rules: [Regex("Bearer\\s[a-z0-9]+")], rule_logic: And, cascaded: false }} }, PATH: MatchingRuleCategory { name: PATH, rules: {} }} }, generators: Generators { categories: {} } }, response: HttpResponse { status: 200, headers: Some({"Content-Type": ["application/json; charset=utf-8"]}), body: Present(b"{\"age\":27,\"animal\":\"goat\",\"available_from\":\"2017-12-04T14:47:18.582Z\",\"eligibility\":{\"available\":true,\"previously_married\":true},\"first_name\":\"Nanny\",\"gender\":\"F\",\"id\":2,\"interests\":[\"walks in the garden/meadow\",\"parkour\"],\"last_name\":\"Doe\",\"location\":{\"country\":\"Australia\",\"description\":\"Werribee Zoo\",\"post_code\":3000}}", Some(ContentType { main_type: "application", sub_type: "json", attributes: {}, suffix: None }), None), matching_rules: MatchingRules { rules: {BODY: MatchingRuleCategory { name: BODY, rules: {DocPath { path_tokens: [Root], expr: "$" }: RuleList { rules: [Type], rule_logic: And, cascaded: false }} }, HEADER: MatchingRuleCategory { name: HEADER, rules: {} }} }, generators: Generators { categories: {} } }, comments: {}, pending: false, plugin_config: {}, interaction_markup: InteractionMarkup { markup: "", markup_type: "" }, transport: None }], metadata: {"pact-js": Object({"version": String("10.1.2")}), "pactRust": Object({"ffi": String("0.3.8")})}, plugin_data: [] }, mock_server_started: true, specification_version: V2 } }

This leads me to believe there is some further processing downstream of this that downcasts it to a general JSON mime type.

@gruntster
Copy link
Author

This is fixed with pact-core 13.11.3. Thanks!

@mefellows
Copy link
Member

Awesome! Thanks for confirming 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Indicates an unexpected problem or unintended behavior
Projects
None yet
Development

No branches or pull requests

2 participants