'; }
function checked( $expected, $actual ) { if ( $expected === $actual ) echo 'checked="checked"'; }
function submit_button() { echo ''; }
function date_i18n( $format, $timestamp ) { return gmdate( $format, $timestamp ); }
function number_format_i18n( $number ) { return number_format( $number ); }
require_once __DIR__ . '/../includes/class-plugin.php';
require_once __DIR__ . '/../includes/class-status.php';
require_once __DIR__ . '/../includes/class-connect.php';
require_once __DIR__ . '/../includes/class-settings.php';
}
namespace Aisthetix\TryOn {
class SettingsTestStatus extends Status {
public $payload = array();
public $get_calls = 0;
public $refresh_calls = 0;
public function get( $force = false ) { ++$this->get_calls; return $this->payload; }
public function refresh() { ++$this->refresh_calls; return $this->payload; }
}
class SettingsTestConnect extends Connect {
public function start_url() { return 'https://woo.aisthetix.fyi/connect'; }
public function disconnect_url() { return 'https://merchant.example/disconnect'; }
}
}
namespace {
use Aisthetix\TryOn\Connect;
use Aisthetix\TryOn\Plugin;
use Aisthetix\TryOn\Settings;
use Aisthetix\TryOn\SettingsTestConnect;
use Aisthetix\TryOn\SettingsTestStatus;
$passed = 0;
$failed = 0;
function settings_check( $name, $condition ) {
global $passed, $failed;
if ( $condition ) { echo " ✓ {$name}\n"; ++$passed; return; }
echo " ✗ {$name}\n"; ++$failed;
}
function settings_render( $callable ) { ob_start(); $callable(); return ob_get_clean(); }
function settings_connected( $connected ) {
$GLOBALS['settings_options'][ Plugin::OPTION_PUBLISHABLE_KEY ] = $connected ? 'pk_test' : '';
$GLOBALS['settings_options'][ Plugin::OPTION_SECRET_KEY ] = $connected ? 'sk_test' : '';
}
echo "Settings\n";
$status = new SettingsTestStatus();
$connect = new SettingsTestConnect( $status );
$settings = new Settings( $status, $connect );
$settings->init();
settings_check( 'registers all three admin hooks', 3 === count( $GLOBALS['settings_hooks'] ) );
$settings->register_menu();
settings_check( 'registers under WooCommerce', 'woocommerce' === $GLOBALS['settings_menu'][0] );
$settings->register_settings();
settings_check( 'registers an array sanitizer', is_callable( $GLOBALS['settings_registration'][2]['sanitize_callback'] ) );
$clean = $settings->sanitize_settings(
array(
'placement' => 'manual',
'button_text' => ' Try now ',
'unavailable_title' => str_repeat( 'T', 90 ),
'unavailable_message' => str_repeat( 'M', 250 ),
'unavailable_button_text' => str_repeat( 'B', 50 ),
'unavailable_button_url' => 'https://merchant.example/new',
'enable_analytics' => '1',
'enable_session_replay' => '1',
)
);
settings_check( 'keeps an allowed placement', 'manual' === $clean['placement'] );
settings_check( 'sanitizes the button label', 'Try now' === $clean['button_text'] );
settings_check( 'applies UI length limits', 80 === strlen( $clean['unavailable_title'] ) && 240 === strlen( $clean['unavailable_message'] ) && 40 === strlen( $clean['unavailable_button_text'] ) );
settings_check( 'keeps a same-site fallback URL', 'https://merchant.example/new' === $clean['unavailable_button_url'] );
settings_check( 'normalizes opt-ins to booleans', true === $clean['enable_analytics'] && true === $clean['enable_session_replay'] );
$invalid = $settings->sanitize_settings( array( 'placement' => 'header', 'unavailable_button_url' => 'https://evil.example/' ) );
settings_check( 'rejects placement and cross-site URL injection', 'after_add_to_cart' === $invalid['placement'] && '' === $invalid['unavailable_button_url'] );
$relative = $settings->sanitize_settings( array( 'unavailable_button_url' => '/relative' ) );
settings_check( 'rejects hostless fallback URLs', '' === $relative['unavailable_button_url'] );
settings_connected( false );
$_GET = array( 'aisthetix_notice' => 'connect_success' );
$out = settings_render( array( $settings, 'render_notices' ) );
settings_check( 'renders a connect result but no usage notice while disconnected', false !== strpos( $out, 'Connected to aisthetix successfully' ) && 0 === $status->get_calls );
settings_connected( true );
$status->payload = array( 'trial' => array( 'remaining' => 7 ), 'plan' => 'Starter', 'includedTryOns' => 100 );
$out = settings_render( array( $settings, 'render_notices' ) );
settings_check( 'warns before trial exhaustion', false !== strpos( $out, '7 try-ons remaining' ) && false !== strpos( $out, 'notice-warning' ) );
$status->payload = array( 'trial' => array( 'remaining' => 0 ), 'plan' => '', 'includedTryOns' => 300 );
$out = settings_render( array( $settings, 'render_notices' ) );
settings_check( 'explains a paused trial and its allowance', false !== strpos( $out, 'currently paused' ) && false !== strpos( $out, '300 monthly' ) );
$_GET = array();
$status->payload = array( 'trial' => array( 'remaining' => 11 ) );
settings_check( 'does not nag above the low-trial threshold', '' === settings_render( array( $settings, 'render_notices' ) ) );
$status->payload = array( 'trial' => null );
settings_check( 'does not fabricate a notice without trial data', '' === settings_render( array( $settings, 'render_notices' ) ) );
$GLOBALS['settings_can_manage'] = false;
settings_check( 'denies the settings page without merchant capability', '' === settings_render( array( $settings, 'render_page' ) ) );
$GLOBALS['settings_can_manage'] = true;
settings_connected( false );
$status->payload = array( 'error' => 'Not connected' );
$out = settings_render( array( $settings, 'render_page' ) );
settings_check( 'renders the disconnected page and privacy promise', false !== strpos( $out, 'Connect aisthetix' ) && false !== strpos( $out, 'never stored on your WordPress server' ) );
settings_connected( true );
$GLOBALS['settings_options'][ Plugin::OPTION_SETTINGS ] = array( 'placement' => 'manual', 'enable_analytics' => true, 'enable_session_replay' => true );
foreach (
array(
array( 'error' => 'offline' ),
array( 'active' => true, 'withinQuota' => true, 'remaining' => 240, 'resetsAt' => '2026-10-01T00:00:00Z', 'plan' => 'Pro' ),
array( 'active' => false, 'withinQuota' => false, 'remaining' => 0, 'resetsAt' => '', 'plan' => '' ),
) as $payload
) {
$status->payload = $payload;
$out = settings_render( array( $settings, 'render_page' ) );
settings_check( 'connected settings page renders its plan state', false !== strpos( $out, 'Disconnect' ) && false !== strpos( $out, 'Plan & usage' ) );
}
settings_check( 'connected page force-refreshes status', 3 <= $status->refresh_calls );
echo "\n{$passed} passed, {$failed} failed\n";
exit( $failed > 0 ? 1 : 0 );
}