async-graphql-test 1.0.0

A test framework for Rust GraphQL servers.
Documentation
use async_graphql::parser::types::{DocumentOperations, ExecutableDocument};
use itertools::Itertools;

/// A a sequence of several GraphQL queries or mutations.
///
/// It can be parsed from a string, then optionally enriched with
/// [variables][Self::variables] and [executed][crate::execute_script].
///
/// Queries and mutations starting with `_` are not returned in the final list
/// of responses. This is useful for ommiting the feedback from the initial
/// "populate the DB" boilerplate in the response snapshot.
#[derive(Debug)]
pub struct Script {
    pub(crate) requests: Vec<async_graphql::Request>,
}

impl From<async_graphql::Request> for Script {
    fn from(value: async_graphql::Request) -> Self {
        Self {
            requests: vec![value],
        }
    }
}

impl From<&str> for Script {
    fn from(value: &str) -> Self {
        Self::parse(value)
    }
}

impl From<String> for Script {
    fn from(value: String) -> Self {
        Self::parse(value.as_str())
    }
}

impl Script {
    /// Set variable values for all inner operations in the [`Script`].
    pub fn variables(mut self, map: async_graphql::Value) -> Self {
        for req in self.requests.iter_mut() {
            req.variables = async_graphql::Variables::from_value(map.clone());
        }
        self
    }

    pub fn upload(mut self, var_path: &str, upload: async_graphql::UploadValue) -> Self {
        for req in self.requests.iter_mut() {
            req.set_upload(var_path, upload.try_clone().unwrap())
        }
        self
    }

    fn parse(source_code: &str) -> Self {
        Self {
            requests: match async_graphql::parser::parse_query(source_code).unwrap() {
                doc @ ExecutableDocument {
                    operations: DocumentOperations::Single(_),
                    ..
                } => {
                    let mut req = async_graphql::Request::new(source_code);
                    req.set_parsed_query(doc);
                    [req].into()
                }
                ExecutableDocument {
                    operations: DocumentOperations::Multiple(map),
                    fragments,
                } => map
                    .into_iter()
                    // preserve the order of inner requests
                    .sorted_by_key(|(_, def)| def.pos)
                    .map(|(name, def)| {
                        let doc = ExecutableDocument {
                            operations: DocumentOperations::Single(def),
                            fragments: fragments.clone(),
                        };
                        let mut req =
                            async_graphql::Request::new(source_code).operation_name(&*name);
                        req.set_parsed_query(doc);
                        req
                    })
                    .collect(),
            },
        }
    }
}