[
  {
    "path": ".codeclimate.yml",
    "content": "---\nengines:\n  duplication:\n    enabled: true\n    config:\n      languages:\n      - ruby\n      - javascript\n      - python\n      - php\n  fixme:\n    enabled: true\n  rubocop:\n    enabled: true\nratings:\n  paths:\n  - \"**.inc\"\n  - \"**.js\"\n  - \"**.jsx\"\n  - \"**.module\"\n  - \"**.php\"\n  - \"**.py\"\n  - \"**.rb\"\nexclude_paths:\n- Gemfile.lock\n- spec/\n- rspec-graphql_matchers.gemspec\n- bin/\n- Rakefile\n"
  },
  {
    "path": ".editorconfig",
    "content": "# EditorConfig help us maintain consistent coding style between different editors.\n#\n# EditorConfig\n# http://editorconfig.org\n#\nroot = true\n\n[*]\nindent_style = space\nindent_size = 2\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n\n[*.md]\ntrim_trailing_whitespace = false\nindent_size = 4\n"
  },
  {
    "path": ".github/workflows/rspec.yml",
    "content": "name: RSpec\n\n# Controls when the action will run. Triggers the workflow on push or pull request\n# events but only for the master branch\non: [push, pull_request]\n\njobs:\n  # This workflow contains a single job \"rspec\"\n  rspec:\n    # The type of runner that the job will run on\n    runs-on: ubuntu-latest\n\n    strategy:\n      matrix:\n        ruby_version: [2.6, 2.7, '3.0', 3.1, 3.2]\n\n    # Steps represent a sequence of tasks that will be executed as part of the job\n    steps:\n      # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it\n      - uses: actions/checkout@v3\n\n      - name: Set up Ruby ${{ matrix.ruby_version }}\n        uses: ruby/setup-ruby@v1\n        with:\n          ruby-version: ${{ matrix.ruby_version }}\n          bundler-cache: true\n      - name: Run RSpec\n        run: bundle exec rspec\n"
  },
  {
    "path": ".gitignore",
    "content": "/.bundle/\n/.yardoc\n/Gemfile.lock\n/_yardoc/\n/coverage/\n/doc/\n/pkg/\n/spec/reports/\n/tmp/\n"
  },
  {
    "path": ".rspec",
    "content": "--format documentation\n--color\n"
  },
  {
    "path": ".rubocop.yml",
    "content": "AllCops:\n  DisplayCopNames: true\n  DisplayStyleGuide: true\n\nLayout/AlignParameters:\n  EnforcedStyle: with_fixed_indentation\n\nMetrics/LineLength:\n  Max: 90\n\nLayout/MultilineMethodCallIndentation:\n  EnforcedStyle: indented\n\nLayout/SpaceBeforeFirstArg:\n  Include:\n    - db/migrate/*.rb\n  Enabled: false\n\nStyle/Documentation:\n  Enabled: false\n\nStyle/ClassAndModuleChildren:\n  Enabled: true\n\nStyle/Lambda:\n  Enabled: false\n\nMetrics/MethodLength:\n  Max: 15\n\nMetrics/BlockLength:\n  Exclude:\n    - spec/rspec/*.rb\n\nMetrics/ModuleLength:\n  Exclude:\n    - spec/rspec/*.rb\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "# Changelog\n\n## 2.0.0 (April 16th, 2023)\n\n-   Adds compatibility with graphql-ruby 2.0+. If you're still using an earlier version, you should stick to 1.4.x.\n\n### Deprecations\n\n-   The usage of the `#types` helper when writing tests (if you're not including `RSpec::GraphqlMatchers::TypesHelper` anywhere, you shoudn't have to change anything). Use `GraphQL::Types::<TYPE_NAME>` instead\n-   The usage of type instances as expected value for a type comparison is deprecated. Instead,\n    use the string that represents the type specification. Examples:\n\n    ```\n      # Bad - These are deprecated:\n      expect(a_type).to have_a_field(:lorem).of_type(GraphQL::Types::ID)\n      expect(a_type).to have_a_field(:lorem).of_type(Types::MyCustomType)\n\n      # Good - Use these instead\n      expect(a_type).to have_a_field(:lorem).of_type('ID')\n      expect(a_type).to have_a_field(:lorem).of_type('MyCustomType')\n    ```\n\n    The reason behind this change relies on the fact that we should have a decoupling between the\n    internal constants used to define our API and the public names exposed through it. If we test\n    a published API using the internal constants, it is possible to perform breaking changes by\n    renaming the graphql names of our types or entities without actually breaking the tests.\n\n    If we're performing a breaking change to a public API, we want our tests to fail.\n\n## 1.4.0 (April 16th, 2023)\n\n-   Removal of deprecated calls to #to_graphql, replacing them with #to_type_signature that was added in graphql-ruby 1.8.3 (https://github.com/khamusa/rspec-graphql_matchers/pull/43 @RobinDaugherty)\n-   Dropped support for legacy .define API\n-   Dropped support to old relay interfaces\n-   Fixed with_hash_key matcher for newer versions of graphql-ruby\n-   Fixed errors that occured in some edge cases when generating descriptions for accept_argument and have_a_field matchers\n-   Documentations improvement and general cleanup\n-   Dropped support to graphql-ruby versions before 1.10.12.\n\n## 1.3.1 (Aug 2nd, 2021)\n\n-   Corrected gem dependencies so it properly requires RSpec when loaded (thanks to @itay-grudev)\n\n## 1.3.0 (May 7th, 2020)\n\n-   `accept_argument` matcher accepts underscored argument names and passes even if the actual argument is camel-cased (https://github.com/khamusa/rspec-graphql_matchers/pull/32 thanks to @TonyArra);\n-   `have_a_field` matcher accepts `.with_deprecation_reason` (https://github.com/khamusa/rspec-graphql_matchers/pull/34 thanks to @TonyArra).\n\n## 1.2.1 (March 31st, 2020)\n\n-   Fixed issue causing the last release to break expectations against snake_cased fields (fixes https://github.com/khamusa/rspec-graphql_matchers/issues/30).\n\n## 1.2 (Feb 6th, 2020)\n\n-   Added support to underscored arguments in have_field (https://github.com/khamusa/rspec-graphql_matchers/pull/29 thanks to @makketagg)\n\n## 1.1 (Sep 19th, 2019)\n\n-   Added graphql-ruby 1.9.x support (thanks to @severin)\n\n## 1.0.1 (June 22th, 2019)\n\n### Bug fixes\n\n-   Fixed issue causing `have_a_field(x).of_type(Y)` to fail on fields defined on implemented interfaces that were defined with legacy syntax.\n\n## 1.0 (June, 2019)\n\n### Breaking changes\n\n-   Support to property and hash_key matchers will be dropped on upcoming releases.\n\n### Deprecations\n\n-   `.with_metadata` and `.with_property` matchers for fields will be removed on the next release;\n-   `.accept_arguments` (plural form) will be removed on the next release;\n-   `.accept_argument` (singular form) receiving a hash with a single or multiple arguments will no longer be supported, use `accept_argument(name).of_type('MyType')` instead.\n\n### New features\n\n-   Add support for Class-based type definition api (adds support for graphql-ruby v1.8.x). Please note that `.with_metadata` and `.with_property` support has been kept but will only work on fields defined using the legacy api.\n-   Implemented `accept_argument(arg_name).of_type('MyType')´ matcher, which returns much clearer error messages when the arguments are not found on the target type.\n\n### Bug fixes\n\n## 0.7.1 (July 27, 2017)\n\nChangelog fixes.\n\n## 0.7.0 (July 27, 2017)\n\n### New features\n\n-   (#3, #8) New chainable matchers `with_property`, `with_hash_key` and `with_metadata` (Thanks to @marcgreenstock).\n\n### Improvements\n\n-   Default Raketask runs rubocop specs as well (Thanks to @marcgreenstock).\n\n## 0.6.0 (July 25, 2017)\n\n### New features\n\n-   (PR #6) New matchers for interfaces: `expect(...).to implement(interface)` (Thanks to @marcgreenstock).\n\n## 0.5.0 (May 10, 2017)\n\n### New features\n\n-   (PR #4) New matchers for mutations: `have_an_input_field` and `have_a_return_field` (Thanks to @aaronklaassen).\n\n## 0.4.0 (Feb, 2017)\n\n### New features\n\n-   Improvements on error messages of have_a_field(...).of_type(...)\n\n### Bug fixes\n\n-   Fixed a bug preventing proper type checking when using matchers in the form have_a_field(fname).of_type(types.X). The bug would not happen when providing the type expectation as a string, only when using the GraphQL constants.\n\n## 0.3.0 (Sep 16, 2016)\n\n### Breaking changes\n\n### Deprecations\n\n### New features\n\n-   New matcher have_field(field_name).of_type(type) for testing types and their fields\n\n### Bug fixes\n\n## 0.2.0 Initial public release\n\n### Breaking changes\n\n### Deprecations\n\n### New features\n\n-   New matcher be_of_type for testing fields\n-   New matcher accept_arguments for testing fields\n\n### Bug fixes\n"
  },
  {
    "path": "CODE_OF_CONDUCT.md",
    "content": "# Contributor Code of Conduct\n\nAs contributors and maintainers of this project, and in the interest of\nfostering an open and welcoming community, we pledge to respect all people who\ncontribute through reporting issues, posting feature requests, updating\ndocumentation, submitting pull requests or patches, and other activities.\n\nWe are committed to making participation in this project a harassment-free\nexperience for everyone, regardless of level of experience, gender, gender\nidentity and expression, sexual orientation, disability, personal appearance,\nbody size, race, ethnicity, age, religion, or nationality.\n\nExamples of unacceptable behavior by participants include:\n\n* The use of sexualized language or imagery\n* Personal attacks\n* Trolling or insulting/derogatory comments\n* Public or private harassment\n* Publishing other's private information, such as physical or electronic\n  addresses, without explicit permission\n* Other unethical or unprofessional conduct\n\nProject maintainers have the right and responsibility to remove, edit, or\nreject comments, commits, code, wiki edits, issues, and other contributions\nthat are not aligned to this Code of Conduct, or to ban temporarily or\npermanently any contributor for other behaviors that they deem inappropriate,\nthreatening, offensive, or harmful.\n\nBy adopting this Code of Conduct, project maintainers commit themselves to\nfairly and consistently applying these principles to every aspect of managing\nthis project. Project maintainers who do not follow or enforce the Code of\nConduct may be permanently removed from the project team.\n\nThis code of conduct applies both within project spaces and in public spaces\nwhen an individual is representing the project or its community.\n\nInstances of abusive, harassing, or otherwise unacceptable behavior may be\nreported by contacting a project maintainer at gb.samuel@gmail.com. All\ncomplaints will be reviewed and investigated and will result in a response that\nis deemed necessary and appropriate to the circumstances. Maintainers are\nobligated to maintain confidentiality with regard to the reporter of an\nincident.\n\nThis Code of Conduct is adapted from the [Contributor Covenant][homepage],\nversion 1.3.0, available at\n[http://contributor-covenant.org/version/1/3/0/][version]\n\n[homepage]: http://contributor-covenant.org\n[version]: http://contributor-covenant.org/version/1/3/0/"
  },
  {
    "path": "Gemfile",
    "content": "# frozen_string_literal: true\n\nsource 'https://rubygems.org'\n\n# Specify your gem's dependencies in rspec-graphql_matchers.gemspec\ngemspec\n"
  },
  {
    "path": "LICENSE.txt",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2016 Samuel Brandão\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "![RSpec Status](https://github.com/khamusa/rspec-graphql_matchers/actions/workflows/rspec.yml/badge.svg)\n\n# Rspec::GraphqlMatchers\n\nConvenient rspec matchers for testing your [graphql-ruby](https://github.com/rmosolgo/graphql-ruby) API/Schema.\n\n## Installation\n\n```\ngem 'rspec-graphql_matchers'\n```\n\n## Usage\n\nThe matchers currently supported are:\n\n-   `expect(a_graphql_object).to have_a_field(field_name).of_type(valid_type)`\n-   `expect(a_graphql_object).to implement(interface_name, ...)`\n-   `expect(a_mutation_type).to have_a_return_field(field_name).returning(valid_type)`\n-   `expect(a_mutation_type).to have_an_input_field(field_name).of_type(valid_type)`\n-   `expect(a_field).to be_of_type(valid_type)`\n-   `expect(an_input).to accept_argument(argument_name).of_type(valid_type)`\n\nWhere `valid_type` is a your type signature as a String: `\"String!\"`, `\"Int!\"`, `\"[String]!\"` (note the exclamation mark at the end, as required by the [GraphQL specifications](http://graphql.org/).\n\nPlease note that using references to type instances is deprecated and will be removed in a future release.\n\n## Examples\n\nGiven a GraphQL object defined as\n\n```ruby\nclass PostType < GraphQL::Schema::Object\n  graphql_name \"Post\"\n  description \"A blog post\"\n\n  implements GraphQL::Types::Relay::Node\n\n  field :id, ID, null: false\n  field :comments, [String], null: false\n  field :isPublished, Boolean, null: true\n  field :published, Boolean, null: false, deprecation_reason: 'Use isPublished instead'\n\n  field :subposts, PostType, null: true do\n    argument :filter, String, required: false\n    argument :id, ID, required: false\n    argument :isPublished, Boolean, required: false\n  end\nend\n```\n\n### 1) Test your type defines the correct fields:\n\n```ruby\ndescribe PostType do\n  subject { described_class }\n\n  it { is_expected.to have_field(:id).of_type(\"ID!\") }\n  it { is_expected.to have_field(:comments).of_type(\"[String!]!\") }\n  it { is_expected.to have_field(:isPublished).of_type(\"Boolean\") }\n\n  # Check a field is deprecated\n  it { is_expected.to have_field(:published).with_deprecation_reason }\n  it { is_expected.to have_field(:published).with_deprecation_reason('Use isPublished instead') }\n  it { is_expected.not_to have_field(:published).with_deprecation_reason('Wrong reason') }\n  it { is_expected.not_to have_field(:isPublished).with_deprecation_reason }\n\n  # The gem automatically converts field names to CamelCase, so this will\n  # pass even though the field was defined as field :isPublished\n  it { is_expected.to have_field(:is_published).of_type(\"Boolean\") }\nend\n```\n\n### 2) Test a specific field type with `be_of_type` matcher:\n\n```ruby\ndescribe PostType do\n  describe 'id' do\n    subject { PostType.fields['id'] }\n\n    it { is_expected.to be_of_type('ID!') }\n    it { is_expected.not_to be_of_type('Float!') }\n  end\n\n  describe 'subposts' do\n    subject { PostType.fields['subposts'] }\n\n    it { is_expected.to be_of_type('Post') }\n  end\nend\n```\n\n### 3) Test the arguments accepted by a field with `accept_argument` matcher:\n\n```ruby\ndescribe PostType do\n  describe 'subposts' do\n    subject { PostType.fields['subposts'] }\n\n    it 'accepts a filter and an id argument, of types String and ID' do\n      expect(subject).to accept_argument(:filter).of_type('String')\n      expect(subject).to accept_argument(:id).of_type('ID')\n    end\n\n    it { is_expected.not_to accept_argument(:weirdo) }\n\n    # The gem automatically converts argument names to CamelCase, so this will\n    # pass even though the argument was defined as :isPublished\n    it { is_expected.to accept_argument(:is_published).of_type(\"Boolean\") }\n  end\nend\n```\n\n### 4) Test an object's interface implementations:\n\n```ruby\ndescribe PostType do\n  subject { described_class }\n\n  it 'implements interface Node' do\n    expect(subject).to implement('Node')\n  end\n\n  it { is_expected.not_to implement('OtherInterface') }\nend\n```\n\n### 5) Using camelize: false on field names\n\nBy default the graphql gem camelizes field names. This gem deals with it transparently:\n\n```ruby\nclass ObjectMessingWithCamelsAndSnakesType < GraphQL::Schema::Object\n  graphql_name 'ObjectMessingWithCamelsAndSnakes'\n\n  implements GraphQL::Types::Relay::Node\n\n  field :me_gusta_los_camellos, ID, null: false\n\n  # note the camelize: false\n  field :prefiero_serpientes, ID, null: false, camelize: false\nend\n```\n\nThe following specs demonstrate the current behavior of the gem regarding fields:\n\n```ruby\ndescribe ObjectMessingWithCamelsAndSnakesType do\n  subject { described_class }\n\n  # For a field name that was automatically camelized, you can add expectations\n  # against both versions and we handle it transparently:\n  it { is_expected.to have_a_field(:meGustaLosCamellos) }\n  it { is_expected.to have_a_field(:me_gusta_los_camellos) }\n\n  # However, when using camelize: false, you have to use the exact case of the field definition:\n  it { is_expected.to have_a_field(:prefiero_serpientes) }\n  it { is_expected.not_to have_a_field(:prefieroSerpientes) } # Note we're using `not_to`\nend\n```\n\nThis behaviour is currently active only on field name matching. PRs are welcome to\nreproduce it to arguments as well.\n\n## TODO\n\n-   New matchers!\n\n## Contributing\n\n-   Send Bug reports, suggestions or any general\n    question through the [Issue tracker](https://github.com/khamusa/rspec-graphql_matchers/issues).\n    Think of another matcher that could be useful? This is the place to ask, or...\n-   Pull requests are welcome through the usual procedure: fork the project,\n    commit your changes and open the [PR](https://github.com/khamusa/rspec-graphql_matchers/pulls).\n\nThis project is intended to be a safe, welcoming space for collaboration, and\ncontributors are expected to adhere to the\n[Contributor Covenant](http://contributor-covenant.org) code of conduct.\n\n## License\n\nThe gem is available as open source under the terms of the\n[MIT License](http://opensource.org/licenses/MIT).\n"
  },
  {
    "path": "Rakefile",
    "content": "# frozen_string_literal: true\n\nrequire 'bundler/gem_tasks'\nrequire 'rspec/core/rake_task'\nrequire 'rubocop/rake_task'\n\nRSpec::Core::RakeTask.new(:spec)\nRuboCop::RakeTask.new\n\ntask default: %i[spec rubocop]\n"
  },
  {
    "path": "bin/console",
    "content": "#!/usr/bin/env ruby\n# frozen_string_literal: true\n\nrequire 'bundler/setup'\nrequire 'rspec/graphql_matchers'\n\n# You can add fixtures and/or initialization code here to make experimenting\n# with your gem easier. You can also use a different console, if you like.\n\n# (If you use this, don't forget to add pry to your Gemfile!)\n# require \"pry\"\n# Pry.start\n\nrequire 'irb'\nIRB.start\n"
  },
  {
    "path": "bin/setup",
    "content": "#!/usr/bin/env bash\nset -euo pipefail\nIFS=$'\\n\\t'\nset -vx\n\nbundle install\n\n# Do any other automated setup that you need to do here\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/accept_argument.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative 'base_matcher'\nrequire_relative './have_a_field_matchers/of_type'\n\nmodule RSpec\n  module GraphqlMatchers\n    class AcceptArgument < BaseMatcher\n      def initialize(expected_arg_name)\n        @expectations = []\n\n        if expected_arg_name.is_a?(Hash)\n          (expected_arg_name, expected_type) = expected_arg_name.to_a.first\n          of_type(expected_type)\n\n          warn 'DEPRECATION WARNING: using accept_arguments with a hash will be '\\\n               'deprecated on the next major release. Use the format ' \\\n               \"`accept_argument(:argument_name).of_type('ExpectedType!') instead.`\"\n        end\n\n        @expected_arg_name = expected_arg_name.to_s\n        @expected_camel_arg_name = GraphQL::Schema::Member::BuildType.camelize(\n          @expected_arg_name\n        )\n      end\n\n      def matches?(graph_object)\n        @graph_object = graph_object\n\n        @actual_argument = field_arguments[@expected_arg_name]\n        @actual_argument ||= field_arguments[@expected_camel_arg_name]\n        return false if @actual_argument.nil?\n\n        @results = @expectations.reject do |matcher|\n          matcher.matches?(@actual_argument)\n        end\n\n        @results.empty?\n      end\n\n      def of_type(expected_field_type)\n        @expectations << HaveAFieldMatchers::OfType.new(expected_field_type)\n        self\n      end\n\n      def failure_message\n        base_msg = \"expected #{member_name(@graph_object)} \" \\\n          \"to accept argument `#{@expected_arg_name}`\" \\\n\n        return \"#{base_msg} #{failure_messages.join(', ')}\" if @actual_argument\n\n        \"#{base_msg} but no argument was found with that name\"\n      end\n\n      def description\n        [\"accept argument `#{@expected_arg_name}`\"].concat(descriptions).join(', ')\n      end\n\n      private\n\n      def descriptions\n        results.map(&:description)\n      end\n\n      def failure_messages\n        results.map(&:failure_message)\n      end\n\n      def field_arguments\n        if @graph_object.respond_to?(:arguments)\n          @graph_object.public_send(:arguments)\n        else\n          raise \"Invalid object #{@graph_object} provided to accept_argument \" \\\n            'matcher. It does not seem to be a valid GraphQL object type.'\n        end\n      end\n\n      def results\n        @results ||= []\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/accept_arguments.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative 'base_matcher'\n\nmodule RSpec\n  module GraphqlMatchers\n    class AcceptArguments < BaseMatcher\n      attr_reader :actual_field, :expected_args\n\n      def initialize(expected_args)\n        @expected_args = expected_args\n      end\n\n      def matches?(actual_field)\n        @actual_field = actual_field\n\n        @expected_args.all? do |arg_name, arg_type|\n          matches_argument?(arg_name, arg_type)\n        end\n      end\n\n      def failure_message\n        \"expected field '#{member_name(actual_field)}' to accept arguments \"\\\n        \"#{describe_arguments(expected_args)}\"\n      end\n\n      def description\n        \"accept arguments #{describe_arguments(expected_args)}\"\n      end\n\n      private\n\n      def matches_argument?(arg_name, arg_type)\n        camel_arg_name = GraphQL::Schema::Member::BuildType.camelize(arg_name.to_s)\n        actual_arg = actual_field.arguments[arg_name.to_s]\n        actual_arg ||= actual_field.arguments[camel_arg_name]\n\n        actual_arg && types_match?(actual_arg.type, arg_type)\n      end\n\n      def describe_arguments(what_args)\n        what_args.sort.map do |arg_name, arg_type|\n          \"#{arg_name}(#{type_name(arg_type)})\"\n        end.join(', ')\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/base_matcher.rb",
    "content": "# frozen_string_literal: true\n\nmodule RSpec\n  module GraphqlMatchers\n    class BaseMatcher\n      private\n\n      def member_name(member)\n        member.respond_to?(:graphql_name) && member.graphql_name ||\n          member.respond_to?(:name) && member.name ||\n          member.inspect\n      end\n\n      def types_match?(actual_type, expected_type)\n        expected_type.nil? || type_name(expected_type) == type_name(actual_type)\n      end\n\n      def type_name(a_type)\n        a_type = a_type.to_type_signature if a_type.respond_to?(:to_type_signature)\n\n        a_type.to_s\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/be_of_type.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative 'base_matcher'\n\nmodule RSpec\n  module GraphqlMatchers\n    class BeOfType < BaseMatcher\n      attr_reader :sample, :expected\n\n      def initialize(expected)\n        @expected = expected\n      end\n\n      def matches?(actual_sample)\n        @sample = to_graphql(actual_sample)\n        sample.respond_to?(:type) && types_match?(sample.type, @expected)\n      end\n\n      def failure_message\n        \"expected field '#{member_name(sample)}' to \" \\\n        \"be of type '#{type_name(expected)}', \" \\\n        \"but it was '#{type_name(sample.type)}'\"\n      end\n\n      def description\n        \"be of type '#{expected}'\"\n      end\n\n      private\n\n      def to_graphql(field_sample)\n        return field_sample unless field_sample.respond_to?(:to_type_signature)\n\n        field_sample.to_type_signature\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/have_a_field.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative 'base_matcher'\nrequire_relative './have_a_field_matchers/of_type'\nrequire_relative './have_a_field_matchers/with_property'\nrequire_relative './have_a_field_matchers/with_metadata'\nrequire_relative './have_a_field_matchers/with_hash_key'\nrequire_relative './have_a_field_matchers/with_deprecation_reason'\n\nmodule RSpec\n  module GraphqlMatchers\n    class HaveAField < BaseMatcher\n      def initialize(expected_field_name, fields = :fields)\n        @expected_field_name = expected_field_name.to_s\n        @expected_camel_field_name = GraphQL::Schema::Member::BuildType.camelize(\n          @expected_field_name\n        )\n        @fields = fields.to_sym\n        @expectations = []\n      end\n\n      def matches?(graph_object)\n        @graph_object = graph_object\n\n        return false if actual_field.nil?\n\n        @results = @expectations.reject do |matcher|\n          matcher.matches?(actual_field)\n        end\n\n        @results.empty?\n      end\n\n      def that_returns(expected_field_type)\n        @expectations << HaveAFieldMatchers::OfType.new(expected_field_type)\n        self\n      end\n\n      alias returning that_returns\n      alias of_type that_returns\n\n      def with_property(expected_property_name)\n        @expectations << HaveAFieldMatchers::WithProperty.new(expected_property_name)\n        self\n      end\n\n      def with_hash_key(expected_hash_key)\n        @expectations << HaveAFieldMatchers::WithHashKey.new(expected_hash_key)\n\n        self\n      end\n\n      def with_metadata(expected_metadata)\n        @expectations << HaveAFieldMatchers::WithMetadata.new(expected_metadata)\n        self\n      end\n\n      def with_deprecation_reason(expected_reason = nil)\n        @expectations << HaveAFieldMatchers::WithDeprecationReason.new(expected_reason)\n        self\n      end\n\n      def failure_message\n        base_msg = \"expected #{member_name(@graph_object)} \" \\\n          \"to define field `#{@expected_field_name}`\" \\\n\n        return \"#{base_msg} #{failure_messages.join(', ')}\" if actual_field\n\n        \"#{base_msg} but no field was found with that name\"\n      end\n\n      def description\n        [\"define field `#{@expected_field_name}`\"].concat(descriptions).join(', ')\n      end\n\n      private\n\n      def actual_field\n        @actual_field ||= begin\n          field = field_collection[@expected_field_name]\n          field ||= field_collection[@expected_camel_field_name]\n\n          field.respond_to?(:to_type_signature) ? field.to_type_signature : field\n        end\n      end\n\n      def descriptions\n        results.map(&:description)\n      end\n\n      def failure_messages\n        results.map(&:failure_message)\n      end\n\n      def field_collection\n        if @graph_object.respond_to?(@fields)\n          @graph_object.public_send(@fields)\n        else\n          raise \"Invalid object #{@graph_object} provided to #{matcher_name} \" \\\n            'matcher. It does not seem to be a valid GraphQL object type.'\n        end\n      end\n\n      def matcher_name\n        case @fields\n        when :fields then 'have_a_field'\n        when :arguments then 'have_an_input_field'\n        end\n      end\n\n      def results\n        @results ||= []\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/have_a_field_matchers/of_type.rb",
    "content": "# frozen_string_literal: true\n\nmodule RSpec\n  module GraphqlMatchers\n    module HaveAFieldMatchers\n      class OfType < RSpec::GraphqlMatchers::BeOfType\n        def description\n          \"of type `#{type_name(expected)}`\"\n        end\n\n        def failure_message\n          \"#{description}, but it was `#{type_name(sample.type)}`\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/have_a_field_matchers/with_deprecation_reason.rb",
    "content": "# frozen_string_literal: true\n\nmodule RSpec\n  module GraphqlMatchers\n    module HaveAFieldMatchers\n      class WithDeprecationReason\n        def initialize(expected_reason)\n          @expected_reason = expected_reason\n        end\n\n        def matches?(actual_field)\n          @actual_reason = actual_field.deprecation_reason\n\n          if @expected_reason.nil?\n            !actual_field.deprecation_reason.nil?\n          else\n            actual_field.deprecation_reason == @expected_reason\n          end\n        end\n\n        def failure_message\n          message = \"#{description}, but it was \"\n          message + (@actual_reason.nil? ? 'not deprecated' : \"`#{@actual_reason}`\")\n        end\n\n        def description\n          if @expected_reason.nil?\n            'with a deprecation reason'\n          else\n            \"with deprecation reason `#{@expected_reason}`\"\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/have_a_field_matchers/with_hash_key.rb",
    "content": "# frozen_string_literal: true\n\nmodule RSpec\n  module GraphqlMatchers\n    module HaveAFieldMatchers\n      class WithHashKey\n        def initialize(expected_hash_key)\n          @expected_hash_key = expected_hash_key\n        end\n\n        def description\n          \"with hash key `#{@expected_hash_key}`\"\n        end\n\n        def matches?(actual_field)\n          @actual_hash_key = get_hash_key(actual_field)\n          @actual_hash_key == @expected_hash_key.to_sym\n        end\n\n        def failure_message\n          \"#{description}, but it was `#{@actual_hash_key}`\"\n        end\n\n        private\n\n        def get_hash_key(actual_field)\n          if actual_field.respond_to?(:hash_key)\n            return actual_field.hash_key.to_sym if actual_field.hash_key\n          end\n\n          if actual_field.respond_to?(:metadata)\n            return actual_field.metadata[:type_class].method_sym\n          end\n\n          actual_field.method_sym\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/have_a_field_matchers/with_metadata.rb",
    "content": "# frozen_string_literal: true\n\nmodule RSpec\n  module GraphqlMatchers\n    module HaveAFieldMatchers\n      class WithMetadata\n        def initialize(expected_metadata)\n          @expected_metadata = expected_metadata\n        end\n\n        def description\n          \"with metadata `#{@expected_metadata}`\"\n        end\n\n        def matches?(actual_field)\n          @actual_metadata = actual_field.metadata\n          actual_field.metadata == @expected_metadata\n        end\n\n        def failure_message\n          \"#{description}, but it was `#{@actual_metadata}`\"\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/have_a_field_matchers/with_property.rb",
    "content": "# frozen_string_literal: true\n\nmodule RSpec\n  module GraphqlMatchers\n    module HaveAFieldMatchers\n      class WithProperty\n        def initialize(expected_property_name)\n          @expected_property_name = expected_property_name\n        end\n\n        def description\n          \"resolving with property `#{@expected_property_name}`\"\n        end\n\n        def matches?(actual_field)\n          @actual_property = property(actual_field).to_sym\n          @actual_property == @expected_property_name.to_sym\n        end\n\n        def failure_message\n          \"#{description}, but it was `#{@actual_property}`\"\n        end\n\n        private\n\n        def property(field)\n          property = field.property\n          property = field.metadata[:type_class].method_sym if property.nil?\n          property\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/implement.rb",
    "content": "# frozen_string_literal: true\n\nrequire_relative 'base_matcher'\n\nmodule RSpec\n  module GraphqlMatchers\n    class Implement < BaseMatcher\n      def initialize(interfaces)\n        @expected = interfaces.map { |interface| interface_name(interface) }\n      end\n\n      def matches?(graph_object)\n        @graph_object = graph_object\n        @actual = actual\n        @expected.all? { |name| @actual.include?(name) }\n      end\n\n      def failure_message\n        message  = \"expected interfaces: #{@expected.join(', ')}\\n\"\n        message += \"actual interfaces:   #{@actual.join(', ')}\"\n        message\n      end\n\n      def failure_message_when_negated\n        message  = \"unexpected interfaces: #{@expected.join(', ')}\\n\"\n        message += \"actual interfaces:     #{@actual.join(', ')}\"\n        message\n      end\n\n      def description\n        \"implement #{@expected.join(', ')}\"\n      end\n\n      private\n\n      def actual\n        if @graph_object.respond_to?(:interfaces)\n          return @graph_object.interfaces.map do |interface|\n            interface_name(interface)\n          end\n        end\n\n        raise \"Invalid object #{@graph_object} provided to #{matcher_name} \" \\\n          'matcher. It does not seem to be a valid GraphQL object type.'\n      end\n\n      def interface_name(interface)\n        return interface.graphql_name if interface.respond_to?(:graphql_name)\n\n        interface.to_s\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/matchers.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rspec/matchers'\nrequire 'rspec/graphql_matchers/be_of_type'\nrequire 'rspec/graphql_matchers/accept_arguments'\nrequire 'rspec/graphql_matchers/accept_argument'\nrequire 'rspec/graphql_matchers/have_a_field'\nrequire 'rspec/graphql_matchers/implement'\n\nmodule RSpec\n  module Matchers\n    def be_of_type(expected)\n      RSpec::GraphqlMatchers::BeOfType.new(expected)\n    end\n\n    def accept_argument(expected_argument)\n      RSpec::GraphqlMatchers::AcceptArgument.new(expected_argument)\n    end\n\n    def accept_arguments(expected_args)\n      RSpec::GraphqlMatchers::AcceptArguments.new(expected_args)\n    end\n\n    # rubocop:disable Naming/PredicateName\n    def have_a_field(field_name)\n      RSpec::GraphqlMatchers::HaveAField.new(field_name)\n    end\n    alias have_field have_a_field\n\n    def have_an_input_field(field_name)\n      RSpec::GraphqlMatchers::HaveAField.new(field_name, :arguments)\n    end\n    alias have_input_field have_an_input_field\n\n    def have_a_return_field(field_name)\n      RSpec::GraphqlMatchers::HaveAField.new(field_name)\n    end\n    alias have_return_field have_a_return_field\n    # rubocop:enable Naming/PredicateName\n\n    def implement(*interface_names)\n      RSpec::GraphqlMatchers::Implement.new(interface_names.flatten)\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/types_helper.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'graphql'\n\nmodule RSpec\n  module GraphqlMatchers\n    module TypesHelper\n      class << self\n        extend Gem::Deprecate\n\n        GraphQL::Types.constants.each do |constant_name|\n          klass = GraphQL::Types.const_get(constant_name)\n\n          define_method(constant_name) { klass }\n\n          deprecate constant_name, \"GraphQL::Types::#{constant_name}\", 2023, 10\n        end\n      end\n\n      def types\n        TypesHelper\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers/version.rb",
    "content": "# frozen_string_literal: true\n\nmodule Rspec\n  module GraphqlMatchers\n    VERSION = '2.0.0-rc.0'.freeze\n  end\nend\n"
  },
  {
    "path": "lib/rspec/graphql_matchers.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'rspec/graphql_matchers/version'\nrequire 'rspec/graphql_matchers/matchers'\nrequire 'rspec/graphql_matchers/types_helper'\n"
  },
  {
    "path": "rspec-graphql_matchers.gemspec",
    "content": "# frozen_string_literal: true\n\nlib = File.expand_path('lib', __dir__)\n$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)\nrequire 'rspec/graphql_matchers/version'\n\nGem::Specification.new do |spec|\n  spec.name = 'rspec-graphql_matchers'\n  spec.version = Rspec::GraphqlMatchers::VERSION\n  spec.authors = ['Samuel Brandão']\n  spec.email = ['gb.samuel@gmail.com']\n\n  spec.summary = 'Collection of rspec matchers to test your graphQL api schema.'\n  spec.homepage = 'https://github.com/khamusa/rspec-graphql_matchers'\n  spec.license = 'MIT'\n\n  spec.files =\n    `git ls-files -z`\n      .split(\"\\x0\")\n      .reject { |f| f.match(%r{^(test|spec|features)/}) }\n  spec.bindir = 'exe'\n  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }\n  spec.require_paths = ['lib']\n\n  spec.add_dependency 'graphql', '~> 2.0'\n  spec.add_dependency 'rspec', '~> 3.0'\n  spec.add_development_dependency 'bundler', '~> 2.0'\n  # CodeClimate does not yet support SimpleCov 0.18\n  spec.add_development_dependency 'simplecov', '~>0.17.0'\n  spec.add_development_dependency 'pry', '~> 0'\n  spec.add_development_dependency 'rubocop', '0.71'\nend\n"
  },
  {
    "path": "spec/rspec/accept_argument_matcher_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nmodule RSpec\n  module GraphqlMatchers\n    describe 'expect(a_type).to accept_argument(field_name)' do\n      subject(:a_type) do\n        Class.new(GraphQL::Schema::InputObject) do\n          graphql_name 'TestObject'\n\n          argument :id, GraphQL::Types::String, required: false\n          argument :other, GraphQL::Types::ID, required: true\n          argument :is_test, GraphQL::Types::Boolean, required: false\n          argument :not_camelized, GraphQL::Types::Boolean, required: false,\n                                                            camelize: false\n        end\n      end\n\n      it { is_expected.to accept_argument(:id) }\n\n      it 'passes when the type defines the field' do\n        expect(a_type).to accept_argument(:id)\n      end\n\n      it 'passes with the underscored argument name' do\n        expect(a_type).to accept_argument(:is_test)\n      end\n\n      it 'passes with the camel cased argument name' do\n        expect(a_type).to accept_argument(:isTest)\n      end\n\n      it 'matches a non camelized argument with the underscored argument name' do\n        expect(a_type).to accept_argument(:not_camelized)\n      end\n\n      it 'fails when the type does not define the expected field' do\n        expect { expect(a_type).to accept_argument(:ids) }\n          .to fail_with(\n            'expected TestObject to accept argument `ids` but no argument was found ' \\\n            'with that name'\n          )\n      end\n\n      it 'fails with a failure message when the type does not define the field' do\n        expect { expect(a_type).to accept_argument(:ids) }\n          .to fail_with(\n            'expected TestObject to accept argument `ids` but no argument ' \\\n            'was found with that name'\n          )\n      end\n\n      it 'provides a description' do\n        matcher = accept_argument(:id)\n        matcher.matches?(a_type)\n\n        expect(matcher.description).to eq('accept argument `id`')\n      end\n\n      describe '.of_type(a_type)' do\n        it 'passes when the type defines the field with correct type as ' \\\n          'strings' do\n          expect(a_type).to accept_argument(:id).of_type('String')\n          expect(a_type).to accept_argument('other').of_type('ID!')\n          expect(a_type).to accept_argument('other' => 'ID!')\n        end\n\n        it 'passes when the type defines the field with correct type as ' \\\n          'graphql objects' do\n          expect(a_type).to accept_argument(:id).of_type(GraphQL::Types::String)\n          expect(a_type).to accept_argument('other').of_type('ID!')\n        end\n\n        it 'fails when the type defines a field of the wrong type' do\n          expect { expect(a_type).to accept_argument(:id).of_type('String!') }\n            .to fail_with(\n              'expected TestObject to accept argument `id` ' \\\n              'of type `String!`, but it was `String`'\n            )\n\n          expect { expect(a_type).to accept_argument('other').of_type(GraphQL::Types::Int.to_non_null_type) }\n            .to fail_with(\n              'expected TestObject to accept argument `other` ' \\\n              'of type `Int!`, but it was `ID!`'\n            )\n\n          expect { expect(a_type).to accept_argument('other' => GraphQL::Types::Int.to_non_null_type) }\n            .to fail_with(\n              'expected TestObject to accept argument `other` ' \\\n              'of type `Int!`, but it was `ID!`'\n            )\n        end\n\n        context 'when an invalid type is passed' do\n          let(:a_type) { {} }\n\n          it 'fails with a Runtime error' do\n            expect { expect(a_type).to accept_argument(:id) }\n              .to raise_error(\n                RuntimeError,\n                'Invalid object {} provided to accept_argument ' \\\n                'matcher. It does not seem to be a valid GraphQL object type.'\n              )\n          end\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/accept_arguments_matcher_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\nrequire 'graphql'\n\ndescribe 'expect(a_field).to accept_arguments(arg_name: arg_type, ...)' do\n  subject(:field) do\n    Class.new(GraphQL::Schema::InputObject) do\n      graphql_name 'SomeInputObject'\n\n      argument :id, GraphQL::Types::ID, required: true\n      argument :name, GraphQL::Types::String, required: true\n      argument :age, GraphQL::Types::Int, required: false\n      argument :is_test, GraphQL::Types::Boolean, required: false\n      argument :not_camelized, GraphQL::Types::Boolean, required: false, camelize: false\n    end\n  end\n\n  describe '#matches?' do\n    context 'when expecting a single argument with type' do\n      let(:expected_args) { { id: GraphQL::Types::ID.to_non_null_type } }\n\n      context 'when the field accepts the expected argument name and type' do\n        it { is_expected.to accept_arguments(expected_args) }\n      end\n\n      context 'the field accepts an argument with the same name but different type' do\n        let(:expected_args) { { id: GraphQL::Types::ID } }\n\n        it { is_expected.not_to accept_arguments(expected_args) }\n      end\n\n      context 'the field does not accept the expected args' do\n        let(:expected_args) { { idz: GraphQL::Types::ID.to_non_null_type } }\n\n        it { is_expected.not_to accept_arguments(expected_args) }\n      end\n\n      context 'when the expected argument is camelcase' do\n        let(:expected_args) { { isTest: GraphQL::Types::Boolean } }\n\n        it { is_expected.to accept_arguments(expected_args) }\n      end\n\n      context 'when the expected argument is underscored' do\n        let(:expected_args) { { is_test: GraphQL::Types::Boolean } }\n\n        it { is_expected.to accept_arguments(expected_args) }\n\n        context 'when the actual argument is not camelized' do\n          let(:expected_args) { { not_camelized: GraphQL::Types::Boolean } }\n\n          it { is_expected.to accept_arguments(expected_args) }\n        end\n      end\n    end\n\n    context 'when expecting multiple arguments with type' do\n      context 'when the field accepts only one argument with correct name and type' do\n        let(:expected_args) do\n          {\n            id: GraphQL::Types::ID.to_non_null_type,\n            age: GraphQL::Types::Int.to_list_type,\n            name: GraphQL::Types::String\n          }\n        end\n\n        it { is_expected.not_to accept_arguments(expected_args) }\n      end\n\n      context 'when the field accepts all but one of the argument expected args' do\n        let(:expected_args) do\n          {\n            id: GraphQL::Types::ID.to_non_null_type,\n            age: GraphQL::Types::Int,\n            name: GraphQL::Types::Float.to_non_null_type\n          }\n        end\n\n        it { is_expected.not_to accept_arguments(expected_args) }\n      end\n\n      context 'when the field accepts all arguments with correct type' do\n        let(:expected_args) do\n          {\n            id: GraphQL::Types::ID.to_non_null_type,\n            age: GraphQL::Types::Int,\n            name: GraphQL::Types::String.to_non_null_type\n          }\n        end\n\n        it { is_expected.to accept_arguments(expected_args) }\n      end\n    end\n  end\n\n  describe '#description' do\n    let(:matcher) { accept_arguments(expected_args) }\n\n    subject(:description) do\n      matcher.matches?(field)\n      matcher.description\n    end\n\n    context 'with a single expected argument with types specified' do\n      let(:expected_args) { { ability: 'Float' } }\n\n      it 'returns a description with the argument name and type' do\n        expect(description)\n          .to eq('accept arguments ability(Float)')\n      end\n    end\n\n    context 'with multiple expected arguments with types specified' do\n      let(:expected_args) do\n        { ability: GraphQL::Types::Int, id: GraphQL::Types::Int, some: GraphQL::Types::Boolean }\n      end\n\n      it 'describes the arguments the field should accept and their types' do\n        expect(description)\n          .to eq('accept arguments ability(Int), id(Int), some(Boolean)')\n      end\n    end\n  end\n\n  describe '#failure_message' do\n    let(:matcher) { accept_arguments(expected_args) }\n    let(:expected_args) { { will: 'NotMatch' } }\n\n    subject(:failure_message) do\n      matcher.matches?(field)\n      matcher.failure_message\n    end\n\n    it 'informs the expected and actual types' do\n      expect(failure_message).to end_with(\n        'to accept arguments will(NotMatch)'\n      )\n    end\n\n    it 'describes the field through #name' do\n      expect(failure_message)\n        .to start_with(\"expected field 'SomeInputObject' to\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/be_of_type_matcher_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\ndescribe 'expect(a_field).to be_of_type(graphql_type)' do\n  scalar_types = {\n    \"Boolean\" => GraphQL::Types::Boolean,\n    \"Int\" => GraphQL::Types::Int,\n    \"Float\" => GraphQL::Types::Float,\n    \"String\" => GraphQL::Types::String,\n    \"ID\" => GraphQL::Types::ID\n  }\n\n  non_nullable_scalar_types = scalar_types.each_with_object({}) do |(string_name, type), result|\n    result[\"#{string_name}!\"] = type.to_non_null_type\n  end\n\n  all_types = scalar_types.merge(non_nullable_scalar_types)\n\n  all_types.each do |(graphql_name, scalar_type)|\n    context \"when the field has type #{graphql_name}\" do\n      subject(:field) { double('GrahQL Field', type: field_type) }\n      let(:field_type) { scalar_type }\n\n      it \"matches a graphQL type object representing #{graphql_name}\" do\n        expect(field).to be_of_type(scalar_type)\n      end\n\n      it \"matches the string '#{graphql_name}'\" do\n        expect(field).to be_of_type(graphql_name)\n      end\n\n      it \"does not match the string '#{graphql_name.downcase}'\" do\n        expect(field).not_to be_of_type(graphql_name.downcase)\n      end\n\n      scalar_types.each do |(another_graphql_name, another_scalar)|\n        next if another_scalar == scalar_type\n\n        context \"when matching against the type #{another_scalar}\" do\n          let(:matcher)       { be_of_type(expected_type) }\n          let(:expected_type) { another_scalar }\n\n          it 'does not match' do\n            expect(matcher.matches?(field)).to be_falsy\n          end\n\n          describe 'the failure messages' do\n            subject(:failure_message) { matcher.failure_message }\n\n            before { matcher.matches?(field) }\n\n            it 'informs the expected and actual types' do\n              expect(failure_message).to end_with(\n                \"to be of type '#{another_graphql_name}', but it was '#{graphql_name}'\"\n              )\n            end\n\n            context 'the field does not respond to #name' do\n              it 'describes the field through #inspect' do\n                expect(failure_message).to start_with(\n                  \"expected field '#{field.inspect}' to be of type\"\n                )\n              end\n            end\n\n            context 'the field responds to #name' do\n              before { allow(field).to receive(:name).and_return('AField') }\n\n              it 'describes the field through #name' do\n                expect(failure_message)\n                  .to start_with(\"expected field 'AField' to be of type\")\n              end\n            end\n          end\n        end\n      end\n    end\n  end\n\n  describe '#description' do\n    let(:matcher) { be_of_type(String) }\n\n    it %q(is \"be of type 'String'\") do\n      matcher.matches?(double(type: 'NotMeaningful'))\n      expect(matcher.description).to eq(\"be of type 'String'\")\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/graphql_matchers_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\ndescribe Rspec::GraphqlMatchers do\n  it 'has a version number' do\n    expect(Rspec::GraphqlMatchers::VERSION).not_to be nil\n  end\nend\n"
  },
  {
    "path": "spec/rspec/have_a_field_matcher_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nmodule RSpec\n  module GraphqlMatchers\n    describe 'expect(a_type).to have_a_field(field_name)' do\n      shared_examples 'have a field' do\n        it { is_expected.to have_a_field(:id) }\n\n        it 'passes when the type defines the field' do\n          expect(a_type).to have_a_field(:id)\n        end\n\n        it 'passes with the underscored field name' do\n          expect(a_type).to have_a_field(:is_test)\n        end\n\n        it 'passes with the camel cased field name' do\n          expect(a_type).to have_a_field(:isTest)\n        end\n\n        it 'matches a non camelized field with the underscored field name' do\n          expect(a_type).to have_a_field(:not_camelized)\n        end\n\n        it 'fails when the type does not define the expected field' do\n          expect { expect(a_type).to have_a_field(:ids) }\n            .to fail_with(\n              'expected TestObject to define field `ids` but no field was found ' \\\n              'with that name'\n            )\n        end\n\n        it 'fails with a failure message when the type does not define the field' do\n          expect { expect(a_type).to have_a_field(:ids) }\n            .to fail_with(\n              'expected TestObject to define field `ids` but no field ' \\\n              'was found with that name'\n            )\n        end\n\n        it 'provides a description' do\n          matcher = have_a_field(:id)\n          matcher.matches?(a_type)\n\n          expect(matcher.description).to eq('define field `id`')\n        end\n\n        describe '.that_returns(a_type)' do\n          it 'passes when the type defines the field with correct type as ' \\\n            'strings' do\n            expect(a_type).to have_a_field(:id).that_returns('ID!')\n            expect(a_type).to have_a_field('other').that_returns('String')\n            expect(a_type).to have_a_field(:is_test).of_type('Boolean')\n            expect(a_type).to have_a_field(:isTest).of_type('Boolean')\n          end\n\n          it 'passes when the type defines the field with correct type as ' \\\n            'graphql objects' do\n            expect(a_type).to have_a_field(:id).that_returns('ID!')\n            expect(a_type).to have_a_field('other').of_type(GraphQL::Types::String)\n            expect(a_type).to have_a_field(:is_test).of_type(GraphQL::Types::Boolean)\n            expect(a_type).to have_a_field(:isTest).of_type(GraphQL::Types::Boolean)\n          end\n\n          it 'fails when the type defines a field of the wrong type' do\n            expect { expect(a_type).to have_a_field(:id).returning('ID') }\n              .to fail_with(\n                'expected TestObject to define field `id` ' \\\n                'of type `ID`, but it was `ID!`'\n              )\n\n            expect { expect(a_type).to have_a_field('other')\n              .returning(GraphQL::Types::Int.to_non_null_type) }\n              .to fail_with(\n                'expected TestObject to define field `other` ' \\\n                'of type `Int!`, but it was `String`'\n              )\n          end\n\n          context 'when an invalid type is passed' do\n            let(:a_type) { {} }\n\n            it 'fails with a Runtime error' do\n              expect { expect(a_type).to have_a_field(:id) }\n                .to raise_error(\n                  RuntimeError,\n                  'Invalid object {} provided to have_a_field ' \\\n                  'matcher. It does not seem to be a valid GraphQL object type.'\n                )\n            end\n          end\n        end\n\n        describe '.with_hash_key(hash_key)' do\n          it { is_expected.to have_a_field(:other).with_hash_key(:other_on_hash) }\n          it { is_expected.to have_a_field(:other).with_hash_key('other_on_hash') }\n\n          it 'fails when the hash_key is incorrect' do\n            expect do\n              expect(a_type).to have_a_field(:other).with_hash_key(:whatever)\n            end.to fail_with(\n              'expected TestObject to define field `other` ' \\\n              'with hash key `whatever`, but it was `other_on_hash`'\n            )\n          end\n        end\n\n        describe '.with_deprecation_reason' do\n          context 'when the field has a deprecation reason' do\n            let(:deprecated_field) { :deprecated_field }\n\n            context 'with an expected deprecation reason' do\n              it 'passes when the deprecation reasons match' do\n                expect(a_type).to have_a_field(deprecated_field)\n                  .with_deprecation_reason('deprecated')\n              end\n\n              it 'fails when the deprecation reasons do not match' do\n                expect do\n                  expect(a_type).to have_a_field(deprecated_field)\n                    .with_deprecation_reason('different deprecation reason')\n                end.to fail_with(\n                  'expected TestObject to define field `deprecated_field` with ' \\\n                  'deprecation reason `different deprecation reason`, ' \\\n                  'but it was `deprecated`'\n                )\n              end\n            end\n\n            context 'without an expected deprecation reason' do\n              it 'passes' do\n                expect(a_type).to have_a_field(deprecated_field).with_deprecation_reason\n              end\n            end\n          end\n\n          context 'when the field does not have a deprecation reason' do\n            let(:non_deprecated_field) { :id }\n\n            it 'fails without an expected deprecation reason' do\n              expect do\n                expect(a_type).to have_a_field(non_deprecated_field)\n                  .with_deprecation_reason\n              end.to fail_with(\n                'expected TestObject to define field `id` with a deprecation reason, ' \\\n                'but it was not deprecated'\n              )\n            end\n\n            it 'fails with an expected deprecation reason' do\n              expect do\n                expect(a_type).to have_a_field(non_deprecated_field)\n                  .with_deprecation_reason('deprecated')\n              end.to fail_with(\n                'expected TestObject to define field `id` with deprecation ' \\\n                'reason `deprecated`, but it was not deprecated'\n              )\n            end\n          end\n        end\n      end\n\n      subject(:a_type) do\n        Class.new(GraphQL::Schema::Object) do\n          graphql_name 'TestObject'\n\n          field :id, GraphQL::Types::ID, null: false\n          field :other, GraphQL::Types::String, hash_key: :other_on_hash, null: true\n          field :is_test, GraphQL::Types::Boolean, null: true\n          field :not_camelized, GraphQL::Types::String, null: false, camelize: false\n          field :deprecated_field, GraphQL::Types::String, null: true,\n                                                  deprecation_reason: 'deprecated'\n        end\n      end\n\n      include_examples 'have a field'\n\n      context 'with fields defined by implementing an interface' do\n        subject(:a_type) do\n          actual_interface = Module.new do\n            include GraphQL::Schema::Interface\n            graphql_name 'ActualInterface'\n\n            field :other, GraphQL::Types::String, hash_key: :other_on_hash, null: true\n            field :is_test, GraphQL::Types::Boolean, null: true\n            field :not_camelized, GraphQL::Types::String, null: false, camelize: false\n            field :deprecated_field, GraphQL::Types::String, null: true,\n                                                    deprecation_reason: 'deprecated'\n          end\n\n          Class.new(GraphQL::Schema::Object) do\n            graphql_name 'TestObject'\n\n            implements actual_interface\n            implements GraphQL::Types::Relay::Node\n          end\n        end\n\n        include_examples 'have a field'\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/have_a_return_field_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nmodule RSpec\n  module GraphqlMatchers\n    describe 'expect(a_type).to have_a_return_field(field_name)' \\\n             '.that_returns(a_type)' do\n      subject(:a_type) do\n        Class.new(GraphQL::Schema::RelayClassicMutation) do\n          graphql_name 'TestObject'\n\n          field :id, GraphQL::Types::String\n          field :other, GraphQL::Types::ID, null: false\n        end\n      end\n\n      it { is_expected.to have_a_return_field(:id) }\n\n      it 'passes when the type defines the field' do\n        expect(a_type).to have_a_return_field(:id)\n      end\n\n      it 'fails when the type does not define the expected field' do\n        expect(a_type).not_to have_a_return_field(:ids)\n      end\n\n      it 'fails with a failure message when the type does not define the field' do\n        expect { expect(a_type).to have_a_return_field(:ids) }\n          .to fail_with(\n            \"expected #{a_type.graphql_name} to define field `ids` but no field was \" \\\n            'found with that name'\n          )\n      end\n\n      it 'provides a description' do\n        matcher = have_a_return_field(:id)\n        matcher.matches?(a_type)\n\n        expect(matcher.description).to eq('define field `id`')\n      end\n\n      it 'passes when the type defines the field with correct type as strings' do\n        expect(a_type).to have_a_return_field(:id).that_returns('String')\n        expect(a_type).to have_a_return_field('other').that_returns('ID!')\n      end\n\n      it 'passes when the type defines the field with correct type as graphql ' \\\n         'objects' do\n        expect(a_type).to have_a_return_field(:id).that_returns(GraphQL::Types::String)\n        expect(a_type).to have_a_return_field('other').that_returns(GraphQL::Types::ID.to_non_null_type)\n      end\n\n      it 'fails when the type defines a field of the wrong type' do\n        expect { expect(a_type).to have_a_return_field(:id).returning('String!') }\n          .to fail_with(\n            \"expected #{a_type.graphql_name} to define field `id` of type `String!`, \" \\\n            'but it was `String`'\n          )\n\n        expect do\n          expect(a_type).to have_a_return_field('other').returning(GraphQL::Types::Int.to_non_null_type)\n        end.to fail_with(\n          \"expected #{a_type.graphql_name} to define field `other` of type `Int!`, \" \\\n          'but it was `ID!`'\n        )\n      end\n\n      context 'when an invalid type is passed' do\n        let(:a_type) { double(to_s: 'InvalidObject') }\n\n        it 'fails with a Runtime error' do\n          expect { expect(a_type).to have_a_return_field(:id) }\n            .to raise_error(\n              RuntimeError,\n              'Invalid object InvalidObject provided to have_a_field ' \\\n              'matcher. It does not seem to be a valid GraphQL object type.'\n            )\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/have_an_input_field_matcher_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nmodule RSpec\n  module GraphqlMatchers\n    describe 'expect(a_type).to have_an_input_field(field_name)' \\\n             '.that_returns(a_type)' do\n\n      subject(:a_type) do\n        Class.new(GraphQL::Schema::RelayClassicMutation) do\n          graphql_name 'TestObject'\n\n\n          argument :id, GraphQL::Types::String, required: false\n          argument :other, GraphQL::Types::ID, required: true\n        end\n      end\n\n      it { is_expected.to have_an_input_field(:id) }\n\n      it 'passes when the type defines the field' do\n        expect(a_type).to have_an_input_field(:id)\n      end\n\n      it 'fails when the type does not define the expected field' do\n        expect(a_type).not_to have_an_input_field(:ids)\n      end\n\n      it 'fails with a failure message when the type does not define the field' do\n        expect { expect(a_type).to have_an_input_field(:ids) }\n          .to fail_with(\n            \"expected #{a_type.graphql_name} to define field `ids` but no field was \" \\\n            'found with that name'\n          )\n      end\n\n      it 'provides a description' do\n        matcher = have_an_input_field(:id)\n        matcher.matches?(a_type)\n\n        expect(matcher.description).to eq('define field `id`')\n      end\n\n      it 'passes when the type defines the field with correct type as strings' do\n        expect(a_type).to have_an_input_field(:id).that_returns('String')\n        expect(a_type).to have_an_input_field('other').that_returns('ID!')\n      end\n\n      it 'passes when the type defines the field with correct type as graphql ' \\\n         'objects' do\n        expect(a_type).to have_an_input_field(:id).that_returns(GraphQL::Types::String)\n        expect(a_type).to have_an_input_field('other').that_returns(GraphQL::Types::ID.to_non_null_type)\n      end\n\n      it 'fails when the type defines a field of the wrong type' do\n        expect { expect(a_type).to have_an_input_field(:id).returning('String!') }\n          .to fail_with(\n            \"expected #{a_type.graphql_name} to define field `id` of type `String!`, \" \\\n            'but it was `String`'\n          )\n\n        expect do\n          expect(a_type).to have_an_input_field('other').returning(GraphQL::Types::Int.to_non_null_type)\n        end.to fail_with(\n          \"expected #{a_type.graphql_name} to define field `other` of type `Int!`, \" \\\n          'but it was `ID!`'\n        )\n      end\n\n      context 'when an invalid type is passed' do\n        let(:a_type) { double(to_s: 'InvalidObject') }\n\n        it 'fails with a Runtime error' do\n          expect { expect(a_type).to have_an_input_field(:id) }\n            .to raise_error(\n              RuntimeError,\n              'Invalid object InvalidObject provided to have_an_input_field ' \\\n              'matcher. It does not seem to be a valid GraphQL object type.'\n            )\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/implement_matcher_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\nmodule RSpec\n  module GraphqlMatchers\n    describe 'expect(a_type).to implement(interface_names)' do\n      AnInterface = Module.new do\n        include GraphQL::Schema::Interface\n        graphql_name 'AnInterface'\n      end\n\n      AnotherInterface = Module.new do\n        include GraphQL::Schema::Interface\n        graphql_name 'AnotherInterface'\n      end\n\n      AThirdInterface = Module.new do\n        include GraphQL::Schema::Interface\n        graphql_name 'AClassBasedApiInterface'\n      end\n\n      subject(:a_type) do\n        Class.new(GraphQL::Schema::Object) do\n          graphql_name 'TestObject'\n\n          implements GraphQL::Types::Relay::Node\n          implements AnInterface\n          implements AThirdInterface\n        end\n      end\n\n      it { is_expected.to implement('Node') }\n      it { is_expected.to implement('AnInterface') }\n      it { is_expected.to implement('AClassBasedApiInterface') }\n      it { is_expected.to implement('Node', 'AnInterface', 'AClassBasedApiInterface') }\n      it { is_expected.to implement(['Node']) }\n      it { is_expected.to implement(['AnInterface']) }\n      it { is_expected.to implement(%w[Node AnInterface]) }\n      it { is_expected.to implement(GraphQL::Types::Relay::Node, AnInterface) }\n      it do\n        is_expected.to implement([GraphQL::Types::Relay::Node, AnInterface])\n      end\n\n      it { is_expected.not_to implement('AnotherInterface') }\n      it { is_expected.not_to implement(['AnotherInterface']) }\n      it { is_expected.not_to implement(AnotherInterface) }\n      it { is_expected.not_to implement([AnotherInterface]) }\n\n      it 'fails with a message when the type does include the interfaces' do\n        expect { expect(a_type).to implement('AnotherInterface') }\n          .to fail_with(\n            \"expected interfaces: AnotherInterface\\n\" \\\n            'actual interfaces:   Node, AnInterface, AClassBasedApiInterface'\n          )\n      end\n\n      it 'provides a description' do\n        matcher = implement('Node, AnInterface')\n        matcher.matches?(a_type)\n\n        expect(matcher.description).to eq('implement Node, AnInterface')\n      end\n\n      context 'when an invalid type is passed' do\n        let(:a_type) { double(to_s: 'InvalidObject') }\n\n        it 'fails with a Runtime error' do\n          expect { expect(a_type).to have_a_field(:id) }\n            .to raise_error(\n              RuntimeError,\n              'Invalid object InvalidObject provided to have_a_field matcher. ' \\\n              'It does not seem to be a valid GraphQL object type.'\n            )\n        end\n      end\n    end\n  end\nend\n"
  },
  {
    "path": "spec/rspec/readme_spec.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'spec_helper'\n\ndescribe 'The readme Examples' do\n  ruby_code_regex = /```ruby(.*?)```/m\n  readme_content = File.read(\n    File.expand_path(\n      '../../README.md',\n      __dir__\n    )\n  )\n\n  # rubocop:disable Security/Eval\n  readme_content.scan(ruby_code_regex) do |ruby_code|\n    eval(ruby_code[0])\n  end\n  # rubocop:enable Security/Eval\nend\n"
  },
  {
    "path": "spec/spec_helper.rb",
    "content": "# frozen_string_literal: true\n\nrequire 'pry'\nrequire 'simplecov'\nSimpleCov.start\n$LOAD_PATH.unshift File.expand_path('../lib', __dir__)\nrequire 'rspec/graphql_matchers'\n# rubocop:disable Style/MixinUsage\ninclude RSpec::GraphqlMatchers::TypesHelper\n# rubocop:enable Style/MixinUsage\n\nmodule RSpec\n  module Matchers\n    def fail_with(message)\n      raise_error(RSpec::Expectations::ExpectationNotMetError, message)\n    end\n  end\nend\n"
  }
]