fix: address QA failures in PR #134 — AJAX nesting, hook typo, test coverage
- Fix: Nested AJAX handler method (on_ajax_sync_runware_models_now) moved to proper class scope in class-ajax-handlers.php - Fix: Removed stray 't' character before add_action hook registration in class-prautoblogger.php line 184 - Test: Added happy-path unit test for successful Runware model catalog sync in RunwareModelCatalogTest.php - All files pass PHP lint validation
This commit is contained in:
@@ -151,60 +151,59 @@ class PRAutoBlogger_Ajax_Handlers {
|
||||
wp_send_json_success( $results );
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler: sync Runware model catalog on demand.
|
||||
*
|
||||
* Nonce-protected and requires manage_options capability.
|
||||
* Returns the updated cache timestamp and model count.
|
||||
*
|
||||
* Side effects: makes HTTP request to Runware API, writes WP options.
|
||||
*/
|
||||
public function on_ajax_sync_runware_models_now(): void {
|
||||
check_ajax_referer( 'prautoblogger_sync_runware_models_now', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$catalog = new PRAutoBlogger_Runware_Model_Catalog();
|
||||
$success = $catalog->sync();
|
||||
|
||||
if ( ! $success ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Catalog sync failed. Check logs for details.', 'prautoblogger' ) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$models = $catalog->get_models();
|
||||
$synced_at = $catalog->get_last_synced_at();
|
||||
$synced_at_str = $synced_at
|
||||
? wp_date( __( 'Y-m-d H:i:s', 'prautoblogger' ), $synced_at )
|
||||
: __( 'Never', 'prautoblogger' );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'message' => __( 'Runware model catalog synced successfully.', 'prautoblogger' ),
|
||||
'model_count' => count( $models ),
|
||||
'synced_at' => $synced_at_str,
|
||||
)
|
||||
);
|
||||
} catch ( \Throwable $e ) {
|
||||
PRAutoBlogger_Logger::instance()->error(
|
||||
sprintf( 'AJAX sync Runware models failed: %s (%s)', $e->getMessage(), get_class( $e ) ),
|
||||
'runware-catalog'
|
||||
);
|
||||
wp_send_json_error( array( 'message' => $e->getMessage() ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the shared model registry instance.
|
||||
*
|
||||
* @return PRAutoBlogger_OpenRouter_Model_Registry
|
||||
*/
|
||||
public function get_registry(): PRAutoBlogger_OpenRouter_Model_Registry {
|
||||
|
||||
/**
|
||||
* AJAX handler: sync Runware model catalog on demand.
|
||||
*
|
||||
* Nonce-protected and requires manage_options capability.
|
||||
* Returns the updated cache timestamp and model count.
|
||||
*
|
||||
* Side effects: makes HTTP request to Runware API, writes WP options.
|
||||
*/
|
||||
public function on_ajax_sync_runware_models_now(): void {
|
||||
check_ajax_referer( 'prautoblogger_sync_runware_models_now', 'nonce' );
|
||||
|
||||
if ( ! current_user_can( 'manage_options' ) ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Insufficient permissions.', 'prautoblogger' ) ), 403 );
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
$catalog = new PRAutoBlogger_Runware_Model_Catalog();
|
||||
$success = $catalog->sync();
|
||||
|
||||
if ( ! $success ) {
|
||||
wp_send_json_error( array( 'message' => __( 'Catalog sync failed. Check logs for details.', 'prautoblogger' ) ) );
|
||||
return;
|
||||
}
|
||||
|
||||
$models = $catalog->get_models();
|
||||
$synced_at = $catalog->get_last_synced_at();
|
||||
$synced_at_str = $synced_at
|
||||
? wp_date( __( 'Y-m-d H:i:s', 'prautoblogger' ), $synced_at )
|
||||
: __( 'Never', 'prautoblogger' );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'message' => __( 'Runware model catalog synced successfully.', 'prautoblogger' ),
|
||||
'model_count' => count( $models ),
|
||||
'synced_at' => $synced_at_str,
|
||||
)
|
||||
);
|
||||
} catch ( \Throwable $e ) {
|
||||
PRAutoBlogger_Logger::instance()->error(
|
||||
sprintf( 'AJAX sync Runware models failed: %s (%s)', $e->getMessage(), get_class( $e ) ),
|
||||
'runware-catalog'
|
||||
);
|
||||
wp_send_json_error( array( 'message' => $e->getMessage() ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $this->model_registry;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,7 +181,7 @@ class PRAutoBlogger {
|
||||
add_action( 'wp_ajax_prautoblogger_test_connection', array( $this->ajax_handlers, 'on_ajax_test_connection' ) );
|
||||
add_action( 'wp_ajax_prautoblogger_get_models', array( $this->ajax_handlers, 'on_ajax_get_models' ) );
|
||||
add_action( 'wp_ajax_prautoblogger_refresh_models', array( new PRAutoBlogger_Model_Registry_Refresh( $this->ajax_handlers->get_registry() ), 'handle' ) );
|
||||
t add_action( 'wp_ajax_prautoblogger_sync_runware_models_now', array( $this->ajax_handlers, 'on_ajax_sync_runware_models_now' ) );
|
||||
add_action( 'wp_ajax_prautoblogger_sync_runware_models_now', array( $this->ajax_handlers, 'on_ajax_sync_runware_models_now' ) );
|
||||
|
||||
$review_queue = new PRAutoBlogger_Review_Queue();
|
||||
add_action( 'wp_ajax_prautoblogger_approve_post', array( $review_queue, 'on_ajax_approve_post' ) );
|
||||
|
||||
@@ -122,4 +122,59 @@ class RunwareModelCatalogTest extends BaseTestCase {
|
||||
$this->assertContains( 'image_generation', $model['capabilities'] );
|
||||
}
|
||||
}
|
||||
|
||||
/** Happy path: successful sync caches models and get_models returns them. */
|
||||
public function test_sync_success_caches_and_returns_models(): void {
|
||||
// Mock a valid Runware API response.
|
||||
Functions\when( 'wp_remote_post' )->justReturn(
|
||||
array(
|
||||
'response' => array( 'code' => 200 ),
|
||||
'body' => wp_json_encode(
|
||||
array(
|
||||
'data' => array(
|
||||
array(
|
||||
'id' => 'test-model-1',
|
||||
'name' => 'Test Model 1',
|
||||
'cost' => 0.001,
|
||||
'provider' => 'runware',
|
||||
),
|
||||
array(
|
||||
'id' => 'test-model-2',
|
||||
'name' => 'Test Model 2',
|
||||
'cost' => 0.002,
|
||||
'provider' => 'runware',
|
||||
),
|
||||
),
|
||||
)
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// Mock the API key to exist.
|
||||
Functions\when( 'get_option' )->alias( function ( $key, $default = false ) {
|
||||
static $options = array();
|
||||
if ( 'prautoblogger_runware_api_key' === $key ) {
|
||||
return 'test-api-key';
|
||||
}
|
||||
return $options[ $key ] ?? $default;
|
||||
} );
|
||||
|
||||
Functions\when( 'update_option' )->alias( function ( $key, $value ) {
|
||||
static $options = array();
|
||||
$options[ $key ] = $value;
|
||||
return true;
|
||||
} );
|
||||
|
||||
// Perform the sync.
|
||||
$catalog = new \PRAutoBlogger_Runware_Model_Catalog();
|
||||
$result = $catalog->sync();
|
||||
$this->assertTrue( $result, 'Sync should return true on success' );
|
||||
|
||||
// Verify get_models returns the synced models (not fallback).
|
||||
$models = $catalog->get_models();
|
||||
$this->assertIsArray( $models );
|
||||
$this->assertCount( 2, $models );
|
||||
$this->assertSame( 'test-model-1', $models[0]['id'] );
|
||||
$this->assertSame( 'test-model-2', $models[1]['id'] );
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user