Skip to content

Add integration tests for the analytics adapter #22102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 17 commits into
base: trunk
Choose a base branch
from
Open
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@
use Google\Site_Kit\Modules\Analytics_4;
use Google\Site_Kit\Plugin;
use Google\Site_Kit_Dependencies\Google\Service\AnalyticsData\RunReportResponse;
use WP_REST_Response;
use Yoast\WP\SEO\Dashboard\Domain\Analytics_4\Failed_Request_Exception;
use Yoast\WP\SEO\Dashboard\Domain\Analytics_4\Invalid_Request_Exception;
use Yoast\WP\SEO\Dashboard\Domain\Analytics_4\Unexpected_Response_Exception;
@@ -28,17 +29,40 @@ class Site_Kit_Analytics_4_Adapter {
*/
private static $analytics_4_module;

/**
* Holds the api call class.
*
* @var Site_Kit_Analytics_4_Api_Call $site_kit_analytics_4_api_call
*/
private $site_kit_search_console_api_call;

/**
* The register method that sets the instance in the adapter.
*
* @param Site_Kit_Analytics_4_Api_Call $site_kit_analytics_4_api_call The api call class.
*
* @return void
*/
public function __construct() {
public function __construct( Site_Kit_Analytics_4_Api_Call $site_kit_analytics_4_api_call ) {
if ( \class_exists( 'Google\Site_Kit\Plugin' ) ) {
$site_kit_plugin = Plugin::instance();
$modules = new Modules( $site_kit_plugin->context() );
self::$analytics_4_module = $modules->get_module( Analytics_4::MODULE_SLUG );
}
$this->site_kit_search_console_api_call = $site_kit_analytics_4_api_call;
}

/**
* Sets the analytics module. Used for tests.
*
* @codeCoverageIgnore
*
* @param Module $module The analytics module.
*
* @return void
*/
public static function set_analytics_4_module( $module ): void {
self::$analytics_4_module = $module;
}

/**
@@ -55,11 +79,11 @@ public function __construct() {
public function get_comparison_data( Analytics_4_Parameters $parameters ): Data_Container {
$api_parameters = $this->build_parameters( $parameters );

$response = self::$analytics_4_module->get_data( 'report', $api_parameters );
$response = $this->site_kit_search_console_api_call->do_request( $api_parameters );

$this->validate_response( $response );

return $this->parse_comparison_response( $response );
return $this->parse_comparison_response( $response->get_data() );
}

/**
@@ -76,11 +100,11 @@ public function get_comparison_data( Analytics_4_Parameters $parameters ): Data_
public function get_daily_data( Analytics_4_Parameters $parameters ): Data_Container {
$api_parameters = $this->build_parameters( $parameters );

$response = self::$analytics_4_module->get_data( 'report', $api_parameters );
$response = $this->site_kit_search_console_api_call->do_request( $api_parameters );

$this->validate_response( $response );

return $this->parse_daily_response( $response );
return $this->parse_daily_response( $response->get_data() );
}

/**
@@ -254,21 +278,21 @@ private function is_daily_request( RunReportResponse $response ): bool {
/**
* Validates the response coming from Google Analytics.
*
* @param mixed $response The response we want to validate.
* @param WP_REST_Response $response The response we want to validate.
*
* @return void
*
* @throws Failed_Request_Exception When the request responds with an error from Site Kit.
* @throws Unexpected_Response_Exception When the request responds with an unexpected format.
*/
private function validate_response( $response ): void {
if ( \is_wp_error( $response ) ) {
$error_data = $response->get_error_data();
private function validate_response( WP_REST_Response $response ): void {
if ( $response->is_error() ) {
$error_data = $response->as_error()->get_error_data();
$error_status_code = ( $error_data['status'] ?? 500 );
throw new Failed_Request_Exception( \wp_kses_post( $response->get_error_message() ), (int) $error_status_code );
throw new Failed_Request_Exception( \wp_kses_post( $response->as_error()->get_error_message() ), (int) $error_status_code );
}

if ( ! \is_a( $response, RunReportResponse::class ) ) {
if ( ! \is_a( $response->get_data(), RunReportResponse::class ) ) {
throw new Unexpected_Response_Exception();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong
// phpcs:disable Yoast.NamingConventions.NamespaceName.MaxExceeded
namespace Yoast\WP\SEO\Dashboard\Infrastructure\Analytics_4;

use WP_REST_Request;
use WP_REST_Response;

/**
* Class that hold the code to do the REST call to the Site Kit api.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Site_Kit_Analytics_4_Api_Call {

/**
* The Analytics 4 API route path.
*/
private const ANALYTICS_DATA_REPORT_ROUTE = '/google-site-kit/v1/modules/analytics-4/data/report';

/**
* Runs the internal REST api call.
*
* @param array<string, array<string, string>> $api_parameters The api parameters.
*
* @return WP_REST_Response
*/
public function do_request( array $api_parameters ): WP_REST_Response {
$request = new WP_REST_Request( 'GET', self::SEARCH_CONSOLE_DATA_SEARCH_ANALYTICS_ROUTE );
$request->set_query_params( $api_parameters );
return \rest_do_request( $request );
}
}
Original file line number Diff line number Diff line change
@@ -3,11 +3,8 @@
// phpcs:disable Yoast.NamingConventions.NamespaceName.MaxExceeded
namespace Yoast\WP\SEO\Dashboard\Infrastructure\Search_Console;

use Google\Site_Kit\Core\Modules\Module;
use Google\Site_Kit\Core\Modules\Modules;
use Google\Site_Kit\Modules\Search_Console;
use Google\Site_Kit\Plugin;
use Google\Site_Kit_Dependencies\Google\Service\SearchConsole\ApiDataRow;
use WP_REST_Response;
use Yoast\WP\SEO\Dashboard\Domain\Data_Provider\Data_Container;
use Yoast\WP\SEO\Dashboard\Domain\Search_Console\Failed_Request_Exception;
use Yoast\WP\SEO\Dashboard\Domain\Search_Console\Unexpected_Response_Exception;
@@ -20,90 +17,60 @@
class Site_Kit_Search_Console_Adapter {

/**
* The search console module class from Site kit.
* Holds the api call class.
*
* @var Module
* @var Site_Kit_Search_Console_Api_Call $site_kit_search_console_api_call
*/
private static $search_console_module;
private $site_kit_search_console_api_call;

/**
* The register method that sets the instance in the adapter.
* The constructor.
*
* @return void
* @param Site_Kit_Search_Console_Api_Call $site_kit_search_console_api_call The api call class.
*/
public function __construct() {
if ( \class_exists( 'Google\Site_Kit\Plugin' ) ) {
$site_kit_plugin = Plugin::instance();
$modules = new Modules( $site_kit_plugin->context() );
self::$search_console_module = $modules->get_module( Search_Console::MODULE_SLUG );
}
}

/**
* Sets the search console module. Used for tests.
*
* @codeCoverageIgnore
*
* @param Module $module The search console module.
*
* @return void
*/
public static function set_search_console_module( $module ): void {
self::$search_console_module = $module;
}

/**
* Gets the search console module. Used for tests.
*
* @codeCoverageIgnore
*
* @return Module The search console module.
*/
public static function get_search_console_module() {
return self::$search_console_module;
public function __construct( Site_Kit_Search_Console_Api_Call $site_kit_search_console_api_call ) {
$this->site_kit_search_console_api_call = $site_kit_search_console_api_call;
}

/**
* The wrapper method to do a Site Kit API request for Search Console.
*
* @param Search_Console_Parameters $parameters The parameters.
*
* @return Data_Container The Site Kit API response.
*
* @throws Failed_Request_Exception When the request responds with an error from Site Kit.
* @throws Unexpected_Response_Exception When the request responds with an unexpected format.
* @return Data_Container The Site Kit API response.
*/
public function get_data( Search_Console_Parameters $parameters ): Data_Container {
$api_parameters = $this->build_parameters( $parameters );

$response = self::$search_console_module->get_data( 'searchanalytics', $api_parameters );
$response = $this->site_kit_search_console_api_call->do_request( $api_parameters );

$this->validate_response( $response );

return $this->parse_response( $response );
return $this->parse_response( $response->get_data() );
}

/**
* The wrapper method to do a comparison Site Kit API request for Search Console.
*
* @param Search_Console_Parameters $parameters The parameters.
*
* @return Data_Container The Site Kit API response.
*
* @throws Failed_Request_Exception When the request responds with an error from Site Kit.
* @throws Unexpected_Response_Exception When the request responds with an unexpected format.
* @return Data_Container The Site Kit API response.
*/
public function get_comparison_data( Search_Console_Parameters $parameters ): Data_Container {
$api_parameters = $this->build_parameters( $parameters );

// Since we're doing a comparison request, we need to increase the date range to the start of the previous period. We'll later split the data into two periods.
$api_parameters['startDate'] = $parameters->get_compare_start_date();

$response = self::$search_console_module->get_data( 'searchanalytics', $api_parameters );
$response = $this->site_kit_search_console_api_call->do_request( $api_parameters );

$this->validate_response( $response );

return $this->parse_comparison_response( $response, $parameters->get_compare_end_date() );
return $this->parse_comparison_response( $response->get_data(), $parameters->get_compare_end_date() );
}

/**
@@ -115,8 +82,6 @@ public function get_comparison_data( Search_Console_Parameters $parameters ): Da
*/
private function build_parameters( Search_Console_Parameters $parameters ): array {
$api_parameters = [
'slug' => 'search-console',
'datapoint' => 'searchanalytics',
'startDate' => $parameters->get_start_date(),
'endDate' => $parameters->get_end_date(),
'dimensions' => $parameters->get_dimensions(),
@@ -135,9 +100,8 @@ private function build_parameters( Search_Console_Parameters $parameters ): arra
* @param ApiDataRow[] $response The response to parse.
* @param string $compare_end_date The compare end date.
*
* @return Data_Container The parsed comparison Site Kit API response.
*
* @throws Unexpected_Response_Exception When the comparison request responds with an unexpected format.
* @return Data_Container The parsed comparison Site Kit API response.
*/
private function parse_comparison_response( array $response, ?string $compare_end_date ): Data_Container {
$data_container = new Data_Container();
@@ -170,9 +134,8 @@ private function parse_comparison_response( array $response, ?string $compare_en
*
* @param ApiDataRow[] $response The response to parse.
*
* @return Data_Container The parsed Site Kit API response.
*
* @throws Unexpected_Response_Exception When the request responds with an unexpected format.
* @return Data_Container The parsed Site Kit API response.
*/
private function parse_response( array $response ): Data_Container {
$search_ranking_data_container = new Data_Container();
@@ -186,9 +149,9 @@ private function parse_response( array $response ): Data_Container {
/**
* Filter: 'wpseo_transform_dashboard_subject_for_testing' - Allows overriding subjects like URLs for the dashboard, to facilitate testing in local environments.
*
* @internal
*
* @param string $url The subject to be transformed.
*
* @internal
*/
$subject = \apply_filters( 'wpseo_transform_dashboard_subject_for_testing', $ranking->getKeys()[0] );

@@ -203,21 +166,26 @@ private function parse_response( array $response ): Data_Container {
/**
* Validates the response coming from Search Console.
*
* @param mixed $response The response we want to validate.
*
* @return void
* @param WP_REST_Response $response The response we want to validate.
*
* @throws Failed_Request_Exception When the request responds with an error from Site Kit.
* @throws Unexpected_Response_Exception When the request responds with an unexpected format.
* @return void.
*/
private function validate_response( $response ): void {
if ( \is_wp_error( $response ) ) {
$error_data = $response->get_error_data();
private function validate_response( WP_REST_Response $response ): void {
if ( $response->is_error() ) {
$error_data = $response->as_error()->get_error_data();
$error_status_code = ( $error_data['status'] ?? 500 );
throw new Failed_Request_Exception( \wp_kses_post( $response->get_error_message() ), (int) $error_status_code );
throw new Failed_Request_Exception(
\wp_kses_post(
$response->as_error()
->get_error_message()
),
(int) $error_status_code
);
}

if ( ! \is_array( $response ) ) {
if ( ! \is_array( $response->get_data() ) ) {
throw new Unexpected_Response_Exception();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php
// phpcs:disable Yoast.NamingConventions.NamespaceName.TooLong
// phpcs:disable Yoast.NamingConventions.NamespaceName.MaxExceeded
namespace Yoast\WP\SEO\Dashboard\Infrastructure\Search_Console;

use WP_REST_Request;
use WP_REST_Response;

/**
* Class that hold the code to do the REST call to the Site Kit api.
*
* @phpcs:disable Yoast.NamingConventions.ObjectNameDepth.MaxExceeded
*/
class Site_Kit_Search_Console_Api_Call {

/**
* The search analytics API route path.
*/
private const SEARCH_CONSOLE_DATA_SEARCH_ANALYTICS_ROUTE = '/google-site-kit/v1/modules/search-console/data/searchanalytics';

/**
* Runs the internal REST api call.
*
* @param array<string, array<string, string>> $api_parameters The api parameters.
*
* @return WP_REST_Response
*/
public function do_request( array $api_parameters ): WP_REST_Response {
$request = new WP_REST_Request( 'GET', self::SEARCH_CONSOLE_DATA_SEARCH_ANALYTICS_ROUTE );
$request->set_query_params( $api_parameters );
return \rest_do_request( $request );
}
}
Original file line number Diff line number Diff line change
@@ -166,6 +166,7 @@ public function register_routes() {
public function get_time_based_seo_metrics( WP_REST_Request $request ): WP_REST_Response {
try {
$widget_name = $request->get_param( 'options' )['widget'];

switch ( $widget_name ) {
case 'query':
$request_parameters = new Search_Console_Parameters();
Loading