Looping through all HTTP methods in a postman test

Hi,

I’m investigating into postman and it looks good. Is there possibility to somehow make postman use a list of methods for single test (script). For example in pytest I can write something like this.

@pytest.mark.parametrize('path', ['/profiles/1/days/1'])
@pytest.mark.parametrize('method', ['POST', 'PUT', 'DELETE', 'PATCH', 'CONNECT'])
def test_must_return_405_method_not_allowed_for_any_distinct_from_GET_request(sut_base_url, path, method):
    response = requests.request(method, urljoin(sut_base_url, path))
    data = response.json()
    assert response.status_code == 405
    assert data['data'] == dict()
    assert data['meta']['result'] == 'error'
    assert data['meta']['desc'] == 'Method not allowed'
    assert re.match(r'[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}', data['meta']['id']) is not None

This will actually create 5 tests and run it for every method designated in the pytest.mark.parametrize list passing over method as actual argument. But with postman I have to create distinct request for every METHOD (see in the picture please) and copy paste test body (script). Is it possible to achieve what I’m asking about?

Thank you.

Hey @y4x :wave:

Welcome to the Postman Community! :postman:

You could check that in an async request from the Post-response section. I used Postbot to create this script but a simplified version of this could also be used:

// Define the HTTP methods
const httpMethods = ['POST', 'PUT', 'DELETE', 'PATCH', 'CONNECT'];
const base_url = pm.environment.get('API_BASE_URL');

// Create an async function to send requests for each HTTP method
async function check405StatusForAllMethods() {
    for (const method of httpMethods) {
        await new Promise((resolve, reject) => {
            pm.sendRequest({
                url: base_url,
                method: method,
                header: {
                    'Content-Type': 'application/json'
                }
            }, (err, res) => {
                pm.test(`Status code is 405 for ${method}`, () => {
                    pm.expect(res).to.have.status(200);
                });
                resolve();
            });
        });
    }
}

// Call the async function
check405StatusForAllMethods();

Another option for consideration.

Using setNextRequest to control the loop instead of sendRequest().

This is using a method available to array’s called shift(). This retrieves the first element in the array (and also deletes it from the array).

This will be what we use to control the loop (while the array length is > 0).

I’m using Postman Echo so I’ve removed the ‘Connect’ option as it takes a while to time out.

In your pre-request script.

if (typeof methods === 'undefined' || methods.length == 0) {
    methods = ['POST', 'PUT', 'DELETE', 'PATCH'];
    pm.environment.unset("method");
}

let currentMethod = methods.shift();

pm.request.method = currentMethod;
pm.request.url.path = '/profiles/1/days/1';

pm.environment.set("method", currentMethod); 
// needed so the value can be read in the post response script

if (methods.length > 0) {
    currentRequest = pm.info.requestName;
    pm.execution.setNextRequest(currentRequest);
}

In your post-response script.

You can retrieve the current method (for a custom test case name), and then test the status.

I’ve used 404 instead of 405 because I’m using Postman Echo and that is what it returns.

let currentMethod = pm.variables.get("method");

pm.test(`${currentMethod} - Status code is 404`, () => {
  pm.response.to.have.status(404);
});

You can see in the console logs that this run once against each method. The query parameter on the end comes from my original GET request. This can also be targetted using the pm.request() function as we do for the method and path.

With the relevant test results.

Pros and cons to note. setNextRequest requires the collection runner to work, where sendRequest() does not.

If you’re feeling more adventurous, you could even create a datafile with your methods and iterate through those in the Collection Runner :smiley:

As you can see, Postman is flexible enough to provide you with a number of different ways to achieve the same thing.

Thank you lads!

These methods work, but there are couple issues I ran into. The first one is with CONNECT method. The test runner hangs up on this method. I see that server responds with 405. But postman gets stuck.

The second one is related to datafile. This datafile is applied to every test in collection. So if I have something like this in the file all tests are run five times unconditionally. But data are only used by one of them actually.

[
  {"method": "PATCH"},
  {"method": "POST"},
  {"method": "PUT"},
  {"method": "DELETE"},
  {"method": "CONNECT"}
]

I had the same issue with “CONNECT” when hitting the Postman Echo API which is why I removed it from the array when I tested it.

Not sure if its a Postman issue or just how servers generally respond to a connect request if the API doesn’t support it.

Can you clarify the query about the datafile?

The data file will run against every “request” in your collection. Once for each object in your array. Your request may have tests, or can have no tests at all. (Just wanted to call out the distinction between requests and tests).

If you only want to loop on one request in your collection. Then sendRequest() or setNextRequest() would be the better options.

I tried to override Connection header with Connection:close, but it doesn’t matter. Looks like the tcp client under the hood opens and keeps connection though it should go like this in case of 200 OK, but I have 405 response. But frankly I don’t see any opened connection via ss -np --tcp.

Regarding datafile I mean as you said it runs all requests for every item in datafile. But I need to “parametrize” the only one request. So yes it’s not the case here.

I think I’ll get back to pytest due to I didn’t find benefits for me. I thought I can get fuzzing out of the box. The only benefits are collaboration ecosystem and GUI that I don’t need.

Thank you for your time and response.