This commit is contained in:
2026-07-02 15:54:39 -06:00
commit 9883323161
17470 changed files with 4470592 additions and 0 deletions
@@ -0,0 +1,48 @@
<?php
namespace Vrts\Services;
use Vrts\Tables\Alerts_Table;
class Alert_Service {
/**
* Create alert from comparison.
*
* @param int $post_id Post ID.
* @param int $test_id Test ID.
* @param array $comparison Comparison.
* @param object $test_run Test run.
*/
public function create_alert_from_comparison( $post_id, $test_id, $comparison, $test_run = null ) {
global $wpdb;
$table_alert = Alerts_Table::get_table_name();
$prepare_alert = [];
$prepare_alert['post_id'] = $post_id;
$prepare_alert['screenshot_test_id'] = $test_id;
$prepare_alert['target_screenshot_url'] = $comparison['screenshot']['image_url'];
$prepare_alert['target_screenshot_finish_date'] = $comparison['screenshot']['updated_at'];
$prepare_alert['base_screenshot_url'] = $comparison['base_screenshot']['image_url'];
$prepare_alert['base_screenshot_finish_date'] = $comparison['base_screenshot']['updated_at'];
$prepare_alert['comparison_screenshot_url'] = $comparison['image_url'];
$prepare_alert['comparison_id'] = $comparison['id'];
$prepare_alert['differences'] = $comparison['pixels_diff'];
$prepare_alert['test_run_id'] = $test_run ? $test_run->id : null;
$prepare_alert['meta'] = maybe_serialize( $comparison['meta'] ?? [] );
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- It's ok.
if ( $wpdb->insert( $table_alert, $prepare_alert ) ) {
$alert_id = $wpdb->insert_id;
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- It's ok.
$wpdb->update(
$table_alert,
[ 'title' => '#' . $alert_id ],
[ 'id' => $alert_id ]
);
}
return $alert_id;
}
}
@@ -0,0 +1,120 @@
<?php
namespace Vrts\Services;
use Vrts\Models\Alert;
use Vrts\Models\Test;
use Vrts\Models\Test_Run;
class Email_Service {
/**
* Send Test Run email.
*
* @param int $test_run_id the id of the test run.
*
* @return bool
*/
public function send_test_run_email( $test_run_id ) {
$subject = sprintf(
/* translators: %1$s: the id of the test run, %2$s: home url */
esc_html_x( 'VRTs: Run #%1$s (%2$s)', 'test run notification email subject', 'visual-regression-tests' ),
$test_run_id,
esc_url( home_url() )
);
$data = $this->get_test_run_email_data( $test_run_id );
$message = vrts()->get_component( 'emails/test-run', $data );
$headers = [
'Content-Type: text/html; charset=UTF-8',
];
$emails = $this->get_test_run_emails( $data['run'] );
if ( $emails ) {
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
return wp_mail( $emails, wp_specialchars_decode( $subject ), $message, $headers );
}
return false;
}
/**
* Get the emails for the test run.
*
* @param object $run the test run.
*
* @return array Email addresses.
*/
private function get_test_run_emails( $run ) {
$emails = [];
$trigger = $run->trigger;
switch ( $trigger ) {
case 'manual':
$meta = maybe_unserialize( $run->trigger_meta );
$user = get_user_by( 'ID', $meta['user_id'] ?? 0 );
if ( $user ) {
$emails = [ $user->user_email ];
}
break;
case 'api':
$emails = vrts()->settings()->get_option( 'vrts_email_api_notification_address' );
break;
case 'update':
$emails = vrts()->settings()->get_option( 'vrts_email_update_notification_address' );
break;
default:
$emails = vrts()->settings()->get_option( 'vrts_email_notification_address' );
break;
}
return $emails;
}
/**
* Get the data for the test run email.
*
* @param int $run_id the id of the test run.
*/
private function get_test_run_email_data( $run_id ) {
$run = Test_Run::get_item( $run_id );
$tests = maybe_unserialize( $run->tests );
$alerts = Alert::get_items_by_test_run( $run_id );
if ( is_array( $tests ) && count( $tests ) > 0 && ! is_array( $tests[0] ) ) {
$tests = array_map( function ( $test ) {
$test = (int) $test;
$post_id = Test::get_post_id( $test );
return [
'id' => $test,
'post_id' => $post_id,
'post_title' => get_the_title( $post_id ),
'permalink' => get_permalink( $post_id ),
];
}, $tests );
}
usort( $tests, function ( $a, $b ) {
return $a['post_id'] > $b['post_id'] ? -1 : 1;
} );
$data = [
'run' => $run,
'tests' => $tests,
'alerts' => $alerts,
];
return $data;
}
/**
* Preview test run email.
*
* @param int $run_id the id of the test run.
*/
public function preview_test_run_email( $run_id ) {
$data = $this->get_test_run_email_data( $run_id );
vrts()->component( 'emails/test-run', $data );
}
}
@@ -0,0 +1,79 @@
<?php
namespace Vrts\Services;
use Vrts\Features\Cron_Jobs;
use Vrts\Features\Service;
use Vrts\Features\Subscription;
use Vrts\Models\Test;
class Manual_Test_Service {
const OPTION_NAME_STATUS = 'vrts_run_manual_test_is_active';
/**
* Check whether the option is set to true.
*
* @return bool
*/
public function get_option() {
return get_option( self::OPTION_NAME_STATUS );
}
/**
* Sets the option.
*
* @param int $status Status 1 for success, 2 for failure.
*/
public function set_option( $status = 1 ) {
update_option( self::OPTION_NAME_STATUS, $status );
}
/**
* Delete the option.
*/
public function delete_option() {
delete_option( self::OPTION_NAME_STATUS );
}
/**
* Run manual tests.
*
* @param array|null $test_ids Array of test ids.
*/
public function run_tests( $test_ids = null ) {
$has_subscription = Subscription::get_subscription_status();
if ( ! $has_subscription ) {
return false;
}
if ( empty( $test_ids ) ) {
$tests = Test::get_all_running();
} else {
$tests = Test::get_items_by_ids( $test_ids );
}
$service_test_ids = array_map( function ( $test ) {
return $test->service_test_id;
}, $tests );
self::set_option();
$request = Service::run_manual_tests( $service_test_ids, [
'trigger_meta' => [ 'user_id' => get_current_user_id() ],
] );
$test_ids = array_map( function ( $test ) {
return $test->id;
}, $tests );
if ( 201 === $request['status_code'] ) {
self::set_option( 1 );
$response = $request['response'];
$service = new Test_Run_Service();
$id = $service->create_test_run( $response['id'], [
'tests' => maybe_serialize( $test_ids ),
'trigger' => 'manual',
'started_at' => current_time( 'mysql' ),
] );
Cron_Jobs::schedule_initial_fetch_test_run_updates( $id );
} else {
self::set_option( 2 );
}
}
}
@@ -0,0 +1,169 @@
<?php
namespace Vrts\Services;
use Vrts\Features\Service;
use Vrts\Features\Subscription;
use Vrts\Models\Test;
use Vrts\Models\Test_Run;
use Vrts\Services\Email_Service;
class Test_Run_Service {
/**
* Create test from API data.
*
* @param array $data Data.
* @param bool $with_cleanup With cleanup.
*
* @return boolean
*/
public function update_run_from_api_data( $data, $with_cleanup = true ) {
$run_id = $data['run_id'];
if ( empty( $run_id ) ) {
return false;
}
$test_run = Test_Run::get_by_service_test_run_id( $run_id );
$test_run_just_finished = false;
if ( $test_run && empty( $test_run->finished_at ) && ! empty( $data['finished_at'] ) ) {
$test_run_just_finished = true;
$alert_ids = $this->update_tests_and_create_alerts( $data['comparisons'], $test_run );
}
$test_ids = empty( $data['comparison_schedule_ids'] ) ? [] : array_map(function ( $test ) {
return [
'id' => $test->id,
'post_id' => $test->post_id,
'post_title' => get_the_title( $test->post_id ),
'permalink' => get_permalink( $test->post_id ),
];
}, Test::get_by_service_test_ids( $data['comparison_schedule_ids'] ));
$test_run_id = $this->create_test_run( $data['run_id'], [
'tests' => maybe_serialize( $test_ids ),
'started_at' => $data['started_at'],
'finished_at' => $data['finished_at'],
'scheduled_at' => $data['scheduled_at'],
'trigger' => $data['trigger'],
'trigger_notes' => $data['trigger_notes'],
'trigger_meta' => maybe_serialize( $data['trigger_meta'] ),
], true, $with_cleanup );
if ( $test_run_just_finished && ! empty( $alert_ids ) ) {
$email_service = new Email_Service();
$email_service->send_test_run_email( $test_run_id );
}
return true;
}
/**
* Update tests and create alerts.
*
* @param array $comparisons Comparisons.
* @param object $test_run Test run.
*
* @return array
*/
protected function update_tests_and_create_alerts( $comparisons, $test_run ) {
$alert_ids = [];
foreach ( $comparisons as $comparison ) {
$test_id = $comparison['comparison_schedule_id'];
$alert_id = null;
if ( $comparison['pixels_diff'] > 1 && ! $comparison['matches_false_positive'] ) {
$post_id = Test::get_post_id_by_service_test_id( $test_id );
$alert_service = new Alert_Service();
$alert_id = $alert_service->create_alert_from_comparison( $post_id, $test_id, $comparison, $test_run );
$alert_ids[] = $alert_id;
}//end if
$test_service = new Test_Service();
$test_service->update_test_from_comparison( $alert_id, $test_id, [
'comparison' => $comparison,
] );
}
return $alert_ids;
}
/**
* Create test run.
*
* @param string $service_test_run_id Service test run id.
* @param array $data Data.
* @param bool $update Update.
* @param bool $with_cleanup With cleanup.
*
* @return boolean
*/
public function create_test_run( $service_test_run_id, $data, $update = false, $with_cleanup = true ) {
$test_run = Test_Run::get_by_service_test_run_id( $service_test_run_id );
if ( $test_run && ! $update ) {
return false;
}
$test_run_id = Test_Run::save(array_merge( $data, [
'service_test_run_id' => $service_test_run_id,
]), $test_run->id ?? null);
if ( $with_cleanup ) {
Test_Run::delete_duplicates();
Test_Run::delete_empty();
$this->check_stalled_test_runs();
}
return $test_run_id;
}
/**
* Check stalled test runs.
*
* @return void
*/
public function check_stalled_test_runs() {
$test_run_ids = array_column( Test_Run::get_stalled_test_run_ids(), 'service_test_run_id' );
if ( empty( $test_run_ids ) ) {
return;
}
$response = Service::fetch_test_runs( $test_run_ids );
if ( 200 === $response['status_code'] ) {
$test_runs = $response['response']['data'] ?? [];
foreach ( $test_runs as $test_run ) {
$this->update_run_from_api_data( $test_run, false );
}
$missing_test_run_ids = array_diff( $test_run_ids, array_column( $test_runs, 'run_id' ) );
foreach ( $missing_test_run_ids as $missing_test_run_id ) {
Test_Run::delete_by_service_test_run_id( $missing_test_run_id );
}
}
}
/**
* Fetch and update tests.
*
* @return void
*/
public function fetch_and_update_test_runs() {
$service_request = Service::fetch_updates();
if ( 200 === $service_request['status_code'] ) {
$response = $service_request['response'];
if ( array_key_exists( 'run_updates', $response ) ) {
$updates = $response['run_updates'];
foreach ( $updates as $update ) {
$this->update_run_from_api_data( $update, false );
}
}
if (
array_key_exists( 'remaining_credits', $response )
&& array_key_exists( 'total_credits', $response )
&& array_key_exists( 'has_subscription', $response )
&& array_key_exists( 'tier_id', $response )
) {
Subscription::update_available_tests( $response['remaining_credits'], $response['total_credits'], $response['has_subscription'], $response['tier_id'] );
}
}
}
}
@@ -0,0 +1,471 @@
<?php
namespace Vrts\Services;
use Vrts\Features\Cron_Jobs;
use Vrts\Features\Service;
use Vrts\Features\Subscription;
use Vrts\Models\Alert;
use Vrts\Models\Test;
use Vrts\Tables\Alerts_Table;
use Vrts\Tables\Tests_Table;
use WP_Error;
class Test_Service {
/**
* Update tests from comparison.
*
* @param int $alert_id Alert id.
* @param int $test_id Test id.
* @param array $data Comparison data.
*
* @return int|false
*/
public function update_test_from_comparison( $alert_id, $test_id, $data ) {
global $wpdb;
$table_test = Tests_Table::get_table_name();
$comparison = $data['comparison'];
if ( $comparison['screenshot']['image_url'] ?? null ) {
// Update test row with new id foreign key and add latest screenshot.
$update_data = [
'next_run_date' => $data['next_run_at'] ?? '',
'last_comparison_date' => $comparison['updated_at'],
'base_screenshot_url' => $comparison['screenshot']['image_url'],
'base_screenshot_date' => $comparison['screenshot']['updated_at'],
'is_running' => false,
];
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- It's ok.
return $wpdb->update(
$table_test,
$update_data,
[ 'service_test_id' => $test_id ]
);
}
}
/**
* Update test from schedule.
*
* @param int $test_id Test id.
* @param array $data Screenshot data.
*
* @return void
*/
public function update_test_from_schedule( $test_id, $data ) {
global $wpdb;
$table_test = Tests_Table::get_table_name();
$screenshot = $data['schedule']['base_screenshot'];
if ( $screenshot['image_url'] ?? null ) {
// Update test row with new id foreign key and add latest screenshot.
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- It's ok.
$wpdb->update(
$table_test,
[
'base_screenshot_url' => $screenshot['image_url'],
'base_screenshot_date' => $screenshot['updated_at'],
'next_run_date' => $data['next_run_at'] ?? '',
],
[ 'service_test_id' => $test_id ]
);
}
}
/**
* Create test from API data.
*
* @param array $data Data.
*
* @return int|false
*/
public function update_test_from_api_data( $data ) {
$test_id = $data['test_id'];
$post_id = Test::get_post_id_by_service_test_id( $test_id );
if ( $post_id ) {
if ( $data['schedule']['base_screenshot'] ?? null ) {
$this->update_test_from_schedule( $test_id, $data );
} elseif ( $data['comparison'] ?? null ) {
$alert_id = null;
if ( $data['comparison']['pixels_diff'] > 1 && ! $data['matches_false_positive'] ) {
$comparison = $data['comparison'];
$alert_service = new Alert_Service();
$alert_id = $alert_service->create_alert_from_comparison( $post_id, $test_id, $comparison );
}//end if
$test_service = new Test_Service();
$test_service->update_test_from_comparison( $alert_id, $test_id, $data );
}//end if
return true;
}//end if
}
/**
* Fetch and update tests.
*
* @return void
*/
public function fetch_and_update_tests() {
$service_request = Service::fetch_updates();
if ( 200 === $service_request['status_code'] ) {
$response = $service_request['response'];
if ( array_key_exists( 'updates', $response ) ) {
$updates = $response['updates'];
foreach ( $updates as $update ) {
$this->update_test_from_api_data( $update );
}
}
if (
array_key_exists( 'remaining_credits', $response )
&& array_key_exists( 'total_credits', $response )
&& array_key_exists( 'has_subscription', $response )
&& array_key_exists( 'tier_id', $response )
) {
Subscription::update_available_tests( $response['remaining_credits'], $response['total_credits'], $response['has_subscription'], $response['tier_id'] );
}
}
}
/**
* Create test.
*
* @param int $post_id Post id.
*
* @return int|WP_Error
*/
public function create_test( $post_id ) {
if ( Service::is_connected() ) {
$post = get_post( $post_id );
if ( ! $post ) {
return new WP_Error( 'vrts_post_error', __( 'Post not found.', 'visual-regression-tests' ) );
}
$test = Test::get_item_by_post_id( $post_id );
if ( $test ) {
return $test;
}
if ( 'publish' === $post->post_status ) {
return $this->create_remote_test( $post );
} elseif ( 'revision' !== $post->post_type && 'auto-draft' !== $post->post_status ) {
$args = [
'post_id' => $post_id,
'status' => 0,
];
$new_row_id = Test::save( $args );
return Test::get_item( $new_row_id );
}
} else {
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
}//end if
return new WP_Error( 'vrts_service_error', __( 'Error creating test.', 'visual-regression-tests' ) );
}
/**
* Create tests.
*
* @param array $post_ids Post ids.
*
* @return array|WP_Error
*/
public function create_tests( $post_ids ) {
if ( Service::is_connected() ) {
$created_tests = [];
$post_types = vrts()->get_public_post_types();
$posts = get_posts( [
'post__in' => $post_ids,
'post_type' => $post_types,
'post_status' => 'any',
'posts_per_page' => -1,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
] );
if ( ! $posts ) {
return new WP_Error( 'vrts_posts_error', __( 'Posts not found.', 'visual-regression-tests' ) );
}
$post_ids = wp_list_pluck( $posts, 'ID' );
$remaining_tests = get_option( 'vrts_remaining_tests' );
$existing_tests = Test::get_items_by_post_ids( $post_ids );
$existing_tests_posts_ids = array_map( 'intval', wp_list_pluck( $existing_tests, 'post_id' ) );
// Remove posts that already have tests.
$posts = array_filter( $posts, function ( $post ) use ( $existing_tests_posts_ids ) {
return ! in_array( $post->ID, $existing_tests_posts_ids, true );
} );
if ( ! $posts ) {
return $existing_tests;
}
// Only try to create as many remote tests as we have remaining.
$published_posts = array_slice( array_filter( $posts, function ( $post ) {
return 'publish' === $post->post_status;
} ), 0, $remaining_tests );
$not_published_posts = array_filter( $posts, function ( $post ) {
return 'publish' !== $post->post_status && 'revision' !== $post->post_type && 'auto-draft' !== $post->post_status;
} );
if ( $published_posts ) {
$published_posts_ids = wp_list_pluck( $published_posts, 'ID' );
$remote_tests = $this->create_remote_tests( $published_posts_ids );
if ( ! is_wp_error( $remote_tests ) ) {
$created_tests = $remote_tests;
}
}
if ( $not_published_posts ) {
$args = array_values( array_map(function ( $post ) {
return [
'post_id' => $post->ID,
'status' => 0,
];
}, $not_published_posts) );
$is_saved = Test::save_multiple( $args );
if ( $is_saved ) {
$not_published_posts_ids = wp_list_pluck( $not_published_posts, 'ID' );
$created_tests = array_merge( $created_tests, Test::get_items_by_post_ids( $not_published_posts_ids ) );
}
}
return $created_tests;
} else {
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
}//end if
return new WP_Error( 'vrts_service_error', __( 'Error creating test.', 'visual-regression-tests' ) );
}
/**
* Create test remotely via service.
*
* @param WP_Post $post Post.
* @param array $test Test.
*
* @return object|WP_Error
*/
public function create_remote_test( $post, $test = [] ) {
if ( Service::is_connected() ) {
$existing_test = Test::get_item_by_post_id( $post->ID );
if ( $existing_test && $existing_test->service_test_id ) {
return $existing_test;
}
$service_project_id = get_option( 'vrts_project_id' );
$request_url = 'tests';
$parameters = [
'project_id' => $service_project_id,
'url' => get_permalink( $post ),
'frequency' => 'daily',
];
$service_request = Service::rest_service_request( $request_url, $parameters, 'post' );
if ( 201 === $service_request['status_code'] ) {
$test_id = $service_request['response']['id'];
$args = array_merge($test, [
'post_id' => $post->ID,
'service_test_id' => $test_id,
'status' => 1,
]);
unset( $args['id'] );
// TODO: Add some validation.
$new_row_id = Test::save( $args, $test['id'] ?? null );
if ( $new_row_id ) {
Subscription::decrease_tests_count();
Cron_Jobs::schedule_initial_fetch_test_updates( $new_row_id );
return Test::get_item( $new_row_id );
}
} else {
return new WP_Error( 'vrts_service_error', __( 'Service could not create test.', 'visual-regression-tests' ) );
}
} else {
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
}//end if
}
/**
* Create tests remotely via service.
*
* @param array $post_ids Post IDs.
*
* @return array|WP_Error
*/
public function create_remote_tests( $post_ids ) {
if ( Service::is_connected() ) {
$service_project_id = get_option( 'vrts_project_id' );
$request_url = 'tests';
$urls = array_combine( $post_ids, array_map( function ( $post_id ) {
return get_permalink( $post_id );
}, $post_ids ) );
$parameters = [
'project_id' => $service_project_id,
'urls' => array_values( $urls ),
'frequency' => 'daily',
];
$service_request = Service::rest_service_request( $request_url, $parameters, 'post' );
if ( 201 === $service_request['status_code'] ) {
$args = [];
foreach ( $service_request['response'] as $test ) {
$args[] = [
'post_id' => array_search( $test['url'], $urls, true ),
'service_test_id' => $test['id'],
'status' => 1,
];
}
$saved_tests_number = Test::save_multiple( $args );
if ( $saved_tests_number ) {
Subscription::decrease_tests_count( $saved_tests_number );
$post_ids = wp_list_pluck( $args, 'post_id' );
$created_tests = Test::get_items_by_post_ids( $post_ids );
foreach ( $created_tests as $test ) {
Cron_Jobs::schedule_initial_fetch_test_updates( $test->id );
}
return $created_tests;
} else {
return new WP_Error( 'vrts_test_error', __( 'Plugin could not save tests.', 'visual-regression-tests' ) );
}
} else {
return new WP_Error( 'vrts_service_error', __( 'Service could not create tests.', 'visual-regression-tests' ) );
}//end if
} else {
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
}//end if
}
/**
* Delete test.
*
* @param int|object $test_id Test id or test object.
*
* @return bool
*/
public function delete_test( $test_id ) {
$delete_locally = true;
$test = ( is_string( $test_id ) || is_int( $test_id ) )
? Test::get_item( (int) $test_id )
: $test_id;
if ( ! empty( $test->service_test_id ) ) {
$delete_locally = (bool) $this->delete_remote_test( $test_id );
}
if ( ! $delete_locally ) {
Subscription::get_latest_status();
}
return $delete_locally && Test::delete( $test->id );
}
/**
* Delete test remotely via service.
*
* @param int|object $test_id Test id or test object.
*
* @return bool
*/
public function delete_remote_test( $test_id ) {
if ( Service::is_connected() ) {
$test = ( is_string( $test_id ) || is_int( $test_id ) )
? Test::get_item( (int) $test_id )
: $test_id;
if (
Service::delete_test( $test->service_test_id )
&& Subscription::increase_tests_count()
) {
$args = (array) $test;
$args['status'] = 0;
$args['service_test_id'] = null;
unset( $args['id'] );
unset( $args['current_alert_id'] );
Test::save( $args, $test->id );
return $test;
} else {
return false;
}
}
}
/**
* Resume stale tests.
*/
public function resume_stale_tests() {
$stale_tests = Test::get_all_inactive();
foreach ( $stale_tests as $stale_test ) {
if ( Subscription::get_remaining_tests() > 0 ) {
$this->resume_stale_test( $stale_test );
}
}
}
/**
* Resume stale test.
*
* @param object $test Test.
*/
private function resume_stale_test( $test ) {
if ( empty( $test->service_test_id ) ) {
$post = get_post( $test->post_id );
if ( 'publish' === $post->post_status ) {
$this->create_remote_test( $post, (array) $test );
}
}
}
/**
* Update test.
*
* @param int $test_id Test id.
* @param string $css_hide_selector CSS selector to hide.
*
* @return int|WP_Error
*/
public function update_css_hide_selectors( $test_id, $css_hide_selector ) {
if ( Service::is_connected() ) {
$test = Test::get_item( $test_id );
if ( ! $test ) {
return new WP_Error( 'vrts_test_error', __( 'Test not found.', 'visual-regression-tests' ) );
}
$updated = Service::update_test(
$test->service_test_id,
[ 'options' => [ 'hideSelectors' => $css_hide_selector ] ]
);
if ( $updated ) {
return Test::save_hide_css_selectors( $test_id, $css_hide_selector );
} else {
return new WP_Error( 'vrts_service_error', __( 'Service could not update test.', 'visual-regression-tests' ) );
}
} else {
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
}
}
/**
* Resume test.
*
* @param int $post_id Post id.
*/
public function resume_test( $post_id ) {
$test = Test::get_item_by_post_id( $post_id );
if ( ! $test ) {
return false;
} else {
Test::reset_base_screenshot( $test->id );
Service::resume_test( $post_id );
}
}
/**
* Resume tests.
*/
public function resume_tests() {
Test::reset_base_screenshots();
Service::resume_tests();
}
}