nils-api-testing-core 0.8.3

Library crate for nils-api-testing-core in the nils-cli workspace.
Documentation
use crate::report::{ReportBuilder, ReportHeader};

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RestReportAssertion {
    pub label: String,
    pub state: String,
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct RestReport {
    pub report_date: String,
    pub case_name: String,
    pub generated_at: String,
    pub endpoint_note: String,
    pub result_note: String,
    pub command_snippet: Option<String>,
    pub assertions: Vec<RestReportAssertion>,
    pub request_json: String,
    pub response_lang: String,
    pub response_body: String,
    pub stderr_note: Option<String>,
}

pub fn render_rest_report_markdown(report: &RestReport) -> String {
    let header = ReportHeader {
        report_date: &report.report_date,
        case_name: &report.case_name,
        generated_at: &report.generated_at,
        endpoint_note: &report.endpoint_note,
        result_note: &report.result_note,
        command_snippet: report.command_snippet.as_deref(),
    };
    let mut builder = ReportBuilder::new(header);

    if !report.assertions.is_empty() {
        builder.push_section_heading("Assertions");
        for a in &report.assertions {
            builder.push_list_item(&format!("{} ({})", a.label, a.state));
        }
        builder.push_blank_line();
    }

    builder.push_code_section("Request", "json", &report.request_json, None, true);
    builder.push_code_section(
        "Response",
        &report.response_lang,
        &report.response_body,
        None,
        true,
    );

    if let Some(stderr_note) = &report.stderr_note
        && !stderr_note.is_empty()
    {
        builder.push_code_section("stderr", "text", stderr_note, None, false);
    }

    builder.finish()
}

#[cfg(test)]
mod tests {
    use super::*;
    use pretty_assertions::assert_eq;

    #[test]
    fn rest_report_renders_markdown_with_optional_sections() {
        let report = RestReport {
            report_date: "2026-02-01".to_string(),
            case_name: "Health".to_string(),
            generated_at: "2026-02-01T00:00:00Z".to_string(),
            endpoint_note: "Endpoint: http://localhost:8080/health".to_string(),
            result_note: "Result: OK".to_string(),
            command_snippet: Some("curl -sS http://localhost:8080/health".to_string()),
            assertions: vec![RestReportAssertion {
                label: "status".to_string(),
                state: "pass".to_string(),
            }],
            request_json: r#"{"method":"GET","path":"/health"}"#.to_string(),
            response_lang: "json".to_string(),
            response_body: r#"{"ok":true}"#.to_string(),
            stderr_note: Some("warning: retrying".to_string()),
        };

        let got = render_rest_report_markdown(&report);
        let expected = concat!(
            "# API Test Report (2026-02-01)\n",
            "\n",
            "## Test Case: Health\n",
            "\n",
            "## Command\n",
            "\n",
            "```bash\n",
            "curl -sS http://localhost:8080/health\n",
            "```\n",
            "\n",
            "Generated at: 2026-02-01T00:00:00Z\n",
            "\n",
            "Endpoint: http://localhost:8080/health\n",
            "\n",
            "Result: OK\n",
            "\n",
            "### Assertions\n",
            "\n",
            "- status (pass)\n",
            "\n",
            "### Request\n",
            "\n",
            "```json\n",
            "{\"method\":\"GET\",\"path\":\"/health\"}\n",
            "```\n",
            "\n",
            "### Response\n",
            "\n",
            "```json\n",
            "{\"ok\":true}\n",
            "```\n",
            "\n",
            "### stderr\n",
            "\n",
            "```text\n",
            "warning: retrying\n",
            "```\n"
        );
        assert_eq!(got, expected);
    }

    #[test]
    fn rest_report_omits_command_assertions_and_empty_stderr() {
        let report = RestReport {
            report_date: "2026-02-01".to_string(),
            case_name: "No-Options".to_string(),
            generated_at: "2026-02-01T00:00:00Z".to_string(),
            endpoint_note: "Endpoint: x".to_string(),
            result_note: "Result: y".to_string(),
            command_snippet: None,
            assertions: vec![],
            request_json: "{}".to_string(),
            response_lang: "text".to_string(),
            response_body: "ok".to_string(),
            stderr_note: Some("".to_string()),
        };

        let got = render_rest_report_markdown(&report);
        assert!(!got.contains("## Command\n"));
        assert!(!got.contains("### Assertions\n"));
        assert!(!got.contains("### stderr\n"));
    }
}