bbyars / mountebank

Over the wire test doubles
http://www.mbtest.org
MIT License
2k stars 268 forks source link

Trouble Getting CLI --origin Flag To Work #626

Open tparikka opened 3 years ago

tparikka commented 3 years ago

I'm attempting to use Mountebank in between a front-end website and an ASP.NET Core API to facilitate automated UI testing. Reading the release notes for v2.3.3 I see that the --origin CLI flag is required to accept requests from a different origin. I ran mb with the origin flag and created my imposter with the allowCORS option set true, but still get a CORS error. Thank you in advance for any help you can offer!

Expected behaviour

When starting mountebank with npx mb --origin "http://app.local.com", I would expect that requests made to Mountebank from a different origin with a header of "Origin":"http://app.local.com" should succeed.

Actual behaviour

When I try to request data from Mountebank from a different origin I get the error Access to XMLHttpRequest at 'http://app.local.com:8080/api/case/search/' from origin 'http://app.local.com' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.

Steps to reproduce

  1. Launch Mountebank with npx mb --origin "http://app.local.com"
  2. Create a new imposter:
    {
    "protocol": "http",
    "port": 8080,
    "allowCORS": true,
    "name": "TestName",
    "stubs": [
        {
            "predicates": [
                {
                    "equals": {
                        "method": "POST",
                        "path": "/api/case/search/"
                    }
                }
            ],
            "responses": [1,2,3]
        }
    ]
    }
  3. From the browser with an XMLHttpRequest, make a request to the mountebank imposter
  4. Error comes back to browser I tried adding the stub at https://github.com/bbyars/mountebank-in-action/blob/master/ch07/examples/cors.json to my imposter with no change in results.

Software versions used

OS         : Windows 10 Version 20H2
mountebank : 2.4.0
node.js    : 7.16.0
  (only if installed via npm)
Installation method : npm
Browser: Chrome 91.0.4472.77

Log contents in mb.log when running mb --loglevel debug

PS C:\src> npx mb start --origin 'http://app.local.com' --origin "http://127.0.0.1" --loglevel debug
info: [mb:2525] mountebank v2.4.0 now taking orders - point your browser to http://localhost:2525/ for help
debug: [mb:2525] config: {"options":{"origin":["http://app.local.com","http://127.0.0.1"],"port":2525,"noParse":false,"no-parse":false,"formatter":"mountebank-formatters","pidfile":"mb.pid","allowInjection":false,"allow-injection":false,"localOnly":false,"local-only":false,"ipWhitelist":["*"],"ip-whitelist":"*","mock":false,"debug":false,"heroku":false,"protofile":"protocols.json","log":{"level":"debug","transports":{"console":{"colorize":true,"format":"%level: %message"},"file":{"path":"mb.log","format":"json"}}}},"process":{"nodeVersion":"v14.16.0","architecture":"x64","platform":"win32"}}
info: [mb:2525] POST /imposters
debug: [mb:2525] ::1:53304 => {"protocol":"http","port":8080,"allowCORS":true,"name":"TestName","stubs":[{"predicates":[{"equals":{"method":"POST","path":"/api/case/search/"}}],"responses":[{"is":{"statusCode":200,"headers":{"Content-Type":"application/json"},"body":SNIP}}]}]}
info: [http:8080 TestName] Open for business...
debug: [http:8080 TestName] ::ffff:127.0.0.1:51258 ESTABLISHED
info: [http:8080 TestName] ::ffff:127.0.0.1:51258 => OPTIONS /api/case/search/
debug: [http:8080 TestName] ::ffff:127.0.0.1:51258 => {"requestFrom":"::ffff:127.0.0.1:51258","method":"OPTIONS","path":"/api/case/search/","query":{},"headers":{"Host":"app.local.com:8080","Connection":"keep-alive","Accept":"*/*","Access-Control-Request-Method":"POST","Access-Control-Request-Headers":"content-type","Origin":"http://app.local.com","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","Sec-Fetch-Mode":"cors","Referer":"http://app.local.com/","Accept-Encoding":"gzip, deflate","Accept-Language":"en-US,en;q=0.9"},"body":"","ip":"::ffff:127.0.0.1"}
info: [http:8080 TestName] no predicate match, using default response
debug: [http:8080 TestName] generating response from {"is":{}}
debug: [http:8080 TestName] ::ffff:127.0.0.1:51258 <= {"statusCode":200,"headers":{"Access-Control-Allow-Headers":"content-type","Access-Control-Allow-Methods":"POST","Access-Control-Allow-Origin":"http://app.local.com","Connection":"close"},"body":"","_mode":"text"}
debug: [http:8080 TestName] ::ffff:127.0.0.1:51258 CLOSED
debug: [http:8080 TestName] ::ffff:127.0.0.1:49981 ESTABLISHED
info: [http:8080 TestName] ::ffff:127.0.0.1:49981 => POST /api/case/search/
debug: [http:8080 TestName] ::ffff:127.0.0.1:49981 => {"requestFrom":"::ffff:127.0.0.1:49981","method":"POST","path":"/api/case/search/","query":{},"headers":{"Host":"app.local.com:8080","Connection":"keep-alive","Content-Length":"67","User-Agent":"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.77 Safari/537.36","Content-Type":"application/json","Accept":"*/*","Origin":"http://app.local.com","Referer":"http://app.local.com/","Accept-Encoding":"gzip, deflate","Accept-Language":"en-US,en;q=0.9"},"body":"{\"param1\":\"633\",\"searchParameters\":{\"searchTerm\":\"abc16\"}}","ip":"::ffff:127.0.0.1"}
debug: [http:8080 TestName] using predicate match: [{"equals":{"method":"POST","path":"/api/case/search/"}}]
debug: [http:8080 TestName] generating response from {"is":{"statusCode":200,"headers":{"Content-Type":"application/json"},"body":SNIP}}
debug: [http:8080 TestName] ::ffff:127.0.0.1:49981 <= {"statusCode":200,"headers":{"Content-Type":"application/json","Connection":"close"},"body":"SNIP","_mode":"text"}
debug: [http:8080 TestName] ::ffff:127.0.0.1:49981 CLOSED
tparikka commented 3 years ago

I made a change to my imposter, adding "Access-Control-Allow-Origin": "http://app.local.com" to the headers of my response and that got things going. I'm new-ish to CORS, so I'm wondering is it just understood that I have to explicitly add that header to each of my responses where I expect to be making a request cross-origin? I had thought that adding the origin in the startup of Mountebank would handle that part for me.

This also appears to impact proxy response types, because the proxy doesn't return the Access-Control-Allow-Origin header. Unlike the is response type, I don't think I can actually work around this because the proxy doesn't allow for injection of headers.

ThyagoMC commented 2 years ago

I worked on a little project that could be helpful: https://github.com/sidilabs/mock-server

This project creates a gulp task to communicate with Mountebank and generate a series of imposters following a defined structure, even if you don't plan to use the project as it is, you could use some of the code to solve a specific problem.