README.md

# Absinthe Query All

Absinthe Query All is a tool for comprehensively and automatically querying and testing your Absinthe GraphQL schema.

You can read the story of how the core functionality of this package was developed [here](https://www.neurodynamic.online/writing/frontend-to-backend-type-safety).

This library primarily provides two utility functions.

## the `get_all_operations` function

This function returns a list of every operation of the specified type (i.e. query or mutation) in your absinthe graphql schema.

```elixir
AbsintheQueryAll.get_all_operations(SomeAbsintheSchema, :query)
[
  :someQuery, :someOtherQuery, :someThirdQuery
]
```
## the `get_comprehensive_response` function

The `get_comprehensive_response` function runs the graphql operation specified, requesting a response that contains every possible field and subfield.

```elixir
AbsintheQueryAll.get_comprehensive_response(%{
  schema: SomeAbsintheSchema,
  operation_type: :query,
  operation_name: :someOperation,
})
{:ok, %{data: %{"someField" => 1, "someOtherField" => 2, "someThirdField" => 3}}}
```

## Automatic comprehensiveness checking of your absinthe `resolve` callbacks

Why these two functions? So that you can set them up like this:

```elixir
describe "SomeAbsintheSchema" do
  # First we get every single query available in the schema
  for operation <- AbsintheQueryAll.get_all_operations(SomeAbsintheSchema, :query) do
    # Then we create a test case
    test "query `#{operation}` responds successfully" do
      # Inside the test case, we run the query
      {status, response} = AbsintheQueryAll.get_comprehensive_response(%{
        schema: TestAbsintheSchema,
        operation_type: :query,
        operation_name: unquote(Macro.escape(operation)),
      })

      # And then we check to see that it returned successfully
      assert status == :ok
      assert Map.has_key?(response, :data)
      refute Map.has_key?(response, :errors)
    end
  end

  # Then we do the same thing with our mutations
  for operation <- AbsintheQueryAll.get_all_operations(SomeAbsintheSchema, :mutation) do
    test "mutation `#{operation}` responds successfully" do
      {status, response} = AbsintheQueryAll.get_comprehensive_response(%{
        schema: TestAbsintheSchema,
        operation_type: :mutation,
        operation_name: unquote(Macro.escape(operation)),
      })

      assert status == :ok
      assert Map.has_key?(response, :data)
      refute Map.has_key?(response, :errors)
    end
  end
end
```

With that setup, your app will automatically generate a test for every single graphql operation and make sure that a response is being generated for every single field in that operation. Just a nice, simple extra layer protection against a specific type of bug.

## Extra details

### Generating Arguments

Your schema likely has operations that require arguments. In order to generate arguments to pass to those operations, the `get_comprehensive_response` function has an optional argument, `argument_generator`, that you can pass an argument generating function to. The argument generating function should take two arguments: the first is the `operation_name` (e.g. `:someQuery`) and the second is the name of the argument you're generating (as an atom; e.g. `:userId`).

For example, you might call `get_comprehensive_response` like this:

```elixir
AbsintheQueryAll.get_comprehensive_response(%{
  schema: SomeAbsintheSchema,
  operation_type: :query,
  operation_name: :testQuery,
  argument_generator: fn operation_name, argument_name ->
    case {operation_name, argument_name} do
      {:someQuery, :theNameOfSomeStringArgumentToTheQuery} ->
        # if this argument requires a string, here's where you choose what string it gets
        "some string"
      {:someQuery, :theNameOfSomeIntegerArgumentToTheQuery} ->
        7

    end
```

### Passing in Context

The optional `context` argument on `get_comprehensive_response` is just for passing along the `context` map that `Absinthe.run` takes. You might use this for something like passing in information on the currently logged in user if that has an effect on what your graphql endpoint will return for some operations.

```elixir
AbsintheQueryAll.get_comprehensive_response(%{
  schema: SomeAbsintheSchema,
  operation_type: :query,
  operation_name: :testQuery,
  context: %{current_user: user}
```

## Other possibilities

This library intentionally exposes a lot of the underlying modules/functions that make the two main functions work, in case anyone wants to use them to build other tools. I use them for a variety of nice graphql testing functions that I may take a stab at generalizing and open-sourcing in the future if I find the time.

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
by adding `absinthe_query_all` to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [
    {:absinthe_query_all, "~> 0.1.1"}
  ]
end
```

Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
be found at <https://hexdocs.pm/absinthe_query_all>.