From a243b4c03203527c26c5de63c301a96e15d88034 Mon Sep 17 00:00:00 2001 From: Matt Friedman Date: Mon, 18 May 2026 08:19:06 -0700 Subject: [PATCH] Update tests and code quality --- tests/controller/log_controller_test.php | 47 +++--- tests/event/listener_test.php | 63 +++----- tests/functional/frontend_test.php | 58 +++---- tests/javascript/consentmanager.test.js | 35 +++-- tests/service/acp_manager_test.php | 189 +++++++++-------------- tests/service/consent_cache_test.php | 35 +---- tests/service/consent_manager_test.php | 122 ++++++--------- tests/service/media_manager_test.php | 50 +++--- 8 files changed, 236 insertions(+), 363 deletions(-) diff --git a/tests/controller/log_controller_test.php b/tests/controller/log_controller_test.php index 408d185..e798a9d 100644 --- a/tests/controller/log_controller_test.php +++ b/tests/controller/log_controller_test.php @@ -12,14 +12,30 @@ class log_controller_test extends \phpbb_test_case { - public function test_log_rejects_invalid_json_payload() + /** @var \phpbb\consentmanager\service\log_manager|\PHPUnit\Framework\MockObject\MockObject */ + protected $log_manager; + + /** @var \phpbb\consentmanager\service\consent_manager_interface|\PHPUnit\Framework\MockObject\MockObject */ + protected $consent_manager; + + /** @var \phpbb\consentmanager\controller\log_controller */ + protected $controller; + + protected function setUp(): void { - $controller = new \phpbb\consentmanager\controller\log_controller( - $this->createMock('\phpbb\consentmanager\service\log_manager'), - $this->createMock('\phpbb\consentmanager\service\consent_manager_interface') + parent::setUp(); + + $this->log_manager = $this->createMock('\phpbb\consentmanager\service\log_manager'); + $this->consent_manager = $this->createMock('\phpbb\consentmanager\service\consent_manager_interface'); + $this->controller = new \phpbb\consentmanager\controller\log_controller( + $this->log_manager, + $this->consent_manager ); + } - $response = $controller->log(\Symfony\Component\HttpFoundation\Request::create( + public function test_log_rejects_invalid_json_payload() + { + $response = $this->controller->log(\Symfony\Component\HttpFoundation\Request::create( '/consent/log', 'POST', array(), @@ -41,12 +57,10 @@ public function test_log_rejects_invalid_json_payload() */ public function test_log_returns_service_validation_failure($submission_error, $expected_status) { - $log_manager = $this->createMock('\phpbb\consentmanager\service\log_manager'); - $log_manager->expects(self::never()) + $this->log_manager->expects(self::never()) ->method('log_consent'); - $consent_manager = $this->createMock('\phpbb\consentmanager\service\consent_manager_interface'); - $consent_manager->expects(self::once()) + $this->consent_manager->expects(self::once()) ->method('validate_log_payload') ->with(array('hash' => 'bad')) ->willReturn(array( @@ -54,8 +68,7 @@ public function test_log_returns_service_validation_failure($submission_error, $ 'error' => $submission_error, )); - $controller = new \phpbb\consentmanager\controller\log_controller($log_manager, $consent_manager); - $response = $controller->log(new \Symfony\Component\HttpFoundation\Request(array(), array(), array(), array(), array(), array(), json_encode(array( + $response = $this->controller->log(new \Symfony\Component\HttpFoundation\Request(array(), array(), array(), array(), array(), array(), json_encode(array( 'hash' => 'bad', )))); @@ -65,14 +78,11 @@ public function test_log_returns_service_validation_failure($submission_error, $ public function test_log_persists_valid_submission() { - $arguments = [['necessary', 'analytics'], 5]; - $log_manager = $this->createMock('\phpbb\consentmanager\service\log_manager'); - $log_manager->expects(self::once()) + $this->log_manager->expects(self::once()) ->method('log_consent') - ->with(...$arguments); + ->with(['necessary', 'analytics'], 5); - $consent_manager = $this->createMock('\phpbb\consentmanager\service\consent_manager_interface'); - $consent_manager->expects(self::once()) + $this->consent_manager->expects(self::once()) ->method('validate_log_payload') ->willReturn(array( 'success' => true, @@ -80,8 +90,7 @@ public function test_log_persists_valid_submission() 'version' => 5, )); - $controller = new \phpbb\consentmanager\controller\log_controller($log_manager, $consent_manager); - $response = $controller->log(new \Symfony\Component\HttpFoundation\Request(array(), array(), array(), array(), array(), array(), json_encode(array( + $response = $this->controller->log(new \Symfony\Component\HttpFoundation\Request(array(), array(), array(), array(), array(), array(), json_encode(array( 'hash' => 'good', 'version' => 5, 'categories' => array('analytics'), diff --git a/tests/event/listener_test.php b/tests/event/listener_test.php index ac90d49..8a23bcd 100644 --- a/tests/event/listener_test.php +++ b/tests/event/listener_test.php @@ -12,9 +12,12 @@ class listener_test extends \phpbb_test_case { - /** @var \phpbb\language\language */ + /** @var \phpbb\language\language|\PHPUnit\Framework\MockObject\MockObject */ protected $language; + /** @var \phpbb\consentmanager\service\media_manager|\PHPUnit\Framework\MockObject\MockObject */ + protected $media_manager; + protected function setUp(): void { parent::setUp(); @@ -22,6 +25,7 @@ protected function setUp(): void global $user; $this->language = $this->createMock('\phpbb\language\language'); + $this->media_manager = $this->createMock('\phpbb\consentmanager\service\media_manager'); $user = new \phpbb\user($this->language, '\phpbb\datetime'); $user->data = [ @@ -30,6 +34,17 @@ protected function setUp(): void ]; } + protected function create_listener($helper = null, $consent_manager = null, $template = null, $media_manager = null) + { + return new \phpbb\consentmanager\event\listener( + $helper ?? $this->createMock('\phpbb\controller\helper'), + $this->language, + $consent_manager ?? $this->createMock('\phpbb\consentmanager\service\consent_manager_interface'), + $template ?? $this->createMock('\phpbb\template\template'), + $media_manager ?? $this->media_manager + ); + } + public function test_get_subscribed_events() { self::assertSame([ @@ -43,22 +58,11 @@ public function test_configure_iframe_embeds_delegates_to_media_manager() { $configurator = new \s9e\TextFormatter\Configurator(); - $args = [$configurator]; - - $media_manager = $this->createMock('\phpbb\consentmanager\service\media_manager'); - $media_manager->expects(self::once()) + $this->media_manager->expects(self::once()) ->method('configure_iframe_embeds') - ->with(...$args); - - $listener = new \phpbb\consentmanager\event\listener( - $this->createMock('\phpbb\controller\helper'), - $this->language, - $this->createMock('\phpbb\consentmanager\service\consent_manager_interface'), - $this->createMock('\phpbb\template\template'), - $media_manager - ); + ->with($configurator); - $listener->configure_iframe_embeds(new \phpbb\event\data([ + $this->create_listener()->configure_iframe_embeds(new \phpbb\event\data([ 'configurator' => $configurator, ])); } @@ -69,22 +73,11 @@ public function test_configure_iframe_renderer_delegates_to_media_manager() ->disableOriginalConstructor() ->getMock(); - $args = [$renderer]; - - $media_manager = $this->createMock('\phpbb\consentmanager\service\media_manager'); - $media_manager->expects(self::once()) + $this->media_manager->expects(self::once()) ->method('configure_iframe_renderer') - ->with(...$args); - - $listener = new \phpbb\consentmanager\event\listener( - $this->createMock('\phpbb\controller\helper'), - $this->language, - $this->createMock('\phpbb\consentmanager\service\consent_manager_interface'), - $this->createMock('\phpbb\template\template'), - $media_manager - ); + ->with($renderer); - $listener->configure_iframe_renderer(new \phpbb\event\data([ + $this->create_listener()->configure_iframe_renderer(new \phpbb\event\data([ 'renderer' => $renderer, ])); } @@ -171,7 +164,7 @@ public function test_inject_frontend_assigns_template_payload($invoke) ]] ); - $listener = new class($helper, $this->language, $consent_manager, $template, $this->createMock('\phpbb\consentmanager\service\media_manager'), $invoke) extends \phpbb\consentmanager\event\listener { + $listener = new class($helper, $this->language, $consent_manager, $template, $this->media_manager, $invoke) extends \phpbb\consentmanager\event\listener { /** @var bool */ protected $is_frontend_context; @@ -214,14 +207,6 @@ public function test_inject_frontend_skips_category_blocks_when_frontend_disable $template->expects(self::never()) ->method('assign_block_vars'); - $listener = new \phpbb\consentmanager\event\listener( - $helper, - $this->language, - $consent_manager, - $template, - $this->createMock('\phpbb\consentmanager\service\media_manager') - ); - - $listener->inject_frontend(); + $this->create_listener($helper, $consent_manager, $template)->inject_frontend(); } } diff --git a/tests/functional/frontend_test.php b/tests/functional/frontend_test.php index 28e23e7..6457fb6 100644 --- a/tests/functional/frontend_test.php +++ b/tests/functional/frontend_test.php @@ -43,7 +43,7 @@ public function test_frontend_markup_is_injected_on_board_pages() public function test_log_endpoint_rejects_invalid_json_payload() { - $payload = $this->extract_payload(self::request('GET', 'index.php') ? self::get_content() : ''); + $payload = $this->fetch_frontend_payload(); self::$client->request( 'POST', @@ -63,22 +63,9 @@ public function test_log_endpoint_rejects_invalid_json_payload() public function test_log_endpoint_accepts_valid_anonymous_submission_without_persisting_it() { - $payload = $this->extract_payload(self::request('GET', 'index.php') ? self::get_content() : ''); + $payload = $this->fetch_frontend_payload(); + $response = $this->post_log_request($payload, array('analytics', 'analytics', 'unknown')); - self::$client->request( - 'POST', - $payload['logEndpoint'], - array(), - array(), - array('CONTENT_TYPE' => 'application/json'), - json_encode(array( - 'hash' => $payload['logHash'], - 'version' => $payload['version'], - 'categories' => array('analytics', 'analytics', 'unknown'), - )) - ); - - $response = json_decode(self::$client->getResponse()->getContent(), true); $this->assertSame(200, self::$client->getResponse()->getStatus()); $this->assertSame(array('necessary', 'analytics'), $response['categories']); $this->assertSame($payload['version'], $response['version']); @@ -97,22 +84,9 @@ public function test_log_endpoint_persists_valid_authenticated_submission() $this->create_user('consentuser'); $this->login('consentuser'); - $payload = $this->extract_payload(self::request('GET', 'index.php') ? self::get_content() : ''); - - self::$client->request( - 'POST', - $payload['logEndpoint'], - array(), - array(), - array('CONTENT_TYPE' => 'application/json'), - json_encode(array( - 'hash' => $payload['logHash'], - 'version' => $payload['version'], - 'categories' => array('analytics', 'analytics', 'unknown'), - )) - ); + $payload = $this->fetch_frontend_payload(); + $response = $this->post_log_request($payload, array('analytics', 'analytics', 'unknown')); - $response = json_decode(self::$client->getResponse()->getContent(), true); $this->assertSame(200, self::$client->getResponse()->getStatus()); $this->assertSame(array('necessary', 'analytics'), $response['categories']); $this->assertSame($payload['version'], $response['version']); @@ -130,8 +104,20 @@ public function test_log_endpoint_persists_valid_authenticated_submission() public function test_log_endpoint_rejects_stale_version() { - $payload = $this->extract_payload(self::request('GET', 'index.php') ? self::get_content() : ''); + $payload = $this->fetch_frontend_payload(); + $response = $this->post_log_request($payload, array('analytics'), $payload['version'] + 1); + + $this->assertSame(409, self::$client->getResponse()->getStatus()); + $this->assertSame('version_mismatch', $response['error']); + } + + protected function fetch_frontend_payload() + { + return $this->extract_payload(self::request('GET', 'index.php') ? self::get_content() : ''); + } + protected function post_log_request(array $payload, array $categories, $version = null) + { self::$client->request( 'POST', $payload['logEndpoint'], @@ -140,14 +126,12 @@ public function test_log_endpoint_rejects_stale_version() array('CONTENT_TYPE' => 'application/json'), json_encode(array( 'hash' => $payload['logHash'], - 'version' => $payload['version'] + 1, - 'categories' => array('analytics'), + 'version' => $version ?? $payload['version'], + 'categories' => $categories, )) ); - $response = json_decode(self::$client->getResponse()->getContent(), true); - $this->assertSame(409, self::$client->getResponse()->getStatus()); - $this->assertSame('version_mismatch', $response['error']); + return json_decode(self::$client->getResponse()->getContent(), true); } protected function extract_payload($content) diff --git a/tests/javascript/consentmanager.test.js b/tests/javascript/consentmanager.test.js index ec5856c..e434c18 100644 --- a/tests/javascript/consentmanager.test.js +++ b/tests/javascript/consentmanager.test.js @@ -1,3 +1,4 @@ +/* jshint ignore:start */ const fs = require('fs'); const path = require('path'); const { JSDOM, VirtualConsole } = require('jsdom'); @@ -20,9 +21,9 @@ function createPayload(overrides) { { id: 'marketing', enabled: true, required: false }, { id: 'media', enabled: true, required: false } ], - requiredCategories: ['necessary'], - enabledCategories: ['necessary', 'analytics', 'marketing', 'media'], - optionalCategories: ['analytics', 'marketing', 'media'], + requiredCategories: [ 'necessary' ], + enabledCategories: [ 'necessary', 'analytics', 'marketing', 'media' ], + optionalCategories: [ 'analytics', 'marketing', 'media' ], scripts: [] }, overrides || {}); } @@ -180,8 +181,8 @@ afterEach(() => { }); test('prefers the newest stored state and synchronizes cookie and local storage', () => { - const localState = createState(['necessary', 'marketing'], '2026-04-27T00:00:00.000Z'); - const cookieState = createState(['necessary', 'analytics'], '2026-04-28T00:00:00.000Z'); + const localState = createState([ 'necessary', 'marketing' ], '2026-04-27T00:00:00.000Z'); + const cookieState = createState([ 'necessary', 'analytics' ], '2026-04-28T00:00:00.000Z'); const { window, document, payload } = setupConsentManager({ localState, cookieState @@ -195,7 +196,7 @@ test('prefers the newest stored state and synchronizes cookie and local storage' test('replays queued API calls and executes consented registered scripts', () => { const ready = jest.fn(); const { window } = setupConsentManager({ - localState: createState(['necessary', 'analytics'], '2026-04-28T00:00:00.000Z'), + localState: createState([ 'necessary', 'analytics' ], '2026-04-28T00:00:00.000Z'), queue: { _queue: [ [ @@ -206,7 +207,7 @@ test('replays queued API calls and executes consented registered scripts', () => inline: 'window.analyticsCounter = (window.analyticsCounter || 0) + 1;' } ], - ['ready', ready] + [ 'ready', ready ] ] } }); @@ -226,7 +227,7 @@ test('accept-all persists consent, logs the decision, and updates the UI state', click(window, '[data-consent-action="accept-all"]'); expect(window.consentManager.getState()).toEqual({ - categories: ['necessary', 'analytics', 'marketing', 'media'], + categories: [ 'necessary', 'analytics', 'marketing', 'media' ], timestamp: expect.any(String), version: payload.version }); @@ -240,13 +241,13 @@ test('accept-all persists consent, logs the decision, and updates the UI state', expect(JSON.parse(requests[0].body)).toEqual({ hash: payload.logHash, version: payload.version, - categories: ['necessary', 'analytics', 'marketing', 'media'] + categories: [ 'necessary', 'analytics', 'marketing', 'media' ] }); }); test('reject-all logs the updated decision before reloading when consent is revoked', () => { const { window, payload, requests, jsdomErrors } = setupConsentManager({ - localState: createState(['necessary', 'analytics', 'marketing', 'media'], '2026-04-28T00:00:00.000Z') + localState: createState([ 'necessary', 'analytics', 'marketing', 'media' ], '2026-04-28T00:00:00.000Z') }); click(window, '[data-consent-action="reject-all"]'); @@ -257,7 +258,7 @@ test('reject-all logs the updated decision before reloading when consent is revo expect(JSON.parse(requests[0].body)).toEqual({ hash: payload.logHash, version: payload.version, - categories: ['necessary'] + categories: [ 'necessary' ] }); expect(jsdomErrors).toHaveLength(1); expect(jsdomErrors[0].message).toContain('Not implemented: navigation'); @@ -265,7 +266,7 @@ test('reject-all logs the updated decision before reloading when consent is revo test('registerScript blocks unsafe sources and executes safe inline scripts', () => { const { window, document } = setupConsentManager({ - localState: createState(['necessary', 'analytics'], '2026-04-28T00:00:00.000Z') + localState: createState([ 'necessary', 'analytics' ], '2026-04-28T00:00:00.000Z') }); expect(window.consentManager.registerScript('unsafe', { @@ -284,7 +285,7 @@ test('registerScript blocks unsafe sources and executes safe inline scripts', () test('processes deferred consent scripts and copies only safe attributes', () => { const { window, document } = setupConsentManager({ - localState: createState(['necessary', 'analytics'], '2026-04-28T00:00:00.000Z'), + localState: createState([ 'necessary', 'analytics' ], '2026-04-28T00:00:00.000Z'), extraMarkup: `