@@ -83,6 +83,7 @@ public function test_admin_can_connect_via_oauth_and_use_admin_mcp_server(): voi
8383 $ names = collect ($ tools ->json ('result.tools ' ))->pluck ('name ' )->all ();
8484
8585 $ this ->assertContains ('admin-create-blog-post ' , $ names );
86+ $ this ->assertContains ('admin-update-blog-post ' , $ names );
8687 $ this ->assertContains ('admin-list-signups ' , $ names );
8788 $ this ->assertContains ('admin-list-companies ' , $ names );
8889 $ this ->assertContains ('admin-search-plugins ' , $ names );
@@ -260,4 +261,153 @@ public function test_search_support_tickets_returns_summaries(): void
260261 $ this ->assertGreaterThanOrEqual (1 , $ payload ['count ' ]);
261262 $ this ->assertSame ($ ticket ->mask , $ payload ['tickets ' ][0 ]['mask ' ]);
262263 }
264+
265+ public function test_update_blog_post_patches_title_and_content_on_draft (): void
266+ {
267+ $ article = Article::factory ()->create ([
268+ 'author_id ' => $ this ->admin ->id ,
269+ 'slug ' => 'draft-to-update ' ,
270+ 'title ' => 'Old Title ' ,
271+ 'content ' => 'Old content ' ,
272+ 'excerpt ' => 'Old excerpt ' ,
273+ 'published_at ' => null ,
274+ ]);
275+
276+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
277+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
278+ 'id ' => $ article ->id ,
279+ 'title ' => 'Updated Title ' ,
280+ 'content ' => "# Updated \n\nNew body. " ,
281+ ])->assertOk ();
282+
283+ $ this ->assertFalse ($ response ->json ('result.isError ' ));
284+ $ payload = json_decode ((string ) data_get ($ response ->json (), 'result.content.0.text ' ), true );
285+
286+ $ this ->assertSame ('Updated Title ' , $ payload ['title ' ]);
287+ $ this ->assertSame ("# Updated \n\nNew body. " , $ payload ['content ' ]);
288+ $ this ->assertSame ('Old excerpt ' , $ payload ['excerpt ' ]);
289+ $ this ->assertSame ('draft-to-update ' , $ payload ['slug ' ]);
290+ $ this ->assertFalse ($ payload ['published ' ]);
291+ $ this ->assertNull ($ payload ['published_at ' ]);
292+
293+ $ article ->refresh ();
294+ $ this ->assertSame ('Updated Title ' , $ article ->title );
295+ $ this ->assertSame ("# Updated \n\nNew body. " , $ article ->content );
296+ $ this ->assertNull ($ article ->published_at );
297+ }
298+
299+ public function test_update_blog_post_by_slug_lookup (): void
300+ {
301+ $ article = Article::factory ()->create ([
302+ 'author_id ' => $ this ->admin ->id ,
303+ 'slug ' => 'lookup-by-slug ' ,
304+ 'title ' => 'Before ' ,
305+ 'published_at ' => null ,
306+ ]);
307+
308+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
309+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
310+ 'slug ' => 'lookup-by-slug ' ,
311+ 'excerpt ' => 'Patched excerpt only ' ,
312+ ])->assertOk ();
313+
314+ $ payload = json_decode ((string ) data_get ($ response ->json (), 'result.content.0.text ' ), true );
315+ $ this ->assertSame ('Patched excerpt only ' , $ payload ['excerpt ' ]);
316+ $ this ->assertSame ('Before ' , $ payload ['title ' ]);
317+ $ this ->assertSame ($ article ->id , $ payload ['id ' ]);
318+ }
319+
320+ public function test_update_blog_post_rejects_empty_update (): void
321+ {
322+ $ article = Article::factory ()->create ([
323+ 'author_id ' => $ this ->admin ->id ,
324+ 'published_at ' => null ,
325+ ]);
326+
327+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
328+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
329+ 'id ' => $ article ->id ,
330+ ])->assertOk ();
331+
332+ $ this ->assertTrue ($ response ->json ('result.isError ' ));
333+ $ text = (string ) data_get ($ response ->json (), 'result.content.0.text ' );
334+ $ this ->assertStringContainsString ('Provide at least one field to update ' , $ text );
335+ }
336+
337+ public function test_update_blog_post_not_found (): void
338+ {
339+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
340+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
341+ 'id ' => 999999 ,
342+ 'title ' => 'Nope ' ,
343+ ])->assertOk ();
344+
345+ $ this ->assertTrue ($ response ->json ('result.isError ' ));
346+ $ text = (string ) data_get ($ response ->json (), 'result.content.0.text ' );
347+ $ this ->assertStringContainsString ('Article not found ' , $ text );
348+ }
349+
350+ public function test_update_blog_post_rejects_slug_change_when_published (): void
351+ {
352+ $ article = Article::factory ()->published ()->create ([
353+ 'author_id ' => $ this ->admin ->id ,
354+ 'slug ' => 'published-slug ' ,
355+ ]);
356+
357+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
358+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
359+ 'id ' => $ article ->id ,
360+ 'slug ' => 'new-published-slug ' ,
361+ ])->assertOk ();
362+
363+ $ this ->assertTrue ($ response ->json ('result.isError ' ));
364+ $ text = (string ) data_get ($ response ->json (), 'result.content.0.text ' );
365+ $ this ->assertStringContainsString ('cannot be changed after the article is published ' , $ text );
366+ $ this ->assertSame ('published-slug ' , $ article ->fresh ()->slug );
367+ }
368+
369+ public function test_update_blog_post_rejects_slug_conflict (): void
370+ {
371+ Article::factory ()->create ([
372+ 'author_id ' => $ this ->admin ->id ,
373+ 'slug ' => 'taken-slug ' ,
374+ 'published_at ' => null ,
375+ ]);
376+ $ article = Article::factory ()->create ([
377+ 'author_id ' => $ this ->admin ->id ,
378+ 'slug ' => 'editable-slug ' ,
379+ 'published_at ' => null ,
380+ ]);
381+
382+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
383+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
384+ 'id ' => $ article ->id ,
385+ 'slug ' => 'taken-slug ' ,
386+ ])->assertOk ();
387+
388+ $ this ->assertTrue ($ response ->json ('result.isError ' ));
389+ $ text = (string ) data_get ($ response ->json (), 'result.content.0.text ' );
390+ $ this ->assertStringContainsString ('already taken ' , $ text );
391+ $ this ->assertSame ('editable-slug ' , $ article ->fresh ()->slug );
392+ }
393+
394+ public function test_update_blog_post_can_rename_draft_slug (): void
395+ {
396+ $ article = Article::factory ()->create ([
397+ 'author_id ' => $ this ->admin ->id ,
398+ 'slug ' => 'old-draft-slug ' ,
399+ 'published_at ' => null ,
400+ ]);
401+
402+ $ tokens = $ this ->issueMcpOAuthTokens ($ this ->admin );
403+ $ response = $ this ->callMcpTool ($ tokens ['access_token ' ], 'admin-update-blog-post ' , [
404+ 'id ' => $ article ->id ,
405+ 'slug ' => 'new-draft-slug ' ,
406+ ])->assertOk ();
407+
408+ $ this ->assertFalse ($ response ->json ('result.isError ' ));
409+ $ payload = json_decode ((string ) data_get ($ response ->json (), 'result.content.0.text ' ), true );
410+ $ this ->assertSame ('new-draft-slug ' , $ payload ['slug ' ]);
411+ $ this ->assertSame ('new-draft-slug ' , $ article ->fresh ()->slug );
412+ }
263413}
0 commit comments