fix: failed library and layout saves name the revision screen (audit L3)

A failed save of a library entry or Theme Builder layout now carries
restore_url when a revision exists; a partial write's hint points to the
WordPress revision screen and lit-divi-outline instead of
lit/revisions-list and lit/revision-restore, which answer not found for
these types. Pages keep the default hint.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01At3V6SjwbMe6eMzVGW3Hs7
This commit is contained in:
2026-09-27 23:25:16 +02:00
co-authored by Claude Opus 5.5
parent 9c3f7d356f
commit 771f3794a0
3 changed files with 84 additions and 1 deletions
@@ -438,6 +438,40 @@ final class GlobalEditsTest extends TestCase
self::assertCount(1, $this->log->partials);
}
/**
* Audit L3 on the failure path (re-review): lit/revision-restore answers not found for library entries, so a
* failed save names the WordPress revision screen instead.
*/
public function testAFailedSaveNamesTheRevisionScreenNotRevisionRestore(): void
{
LibraryFixtures::given([LibraryFixtures::item(1059)]);
$this->log = FakeChangeLog::partialsOnly();
$cause = new \RuntimeException('hook');
foreach (
[
WriteFailed::partial(DiviSaver::REASON, $cause, postId: 1059, revisionId: 811),
WriteFailed::rolledBack(DiviSaver::REASON, $cause, postId: 1059, revisionId: 811),
] as $failure
) {
$this->failure = $failure;
try {
(new DiviUpdateAbility($this->writer()))->execute(self::relabel(1059, true));
self::fail('WriteFailed expected');
} catch (WriteFailed $e) {
$error = $e->toError();
}
$data = $error->get_error_data();
self::assertSame('https://kunde.test/wp-admin/revision.php?revision=811', $data['restore_url']);
self::assertStringNotContainsString('lit/revision-restore', $data['hint']);
self::assertStringNotContainsString('lit/revisions-list', $data['hint']);
if (! $failure->rolledBack) {
self::assertStringContainsString('restore_url', $data['hint']);
self::assertStringContainsString('Revision 811', $data['hint']);
}
}
}
/** Ruling P14 (M-2): one page is "Seite". */
public function testDeleteNoticeUsesTheSingularForOnePage(): void
{
@@ -155,6 +155,23 @@ final class DiviWriterThemeBuilderTest extends TestCase
self::assertSame([], $this->saved);
}
/** Audit L3 on the failure path: a failed layout save names the WordPress revision screen. */
public function testAFailedSaveNamesTheRevisionScreen(): void
{
$this->failures = [WriteFailed::rolledBack(DiviSaver::REASON, new \RuntimeException('hook'), postId: 1062, revisionId: 811)];
$ability = new DiviInsertAbility($this->writer([ThemeBuilderFixtures::template()]));
try {
$ability->execute($this->insert($this->body, []));
self::fail('WriteFailed expected');
} catch (WriteFailed $e) {
$error = $e->toError();
}
self::assertSame('https://kunde.test/wp-admin/revision.php?revision=811', $error->get_error_data()['restore_url']);
self::assertStringNotContainsString('lit/revision-restore', $error->get_error_data()['hint']);
}
/** Without a ThemeBuilderEdits (no Theme Builder wiring) a layout is never written. */
public function testWithoutThemeBuilderEditsLayoutsAreNotWritten(): void
{