Bug: [BUG] collections fail to import if variable is not a string



Newman runner i.e., newman-dir does support dynamic values but only string variables and not other variables say integer. Hence, variables like `"{{value}}"` is the only way for you to export the collection json file to its directory structure and having the variables like `{{value}}` will result in the `dir-export` / `dir-import` commands to fail.  

This bug affects collections that use dynamic values for amount fields. One such connector is NMI which has a hard limit on transactions i.e., once a payment for a n amount is done, the payment cannot be repeated up until the next 20 mins. If not, the payment is flagged as duplicate. The only work around for this is to use dynamic values. But that is restricted because of this bug with `newman-dir`. 

One work around that we can do is to:

- export the collection to its json format
- remove double quotes (`\"`) for integer fields
- run the collection -- json and not dir
- and all this should happen in run time

Example:

```sh
newman dir-import -o /tmp/generated_collection.json
perl -pi -e 's/\\"{{value}}\\"/{{value}}/g' /tmp/generated_collection.json
newman run /tmp/generated_collection.json
```

We can use `sed` / `regex` instead of `perl` as well.

Reference:
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=9a9eef47fb334cb686b2fff360e09536
https://play.rust-lang.org/?version=stable&mode=debug&edition=2021&gist=4e5ead4663c85da803b0a2c2030852eb
https://regex101.com/r/G6iapi/1
https://www.regular-expressions.info/named.html

diff --git a/Cargo.lock b/Cargo.lock
index 2c9293c1701..7823e917ed5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4977,14 +4977,14 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.9.6"
+version = "1.10.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ebee201405406dbf528b8b672104ae6d6d63e6d118cb10e4d51abbc7b58044ff"
+checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-automata 0.3.9",
- "regex-syntax 0.7.5",
+ "regex-automata 0.4.5",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
@@ -4998,13 +4998,13 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.3.9"
+version = "0.4.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59b23e92ee4318893fa3fe3e6fb365258efbfe6ac6ab30f090cdcbb7aa37efa9"
+checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd"
 dependencies = [
  "aho-corasick",
  "memchr",
- "regex-syntax 0.7.5",
+ "regex-syntax 0.8.2",
 ]
 
 [[package]]
@@ -5031,6 +5031,12 @@ version = "0.7.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
 
+[[package]]
+name = "regex-syntax"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
+
 [[package]]
 name = "rend"
 version = "0.4.1"
@@ -6356,6 +6362,7 @@ dependencies = [
  "clap",
  "masking",
  "rand 0.8.5",
+ "regex",
  "reqwest",
  "serde",
  "serde_json",
diff --git a/crates/test_utils/Cargo.toml b/crates/test_utils/Cargo.toml
index ceb188b74db..59ff36e6cc5 100644
--- a/crates/test_utils/Cargo.toml
+++ b/crates/test_utils/Cargo.toml
@@ -17,6 +17,7 @@ async-trait = "0.1.68"
 base64 = "0.21.2"
 clap = { version = "4.3.2", default-features = false, features = ["std", "derive", "help", "usage"] }
 rand = "0.8.5"
+regex = "1.10.3"
 reqwest = { version = "0.11.18", features = ["native-tls"] }
 serde = { version = "1.0.193", features = ["derive"] }
 serde_json = "1.0.108"
diff --git a/crates/test_utils/src/main.rs b/crates/test_utils/src/main.rs
index 22c91e063d8..006075895b5 100644
--- a/crates/test_utils/src/main.rs
+++ b/crates/test_utils/src/main.rs
@@ -16,28 +16,20 @@ fn main() {
     };
     let status = child.wait();
 
-    if runner.file_modified_flag {
-        let git_status = Command::new("git")
-            .args([
-                "restore",
-                format!("{}/event.prerequest.js", runner.collection_path).as_str(),
-            ])
-            .output();
+    // Filter out None values leaving behind Some(Path)
+    let paths: Vec<String> = runner.modified_file_paths.into_iter().flatten().collect();
+    let git_status = Command::new("git").arg("restore").args(&paths).output();
 
-        match git_status {
-            Ok(output) => {
-                if output.status.success() {
-                    let stdout_str = String::from_utf8_lossy(&output.stdout);
-                    println!("Git command executed successfully: {stdout_str}");
-                } else {
-                    let stderr_str = String::from_utf8_lossy(&output.stderr);
-                    eprintln!("Git command failed with error: {stderr_str}");
-                }
-            }
-            Err(e) => {
-                eprintln!("Error running Git: {e}");
+    match git_status {
+        Ok(output) => {
+            if !output.status.success() {
+                let stderr_str = String::from_utf8_lossy(&output.stderr);
+                eprintln!("Git command failed with error: {stderr_str}");
             }
         }
+        Err(e) => {
+            eprintln!("Error running Git: {e}");
+        }
     }
 
     let exit_code = match status {
diff --git a/crates/test_utils/src/newman_runner.rs b/crates/test_utils/src/newman_runner.rs
index 961853548a2..e70c630cffe 100644
--- a/crates/test_utils/src/newman_runner.rs
+++ b/crates/test_utils/src/newman_runner.rs
@@ -1,7 +1,14 @@
-use std::{env, io::Write, path::Path, process::Command};
+use std::{
+    env,
+    fs::{self, OpenOptions},
+    io::{self, Write},
+    path::Path,
+    process::{exit, Command},
+};
 
 use clap::{arg, command, Parser};
 use masking::PeekInterface;
+use regex::Regex;
 
 use crate::connector_auth::{ConnectorAuthType, ConnectorAuthenticationMap};
 #[derive(Parser)]
@@ -33,14 +40,24 @@ struct Args {
 
 pub struct ReturnArgs {
     pub newman_command: Command,
-    pub file_modified_flag: bool,
+    pub modified_file_paths: Vec<Option<String>>,
     pub collection_path: String,
 }
 
-// Just by the name of the connector, this function generates the name of the collection dir
+// Generates the name of the collection JSON file for the specified connector.
+// Example: CONNECTOR_NAME="stripe" -> OUTPUT: postman/collection-json/stripe.postman_collection.json
+#[inline]
+fn get_collection_path(name: impl AsRef<str>) -> String {
+    format!(
+        "postman/collection-json/{}.postman_collection.json",
+        name.as_ref()
+    )
+}
+
+// Generates the name of the collection directory for the specified connector.
 // Example: CONNECTOR_NAME="stripe" -> OUTPUT: postman/collection-dir/stripe
 #[inline]
-fn get_path(name: impl AsRef<str>) -> String {
+fn get_dir_path(name: impl AsRef<str>) -> String {
     format!("postman/collection-dir/{}", name.as_ref())
 }
 
@@ -72,22 +89,34 @@ pub fn generate_newman_command() -> ReturnArgs {
     let base_url = args.base_url;
     let admin_api_key = args.admin_api_key;
 
-    let collection_path = get_path(&connector_name);
+    let collection_path = get_collection_path(&connector_name);
+    let collection_dir_path = get_dir_path(&connector_name);
     let auth_map = ConnectorAuthenticationMap::new();
 
     let inner_map = auth_map.inner();
 
-    // Newman runner
-    // Depending on the conditions satisfied, variables are added. Since certificates of stripe have already
-    // been added to the postman collection, those conditions are set to true and collections that have
-    // variables set up for certificate, will consider those variables and will fail.
+    /*
+    Newman runner
+    Certificate keys are added through secrets in CI, so there's no need to explicitly pass it as arguments.
+    It can be overridden by explicitly passing certificates as arguments.
+
+    If the collection requires certificates (Stripe collection for example) during the merchant connector account create step,
+    then Stripe's certificates will be passed implicitly (for now).
+    If any other connector requires certificates to be passed, that has to be passed explicitly for now.
+    */
 
     let mut newman_command = Command::new("newman");
-    newman_command.args(["dir-run", &collection_path]);
+    newman_command.args(["run", &collection_path]);
     newman_command.args(["--env-var", &format!("admin_api_key={admin_api_key}")]);
     newman_command.args(["--env-var", &format!("baseUrl={base_url}")]);
 
-    if let Some(auth_type) = inner_map.get(&connector_name) {
+    let custom_header_exist = check_for_custom_headers(args.custom_headers, &collection_dir_path);
+
+    // validation of connector is needed here as a work around to the limitation of the fork of newman that Hyperswitch uses
+    let (connector_name, modified_collection_file_paths) =
+        check_connector_for_dynamic_amount(&connector_name);
+
+    if let Some(auth_type) = inner_map.get(connector_name) {
         match auth_type {
             ConnectorAuthType::HeaderKey { api_key } => {
                 newman_command.args([
@@ -187,24 +216,126 @@ pub fn generate_newman_command() -> ReturnArgs {
         newman_command.arg("--verbose");
     }
 
-    let mut modified = false;
-    if let Some(headers) = &args.custom_headers {
+    ReturnArgs {
+        newman_command,
+        modified_file_paths: vec![modified_collection_file_paths, custom_header_exist],
+        collection_path,
+    }
+}
+
+pub fn check_for_custom_headers(headers: Option<Vec<String>>, path: &str) -> Option<String> {
+    if let Some(headers) = &headers {
         for header in headers {
             if let Some((key, value)) = header.split_once(':') {
                 let content_to_insert =
                     format!(r#"pm.request.headers.add({{key: "{key}", value: "{value}"}});"#);
-                if insert_content(&collection_path, &content_to_insert).is_ok() {
-                    modified = true;
+
+                if let Err(err) = insert_content(path, &content_to_insert) {
+                    eprintln!("An error occurred while inserting the custom header: {err}");
                 }
             } else {
                 eprintln!("Invalid header format: {}", header);
             }
         }
+
+        return Some(format!("{}/event.prerequest.js", path));
     }
+    None
+}
 
-    ReturnArgs {
-        newman_command,
-        file_modified_flag: modified,
-        collection_path,
+// If the connector name exists in dynamic_amount_connectors,
+// the corresponding collection is modified at runtime to remove double quotes
+pub fn check_connector_for_dynamic_amount(connector_name: &str) -> (&str, Option<String>) {
+    let collection_dir_path = get_dir_path(connector_name);
+
+    let dynamic_amount_connectors = ["nmi", "powertranz"];
+
+    if dynamic_amount_connectors.contains(&connector_name) {
+        return remove_quotes_for_integer_values(connector_name).unwrap_or((connector_name, None));
+    }
+    /*
+    If connector name does not exist in dynamic_amount_connectors but we want to run it with custom headers,
+    since we're running from collections directly, we'll have to export the collection again and it is much simpler.
+    We could directly inject the custom-headers using regex, but it is not encouraged as it is hard
+    to determine the place of edit.
+    */
+    export_collection(connector_name, collection_dir_path);
+
+    (connector_name, None)
+}
+
+/*
+Existing issue with the fork of newman is that, it requires you to pass variables like `{{value}}` within
+double quotes without which it fails to execute.
+For integer values like `amount`, this is a bummer as it flags the value stating it is of type
+string and not integer.
+Refactoring is done in 2 steps:
+- Export the collection to json (although the json will be up-to-date, we export it again for safety)
+- Use regex to replace the values which removes double quotes from integer values
+  Ex: \"{{amount}}\" -> {{amount}}
+*/
+
+pub fn remove_quotes_for_integer_values(
+    connector_name: &str,
+) -> Result<(&str, Option<String>), io::Error> {
+    let collection_path = get_collection_path(connector_name);
+    let collection_dir_path = get_dir_path(connector_name);
+
+    let values_to_replace = [
+        "amount",
+        "another_random_number",
+        "capture_amount",
+        "random_number",
+        "refund_amount",
+    ];
+
+    export_collection(connector_name, collection_dir_path);
+
+    let mut contents = fs::read_to_string(&collection_path)?;
+    for value_to_replace in values_to_replace {
+        if let Ok(re) = Regex::new(&format!(
+            r#"\\"(?P<field>\{{\{{{}\}}\}})\\""#,
+            value_to_replace
+        )) {
+            contents = re.replace_all(&contents, "$field").to_string();
+        } else {
+            eprintln!("Regex validation failed.");
+        }
+
+        let mut file = OpenOptions::new()
+            .write(true)
+            .truncate(true)
+            .open(&collection_path)?;
+
+        file.write_all(contents.as_bytes())?;
+    }
+
+    Ok((connector_name, Some(collection_path)))
+}
+
+pub fn export_collection(connector_name: &str, collection_dir_path: String) {
+    let collection_path = get_collection_path(connector_name);
+
+    let mut newman_command = Command::new("newman");
+    newman_command.args([
+        "dir-import".to_owned(),
+        collection_dir_path,
+        "-o".to_owned(),
+        collection_path.clone(),
+    ]);
+
+    match newman_command.spawn().and_then(|mut child| child.wait()) {
+        Ok(exit_status) => {
+            if exit_status.success() {
+                println!("Conversion of collection from directory structure to json successful!");
+            } else {
+                eprintln!("Conversion of collection from directory structure to json failed!");
+                exit(exit_status.code().unwrap_or(1));
+            }
+        }
+        Err(err) => {
+            eprintln!("Failed to execute dir-import: {:?}", err);
+            exit(1);
+        }
     }
 }
diff --git a/postman/collection-dir/aci/Health check/New Request/request.json b/postman/collection-dir/aci/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/aci/Health check/New Request/request.json	
+++ b/postman/collection-dir/aci/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/adyen_uk/Health check/New Request/request.json b/postman/collection-dir/adyen_uk/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/adyen_uk/Health check/New Request/request.json	
+++ b/postman/collection-dir/adyen_uk/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/airwallex/Health check/New Request/request.json b/postman/collection-dir/airwallex/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/airwallex/Health check/New Request/request.json	
+++ b/postman/collection-dir/airwallex/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/authorizedotnet/Health check/New Request/request.json b/postman/collection-dir/authorizedotnet/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/authorizedotnet/Health check/New Request/request.json	
+++ b/postman/collection-dir/authorizedotnet/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/bambora/Health check/New Request/request.json b/postman/collection-dir/bambora/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/bambora/Health check/New Request/request.json	
+++ b/postman/collection-dir/bambora/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/bambora_3ds/Health check/New Request/request.json b/postman/collection-dir/bambora_3ds/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/bambora_3ds/Health check/New Request/request.json	
+++ b/postman/collection-dir/bambora_3ds/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/bankofamerica/Health check/New Request/request.json b/postman/collection-dir/bankofamerica/Health check/New Request/request.json
index 4cc8d4b1a96..ce92926c776 100644
--- a/postman/collection-dir/bankofamerica/Health check/New Request/request.json	
+++ b/postman/collection-dir/bankofamerica/Health check/New Request/request.json	
@@ -1,20 +1,9 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "health"
-    ]
+    "host": ["{{baseUrl}}"],
+    "path": ["health"]
   }
 }
diff --git a/postman/collection-dir/bluesnap/Health check/New Request/request.json b/postman/collection-dir/bluesnap/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/bluesnap/Health check/New Request/request.json	
+++ b/postman/collection-dir/bluesnap/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/braintree/Health check/New Request/request.json b/postman/collection-dir/braintree/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/braintree/Health check/New Request/request.json	
+++ b/postman/collection-dir/braintree/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/checkout/Health check/New Request/request.json b/postman/collection-dir/checkout/Health check/New Request/request.json
index 4cc8d4b1a96..ce92926c776 100644
--- a/postman/collection-dir/checkout/Health check/New Request/request.json	
+++ b/postman/collection-dir/checkout/Health check/New Request/request.json	
@@ -1,20 +1,9 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "health"
-    ]
+    "host": ["{{baseUrl}}"],
+    "path": ["health"]
   }
 }
diff --git a/postman/collection-dir/forte/Health check/New Request/request.json b/postman/collection-dir/forte/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/forte/Health check/New Request/request.json	
+++ b/postman/collection-dir/forte/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/globalpay/Health check/New Request/request.json b/postman/collection-dir/globalpay/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/globalpay/Health check/New Request/request.json	
+++ b/postman/collection-dir/globalpay/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/hyperswitch/Health check/New Request/request.json b/postman/collection-dir/hyperswitch/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/hyperswitch/Health check/New Request/request.json	
+++ b/postman/collection-dir/hyperswitch/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/mollie/Health check/New Request/request.json b/postman/collection-dir/mollie/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/mollie/Health check/New Request/request.json	
+++ b/postman/collection-dir/mollie/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/multisafepay/Health check/New Request/request.json b/postman/collection-dir/multisafepay/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/multisafepay/Health check/New Request/request.json	
+++ b/postman/collection-dir/multisafepay/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/nexinets/Health check/New Request/request.json b/postman/collection-dir/nexinets/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/nexinets/Health check/New Request/request.json	
+++ b/postman/collection-dir/nexinets/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Confirm/request.json b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Confirm/request.json
index 6c99817eb04..7b72495e5c4 100644
--- a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Confirm/request.json	
+++ b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Confirm/request.json	
@@ -29,12 +29,7 @@
       "key": "Accept",
       "value": "application/json"
     },
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    },
+    ,
     {
       "key": "publishable_key",
       "value": "",
@@ -79,14 +74,8 @@
   },
   "url": {
     "raw": "{{baseUrl}}/payments/:id/confirm",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "payments",
-      ":id",
-      "confirm"
-    ],
+    "host": ["{{baseUrl}}"],
+    "path": ["payments", ":id", "confirm"],
     "variable": [
       {
         "key": "id",
diff --git a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Update/request.json b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Update/request.json
index 2d931088d18..bad52859824 100644
--- a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Update/request.json	
+++ b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9-Update amount with automatic capture/Payments - Update/request.json	
@@ -18,18 +18,14 @@
       }
     },
     "raw_json_formatted": {
-      "amount": "{{another_random_number}}"
+      "amount": "{{another_random_number}}",
+      "amount_to_capture": "{{another_random_number}}"
     }
   },
   "url": {
     "raw": "{{baseUrl}}/payments/:id",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "payments",
-      ":id"
-    ],
+    "host": ["{{baseUrl}}"],
+    "path": ["payments", ":id"],
     "variable": [
       {
         "key": "id",
diff --git a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Confirm/request.json b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Confirm/request.json
index 6c99817eb04..7b72495e5c4 100644
--- a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Confirm/request.json	
+++ b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Confirm/request.json	
@@ -29,12 +29,7 @@
       "key": "Accept",
       "value": "application/json"
     },
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    },
+    ,
     {
       "key": "publishable_key",
       "value": "",
@@ -79,14 +74,8 @@
   },
   "url": {
     "raw": "{{baseUrl}}/payments/:id/confirm",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "payments",
-      ":id",
-      "confirm"
-    ],
+    "host": ["{{baseUrl}}"],
+    "path": ["payments", ":id", "confirm"],
     "variable": [
       {
         "key": "id",
diff --git a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Update/request.json b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Update/request.json
index 2d931088d18..bad52859824 100644
--- a/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Update/request.json	
+++ b/postman/collection-dir/nmi/Flow Testcases/Happy Cases/Scenario9a-Update amount with manual capture/Payments - Update/request.json	
@@ -18,18 +18,14 @@
       }
     },
     "raw_json_formatted": {
-      "amount": "{{another_random_number}}"
+      "amount": "{{another_random_number}}",
+      "amount_to_capture": "{{another_random_number}}"
     }
   },
   "url": {
     "raw": "{{baseUrl}}/payments/:id",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "payments",
-      ":id"
-    ],
+    "host": ["{{baseUrl}}"],
+    "path": ["payments", ":id"],
     "variable": [
       {
         "key": "id",
diff --git a/postman/collection-dir/nmi/Health check/New Request/request.json b/postman/collection-dir/nmi/Health check/New Request/request.json
index 4cc8d4b1a96..ce92926c776 100644
--- a/postman/collection-dir/nmi/Health check/New Request/request.json	
+++ b/postman/collection-dir/nmi/Health check/New Request/request.json	
@@ -1,20 +1,9 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "health"
-    ]
+    "host": ["{{baseUrl}}"],
+    "path": ["health"]
   }
 }
diff --git a/postman/collection-dir/payme/Health check/New Request/request.json b/postman/collection-dir/payme/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/payme/Health check/New Request/request.json	
+++ b/postman/collection-dir/payme/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/paypal/Health check/New Request/request.json b/postman/collection-dir/paypal/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/paypal/Health check/New Request/request.json	
+++ b/postman/collection-dir/paypal/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/powertranz/Health check/New Request/request.json b/postman/collection-dir/powertranz/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/powertranz/Health check/New Request/request.json	
+++ b/postman/collection-dir/powertranz/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/rapyd/Health check/New Request/request.json b/postman/collection-dir/rapyd/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/rapyd/Health check/New Request/request.json	
+++ b/postman/collection-dir/rapyd/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/shift4/Health check/New Request/request.json b/postman/collection-dir/shift4/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/shift4/Health check/New Request/request.json	
+++ b/postman/collection-dir/shift4/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant-copy/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant-copy/request.json
index fed600e09cd..dfe421f512f 100644
--- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant-copy/request.json	
+++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant-copy/request.json	
@@ -24,23 +24,12 @@
     {
       "key": "Accept",
       "value": "application/json"
-    },
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
     }
   ],
   "url": {
     "raw": "{{baseUrl}}/account/payment_methods?client_secret={{client_secret}}",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "account",
-      "payment_methods"
-    ],
+    "host": ["{{baseUrl}}"],
+    "path": ["account", "payment_methods"],
     "query": [
       {
         "key": "client_secret",
diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant/request.json
index fed600e09cd..dfe421f512f 100644
--- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant/request.json	
+++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario22- Update address and List Payment method/List Payment Methods for a Merchant/request.json	
@@ -24,23 +24,12 @@
     {
       "key": "Accept",
       "value": "application/json"
-    },
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
     }
   ],
   "url": {
     "raw": "{{baseUrl}}/account/payment_methods?client_secret={{client_secret}}",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "account",
-      "payment_methods"
-    ],
+    "host": ["{{baseUrl}}"],
+    "path": ["account", "payment_methods"],
     "query": [
       {
         "key": "client_secret",
diff --git a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario23- Update Amount/Payments - Confirm/request.json b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario23- Update Amount/Payments - Confirm/request.json
index 5b0c090f2be..5a51941cf64 100644
--- a/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario23- Update Amount/Payments - Confirm/request.json	
+++ b/postman/collection-dir/stripe/Flow Testcases/Happy Cases/Scenario23- Update Amount/Payments - Confirm/request.json	
@@ -29,12 +29,7 @@
       "key": "Accept",
       "value": "application/json"
     },
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    },
+    ,
     {
       "key": "publishable_key",
       "value": "",
diff --git a/postman/collection-dir/stripe/Health check/New Request/request.json b/postman/collection-dir/stripe/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/stripe/Health check/New Request/request.json	
+++ b/postman/collection-dir/stripe/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/trustpay/Health check/New Request/request.json b/postman/collection-dir/trustpay/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/trustpay/Health check/New Request/request.json	
+++ b/postman/collection-dir/trustpay/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/volt/Health check/New Request/request.json b/postman/collection-dir/volt/Health check/New Request/request.json
index 4cc8d4b1a96..ce92926c776 100644
--- a/postman/collection-dir/volt/Health check/New Request/request.json	
+++ b/postman/collection-dir/volt/Health check/New Request/request.json	
@@ -1,20 +1,9 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
-    "host": [
-      "{{baseUrl}}"
-    ],
-    "path": [
-      "health"
-    ]
+    "host": ["{{baseUrl}}"],
+    "path": ["health"]
   }
 }
diff --git a/postman/collection-dir/wise/Health check/Health/request.json b/postman/collection-dir/wise/Health check/Health/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/wise/Health check/Health/request.json	
+++ b/postman/collection-dir/wise/Health check/Health/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/worldline/Health check/New Request/request.json b/postman/collection-dir/worldline/Health check/New Request/request.json
index e40e9396178..ce92926c776 100644
--- a/postman/collection-dir/worldline/Health check/New Request/request.json	
+++ b/postman/collection-dir/worldline/Health check/New Request/request.json	
@@ -1,13 +1,6 @@
 {
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],
diff --git a/postman/collection-dir/zen/Health check/New Request/request.json b/postman/collection-dir/zen/Health check/New Request/request.json
index 9b836ff05cb..24ea5a4157a 100644
--- a/postman/collection-dir/zen/Health check/New Request/request.json	
+++ b/postman/collection-dir/zen/Health check/New Request/request.json	
@@ -3,14 +3,7 @@
     "type": "noauth"
   },
   "method": "GET",
-  "header": [
-    {
-      "key": "x-feature",
-      "value": "router-custom",
-      "type": "text",
-      "disabled": true
-    }
-  ],
+  "header": [],
   "url": {
     "raw": "{{baseUrl}}/health",
     "host": ["{{baseUrl}}"],

## Type of Change
<!-- Put an `x` in the boxes that apply -->

- [ ] Bugfix
- [ ] New feature
- [ ] Enhancement
- [x] Refactoring
- [ ] Dependency updates
- [ ] Documentation
- [x] CI/CD

## Description
<!-- Describe your changes in detail -->

This PR refactors test_utils crate's `newman_runner` to support dynamic values through postman variables.

The main issue with `newman-dir` is that in order to export the collection, the variables must be of type string (Example: Variable value must be of type `"{{value}}"` and not `{{value}}`) without which the user cannot import or export the collection in directory format which is a bummer.

With this refactor, we've introduced a validation to look after `connector_name` and if it is `nmi` or `powertranz`, we'll be doing the collection refactor in run time (collection refactor here means that before the collection is run, we'll be updating the json collection file by removing the double quotes in the integer values (`amount`) at least in 40+ places) which is later restored after the collection is run.

With this change, we'll again be using `run` command to run the collections instead of `dir-run` going forward.

This also added some complexity with how we're running tests for `custom_headers` and removed that part of code from all the existing collections.

### Additional Changes

- [ ] This PR modifies the API contract
- [ ] This PR modifies the database schema
- [ ] This PR modifies application configuration/environment variables

<!--
Provide links to the files with corresponding changes.

Following are the paths where you can find config files:
1. `config`
2. `crates/router/src/configs`
3. `loadtest/config`
-->


## Motivation and Context
<!--
Why is this change required? What problem does it solve?
If it fixes an open issue, please link to the issue here.

If you don't have an issue, we'd recommend starting with one first so the PR
can focus on the implementation (unless it is an obvious bug or documentation fix
that will have little conversation).
-->

In order to run NMI collection which is updated here at #3805, this change is needed.

This PR should also close #3806.

## How did you test it?
<!--
Did you write an integration/unit/API test to verify the code changes?
Or did you test this change manually (provide relevant screenshots)?
-->

In #3805, the tests ran without any issues. Adding the screenshot below:

<img width="485" alt="image" src="https://github.com/juspay/hyperswitch/assets/69745008/7c925fb8-b6b0-4eac-9657-ee3c181c6b70">

Yet another validation: https://github.com/juspay/hyperswitch/actions/runs/8092287211/job/22112758729?pr=3807 (i know why it failed, outdated collection-json file which will be updated on next release after this pr is merged)

## Checklist
<!-- Put an `x` in the boxes that apply -->

- [x] I formatted the code `cargo +nightly fmt --all`
- [x] I addressed lints thrown by `cargo clippy`
- [x] I reviewed the submitted code
- [ ] I added unit tests for my changes where possible
- [ ] I added a [CHANGELOG](/CHANGELOG.md) entry if applicable
