diff --git a/compiler/crates/common/src/feature_flags.rs b/compiler/crates/common/src/feature_flags.rs index 4dee91e95cfc2..8ea28bcd04724 100644 --- a/compiler/crates/common/src/feature_flags.rs +++ b/compiler/crates/common/src/feature_flags.rs @@ -76,6 +76,10 @@ pub struct FeatureFlags { /// Print queries in compact form #[serde(default)] pub compact_query_text: FeatureFlag, + + // Enables @relay_test_operation support for client data. + #[serde(default)] + pub enable_mock_client_data_metadata: FeatureFlag, } #[derive(Debug, Deserialize, Clone, Serialize)] diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs index b2afc708b3697..c0c618134da9e 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts/mod.rs @@ -120,6 +120,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { use_named_imports_for_relay_resolvers: false, relay_resolver_model_syntax_enabled: false, relay_resolver_enable_terse_syntax: false, + enable_mock_client_data_metadata: FeatureFlag::Disabled, }; let default_project_config = ProjectConfig { diff --git a/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs b/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs index 9e9c93e0a1966..deb8cfa6986aa 100644 --- a/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs +++ b/compiler/crates/relay-compiler/tests/compile_relay_artifacts_with_custom_id/mod.rs @@ -90,6 +90,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { use_named_imports_for_relay_resolvers: false, relay_resolver_model_syntax_enabled: false, relay_resolver_enable_terse_syntax: false, + enable_mock_client_data_metadata: FeatureFlag::Disabled, }; let project_config = ProjectConfig { diff --git a/compiler/crates/relay-transforms/src/apply_transforms.rs b/compiler/crates/relay-transforms/src/apply_transforms.rs index f00184c1df0c7..2c7ef855d421e 100644 --- a/compiler/crates/relay-transforms/src/apply_transforms.rs +++ b/compiler/crates/relay-transforms/src/apply_transforms.rs @@ -479,7 +479,13 @@ fn apply_normalization_transforms( } program = log_event.time("generate_test_operation_metadata", || { - generate_test_operation_metadata(&program, &project_config.test_path_regex) + generate_test_operation_metadata( + &program, + &project_config.test_path_regex, + &project_config + .feature_flags + .enable_mock_client_data_metadata, + ) })?; if let Some(print_stats) = maybe_print_stats { print_stats("generate_test_operation_metadata", &program); diff --git a/compiler/crates/relay-transforms/src/test_operation_metadata.rs b/compiler/crates/relay-transforms/src/test_operation_metadata.rs index a0e7443fa28ec..8fc709dac1013 100644 --- a/compiler/crates/relay-transforms/src/test_operation_metadata.rs +++ b/compiler/crates/relay-transforms/src/test_operation_metadata.rs @@ -9,6 +9,7 @@ use common::ArgumentName; use common::Diagnostic; use common::DiagnosticsResult; use common::DirectiveName; +use common::FeatureFlag; use common::NamedItem; use common::WithLocation; use graphql_ir::ConstantArgument; @@ -45,6 +46,7 @@ lazy_static! { static ref NULLABLE_KEY: ArgumentName = ArgumentName("nullable".intern()); static ref PLURAL_KEY: ArgumentName = ArgumentName("plural".intern()); static ref TYPE_KEY: ArgumentName = ArgumentName("type".intern()); + static ref MOCK_CLIENT_DATA: ArgumentName = ArgumentName("mock_client_data".intern()); } /// Transforms the @relay_test_operation directive to @__metadata thats printed @@ -54,8 +56,13 @@ lazy_static! { pub fn generate_test_operation_metadata( program: &Program, test_path_regex: &Option, + enable_mock_client_data_metadata_flag: &FeatureFlag, ) -> DiagnosticsResult { - let mut transformer = GenerateTestOperationMetadata::new(program, test_path_regex); + let mut transformer = GenerateTestOperationMetadata::new( + program, + test_path_regex, + enable_mock_client_data_metadata_flag, + ); let next_program = transformer .transform_program(program) .replace_or_else(|| program.clone()); @@ -67,23 +74,29 @@ pub fn generate_test_operation_metadata( } } -struct GenerateTestOperationMetadata<'a> { - program: &'a Program, - test_path_regex: &'a Option, +struct GenerateTestOperationMetadata<'program, 'flag> { + program: &'program Program, + test_path_regex: &'program Option, errors: Vec, + enable_mock_client_data_metadata_flag: &'flag FeatureFlag, } -impl<'a> GenerateTestOperationMetadata<'a> { - fn new(program: &'a Program, test_path_regex: &'a Option) -> Self { +impl<'program, 'flag> GenerateTestOperationMetadata<'program, 'flag> { + fn new( + program: &'program Program, + test_path_regex: &'program Option, + enable_mock_client_data_metadata_flag: &'flag FeatureFlag, + ) -> Self { GenerateTestOperationMetadata { program, test_path_regex, errors: Vec::new(), + enable_mock_client_data_metadata_flag: &enable_mock_client_data_metadata_flag, } } } -impl<'a> Transformer for GenerateTestOperationMetadata<'a> { +impl<'program, 'flag> Transformer for GenerateTestOperationMetadata<'program, 'flag> { const NAME: &'static str = "GenerateTestOperationMetadata"; const VISIT_ARGUMENTS: bool = false; const VISIT_DIRECTIVES: bool = false; @@ -116,6 +129,8 @@ impl<'a> Transformer for GenerateTestOperationMetadata<'a> { ConstantValue::Object(From::from(RelayTestOperationMetadata::new( self.program, &operation.selections, + self.enable_mock_client_data_metadata_flag + .is_fully_enabled(), ))), )); } else { @@ -211,7 +226,7 @@ pub struct RelayTestOperationMetadata { } impl RelayTestOperationMetadata { - pub fn new(program: &Program, selections: &[Selection]) -> Self { + pub fn new(program: &Program, selections: &[Selection], mock_client_data: bool) -> Self { let schema = program.schema.as_ref(); let mut selection_type_info: IndexMap = Default::default(); @@ -224,7 +239,7 @@ impl RelayTestOperationMetadata { match selection { Selection::ScalarField(scalar_field) => { let field = schema.field(scalar_field.definition.item); - if !field.is_extension { + if !field.is_extension || mock_client_data { let alias_or_name = scalar_field.alias_or_name(schema); let next_path = next_path(path, alias_or_name); selection_type_info.insert( @@ -235,7 +250,7 @@ impl RelayTestOperationMetadata { } Selection::LinkedField(linked_field) => { let field = schema.field(linked_field.definition.item); - if !field.is_extension { + if !field.is_extension || mock_client_data { let alias_or_name = linked_field.alias_or_name(schema); let next_path = next_path(path, alias_or_name); selection_type_info.insert( diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.expected b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.expected index a07827b0a110c..c206d1baa742d 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.expected +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.expected @@ -6,6 +6,7 @@ query ProdQuery @relay_test_operation { id } } +# %extensions% ==================================== ERROR ==================================== ✖︎ The `@relay_test_operation` directive is only allowed within test files because it creates larger generated files we don't want to include in production. File does not match test regex: ^test diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.graphql b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.graphql index d2da5fa230a06..1a34320349ec9 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.graphql +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/prod_query.invalid.graphql @@ -5,3 +5,4 @@ query ProdQuery @relay_test_operation { id } } +# %extensions% \ No newline at end of file diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_not_generated_query.expected b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_not_generated_query.expected new file mode 100644 index 0000000000000..a39e375936bb9 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_not_generated_query.expected @@ -0,0 +1,37 @@ +==================================== INPUT ==================================== +query ClientFieldsQuery @relay_test_operation { + node(id: "test-id") { + id + ... on User { + name + client_info { + name + description + } + } + } +} + +# %extensions% + +extend type User { + client_info: ClientInfo +} + +type ClientInfo { + name: String + description: String +} +==================================== OUTPUT =================================== +query ClientFieldsQuery @__metadata(relayTestingSelectionTypeInfo: {node: {enumValues: null, nullable: true, plural: false, type: "Node"}, node.id: {enumValues: null, nullable: false, plural: false, type: "ID"}, node.name: {enumValues: null, nullable: true, plural: false, type: "String"}}) { + node(id: "test-id") { + id + ... on User { + name + client_info { + name + description + } + } + } +} diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_not_generated_query.graphql b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_not_generated_query.graphql new file mode 100644 index 0000000000000..0d2e191413010 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_not_generated_query.graphql @@ -0,0 +1,23 @@ +query ClientFieldsQuery @relay_test_operation { + node(id: "test-id") { + id + ... on User { + name + client_info { + name + description + } + } + } +} + +# %extensions% + +extend type User { + client_info: ClientInfo +} + +type ClientInfo { + name: String + description: String +} diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_query.expected b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_query.expected new file mode 100644 index 0000000000000..85e54cea82fe2 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_query.expected @@ -0,0 +1,37 @@ +==================================== INPUT ==================================== +query ClientFieldsQuery @relay_test_operation { + node(id: "test-id") { + id + ... on User { + name + client_info { + name + description + } + } + } +} + +# %extensions% + +extend type User { + client_info: ClientInfo +} + +type ClientInfo { + name: String + description: String +} +==================================== OUTPUT =================================== +query ClientFieldsQuery @__metadata(relayTestingSelectionTypeInfo: {node: {enumValues: null, nullable: true, plural: false, type: "Node"}, node.id: {enumValues: null, nullable: false, plural: false, type: "ID"}, node.name: {enumValues: null, nullable: true, plural: false, type: "String"}, node.client_info: {enumValues: null, nullable: true, plural: false, type: "ClientInfo"}, node.client_info.name: {enumValues: null, nullable: true, plural: false, type: "String"}, node.client_info.description: {enumValues: null, nullable: true, plural: false, type: "String"}}) { + node(id: "test-id") { + id + ... on User { + name + client_info { + name + description + } + } + } +} diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_query.graphql b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_query.graphql new file mode 100644 index 0000000000000..0d2e191413010 --- /dev/null +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_client_fields_query.graphql @@ -0,0 +1,23 @@ +query ClientFieldsQuery @relay_test_operation { + node(id: "test-id") { + id + ... on User { + name + client_info { + name + description + } + } + } +} + +# %extensions% + +extend type User { + client_info: ClientInfo +} + +type ClientInfo { + name: String + description: String +} diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.expected b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.expected index 0df9d69cbc73b..5c4584075b223 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.expected +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.expected @@ -8,6 +8,7 @@ query QueryWitEnums @relay_test_operation { } } } +# %extensions% ==================================== OUTPUT =================================== query QueryWitEnums @__metadata(relayTestingSelectionTypeInfo: {node: {enumValues: null, nullable: true, plural: false, type: "Node"}, node.id: {enumValues: null, nullable: false, plural: false, type: "ID"}, node.name: {enumValues: null, nullable: true, plural: false, type: "String"}, node.environment: {enumValues: ["WEB", "MOBILE"], nullable: true, plural: false, type: "Environment"}}) { node(id: "test-id") { diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.graphql b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.graphql index c5629f34a9054..6c4be87f92099 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.graphql +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_query_with_enums.graphql @@ -7,3 +7,4 @@ query QueryWitEnums @relay_test_operation { } } } +# %extensions% \ No newline at end of file diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.expected b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.expected index 09e0385f19552..e0d1b47d7d646 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.expected +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.expected @@ -7,6 +7,7 @@ query SimpleQuery @relay_test_operation { } } } +# %extensions% ==================================== OUTPUT =================================== query SimpleQuery @__metadata(relayTestingSelectionTypeInfo: {node: {enumValues: null, nullable: true, plural: false, type: "Node"}, node.id: {enumValues: null, nullable: false, plural: false, type: "ID"}, node.name: {enumValues: null, nullable: true, plural: false, type: "String"}}) { node(id: "test-id") { diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.graphql b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.graphql index f9428e244f38a..985b6c4356ce2 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.graphql +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/fixtures/test_simple_query.graphql @@ -6,3 +6,4 @@ query SimpleQuery @relay_test_operation { } } } +# %extensions% \ No newline at end of file diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation/mod.rs b/compiler/crates/relay-transforms/tests/relay_test_operation/mod.rs index bf63e2ac636c4..3a88bfd19566c 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation/mod.rs +++ b/compiler/crates/relay-transforms/tests/relay_test_operation/mod.rs @@ -5,14 +5,72 @@ * LICENSE file in the root directory of this source tree. */ +use std::sync::Arc; + +use common::FeatureFlag; +use common::SourceLocationKey; use fixture_tests::Fixture; -use graphql_test_helpers::apply_transform_for_test; +use graphql_ir::build; +use graphql_ir::Program; +use graphql_syntax::parse_executable; +use graphql_test_helpers::diagnostics_to_sorted_string; +use graphql_text_printer::print_fragment; +use graphql_text_printer::print_operation; +use graphql_text_printer::PrinterOptions; use regex::Regex; +use relay_test_schema::get_test_schema_with_extensions; use relay_transforms::generate_test_operation_metadata; +fn transform_fixture_inner( + fixture: &Fixture<'_>, + enable_mock_client_data_metadata_flag: &FeatureFlag, +) -> Result { + let parts: Vec<_> = fixture.content.split("%extensions%").collect(); + + if let [base, extensions] = parts.as_slice() { + let source_location = SourceLocationKey::standalone(fixture.file_name); + let ast = parse_executable(base, source_location).unwrap(); + let schema = get_test_schema_with_extensions(extensions); + + let ir = build(&schema, &ast.definitions).unwrap(); + let program = Program::from_definitions(Arc::clone(&schema), ir); + + let test_path_regex = Some(Regex::new(r#"^test"#).unwrap()); + + let next_program = generate_test_operation_metadata( + &program, + &test_path_regex, + enable_mock_client_data_metadata_flag, + ) + .map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?; + + let printer_options = PrinterOptions { + debug_directive_data: true, + ..Default::default() + }; + + let mut printed = next_program + .operations() + .map(|def| print_operation(&schema, def, printer_options.clone())) + .chain( + next_program + .fragments() + .map(|def| print_fragment(&schema, def, printer_options.clone())), + ) + .collect::>(); + printed.sort(); + Ok(printed.join("\n\n")) + } else { + panic!("Expected exactly one %extensions% section marker.") + } +} + pub fn transform_fixture(fixture: &Fixture<'_>) -> Result { - let test_path_regex = Some(Regex::new(r#"^test"#).unwrap()); - apply_transform_for_test(fixture, |program| { - generate_test_operation_metadata(program, &test_path_regex) - }) + transform_fixture_inner(fixture, &FeatureFlag::Disabled) +} + +pub fn transform_fixture_with_mock_client_data_enabled( + fixture: &Fixture<'_>, +) -> Result { + transform_fixture_inner(fixture, &FeatureFlag::Enabled) } diff --git a/compiler/crates/relay-transforms/tests/relay_test_operation_test.rs b/compiler/crates/relay-transforms/tests/relay_test_operation_test.rs index 7f4e0dc5f36ae..c525f5ea65279 100644 --- a/compiler/crates/relay-transforms/tests/relay_test_operation_test.rs +++ b/compiler/crates/relay-transforms/tests/relay_test_operation_test.rs @@ -4,12 +4,13 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * - * @generated SignedSource<<13a74be1bf3601ce595319e9b12ebb4b>> + * @generated SignedSource<<83ef3f0f07b6241de41d1c8d97f48ff4>> */ mod relay_test_operation; use relay_test_operation::transform_fixture; +use relay_test_operation::transform_fixture_with_mock_client_data_enabled; use fixture_tests::test_fixture; #[test] @@ -19,6 +20,20 @@ fn prod_query_invalid() { test_fixture(transform_fixture, "prod_query.invalid.graphql", "relay_test_operation/fixtures/prod_query.invalid.expected", input, expected); } +#[test] +fn test_client_fields_not_generated_query() { + let input = include_str!("relay_test_operation/fixtures/test_client_fields_not_generated_query.graphql"); + let expected = include_str!("relay_test_operation/fixtures/test_client_fields_not_generated_query.expected"); + test_fixture(transform_fixture, "test_client_fields_not_generated_query.graphql", "relay_test_operation/fixtures/test_client_fields_not_generated_query.expected", input, expected); +} + +#[test] +fn test_client_fields_query() { + let input = include_str!("relay_test_operation/fixtures/test_client_fields_query.graphql"); + let expected = include_str!("relay_test_operation/fixtures/test_client_fields_query.expected"); + test_fixture(transform_fixture_with_mock_client_data_enabled, "test_client_fields_query.graphql", "relay_test_operation/fixtures/test_client_fields_query.expected", input, expected); +} + #[test] fn test_query_with_enums() { let input = include_str!("relay_test_operation/fixtures/test_query_with_enums.graphql");