Skip to content

Commit

Permalink
Fix/add tests for compile time default value evaluation (#1026)
Browse files Browse the repository at this point in the history
* Fix and add tests for compile time default_value evaluation

* More tests

* Update CHANGELOG

* Remove failing test

* Make the current time different
  • Loading branch information
dylan-chong authored Jan 11, 2021
1 parent 2aed570 commit 4154c91
Show file tree
Hide file tree
Showing 10 changed files with 272 additions and 57 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
- Feature: Support for the [`repeatable` directive](https://github.com/absinthe-graphql/absinthe/pull/999)
- Feature: Enable [rendering](https://github.com/absinthe-graphql/absinthe/pull/1010) of Type System Directives in SDL based schemas.
- Feature: Correctly match [Introspection type specs](https://github.com/absinthe-graphql/absinthe/pull/1017)
- Bug Fix: Restore dynamic description support [comprehensively fixed](https://github.com/absinthe-graphql/absinthe/pull/1005)
- Bug Fix: Restore dynamic description support [comprehensively fixed](https://github.com/absinthe-graphql/absinthe/pull/1005) (Note: the `description`s are evaluated once --- at compile time)
- Bug Fix: Restore dynamic default_value support [comprehensively fixed](https://github.com/absinthe-graphql/absinthe/pull/1026) (Note: the `default_value`s evaluated once --- at compile time)
- Bug Fix: [Interface nullability](https://github.com/absinthe-graphql/absinthe/pull/1009) corrections
- Bug Fix: Fix [field listing for Inputs](https://github.com/absinthe-graphql/absinthe/pull/1015) that import fields
- Bug Fix: Properly [trim all descriptions](https://github.com/absinthe-graphql/absinthe/pull/1014) no matter the mechanism used to specify them
Expand Down
1 change: 0 additions & 1 deletion lib/absinthe/blueprint/schema.ex
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,6 @@ defmodule Absinthe.Blueprint.Schema do
end

defp build_types([:close | rest], [%Schema.InputValueDefinition{} = arg, field | stack], buff) do
arg = Map.update!(arg, :default_value, fn val -> {:unquote, [], [val]} end)
build_types(rest, [push(field, :arguments, arg) | stack], buff)
end

Expand Down
2 changes: 2 additions & 0 deletions lib/absinthe/schema/notation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -413,6 +413,7 @@ defmodule Absinthe.Schema.Notation do
|> Keyword.delete(:args)
|> Keyword.delete(:meta)
|> Keyword.update(:description, nil, &wrap_in_unquote/1)
|> Keyword.update(:default_value, nil, &wrap_in_unquote/1)
|> handle_deprecate

{attrs, block}
Expand Down Expand Up @@ -1337,6 +1338,7 @@ defmodule Absinthe.Schema.Notation do
|> Keyword.put_new(:name, to_string(identifier))
|> Keyword.put_new(:type, type)
|> Keyword.update(:description, nil, &wrap_in_unquote/1)
|> Keyword.update(:default_value, nil, &wrap_in_unquote/1)
|> handle_deprecate
end

Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
defmodule Elixir.Absinthe.Integration.Execution.Variables.DefaultValueTest do
use Absinthe.Case, async: true

@query """
@times_query """
query ($mult: Int = 6) {
times(base: 4, multiplier: $mult)
}
"""

test "scenario #1" do
@default_value_query """
query {
microsecond
}
"""

test "query field arg default_value and resolve execution" do
assert {:ok, %{data: %{"times" => 24}}} ==
Absinthe.run(@query, Absinthe.Fixtures.TimesSchema, [])
Absinthe.run(@times_query, Absinthe.Fixtures.TimesSchema, [])
end

test "query field default is evaluated only once" do
{:ok, %{data: %{"microsecond" => first_current_microsecond}}} =
Absinthe.run(@default_value_query, Absinthe.Fixtures.DefaultValueSchema, [])

Process.sleep(5)

{:ok, %{data: %{"microsecond" => second_current_microsecond}}} =
Absinthe.run(@default_value_query, Absinthe.Fixtures.DefaultValueSchema, [])

# If the code to grab the default_value was executed twice, this would be different
assert first_current_microsecond == second_current_microsecond
end
end
17 changes: 17 additions & 0 deletions test/absinthe/type/input_object_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ defmodule Absinthe.Type.InputObjectTest do

alias Absinthe.Fixtures.InputObject

# Note: The arg description evaluation tests are in test/absinthe/type/query_test.exs

defmodule Schema do
use Absinthe.Schema

Expand Down Expand Up @@ -120,4 +122,19 @@ defmodule Absinthe.Type.InputObjectTest do
end
end)
end

describe "input object field default_value evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates default_value to '#{expected_value}')" do
type =
InputObject.TestSchemaFieldsAndArgsDescription.__absinthe_type__(:field_default_value)

assert type.fields[unquote(test_label)].default_value == unquote(expected_value)
end
end)
end
end
8 changes: 4 additions & 4 deletions test/absinthe/type/object_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ defmodule Absinthe.Type.ObjectTest do
end
end

describe "input object keyword description evaluation" do
describe "object keyword description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
Expand Down Expand Up @@ -83,7 +83,7 @@ defmodule Absinthe.Type.ObjectTest do
end)
end

describe "input object field keyword description evaluation" do
describe "object field keyword description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
Expand All @@ -100,7 +100,7 @@ defmodule Absinthe.Type.ObjectTest do
end)
end

describe "input object field attribute description evaluation" do
describe "object field attribute description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Absinthe.Fixtures.FunctionEvaluationHelpers.filter_test_params_for_description_attribute()
|> Enum.each(fn %{
Expand All @@ -115,7 +115,7 @@ defmodule Absinthe.Type.ObjectTest do
end)
end

describe "input object field macro description evaluation" do
describe "object field macro description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
Expand Down
79 changes: 31 additions & 48 deletions test/absinthe/type/query_test.exs
Original file line number Diff line number Diff line change
@@ -1,68 +1,51 @@
defmodule Absinthe.Type.QueryTest do
use Absinthe.Case, async: true

defmodule TestSchema do
use Absinthe.Schema
@module_attribute "goodbye"
alias Absinthe.Fixtures.Query

defmodule NestedModule do
def nested_function(arg1) do
arg1
end
end

def test_function(arg1) do
arg1
end

query do
field :normal_string, :string do
arg :arg_example, :string, description: "string"
end

field :local_function_call, :string do
arg :arg_example, :string, description: test_function("red")
end

field :function_call_using_absolute_path_to_current_module, :string do
arg :arg_example, :string,
description: Absinthe.Type.QueryTest.TestSchema.test_function("red")
end

field :standard_library_function, :string do
arg :arg_example, :string, description: String.replace("red", "e", "a")
end

field :function_in_nested_module, :string do
arg :arg_example, :string, description: NestedModule.nested_function("hello")
end
describe "query field arg keyword description evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = Query.TestSchemaFieldArgDescription.__absinthe_type__("RootQueryType")

field :external_module_function_call, :string do
arg :arg_example, :string,
description: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello")
assert type.fields[unquote(test_label)].args.arg_example.description ==
unquote(expected_value)
end
end)
end

field :module_attribute_string_concat, :string do
arg :arg_example, :string, description: "hello " <> @module_attribute
end
describe "query field arg default_value evaluation" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates default_value to '#{expected_value}')" do
type = Query.TestSchemaFieldArgDefaultValue.__absinthe_type__("RootQueryType")
field = type.fields[unquote(test_label)]

field :interpolation_of_module_attribute, :string do
arg :arg_example, :string, description: "hello #{@module_attribute}"
assert field.args.arg_example.default_value == unquote(expected_value)
end
end
end)
end

describe "query field arg keyword description evaluation" do
describe "query field arg default_value evaluation with import_fields" do
Absinthe.Fixtures.FunctionEvaluationHelpers.function_evaluation_test_params()
|> Enum.each(fn %{
test_label: test_label,
expected_value: expected_value
} ->
test "for #{test_label} (evaluates description to '#{expected_value}')" do
type = TestSchema.__absinthe_type__("RootQueryType")
test "for #{test_label} (evaluates default_value to '#{expected_value}')" do
type =
Query.TestSchemaFieldArgDefaultValueWithImportFields.__absinthe_type__("RootQueryType")

assert type.fields[unquote(test_label)].args.arg_example.description ==
unquote(expected_value)
field = type.fields[unquote(test_label)]

assert field.args.arg_example.default_value == unquote(expected_value)
end
end)
end
Expand Down
10 changes: 10 additions & 0 deletions test/support/fixtures/default_value_schema.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defmodule Absinthe.Fixtures.DefaultValueSchema do
use Absinthe.Schema
use Absinthe.Fixture

# Note: More examples in Absinthe.Fixtures.Query.TestSchemaFieldArgDefaultValueWithImportFields

query do
field :microsecond, :integer, default_value: DateTime.utc_now().microsecond |> elem(0)
end
end
22 changes: 22 additions & 0 deletions test/support/fixtures/input_object.ex
Original file line number Diff line number Diff line change
Expand Up @@ -251,5 +251,27 @@ defmodule Absinthe.Fixtures.InputObject do
description "hello #{@module_attribute}"
end
end

input_object :field_default_value do
field :normal_string, :string, default_value: "string"
field :local_function_call, :string, default_value: test_function("red")

field :function_call_using_absolute_path_to_current_module, :string,
default_value:
Absinthe.Fixtures.InputObject.TestSchemaFieldsAndArgsDescription.test_function("red")

field :standard_library_function, :string, default_value: String.replace("red", "e", "a")

field :function_in_nested_module, :string,
default_value: NestedModule.nested_function("hello")

field :external_module_function_call, :string,
default_value: Absinthe.Fixtures.FunctionEvaluationHelpers.external_function("hello")

field :module_attribute_string_concat, :string, default_value: "hello " <> @module_attribute

field :interpolation_of_module_attribute, :string,
default_value: "hello #{@module_attribute}"
end
end
end
Loading

0 comments on commit 4154c91

Please sign in to comment.