<#1224 V4InteractionWithCompleteRequest is unimple...
# pact-js-development
g
#1224 V4InteractionWithCompleteRequest is unimplemented Issue created by shishkin I'm trying to write a pact for multipart/form-data with file upload. When I use V4 DSL
withRequest
I get body content type mismatch because my test uses random boundary for multipart body. Then I tried
withCompleteRequest
so I can just use
regex
matcher for the body. PactJS gives me
Error: V4InteractionWithCompleteRequest is unimplemented
. Software versions • OS: MacOS 14.5 • Consumer Pact library: Pact JS 12.5.2 • Provider Pact library: Pact JS 12.5.2 • Node Version: v20.11.1 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 There should be a way to relax request matching while still providing a specific example for provider verification. Actual behaviour
Error: V4InteractionWithCompleteRequest is unimplemented
Steps to reproduce
Copy code
await new PactV4({
        provider: "P",
        consumer: "C",
        logLevel: "debug",
    })
    .addInteraction()
    .uponReceiving("...")
    .withCompleteRequest({
        method: "POST",
        path: "/upload-file",
        headers: {
            accept: M.regex(/application\/json/, "application/json"),
            "content-type": M.regex(
                /^multipart\/form-data.+$/,
                `multipart/form-data; boundary=${boundary}`,
            ),
        },
        body: M.regex(/.*/, bodyBuffer.toString("utf-8")),
    })
    .withCompleteResponse({
        status: 200,
        contentType: "application/json; charset=utf-8",
        body: {
            success: true,
        },
    })
    .executeTest(async (server) => {
        const form = new FormData();
        form.append("uploadPath", "/blog");
        form.append(
            "files",
            await openAsBlob(testImagePath),
            "image.png",
        );
        await fetch(new URL("/upload-file", server.url), {
            method: "POST",
            headers: {
                accept: "application/json",
            },
            body: form,
        });
    });
Relevant log files
Copy code
2024-06-21T05:18:39.925518Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server:
      ----------------------------------------------------------------------------------------
       method: POST
       path: /upload-file
       query: None
       headers: Some({"connection": ["keep-alive"], "host": ["127.0.0.1:58624"], "accept-language": ["*"], "accept-encoding": ["gzip", "deflate"], "content-length": ["363"], "accept": ["application/json"], "user-agent": ["node"], "sec-fetch-mode": ["cors"], "content-type": ["multipart/form-data; boundary=----formdata-undici-074263581352"]})
       body: Present(363 bytes, multipart/form-data;boundary=----formdata-undici-074263581352)
      ----------------------------------------------------------------------------------------

2024-06-21T05:18:39.925555Z  INFO tokio-runtime-worker pact_matching: comparing to expected HTTP Request ( method: POST, path: /upload-file, query: None, headers: Some({"accept": ["application/json"], "content-type": ["multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"]}), body: Present(362 bytes) )
2024-06-21T05:18:39.925564Z DEBUG tokio-runtime-worker pact_matching:      body: '2D2D2D2D5765624B6974466F726D426F756E64617279374D41345957786B5472... (362 bytes)'
2024-06-21T05:18:39.925565Z DEBUG tokio-runtime-worker pact_matching:      matching_rules: MatchingRules { rules: {BODY: MatchingRuleCategory { name: BODY, rules: {DocPath { path_tokens: [Root], expr: "$" }: RuleList { rules: [ContentType("multipart/form-data")], rule_logic: And, cascaded: false }} }, PATH: MatchingRuleCategory { name: PATH, rules: {} }, HEADER: MatchingRuleCategory { name: HEADER, rules: {DocPath { path_tokens: [Root, Field("content-type")], expr: "$['content-type']" }: RuleList { rules: [Regex("^multipart\\/form-data.+$")], rule_logic: And, cascaded: false }} }} }
2024-06-21T05:18:39.925573Z DEBUG tokio-runtime-worker pact_matching:      generators: Generators { categories: {} }
2024-06-21T05:18:39.925594Z DEBUG tokio-runtime-worker pact_matching::matchers: String -> String: comparing '/upload-file' to '/upload-file' ==> true cascaded=false matcher=Equality
2024-06-21T05:18:39.925602Z DEBUG tokio-runtime-worker pact_matching: expected content type = 'multipart/form-data;boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW', actual content type = 'multipart/form-data;boundary=----formdata-undici-074263581352'
2024-06-21T05:18:39.925619Z DEBUG tokio-runtime-worker pact_matching: content type header matcher = 'RuleList { rules: [], rule_logic: And, cascaded: false }'
2024-06-21T05:18:39.925670Z DEBUG tokio-runtime-worker pact_matching::matchers: String -> String: comparing 'multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' to 'multipart/form-data; boundary=----formdata-undici-074263581352' ==> true cascaded=false matcher=Regex("^multipart\\/form-data.+$")
2024-06-21T05:18:39.925677Z DEBUG tokio-runtime-worker pact_matching: --> Mismatches: [BodyTypeMismatch { expected: "multipart/form-data;boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW", actual: "multipart/form-data;boundary=----formdata-undici-074263581352", mismatch: "Expected a body of 'multipart/form-data;boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' but the actual content type was 'multipart/form-data;boundary=----formdata-undici-074263581352'", expected_body: Some(b"----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"files\"; filename=\"white.png\"\nContent-Type: application/octet-stream\n\n\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\0\x01\0\0\0\x01\x08\x06\0\0\0\x1f\x15\xc4\x89\0\0\0\x01sRGB\0\xae\xce\x1c\xe9\0\0\0\rIDAT\x18Wc\xf8\xff\xef\xdf\x7f\0\t\xf6\x03\xfbW\xfe{\x1b\0\0\0\0IEND\xaeB`\x82\n----WebKitFormBoundary7MA4YWxkTrZu0gW\nContent-Disposition: form-data; name=\"uploadPath\"\n\n/blog\n----WebKitFormBoundary7MA4YWxkTrZu0gW\n"), actual_body: Some(b"------formdata-undici-074263581352\r\nContent-Disposition: form-data; name=\"uploadPath\"\r\n\r\n/blog\r\n------formdata-undici-074263581352\r\nContent-Disposition: form-data; name=\"files\"; filename=\"image.png\"\r\nContent-Type: application/octet-stream\r\n\r\n\x89PNG\r\n\x1a\n\0\0\0\rIHDR\0\0\0\x01\0\0\0\x01\x08\x06\0\0\0\x1f\x15\xc4\x89\0\0\0\x01sRGB\0\xae\xce\x1c\xe9\0\0\0\rIDAT\x18Wc\xf8\xff\xef\xdf\x7f\0\t\xf6\x03\xfbW\xfe{\x1b\0\0\0\0IEND\xaeB`\x82\r\n------formdata-undici-074263581352--") }]
2024-06-21T05:18:39.925738Z DEBUG tokio-runtime-worker pact_mock_server::hyper_server: Request did not match: Request did not match - HTTP Request ( method: POST, path: /upload-file, query: None, headers: Some({"accept": ["application/json"], "content-type": ["multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW"]}), body: Present(362 bytes) )    0) Expected a body of 'multipart/form-data;boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' but the actual content type was 'multipart/form-data;boundary=----formdata-undici-074263581352'
pact-foundation/pact-js