@@ -179,13 +179,31 @@ public function test_one_time_email_sends_successfully(): void {
179179 // Note: SMTP mailer uses PHPMailer directly, not wp_mail.
180180 // The mock PHPMailer in bootstrap.php returns true from send().
181181
182- // Mock subscriber lookup (get_by_email returns null - subscriber doesn't exist).
182+ // Mock all get_row calls:
183+ // 1. replace_one_time_placeholders() checks if recipient is subscriber → null (not found)
184+ // 2. subscriber_service->get_by_email() in get_or_create() → null (not found)
185+ // 3. subscriber_service->get_by_id() after creating subscriber → subscriber object
186+ $ call_count = 0 ;
187+ $ subscriber_insert_id = 100 ;
183188 $ wpdb ->shouldReceive ( 'get_row ' )
184- ->once ()
185- ->andReturn ( null );
189+ ->andReturnUsing ( function () use ( &$ call_count , $ subscriber_insert_id ) {
190+ ++$ call_count ;
191+ // First two calls return null (subscriber not found).
192+ if ( $ call_count <= 2 ) {
193+ return null ;
194+ }
195+ // Third call returns the newly created subscriber.
196+ return (object ) array (
197+ 'id ' => $ subscriber_insert_id ,
198+ 'email ' => 'user@example.com ' ,
199+ 'first_name ' => 'Test User ' ,
200+ 'last_name ' => '' ,
201+ 'status ' => 'active ' ,
202+ 'unsubscribe_token ' => 'test_token_123 ' ,
203+ );
204+ } );
186205
187- // Mock subscriber creation (insert into subscribers table).
188- $ subscriber_insert_id = 100 ;
206+ // Mock subscriber creation (insert into subscribers table by get_or_create).
189207 $ wpdb ->shouldReceive ( 'insert ' )
190208 ->once ()
191209 ->with (
@@ -198,18 +216,6 @@ public function test_one_time_email_sends_successfully(): void {
198216 return 1 ;
199217 } );
200218
201- // Mock get_by_id after creation.
202- $ wpdb ->shouldReceive ( 'get_row ' )
203- ->once ()
204- ->andReturn ( (object ) array (
205- 'id ' => $ subscriber_insert_id ,
206- 'email ' => 'user@example.com ' ,
207- 'first_name ' => 'Test User ' ,
208- 'last_name ' => '' ,
209- 'status ' => 'active ' ,
210- 'unsubscribe_token ' => 'test_token_123 ' ,
211- ) );
212-
213219 // Expect database inserts: campaigns table, then queue table.
214220 $ wpdb ->shouldReceive ( 'insert ' )
215221 ->once ()
@@ -295,13 +301,30 @@ public function test_one_time_email_logs_failure(): void {
295301 return $ default ;
296302 });
297303
298- // Mock subscriber lookup (get_by_email returns null - subscriber doesn't exist).
304+ // Mock subscriber lookup for placeholder replacement (recipient is NOT a subscriber).
305+ // This is called by replace_one_time_placeholders() in Admin_Email.
306+ // Then subscriber_service->get_or_create() also does lookups.
307+ $ call_count = 0 ;
308+ $ subscriber_insert_id = 100 ;
299309 $ wpdb ->shouldReceive ( 'get_row ' )
300- ->once ()
301- ->andReturn ( null );
310+ ->andReturnUsing ( function () use ( &$ call_count , $ subscriber_insert_id ) {
311+ ++$ call_count ;
312+ // First two calls return null (subscriber not found).
313+ if ( $ call_count <= 2 ) {
314+ return null ;
315+ }
316+ // Third call returns the newly created subscriber.
317+ return (object ) array (
318+ 'id ' => $ subscriber_insert_id ,
319+ 'email ' => 'user@example.com ' ,
320+ 'first_name ' => 'Test User ' ,
321+ 'last_name ' => '' ,
322+ 'status ' => 'active ' ,
323+ 'unsubscribe_token ' => 'test_token_123 ' ,
324+ );
325+ } );
302326
303- // Mock subscriber creation (insert into subscribers table).
304- $ subscriber_insert_id = 100 ;
327+ // Mock subscriber creation (insert into subscribers table by get_or_create).
305328 $ wpdb ->shouldReceive ( 'insert ' )
306329 ->once ()
307330 ->with (
@@ -314,18 +337,6 @@ public function test_one_time_email_logs_failure(): void {
314337 return 1 ;
315338 } );
316339
317- // Mock get_by_id after creation.
318- $ wpdb ->shouldReceive ( 'get_row ' )
319- ->once ()
320- ->andReturn ( (object ) array (
321- 'id ' => $ subscriber_insert_id ,
322- 'email ' => 'user@example.com ' ,
323- 'first_name ' => 'Test User ' ,
324- 'last_name ' => '' ,
325- 'status ' => 'active ' ,
326- 'unsubscribe_token ' => 'test_token_123 ' ,
327- ) );
328-
329340 // Expect database insert for campaigns table.
330341 $ wpdb ->shouldReceive ( 'insert ' )
331342 ->once ()
@@ -409,13 +420,31 @@ public function test_placeholder_replacement_in_one_time_email(): void {
409420 $ sent_subject = '' ;
410421 $ sent_body = '' ;
411422
412- // Mock subscriber lookup (get_by_email returns null - subscriber doesn't exist).
423+ // Mock all get_row calls:
424+ // 1. replace_one_time_placeholders() checks if recipient is subscriber → null (not found)
425+ // 2. subscriber_service->get_by_email() in get_or_create() → null (not found)
426+ // 3. subscriber_service->get_by_id() after creating subscriber → subscriber object
427+ $ call_count = 0 ;
428+ $ subscriber_insert_id = 100 ;
413429 $ wpdb ->shouldReceive ( 'get_row ' )
414- ->once ()
415- ->andReturn ( null );
430+ ->andReturnUsing ( function () use ( &$ call_count , $ subscriber_insert_id ) {
431+ ++$ call_count ;
432+ // First two calls return null (subscriber not found).
433+ if ( $ call_count <= 2 ) {
434+ return null ;
435+ }
436+ // Third call returns the newly created subscriber.
437+ return (object ) array (
438+ 'id ' => $ subscriber_insert_id ,
439+ 'email ' => 'john@example.com ' ,
440+ 'first_name ' => 'John Doe ' ,
441+ 'last_name ' => '' ,
442+ 'status ' => 'active ' ,
443+ 'unsubscribe_token ' => 'test_token_123 ' ,
444+ );
445+ } );
416446
417- // Mock subscriber creation (insert into subscribers table).
418- $ subscriber_insert_id = 100 ;
447+ // Mock subscriber creation (insert into subscribers table by get_or_create).
419448 $ wpdb ->shouldReceive ( 'insert ' )
420449 ->once ()
421450 ->with (
@@ -428,18 +457,6 @@ public function test_placeholder_replacement_in_one_time_email(): void {
428457 return 1 ;
429458 } );
430459
431- // Mock get_by_id after creation.
432- $ wpdb ->shouldReceive ( 'get_row ' )
433- ->once ()
434- ->andReturn ( (object ) array (
435- 'id ' => $ subscriber_insert_id ,
436- 'email ' => 'john@example.com ' ,
437- 'first_name ' => 'John Doe ' ,
438- 'last_name ' => '' ,
439- 'status ' => 'active ' ,
440- 'unsubscribe_token ' => 'test_token_123 ' ,
441- ) );
442-
443460 // First insert is to campaigns table.
444461 $ wpdb ->shouldReceive ( 'insert ' )
445462 ->once ()
0 commit comments