use apollo_compiler::validation::Valid;
use apollo_compiler::ExecutableDocument;
use apollo_compiler::Schema;
use expect_test::Expect;
use std::sync::OnceLock;
use unindent::unindent;
const GRAPHQL_JS_TEST_SCHEMA: &str = r#"
interface Mammal {
mother: Mammal
father: Mammal
}
interface Pet {
name(surname: Boolean): String
}
interface Canine implements Mammal {
name(surname: Boolean): String
mother: Canine
father: Canine
}
enum DogCommand {
SIT
HEEL
DOWN
}
type Dog implements Pet & Mammal & Canine {
name(surname: Boolean): String
nickname: String
barkVolume: Int
barks: Boolean
doesKnowCommand(dogCommand: DogCommand): Boolean
isHouseTrained(atOtherHomes: Boolean = true): Boolean
isAtLocation(x: Int, y: Int): Boolean
mother: Dog
father: Dog
}
type Cat implements Pet {
name(surname: Boolean): String
nickname: String
meows: Boolean
meowsVolume: Int
furColor: FurColor
}
union CatOrDog = Cat | Dog
type Human {
name(surname: Boolean): String
pets: [Pet]
relatives: [Human]!
}
enum FurColor {
BROWN
BLACK
TAN
SPOTTED
NO_FUR
UNKNOWN
}
input ComplexInput {
requiredField: Boolean!
nonNullField: Boolean! = false
intField: Int
stringField: String
booleanField: Boolean
stringListField: [String]
}
# TODO oneOf not supported in apollo-rs
input OneOfInput { # @oneOf
stringField: String
intField: Int
}
type ComplicatedArgs {
# TODO List
# TODO Coercion
# TODO NotNulls
intArgField(intArg: Int): String
nonNullIntArgField(nonNullIntArg: Int!): String
stringArgField(stringArg: String): String
booleanArgField(booleanArg: Boolean): String
enumArgField(enumArg: FurColor): String
floatArgField(floatArg: Float): String
idArgField(idArg: ID): String
stringListArgField(stringListArg: [String]): String
stringListNonNullArgField(stringListNonNullArg: [String!]): String
complexArgField(complexArg: ComplexInput): String
oneOfArgField(oneOfArg: OneOfInput): String
multipleReqs(req1: Int!, req2: Int!): String
nonNullFieldWithDefault(arg: Int! = 0): String
multipleOpts(opt1: Int = 0, opt2: Int = 0): String
multipleOptAndReq(req1: Int!, req2: Int!, opt1: Int = 0, opt2: Int = 0): String
}
type QueryRoot {
human(id: ID): Human
dog: Dog
cat: Cat
pet: Pet
catOrDog: CatOrDog
complicatedArgs: ComplicatedArgs
}
schema {
query: QueryRoot
}
directive @onField on FIELD
"#;
fn test_schema() -> &'static Valid<Schema> {
static SCHEMA: OnceLock<Valid<Schema>> = OnceLock::new();
SCHEMA.get_or_init(|| {
Schema::parse_and_validate(unindent(GRAPHQL_JS_TEST_SCHEMA), "schema.graphql").unwrap()
})
}
#[track_caller]
fn expect_valid(query: &'static str) {
let schema = test_schema();
ExecutableDocument::parse_and_validate(schema, unindent(query), "query.graphql").unwrap();
}
fn expect_errors(query: &'static str, expect: Expect) {
let schema = test_schema();
let errors = ExecutableDocument::parse_and_validate(schema, unindent(query), "query.graphql")
.expect_err("should have errors")
.errors;
expect.assert_eq(&errors.to_string());
}
mod valid_values {
use super::expect_valid;
#[test]
fn good_int_value() {
expect_valid(
"
{
complicatedArgs {
intArgField(intArg: 2)
}
}
",
);
}
#[test]
fn good_negative_int_value() {
expect_valid(
"
{
complicatedArgs {
intArgField(intArg: -2)
}
}
",
);
}
#[test]
fn good_boolean_value() {
expect_valid(
"
{
complicatedArgs {
booleanArgField(booleanArg: true)
}
}
",
);
}
#[test]
fn good_string_value() {
expect_valid(
r#"
{
complicatedArgs {
stringArgField(stringArg: "foo")
}
}
"#,
);
}
#[test]
fn good_float_value() {
expect_valid(
"
{
complicatedArgs {
floatArgField(floatArg: 1.1)
}
}
",
);
}
#[test]
fn good_negative_float_value() {
expect_valid(
"
{
complicatedArgs {
floatArgField(floatArg: -1.1)
}
}
",
);
}
#[test]
fn int_into_float() {
expect_valid(
"
{
complicatedArgs {
floatArgField(floatArg: 1)
}
}
",
);
}
#[test]
fn int_into_id() {
expect_valid(
"
{
complicatedArgs {
idArgField(idArg: 1)
}
}
",
);
}
#[test]
fn string_into_id() {
expect_valid(
r#"
{
complicatedArgs {
idArgField(idArg: "someIdString")
}
}
"#,
);
}
#[test]
fn good_enum_value() {
expect_valid(
"
{
dog {
doesKnowCommand(dogCommand: SIT)
}
}
",
);
}
#[test]
fn enum_with_undefined_value() {
expect_valid(
"
{
complicatedArgs {
enumArgField(enumArg: UNKNOWN)
}
}
",
);
}
#[test]
fn enum_with_null_value() {
expect_valid(
"
{
complicatedArgs {
enumArgField(enumArg: NO_FUR)
}
}
",
);
}
#[test]
fn null_into_nullable_type() {
expect_valid(
"
{
complicatedArgs {
intArgField(intArg: null)
}
}
",
);
}
}
mod invalid_string_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn int_into_string() {
expect_errors(
"
{
complicatedArgs {
stringArgField(stringArg: 1)
}
}
",
expect![[r#"
Error: expected value of type String, found an integer
╭─[ query.graphql:3:31 ]
│
3 │ stringArgField(stringArg: 1)
│ ┬
│ ╰── provided value is an integer
│
├─[ schema.graphql:80:29 ]
│
80 │ stringArgField(stringArg: String): String
│ ───┬──
│ ╰──── expected type declared here as String
────╯
"#]],
);
}
#[test]
fn float_into_string() {
expect_errors(
"
{
complicatedArgs {
stringArgField(stringArg: 1.0)
}
}
",
expect![[r#"
Error: expected value of type String, found a float
╭─[ query.graphql:3:31 ]
│
3 │ stringArgField(stringArg: 1.0)
│ ─┬─
│ ╰─── provided value is a float
│
├─[ schema.graphql:80:29 ]
│
80 │ stringArgField(stringArg: String): String
│ ───┬──
│ ╰──── expected type declared here as String
────╯
"#]],
);
}
#[test]
fn boolean_into_string() {
expect_errors(
"
{
complicatedArgs {
stringArgField(stringArg: true)
}
}
",
expect![[r#"
Error: expected value of type String, found a boolean
╭─[ query.graphql:3:31 ]
│
3 │ stringArgField(stringArg: true)
│ ──┬─
│ ╰─── provided value is a boolean
│
├─[ schema.graphql:80:29 ]
│
80 │ stringArgField(stringArg: String): String
│ ───┬──
│ ╰──── expected type declared here as String
────╯
"#]],
);
}
#[test]
fn unquoted_into_string() {
expect_errors(
"
{
complicatedArgs {
stringArgField(stringArg: BAR)
}
}
",
expect![[r#"
Error: expected value of type String, found an enum
╭─[ query.graphql:3:31 ]
│
3 │ stringArgField(stringArg: BAR)
│ ─┬─
│ ╰─── provided value is an enum
│
├─[ schema.graphql:80:29 ]
│
80 │ stringArgField(stringArg: String): String
│ ───┬──
│ ╰──── expected type declared here as String
────╯
"#]],
);
}
}
mod invalid_int_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn string_into_int() {
expect_errors(
r#"
{
complicatedArgs {
intArgField(intArg: "3")
}
}
"#,
expect![[r#"
Error: expected value of type Int, found a string
╭─[ query.graphql:3:25 ]
│
3 │ intArgField(intArg: "3")
│ ─┬─
│ ╰─── provided value is a string
│
├─[ schema.graphql:78:23 ]
│
78 │ intArgField(intArg: Int): String
│ ─┬─
│ ╰─── expected type declared here as Int
────╯
"#]],
);
}
#[test]
fn big_int_into_int() {
expect_errors(
"
{
complicatedArgs {
intArgField(intArg: 829384293849283498239482938)
}
}
",
expect![[r#"
Error: int cannot represent non 32-bit signed integer value
╭─[ query.graphql:3:25 ]
│
3 │ intArgField(intArg: 829384293849283498239482938)
│ ─────────────┬─────────────
│ ╰─────────────── cannot be coerced to a 32-bit integer
───╯
"#]],
);
}
#[test]
fn unquoted_string_into_int() {
expect_errors(
"
{
complicatedArgs {
intArgField(intArg: FOO)
}
}
",
expect![[r#"
Error: expected value of type Int, found an enum
╭─[ query.graphql:3:25 ]
│
3 │ intArgField(intArg: FOO)
│ ─┬─
│ ╰─── provided value is an enum
│
├─[ schema.graphql:78:23 ]
│
78 │ intArgField(intArg: Int): String
│ ─┬─
│ ╰─── expected type declared here as Int
────╯
"#]],
);
}
#[test]
fn simple_float_into_int() {
expect_errors(
"
{
complicatedArgs {
intArgField(intArg: 3.0)
}
}
",
expect![[r#"
Error: expected value of type Int, found a float
╭─[ query.graphql:3:25 ]
│
3 │ intArgField(intArg: 3.0)
│ ─┬─
│ ╰─── provided value is a float
│
├─[ schema.graphql:78:23 ]
│
78 │ intArgField(intArg: Int): String
│ ─┬─
│ ╰─── expected type declared here as Int
────╯
"#]],
);
}
#[test]
fn float_into_int() {
expect_errors(
"
{
complicatedArgs {
intArgField(intArg: 3.333)
}
}
",
expect![[r#"
Error: expected value of type Int, found a float
╭─[ query.graphql:3:25 ]
│
3 │ intArgField(intArg: 3.333)
│ ──┬──
│ ╰──── provided value is a float
│
├─[ schema.graphql:78:23 ]
│
78 │ intArgField(intArg: Int): String
│ ─┬─
│ ╰─── expected type declared here as Int
────╯
"#]],
);
}
}
mod invalid_float_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn string_into_float() {
expect_errors(
r#"
{
complicatedArgs {
floatArgField(floatArg: "3.333")
}
}
"#,
expect![[r#"
Error: expected value of type Float, found a string
╭─[ query.graphql:3:29 ]
│
3 │ floatArgField(floatArg: "3.333")
│ ───┬───
│ ╰───── provided value is a string
│
├─[ schema.graphql:83:27 ]
│
83 │ floatArgField(floatArg: Float): String
│ ──┬──
│ ╰──── expected type declared here as Float
────╯
"#]],
);
}
#[test]
fn boolean_into_float() {
expect_errors(
"
{
complicatedArgs {
floatArgField(floatArg: true)
}
}
",
expect![[r#"
Error: expected value of type Float, found a boolean
╭─[ query.graphql:3:29 ]
│
3 │ floatArgField(floatArg: true)
│ ──┬─
│ ╰─── provided value is a boolean
│
├─[ schema.graphql:83:27 ]
│
83 │ floatArgField(floatArg: Float): String
│ ──┬──
│ ╰──── expected type declared here as Float
────╯
"#]],
);
}
#[test]
fn unquoted_into_float() {
expect_errors(
"
{
complicatedArgs {
floatArgField(floatArg: FOO)
}
}
",
expect![[r#"
Error: expected value of type Float, found an enum
╭─[ query.graphql:3:29 ]
│
3 │ floatArgField(floatArg: FOO)
│ ─┬─
│ ╰─── provided value is an enum
│
├─[ schema.graphql:83:27 ]
│
83 │ floatArgField(floatArg: Float): String
│ ──┬──
│ ╰──── expected type declared here as Float
────╯
"#]],
);
}
}
mod invalid_boolean_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn int_into_boolean() {
expect_errors(
"
{
complicatedArgs {
booleanArgField(booleanArg: 2)
}
}
",
expect![[r#"
Error: expected value of type Boolean, found an integer
╭─[ query.graphql:3:33 ]
│
3 │ booleanArgField(booleanArg: 2)
│ ┬
│ ╰── provided value is an integer
│
├─[ schema.graphql:81:31 ]
│
81 │ booleanArgField(booleanArg: Boolean): String
│ ───┬───
│ ╰───── expected type declared here as Boolean
────╯
"#]],
);
}
#[test]
fn float_into_boolean() {
expect_errors(
"
{
complicatedArgs {
booleanArgField(booleanArg: 1.0)
}
}
",
expect![[r#"
Error: expected value of type Boolean, found a float
╭─[ query.graphql:3:33 ]
│
3 │ booleanArgField(booleanArg: 1.0)
│ ─┬─
│ ╰─── provided value is a float
│
├─[ schema.graphql:81:31 ]
│
81 │ booleanArgField(booleanArg: Boolean): String
│ ───┬───
│ ╰───── expected type declared here as Boolean
────╯
"#]],
);
}
#[test]
fn string_into_boolean() {
expect_errors(
r#"
{
complicatedArgs {
booleanArgField(booleanArg: "true")
}
}
"#,
expect![[r#"
Error: expected value of type Boolean, found a string
╭─[ query.graphql:3:33 ]
│
3 │ booleanArgField(booleanArg: "true")
│ ───┬──
│ ╰──── provided value is a string
│
├─[ schema.graphql:81:31 ]
│
81 │ booleanArgField(booleanArg: Boolean): String
│ ───┬───
│ ╰───── expected type declared here as Boolean
────╯
"#]],
);
}
#[test]
fn unquoted_into_boolean() {
expect_errors(
"
{
complicatedArgs {
booleanArgField(booleanArg: TRUE)
}
}
",
expect![[r#"
Error: expected value of type Boolean, found an enum
╭─[ query.graphql:3:33 ]
│
3 │ booleanArgField(booleanArg: TRUE)
│ ──┬─
│ ╰─── provided value is an enum
│
├─[ schema.graphql:81:31 ]
│
81 │ booleanArgField(booleanArg: Boolean): String
│ ───┬───
│ ╰───── expected type declared here as Boolean
────╯
"#]],
);
}
}
mod invalid_id_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn float_into_id() {
expect_errors(
"
{
complicatedArgs {
idArgField(idArg: 1.0)
}
}
",
expect![[r#"
Error: expected value of type ID, found a float
╭─[ query.graphql:3:23 ]
│
3 │ idArgField(idArg: 1.0)
│ ─┬─
│ ╰─── provided value is a float
│
├─[ schema.graphql:84:21 ]
│
84 │ idArgField(idArg: ID): String
│ ─┬
│ ╰── expected type declared here as ID
────╯
"#]],
);
}
#[test]
fn boolean_into_id() {
expect_errors(
"
{
complicatedArgs {
idArgField(idArg: true)
}
}
",
expect![[r#"
Error: expected value of type ID, found a boolean
╭─[ query.graphql:3:23 ]
│
3 │ idArgField(idArg: true)
│ ──┬─
│ ╰─── provided value is a boolean
│
├─[ schema.graphql:84:21 ]
│
84 │ idArgField(idArg: ID): String
│ ─┬
│ ╰── expected type declared here as ID
────╯
"#]],
);
}
#[test]
fn unquoted_into_id() {
expect_errors(
"
{
complicatedArgs {
idArgField(idArg: SOMETHING)
}
}
",
expect![[r#"
Error: expected value of type ID, found an enum
╭─[ query.graphql:3:23 ]
│
3 │ idArgField(idArg: SOMETHING)
│ ────┬────
│ ╰────── provided value is an enum
│
├─[ schema.graphql:84:21 ]
│
84 │ idArgField(idArg: ID): String
│ ─┬
│ ╰── expected type declared here as ID
────╯
"#]],
);
}
}
mod invalid_enum_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn int_into_enum() {
expect_errors(
"
{
dog {
doesKnowCommand(dogCommand: 2)
}
}
",
expect![[r#"
Error: expected value of type DogCommand, found an integer
╭─[ query.graphql:3:33 ]
│
3 │ doesKnowCommand(dogCommand: 2)
│ ┬
│ ╰── provided value is an integer
│
├─[ schema.graphql:27:31 ]
│
27 │ doesKnowCommand(dogCommand: DogCommand): Boolean
│ ─────┬────
│ ╰────── expected type declared here as DogCommand
────╯
"#]],
);
}
#[test]
fn float_into_enum() {
expect_errors(
"
{
dog {
doesKnowCommand(dogCommand: 1.0)
}
}
",
expect![[r#"
Error: expected value of type DogCommand, found a float
╭─[ query.graphql:3:33 ]
│
3 │ doesKnowCommand(dogCommand: 1.0)
│ ─┬─
│ ╰─── provided value is a float
│
├─[ schema.graphql:27:31 ]
│
27 │ doesKnowCommand(dogCommand: DogCommand): Boolean
│ ─────┬────
│ ╰────── expected type declared here as DogCommand
────╯
"#]],
);
}
#[test]
fn string_into_enum() {
expect_errors(
r#"
{
dog {
doesKnowCommand(dogCommand: "SIT")
}
}
"#,
expect![[r#"
Error: expected value of type DogCommand, found a string
╭─[ query.graphql:3:33 ]
│
3 │ doesKnowCommand(dogCommand: "SIT")
│ ──┬──
│ ╰──── provided value is a string
│
├─[ schema.graphql:27:31 ]
│
27 │ doesKnowCommand(dogCommand: DogCommand): Boolean
│ ─────┬────
│ ╰────── expected type declared here as DogCommand
────╯
"#]],
);
}
#[test]
fn boolean_into_enum() {
expect_errors(
"
{
dog {
doesKnowCommand(dogCommand: true)
}
}
",
expect![[r#"
Error: expected value of type DogCommand, found a boolean
╭─[ query.graphql:3:33 ]
│
3 │ doesKnowCommand(dogCommand: true)
│ ──┬─
│ ╰─── provided value is a boolean
│
├─[ schema.graphql:27:31 ]
│
27 │ doesKnowCommand(dogCommand: DogCommand): Boolean
│ ─────┬────
│ ╰────── expected type declared here as DogCommand
────╯
"#]],
);
}
#[test]
fn unknown_enum_value_into_enum() {
expect_errors(
"
{
dog {
doesKnowCommand(dogCommand: JUGGLE)
}
}
",
expect![[r#"
Error: value `JUGGLE` does not exist on `DogCommand`
╭─[ query.graphql:3:33 ]
│
3 │ doesKnowCommand(dogCommand: JUGGLE)
│ ───┬──
│ ╰──── value does not exist on `DogCommand` enum
│
├─[ schema.graphql:16:1 ]
│
16 │ ╭─▶ enum DogCommand {
┆ ┆
20 │ ├─▶ }
│ │
│ ╰─────── enum defined here
────╯
"#]],
);
}
#[test]
fn different_case_enum_value_into_enum() {
expect_errors(
"
{
dog {
doesKnowCommand(dogCommand: sit)
}
}
",
expect![[r#"
Error: value `sit` does not exist on `DogCommand`
╭─[ query.graphql:3:33 ]
│
3 │ doesKnowCommand(dogCommand: sit)
│ ─┬─
│ ╰─── value does not exist on `DogCommand` enum
│
├─[ schema.graphql:16:1 ]
│
16 │ ╭─▶ enum DogCommand {
┆ ┆
20 │ ├─▶ }
│ │
│ ╰─────── enum defined here
────╯
"#]],
);
}
}
mod valid_list_values {
use super::expect_valid;
#[test]
fn good_list_value() {
expect_valid(
r#"
{
complicatedArgs {
stringListArgField(stringListArg: ["one", null, "two"])
}
}
"#,
);
}
#[test]
fn empty_list_value() {
expect_valid(
"
{
complicatedArgs {
stringListArgField(stringListArg: [])
}
}
",
);
}
#[test]
fn null_value() {
expect_valid(
"
{
complicatedArgs {
stringListArgField(stringListArg: null)
}
}
",
);
}
#[test]
fn single_value_into_list() {
expect_valid(
r#"
{
complicatedArgs {
stringListArgField(stringListArg: "one")
}
}
"#,
);
}
}
mod invalid_list_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn incorrect_item_type() {
expect_errors(
r#"
{
complicatedArgs {
stringListArgField(stringListArg: ["one", 2])
}
}
"#,
expect![[r#"
Error: expected value of type String, found an integer
╭─[ query.graphql:3:47 ]
│
3 │ stringListArgField(stringListArg: ["one", 2])
│ ┬
│ ╰── provided value is an integer
│
├─[ schema.graphql:85:37 ]
│
85 │ stringListArgField(stringListArg: [String]): String
│ ────┬───
│ ╰───── expected type declared here as String
────╯
"#]],
);
}
#[test]
fn single_value_of_incorrect_type() {
expect_errors(
"
{
complicatedArgs {
stringListArgField(stringListArg: 1)
}
}
",
expect![[r#"
Error: expected value of type [String], found an integer
╭─[ query.graphql:3:39 ]
│
3 │ stringListArgField(stringListArg: 1)
│ ┬
│ ╰── provided value is an integer
│
├─[ schema.graphql:85:37 ]
│
85 │ stringListArgField(stringListArg: [String]): String
│ ────┬───
│ ╰───── expected type declared here as [String]
────╯
"#]],
);
}
}
mod valid_non_nullable_values {
use super::expect_valid;
#[test]
fn arg_on_optional_arg() {
expect_valid(
"
{
dog {
isHouseTrained(atOtherHomes: true)
}
}
",
);
}
#[test]
fn no_arg_on_optional_arg() {
expect_valid(
"
{
dog {
isHouseTrained
}
}
",
);
}
#[test]
fn multiple_args() {
expect_valid(
"
{
complicatedArgs {
multipleReqs(req1: 1, req2: 2)
}
}
",
);
}
#[test]
fn multiple_args_reverse_order() {
expect_valid(
"
{
complicatedArgs {
multipleReqs(req2: 2, req1: 1)
}
}
",
);
}
#[test]
fn no_args_on_multiple_optional() {
expect_valid(
"
{
complicatedArgs {
multipleOpts
}
}
",
);
}
#[test]
fn one_arg_on_multiple_optional() {
expect_valid(
"
{
complicatedArgs {
multipleOpts(opt1: 1)
}
}
",
);
}
#[test]
fn second_arg_on_multiple_optional() {
expect_valid(
"
{
complicatedArgs {
multipleOpts(opt2: 1)
}
}
",
);
}
#[test]
fn multiple_required_args_on_mixed_list() {
expect_valid(
"
{
complicatedArgs {
multipleOptAndReq(req1: 3, req2: 4)
}
}
",
);
}
#[test]
fn multiple_required_and_one_optional_arg_on_mixed_list() {
expect_valid(
"
{
complicatedArgs {
multipleOptAndReq(req1: 3, req2: 4, opt1: 5)
}
}
",
);
}
#[test]
fn all_required_and_optional_args_on_mixed_list() {
expect_valid(
"
{
complicatedArgs {
multipleOptAndReq(req1: 3, req2: 4, opt1: 5, opt2: 6)
}
}
",
);
}
}
mod invalid_non_nullable_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn incorrect_value_type() {
expect_errors(
r#"
{
complicatedArgs {
multipleReqs(req2: "two", req1: "one")
}
}
"#,
expect![[r#"
Error: expected value of type Int!, found a string
╭─[ query.graphql:3:24 ]
│
3 │ multipleReqs(req2: "two", req1: "one")
│ ──┬──
│ ╰──── provided value is a string
│
├─[ schema.graphql:89:34 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ──┬─
│ ╰─── expected type declared here as Int!
────╯
Error: expected value of type Int!, found a string
╭─[ query.graphql:3:37 ]
│
3 │ multipleReqs(req2: "two", req1: "one")
│ ──┬──
│ ╰──── provided value is a string
│
├─[ schema.graphql:89:22 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ──┬─
│ ╰─── expected type declared here as Int!
────╯
"#]],
);
}
#[test]
fn incorrect_value_and_missing_argument() {
expect_errors(
r#"
{
complicatedArgs {
multipleReqs(req1: "one")
}
}
"#,
expect![[r#"
Error: the required argument `ComplicatedArgs.multipleReqs(req2:)` is not provided
╭─[ query.graphql:3:5 ]
│
3 │ multipleReqs(req1: "one")
│ ────────────┬────────────
│ ╰────────────── missing value for argument `req2`
│
├─[ schema.graphql:89:28 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ─────┬────
│ ╰────── argument defined here
────╯
Error: expected value of type Int!, found a string
╭─[ query.graphql:3:24 ]
│
3 │ multipleReqs(req1: "one")
│ ──┬──
│ ╰──── provided value is a string
│
├─[ schema.graphql:89:22 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ──┬─
│ ╰─── expected type declared here as Int!
────╯
"#]],
);
}
#[test]
fn null_value() {
expect_errors(
"
{
complicatedArgs {
multipleReqs(req1: null)
}
}
",
expect![[r#"
Error: the required argument `ComplicatedArgs.multipleReqs(req1:)` is not provided
╭─[ query.graphql:3:5 ]
│
3 │ multipleReqs(req1: null)
│ ────────────┬───────────
│ ╰───────────── missing value for argument `req1`
│
├─[ schema.graphql:89:16 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ─────┬────
│ ╰────── argument defined here
────╯
Error: the required argument `ComplicatedArgs.multipleReqs(req2:)` is not provided
╭─[ query.graphql:3:5 ]
│
3 │ multipleReqs(req1: null)
│ ────────────┬───────────
│ ╰───────────── missing value for argument `req2`
│
├─[ schema.graphql:89:28 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ─────┬────
│ ╰────── argument defined here
────╯
Error: expected value of type Int!, found null
╭─[ query.graphql:3:24 ]
│
3 │ multipleReqs(req1: null)
│ ──┬─
│ ╰─── provided value is null
│
├─[ schema.graphql:89:22 ]
│
89 │ multipleReqs(req1: Int!, req2: Int!): String
│ ──┬─
│ ╰─── expected type declared here as Int!
────╯
"#]],
);
}
}
mod valid_input_object_values {
use super::expect_valid;
#[test]
fn optional_arg_required_field() {
expect_valid(
"
{
complicatedArgs {
complexArgField
}
}
",
);
}
#[test]
fn partial_object_only_required() {
expect_valid(
"
{
complicatedArgs {
complexArgField(complexArg: { requiredField: true })
}
}
",
);
}
#[test]
fn partial_object_required_boolean_false() {
expect_valid(
"
{
complicatedArgs {
complexArgField(complexArg: { requiredField: false })
}
}
",
);
}
#[test]
fn partial_object_including_required() {
expect_valid(
"
{
complicatedArgs {
complexArgField(complexArg: { requiredField: true, intField: 4 })
}
}
",
);
}
#[test]
fn full_object() {
expect_valid(
r#"
{
complicatedArgs {
complexArgField(complexArg: {
requiredField: true,
intField: 4,
stringField: "foo",
booleanField: false,
stringListField: ["one", "two"]
})
}
}
"#,
);
}
#[test]
fn full_object_unordered() {
expect_valid(
r#"
{
complicatedArgs {
complexArgField(complexArg: {
stringListField: ["one", "two"],
booleanField: false,
requiredField: true,
stringField: "foo",
intField: 4,
})
}
}
"#,
);
}
}
mod invalid_input_object_values {
use super::expect_errors;
use expect_test::expect;
#[test]
fn partial_object_missing_required() {
expect_errors(
"
{
complicatedArgs {
complexArgField(complexArg: { intField: 4 })
}
}
",
expect![[r#"
Error: the required field `ComplexInput.requiredField` is not provided
╭─[ query.graphql:3:33 ]
│
3 │ complexArgField(complexArg: { intField: 4 })
│ ───────┬───────
│ ╰───────── missing value for field `requiredField`
│
├─[ schema.graphql:60:3 ]
│
60 │ requiredField: Boolean!
│ ───────────┬───────────
│ ╰───────────── field defined here
────╯
"#]],
);
}
#[test]
fn partial_object_invalid_field_type() {
expect_errors(
r#"
{
complicatedArgs {
complexArgField(complexArg: {
stringListField: ["one", 2],
requiredField: true,
})
}
}
"#,
expect![[r#"
Error: expected value of type String, found an integer
╭─[ query.graphql:4:32 ]
│
4 │ stringListField: ["one", 2],
│ ┬
│ ╰── provided value is an integer
│
├─[ schema.graphql:65:20 ]
│
65 │ stringListField: [String]
│ ────┬───
│ ╰───── expected type declared here as String
────╯
"#]],
);
}
#[test]
fn partial_object_null_to_non_null_field() {
expect_errors(
"
{
complicatedArgs {
complexArgField(complexArg: {
requiredField: true,
nonNullField: null,
})
}
}
",
expect![[r#"
Error: expected value of type Boolean!, found null
╭─[ query.graphql:5:21 ]
│
5 │ nonNullField: null,
│ ──┬─
│ ╰─── provided value is null
│
├─[ schema.graphql:61:17 ]
│
61 │ nonNullField: Boolean! = false
│ ────┬───
│ ╰───── expected type declared here as Boolean!
────╯
"#]],
);
}
#[test]
fn partial_object_unknown_field() {
expect_errors(
r#"
{
complicatedArgs {
complexArgField(complexArg: {
requiredField: true,
invalidField: "value"
})
}
}
"#,
expect![[r#"
Error: field `invalidField` does not exist on `ComplexInput`
╭─[ query.graphql:5:21 ]
│
5 │ invalidField: "value"
│ ───┬───
│ ╰───── value does not exist on `ComplexInput` input object
│
├─[ schema.graphql:59:1 ]
│
59 │ ╭─▶ input ComplexInput {
┆ ┆
66 │ ├─▶ }
│ │
│ ╰─────── input object defined here
────╯
"#]],
);
}
#[test]
fn custom_scalar_accept_complex_literals() {
use apollo_compiler::ExecutableDocument;
use apollo_compiler::Schema;
let schema = Schema::parse_and_validate(
"
scalar Any
type Query {
anyArg(arg: Any): String
}
",
"schema.graphql",
)
.unwrap();
ExecutableDocument::parse_and_validate(
&schema,
r#"
{
test1: anyArg(arg: 123)
test2: anyArg(arg: "abc")
test3: anyArg(arg: [123, "abc"])
test4: anyArg(arg: {deep: [123, "abc"]})
}
"#,
"query.graphql",
)
.unwrap();
}
}
mod directive_arguments {
use super::expect_errors;
use super::expect_valid;
use expect_test::expect;
#[test]
fn with_directives_of_valid_types() {
expect_valid(
"
{
dog @include(if: true) {
name
}
human @skip(if: false) {
name
}
}
",
);
}
#[test]
fn with_directives_of_invalid_types() {
expect_errors(
r#"
{
dog @include(if: "yes") {
name @skip(if: ENUM)
}
}
"#,
expect![[r#"
Error: expected value of type Boolean!, found a string
╭─[ query.graphql:2:20 ]
│
2 │ dog @include(if: "yes") {
│ ──┬──
│ ╰──── provided value is a string
│
├─[ built_in.graphql:146:7 ]
│
146 │ if: Boolean!
│ ────┬───
│ ╰───── expected type declared here as Boolean!
─────╯
Error: expected value of type Boolean!, found an enum
╭─[ query.graphql:3:20 ]
│
3 │ name @skip(if: ENUM)
│ ──┬─
│ ╰─── provided value is an enum
│
├─[ built_in.graphql:140:7 ]
│
140 │ if: Boolean!
│ ────┬───
│ ╰───── expected type declared here as Boolean!
─────╯
"#]],
);
}
}
mod variable_default_values {
use super::expect_errors;
use super::expect_valid;
use expect_test::expect;
#[test]
fn variables_with_valid_default_values() {
expect_valid(
r#"
query WithDefaultValues(
$a: Int = 1,
$b: String = "ok",
$c: ComplexInput = { requiredField: true, intField: 3 }
$d: Int! = 123
) {
dog { name }
complicatedArgs {
intArgField(intArg: $a)
stringArgField(stringArg: $b)
complexArgField(complexArg: $c)
intArgField2: intArgField(intArg: $d)
}
}
"#,
);
}
#[test]
fn variables_with_valid_default_null_values() {
expect_valid(
"
query WithDefaultValues(
$a: Int = null,
$b: String = null,
$c: ComplexInput = { requiredField: true, intField: null }
) {
dog { name }
complicatedArgs {
intArgField(intArg: $a)
stringArgField(stringArg: $b)
complexArgField(complexArg: $c)
}
}
",
);
}
#[test]
fn variables_with_invalid_default_null_values() {
expect_errors(
"
query WithDefaultValues(
$a: Int! = null,
$b: String! = null,
$c: ComplexInput = { requiredField: null, intField: null }
) {
dog { name }
complicatedArgs {
intArgField(intArg: $a)
stringArgField(stringArg: $b)
complexArgField(complexArg: $c)
}
}
",
expect![[r#"
Error: expected value of type Int!, found null
╭─[ query.graphql:2:14 ]
│
2 │ $a: Int! = null,
│ ──┬─ ──┬─
│ ╰────────── expected type declared here as Int!
│ │
│ ╰─── provided value is null
───╯
Error: expected value of type String!, found null
╭─[ query.graphql:3:17 ]
│
3 │ $b: String! = null,
│ ───┬─── ──┬─
│ ╰──────────── expected type declared here as String!
│ │
│ ╰─── provided value is null
───╯
Error: the required field `ComplexInput.requiredField` is not provided
╭─[ query.graphql:4:22 ]
│
4 │ $c: ComplexInput = { requiredField: null, intField: null }
│ ───────────────────┬───────────────────
│ ╰───────────────────── missing value for field `requiredField`
│
├─[ schema.graphql:60:3 ]
│
60 │ requiredField: Boolean!
│ ───────────┬───────────
│ ╰───────────── field defined here
────╯
Error: expected value of type Boolean!, found null
╭─[ query.graphql:4:39 ]
│
4 │ $c: ComplexInput = { requiredField: null, intField: null }
│ ──┬─
│ ╰─── provided value is null
│
├─[ schema.graphql:60:18 ]
│
60 │ requiredField: Boolean!
│ ────┬───
│ ╰───── expected type declared here as Boolean!
────╯
"#]],
);
}
#[test]
fn variables_with_invalid_default_values() {
expect_errors(
r#"
query InvalidDefaultValues(
$a: Int = "one",
$b: String = 4,
$c: ComplexInput = "NotVeryComplex"
) {
dog { name }
complicatedArgs {
intArgField(intArg: $a)
stringArgField(stringArg: $b)
complexArgField(complexArg: $c)
}
}
"#,
expect![[r#"
Error: expected value of type Int, found a string
╭─[ query.graphql:2:13 ]
│
2 │ $a: Int = "one",
│ ─┬─ ──┬──
│ ╰─────────── expected type declared here as Int
│ │
│ ╰──── provided value is a string
───╯
Error: expected value of type String, found an integer
╭─[ query.graphql:3:16 ]
│
3 │ $b: String = 4,
│ ───┬── ┬
│ ╰──────── expected type declared here as String
│ │
│ ╰── provided value is an integer
───╯
Error: expected value of type ComplexInput, found a string
╭─[ query.graphql:4:22 ]
│
4 │ $c: ComplexInput = "NotVeryComplex"
│ ──────┬───── ────────┬───────
│ ╰────────────────────────── expected type declared here as ComplexInput
│ │
│ ╰───────── provided value is a string
───╯
"#]],
);
}
#[test]
fn variables_with_complex_invalid_default_values() {
expect_errors(
r#"
query WithDefaultValues(
$a: ComplexInput = { requiredField: 123, intField: "abc" }
) {
dog { name }
complicatedArgs { complexArgField(complexArg: $a) }
}
"#,
expect![[r#"
Error: expected value of type Boolean!, found an integer
╭─[ query.graphql:2:39 ]
│
2 │ $a: ComplexInput = { requiredField: 123, intField: "abc" }
│ ─┬─
│ ╰─── provided value is an integer
│
├─[ schema.graphql:60:18 ]
│
60 │ requiredField: Boolean!
│ ────┬───
│ ╰───── expected type declared here as Boolean!
────╯
Error: expected value of type Int, found a string
╭─[ query.graphql:2:54 ]
│
2 │ $a: ComplexInput = { requiredField: 123, intField: "abc" }
│ ──┬──
│ ╰──── provided value is a string
│
├─[ schema.graphql:62:13 ]
│
62 │ intField: Int
│ ─┬─
│ ╰─── expected type declared here as Int
────╯
"#]],
);
}
#[test]
fn complex_variables_missing_required_field() {
expect_errors(
"
query MissingRequiredField($a: ComplexInput = {intField: 3}) {
dog { name }
complicatedArgs { complexArgField(complexArg: $a) }
}
",
expect![[r#"
Error: the required field `ComplexInput.requiredField` is not provided
╭─[ query.graphql:1:47 ]
│
1 │ query MissingRequiredField($a: ComplexInput = {intField: 3}) {
│ ──────┬──────
│ ╰──────── missing value for field `requiredField`
│
├─[ schema.graphql:60:3 ]
│
60 │ requiredField: Boolean!
│ ───────────┬───────────
│ ╰───────────── field defined here
────╯
"#]],
);
}
#[test]
fn list_variables_with_invalid_item() {
expect_errors(
r#"
query InvalidItem($a: [String] = ["one", 2]) {
dog { name }
complicatedArgs { stringListArgField(stringListArg: $a) }
}
"#,
expect![[r#"
Error: expected value of type String, found an integer
╭─[ query.graphql:1:42 ]
│
1 │ query InvalidItem($a: [String] = ["one", 2]) {
│ ────┬─── ┬
│ ╰───────────────── expected type declared here as String
│ │
│ ╰── provided value is an integer
───╯
"#]],
);
}
}