Connect AdSense over OAuth, sync entities and daily reports locally, and show placement performance in the admin panel without calling the Management API from public pages.
107 lines
4.4 KiB
PHP
107 lines
4.4 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Models\AdsenseDailyStat;
|
|
use App\Services\Adsense\AdsenseReportParser;
|
|
use Tests\TestCase;
|
|
|
|
uses(TestCase::class);
|
|
|
|
function adsenseReport(array $headers, array $rowValues): array
|
|
{
|
|
return [
|
|
'headers' => $headers,
|
|
'rows' => [
|
|
[
|
|
'cells' => array_map(fn (string $value): array => ['value' => $value], $rowValues),
|
|
],
|
|
],
|
|
];
|
|
}
|
|
|
|
it('maps report cells by header name rather than position', function (): void {
|
|
$parser = new AdsenseReportParser;
|
|
$report = adsenseReport([
|
|
['name' => 'ESTIMATED_EARNINGS', 'type' => 'METRIC_CURRENCY', 'currencyCode' => 'EUR'],
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
['name' => 'PAGE_VIEWS', 'type' => 'METRIC_TALLY'],
|
|
['name' => 'PAGE_VIEWS_CTR', 'type' => 'METRIC_RATIO'],
|
|
], ['12.50', '2026-09-18', '1000', '0.0125']);
|
|
|
|
$rows = $parser->parse($report, AdsenseDailyStat::DIMENSION_TOTAL, 'accounts/pub-1');
|
|
|
|
expect($rows)->toHaveCount(1)
|
|
->and($rows[0]['date'])->toBe('2026-09-18')
|
|
->and($rows[0]['dimension_key'])->toBe(AdsenseDailyStat::TOTAL_DIMENSION_KEY)
|
|
->and($rows[0]['estimated_earnings'])->toBe('12.50')
|
|
->and($rows[0]['page_views'])->toBe(1000)
|
|
->and($rows[0]['page_views_ctr'])->toBe('0.0125')
|
|
->and($rows[0]['currency_code'])->toBe('EUR');
|
|
});
|
|
|
|
it('parses the same values when Google returns columns in another order', function (): void {
|
|
$parser = new AdsenseReportParser;
|
|
$first = $parser->parse(adsenseReport([
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
['name' => 'AD_UNIT_ID', 'type' => 'DIMENSION'],
|
|
['name' => 'CLICKS', 'type' => 'METRIC_TALLY'],
|
|
['name' => 'ESTIMATED_EARNINGS', 'type' => 'METRIC_CURRENCY', 'currencyCode' => 'USD'],
|
|
], ['2026-09-18', 'unit-1', '8', '4.25']), AdsenseDailyStat::DIMENSION_AD_UNIT, 'accounts/pub-1');
|
|
|
|
$second = $parser->parse(adsenseReport([
|
|
['name' => 'ESTIMATED_EARNINGS', 'type' => 'METRIC_CURRENCY', 'currencyCode' => 'USD'],
|
|
['name' => 'CLICKS', 'type' => 'METRIC_TALLY'],
|
|
['name' => 'AD_UNIT_ID', 'type' => 'DIMENSION'],
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
], ['4.25', '8', 'unit-1', '2026-09-18']), AdsenseDailyStat::DIMENSION_AD_UNIT, 'accounts/pub-1');
|
|
|
|
expect($first[0]['dimension_key'])->toBe('unit-1')
|
|
->and($first[0]['clicks'])->toBe($second[0]['clicks'])
|
|
->and($first[0]['estimated_earnings'])->toBe($second[0]['estimated_earnings'])
|
|
->and($first[0]['date'])->toBe($second[0]['date']);
|
|
});
|
|
|
|
it('detects monetary currency from metric headers', function (): void {
|
|
$parser = new AdsenseReportParser;
|
|
$code = $parser->currencyCode([
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
['name' => 'ESTIMATED_EARNINGS', 'type' => 'METRIC_CURRENCY', 'currencyCode' => 'GBP'],
|
|
]);
|
|
|
|
expect($code)->toBe('GBP');
|
|
});
|
|
|
|
it('keeps ratio metrics as google decimals', function (): void {
|
|
$parser = new AdsenseReportParser;
|
|
$rows = $parser->parse(adsenseReport([
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
['name' => 'PLATFORM_TYPE_CODE', 'type' => 'DIMENSION'],
|
|
['name' => 'AD_REQUESTS_COVERAGE', 'type' => 'METRIC_RATIO'],
|
|
['name' => 'IMPRESSIONS_CTR', 'type' => 'METRIC_RATIO'],
|
|
], ['2026-09-19', 'DESKTOP', '0.84', '0.031']), AdsenseDailyStat::DIMENSION_PLATFORM, 'accounts/pub-1');
|
|
|
|
expect($rows[0]['ad_requests_coverage'])->toBe('0.84')
|
|
->and($rows[0]['impressions_ctr'])->toBe('0.031')
|
|
->and($rows[0]['dimension_key'])->toBe('DESKTOP');
|
|
});
|
|
|
|
it('parses country and custom channel dimension keys', function (): void {
|
|
$parser = new AdsenseReportParser;
|
|
|
|
$country = $parser->parse(adsenseReport([
|
|
['name' => 'COUNTRY_CODE', 'type' => 'DIMENSION'],
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
['name' => 'PAGE_VIEWS', 'type' => 'METRIC_TALLY'],
|
|
], ['SI', '2026-09-19', '12']), AdsenseDailyStat::DIMENSION_COUNTRY, 'accounts/pub-1');
|
|
|
|
$channel = $parser->parse(adsenseReport([
|
|
['name' => 'DATE', 'type' => 'DIMENSION'],
|
|
['name' => 'CUSTOM_CHANNEL_ID', 'type' => 'DIMENSION'],
|
|
['name' => 'CLICKS', 'type' => 'METRIC_TALLY'],
|
|
], ['2026-09-19', 'ch-9', '3']), AdsenseDailyStat::DIMENSION_CUSTOM_CHANNEL, 'accounts/pub-1');
|
|
|
|
expect($country[0]['dimension_key'])->toBe('SI')
|
|
->and($channel[0]['dimension_key'])->toBe('ch-9');
|
|
});
|