diff --git a/CHANGELOG.md b/CHANGELOG.md index 81456f6c..70000fc7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ - feat!: Implement `FormField` model and `DataLoader`, and refactor `FormFieldsConnectionResolver` to extend `AbstractConnectionResolver`. - feat!: Refactor `FormsConnectionResolver` and `EntriesConnectionResolver` for compatibility with WPGraphQL v1.26.0 improvements. - feat!: Narrow `FormField.choices` and `FormField.inputs` field types to their implementations. +- fix!: Keep `PageField` with previous page data when filtering `formFields` by `pageNumber`. H/t @SamuelHadsall . - fix: Handle RadioField submission values when using a custom "other" choice. H/t @Gytjarek . - dev: Use `FormFieldsDataLoader` to resolve fields instead of instantiating a new `Model`. - chore: Add iterable type hints. diff --git a/src/Data/Connection/FormFieldsConnectionResolver.php b/src/Data/Connection/FormFieldsConnectionResolver.php index 0e1f788b..78436c1c 100644 --- a/src/Data/Connection/FormFieldsConnectionResolver.php +++ b/src/Data/Connection/FormFieldsConnectionResolver.php @@ -215,12 +215,17 @@ static function ( \GF_Field $field ) use ( $query_args, &$has_page_number ) { // Set the flag to true if the page number is found. $has_page_number = true; + // PageFields use the next page number. + if ( $field instanceof \GF_Field_Page ) { + return $field->pageNumber === $query_args['pageNumber'] + 1; + } + return $query_args['pageNumber'] === (int) $field->pageNumber; } ); - // Dont use filtered fileds if the form isnt paged. - if ( $has_page_number || 1 < $query_args['pageNumber'] ) { + // Dont use filtered filds if the form isnt paged. + if ( $has_page_number ) { $fields = $filtered_fields; } } diff --git a/tests/wpunit/FormFieldConnectionPageFilterTest.php b/tests/wpunit/FormFieldConnectionPageFilterTest.php new file mode 100644 index 00000000..deb20f0c --- /dev/null +++ b/tests/wpunit/FormFieldConnectionPageFilterTest.php @@ -0,0 +1,215 @@ +admin->ID ); + + $this->fields = $this->generate_form_pages( 3 ); + $this->form_id = $this->factory->form->create( + array_merge( + [ 'fields' => $this->fields ], + $this->tester->getFormDefaultArgs() + ) + ); + + $this->clearSchema(); + } + + /** + * Run after each test. + */ + public function tearDown(): void { + // Your tear down methods here. + $this->factory->form->delete( $this->form_id ); + + // Then... + parent::tearDown(); + } + + private function generate_form_pages( int $count = 1 ): array { + $fields = []; + $field_id = 1; + + for ( $i = 0; $i < $count; $i++ ) { + // Fields should cycle between text, number, and radio fields. + $property_helper_type = ''; + + switch ( $i % 3 ) { + case 1: + $property_helper_type = 'NumberField'; + break; + case 2: + $property_helper_type = 'RadioField'; + break; + case 0: + default: + $property_helper_type = 'TextField'; + break; + } + + // Add the form field. + $fields[] = $this->factory->field->create( + array_merge( + $this->tester->getPropertyHelper( $property_helper_type )->values, + [ + 'id' => $field_id++, + 'pageNumber' => $i + 1, + ] + ) + ); + + // Add a page field if we are not on the last page. + if ( $i < $count ) { + $fields[] = $this->factory->field->create( + array_merge( + $this->tester->getPropertyHelper( 'PageField' )->values, + [ + 'id' => $field_id++, + 'pageNumber' => $i + 2, + ] + ) + ); + } + } + + return $fields; + } + + public function getQuery(): string { + return ' + query FormFields($formId: ID!, $pageNumber: Int!) { + gfForm(id: $formId, idType: DATABASE_ID) { + formFields( + where: { + pageNumber: $pageNumber + } + ) { + pageInfo { + hasNextPage + hasPreviousPage + } + nodes { + id + databaseId + type + pageNumber + ... on PageField { + nextButton{ + text + } + previousButton{ + text + } + } + } + } + } + } + '; + } + + public function testFilterByPageNumber(): void { + $query = $this->getQuery(); + + $form = GFAPI::get_form( $this->form_id ); + $wp_query = $form['fields']; + + error_log( print_r( $wp_query, true ) ); + + /** + * Test with empty offset. + */ + $variables = [ + 'formId' => $this->form_id, + 'pageNumber' => 0, + ]; + + $expected = $wp_query; + $actual = $this->graphql( compact( 'query', 'variables' ) ); + + $this->assertResponseIsValid( $actual ); + $this->assertArrayNotHasKey( 'errors', $actual ); + $this->assertCount( 6, $actual['data']['gfForm']['formFields']['nodes'] ); + + // Set the variables to use in the GraphQL query. + $variables['pageNumber'] = 1; + + // Run the GraphQL Query. + $expected = array_slice( $wp_query, 0, 2, false ); + $actual = $this->graphql( compact( 'query', 'variables' ) ); + + $this->assertValidPageFields( $expected, $actual ); + + /** + * Test the next two results. + */ + + // Set the variables to use in the GraphQL query. + $variables['pageNumber'] = 2; + + // Run the GraphQL Query. + $expected = array_slice( $wp_query, 2, 2, false ); + $actual = $this->graphql( compact( 'query', 'variables' ) ); + + $this->assertValidPageFields( $expected, $actual ); + + + /** + * Test the last two results. + */ + + // Set the variables to use in the GraphQL query. + $variables['pageNumber'] = 3; + + // Run the GraphQL Query. + $expected = array_slice( $wp_query, 4, 2, false ); + $actual = $this->graphql( compact( 'query', 'variables' ) ); + + $this->assertValidPageFields( $expected, $actual ); + } + + /** + * Common assertions for testing pagination. + * + * @param array $expected Expected results from GFAPI. + * @param array $actual Actual results from GraphQL. + */ + private function assertValidPageFields( array $expected, array $actual ): void { + $this->assertResponseIsValid( $actual ); + $this->assertArrayNotHasKey( 'errors', $actual ); + + $this->assertArrayHasKey( 'data', $actual ); + $this->assertCount( 2, $actual['data']['gfForm']['formFields']['nodes'] ); + + + $this->assertEquals( $expected[0]['id'], $actual['data']['gfForm']['formFields']['nodes'][0]['databaseId'] ); + $this->assertEquals( $expected[0]['pageNumber'], $actual['data']['gfForm']['formFields']['nodes'][0]['pageNumber'] ); + $this->assertEquals( $expected[1]['id'], $actual['data']['gfForm']['formFields']['nodes'][1]['databaseId'] ); + $this->assertEquals( $expected[1]['pageNumber'], $actual['data']['gfForm']['formFields']['nodes'][1]['pageNumber'] ); + $this->assertEquals( GFHelpers::get_enum_for_value( FormFieldTypeEnum::$type, $expected[1]['type'] ), $actual['data']['gfForm']['formFields']['nodes'][1]['type'] ); + $this->assertEquals( $expected[1]['nextButton']['text'], $actual['data']['gfForm']['formFields']['nodes'][1]['nextButton']['text'] ); + $this->assertEquals( + $expected[1]['previousButton']['text'], $actual['data']['gfForm']['formFields']['nodes'][1]['previousButton']['text'] ); + } +} diff --git a/tests/wpunit/FormFieldConnectionQueriesTest.php b/tests/wpunit/FormFieldConnectionQueriesTest.php index 93f802c4..7b480e5a 100644 --- a/tests/wpunit/FormFieldConnectionQueriesTest.php +++ b/tests/wpunit/FormFieldConnectionQueriesTest.php @@ -79,50 +79,6 @@ private function generate_fields( int $count = 1 ): array { return $fields; } - private function create_fields_for_paged_form( int $pages = 1 ): array { - $fields = []; - $field_count = 0; - for ( $i = 0; $i < $pages; $i++ ) { - $fields[] = $this->factory->field->create( - array_merge( - $this->tester->getPropertyHelper( 'TextField' )->values, - [ - 'id' => ++$field_count, - ] - ) - ); - $fields[] = $this->factory->field->create( - array_merge( - $this->tester->getPropertyHelper( 'NumberField' )->values, - [ - 'id' => ++$field_count, - ] - ) - ); - $fields[] = $this->factory->field->create( - array_merge( - $this->tester->getPropertyHelper( 'RadioField' )->values, - [ - 'id' => ++$field_count, - ] - ) - ); - - // Add a page field if we are not on the last page. - if ( $i < $pages - 1 ) { - $fields[] = $this->factory->field->create( - array_merge( - $this->tester->getPropertyHelper( 'PageField' )->values, - [ - 'id' => ++$field_count, - ] - ) - ); - } - } - return $fields; - } - public function getQuery(): string { return ' query FormFields($formId: ID!, $first: Int, $last: Int, $after: String, $before: String, $where: GfFormToFormFieldConnectionWhereArgs) {