use autumn_web::test::TestClient;
use serde_json::{Value, json};
pub trait GraphqlTestExt {
fn graphql(&self, query: &str) -> GraphqlTestRequest<'_>;
}
impl GraphqlTestExt for TestClient {
fn graphql(&self, query: &str) -> GraphqlTestRequest<'_> {
GraphqlTestRequest {
client: self,
path: "/graphql".to_owned(),
body: json!({ "query": query }),
headers: Vec::new(),
}
}
}
#[must_use]
pub struct GraphqlTestRequest<'a> {
client: &'a TestClient,
path: String,
body: Value,
headers: Vec<(String, String)>,
}
impl GraphqlTestRequest<'_> {
pub fn at(mut self, path: &str) -> Self {
path.clone_into(&mut self.path);
self
}
pub fn variables(mut self, variables: Value) -> Self {
self.body["variables"] = variables;
self
}
pub fn operation_name(mut self, name: &str) -> Self {
self.body["operationName"] = Value::from(name);
self
}
pub fn extensions(mut self, extensions: Value) -> Self {
self.body["extensions"] = extensions;
self
}
pub fn header(mut self, name: &str, value: &str) -> Self {
self.headers.push((name.to_owned(), value.to_owned()));
self
}
pub async fn send(self) -> GraphqlTestResponse {
let mut request = self.client.post(&self.path).json(&self.body);
for (name, value) in &self.headers {
request = request.header(name, value);
}
let response = request.send().await;
let status = response.status.as_u16();
let body: Value = serde_json::from_str(&response.text()).unwrap_or(Value::Null);
GraphqlTestResponse { status, body }
}
}
#[derive(Debug, Clone)]
pub struct GraphqlTestResponse {
pub status: u16,
pub body: Value,
}
#[allow(clippy::must_use_candidate)]
impl GraphqlTestResponse {
#[must_use]
pub fn data(&self) -> &Value {
&self.body["data"]
}
#[must_use]
pub fn errors(&self) -> Vec<Value> {
self.body["errors"].as_array().cloned().unwrap_or_default()
}
#[must_use]
pub fn error_codes(&self) -> Vec<String> {
self.errors()
.iter()
.filter_map(|e| e["extensions"]["code"].as_str().map(str::to_owned))
.collect()
}
#[allow(clippy::panic)]
pub fn assert_no_errors(&self) -> &Self {
assert!(
self.errors().is_empty(),
"expected no GraphQL errors, got: {}",
self.body
);
self
}
pub fn assert_error_code(&self, code: &str) -> &Self {
assert!(
self.error_codes().iter().any(|c| c == code),
"expected an error with code {code}, got: {}",
self.body
);
self
}
pub fn assert_status(&self, status: u16) -> &Self {
assert_eq!(
self.status, status,
"unexpected status; body: {}",
self.body
);
self
}
}