mod common;
use common::{start_server, stdout, toad, write_collection, write_file};
#[test]
fn login_create_read_delete_chain() {
let base_url = start_server();
let file = write_collection(
"chain",
&format!(
r#"
[config]
auth = "bearer {{{{token}}}}"
[vars]
base_url = "{base_url}"
[login]
method = "POST"
url = "{{{{base_url}}}}/login"
ignore_config = ["auth"]
expect_status = [200]
[login.capture]
token = "$.access_token"
[create-user]
method = "POST"
url = "{{{{base_url}}}}/users"
body = '{{"name": "Toad"}}'
expect_status = [201]
[create-user.capture]
user_id = "$.id"
location = "header:Location"
roles = "$.roles"
code = "status"
[get-user]
method = "GET"
url = "{{{{base_url}}}}/users/{{{{user_id}}}}"
expect_status = [200]
[get-user-by-location]
method = "GET"
url = "{{{{base_url}}}}{{{{location}}}}"
expect_status = [200]
[delete-user]
method = "DELETE"
url = "{{{{base_url}}}}/users/{{{{user_id}}}}"
expect_status = [204]
"#
),
);
let output = toad(&[file.to_str().unwrap(), "-o", "verbose"]);
let out = stdout(&output);
assert!(output.status.success(), "toad failed:\n{out}");
assert!(out.contains("token = tok-123"), "{out}");
assert!(out.contains("user_id = 42"), "{out}");
assert!(out.contains("location = /users/42"), "{out}");
assert!(out.contains(r#"roles = ["reader","editor"]"#), "{out}");
assert!(out.contains("code = 201"), "{out}");
}
#[test]
fn login_without_ignore_config_fails_on_undefined_token() {
let base_url = start_server();
let file = write_collection(
"no-ignore",
&format!(
r#"
[config]
auth = "bearer {{{{token}}}}"
[login]
method = "POST"
url = "{base_url}/login"
[login.capture]
token = "$.access_token"
"#
),
);
let output = toad(&[file.to_str().unwrap()]);
assert!(!output.status.success());
assert!(stdout(&output).contains("undefined variable 'token'"));
}
#[test]
fn single_request_uses_vars_fallback() {
let base_url = start_server();
let file = write_collection(
"fallback",
&format!(
r#"
[vars]
user_id = "42"
token = "tok-123"
[create-user]
method = "POST"
url = "{base_url}/users"
auth = "bearer {{{{token}}}}"
[create-user.capture]
user_id = "$.id"
[get-user]
url = "{base_url}/users/{{{{user_id}}}}"
auth = "bearer {{{{token}}}}"
expect_status = [200]
"#
),
);
let output = toad(&[file.to_str().unwrap(), "get-user"]);
assert!(output.status.success(), "{}", stdout(&output));
}
#[test]
fn single_request_without_fallback_fails() {
let base_url = start_server();
let file = write_collection(
"no-fallback",
&format!(
r#"
[create-user]
method = "POST"
url = "{base_url}/users"
[create-user.capture]
user_id = "$.id"
[get-user]
url = "{base_url}/users/{{{{user_id}}}}"
"#
),
);
let output = toad(&[file.to_str().unwrap(), "get-user"]);
assert!(!output.status.success());
assert!(stdout(&output).contains("undefined variable 'user_id'"));
}
#[test]
fn failed_capture_stops_the_run() {
let base_url = start_server();
let file = write_collection(
"failed-capture",
&format!(
r#"
[login]
method = "POST"
url = "{base_url}/login"
[login.capture]
token = "$.missing"
[never-runs]
url = "{base_url}/users/42"
"#
),
);
let output = toad(&[file.to_str().unwrap()]);
let out = stdout(&output);
assert!(!output.status.success());
assert!(
out.contains("capture 'token': no value matched '$.missing'"),
"{out}"
);
assert!(!out.contains("[never-runs]"), "{out}");
}
#[test]
fn invalid_capture_is_reported_before_any_request() {
let file = write_collection(
"invalid-capture",
r#"
[create-user]
method = "POST"
url = "http://127.0.0.1:1/users"
[create-user.capture]
user_id = "id"
"#,
);
let output = toad(&[file.to_str().unwrap()]);
let err = String::from_utf8_lossy(&output.stderr);
assert!(!output.status.success());
assert!(
err.contains("invalid capture 'user_id' in request 'create-user'"),
"{err}"
);
}
#[test]
fn escaped_braces_are_sent_literally() {
let base_url = start_server();
let file = write_collection(
"escape",
&format!(
r#"
[vars]
email = "ben@example.com"
[send-welcome-email]
method = "POST"
url = "{base_url}/echo"
body = '''
{{
"to": "{{{{email}}}}",
"subject": "Welcome, \{{{{first_name}}}}!"
}}
'''
[send-welcome-email.capture]
to = "$.to"
subject = "$.subject"
"#
),
);
let output = toad(&[file.to_str().unwrap(), "-o", "verbose"]);
let out = stdout(&output);
assert!(output.status.success(), "{out}");
assert!(out.contains("to = ben@example.com"), "{out}");
assert!(out.contains("subject = Welcome, {{first_name}}!"), "{out}");
}
#[test]
fn interpolate_body_false_sends_body_file_unchanged() {
let base_url = start_server();
let template =
r#"{"template": "Hi {{first_name}}, {{#if vip}}welcome back{{/if}}. Path: C:\\{{dir}}"}"#;
write_file("raw-body", "welcome.hbs.json", template);
let file = write_collection(
"raw-body",
&format!(
r#"
[vars]
base_url = "{base_url}"
[upload-template]
method = "POST"
url = "{{{{base_url}}}}/echo"
body_file = "./welcome.hbs.json"
interpolate_body = false
[upload-template.capture]
sent = "body"
"#
),
);
let output = toad(&[file.to_str().unwrap(), "-o", "verbose"]);
let out = stdout(&output);
assert!(output.status.success(), "{out}");
assert!(out.contains(&format!("sent = {template}")), "{out}");
}