Skip to main content

api_testing_core/websocket/
expect.rs

1use anyhow::Context;
2
3use crate::Result;
4use crate::websocket::runner::WebsocketExecutedRequest;
5use crate::websocket::schema::{WebsocketExpect, WebsocketRequest};
6
7pub fn evaluate_text_expect(expect: &WebsocketExpect, text: &str, label: &str) -> Result<()> {
8    if let Some(contains) = expect.text_contains.as_deref()
9        && !text.contains(contains)
10    {
11        anyhow::bail!("{label} textContains failed: expected to contain '{contains}'");
12    }
13
14    if let Some(expr) = expect.jq.as_deref() {
15        let json: serde_json::Value = serde_json::from_str(text)
16            .with_context(|| format!("{label} jq requires a JSON response text"))?;
17        if !crate::jq::eval_exit_status(&json, expr).unwrap_or(false) {
18            anyhow::bail!("{label} jq failed: {expr}");
19        }
20    }
21
22    Ok(())
23}
24
25pub fn evaluate_main_response(
26    request: &WebsocketRequest,
27    executed: &WebsocketExecutedRequest,
28) -> Result<()> {
29    let Some(expect) = request.expect.as_ref() else {
30        return Ok(());
31    };
32
33    let last = executed.last_received.as_deref().ok_or_else(|| {
34        anyhow::anyhow!("websocket expect requires at least one received message")
35    })?;
36
37    evaluate_text_expect(expect, last, "websocket expect")
38}
39
40#[cfg(test)]
41mod tests {
42    use pretty_assertions::assert_eq;
43
44    use super::*;
45
46    fn request_with_expect(expect: Option<WebsocketExpect>) -> WebsocketRequest {
47        WebsocketRequest {
48            url: None,
49            headers: Vec::new(),
50            connect_timeout_seconds: None,
51            steps: Vec::new(),
52            expect,
53            raw: serde_json::json!({}),
54        }
55    }
56
57    fn executed_with_text(text: Option<&str>) -> WebsocketExecutedRequest {
58        WebsocketExecutedRequest {
59            target: "ws://127.0.0.1:9001/ws".to_string(),
60            transcript: Vec::new(),
61            last_received: text.map(ToString::to_string),
62        }
63    }
64
65    #[test]
66    fn websocket_expect_accepts_matching_text_contains_and_jq() {
67        let expect = WebsocketExpect {
68            jq: Some(".ok == true".to_string()),
69            text_contains: Some("ok".to_string()),
70        };
71        let request = request_with_expect(Some(expect));
72        let executed = executed_with_text(Some("{\"ok\":true}"));
73        evaluate_main_response(&request, &executed).unwrap();
74    }
75
76    #[test]
77    fn websocket_expect_rejects_missing_receive_text() {
78        let expect = WebsocketExpect {
79            jq: None,
80            text_contains: Some("ok".to_string()),
81        };
82        let request = request_with_expect(Some(expect));
83        let executed = executed_with_text(None);
84        let err = evaluate_main_response(&request, &executed).unwrap_err();
85        assert!(format!("{err:#}").contains("at least one received message"));
86    }
87
88    #[test]
89    fn websocket_expect_rejects_failed_jq() {
90        let err = evaluate_text_expect(
91            &WebsocketExpect {
92                jq: Some(".ok == false".to_string()),
93                text_contains: None,
94            },
95            "{\"ok\":true}",
96            "test",
97        )
98        .unwrap_err();
99        assert!(format!("{err:#}").contains("jq failed"));
100    }
101
102    #[test]
103    fn websocket_expect_rejects_missing_text_contains() {
104        let err = evaluate_text_expect(
105            &WebsocketExpect {
106                jq: None,
107                text_contains: Some("needle".to_string()),
108            },
109            "haystack",
110            "test",
111        )
112        .unwrap_err();
113        assert!(format!("{err:#}").contains("textContains failed"));
114    }
115
116    #[test]
117    fn websocket_expect_accepts_empty_when_no_expect() {
118        let request = request_with_expect(None);
119        let executed = executed_with_text(None);
120        let result = evaluate_main_response(&request, &executed);
121        assert_eq!(result.is_ok(), true);
122    }
123}