From bf22a79551e20ae664ccbc6b94346cfdeca89a98 Mon Sep 17 00:00:00 2001
From: catch <catch@35733.no-reply.drupal.org>
Date: Thu, 11 Apr 2024 09:44:10 +0100
Subject: [PATCH] Issue #3000749 by amateescu, s_leu, dragos-dumi,
 tim.plunkett, jeremylichtman, smithmilner, velocis: Layout builder overrides
 on a single content item not allowed in a workspace

---
 .../config/schema/layout_builder.schema.yml   |   3 +
 .../src/Form/ConfigureBlockFormBase.php       |   2 +
 .../src/Form/ConfigureSectionForm.php         |   2 +
 .../src/Form/DiscardLayoutChangesForm.php     |   3 +
 .../src/Form/LayoutBuilderDisableForm.php     |   3 +
 .../src/Form/LayoutRebuildConfirmFormBase.php |   2 +
 .../layout_builder/src/Form/MoveBlockForm.php |   2 +
 .../src/Form/OverridesEntityForm.php          |   2 +
 .../src/Form/RevertOverridesForm.php          |   3 +
 .../src/Form/WorkspaceSafeFormTrait.php       |  81 ++++++++
 .../src/InlineBlockEntityOperations.php       |  21 +--
 .../src/Plugin/Block/InlineBlock.php          |   2 +
 .../InlineBlockTestBase.php                   |  13 +-
 ...WorkspacesLayoutBuilderIntegrationTest.php | 178 ++++++++++++++++++
 14 files changed, 293 insertions(+), 24 deletions(-)
 create mode 100644 core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php
 create mode 100644 core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php

diff --git a/core/modules/layout_builder/config/schema/layout_builder.schema.yml b/core/modules/layout_builder/config/schema/layout_builder.schema.yml
index 11bfcd736126..9240ee8cb55d 100644
--- a/core/modules/layout_builder/config/schema/layout_builder.schema.yml
+++ b/core/modules/layout_builder/config/schema/layout_builder.schema.yml
@@ -64,6 +64,9 @@ inline_block:
     view_mode:
       type: string
       label: 'View mode'
+    block_id:
+      type: integer
+      label: 'Block ID'
     block_revision_id:
       type: integer
       label: 'Block revision ID'
diff --git a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
index 76f2526d0410..4be13361aff4 100644
--- a/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
+++ b/core/modules/layout_builder/src/Form/ConfigureBlockFormBase.php
@@ -35,6 +35,7 @@ abstract class ConfigureBlockFormBase extends FormBase implements BaseFormIdInte
   use ContextAwarePluginAssignmentTrait;
   use LayoutBuilderContextTrait;
   use LayoutRebuildTrait;
+  use WorkspaceSafeFormTrait;
 
   /**
    * The plugin being configured.
@@ -163,6 +164,7 @@ public function doBuildForm(array $form, FormStateInterface $form_state, Section
     $this->delta = $delta;
     $this->uuid = $component->getUuid();
     $this->block = $component->getPlugin();
+    $this->markWorkspaceSafe($form_state);
 
     $form_state->setTemporaryValue('gathered_contexts', $this->getPopulatedContexts($section_storage));
 
diff --git a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
index 7f31ec571783..42166abc1fbf 100644
--- a/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
+++ b/core/modules/layout_builder/src/Form/ConfigureSectionForm.php
@@ -32,6 +32,7 @@ class ConfigureSectionForm extends FormBase {
   use LayoutBuilderContextTrait;
   use LayoutBuilderHighlightTrait;
   use LayoutRebuildTrait;
+  use WorkspaceSafeFormTrait;
 
   /**
    * The layout tempstore repository.
@@ -127,6 +128,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     $this->delta = $delta;
     $this->isUpdate = is_null($plugin_id);
     $this->pluginId = $plugin_id;
+    $this->markWorkspaceSafe($form_state);
 
     $section = $this->getCurrentSection();
 
diff --git a/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php b/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php
index 5e4f7c250310..2befa97d3b0a 100644
--- a/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php
+++ b/core/modules/layout_builder/src/Form/DiscardLayoutChangesForm.php
@@ -17,6 +17,8 @@
  */
 class DiscardLayoutChangesForm extends ConfirmFormBase {
 
+  use WorkspaceSafeFormTrait;
+
   /**
    * The layout tempstore repository.
    *
@@ -87,6 +89,7 @@ public function getCancelUrl() {
    */
   public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
     $this->sectionStorage = $section_storage;
+    $this->markWorkspaceSafe($form_state);
     // Mark this as an administrative page for JavaScript ("Back to site" link).
     $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE;
     return parent::buildForm($form, $form_state);
diff --git a/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php b/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php
index 1b30ca932cb7..2f7173fb30a7 100644
--- a/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php
+++ b/core/modules/layout_builder/src/Form/LayoutBuilderDisableForm.php
@@ -18,6 +18,8 @@
  */
 class LayoutBuilderDisableForm extends ConfirmFormBase {
 
+  use WorkspaceSafeFormTrait;
+
   /**
    * The layout tempstore repository.
    *
@@ -92,6 +94,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     }
 
     $this->sectionStorage = $section_storage;
+    $this->markWorkspaceSafe($form_state);
     // Mark this as an administrative page for JavaScript ("Back to site" link).
     $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE;
     return parent::buildForm($form, $form_state);
diff --git a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
index 75eba575b752..8e7cbf4b450d 100644
--- a/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
+++ b/core/modules/layout_builder/src/Form/LayoutRebuildConfirmFormBase.php
@@ -22,6 +22,7 @@ abstract class LayoutRebuildConfirmFormBase extends ConfirmFormBase {
   use AjaxFormHelperTrait;
   use LayoutBuilderHighlightTrait;
   use LayoutRebuildTrait;
+  use WorkspaceSafeFormTrait;
 
   /**
    * The layout tempstore repository.
@@ -77,6 +78,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     $this->sectionStorage = $section_storage;
     $this->delta = $delta;
 
+    $this->markWorkspaceSafe($form_state);
     $form = parent::buildForm($form, $form_state);
 
     if ($this->isAjax()) {
diff --git a/core/modules/layout_builder/src/Form/MoveBlockForm.php b/core/modules/layout_builder/src/Form/MoveBlockForm.php
index beb3aa975725..574f2c5d0d73 100644
--- a/core/modules/layout_builder/src/Form/MoveBlockForm.php
+++ b/core/modules/layout_builder/src/Form/MoveBlockForm.php
@@ -24,6 +24,7 @@ class MoveBlockForm extends FormBase {
   use LayoutBuilderContextTrait;
   use LayoutBuilderHighlightTrait;
   use LayoutRebuildTrait;
+  use WorkspaceSafeFormTrait;
 
   /**
    * The section storage.
@@ -117,6 +118,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     $this->delta = $delta;
     $this->uuid = $uuid;
     $this->region = $region;
+    $this->markWorkspaceSafe($form_state);
 
     $form['#attributes']['data-layout-builder-target-highlight-id'] = $this->blockUpdateHighlightId($uuid);
 
diff --git a/core/modules/layout_builder/src/Form/OverridesEntityForm.php b/core/modules/layout_builder/src/Form/OverridesEntityForm.php
index 87f647e31a4e..77743a3c585d 100644
--- a/core/modules/layout_builder/src/Form/OverridesEntityForm.php
+++ b/core/modules/layout_builder/src/Form/OverridesEntityForm.php
@@ -25,6 +25,7 @@ class OverridesEntityForm extends ContentEntityForm {
 
   use PreviewToggleTrait;
   use LayoutBuilderEntityFormTrait;
+  use WorkspaceSafeFormTrait;
 
   /**
    * Layout tempstore repository.
@@ -90,6 +91,7 @@ protected function init(FormStateInterface $form_state) {
    */
   public function buildForm(array $form, FormStateInterface $form_state, SectionStorageInterface $section_storage = NULL) {
     $this->sectionStorage = $section_storage;
+    $this->markWorkspaceSafe($form_state);
     $form = parent::buildForm($form, $form_state);
     $form['#attributes']['class'][] = 'layout-builder-form';
 
diff --git a/core/modules/layout_builder/src/Form/RevertOverridesForm.php b/core/modules/layout_builder/src/Form/RevertOverridesForm.php
index c852504f5c9c..9375904e0e62 100644
--- a/core/modules/layout_builder/src/Form/RevertOverridesForm.php
+++ b/core/modules/layout_builder/src/Form/RevertOverridesForm.php
@@ -18,6 +18,8 @@
  */
 class RevertOverridesForm extends ConfirmFormBase {
 
+  use WorkspaceSafeFormTrait;
+
   /**
    * The layout tempstore repository.
    *
@@ -99,6 +101,7 @@ public function buildForm(array $form, FormStateInterface $form_state, SectionSt
     }
 
     $this->sectionStorage = $section_storage;
+    $this->markWorkspaceSafe($form_state);
     // Mark this as an administrative page for JavaScript ("Back to site" link).
     $form['#attached']['drupalSettings']['path']['currentPathIsAdmin'] = TRUE;
     return parent::buildForm($form, $form_state);
diff --git a/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php b/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php
new file mode 100644
index 000000000000..f93986b99c8f
--- /dev/null
+++ b/core/modules/layout_builder/src/Form/WorkspaceSafeFormTrait.php
@@ -0,0 +1,81 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\layout_builder\Form;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\layout_builder\SectionStorageInterface;
+use Drupal\workspaces\WorkspaceInformationInterface;
+
+/**
+ * Provides a trait that marks Layout Builder forms as workspace-safe.
+ */
+trait WorkspaceSafeFormTrait {
+
+  /**
+   * The workspace information service.
+   */
+  protected ?WorkspaceInformationInterface $workspaceInfo = NULL;
+
+  /**
+   * Marks a form as workspace-safe, if possible.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state object.
+   */
+  protected function markWorkspaceSafe(FormStateInterface $form_state): void {
+    if (!\Drupal::hasService('workspaces.information')) {
+      return;
+    }
+
+    $section_storage = $this->sectionStorage ?: $this->getSectionStorageFromFormState($form_state);
+    if ($section_storage) {
+      $context_definitions = $section_storage->getContextDefinitions();
+      if (!empty($context_definitions['entity'])) {
+        /** @var \Drupal\Core\Entity\EntityInterface $entity */
+        $entity = $section_storage->getContext('entity')->getContextValue();
+        $supported = $entity && $this->getWorkspaceInfo()->isEntitySupported($entity);
+        $ignored = $entity && $this->getWorkspaceInfo()->isEntityIgnored($entity);
+
+        if ($supported || $ignored) {
+          $form_state->set('workspace_safe', TRUE);
+        }
+      }
+    }
+  }
+
+  /**
+   * Retrieves the section storage from a form state object, if it exists.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state object.
+   *
+   * @return \Drupal\layout_builder\SectionStorageInterface|null
+   *   The section storage or NULL if it doesn't exist.
+   */
+  protected function getSectionStorageFromFormState(FormStateInterface $form_state): ?SectionStorageInterface {
+    foreach ($form_state->getBuildInfo()['args'] as $argument) {
+      if ($argument instanceof SectionStorageInterface) {
+        return $argument;
+      }
+    }
+
+    return NULL;
+  }
+
+  /**
+   * Retrieves the workspace information service.
+   *
+   * @return \Drupal\workspaces\WorkspaceInformationInterface
+   *   The workspace information service.
+   */
+  protected function getWorkspaceInfo(): WorkspaceInformationInterface {
+    if (!$this->workspaceInfo) {
+      $this->workspaceInfo = \Drupal::service('workspaces.information');
+    }
+
+    return $this->workspaceInfo;
+  }
+
+}
diff --git a/core/modules/layout_builder/src/InlineBlockEntityOperations.php b/core/modules/layout_builder/src/InlineBlockEntityOperations.php
index 0007b9b3baab..25717b33e6ed 100644
--- a/core/modules/layout_builder/src/InlineBlockEntityOperations.php
+++ b/core/modules/layout_builder/src/InlineBlockEntityOperations.php
@@ -7,7 +7,6 @@
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Entity\RevisionableInterface;
 use Drupal\Core\Entity\SynchronizableInterface;
-use Drupal\layout_builder\Plugin\Block\InlineBlock;
 use Drupal\layout_builder\SectionStorage\SectionStorageManagerInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 
@@ -171,24 +170,6 @@ public function handlePreSave(EntityInterface $entity) {
     $this->removeUnusedForEntityOnSave($entity);
   }
 
-  /**
-   * Gets a block ID for an inline block plugin.
-   *
-   * @param \Drupal\layout_builder\Plugin\Block\InlineBlock $block_plugin
-   *   The inline block plugin.
-   *
-   * @return int
-   *   The block content ID or null none available.
-   */
-  protected function getPluginBlockId(InlineBlock $block_plugin) {
-    $configuration = $block_plugin->getConfiguration();
-    if (!empty($configuration['block_revision_id'])) {
-      $revision_ids = $this->getBlockIdsForRevisionIds([$configuration['block_revision_id']]);
-      return array_pop($revision_ids);
-    }
-    return NULL;
-  }
-
   /**
    * Delete the inline blocks and the usage records.
    *
@@ -252,7 +233,7 @@ protected function saveInlineBlockComponent(EntityInterface $entity, SectionComp
     $plugin->saveBlockContent($new_revision, $duplicate_blocks);
     $post_save_configuration = $plugin->getConfiguration();
     if ($duplicate_blocks || (empty($pre_save_configuration['block_revision_id']) && !empty($post_save_configuration['block_revision_id']))) {
-      $this->usage->addUsage($this->getPluginBlockId($plugin), $entity);
+      $this->usage->addUsage($post_save_configuration['block_id'], $entity);
     }
     $component->setConfiguration($post_save_configuration);
   }
diff --git a/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php b/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php
index a13bb8392d32..cfd853f6e9a6 100644
--- a/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php
+++ b/core/modules/layout_builder/src/Plugin/Block/InlineBlock.php
@@ -115,6 +115,7 @@ public static function create(ContainerInterface $container, array $configuratio
   public function defaultConfiguration() {
     return [
       'view_mode' => 'full',
+      'block_id' => NULL,
       'block_revision_id' => NULL,
       'block_serialized' => NULL,
     ];
@@ -289,6 +290,7 @@ public function saveBlockContent($new_revision = FALSE, $duplicate_block = FALSE
         $block->setNewRevision();
       }
       $block->save();
+      $this->configuration['block_id'] = $block->id();
       $this->configuration['block_revision_id'] = $block->getRevisionId();
       $this->configuration['block_serialized'] = NULL;
     }
diff --git a/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTestBase.php b/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTestBase.php
index 9aff647e639f..c51a5896882c 100644
--- a/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTestBase.php
+++ b/core/modules/layout_builder/tests/src/FunctionalJavascript/InlineBlockTestBase.php
@@ -112,18 +112,23 @@ protected function getLatestBlockEntityId() {
   /**
    * Removes an entity block from the layout but does not save the layout.
    */
-  protected function removeInlineBlockFromLayout() {
+  protected function removeInlineBlockFromLayout($selector = NULL) {
+    $selector = $selector ?? static::INLINE_BLOCK_LOCATOR;
     $assert_session = $this->assertSession();
     $page = $this->getSession()->getPage();
-    $block_text = $page->find('css', static::INLINE_BLOCK_LOCATOR)->getText();
+    $block_text = $page->find('css', $selector)->getText();
     $this->assertNotEmpty($block_text);
     $assert_session->pageTextContains($block_text);
-    $this->clickContextualLink(static::INLINE_BLOCK_LOCATOR, 'Remove block');
+    $this->clickContextualLink($selector, 'Remove block');
     $assert_session->waitForElement('css', "#drupal-off-canvas input[value='Remove']");
     $assert_session->assertWaitOnAjaxRequest();
+
+    // Output the new HTML.
+    $this->htmlOutput($page->getHtml());
+
     $page->find('css', '#drupal-off-canvas')->pressButton('Remove');
     $assert_session->assertNoElementAfterWait('css', '#drupal-off-canvas');
-    $assert_session->assertNoElementAfterWait('css', static::INLINE_BLOCK_LOCATOR);
+    $assert_session->assertNoElementAfterWait('css', $selector);
     $assert_session->assertWaitOnAjaxRequest();
     $assert_session->pageTextNotContains($block_text);
   }
diff --git a/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php b/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php
new file mode 100644
index 000000000000..b4ed65d0961c
--- /dev/null
+++ b/core/modules/workspaces/tests/src/FunctionalJavascript/WorkspacesLayoutBuilderIntegrationTest.php
@@ -0,0 +1,178 @@
+<?php
+
+declare(strict_types=1);
+
+namespace Drupal\Tests\workspaces\FunctionalJavascript;
+
+use Drupal\Tests\layout_builder\FunctionalJavascript\InlineBlockTestBase;
+use Drupal\Tests\system\Traits\OffCanvasTestTrait;
+use Drupal\Tests\workspaces\Functional\WorkspaceTestUtilities;
+use Drupal\workspaces\Entity\Workspace;
+
+/**
+ * Tests for layout editing in workspaces.
+ *
+ * @group layout_builder
+ * @group workspaces
+ * @group #slow
+ */
+class WorkspacesLayoutBuilderIntegrationTest extends InlineBlockTestBase {
+
+  use OffCanvasTestTrait;
+  use WorkspaceTestUtilities;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected $defaultTheme = 'starterkit_theme';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $modules = [
+    'field_ui',
+    'workspaces',
+  ];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUp(): void {
+    parent::setUp();
+    $this->drupalLogin($this->drupalCreateUser([
+      'access contextual links',
+      'configure any layout',
+      'administer node display',
+      'administer node fields',
+      'create and edit custom blocks',
+      'administer blocks',
+      'administer content types',
+      'administer workspaces',
+      'view any workspace',
+      'administer site configuration',
+      'administer nodes',
+      'bypass node access',
+    ]));
+    $this->setupWorkspaceSwitcherBlock();
+
+    // Enable layout builder.
+    $this->drupalGet(static::FIELD_UI_PREFIX . '/display/default');
+    $this->submitForm([
+      'layout[enabled]' => TRUE,
+      'layout[allow_custom]' => TRUE,
+    ], 'Save');
+    $this->clickLink('Manage layout');
+    $this->assertSession()->addressEquals(static::FIELD_UI_PREFIX . '/display/default/layout');
+    // Add a basic block with the body field set.
+    $this->addInlineBlockToLayout('Block title', 'The DEFAULT block body');
+    $this->assertSaveLayout();
+  }
+
+  /**
+   * Tests changing a layout/blocks inside a workspace.
+   */
+  public function testBlocksInWorkspaces(): void {
+    $assert_session = $this->assertSession();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains('The DEFAULT block body');
+    $this->drupalGet('node/2');
+    $assert_session->pageTextContains('The DEFAULT block body');
+
+    $stage = Workspace::load('stage');
+    $this->switchToWorkspace($stage);
+
+    // Confirm the block can be edited.
+    $this->drupalGet('node/1/layout');
+    $new_block_body = 'The NEW block body';
+    $this->configureInlineBlock('The DEFAULT block body', $new_block_body);
+    $this->assertSaveLayout();
+
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains($new_block_body);
+    $assert_session->pageTextNotContains('The DEFAULT block body');
+    $this->drupalGet('node/2');
+    // Node 2 should use default layout.
+    $assert_session->pageTextContains('The DEFAULT block body');
+    $assert_session->pageTextNotContains($new_block_body);
+
+    // Switch back to the live workspace and verify that the changes are not
+    // visible there.
+    $this->switchToLive();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextNotContains($new_block_body);
+    $assert_session->pageTextContains('The DEFAULT block body');
+
+    $this->switchToWorkspace($stage);
+    // Add a basic block with the body field set.
+    $this->drupalGet('node/1/layout');
+    $second_block_body = 'The 2nd block body';
+    $this->addInlineBlockToLayout('2nd Block title', $second_block_body);
+    $this->assertSaveLayout();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains($second_block_body);
+    $this->drupalGet('node/2');
+    // Node 2 should use default layout.
+    $assert_session->pageTextContains('The DEFAULT block body');
+    $assert_session->pageTextNotContains($new_block_body);
+    $assert_session->pageTextNotContains($second_block_body);
+
+    // Switch back to the live workspace and verify that the new added block is
+    // not visible there.
+    $this->switchToLive();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextNotContains($second_block_body);
+    $assert_session->pageTextContains('The DEFAULT block body');
+
+    $stage->publish();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextNotContains('The DEFAULT block body');
+    $assert_session->pageTextContains($new_block_body);
+    $assert_session->pageTextContains($second_block_body);
+  }
+
+  /**
+   * Tests that blocks can be deleted inside workspaces.
+   */
+  public function testBlockDeletionInWorkspaces(): void {
+    $assert_session = $this->assertSession();
+
+    $stage = Workspace::load('stage');
+    $this->switchToWorkspace($stage);
+
+    $this->drupalGet('node/1/layout');
+    $workspace_block_content = 'The WORKSPACE block body';
+    $this->addInlineBlockToLayout('Workspace block title', $workspace_block_content);
+    $this->assertSaveLayout();
+
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains('The DEFAULT block body');
+    $assert_session->pageTextContains($workspace_block_content);
+
+    $this->switchToLive();
+    $assert_session->pageTextNotContains($workspace_block_content);
+
+    $this->switchToWorkspace($stage);
+    $this->drupalGet('node/1/layout');
+    $this->removeInlineBlockFromLayout(static::INLINE_BLOCK_LOCATOR . ' ~ ' . static::INLINE_BLOCK_LOCATOR);
+    $this->assertSaveLayout();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains('The DEFAULT block body');
+    $assert_session->pageTextNotContains($workspace_block_content);
+
+    $this->drupalGet('node/1/layout');
+    $this->removeInlineBlockFromLayout();
+    $this->assertSaveLayout();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextNotContains('The DEFAULT block body');
+    $assert_session->pageTextNotContains($workspace_block_content);
+
+    $this->switchToLive();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextContains('The DEFAULT block body');
+    $stage->publish();
+    $this->drupalGet('node/1');
+    $assert_session->pageTextNotContains('The DEFAULT block body');
+    $assert_session->pageTextNotContains($workspace_block_content);
+  }
+
+}
-- 
GitLab