Skip to content

Commit eaaa8c8

Browse files
committed
Added unit tests for fields. Slight refactor. Added some local test scripts.
1 parent 920735e commit eaaa8c8

17 files changed

+793
-124
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#!/usr/bin/env bash
2+
3+
# Running Unit Tests for the HWP Previews Plugin
4+
5+
# Usage:
6+
## - sh bin/local/run-unit-tests.sh
7+
## - sh bin/local/run-unit-tests.sh coverage --coverage-html
8+
9+
# Check if Docker is running
10+
if ! docker info > /dev/null 2>&1; then
11+
echo "Docker is not running. Please start Docker Desktop and try again."
12+
open -a Docker
13+
exit 1
14+
fi
15+
16+
COVERAGE_ARG=""
17+
COVERAGE_OUTPUT_ARG=""
18+
19+
if [[ "$1" == "coverage" ]]; then
20+
COVERAGE_ARG="-e COVERAGE=1"
21+
shift
22+
if [[ -n "$1" ]]; then
23+
COVERAGE_OUTPUT_ARG="-e COVERAGE_OUTPUT=$1"
24+
fi
25+
fi
26+
27+
docker exec $COVERAGE_ARG $COVERAGE_OUTPUT_ARG -e SUITES=wpunit -w /var/www/html/wp-content/plugins/hwp-previews hwp-previews-wordpress-1 bin/run-codeception.sh

plugins/hwp-previews/bin/run-codeception.sh

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,12 @@ setup_before() {
4141
fi
4242

4343
# Install the PHP dev-dependencies.
44-
echo "Running composer install"
45-
COMPOSER_MEMORY_LIMIT=-1 composer install
44+
if [ ! -d "vendor" ]; then
45+
echo "Running composer install"
46+
COMPOSER_MEMORY_LIMIT=-1 composer install
47+
fi
4648

47-
# Set output permission
49+
# Set output permission
4850
echo "Setting Codeception output directory permissions"
4951
chmod 777 -R tests/_output
5052
}
@@ -64,7 +66,11 @@ run_tests() {
6466
fi
6567

6668
if [[ -n "$COVERAGE" ]]; then
67-
local coverage="--coverage --coverage-xml $suites-coverage.xml"
69+
if [[ -n "$COVERAGE_OUTPUT" ]]; then
70+
local coverage="--coverage --coverage-xml $COVERAGE_OUTPUT"
71+
else
72+
local coverage="--coverage --coverage-xml $suites-coverage.xml"
73+
fi
6874
fi
6975

7076
# If maintenance mode is active, de-activate it
@@ -86,7 +92,7 @@ run_tests() {
8692
echo "Error: Codeception build failed"
8793
exit 1
8894
fi
89-
95+
9096
XDEBUG_MODE=coverage vendor/bin/codecept run -c codeception.dist.yml ${suites} ${coverage:-} ${debug:-} --no-exit
9197
if [ $? -ne 0 ]; then
9298
echo "Error: Codeception tests failed with exit code $?"

plugins/hwp-previews/src/Admin/Settings/Fields/Field/Abstract_Settings_Field.php

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,20 @@ public function is_hierarchical(): bool {
7979
return $this->is_hierarchical;
8080
}
8181

82+
/**
83+
* Get the settings field title.
84+
*/
85+
public function get_title(): string {
86+
return $this->title;
87+
}
88+
89+
/**
90+
* Get the description field.
91+
*/
92+
public function get_description(): string {
93+
return esc_attr( $this->description );
94+
}
95+
8296
/**
8397
* Register the settings field.
8498
*
@@ -89,7 +103,7 @@ public function is_hierarchical(): bool {
89103
public function add_settings_field( string $section, string $page, array $args ): void {
90104
add_settings_field(
91105
$this->id,
92-
$this->title,
106+
$this->get_title(),
93107
[ $this, 'settings_field_callback' ],
94108
$page,
95109
$section,
@@ -112,13 +126,17 @@ public function settings_field_callback( array $args ): void {
112126
<span class="dashicons dashicons-editor-help"></span>
113127
<span id="%2$s-tooltip" class="tooltip-text description">%1$s</span>
114128
</div>',
115-
esc_attr( $this->description ),
129+
$this->get_description(),
116130
esc_attr( $settings_key )
117131
);
118132

119-
$this->render_field(
133+
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
134+
echo $this->render_field(
135+
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
120136
$this->get_setting_value( $settings_key, $post_type ),
137+
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
121138
$settings_key,
139+
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
122140
$post_type,
123141
);
124142
}
@@ -129,11 +147,12 @@ public function settings_field_callback( array $args ): void {
129147
* @param bool $post_type_hierarchal
130148
*/
131149
public function should_render_field( bool $post_type_hierarchal ): bool {
150+
151+
// If the post-type is hierarchical, then we always render the field as we don't need to check the field hierarchy.
132152
if ( true === $post_type_hierarchal ) {
133153
return true;
134154
}
135155

136-
// If the field is not hierarchical and the post-type is hierarchical, we don't render it.
137156
return ! $this->is_hierarchical();
138157
}
139158

@@ -145,7 +164,7 @@ public function should_render_field( bool $post_type_hierarchal ): bool {
145164
*
146165
* @return array<string, mixed>
147166
*/
148-
private function get_setting_value( string $settings_key, string $post_type ): array {
167+
public function get_setting_value( string $settings_key, string $post_type ): array {
149168
$value = get_option( $settings_key, [] );
150169

151170
if (

plugins/hwp-previews/src/Admin/Settings/Fields/Field/Checkbox_Field.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Checkbox_Field extends Abstract_Settings_Field {
1010
*
1111
* @var bool
1212
*/
13-
private bool $default;
13+
protected bool $default;
1414

1515
/**
1616
* Constructor.
@@ -35,12 +35,12 @@ public function __construct( string $id, bool $is_hierarchical, string $title, s
3535
* @param string $setting_key The settings key.
3636
* @param string $post_type The post type.
3737
*/
38-
public function render_field( $option_value, $setting_key, $post_type ): void {
38+
public function render_field( $option_value, $setting_key, $post_type ): string {
3939
$enabled = isset( $option_value[ $this->id ] )
4040
? (bool) $option_value[ $this->id ]
4141
: $this->default;
4242

43-
printf(
43+
return sprintf(
4444
'<input type="checkbox" name="%1$s[%2$s][%3$s]" value="1" %4$s class="%5$s" />',
4545
esc_attr( $setting_key ),
4646
esc_attr( $post_type ),

plugins/hwp-previews/src/Admin/Settings/Fields/Field/Text_Input_Field.php

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Text_Input_Field extends Abstract_Settings_Field {
1010
*
1111
* @var string
1212
*/
13-
private string $default;
13+
protected string $default;
1414

1515
/**
1616
* Constructor.
@@ -35,14 +35,31 @@ public function __construct( string $id, bool $is_hierarchical, string $title, s
3535
* @param string $setting_key The settings key.
3636
* @param string $post_type The post type.
3737
*/
38-
public function render_field( array $option_value, string $setting_key, string $post_type ): void {
39-
printf(
40-
'<input type="text" name="%1$s[%2$s][%3$s]" value="%4$s" placeholder="%5$s" class="%6$s" />',
38+
public function render_field( array $option_value, string $setting_key, string $post_type ): string {
39+
40+
$default_value = $this->default;
41+
if ( ! empty( $default_value ) && str_contains( $default_value, '%s' ) ) {
42+
$default_value = sprintf( $default_value, $post_type );
43+
}
44+
45+
// Get option value for the current post type.
46+
$option_escaped_value = null;
47+
if ( array_key_exists( $this->get_id(), $option_value ) ) {
48+
$option_escaped_value = $option_value[ $this->get_id() ];
49+
if ( str_contains( $option_escaped_value, '%s' ) ) {
50+
$option_escaped_value = sprintf( $option_escaped_value, $post_type );
51+
}
52+
}
53+
54+
55+
return sprintf(
56+
'<input type="%1$s" name="%2$s[%3$s][%4$s]" value="%5$s" placeholder="%6$s" class="%7$s" />',
57+
$this->get_input_type(),
4158
esc_attr( $setting_key ),
4259
esc_attr( $post_type ),
43-
esc_attr( $this->id ),
44-
esc_attr( (string) ( $option_value[ $this->id ] ?? $this->default ) ),
45-
esc_attr( $this->default ),
60+
esc_attr( $this->get_id() ),
61+
$this->escape_render_input_value( ( $option_escaped_value ?? $default_value ) ),
62+
$this->escape_render_input_value( $default_value ),
4663
esc_attr( $this->class )
4764
);
4865
}
@@ -53,4 +70,22 @@ public function render_field( array $option_value, string $setting_key, string $
5370
public function sanitize_field( $value ): string {
5471
return sanitize_text_field( (string) $value );
5572
}
73+
74+
/**
75+
* Get the input type for the field.
76+
*
77+
* @return string The input type.
78+
*/
79+
public function get_input_type(): string {
80+
return 'text';
81+
}
82+
83+
/**
84+
* Escape the value for rendering in the input field.
85+
*
86+
* @param string $value
87+
*/
88+
protected function escape_render_input_value(string $value): string {
89+
return esc_attr( $value );
90+
}
5691
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace HWP\Previews\Admin\Settings\Fields\Field;
6+
7+
class URL_Input_Field extends Text_Input_Field {
8+
/**
9+
* @param mixed $value
10+
*/
11+
public function sanitize_field( $value ): string {
12+
$value = sanitize_text_field( (string) $value );
13+
if ( ! $value ) {
14+
return '';
15+
}
16+
17+
// Validate the URL format
18+
if ( false !== wp_http_validate_url( $value ) ) {
19+
return $value;
20+
}
21+
22+
// Clean and fix the URL and allow curly braces for parameter replacement
23+
$value = $this->fix_url( $value );
24+
25+
// Sanitize while preserving placeholders
26+
$value = str_replace( ['{', '}'], ['___OPEN___', '___CLOSE___'], $value );
27+
$value = esc_url_raw( $value );
28+
return str_replace( ['___OPEN___', '___CLOSE___'], ['{', '}'], $value );
29+
}
30+
31+
private function fix_url( string $value ): string {
32+
// Remove HTML tags, trim, encode spaces, add protocol
33+
$value = preg_replace( '/<(?!\{)[^>]+>/', '', $value );
34+
$value = trim( str_replace( ' ', '%20', $value ) );
35+
36+
if ( $value && ! preg_match( '/^https?:\/\//i', $value ) ) {
37+
$protocol = is_ssl() ? 'https://' : 'http://';
38+
$value = $protocol . ltrim( $value, '/' );
39+
}
40+
41+
return $value;
42+
}
43+
44+
45+
/**
46+
* URL input field constructor.
47+
*
48+
* Note: We did not change escape_render_input_value method to esc_url as this would remove any brackets from the URL.
49+
*/
50+
public function get_input_type(): string {
51+
return 'url';
52+
}
53+
}

plugins/hwp-previews/src/Admin/Settings/Fields/Settings_Field_Collection.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
namespace HWP\Previews\Admin\Settings\Fields;
66

77
use HWP\Previews\Admin\Settings\Fields\Field\Checkbox_Field;
8-
use HWP\Previews\Admin\Settings\Fields\Field\Text_Input_Field;
8+
use HWP\Previews\Admin\Settings\Fields\Field\URL_Input_Field;
99

1010
class Settings_Field_Collection {
1111
/**
@@ -92,7 +92,7 @@ protected function initialize_fields(): void {
9292
);
9393

9494
$this->add_field(
95-
new Text_Input_Field(
95+
new URL_Input_Field(
9696
'preview_url',
9797
false,
9898
__( 'Preview URL', 'hwp-previews' ),

plugins/hwp-previews/src/Admin/Settings/Fields/Settings_Field_Interface.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ interface Settings_Field_Interface {
1212
* @param string $setting_key The setting key.
1313
* @param string $post_type The post-type.
1414
*/
15-
public function render_field( array $option_value, string $setting_key, string $post_type ): void;
15+
public function render_field( array $option_value, string $setting_key, string $post_type ): string;
1616

1717
/**
1818
* Get the field ID

0 commit comments

Comments
 (0)