From 08c32cfede3b1e845bf053b3321f101ee8290166 Mon Sep 17 00:00:00 2001 From: Jordan Eldredge Date: Fri, 19 Jan 2024 13:18:36 -0800 Subject: [PATCH] Integration test for resolvers implementing fields for interface Reviewed By: monicatang Differential Revision: D52916612 fbshipit-source-id: 0b2e52b5dc92bf9a4ce29a611bfa4c7232dc945c --- .../src/project_fixture.rs | 5 +- .../fixtures/resolver_on_interface.expected | 356 ++++++++++++++++++ .../fixtures/resolver_on_interface.input | 46 +++ .../tests/relay_compiler_integration_test.rs | 9 +- 4 files changed, 414 insertions(+), 2 deletions(-) create mode 100644 compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.expected create mode 100644 compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.input diff --git a/compiler/crates/graphql-test-helpers/src/project_fixture.rs b/compiler/crates/graphql-test-helpers/src/project_fixture.rs index 1f5544413469d..6991346395b97 100644 --- a/compiler/crates/graphql-test-helpers/src/project_fixture.rs +++ b/compiler/crates/graphql-test-helpers/src/project_fixture.rs @@ -73,7 +73,10 @@ impl ProjectFixture { fs::create_dir_all(dir).expect("Expected to create temp dir"); for (file_name, content) in &self.files { - fs::write(dir.join(file_name), content).expect("Expected to write file"); + let file_path = dir.join(file_name); + fs::create_dir_all(file_path.clone().parent().unwrap()) + .expect("Expected to create dir"); + fs::write(file_path, content).expect("Expected to write file"); } } diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.expected b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.expected new file mode 100644 index 0000000000000..281066af3b04f --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.expected @@ -0,0 +1,356 @@ +==================================== INPUT ==================================== +//- PersonComponent.js +graphql`fragment PersonComponentFragment on IPerson { + name +}` + +//- UserTypeResolvers.js +/** + * @RelayResolver User implements IPerson + */ + + /** + * @RelayResolver User.name: String + */ + +//- AdminTypeResolvers.js +/** + * @RelayResolver Admin implements IPerson + */ + + /** + * @RelayResolver Admin.name: String + */ + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql", + "schemaExtensions": [ + "schema-extensions" + ], + "featureFlags": { + "enable_relay_resolver_transform": true, + "enable_resolver_normalization_ast": true, + "relay_resolver_enable_interface_output_type": { "kind": "enabled" } + } +} + +//- schema.graphql +# Empty server schema + +//- schema-extensions/extension.graphql +interface IPerson { + id: ID! + name: String +} +==================================== OUTPUT =================================== +//- __generated__/Admin____relay_model_instance.graphql.js +/** + * SignedSource<<8461666cd2581b056dffb184d149c4ae>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { Admin__id$data } from "Admin__id.graphql"; +import type { FragmentType } from "relay-runtime"; +import {Admin as adminRelayModelInstanceResolverType} from "AdminTypeResolvers"; +// Type assertion validating that `adminRelayModelInstanceResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(adminRelayModelInstanceResolverType: ( + id: Admin__id$data['id'], +) => mixed); +declare export opaque type Admin____relay_model_instance$fragmentType: FragmentType; +export type Admin____relay_model_instance$data = {| + +__relay_model_instance: ?ReturnType, + +$fragmentType: Admin____relay_model_instance$fragmentType, +|}; +export type Admin____relay_model_instance$key = { + +$data?: Admin____relay_model_instance$data, + +$fragmentSpreads: Admin____relay_model_instance$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "Admin____relay_model_instance", + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "Admin__id" + }, + "kind": "RelayResolver", + "name": "__relay_model_instance", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('Admin__id.graphql'), require('AdminTypeResolvers').Admin, 'id', true), + "path": "__relay_model_instance" + } + ], + "type": "Admin", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + Admin____relay_model_instance$fragmentType, + Admin____relay_model_instance$data, +>*/); + +//- __generated__/Admin__id.graphql.js +/** + * SignedSource<<29acfbf1d6f559b8b77e9cd1f35218c0>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type Admin__id$fragmentType: FragmentType; +export type Admin__id$data = {| + +id: string, + +$fragmentType: Admin__id$fragmentType, +|}; +export type Admin__id$key = { + +$data?: Admin__id$data, + +$fragmentSpreads: Admin__id$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "Admin__id", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ] + } + ], + "type": "Admin", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + Admin__id$fragmentType, + Admin__id$data, +>*/); + +//- __generated__/PersonComponentFragment.graphql.js +/** + * SignedSource<<0c7a40c7d7335bf20aeaf1274db556b1>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type PersonComponentFragment$fragmentType: FragmentType; +export type PersonComponentFragment$data = {| + +name: ?string, + +$fragmentType: PersonComponentFragment$fragmentType, +|}; +export type PersonComponentFragment$key = { + +$data?: PersonComponentFragment$data, + +$fragmentSpreads: PersonComponentFragment$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = (function(){ +var v0 = [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "name", + "storageKey": null + } +]; +return { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "PersonComponentFragment", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "kind": "InlineFragment", + "selections": (v0/*: any*/), + "type": "Admin", + "abstractKey": null + }, + { + "kind": "InlineFragment", + "selections": (v0/*: any*/), + "type": "User", + "abstractKey": null + } + ] + } + ], + "type": "IPerson", + "abstractKey": "__isIPerson" +}; +})(); + +(node/*: any*/).hash = "a57dd30bd59412781e9566e1553e2d70"; + +module.exports = ((node/*: any*/)/*: Fragment< + PersonComponentFragment$fragmentType, + PersonComponentFragment$data, +>*/); + +//- __generated__/User____relay_model_instance.graphql.js +/** + * SignedSource<<94945c0964315b1c832485dc58b5ff38>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { User__id$data } from "User__id.graphql"; +import type { FragmentType } from "relay-runtime"; +import {User as userRelayModelInstanceResolverType} from "UserTypeResolvers"; +// Type assertion validating that `userRelayModelInstanceResolverType` resolver is correctly implemented. +// A type error here indicates that the type signature of the resolver module is incorrect. +(userRelayModelInstanceResolverType: ( + id: User__id$data['id'], +) => mixed); +declare export opaque type User____relay_model_instance$fragmentType: FragmentType; +export type User____relay_model_instance$data = {| + +__relay_model_instance: ?ReturnType, + +$fragmentType: User____relay_model_instance$fragmentType, +|}; +export type User____relay_model_instance$key = { + +$data?: User____relay_model_instance$data, + +$fragmentSpreads: User____relay_model_instance$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "User____relay_model_instance", + "selections": [ + { + "alias": null, + "args": null, + "fragment": { + "args": null, + "kind": "FragmentSpread", + "name": "User__id" + }, + "kind": "RelayResolver", + "name": "__relay_model_instance", + "resolverModule": require('relay-runtime/experimental').resolverDataInjector(require('User__id.graphql'), require('UserTypeResolvers').User, 'id', true), + "path": "__relay_model_instance" + } + ], + "type": "User", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + User____relay_model_instance$fragmentType, + User____relay_model_instance$data, +>*/); + +//- __generated__/User__id.graphql.js +/** + * SignedSource<<0a0f39eb34bfc882d28378a0b05b3c17>> + * @flow + * @lightSyntaxTransform + * @nogrep + */ + +/* eslint-disable */ + +'use strict'; + +/*:: +import type { Fragment, ReaderFragment } from 'relay-runtime'; +import type { FragmentType } from "relay-runtime"; +declare export opaque type User__id$fragmentType: FragmentType; +export type User__id$data = {| + +id: string, + +$fragmentType: User__id$fragmentType, +|}; +export type User__id$key = { + +$data?: User__id$data, + +$fragmentSpreads: User__id$fragmentType, + ... +}; +*/ + +var node/*: ReaderFragment*/ = { + "argumentDefinitions": [], + "kind": "Fragment", + "metadata": null, + "name": "User__id", + "selections": [ + { + "kind": "ClientExtension", + "selections": [ + { + "alias": null, + "args": null, + "kind": "ScalarField", + "name": "id", + "storageKey": null + } + ] + } + ], + "type": "User", + "abstractKey": null +}; + +module.exports = ((node/*: any*/)/*: Fragment< + User__id$fragmentType, + User__id$data, +>*/); diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.input b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.input new file mode 100644 index 0000000000000..c36cbdae6efbd --- /dev/null +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration/fixtures/resolver_on_interface.input @@ -0,0 +1,46 @@ +//- PersonComponent.js +graphql`fragment PersonComponentFragment on IPerson { + name +}` + +//- UserTypeResolvers.js +/** + * @RelayResolver User implements IPerson + */ + + /** + * @RelayResolver User.name: String + */ + +//- AdminTypeResolvers.js +/** + * @RelayResolver Admin implements IPerson + */ + + /** + * @RelayResolver Admin.name: String + */ + +//- relay.config.json +{ + "language": "flow", + "jsModuleFormat": "haste", + "schema": "schema.graphql", + "schemaExtensions": [ + "schema-extensions" + ], + "featureFlags": { + "enable_relay_resolver_transform": true, + "enable_resolver_normalization_ast": true, + "relay_resolver_enable_interface_output_type": { "kind": "enabled" } + } +} + +//- schema.graphql +# Empty server schema + +//- schema-extensions/extension.graphql +interface IPerson { + id: ID! + name: String +} diff --git a/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs b/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs index 88a9c6cca5bd4..39e3179d13312 100644 --- a/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs +++ b/compiler/crates/relay-compiler/tests/relay_compiler_integration_test.rs @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<81e6648f89d4ad26d959f72f1eaab040>> + * @generated SignedSource<> */ mod relay_compiler_integration; @@ -82,6 +82,13 @@ async fn preloadable_query_typescript() { test_fixture(transform_fixture, file!(), "preloadable_query_typescript.input", "relay_compiler_integration/fixtures/preloadable_query_typescript.expected", input, expected).await; } +#[tokio::test] +async fn resolver_on_interface() { + let input = include_str!("relay_compiler_integration/fixtures/resolver_on_interface.input"); + let expected = include_str!("relay_compiler_integration/fixtures/resolver_on_interface.expected"); + test_fixture(transform_fixture, file!(), "resolver_on_interface.input", "relay_compiler_integration/fixtures/resolver_on_interface.expected", input, expected).await; +} + #[tokio::test] async fn resolvers_schema_module() { let input = include_str!("relay_compiler_integration/fixtures/resolvers_schema_module.input");