Skip to content

Commit 8b91af6

Browse files
committed
Added tests for Events.
1 parent 81a7c69 commit 8b91af6

File tree

2 files changed

+878
-0
lines changed

2 files changed

+878
-0
lines changed
Lines changed: 366 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,366 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace WPGraphQL\Logging\Tests\Events;
6+
7+
use lucatume\WPBrowser\TestCase\WPTestCase;
8+
use ReflectionClass;
9+
use WPGraphQL\Logging\Events\EventManager;
10+
use WPGraphQL\Logging\Events\Events;
11+
12+
/**
13+
* Class EventManagerTest
14+
*
15+
* Tests for the EventManager class.
16+
*/
17+
class EventManagerTest extends WPTestCase {
18+
19+
/**
20+
* Reset EventManager state after each test.
21+
*/
22+
public function tearDown(): void {
23+
parent::tearDown();
24+
$this->reset_event_manager();
25+
}
26+
27+
/**
28+
* Reset the EventManager static state.
29+
*/
30+
private function reset_event_manager(): void {
31+
$reflection = new ReflectionClass(EventManager::class);
32+
33+
$events_prop = $reflection->getProperty('events');
34+
$events_prop->setAccessible(true);
35+
$events_prop->setValue(null, []);
36+
37+
$transforms_prop = $reflection->getProperty('transforms');
38+
$transforms_prop->setAccessible(true);
39+
$transforms_prop->setValue(null, []);
40+
}
41+
42+
/**
43+
* Get the internal events array for testing.
44+
*/
45+
private function get_events_array(): array {
46+
$reflection = new ReflectionClass(EventManager::class);
47+
$events_prop = $reflection->getProperty('events');
48+
$events_prop->setAccessible(true);
49+
return $events_prop->getValue();
50+
}
51+
52+
/**
53+
* Get the internal transforms array for testing.
54+
*/
55+
private function get_transforms_array(): array {
56+
$reflection = new ReflectionClass(EventManager::class);
57+
$transforms_prop = $reflection->getProperty('transforms');
58+
$transforms_prop->setAccessible(true);
59+
return $transforms_prop->getValue();
60+
}
61+
62+
public function test_subscribe_adds_listener_to_event(): void {
63+
$listener_called = false;
64+
$listener = function(array $payload) use (&$listener_called) {
65+
$listener_called = true;
66+
};
67+
68+
EventManager::subscribe('test_event', $listener);
69+
70+
$events = $this->get_events_array();
71+
$this->assertArrayHasKey('test_event', $events);
72+
$this->assertArrayHasKey(10, $events['test_event']); // Default priority
73+
$this->assertCount(1, $events['test_event'][10]);
74+
$this->assertSame($listener, $events['test_event'][10][0]);
75+
}
76+
77+
public function test_subscribe_with_custom_priority(): void {
78+
$listener1 = function() {};
79+
$listener2 = function() {};
80+
81+
EventManager::subscribe('priority_test', $listener1, 5);
82+
EventManager::subscribe('priority_test', $listener2, 15);
83+
84+
$events = $this->get_events_array();
85+
$this->assertArrayHasKey(5, $events['priority_test']);
86+
$this->assertArrayHasKey(15, $events['priority_test']);
87+
$this->assertSame($listener1, $events['priority_test'][5][0]);
88+
$this->assertSame($listener2, $events['priority_test'][15][0]);
89+
}
90+
91+
public function test_subscribe_multiple_listeners_same_priority(): void {
92+
$listener1 = function() {};
93+
$listener2 = function() {};
94+
95+
EventManager::subscribe('multi_test', $listener1);
96+
EventManager::subscribe('multi_test', $listener2);
97+
98+
$events = $this->get_events_array();
99+
$this->assertCount(2, $events['multi_test'][10]);
100+
$this->assertSame($listener1, $events['multi_test'][10][0]);
101+
$this->assertSame($listener2, $events['multi_test'][10][1]);
102+
}
103+
104+
public function test_publish_calls_subscribed_listeners(): void {
105+
$payload_received = null;
106+
$listener_calls = 0;
107+
108+
$listener = function(array $payload) use (&$payload_received, &$listener_calls) {
109+
$payload_received = $payload;
110+
$listener_calls++;
111+
};
112+
113+
EventManager::subscribe('publish_test', $listener);
114+
115+
$test_payload = ['test' => 'data'];
116+
EventManager::publish('publish_test', $test_payload);
117+
118+
$this->assertEquals(1, $listener_calls);
119+
$this->assertEquals($test_payload, $payload_received);
120+
}
121+
122+
public function test_publish_calls_listeners_in_priority_order(): void {
123+
$call_order = [];
124+
125+
$high_priority = function() use (&$call_order) {
126+
$call_order[] = 'high';
127+
};
128+
129+
$low_priority = function() use (&$call_order) {
130+
$call_order[] = 'low';
131+
};
132+
133+
$medium_priority = function() use (&$call_order) {
134+
$call_order[] = 'medium';
135+
};
136+
137+
EventManager::subscribe('order_test', $high_priority, 5); // Lower number = higher priority
138+
EventManager::subscribe('order_test', $low_priority, 20);
139+
EventManager::subscribe('order_test', $medium_priority, 10);
140+
141+
EventManager::publish('order_test');
142+
143+
$this->assertEquals(['high', 'medium', 'low'], $call_order);
144+
}
145+
146+
public function test_publish_with_no_listeners_triggers_wordpress_action(): void {
147+
$action_called = false;
148+
$received_payload = null;
149+
150+
// Mock WordPress do_action by overriding the global function
151+
$this->mock_wordpress_action('wpgraphql_logging_event_no_listeners', function($payload) use (&$action_called, &$received_payload) {
152+
$action_called = true;
153+
$received_payload = $payload;
154+
});
155+
156+
$test_payload = ['empty' => 'test'];
157+
EventManager::publish('no_listeners', $test_payload);
158+
159+
$this->assertTrue($action_called);
160+
$this->assertEquals($test_payload, $received_payload);
161+
}
162+
163+
public function test_publish_triggers_wordpress_action_after_listeners(): void {
164+
$execution_order = [];
165+
166+
$listener = function() use (&$execution_order) {
167+
$execution_order[] = 'listener';
168+
};
169+
170+
EventManager::subscribe('wp_action_test', $listener);
171+
172+
$this->mock_wordpress_action('wpgraphql_logging_event_wp_action_test', function() use (&$execution_order) {
173+
$execution_order[] = 'wp_action';
174+
});
175+
176+
EventManager::publish('wp_action_test');
177+
178+
$this->assertEquals(['listener', 'wp_action'], $execution_order);
179+
}
180+
181+
public function test_subscribe_to_transform_adds_transformer(): void {
182+
$transformer = function(array $payload): array {
183+
return $payload;
184+
};
185+
186+
EventManager::subscribe_to_transform('transform_test', $transformer);
187+
188+
$transforms = $this->get_transforms_array();
189+
$this->assertArrayHasKey('transform_test', $transforms);
190+
$this->assertArrayHasKey(10, $transforms['transform_test']);
191+
$this->assertSame($transformer, $transforms['transform_test'][10][0]);
192+
}
193+
194+
public function test_transform_modifies_payload(): void {
195+
$transformer = function(array $payload): array {
196+
$payload['transformed'] = true;
197+
return $payload;
198+
};
199+
200+
EventManager::subscribe_to_transform('modify_test', $transformer);
201+
202+
$original = ['original' => 'data'];
203+
$result = EventManager::transform('modify_test', $original);
204+
205+
$this->assertTrue($result['transformed']);
206+
$this->assertEquals('data', $result['original']);
207+
}
208+
209+
public function test_transform_with_multiple_transformers_in_priority_order(): void {
210+
$first_transformer = function(array $payload): array {
211+
$payload['order'][] = 'first';
212+
return $payload;
213+
};
214+
215+
$second_transformer = function(array $payload): array {
216+
$payload['order'][] = 'second';
217+
return $payload;
218+
};
219+
220+
EventManager::subscribe_to_transform('multi_transform', $first_transformer, 5);
221+
EventManager::subscribe_to_transform('multi_transform', $second_transformer, 10);
222+
223+
$result = EventManager::transform('multi_transform', ['order' => []]);
224+
225+
$this->assertEquals(['first', 'second'], $result['order']);
226+
}
227+
228+
public function test_transform_with_no_transformers_applies_wordpress_filter(): void {
229+
$filter_applied = false;
230+
$received_payload = null;
231+
232+
$this->mock_wordpress_filter('wpgraphql_logging_filter_filter_test', function($payload) use (&$filter_applied, &$received_payload) {
233+
$filter_applied = true;
234+
$received_payload = $payload;
235+
$payload['filtered'] = true;
236+
return $payload;
237+
});
238+
239+
$original = ['test' => 'data'];
240+
$result = EventManager::transform('filter_test', $original);
241+
242+
$this->assertTrue($filter_applied);
243+
$this->assertEquals($original, $received_payload);
244+
$this->assertTrue($result['filtered']);
245+
}
246+
247+
public function test_transform_applies_wordpress_filter_after_transformers(): void {
248+
$execution_order = [];
249+
250+
$transformer = function(array $payload) use (&$execution_order): array {
251+
$execution_order[] = 'transformer';
252+
return $payload;
253+
};
254+
255+
EventManager::subscribe_to_transform('filter_order_test', $transformer);
256+
257+
$this->mock_wordpress_filter('wpgraphql_logging_filter_filter_order_test', function($payload) use (&$execution_order) {
258+
$execution_order[] = 'filter';
259+
return $payload;
260+
});
261+
262+
EventManager::transform('filter_order_test', []);
263+
264+
$this->assertEquals(['transformer', 'filter'], $execution_order);
265+
}
266+
267+
public function test_listener_exceptions_are_caught_and_logged(): void {
268+
$good_listener_called = false;
269+
$exception_thrown = false;
270+
271+
$bad_listener = function() use (&$exception_thrown) {
272+
$exception_thrown = true;
273+
throw new \Exception('Test exception');
274+
};
275+
276+
$good_listener = function() use (&$good_listener_called) {
277+
$good_listener_called = true;
278+
};
279+
280+
EventManager::subscribe('exception_test', $bad_listener, 5);
281+
EventManager::subscribe('exception_test', $good_listener, 10);
282+
283+
// Publishing should not throw an exception even if a listener throws
284+
EventManager::publish('exception_test');
285+
286+
$this->assertTrue($exception_thrown, 'Exception should have been thrown by bad listener');
287+
$this->assertTrue($good_listener_called, 'Good listener should still be called after exception');
288+
}
289+
290+
public function test_transformer_exceptions_are_caught_and_logged(): void {
291+
$exception_thrown = false;
292+
293+
$bad_transformer = function(array $payload) use (&$exception_thrown): array {
294+
$exception_thrown = true;
295+
throw new \Exception('Transform exception');
296+
};
297+
298+
EventManager::subscribe_to_transform('transform_exception_test', $bad_transformer);
299+
300+
$original = ['test' => 'data'];
301+
$result = EventManager::transform('transform_exception_test', $original);
302+
303+
$this->assertTrue($exception_thrown, 'Exception should have been thrown by bad transformer');
304+
$this->assertEquals($original, $result, 'Original payload should be returned on exception');
305+
}
306+
307+
public function test_transformer_returning_non_array_is_ignored(): void {
308+
$transformer_called = false;
309+
310+
$bad_transformer = function(array $payload) use (&$transformer_called) {
311+
$transformer_called = true;
312+
return 'not an array';
313+
};
314+
315+
EventManager::subscribe_to_transform('bad_return_test', $bad_transformer);
316+
317+
$original = ['test' => 'data'];
318+
$result = EventManager::transform('bad_return_test', $original);
319+
320+
$this->assertTrue($transformer_called, 'Transformer should have been called');
321+
$this->assertEquals($original, $result, 'Original payload should be returned when transformer returns non-array');
322+
}
323+
324+
/**
325+
* Data provider for event constants.
326+
*/
327+
public function eventConstantsProvider(): array {
328+
return [
329+
[Events::PRE_REQUEST, 'do_graphql_request'],
330+
[Events::BEFORE_GRAPHQL_EXECUTION, 'graphql_before_execute'],
331+
[Events::AFTER_GRAPHQL_EXECUTION, 'graphql_execute'],
332+
[Events::BEFORE_RESPONSE_RETURNED, 'graphql_return_response'],
333+
];
334+
}
335+
336+
/**
337+
* @dataProvider eventConstantsProvider
338+
*/
339+
public function test_works_with_event_constants(string $event_constant, string $expected_value): void {
340+
$this->assertEquals($expected_value, $event_constant);
341+
342+
$listener_called = false;
343+
$listener = function() use (&$listener_called) {
344+
$listener_called = true;
345+
};
346+
347+
EventManager::subscribe($event_constant, $listener);
348+
EventManager::publish($event_constant);
349+
350+
$this->assertTrue($listener_called, "Listener should be called for event: {$event_constant}");
351+
}
352+
353+
/**
354+
* Helper method to mock WordPress do_action function.
355+
*/
356+
private function mock_wordpress_action(string $action_name, callable $callback): void {
357+
add_action($action_name, $callback);
358+
}
359+
360+
/**
361+
* Helper method to mock WordPress apply_filters function.
362+
*/
363+
private function mock_wordpress_filter(string $filter_name, callable $callback): void {
364+
add_filter($filter_name, $callback);
365+
}
366+
}

0 commit comments

Comments
 (0)