Skip to content

Commit

Permalink
Unit tests and docs
Browse files Browse the repository at this point in the history
  • Loading branch information
felipeelia committed Feb 6, 2024
1 parent 7b1b32a commit 9816747
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 6 deletions.
1 change: 1 addition & 0 deletions elasticpresslabs.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function ep_labs_autoload_notice() {

// Include files.
require_once ELASTICPRESS_LABS_INC . 'functions/core.php';
require_once ELASTICPRESS_LABS_INC . 'functions/utils.php';

// Activation/Deactivation.
register_activation_hook( __FILE__, '\ElasticPressLabs\Core\activate' );
Expand Down
61 changes: 57 additions & 4 deletions includes/classes/Feature/ExternalContent.php
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function __construct() {
public function setup() {
add_filter( 'ep_prepare_meta_data', [ $this, 'append_external_content' ] );
add_filter( 'ep_external_content_file_content', 'wp_strip_all_tags' );
add_filter( 'ep_external_content_file_content', [ $this, 'maybe_remove_js_reserved_words' ], 10, 2 );
add_filter( 'ep_external_content_file_content', [ $this, 'maybe_parse_js' ], 10, 2 );
add_filter( 'ep_prepare_meta_allowed_protected_keys', [ $this, 'allow_meta_keys' ], 10, 2 );
}

Expand Down Expand Up @@ -133,6 +133,14 @@ public function append_external_content( $post_meta ) {
public function get_meta_keys() {
$meta_keys = preg_split( "/\r\n|\n|\r/", $this->get_setting( 'meta_fields' ) );

/**
* Filter the list meta keys that contain paths or URLs to external content
*
* @since 2.3.0
* @hook ep_external_content_meta_keys
* @param {array} $meta_keys List of meta keys
* @return {array} New list of meta keys
*/
return apply_filters( 'ep_external_content_meta_keys', $meta_keys );
}

Expand All @@ -143,6 +151,19 @@ public function get_meta_keys() {
* @return string
*/
public function get_stored_meta_key( $meta_key ) {
/**
* Filter the meta key that will contain the external content.
*
* If a meta key `meta_key_1` has `https://wordpress.org/news/wp-json/wp/v2/posts/16837`
* as its value, the `ep_external_content_meta_key_1` field would have that post JSON as its value.
* With this filter it is possible to change that `ep_external_content_meta_key_1` meta key.
*
* @since 2.3.0
* @hook ep_external_content_stored_meta_key
* @param {string} $stored_meta_key Meta key that holds the actual external content
* @param {string} $meta_key Meta key that contains the external content path or URL
* @return {string} New $stored_meta_key
*/
return apply_filters( 'ep_external_content_stored_meta_key', "ep_external_content_{$meta_key}", $meta_key );
}

Expand Down Expand Up @@ -177,9 +198,30 @@ function ( $acc, $meta_key ) {
* @param string $path_or_url File path or URL
* @return string
*/
public function maybe_remove_js_reserved_words( $content, $path_or_url ) {
if ( str_ends_with( $path_or_url, '.js' ) ) {
$content = str_replace( get_js_reserved_words(), '', $content );
public function maybe_parse_js( $content, $path_or_url ) {
if ( stripos( $path_or_url, '.js' ) !== false ) {
/**
* Filter the method of parsing JavaScript files.
*
* If the external content path or URL is a JS file, it is possible to parse its content.
* Passing `only_strings` (default) only strings will be stored. Passing `remove_js_reserved_words`
* all JS reserved words will be removed, leaving strings and function names, for example.
* If anything else is sent, the content is not changed.
*
* @since 2.3.0
* @hook ep_external_content_parse_js_method
* @param {string} $method Method to parse the JS file. Could be `only_strings` or `remove_js_reserved_words`.
* @return {string} New $method
*/
$method = apply_filters( 'ep_external_content_parse_js_method', 'only_strings' );

if ( 'only_strings' === $method && preg_match_all( '/([\'"])(?:\\\1|(?!\1).)*?\1/', $content, $matches ) ) {
$content = implode( ' ', $matches[0] );
}

if ( 'remove_js_reserved_words' === $method ) {
$content = str_replace( get_js_reserved_words(), '', $content );
}
}
return $content;
}
Expand All @@ -194,6 +236,17 @@ public function maybe_remove_js_reserved_words( $content, $path_or_url ) {
* @return array
*/
protected function add_external_content_to_post_meta( $post_meta, $meta_key, $content, $path_or_url ) {
/**
* Filter the content.
*
* @since 2.3.0
* @hook ep_external_content_file_content
* @param {string} $content Content being processed
* @param {string} $path_or_url Path or URL
* @param {string} $meta_key The meta key that contains the path or URL
* @param {array} $post_meta Post meta
* @return {string} New $content
*/
$content = apply_filters( 'ep_external_content_file_content', $content, $path_or_url, $meta_key, $post_meta );

if ( empty( $content ) ) {
Expand Down
2 changes: 0 additions & 2 deletions includes/functions/utils.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ function get_js_reserved_words() {
'if',
'implements',
'import',
'in',
'instanceof',
'int',
'interface',
Expand All @@ -64,7 +63,6 @@ function get_js_reserved_words() {
'super',
'switch',
'synchronized',
'this',
'throw',
'throws',
'transient',
Expand Down
1 change: 1 addition & 0 deletions tests/bootstrap.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ function load_plugin() {

include_once __DIR__ . '/../vendor/elasticpress/elasticpress.php';
include_once __DIR__ . '/../vendor/woocommerce/woocommerce.php';
include_once __DIR__ . '/../elasticpresslabs.php';

update_option( 'ep_host', $host );
update_site_option( 'ep_host', $host );
Expand Down
252 changes: 252 additions & 0 deletions tests/phpunit/feature/TestExternalContent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,252 @@
<?php
/**
* Test External Content feature
*
* @since 2.3.0
* @package ElasticPressLabs
*/

namespace ElasticPressLabsTest;

use ElasticPressLabs;
use ElasticPressLabs\Feature\ExternalContent;

/**
* External Content test class
*/
class TestExternalContent extends \WP_UnitTestCase {
/**
* Setup each test
*/
public function set_up() {
$instance = new ExternalContent();
\ElasticPress\Features::factory()->register_feature( $instance );
add_filter( 'pre_option_ep_feature_settings', [ $this, 'set_settings' ] );
add_filter( 'pre_http_request', [ $this, 'set_http_request_value' ] );
}

/**
* Clean up after each test
*/
public function tear_down() {
remove_filter( 'pre_option_ep_feature_settings', [ $this, 'set_settings' ] );
remove_filter( 'pre_http_request', [ $this, 'set_http_request_value' ] );
}

/**
* Get External Content feature
*
* @return ExternalContent
*/
protected function get_feature() {
return \ElasticPress\Features::factory()->get_registered_feature( 'external_content' );
}

/**
* Test construct
*/
public function test_construct() {
$instance = $this->get_feature();

$this->assertEquals( 'external_content', $instance->slug );
$this->assertEquals( 'External Content', $instance->title );
}

/**
* Test requirements_status
*/
public function test_requirements_status() {
$requirements_status = $this->get_feature()->requirements_status();

$this->assertSame( 1, $requirements_status->code );
}

/**
* Test set_settings_schema
*/
public function test_set_settings_schema() {
$this->get_feature()->set_settings_schema();

$expected_schema = [
'default' => '',
'help' => '<p>Add one field per line</p>',
'key' => 'meta_fields',
'label' => 'Meta fields with external URLs',
'type' => 'textarea',
];

$this->assertSame( $this->get_feature()->get_settings_schema()[1], $expected_schema );
}

/**
* Test append_external_content
*/
public function test_append_external_content() {
$original_post_meta = [
'meta_key_1' => 'https://example.org/news/wp-json/wp/v2/posts/1',
];

$post_meta = $this->get_feature()->append_external_content( $original_post_meta );

$this->assertSame( $post_meta['ep_external_content_meta_key_1'], ' {"id":123,"content":"Lorem ipsum"}' );

$change_via_filter = function ( $content ) {
$this->assertSame( $content, '{"id":123,"content":"Lorem ipsum"}' );
return 'Something different';
};
add_filter( 'ep_external_content_file_content', $change_via_filter );

$post_meta = $this->get_feature()->append_external_content( $original_post_meta );
$this->assertSame( $post_meta['ep_external_content_meta_key_1'], ' Something different' );

remove_filter( 'ep_external_content_file_content', $change_via_filter );
}

/**
* Test get_meta_keys
*/
public function test_get_meta_keys() {
$expected = [ 'meta_key_1', 'meta_key_2' ];

$this->assertSame( $this->get_feature()->get_meta_keys(), $expected );

$change_via_filter = function ( $meta_keys ) {
$meta_keys[] = 'meta_key_3';
return $meta_keys;
};
add_filter( 'ep_external_content_meta_keys', $change_via_filter );

$this->assertSame( $this->get_feature()->get_meta_keys(), array_merge( $expected, [ 'meta_key_3' ] ) );

remove_filter( 'ep_external_content_meta_keys', $change_via_filter );
}

/**
* Test get_stored_meta_key
*/
public function test_get_stored_meta_key() {
$this->assertSame( $this->get_feature()->get_stored_meta_key( 'meta_key' ), 'ep_external_content_meta_key' );

$change_via_filter = function ( $stored_meta_key, $meta_key ) {
$this->assertSame( $meta_key, 'meta_key' );
$stored_meta_key .= 'changed';
return $stored_meta_key;
};
add_filter( 'ep_external_content_stored_meta_key', $change_via_filter, 10, 2 );

$this->assertSame( $this->get_feature()->get_stored_meta_key( 'meta_key' ), 'ep_external_content_meta_keychanged' );

remove_filter( 'ep_external_content_stored_meta_key', $change_via_filter );
}

/**
* Test allow_meta_keys
*/
public function test_allow_meta_keys() {
$expected = [
'some_other_key',
'ep_external_content_meta_key_1',
'ep_external_content_meta_key_2',
];

$this->assertSame( $this->get_feature()->allow_meta_keys( [ 'some_other_key' ] ), $expected );
}

/**
* Test maybe_parse_js
*/
public function test_maybe_parse_js() {
$content = $this->get_javascript_contents();
$this->get_feature()->maybe_parse_js( $content, 'file.txt' );

$this->assertSame( $this->get_feature()->maybe_parse_js( $content, 'file.txt' ), $content );

$parsed_js = $this->get_feature()->maybe_parse_js( $content, 'file.js' );

$this->assertStringContainsString( 'Excludes this post from the results ', $parsed_js );
$this->assertStringContainsString( 'Exclude from search results', $parsed_js );
$this->assertStringNotContainsString( 'WordPress dependencies', $parsed_js );
$this->assertStringNotContainsString( 'PluginPostStatusInfo', $parsed_js );
}

/**
* Test maybe_parse_js with `remove_js_reserved_words`
*/
public function test_maybe_parse_js_remove_js_reserved_words() {
$content = $this->get_javascript_contents();

$change_via_filter = function ( $method ) {
$this->assertSame( $method, 'only_strings' );
return 'remove_js_reserved_words';
};
add_filter( 'ep_external_content_parse_js_method', $change_via_filter );

$parsed_js = $this->get_feature()->maybe_parse_js( $content, 'file.js' );

$this->assertStringContainsString( 'Excludes this post from the results ', $parsed_js );
$this->assertStringContainsString( 'Exclude from search results', $parsed_js );
$this->assertStringContainsString( 'WordPress dependencies', $parsed_js );
$this->assertStringContainsString( 'PluginPostStatusInfo', $parsed_js );
}

/**
* Set the feature settings
*/
public function set_settings() {
return [
'external_content' => [
'meta_fields' => "meta_key_1\nmeta_key_2",
],
];
}

/**
* Set the feature settings
*/
public function set_http_request_value() {
return [
'body' => json_encode(

Check warning on line 208 in tests/phpunit/feature/TestExternalContent.php

View workflow job for this annotation

GitHub Actions / PHP Lint

json_encode() is discouraged. Use wp_json_encode() instead.
[
'id' => 123,
'content' => 'Lorem ipsum',
]
),
];
}

/**
* Utilitary function to get a JS file contents
*/
protected function get_javascript_contents() {
return '
/**
* WordPress dependencies.
*/
export default () => {
const { editPost } = useDispatch(\'core/editor\');
const { ep_exclude_from_search = false, ...meta } = useSelect(
(select) => select(\'core/editor\').getEditedPostAttribute(\'meta\') || {},
);
const onChange = (ep_exclude_from_search) => {
editPost({ meta: { ...meta, ep_exclude_from_search } });
};
return (
<PluginPostStatusInfo>
<CheckboxControl
label={__(\'Exclude from search results\', \'elasticpress\')}
help={__(
"Excludes this post from the results of your site\'s search form while ElasticPress is active.",
\'elasticpress\',
)}
checked={ep_exclude_from_search}
onChange={onChange}
/>
</PluginPostStatusInfo>
);
};';
}
}

0 comments on commit 9816747

Please sign in to comment.