Skip to content

Commit 810a5ac

Browse files
committed
Improve settings field sanitization and add tests
Refactored Select_Field sanitization to handle non-string values and filter out invalid options. Removed redundant is_admin() check in Settings_Page::init. Added comprehensive unit tests for Settings_Page to verify initialization, hook registration, tab selection, and asset loading behaviors.
1 parent fe33b7c commit 810a5ac

File tree

7 files changed

+488
-6
lines changed

7 files changed

+488
-6
lines changed

plugins/wpgraphql-logging/src/Admin/Settings/Fields/Field/Select_Field.php

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,8 @@ public function sanitize_field( $value ): mixed {
100100
*
101101
* @return string The sanitized value.
102102
*/
103-
protected function sanitize_single_value( string $value ): string {
104-
$sanitized_value = sanitize_text_field( $value );
103+
protected function sanitize_single_value( $value ): string {
104+
$sanitized_value = sanitize_text_field( (string) $value );
105105
return array_key_exists( $sanitized_value, $this->options ) ? $sanitized_value : '';
106106
}
107107

@@ -115,7 +115,10 @@ protected function sanitize_single_value( string $value ): string {
115115
protected function sanitize_multiple_value( array $values ): array {
116116
$sanitized = [];
117117
foreach ( $values as $value ) {
118-
$sanitized[] = $this->sanitize_single_value( $value );
118+
$single = $this->sanitize_single_value( $value );
119+
if ( '' !== $single ) {
120+
$sanitized[] = $single;
121+
}
119122
}
120123
return $sanitized;
121124
}

plugins/wpgraphql-logging/src/Admin/Settings_Page.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class Settings_Page {
4242
* Initializes the settings page.
4343
*/
4444
public static function init(): ?Settings_Page {
45-
if ( ! current_user_can( 'manage_options' ) || ! is_admin() ) {
45+
if ( ! current_user_can( 'manage_options' ) ) {
4646
return null;
4747
}
4848

plugins/wpgraphql-logging/src/Events/QueryEventLifecycle.php

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -133,8 +133,6 @@ public function log_graphql_before_execute(Request $request ): void {
133133
}
134134
}
135135

136-
137-
138136
/**
139137
* Before the GraphQL response is returned to the client.
140138
*
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WPGraphQL\Logging\wpunit\Admin\Settings\Fields\Field;
6+
7+
use WPGraphQL\Logging\Admin\Settings\Fields\Field\Checkbox_Field;
8+
use WPGraphQL\Logging\Admin\Settings\Fields\Settings_Field_Interface;
9+
use lucatume\WPBrowser\TestCase\WPTestCase;
10+
11+
class CheckboxFieldTest extends WPTestCase {
12+
13+
protected ?Checkbox_Field $field = null;
14+
15+
protected function setUp(): void {
16+
parent::setUp();
17+
$this->field = new Checkbox_Field(
18+
'enable_logging',
19+
'basic_configuration',
20+
'Enable Logging',
21+
'custom-css-class',
22+
'Enable or disable query logging for WPGraphQL requests.'
23+
);
24+
}
25+
26+
public function test_basic_field_properties(): void {
27+
$field = $this->field;
28+
$this->assertEquals( 'enable_logging', $field->get_id() );
29+
$this->assertTrue( $field->should_render_for_tab( 'basic_configuration' ) );
30+
$this->assertFalse( $field->should_render_for_tab( 'other_tab' ) );
31+
}
32+
33+
public function test_sanitize_field(): void {
34+
$field = $this->field;
35+
$this->assertTrue( $field->sanitize_field( true ) );
36+
$this->assertTrue( $field->sanitize_field( 1 ) );
37+
$this->assertFalse( $field->sanitize_field( false ) );
38+
$this->assertFalse( $field->sanitize_field( 0 ) );
39+
$this->assertFalse( $field->sanitize_field( null ) );
40+
}
41+
42+
public function test_render_field(): void {
43+
$field = $this->field;
44+
$option_value = [];
45+
$setting_key = 'wpgraphql_logging_settings';
46+
$tab_key = 'basic_configuration';
47+
$args = [
48+
'tab_key' => $tab_key,
49+
'settings_key' => $setting_key,
50+
];
51+
52+
ob_start();
53+
$field->render_field_callback( $args );
54+
$rendered_output = ob_get_contents();
55+
ob_end_clean();
56+
57+
$expected_output = <<<HTML
58+
<span class="wpgraphql-logging-tooltip">
59+
<span class="dashicons dashicons-editor-help"></span>
60+
<span id="wpgraphql_logging_settings[basic_configuration][enable_logging]-tooltip" class="tooltip-text description">Enable or disable query logging for WPGraphQL requests.</span>
61+
</span><input type="checkbox" name="wpgraphql_logging_settings[basic_configuration][enable_logging]" aria-labelledby="wpgraphql_logging_settings[basic_configuration][enable_logging]-tooltip" value="1" class="custom-css-class" />
62+
HTML;
63+
$this->assertEquals(
64+
preg_replace('/[\s\t\r\n]+/', '', $expected_output),
65+
preg_replace('/[\s\t\r\n]+/', '', $rendered_output)
66+
);
67+
68+
}
69+
}
Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WPGraphQL\Logging\wpunit\Admin\Settings\Fields\Field;
6+
7+
use WPGraphQL\Logging\Admin\Settings\Fields\Field\Select_Field;
8+
use WPGraphQL\Logging\Admin\Settings\Fields\Settings_Field_Interface;
9+
use lucatume\WPBrowser\TestCase\WPTestCase;
10+
11+
class SelectFieldTest extends WPTestCase {
12+
13+
protected ?Select_Field $field = null;
14+
protected ?Select_Field $multipleField = null;
15+
16+
protected function setUp(): void {
17+
parent::setUp();
18+
$this->field = new Select_Field(
19+
'log_level',
20+
'basic_configuration',
21+
'Log Level',
22+
[
23+
'debug' => 'Debug',
24+
'info' => 'Info',
25+
'warning' => 'Warning',
26+
'error' => 'Error',
27+
],
28+
'custom-css-class',
29+
'Select the minimum log level for WPGraphQL queries.',
30+
false
31+
);
32+
33+
$this->multipleField = new Select_Field(
34+
'query_types',
35+
'basic_configuration',
36+
'Query Types',
37+
[
38+
'query' => 'Query',
39+
'mutation' => 'Mutation',
40+
'subscription' => 'Subscription',
41+
],
42+
'multiple-select-class',
43+
'Select which query types to log.',
44+
true
45+
);
46+
}
47+
48+
public function test_basic_field_properties(): void {
49+
$field = $this->field;
50+
$this->assertEquals( 'log_level', $field->get_id() );
51+
$this->assertTrue( $field->should_render_for_tab( 'basic_configuration' ) );
52+
$this->assertFalse( $field->should_render_for_tab( 'other_tab' ) );
53+
}
54+
55+
public function test_multiple_field_properties(): void {
56+
$field = $this->multipleField;
57+
$this->assertEquals( 'query_types', $field->get_id() );
58+
}
59+
60+
public function test_sanitize_field_single_select(): void {
61+
$field = $this->field;
62+
63+
$this->assertEquals( 'debug', $field->sanitize_field( 'debug' ) );
64+
$this->assertEquals( 'info', $field->sanitize_field( 'info' ) );
65+
$this->assertEquals( 'warning', $field->sanitize_field( 'warning' ) );
66+
$this->assertEquals( 'error', $field->sanitize_field( 'error' ) );
67+
$this->assertEquals( '', $field->sanitize_field( 'invalid' ) );
68+
$this->assertEquals( '', $field->sanitize_field( 'critical' ) );
69+
$this->assertEquals( '', $field->sanitize_field( '' ) );
70+
$this->assertEquals( '', $field->sanitize_field( '<script>alert("xss")</script>' ) );
71+
$this->assertEquals( 'debug', $field->sanitize_field( '<b>debug</b>' ) );
72+
$this->assertEquals( '', $field->sanitize_field( 123 ) );
73+
$this->assertEquals( '', $field->sanitize_field( true ) );
74+
$this->assertEquals( '', $field->sanitize_field( false ) );
75+
}
76+
77+
public function test_sanitize_field_multiple_select(): void {
78+
$field = $this->multipleField;
79+
80+
$this->assertEquals( ['query'], $field->sanitize_field( ['query'] ) );
81+
$this->assertEquals( ['query', 'mutation'], $field->sanitize_field( ['query', 'mutation'] ) );
82+
$this->assertEquals( ['query', 'mutation', 'subscription'], $field->sanitize_field( ['query', 'mutation', 'subscription'] ) );
83+
$this->assertEquals( [], $field->sanitize_field( ['invalid', 'another_invalid'] ) );
84+
$this->assertEquals( ['query'], $field->sanitize_field( 'query' ) );
85+
$this->assertEquals( [], $field->sanitize_field( 'invalid' ) );
86+
}
87+
88+
public function test_render_field_callback(): void {
89+
$field = $this->field;
90+
$option_value = [];
91+
$setting_key = 'wpgraphql_logging_settings';
92+
$tab_key = 'basic_configuration';
93+
$args = [
94+
'tab_key' => $tab_key,
95+
'settings_key' => $setting_key,
96+
];
97+
98+
// Capture the echoed output using output buffering
99+
ob_start();
100+
$field->render_field_callback( $args );
101+
$rendered_output = ob_get_contents();
102+
ob_end_clean();
103+
104+
$this->assertStringContainsString( 'name="wpgraphql_logging_settings[basic_configuration][log_level]"', $rendered_output );
105+
$this->assertStringContainsString( 'id="log_level"', $rendered_output );
106+
$this->assertStringContainsString( 'class="custom-css-class"', $rendered_output );
107+
$this->assertStringContainsString( 'Select the minimum log level for WPGraphQL queries.', $rendered_output );
108+
}
109+
}

0 commit comments

Comments
 (0)