diff --git a/core/modules/comment/src/Plugin/views/field/EntityLink.php b/core/modules/comment/src/Plugin/views/field/EntityLink.php
index 9760057103..e51385876d 100644
--- a/core/modules/comment/src/Plugin/views/field/EntityLink.php
+++ b/core/modules/comment/src/Plugin/views/field/EntityLink.php
@@ -73,10 +73,12 @@ public function preRender(&$values) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    $entity = $this->getEntity($values);
-
     // Only render the links, if they are defined.
-    return !empty($this->build[$entity->id()]['links']['comment__comment']) ? \Drupal::service('renderer')->render($this->build[$entity->id()]['links']['comment__comment']) : '';
+    if ($entity = $this->getEntity($values)) {
+      return !empty($this->build[$entity->id()]['links']['comment__comment']) ? \Drupal::service('renderer')->render($this->build[$entity->id()]['links']['comment__comment']) : '';
+    }
+
+    return '';
   }
 
 }
diff --git a/core/modules/comment/src/Plugin/views/field/LinkApprove.php b/core/modules/comment/src/Plugin/views/field/LinkApprove.php
index 683c3cbb4c..0cd4734ee8 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkApprove.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkApprove.php
@@ -19,7 +19,9 @@ class LinkApprove extends LinkBase {
    * {@inheritdoc}
    */
   protected function getUrlInfo(ResultRow $row) {
-    return Url::fromRoute('comment.approve', ['comment' => $this->getEntity($row)->id()]);
+    if ($entity = $this->getEntity($row)) {
+      return Url::fromRoute('comment.approve', ['comment' => $entity->id()]);
+    }
   }
 
   /**
diff --git a/core/modules/comment/src/Plugin/views/field/LinkReply.php b/core/modules/comment/src/Plugin/views/field/LinkReply.php
index 3ddbd08152..5ab91cb9ee 100644
--- a/core/modules/comment/src/Plugin/views/field/LinkReply.php
+++ b/core/modules/comment/src/Plugin/views/field/LinkReply.php
@@ -20,13 +20,14 @@ class LinkReply extends LinkBase {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\comment\CommentInterface $comment */
-    $comment = $this->getEntity($row);
-    return Url::fromRoute('comment.reply', [
-      'entity_type' => $comment->getCommentedEntityTypeId(),
-      'entity' => $comment->getCommentedEntityId(),
-      'field_name' => $comment->getFieldName(),
-      'pid' => $comment->id(),
-    ]);
+    if ($comment = $this->getEntity($row)) {
+      return Url::fromRoute('comment.reply', [
+        'entity_type' => $comment->getCommentedEntityTypeId(),
+        'entity' => $comment->getCommentedEntityId(),
+        'field_name' => $comment->getFieldName(),
+        'pid' => $comment->id(),
+      ]);
+    }
   }
 
   /**
diff --git a/core/modules/comment/tests/src/Unit/Plugin/views/field/EntityLinkTest.php b/core/modules/comment/tests/src/Unit/Plugin/views/field/EntityLinkTest.php
new file mode 100644
index 0000000000..d0f3ec5417
--- /dev/null
+++ b/core/modules/comment/tests/src/Unit/Plugin/views/field/EntityLinkTest.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Drupal\Tests\comment\Unit\Plugin\views\field;
+
+use Drupal\comment\Plugin\views\field\EntityLink;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+
+/**
+ * @coversDefaultClass \Drupal\comment\Plugin\views\field\EntityLink
+ * @group comment
+ */
+class EntityLinkTest extends UnitTestCase {
+
+  /**
+   * Test the render method.
+   *
+   * @covers ::render
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $field = new EntityLink([], '', []);
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkApproveTest.php b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkApproveTest.php
new file mode 100644
index 0000000000..c5787fa838
--- /dev/null
+++ b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkApproveTest.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Drupal\Tests\comment\Unit\Plugin\views\field;
+
+use Drupal;
+use Drupal\comment\Plugin\views\field\LinkApprove;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\comment\Plugin\views\field\LinkApprove
+ * @group comment
+ */
+class LinkApproveTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    Drupal::setContainer($container);
+    $field = new LinkApprove([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkReplyTest.php b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkReplyTest.php
new file mode 100644
index 0000000000..76dfd0f503
--- /dev/null
+++ b/core/modules/comment/tests/src/Unit/Plugin/views/field/LinkReplyTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\comment\Unit\Plugin\views\field;
+
+use Drupal\comment\Plugin\views\field\LinkReply;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\comment\Plugin\views\field\LinkReply
+ * @group comment
+ */
+class LinkReplyTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new LinkReply([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/contact/src/Plugin/views/field/ContactLink.php b/core/modules/contact/src/Plugin/views/field/ContactLink.php
index a98be137dd..b2f9e66c10 100644
--- a/core/modules/contact/src/Plugin/views/field/ContactLink.php
+++ b/core/modules/contact/src/Plugin/views/field/ContactLink.php
@@ -30,14 +30,18 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   protected function getUrlInfo(ResultRow $row) {
-    return Url::fromRoute('entity.user.contact_form', ['user' => $this->getEntity($row)->id()]);
+    if ($entity = $this->getEntity($row)) {
+      return Url::fromRoute('entity.user.contact_form', ['user' => $entity->id()]);
+    }
   }
 
   /**
    * {@inheritdoc}
    */
   protected function renderLink(ResultRow $row) {
-    $entity = $this->getEntity($row);
+    if (!$entity = $this->getEntity($row)) {
+      return '';
+    }
 
     $this->options['alter']['make_link'] = TRUE;
     $this->options['alter']['url'] = $this->getUrlInfo($row);
diff --git a/core/modules/contact/tests/src/Unit/ContactLinkTest.php b/core/modules/contact/tests/src/Unit/ContactLinkTest.php
new file mode 100644
index 0000000000..511720ae12
--- /dev/null
+++ b/core/modules/contact/tests/src/Unit/ContactLinkTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\contact\Unit;
+
+use Drupal\contact\Plugin\views\field\ContactLink;
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\contact\Plugin\views\field\ContactLink
+ * @group contact
+ */
+class ContactLinkTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new ContactLink([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/media_library/media_library.module b/core/modules/media_library/media_library.module
index 84c0f67732..aa15d9e44d 100644
--- a/core/modules/media_library/media_library.module
+++ b/core/modules/media_library/media_library.module
@@ -271,7 +271,10 @@ function media_library_form_views_form_media_library_page_alter(array &$form, Fo
     $view = $form['output'][0]['#view'];
     foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
       if (isset($view->result[$key])) {
-        $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
+        if (!$media = $view->field['media_bulk_form']->getEntity($view->result[$key])) {
+          $form['media_bulk_form'][$key]['#title'] = '';
+          continue;
+        }
         $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
           '@label' => $media->label(),
         ]);
diff --git a/core/modules/media_library/media_library.module.orig b/core/modules/media_library/media_library.module.orig
new file mode 100644
index 0000000000..84c0f67732
--- /dev/null
+++ b/core/modules/media_library/media_library.module.orig
@@ -0,0 +1,540 @@
+<?php
+
+/**
+ * @file
+ * Contains hook implementations for the media_library module.
+ */
+
+use Drupal\Component\Utility\UrlHelper;
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Entity\EntityInterface;
+use Drupal\Core\Entity\Entity\EntityFormDisplay;
+use Drupal\Core\Entity\Entity\EntityViewDisplay;
+use Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Render\Element;
+use Drupal\Core\Routing\RouteMatchInterface;
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Template\Attribute;
+use Drupal\Core\Url;
+use Drupal\image\Entity\ImageStyle;
+use Drupal\image\Plugin\Field\FieldType\ImageItem;
+use Drupal\media\MediaTypeForm;
+use Drupal\media\MediaTypeInterface;
+use Drupal\media_library\Form\FileUploadForm;
+use Drupal\media_library\Form\OEmbedForm;
+use Drupal\media_library\MediaLibraryState;
+use Drupal\views\Plugin\views\cache\CachePluginBase;
+use Drupal\views\ViewExecutable;
+use Drupal\Core\StringTranslation\TranslatableMarkup;
+use Drupal\Component\Serialization\Json;
+
+/**
+ * Implements hook_help().
+ *
+ * @todo Update in https://www.drupal.org/project/drupal/issues/2964789
+ */
+function media_library_help($route_name, RouteMatchInterface $route_match) {
+  switch ($route_name) {
+    case 'help.page.media_library':
+      $output = '<h3>' . t('About') . '</h3>';
+      $output .= '<p>' . t('The Media Library module provides a rich, visual interface for managing media, and allows media to be reused in entity reference fields or embedded into text content. It overrides the <a href=":media-collection">media administration page</a>, allowing users to toggle between the existing table-style interface and a new grid-style interface for browsing and performing administrative operations on media.', [
+        ':media-collection' => Url::fromRoute('entity.media.collection')->toString(),
+      ]) . '</p>';
+      $output .= '<p>' . t('To learn more about media management, begin by reviewing the <a href=":media-help">documentation for the Media module</a>. For more information about the media library and related functionality, see the <a href=":media-library-handbook">online documentation for the Media Library module</a>.', [
+        ':media-help' => Url::fromRoute('help.page', ['name' => 'media'])->toString(),
+        ':media-library-handbook' => 'https://www.drupal.org/docs/8/core/modules/media-library-module',
+      ]) . '</p>';
+      $output .= '<h3>' . t('Selection dialog') . '</h3>';
+      $output .= '<p>' . t('When selecting media for an entity reference field or a text editor, Media Library opens a modal dialog to help users easily find and select media. The modal dialog can toggle between a grid-style and table-style interface, and new media items can be uploaded directly into it.') . '</p>';
+      $output .= '<p>' . t('Within the dialog, media items are divided up by type. If more than one media type can be selected by the user, the available types will be displayed as a set of vertical tabs. To users who have appropriate permissions, each media type may also present a short form allowing you to upload or create new media items of that type.') . '</p>';
+      $output .= '<h3>' . t('Uses') . '</h3>';
+      $output .= '<dl>';
+      $output .= '<dt>' . t('Grid-style vs. table-style interface') . '</dt>';
+      $output .= '<dd>' . t('The Media Library module provides a new grid-style interface for the media administration page that displays media as thumbnails, with minimal textual information, allowing users to visually browse media in their site. The existing table-style interface is better suited to displaying additional information about media items, in addition to being more accessible to users with assistive technology.') . '</dd>';
+      $output .= '<dt>' . t('Reusing media in entity reference fields') . '</dt>';
+      $output .= '<dd>' . t('Any entity reference field that references media can use the media library. To enable, configure the form display for the field to use the "Media library" widget.') . '</dd>';
+      $output .= '<dt>' . t('Embedding media in text content') . '</dt>';
+      $output .= '<dd>' . t('To use the media library within CKEditor, you must add the "Insert from Media Library" button to the CKEditor toolbar, and enable the "Embed media" filter in the text format associated with the text editor.') . '</dd>';
+      $output .= '</dl>';
+      $output .= '<h3>' . t('Customize') . '</h3>';
+      $output .= '<ul>';
+      $output .= '<li>';
+      if (\Drupal::moduleHandler()->moduleExists('views_ui') && \Drupal::currentUser()->hasPermission('administer views')) {
+        $output .= t('Both the table-style and grid-style interfaces are regular views and can be customized via the <a href=":views-ui">Views UI</a>, including sorting and filtering. This is the case for both the administration page and the modal dialog.', [
+          ':views_ui' => Url::fromRoute('entity.view.collection')->toString(),
+        ]);
+      }
+      else {
+        $output .= t('Both the table-style and grid-style interfaces are regular views and can be customized via the Views UI, including sorting and filtering. This is the case for both the administration page and the modal dialog.');
+      }
+      $output .= '</li>';
+      $output .= '<li>' . t('Both the table-style and grid-style interfaces are regular views and can be customized via the Views UI, including sorting and filtering. This is the case for both the administration page and the modal dialog.') . '</li>';
+      $output .= '<li>' . t('In the grid-style interface, the fields that are displayed (including which image style is used for images) can be customized by configuring the "Media library" view mode for each of your <a href=":media-types">media types</a>. The thumbnail images in the grid-style interface can be customized by configuring the "Media Library thumbnail (220×220)" image style.', [
+        ':media-types' => Url::fromRoute('entity.media_type.collection')->toString(),
+      ]) . '</li>';
+      $output .= '<li>' . t('When adding new media items within the modal dialog, the fields that are displayed can be customized by configuring the "Media library" form mode for each of your <a href=":media-types">media types</a>.', [
+        ':media-types' => Url::fromRoute('entity.media_type.collection')->toString(),
+      ]) . '</li>';
+      $output .= '</ul>';
+      return $output;
+  }
+}
+
+/**
+ * Implements hook_media_source_info_alter().
+ */
+function media_library_media_source_info_alter(array &$sources) {
+  $sources['audio_file']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['file']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['image']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['video_file']['forms']['media_library_add'] = FileUploadForm::class;
+  $sources['oembed:video']['forms']['media_library_add'] = OEmbedForm::class;
+}
+
+/**
+ * Implements hook_theme().
+ */
+function media_library_theme() {
+  return [
+    'media__media_library' => [
+      'base hook' => 'media',
+    ],
+    'media_library_wrapper' => [
+      'render element' => 'element',
+    ],
+    'media_library_item' => [
+      'render element' => 'element',
+    ],
+  ];
+}
+
+/**
+ * Prepares variables for the media library modal dialog.
+ *
+ * Default template: media-library-wrapper.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties of the element.
+ *     Properties used: #menu, #content.
+ */
+function template_preprocess_media_library_wrapper(array &$variables) {
+  $variables['menu'] = &$variables['element']['menu'];
+  $variables['content'] = &$variables['element']['content'];
+}
+
+/**
+ * Prepares variables for a selected media item.
+ *
+ * Default template: media-library-item.html.twig.
+ *
+ * @param array $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties and children of
+ *     the element.
+ */
+function template_preprocess_media_library_item(array &$variables) {
+  $element = &$variables['element'];
+  foreach (Element::children($element) as $key) {
+    $variables['content'][$key] = $element[$key];
+  }
+}
+
+/**
+ * Implements hook_views_pre_render().
+ */
+function media_library_views_pre_render(ViewExecutable $view) {
+  $add_classes = function (&$option, array $classes_to_add) {
+    $classes = $option ? preg_split('/\s+/', trim($option)) : [];
+    $classes = array_filter($classes);
+    $classes = array_merge($classes, $classes_to_add);
+    $option = implode(' ', array_unique($classes));
+  };
+
+  if ($view->id() === 'media_library') {
+    if ($view->current_display === 'page') {
+      $add_classes($view->style_plugin->options['row_class'], ['js-media-library-item', 'js-click-to-select']);
+
+      if (array_key_exists('media_bulk_form', $view->field)) {
+        $add_classes($view->field['media_bulk_form']->options['element_class'], ['js-click-to-select-checkbox']);
+      }
+    }
+    elseif (strpos($view->current_display, 'widget') === 0) {
+      if (array_key_exists('media_library_select_form', $view->field)) {
+        $add_classes($view->field['media_library_select_form']->options['element_wrapper_class'], ['js-click-to-select-checkbox']);
+      }
+      $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']);
+    }
+
+    $add_classes($view->style_plugin->options['row_class'], ['js-media-library-item', 'js-click-to-select']);
+
+    if ($view->display_handler->options['defaults']['css_class']) {
+      $add_classes($view->displayHandlers->get('default')->options['css_class'], ['js-media-library-view']);
+    }
+    else {
+      $add_classes($view->display_handler->options['css_class'], ['js-media-library-view']);
+    }
+  }
+}
+
+/**
+ * Implements hook_views_post_render().
+ */
+function media_library_views_post_render(ViewExecutable $view, &$output, CachePluginBase $cache) {
+  if ($view->id() === 'media_library') {
+    $output['#attached']['library'][] = 'media_library/view';
+    if (strpos($view->current_display, 'widget') === 0) {
+      try {
+        $query = MediaLibraryState::fromRequest($view->getRequest())->all();
+      }
+      catch (InvalidArgumentException $e) {
+        // MediaLibraryState::fromRequest() will throw an exception if the view
+        // is being previewed, since not all required query parameters will be
+        // present. In a preview, however, this can be omitted since we're
+        // merely previewing.
+        // @todo Use the views API for checking for the preview mode when it
+        //   lands. https://www.drupal.org/project/drupal/issues/3060855
+        if (empty($view->preview) && empty($view->live_preview)) {
+          throw $e;
+        }
+      }
+
+      // If the current query contains any parameters we use to contextually
+      // filter the view, ensure they persist across AJAX rebuilds.
+      // The ajax_path is shared for all AJAX views on the page, but our query
+      // parameters are prefixed and should not interfere with any other views.
+      // @todo Rework or remove this in https://www.drupal.org/node/2983451
+      if (!empty($query)) {
+        $ajax_path = &$output['#attached']['drupalSettings']['views']['ajax_path'];
+        $parsed_url = UrlHelper::parse($ajax_path);
+        $query = array_merge($query, $parsed_url['query']);
+        $ajax_path = $parsed_url['path'] . '?' . UrlHelper::buildQuery($query);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_preprocess_media().
+ */
+function media_library_preprocess_media(&$variables) {
+  if ($variables['view_mode'] === 'media_library') {
+    /** @var \Drupal\media\MediaInterface $media */
+    $media = $variables['media'];
+    $variables['#cache']['contexts'][] = 'user.permissions';
+    $rel = $media->access('edit') ? 'edit-form' : 'canonical';
+    $variables['url'] = $media->toUrl($rel, [
+      'language' => $media->language(),
+    ]);
+    $variables += [
+      'preview_attributes' => new Attribute(),
+      'metadata_attributes' => new Attribute(),
+    ];
+    $variables['status'] = $media->isPublished();
+  }
+}
+
+/**
+ * Implements hook_preprocess_views_view() for the 'media_library' view.
+ */
+function media_library_preprocess_views_view__media_library(array &$variables) {
+  $variables['attributes']['data-view-display-id'] = $variables['view']->current_display;
+}
+
+/**
+ * Implements hook_preprocess_views_view_fields().
+ */
+function media_library_preprocess_views_view_fields(&$variables) {
+  // Add classes to media rendered entity field so it can be targeted for
+  // JavaScript mouseover and click events.
+  if ($variables['view']->id() === 'media_library' && isset($variables['fields']['rendered_entity'])) {
+    if (isset($variables['fields']['rendered_entity']->wrapper_attributes)) {
+      $variables['fields']['rendered_entity']->wrapper_attributes->addClass('js-click-to-select-trigger');
+    }
+  }
+}
+
+/**
+ * Alter the bulk form to add a more accessible label.
+ *
+ * @param array $form
+ *   An associative array containing the structure of the form.
+ * @param \Drupal\Core\Form\FormStateInterface $form_state
+ *   The current state of the form.
+ *
+ * @todo Remove in https://www.drupal.org/node/2983454
+ */
+function media_library_form_views_form_media_library_page_alter(array &$form, FormStateInterface $form_state) {
+  if (isset($form['media_bulk_form']) && isset($form['output'])) {
+    /** @var \Drupal\views\ViewExecutable $view */
+    $view = $form['output'][0]['#view'];
+    foreach (Element::getVisibleChildren($form['media_bulk_form']) as $key) {
+      if (isset($view->result[$key])) {
+        $media = $view->field['media_bulk_form']->getEntity($view->result[$key]);
+        $form['media_bulk_form'][$key]['#title'] = t('Select @label', [
+          '@label' => $media->label(),
+        ]);
+      }
+    }
+  }
+}
+
+/**
+ * Implements hook_form_alter().
+ */
+function media_library_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
+  // Add a process callback to ensure that the media library view's exposed
+  // filters submit button is not moved to the modal dialog's button area.
+  if ($form_id === 'views_exposed_form' && strpos($form['#id'], 'views-exposed-form-media-library-widget') === 0) {
+    $form['#after_build'][] = '_media_library_views_form_media_library_after_build';
+  }
+
+  // Configures media_library displays when a type is submitted.
+  if ($form_state->getFormObject() instanceof MediaTypeForm) {
+    $form['actions']['submit']['#submit'][] = '_media_library_media_type_form_submit';
+  }
+}
+
+/**
+ * Form #after_build callback for media_library view's exposed filters form.
+ */
+function _media_library_views_form_media_library_after_build(array $form, FormStateInterface $form_state) {
+  // Remove .form-actions from the view's exposed filter actions. This prevents
+  // the "Apply filters" submit button from being moved into the dialog's
+  // button area.
+  // @see \Drupal\Core\Render\Element\Actions::processActions
+  // @see Drupal.behaviors.dialog.prepareDialogButtons
+  // @todo Remove this after
+  //   https://www.drupal.org/project/drupal/issues/3089751 is fixed.
+  if (($key = array_search('form-actions', $form['actions']['#attributes']['class'])) !== FALSE) {
+    unset($form['actions']['#attributes']['class'][$key]);
+  }
+  return $form;
+}
+
+/**
+ * Submit callback for media type form.
+ */
+function _media_library_media_type_form_submit(array &$form, FormStateInterface $form_state) {
+  $form_object = $form_state->getFormObject();
+  if ($form_object->getOperation() === 'add') {
+    $type = $form_object->getEntity();
+    $form_display_created = _media_library_configure_form_display($type);
+    $view_display_created = _media_library_configure_view_display($type);
+    if ($form_display_created || $view_display_created) {
+      \Drupal::messenger()->addStatus(t('Media Library form and view displays have been created for the %type media type.', [
+        '%type' => $type->label(),
+      ]));
+    }
+  }
+}
+
+/**
+ * Implements hook_field_ui_preconfigured_options_alter().
+ */
+function media_library_field_ui_preconfigured_options_alter(array &$options, $field_type) {
+  // If the field is not an "entity_reference"-based field, bail out.
+  $class = \Drupal::service('plugin.manager.field.field_type')->getPluginClass($field_type);
+  if (!is_a($class, EntityReferenceItem::class, TRUE)) {
+    return;
+  }
+
+  // Set the default field widget for media to be the Media library.
+  if (!empty($options['media'])) {
+    $options['media']['entity_form_display']['type'] = 'media_library_widget';
+  }
+}
+
+/**
+ * Implements hook_local_tasks_alter().
+ *
+ * Removes tasks for the Media library if the view display no longer exists.
+ */
+function media_library_local_tasks_alter(&$local_tasks) {
+  /** @var \Symfony\Component\Routing\RouteCollection $route_collection */
+  $route_collection = \Drupal::service('router')->getRouteCollection();
+  foreach (['media_library.grid', 'media_library.table'] as $key) {
+    if (isset($local_tasks[$key]) && !$route_collection->get($local_tasks[$key]['route_name'])) {
+      unset($local_tasks[$key]);
+    }
+  }
+}
+
+/**
+ * Implements hook_ENTITY_TYPE_access().
+ */
+function media_library_image_style_access(EntityInterface $entity, $operation, AccountInterface $account) {
+  // Prevent the fallback 'media_library' image style from being deleted.
+  // @todo: Lock the image style instead of preventing delete access.
+  //   https://www.drupal.org/project/drupal/issues/2247293
+  if ($operation === 'delete' && $entity->id() === 'media_library') {
+    return AccessResult::forbidden();
+  }
+}
+
+/**
+ * Ensures that the given media type has a media_library form display.
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ *   The media type to configure.
+ *
+ * @return bool
+ *   Whether a form display has been created or not.
+ *
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+function _media_library_configure_form_display(MediaTypeInterface $type) {
+  $display = EntityFormDisplay::load('media.' . $type->id() . '.media_library');
+
+  if ($display) {
+    return FALSE;
+  }
+
+  $values = [
+    'targetEntityType' => 'media',
+    'bundle' => $type->id(),
+    'mode' => 'media_library',
+    'status' => TRUE,
+  ];
+  $display = EntityFormDisplay::create($values);
+  // Remove all default components.
+  foreach (array_keys($display->getComponents()) as $name) {
+    $display->removeComponent($name);
+  }
+  // Expose the name field when it is not mapped.
+  $field_map = $type->getFieldMap();
+  if (empty($field_map['name'])) {
+    $display->setComponent('name', [
+      'type' => 'string_textfield',
+      'settings' => [
+        'size' => 60,
+      ],
+    ]);
+  }
+  // If the source field is an image field, expose it so that users can set alt
+  // and title text.
+  $source_field = $type->getSource()->getSourceFieldDefinition($type);
+  if ($source_field->isDisplayConfigurable('form') && is_a($source_field->getItemDefinition()->getClass(), ImageItem::class, TRUE)) {
+    $type->getSource()->prepareFormDisplay($type, $display);
+  }
+  return (bool) $display->save();
+}
+
+/**
+ * Ensures that the given media type has a media_library view display.
+ *
+ * @param \Drupal\media\MediaTypeInterface $type
+ *   The media type to configure.
+ *
+ * @return bool
+ *   Whether a view display has been created or not.
+ *
+ * @throws \Drupal\Core\Entity\EntityStorageException
+ */
+function _media_library_configure_view_display(MediaTypeInterface $type) {
+  $display = EntityViewDisplay::load('media.' . $type->id() . '.media_library');
+
+  if ($display) {
+    return FALSE;
+  }
+
+  $values = [
+    'targetEntityType' => 'media',
+    'bundle' => $type->id(),
+    'mode' => 'media_library',
+    'status' => TRUE,
+  ];
+  $display = EntityViewDisplay::create($values);
+  // Remove all default components.
+  foreach (array_keys($display->getComponents()) as $name) {
+    $display->removeComponent($name);
+  }
+
+  // @todo: Remove dependency on 'medium' and 'thumbnail' image styles from
+  //   media and media library modules.
+  //   https://www.drupal.org/project/drupal/issues/3030437
+  $image_style = ImageStyle::load('medium');
+
+  // Expose the thumbnail component. If the medium image style doesn't exist,
+  // use the fallback 'media_library' image style.
+  $display->setComponent('thumbnail', [
+    'type' => 'image',
+    'label' => 'hidden',
+    'settings' => [
+      'image_style' => $image_style ? $image_style->id() : 'media_library',
+      'image_link' => '',
+    ],
+  ]);
+  return (bool) $display->save();
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function media_library_form_filter_format_edit_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
+  // Add an additional validate callback so so we can ensure the media_embed
+  // filter is enabled when the DrupalMediaLibrary button is enabled.
+  $form['#validate'][] = 'media_library_filter_format_edit_form_validate';
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function media_library_form_filter_format_add_form_alter(array &$form, FormStateInterface $form_state, $form_id) {
+  // Add an additional validate callback so so we can ensure the media_embed
+  // filter is enabled when the DrupalMediaLibrary button is enabled.
+  $form['#validate'][] = 'media_library_filter_format_edit_form_validate';
+}
+
+/**
+ * Validate callback to ensure the DrupalMediaLibrary button can work correctly.
+ */
+function media_library_filter_format_edit_form_validate($form, FormStateInterface $form_state) {
+  if ($form_state->getTriggeringElement()['#name'] !== 'op') {
+    return;
+  }
+
+  // The "DrupalMediaLibrary" button is for the CKEditor text editor.
+  if ($form_state->getValue(['editor', 'editor']) !== 'ckeditor') {
+    return;
+  }
+
+  $button_group_path = [
+    'editor',
+    'settings',
+    'toolbar',
+    'button_groups',
+  ];
+
+  if ($button_groups = $form_state->getValue($button_group_path)) {
+    $buttons = [];
+    $button_groups = Json::decode($button_groups);
+
+    foreach ($button_groups as $button_row) {
+      foreach ($button_row as $button_group) {
+        $buttons = array_merge($buttons, array_values($button_group['items']));
+      }
+    }
+
+    $get_filter_label = function ($filter_plugin_id) use ($form) {
+      return (string) $form['filters']['order'][$filter_plugin_id]['filter']['#markup'];
+    };
+
+    if (in_array('DrupalMediaLibrary', $buttons, TRUE)) {
+      $media_embed_enabled = $form_state->getValue([
+        'filters',
+        'media_embed',
+        'status',
+      ]);
+
+      if (!$media_embed_enabled) {
+        $error_message = new TranslatableMarkup('The %media-embed-filter-label filter must be enabled to use the %drupal-media-library-button button.', [
+          '%media-embed-filter-label' => $get_filter_label('media_embed'),
+          '%drupal-media-library-button' => new TranslatableMarkup('Insert from Media Library'),
+        ]);
+        $form_state->setErrorByName('filters', $error_message);
+      }
+    }
+  }
+}
diff --git a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php
index 2d0702bd4d..f107d174f1 100644
--- a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php
+++ b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php
@@ -55,7 +55,10 @@ public function viewsForm(array &$form, FormStateInterface $form_state) {
     // Render checkboxes for all rows.
     $form[$this->options['id']]['#tree'] = TRUE;
     foreach ($this->view->result as $row_index => $row) {
-      $entity = $this->getEntity($row);
+      if (!$entity = $this->getEntity($row)) {
+        $form[$this->options['id']][$row_index] = [];
+        continue;
+      }
       $form[$this->options['id']][$row_index] = [
         '#type' => 'checkbox',
         '#title' => $this->t('Select @label', [
diff --git a/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php.orig b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php.orig
new file mode 100644
index 0000000000..2d0702bd4d
--- /dev/null
+++ b/core/modules/media_library/src/Plugin/views/field/MediaLibrarySelectForm.php.orig
@@ -0,0 +1,153 @@
+<?php
+
+namespace Drupal\media_library\Plugin\views\field;
+
+use Drupal\Core\Ajax\CloseDialogCommand;
+use Drupal\Core\Form\FormBuilderInterface;
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\Url;
+use Drupal\media_library\MediaLibraryState;
+use Drupal\views\Plugin\views\field\FieldPluginBase;
+use Drupal\views\Render\ViewsRenderPipelineMarkup;
+use Drupal\views\ResultRow;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * Defines a field that outputs a checkbox and form for selecting media.
+ *
+ * @ViewsField("media_library_select_form")
+ *
+ * @internal
+ *   Plugin classes are internal.
+ */
+class MediaLibrarySelectForm extends FieldPluginBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public function getValue(ResultRow $row, $field = NULL) {
+    return '<!--form-item-' . $this->options['id'] . '--' . $row->index . '-->';
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function render(ResultRow $values) {
+    return ViewsRenderPipelineMarkup::create($this->getValue($values));
+  }
+
+  /**
+   * Form constructor for the media library select form.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   */
+  public function viewsForm(array &$form, FormStateInterface $form_state) {
+    $form['#attributes']['class'] = ['js-media-library-views-form'];
+
+    // Add an attribute that identifies the media type displayed in the form.
+    if (isset($this->view->args[0])) {
+      $form['#attributes']['data-drupal-media-type'] = $this->view->args[0];
+    }
+
+    // Render checkboxes for all rows.
+    $form[$this->options['id']]['#tree'] = TRUE;
+    foreach ($this->view->result as $row_index => $row) {
+      $entity = $this->getEntity($row);
+      $form[$this->options['id']][$row_index] = [
+        '#type' => 'checkbox',
+        '#title' => $this->t('Select @label', [
+          '@label' => $entity->label(),
+        ]),
+        '#title_display' => 'invisible',
+        '#return_value' => $entity->id(),
+      ];
+    }
+
+    // The selection is persistent across different pages in the media library
+    // and populated via JavaScript.
+    $selection_field_id = $this->options['id'] . '_selection';
+    $form[$selection_field_id] = [
+      '#type' => 'hidden',
+      '#attributes' => [
+        // This is used to identify the hidden field in the form via JavaScript.
+        'id' => 'media-library-modal-selection',
+      ],
+    ];
+
+    // @todo Remove in https://www.drupal.org/project/drupal/issues/2504115
+    // Currently the default URL for all AJAX form elements is the current URL,
+    // not the form action. This causes bugs when this form is rendered from an
+    // AJAX path like /views/ajax, which cannot process AJAX form submits.
+    $query = $this->view->getRequest()->query->all();
+    $query[FormBuilderInterface::AJAX_FORM_REQUEST] = TRUE;
+    $query['views_display_id'] = $this->view->getDisplay()->display['id'];
+    $form['actions']['submit']['#ajax'] = [
+      'url' => Url::fromRoute('media_library.ui'),
+      'options' => [
+        'query' => $query,
+      ],
+      'callback' => [static::class, 'updateWidget'],
+    ];
+
+    $form['actions']['submit']['#value'] = $this->t('Insert selected');
+    $form['actions']['submit']['#button_type'] = 'primary';
+    $form['actions']['submit']['#field_id'] = $selection_field_id;
+    // By default, the AJAX system tries to move the focus back to the element
+    // that triggered the AJAX request. Since the media library is closed after
+    // clicking the select button, the focus can't be moved back. We need to set
+    // the 'data-disable-refocus' attribute to prevent the AJAX system from
+    // moving focus to a random element. The select button triggers an update in
+    // the opener, and the opener should be responsible for moving the focus. An
+    // example of this can be seen in MediaLibraryWidget::updateWidget().
+    // @see \Drupal\media_library\Plugin\Field\FieldWidget\MediaLibraryWidget::updateWidget()
+    $form['actions']['submit']['#attributes']['data-disable-refocus'] = 'true';
+  }
+
+  /**
+   * Submit handler for the media library select form.
+   *
+   * @param array $form
+   *   An associative array containing the structure of the form.
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The current state of the form.
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The current request.
+   *
+   * @return \Drupal\Core\Ajax\AjaxResponse
+   *   A command to send the selection to the current field widget.
+   */
+  public static function updateWidget(array &$form, FormStateInterface $form_state, Request $request) {
+    $field_id = $form_state->getTriggeringElement()['#field_id'];
+    $selected_ids = $form_state->getValue($field_id);
+    $selected_ids = $selected_ids ? array_filter(explode(',', $selected_ids)) : [];
+
+    // Allow the opener service to handle the selection.
+    $state = MediaLibraryState::fromRequest($request);
+
+    return \Drupal::service('media_library.opener_resolver')
+      ->get($state)
+      ->getSelectionResponse($state, $selected_ids)
+      ->addCommand(new CloseDialogCommand());
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function viewsFormValidate(array &$form, FormStateInterface $form_state) {
+    $selected = array_filter($form_state->getValue($this->options['id']));
+    if (empty($selected)) {
+      $form_state->setErrorByName('', $this->t('No items selected.'));
+    }
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clickSortable() {
+    return FALSE;
+  }
+
+}
diff --git a/core/modules/media_library/tests/src/Unit/MediaLibrarySelectFormTest.php b/core/modules/media_library/tests/src/Unit/MediaLibrarySelectFormTest.php
new file mode 100644
index 0000000000..45ee094482
--- /dev/null
+++ b/core/modules/media_library/tests/src/Unit/MediaLibrarySelectFormTest.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Drupal\Tests\media_library\Unit;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\media_library\Plugin\views\field\MediaLibrarySelectForm;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+use Symfony\Component\HttpFoundation\ParameterBag;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * @coversDefaultClass \Drupal\media_library\Plugin\views\field\MediaLibrarySelectForm
+ * @group media_library
+ */
+class MediaLibrarySelectFormTest extends UnitTestCase {
+
+  /**
+   * Tests the viewsForm method.
+   *
+   * @covers ::viewsForm
+   */
+  public function testViewsForm() {
+    $row = new ResultRow();
+    $field = new MediaLibrarySelectForm([], '', []);
+
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+
+    $query = $this->getMockBuilder(ParameterBag::class)
+      ->setMethods(['all'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $query->expects($this->any())
+      ->method('all')
+      ->willReturn([]);
+
+    $request = $this->getMockBuilder(Request::class)
+      ->disableOriginalConstructor()
+      ->getMock();
+    $request->query = $query;
+
+    $view = $this->getMockBuilder(ViewExecutable::class)
+      ->setMethods(['getRequest', 'initStyle'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $view->expects($this->any())
+      ->method('getRequest')
+      ->willReturn($request);
+    $view->expects($this->any())
+      ->method('initStyle')
+      ->willReturn(TRUE);
+
+    $display_manager = $this->getMockBuilder('\Drupal\views\Plugin\ViewsPluginManager')
+      ->disableOriginalConstructor()
+      ->getMock();
+    $container->set('plugin.manager.views.display', $display_manager);
+    \Drupal::setContainer($container);
+
+    $display = $this->createMock(DisplayPluginBase::class);
+    $form_state = $this->createMock(FormStateInterface::class);
+    $view->result = [$row];
+    $field->init($view, $display);
+    $form = [];
+    $field->viewsForm($form, $form_state);
+    $this->assertNotEmpty($form);
+  }
+
+}
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLink.php b/core/modules/node/src/Plugin/views/field/RevisionLink.php
index 949ad6e07c..0a87d3cd3f 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLink.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLink.php
@@ -20,11 +20,15 @@ class RevisionLink extends LinkBase {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->getEntity($row);
-    // Current revision uses the node view path.
-    return !$node->isDefaultRevision() ?
-      Url::fromRoute('entity.node.revision', ['node' => $node->id(), 'node_revision' => $node->getRevisionId()]) :
-      $node->toUrl();
+    if ($node = $this->getEntity($row)) {
+      // Current revision uses the node view path.
+      return !$node->isDefaultRevision() ?
+        Url::fromRoute('entity.node.revision', [
+          'node' => $node->id(),
+          'node_revision' => $node->getRevisionId(),
+        ]) :
+        $node->toUrl();
+    }
   }
 
   /**
@@ -33,7 +37,7 @@ protected function getUrlInfo(ResultRow $row) {
   protected function renderLink(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
     $node = $this->getEntity($row);
-    if (!$node->getRevisionid()) {
+    if (!$node || !$node->getRevisionid()) {
       return '';
     }
     $text = parent::renderLink($row);
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php b/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
index 2e1f683b52..301658ad9f 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLinkDelete.php
@@ -19,8 +19,12 @@ class RevisionLinkDelete extends RevisionLink {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->getEntity($row);
-    return Url::fromRoute('node.revision_delete_confirm', ['node' => $node->id(), 'node_revision' => $node->getRevisionId()]);
+    if ($node = $this->getEntity($row)) {
+      return Url::fromRoute('node.revision_delete_confirm', [
+        'node' => $node->id(),
+        'node_revision' => $node->getRevisionId(),
+      ]);
+    }
   }
 
   /**
diff --git a/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php b/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
index 33b20b8885..2fb7fdd2aa 100644
--- a/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
+++ b/core/modules/node/src/Plugin/views/field/RevisionLinkRevert.php
@@ -19,8 +19,12 @@ class RevisionLinkRevert extends RevisionLink {
    */
   protected function getUrlInfo(ResultRow $row) {
     /** @var \Drupal\node\NodeInterface $node */
-    $node = $this->getEntity($row);
-    return Url::fromRoute('node.revision_revert_confirm', ['node' => $node->id(), 'node_revision' => $node->getRevisionId()]);
+    if ($node = $this->getEntity($row)) {
+      return Url::fromRoute('node.revision_revert_confirm', [
+        'node' => $node->id(),
+        'node_revision' => $node->getRevisionId(),
+      ]);
+    }
   }
 
   /**
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkDeleteTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkDeleteTest.php
new file mode 100644
index 0000000000..370fc7c6b2
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkDeleteTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\node\Plugin\views\field\RevisionLinkDelete;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\node\Plugin\views\field\RevisionLinkDelete
+ * @group node
+ */
+class RevisionLinkDeleteTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new RevisionLinkDelete([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkRevertTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkRevertTest.php
new file mode 100644
index 0000000000..9b0ee88562
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkRevertTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\node\Plugin\views\field\RevisionLinkDelete;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\node\Plugin\views\field\RevisionLinkRevert
+ * @group node
+ */
+class RevisionLinkRevertTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new RevisionLinkDelete([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkTest.php b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkTest.php
new file mode 100644
index 0000000000..4c0235fa15
--- /dev/null
+++ b/core/modules/node/tests/src/Unit/Plugin/views/field/RevisionLinkTest.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Drupal\Tests\node\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\node\Plugin\views\field\RevisionLink;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\node\Plugin\views\field\RevisionLink
+ * @group node
+ */
+class RevisionLinkTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the render method.
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+    $field = new RevisionLink([], '', [], $this->createMock(AccessManagerInterface::class), $this->createMock(EntityTypeManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(LanguageManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
diff --git a/core/modules/user/src/Plugin/views/field/Permissions.php b/core/modules/user/src/Plugin/views/field/Permissions.php
index 705ba7a589..ff77b3102d 100644
--- a/core/modules/user/src/Plugin/views/field/Permissions.php
+++ b/core/modules/user/src/Plugin/views/field/Permissions.php
@@ -87,7 +87,10 @@ public function preRender(&$values) {
 
     $rids = [];
     foreach ($values as $result) {
-      $user_rids = $this->getEntity($result)->getRoles();
+      if (!$user = $this->getEntity($result)) {
+        continue;
+      }
+      $user_rids = $user->getRoles();
       $uid = $this->getValue($result);
 
       foreach ($user_rids as $rid) {
diff --git a/core/modules/user/tests/src/Unit/Plugin/views/field/PermissionsTest.php b/core/modules/user/tests/src/Unit/Plugin/views/field/PermissionsTest.php
new file mode 100644
index 0000000000..00967204f7
--- /dev/null
+++ b/core/modules/user/tests/src/Unit/Plugin/views/field/PermissionsTest.php
@@ -0,0 +1,49 @@
+<?php
+
+namespace Drupal\Tests\user\Unit\Plugin\views\field;
+
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Extension\ModuleHandlerInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\user\PermissionHandlerInterface;
+use Drupal\user\Plugin\views\field\Permissions;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\user\Plugin\views\field\Permissions
+ * @group user
+ */
+class PermissionsTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the preRender method.
+   *
+   * @covers ::preRender
+   */
+  public function testPreRender() {
+    $values = [new ResultRow()];
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    $container->set('user.permissions', $this->createMock(PermissionHandlerInterface::class));
+    \Drupal::setContainer($container);
+    $field = new Permissions([], '', [], $this->createMock(ModuleHandlerInterface::class), $this->createMock(EntityTypeManagerInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->preRender($values));
+  }
+
+}
diff --git a/core/modules/views/src/Plugin/views/field/BulkForm.php b/core/modules/views/src/Plugin/views/field/BulkForm.php
index 5ee5891d9d..beb5abc773 100644
--- a/core/modules/views/src/Plugin/views/field/BulkForm.php
+++ b/core/modules/views/src/Plugin/views/field/BulkForm.php
@@ -308,7 +308,11 @@ public function viewsForm(&$form, FormStateInterface $form_state) {
       // Render checkboxes for all rows.
       $form[$this->options['id']]['#tree'] = TRUE;
       foreach ($this->view->result as $row_index => $row) {
-        $entity = $this->getEntityTranslation($this->getEntity($row), $row);
+        if (!$entity = $this->getEntity($row)) {
+          $form[$this->options['id']][$row_index] = [];
+          continue;
+        }
+        $entity = $this->getEntityTranslation($entity, $row);
 
         $form[$this->options['id']][$row_index] = [
           '#type' => 'checkbox',
diff --git a/core/modules/views/src/Plugin/views/field/EntityLink.php b/core/modules/views/src/Plugin/views/field/EntityLink.php
index f7b2877a6c..2ae4d032e6 100644
--- a/core/modules/views/src/Plugin/views/field/EntityLink.php
+++ b/core/modules/views/src/Plugin/views/field/EntityLink.php
@@ -26,6 +26,9 @@ public function render(ResultRow $row) {
    */
   protected function renderLink(ResultRow $row) {
     if ($this->options['output_url_as_text']) {
+      if (!$urlInfo = $this->getUrlInfo($row)) {
+        return '';
+      }
       return $this->getUrlInfo($row)->toString();
     }
     return parent::renderLink($row);
@@ -37,6 +40,9 @@ protected function renderLink(ResultRow $row) {
   protected function getUrlInfo(ResultRow $row) {
     $template = $this->getEntityLinkTemplate();
     $entity = $this->getEntity($row);
+    if (!$entity) {
+      return NULL;
+    }
     if ($this->languageManager->isMultilingual()) {
       $entity = $this->getEntityTranslation($entity, $row);
     }
diff --git a/core/modules/views/src/Plugin/views/field/EntityOperations.php b/core/modules/views/src/Plugin/views/field/EntityOperations.php
index 32a30ad1ae..5d5c9abc58 100644
--- a/core/modules/views/src/Plugin/views/field/EntityOperations.php
+++ b/core/modules/views/src/Plugin/views/field/EntityOperations.php
@@ -139,7 +139,10 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    $entity = $this->getEntityTranslation($this->getEntity($values), $values);
+    if (!$entity = $this->getEntity($values)) {
+      return [];
+    }
+    $entity = $this->getEntityTranslation($entity, $values);
     $operations = $this->entityTypeManager->getListBuilder($entity->getEntityTypeId())->getOperations($entity);
     if ($this->options['destination']) {
       foreach ($operations as &$operation) {
diff --git a/core/modules/views/src/Plugin/views/field/LinkBase.php b/core/modules/views/src/Plugin/views/field/LinkBase.php
index 6534482f2d..bce83c2780 100644
--- a/core/modules/views/src/Plugin/views/field/LinkBase.php
+++ b/core/modules/views/src/Plugin/views/field/LinkBase.php
@@ -177,6 +177,9 @@ public function query() {
    */
   public function render(ResultRow $row) {
     $access = $this->checkUrlAccess($row);
+    if ($access === NULL) {
+      return '';
+    }
     $build = ['#markup' => $access->isAllowed() ? $this->renderLink($row) : ''];
     BubbleableMetadata::createFromObject($access)->applyTo($build);
     return $build;
@@ -188,12 +191,13 @@ public function render(ResultRow $row) {
    * @param \Drupal\views\ResultRow $row
    *   A view result row.
    *
-   * @return \Drupal\Core\Access\AccessResultInterface
+   * @return \Drupal\Core\Access\AccessResultInterface|null
    *   The access result.
    */
   protected function checkUrlAccess(ResultRow $row) {
-    $url = $this->getUrlInfo($row);
-    return $this->accessManager->checkNamedRoute($url->getRouteName(), $url->getRouteParameters(), $this->currentUser(), TRUE);
+    if ($url = $this->getUrlInfo($row)) {
+      return $this->accessManager->checkNamedRoute($url->getRouteName(), $url->getRouteParameters(), $this->currentUser(), TRUE);
+    }
   }
 
   /**
@@ -202,7 +206,7 @@ protected function checkUrlAccess(ResultRow $row) {
    * @param \Drupal\views\ResultRow $row
    *   A view result row.
    *
-   * @return \Drupal\Core\Url
+   * @return \Drupal\Core\Url|null
    *   The URI elements of the link.
    */
   abstract protected function getUrlInfo(ResultRow $row);
@@ -218,7 +222,9 @@ protected function checkUrlAccess(ResultRow $row) {
    */
   protected function renderLink(ResultRow $row) {
     $this->options['alter']['make_link'] = TRUE;
-    $this->options['alter']['url'] = $this->getUrlInfo($row);
+    if ($urlInfo = $this->getUrlInfo($row)) {
+      $this->options['alter']['url'] = $this->getUrlInfo($row);
+    }
     $text = !empty($this->options['text']) ? $this->sanitizeValue($this->options['text']) : $this->getDefaultLabel();
     $this->addLangcode($row);
     return $text;
@@ -231,8 +237,7 @@ protected function renderLink(ResultRow $row) {
    *   A view result row.
    */
   protected function addLangcode(ResultRow $row) {
-    $entity = $this->getEntity($row);
-    if ($this->languageManager->isMultilingual()) {
+    if (($entity = $this->getEntity($row)) && $this->languageManager->isMultilingual()) {
       $this->options['alter']['language'] = $this->getEntityTranslation($entity, $row)->language();
     }
   }
diff --git a/core/modules/views/src/Plugin/views/field/RenderedEntity.php b/core/modules/views/src/Plugin/views/field/RenderedEntity.php
index 90e5469eae..98c477547d 100644
--- a/core/modules/views/src/Plugin/views/field/RenderedEntity.php
+++ b/core/modules/views/src/Plugin/views/field/RenderedEntity.php
@@ -146,15 +146,16 @@ public function buildOptionsForm(&$form, FormStateInterface $form_state) {
    * {@inheritdoc}
    */
   public function render(ResultRow $values) {
-    $entity = $this->getEntityTranslation($this->getEntity($values), $values);
+    if (!$entity = $this->getEntity($values)) {
+      return '';
+    }
+    $entity = $this->getEntityTranslation($entity, $values);
     $build = [];
-    if (isset($entity)) {
-      $access = $entity->access('view', NULL, TRUE);
-      $build['#access'] = $access;
-      if ($access->isAllowed()) {
-        $view_builder = $this->entityTypeManager->getViewBuilder($this->getEntityTypeId());
-        $build += $view_builder->view($entity, $this->options['view_mode'], $entity->language()->getId());
-      }
+    $access = $entity->access('view', NULL, TRUE);
+    $build['#access'] = $access;
+    if ($access->isAllowed()) {
+      $view_builder = $this->entityTypeManager->getViewBuilder($this->getEntityTypeId());
+      $build += $view_builder->view($entity, $this->options['view_mode'], $entity->language()->getId());
     }
     return $build;
   }
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/BulkFormTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/BulkFormTest.php
new file mode 100644
index 0000000000..2b8b8dd47a
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/BulkFormTest.php
@@ -0,0 +1,76 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Form\FormStateInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\field\BulkForm;
+use Drupal\views\Plugin\views\query\QueryPluginBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\BulkForm
+ * @group Views
+ */
+class BulkFormTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * Tests the viewsForm method.
+   *
+   * @covers ::viewsForm
+   */
+  public function testViewsForm() {
+    $row = new ResultRow();
+
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    \Drupal::setContainer($container);
+
+    $field = $this->getMockBuilder(BulkForm::class)
+      ->setMethods(['getEntityType', 'getEntity'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $field->expects($this->any())
+      ->method('getEntityType')
+      ->willReturn('foo');
+    $field->expects($this->any())
+      ->method('getEntity')
+      ->willReturn(NULL);
+
+    $query = $this->getMockBuilder(QueryPluginBase::class)
+      ->setMethods(['getEntityTableInfo'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $query->expects($this->any())
+      ->method('getEntityTableInfo')
+      ->willReturn([]);
+    $view = $this->getMockBuilder(ViewExecutable::class)
+      ->setMethods(['getQuery'])
+      ->disableOriginalConstructor()
+      ->getMock();
+    $view->expects($this->any())
+      ->method('getQuery')
+      ->willReturn($query);
+    $view->result = [$row];
+    $view->query = $query;
+    $field->view = $view;
+    $field->options = ['id' => 'bar', 'action_title' => 'zee'];
+    $form_state = $this->createMock(FormStateInterface::class);
+    $form = [];
+    $field->viewsForm($form, $form_state);
+    $this->assertNotEmpty($form, print_r($field->view->result, 1));
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/LinkBaseTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/LinkBaseTest.php
new file mode 100644
index 0000000000..dcbd43486e
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/LinkBaseTest.php
@@ -0,0 +1,73 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Access\AccessManagerInterface;
+use Drupal\Core\Access\AccessResultAllowed;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Core\Render\RendererInterface;
+use Drupal\Core\StringTranslation\TranslationInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\Plugin\views\field\LinkBase;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\EntityLink
+ * @group Views
+ */
+class LinkBaseTest extends UnitTestCase {
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function tearDown() {
+    parent::tearDown();
+    $container = new ContainerBuilder();
+    \Drupal::setContainer($container);
+  }
+
+  /**
+   * @covers ::render
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $container = new ContainerBuilder();
+    $container->set('string_translation', $this->createMock(TranslationInterface::class));
+    $container->set('renderer', $this->createMock(RendererInterface::class));
+    \Drupal::setContainer($container);
+
+    $access = new AccessResultAllowed();
+    $languageManager = $this->createMock(LanguageManagerInterface::class);
+    $languageManager->expects($this->any())
+      ->method('isMultilingual')
+      ->willReturn(TRUE);
+    $field = $this->getMockBuilder(LinkBase::class)
+      ->setConstructorArgs([
+        [],
+        'foo',
+        [],
+        $this->createMock(AccessManagerInterface::class),
+        $this->createMock(EntityTypeManagerInterface::class),
+        $this->createMock(EntityRepositoryInterface::class),
+        $languageManager,
+      ])
+      ->setMethods(['checkUrlAccess', 'getUrlInfo'])
+      ->getMock();
+    $field->expects($this->any())
+      ->method('checkUrlAccess')
+      ->willReturn($access);
+
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+
+    $field->init($view, $display);
+    $field_built = $field->render($row);
+    $this->assertEquals('', \Drupal::service('renderer')->render($field_built));
+  }
+
+}
diff --git a/core/modules/views/tests/src/Unit/Plugin/views/field/RenderedEntityTest.php b/core/modules/views/tests/src/Unit/Plugin/views/field/RenderedEntityTest.php
new file mode 100644
index 0000000000..3943c462d1
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/Plugin/views/field/RenderedEntityTest.php
@@ -0,0 +1,33 @@
+<?php
+
+namespace Drupal\Tests\views\Unit\Plugin\views\field;
+
+use Drupal\Core\Entity\EntityDisplayRepositoryInterface;
+use Drupal\Core\Entity\EntityRepositoryInterface;
+use Drupal\Core\Entity\EntityTypeManagerInterface;
+use Drupal\Core\Language\LanguageManagerInterface;
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Plugin\views\display\DisplayPluginBase;
+use Drupal\views\Plugin\views\field\RenderedEntity;
+use Drupal\views\ResultRow;
+use Drupal\views\ViewExecutable;
+
+/**
+ * @coversDefaultClass \Drupal\views\Plugin\views\field\RenderedEntity
+ * @group Views
+ */
+class RenderedEntityTest extends UnitTestCase {
+
+  /**
+   * @covers ::render
+   */
+  public function testRender() {
+    $row = new ResultRow();
+    $field = new RenderedEntity([], '', [], $this->createMock(EntityTypeManagerInterface::class), $this->createMock(LanguageManagerInterface::class), $this->createMock(EntityRepositoryInterface::class), $this->createMock(EntityDisplayRepositoryInterface::class));
+    $view = $this->createMock(ViewExecutable::class);
+    $display = $this->createMock(DisplayPluginBase::class);
+    $field->init($view, $display);
+    $this->assertEquals('', $field->render($row));
+  }
+
+}
