 src/EntityToJsonApi.php                            |  2 +-
 src/EventSubscriber/ResourceResponseSubscriber.php |  2 +-
 src/Normalizer/EntityNormalizer.php                |  2 +-
 .../JsonApiDocumentTopLevelNormalizer.php          |  4 +-
 src/Normalizer/RelationshipItemNormalizer.php      |  4 +-
 tests/src/Functional/ActionTest.php                | 11 ---
 tests/src/Functional/BaseFieldOverrideTest.php     | 11 ---
 tests/src/Functional/BlockContentTest.php          | 11 +--
 tests/src/Functional/BlockTest.php                 | 12 ----
 tests/src/Functional/CommentTest.php               | 19 +++---
 .../src/Functional/ContentLanguageSettingsTest.php |  7 --
 tests/src/Functional/EditorTest.php                | 12 ----
 tests/src/Functional/EntityFormDisplayTest.php     | 11 ---
 tests/src/Functional/EntityViewDisplayTest.php     | 11 ---
 tests/src/Functional/FieldConfigTest.php           | 11 ---
 tests/src/Functional/FieldStorageConfigTest.php    | 11 ---
 tests/src/Functional/FileTest.php                  | 11 ---
 tests/src/Functional/MenuTest.php                  | 11 ---
 tests/src/Functional/RdfMappingTest.php            | 11 ---
 tests/src/Functional/RestResourceConfigTest.php    | 11 ---
 tests/src/Functional/TermTest.php                  | 20 +++---
 tests/src/Functional/TourTest.php                  | 11 ---
 tests/src/Functional/ViewTest.php                  | 11 ---
 .../JsonApiDocumentTopLevelNormalizerTest.php      | 79 ++++++++++++++++++++--
 24 files changed, 106 insertions(+), 200 deletions(-)

diff --git a/src/EntityToJsonApi.php b/src/EntityToJsonApi.php
index 09f97be..5b28497 100644
--- a/src/EntityToJsonApi.php
+++ b/src/EntityToJsonApi.php
@@ -102,7 +102,7 @@ class EntityToJsonApi {
     $request = Request::create($path, 'GET');
     return [
       'account' => $this->currentUser,
-      'cacheable_metadata' => new CacheableMetadata(),
+      'cacheability' => new CacheableMetadata(),
       'resource_type' => $this->resourceTypeRepository->get(
         $entity->getEntityTypeId(),
         $entity->bundle()
diff --git a/src/EventSubscriber/ResourceResponseSubscriber.php b/src/EventSubscriber/ResourceResponseSubscriber.php
index 8fddd81..923134e 100644
--- a/src/EventSubscriber/ResourceResponseSubscriber.php
+++ b/src/EventSubscriber/ResourceResponseSubscriber.php
@@ -215,7 +215,7 @@ class ResourceResponseSubscriber implements EventSubscriberInterface {
         // updating the response object's cacheability.
         return $serializer->serialize($data, $format, [
           'request' => $request,
-          'cacheable_metadata' => $response->getCacheableMetadata(),
+          'cacheability' => $response->getCacheableMetadata(),
         ]);
       };
       $output = $this->renderer->executeInRenderContext($context, $render_function);
diff --git a/src/Normalizer/EntityNormalizer.php b/src/Normalizer/EntityNormalizer.php
index bb07c12..fae740f 100644
--- a/src/Normalizer/EntityNormalizer.php
+++ b/src/Normalizer/EntityNormalizer.php
@@ -216,7 +216,7 @@ class EntityNormalizer extends NormalizerBase implements DenormalizerInterface {
     /* @var \Drupal\Core\Field\FieldItemListInterface|\Drupal\jsonapi\Normalizer\Relationship $field */
     // Continue if the current user does not have access to view this field.
     $access = $field->access('view', $context['account'], TRUE);
-    $context['cacheable_metadata']->addCacheableDependency($access);
+    $context['cacheability']->addCacheableDependency($access);
     if ($field instanceof AccessibleInterface && !$access->isAllowed()) {
       return (new NullFieldNormalizerValue())->addCacheableDependency($access);
     }
diff --git a/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php b/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php
index 1f33db5..9e80baf 100644
--- a/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php
+++ b/src/Normalizer/JsonApiDocumentTopLevelNormalizer.php
@@ -197,8 +197,8 @@ class JsonApiDocumentTopLevelNormalizer extends NormalizerBase implements Denorm
       $context['resource_type'] = $this->currentContext->getResourceType();
     }
     $value_extractor = $this->buildNormalizerValue($object->getData(), $format, $context);
-    if (!empty($context['cacheable_metadata'])) {
-      $context['cacheable_metadata']->addCacheableDependency($value_extractor);
+    if (!empty($context['cacheability'])) {
+      $context['cacheability']->addCacheableDependency($value_extractor);
     }
     $normalized = $value_extractor->rasterizeValue();
     $included = array_filter($value_extractor->rasterizeIncludes());
diff --git a/src/Normalizer/RelationshipItemNormalizer.php b/src/Normalizer/RelationshipItemNormalizer.php
index 93bc6af..d099a80 100644
--- a/src/Normalizer/RelationshipItemNormalizer.php
+++ b/src/Normalizer/RelationshipItemNormalizer.php
@@ -83,8 +83,8 @@ class RelationshipItemNormalizer extends FieldItemNormalizer {
       // Add the cacheable dependency of the included item directly to the
       // response cacheable metadata. This is similar to the flatten include
       // data structure, instead of a content graph.
-      if (!empty($context['cacheable_metadata'])) {
-        $context['cacheable_metadata']->addCacheableDependency($normalizer_value);
+      if (!empty($context['cacheability'])) {
+        $context['cacheability']->addCacheableDependency($normalizer_value);
       }
     }
     return $normalizer_value;
diff --git a/tests/src/Functional/ActionTest.php b/tests/src/Functional/ActionTest.php
index 1dc6a29..cc57864 100644
--- a/tests/src/Functional/ActionTest.php
+++ b/tests/src/Functional/ActionTest.php
@@ -110,15 +110,4 @@ class ActionTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Functional/BaseFieldOverrideTest.php b/tests/src/Functional/BaseFieldOverrideTest.php
index c9623ac..3dffc9d 100644
--- a/tests/src/Functional/BaseFieldOverrideTest.php
+++ b/tests/src/Functional/BaseFieldOverrideTest.php
@@ -121,17 +121,6 @@ class BaseFieldOverrideTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/BlockContentTest.php b/tests/src/Functional/BlockContentTest.php
index d4d7c52..a368452 100644
--- a/tests/src/Functional/BlockContentTest.php
+++ b/tests/src/Functional/BlockContentTest.php
@@ -4,6 +4,7 @@ namespace Drupal\Tests\jsonapi\Functional;
 
 use Drupal\block_content\Entity\BlockContent;
 use Drupal\block_content\Entity\BlockContentType;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Url;
 use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
 
@@ -185,25 +186,19 @@ class BlockContentTest extends ResourceTestBase {
       ->addCacheTags(['block_content:1']);
   }
 
-  // @codingStandardsIgnoreStart
   /**
    * {@inheritdoc}
    */
   protected function getExpectedCacheTags() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text']);
-    return parent::getExpectedCacheTags();
+    return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text']);
   }
 
   /**
    * {@inheritdoc}
    */
   protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
-    return parent::getExpectedCacheContexts();
+    return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['languages:language_interface', 'theme']);
   }
-  // @codingStandardsIgnoreEnd
 
   /**
    * {@inheritdoc}
diff --git a/tests/src/Functional/BlockTest.php b/tests/src/Functional/BlockTest.php
index 47424b4..6c281de 100644
--- a/tests/src/Functional/BlockTest.php
+++ b/tests/src/Functional/BlockTest.php
@@ -142,18 +142,6 @@ class BlockTest extends ResourceTestBase {
     return array_values(array_diff(parent::getExpectedCacheTags(), ['config:user.role.anonymous']));
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @see ::createEntity()
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['url.site'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/CommentTest.php b/tests/src/Functional/CommentTest.php
index c4d3d18..b56f768 100644
--- a/tests/src/Functional/CommentTest.php
+++ b/tests/src/Functional/CommentTest.php
@@ -7,6 +7,7 @@ use Drupal\comment\Entity\CommentType;
 use Drupal\comment\Tests\CommentTestTrait;
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Url;
 use Drupal\entity_test\Entity\EntityTest;
 use Drupal\Tests\rest\Functional\BcTimestampNormalizerUnixTestTrait;
@@ -248,25 +249,27 @@ class CommentTest extends ResourceTestBase {
     ];
   }
 
-  // @codingStandardsIgnoreStart
   /**
    * {@inheritdoc}
    */
   protected function getExpectedCacheTags() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text']);
-    return parent::getExpectedCacheTags();
+    // @todo Remove this when JSON API requires Drupal 8.5 or newer.
+    if (floatval(\Drupal::VERSION) < 8.5) {
+      return parent::getExpectedCacheTags();
+    }
+    return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text']);
   }
 
   /**
    * {@inheritdoc}
    */
   protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return Cache::mergeContexts(['languages:language_interface', 'theme'], parent::getExpectedCacheContexts());
-    return parent::getExpectedCacheContexts();
+    // @todo Remove this when JSON API requires Drupal 8.5 or newer.
+    if (floatval(\Drupal::VERSION) < 8.5) {
+      return parent::getExpectedCacheContexts();
+    }
+    return Cache::mergeContexts(['languages:language_interface', 'theme'], parent::getExpectedCacheContexts());
   }
-  // @codingStandardsIgnoreEnd
 
   /**
    * {@inheritdoc}
diff --git a/tests/src/Functional/ContentLanguageSettingsTest.php b/tests/src/Functional/ContentLanguageSettingsTest.php
index b9b7570..4151e70 100644
--- a/tests/src/Functional/ContentLanguageSettingsTest.php
+++ b/tests/src/Functional/ContentLanguageSettingsTest.php
@@ -117,13 +117,6 @@ class ContentLanguageSettingsTest extends ResourceTestBase {
    * {@inheritdoc}
    */
   protected function getExpectedCacheContexts() {
-    // @todo Uncomment first 4 lines, remove last line in https://www.drupal.org/project/jsonapi/issues/2940342.
-    // @codingStandardsIgnoreStart
-//    return [
-//      'languages:language_interface',
-//      'user.permissions',
-//    ];
-    // @codingStandardsIgnoreEnd
     return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['languages:language_interface']);
   }
 
diff --git a/tests/src/Functional/EditorTest.php b/tests/src/Functional/EditorTest.php
index bff64cc..d34966f 100644
--- a/tests/src/Functional/EditorTest.php
+++ b/tests/src/Functional/EditorTest.php
@@ -190,18 +190,6 @@ class EditorTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @see ::createEntity()
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/EntityFormDisplayTest.php b/tests/src/Functional/EntityFormDisplayTest.php
index f4618b4..e896c3d 100644
--- a/tests/src/Functional/EntityFormDisplayTest.php
+++ b/tests/src/Functional/EntityFormDisplayTest.php
@@ -170,17 +170,6 @@ class EntityFormDisplayTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/EntityViewDisplayTest.php b/tests/src/Functional/EntityViewDisplayTest.php
index 0d28996..fc522f4 100644
--- a/tests/src/Functional/EntityViewDisplayTest.php
+++ b/tests/src/Functional/EntityViewDisplayTest.php
@@ -123,17 +123,6 @@ class EntityViewDisplayTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/FieldConfigTest.php b/tests/src/Functional/FieldConfigTest.php
index 943cfa9..f28d8b1 100644
--- a/tests/src/Functional/FieldConfigTest.php
+++ b/tests/src/Functional/FieldConfigTest.php
@@ -129,17 +129,6 @@ class FieldConfigTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/FieldStorageConfigTest.php b/tests/src/Functional/FieldStorageConfigTest.php
index 9c5248e..13e7631 100644
--- a/tests/src/Functional/FieldStorageConfigTest.php
+++ b/tests/src/Functional/FieldStorageConfigTest.php
@@ -117,15 +117,4 @@ class FieldStorageConfigTest extends ResourceTestBase {
     return "The 'administer node fields' permission is required.";
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Functional/FileTest.php b/tests/src/Functional/FileTest.php
index 3266f1d..4d6af09 100644
--- a/tests/src/Functional/FileTest.php
+++ b/tests/src/Functional/FileTest.php
@@ -203,17 +203,6 @@ class FileTest extends ResourceTestBase {
     return parent::getExpectedUnauthorizedAccessMessage($method);
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
   /**
    * {@inheritdoc}
    */
diff --git a/tests/src/Functional/MenuTest.php b/tests/src/Functional/MenuTest.php
index f5d3ede..ea7e8c2 100644
--- a/tests/src/Functional/MenuTest.php
+++ b/tests/src/Functional/MenuTest.php
@@ -99,15 +99,4 @@ class MenuTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Functional/RdfMappingTest.php b/tests/src/Functional/RdfMappingTest.php
index b090ad7..ddb9f96 100644
--- a/tests/src/Functional/RdfMappingTest.php
+++ b/tests/src/Functional/RdfMappingTest.php
@@ -146,15 +146,4 @@ class RdfMappingTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Functional/RestResourceConfigTest.php b/tests/src/Functional/RestResourceConfigTest.php
index bc0c602..fb8a74e 100644
--- a/tests/src/Functional/RestResourceConfigTest.php
+++ b/tests/src/Functional/RestResourceConfigTest.php
@@ -124,15 +124,4 @@ class RestResourceConfigTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Functional/TermTest.php b/tests/src/Functional/TermTest.php
index a371854..00ff4e5 100644
--- a/tests/src/Functional/TermTest.php
+++ b/tests/src/Functional/TermTest.php
@@ -4,6 +4,7 @@ namespace Drupal\Tests\jsonapi\Functional;
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Component\Utility\NestedArray;
+use Drupal\Core\Cache\Cache;
 use Drupal\Core\Url;
 use Drupal\taxonomy\Entity\Term;
 use Drupal\taxonomy\Entity\Vocabulary;
@@ -336,27 +337,28 @@ class TermTest extends ResourceTestBase {
     $this->assertSame($normalization['data']['attributes']['path']['alias'], $updated_normalization['data']['attributes']['path']['alias']);
   }
 
-  // @codingStandardsIgnoreStart
   /**
    * {@inheritdoc}
    */
   protected function getExpectedCacheTags() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text', 'config:filter.settings']);
-    return parent::getExpectedCacheTags();
+    // @todo Remove this when JSON API requires Drupal 8.5 or newer.
+    if (floatval(\Drupal::VERSION) < 8.5) {
+      return parent::getExpectedCacheTags();
+    }
+    return Cache::mergeTags(parent::getExpectedCacheTags(), ['config:filter.format.plain_text', 'config:filter.settings']);
   }
 
   /**
    * {@inheritdoc}
    */
   protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return Cache::mergeContexts(['url.site'], $this->container->getParameter('renderer.config')['required_cache_contexts']);
-    return parent::getExpectedCacheContexts();
+    // @todo Remove this when JSON API requires Drupal 8.5 or newer.
+    if (floatval(\Drupal::VERSION) < 8.5) {
+      return parent::getExpectedCacheContexts();
+    }
+    return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['languages:language_interface', 'theme']);
   }
 
-  // @codingStandardsIgnoreEnd
-
   /**
    * Tests GETting a term with a parent term other than the default <root> (0).
    *
diff --git a/tests/src/Functional/TourTest.php b/tests/src/Functional/TourTest.php
index 496954e..e2daee5 100644
--- a/tests/src/Functional/TourTest.php
+++ b/tests/src/Functional/TourTest.php
@@ -140,15 +140,4 @@ class TourTest extends ResourceTestBase {
     return "The following permissions are required: 'access tour' OR 'administer site configuration'.";
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Functional/ViewTest.php b/tests/src/Functional/ViewTest.php
index 347451d..97644e6 100644
--- a/tests/src/Functional/ViewTest.php
+++ b/tests/src/Functional/ViewTest.php
@@ -120,15 +120,4 @@ class ViewTest extends ResourceTestBase {
     // @todo Update in https://www.drupal.org/node/2300677.
   }
 
-  // @codingStandardsIgnoreStart
-  /**
-   * {@inheritdoc}
-   */
-  protected function getExpectedCacheContexts() {
-    // @todo Uncomment first line, remove second line in https://www.drupal.org/project/jsonapi/issues/2940342.
-//    return ['user.permissions'];
-    return parent::getExpectedCacheContexts();
-  }
-  // @codingStandardsIgnoreEnd
-
 }
diff --git a/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php b/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
index ce06be1..a31b451 100644
--- a/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
+++ b/tests/src/Kernel/Normalizer/JsonApiDocumentTopLevelNormalizerTest.php
@@ -4,6 +4,7 @@ namespace Drupal\Tests\jsonapi\Kernel\Normalizer;
 
 use Drupal\Component\Serialization\Json;
 use Drupal\Core\Cache\Cache;
+use Drupal\Core\Cache\CacheableMetadata;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\file\Entity\File;
 use Drupal\jsonapi\ResourceType\ResourceType;
@@ -48,6 +49,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
     'system',
     'taxonomy',
     'text',
+    'filter',
     'user',
     'file',
     'image',
@@ -96,6 +98,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
       ['target_bundles' => ['tags']],
       FieldStorageDefinitionInterface::CARDINALITY_UNLIMITED
     );
+    $this->createTextField('node', 'article', 'body', 'Body');
 
     $this->createImageField('field_image', 'article');
 
@@ -136,6 +139,10 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
       'title' => 'dummy_title',
       'type' => 'article',
       'uid' => 1,
+      'body' => [
+        'format' => 'plain_text',
+        'value' => $this->randomStringValidate(42),
+      ],
       'field_tags' => [
         ['target_id' => $this->term1->id()],
         ['target_id' => $this->term2->id()],
@@ -220,7 +227,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
         [
           'request' => $request,
           'resource_type' => $resource_type,
-          'cacheable_metadata' => $response->getCacheableMetadata(),
+          'cacheability' => $response->getCacheableMetadata(),
         ]
       );
 
@@ -319,7 +326,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
         [
           'request' => $request,
           'resource_type' => $resource_type,
-          'cacheable_metadata' => $response->getCacheableMetadata(),
+          'cacheability' => $response->getCacheableMetadata(),
         ]
       );
     $this->assertSame($normalized['data']['attributes']['name'], 'user1');
@@ -358,7 +365,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
         [
           'request' => $request,
           'resource_type' => $resource_type,
-          'cacheable_metadata' => $response->getCacheableMetadata(),
+          'cacheability' => $response->getCacheableMetadata(),
         ]
       );
     $this->assertStringMatchesFormat($this->node->uuid(), $normalized['data']['id']);
@@ -400,7 +407,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
         [
           'request' => $request,
           'resource_type' => $resource_type,
-          'cacheable_metadata' => $response->getCacheableMetadata(),
+          'cacheability' => $response->getCacheableMetadata(),
           'data_wrapper' => 'errors',
         ]
       );
@@ -433,7 +440,7 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
       ->normalize($document_wrapper->reveal(), 'api_json', [
         'request' => $request,
         'resource_type' => $resource_type,
-        'cacheable_metadata' => $response->getCacheableMetadata(),
+        'cacheability' => $response->getCacheableMetadata(),
       ]);
     $this->assertTrue(empty($normalized['data']['attributes']['type']));
     $this->assertTrue(!empty($normalized['data']['attributes']['uuid']));
@@ -680,6 +687,68 @@ class JsonApiDocumentTopLevelNormalizerTest extends JsonapiKernelTestBase {
   }
 
   /**
+   * Ensure that cacheability metadata is properly added.
+   *
+   * @param \Drupal\Core\Cache\CacheableMetadata $expected_metadata
+   *   The expected cacheable metadata.
+   * @param array|null $fields
+   *   Fields to include in the response, keyed by resource type.
+   * @param array|null $includes
+   *   Resources paths to include in the response.
+   *
+   * @dataProvider testCacheableMetadataProvider
+   */
+  public function testCacheableMetadata(CacheableMetadata $expected_metadata, $fields = NULL, $includes = NULL) {
+    list($request, $resource_type) = $this->generateProphecies('node', 'article');
+    $actual_metadata = new CacheableMetadata();
+    $context = [
+      'request' => $this->decorateRequest($request, $fields, $includes),
+      'resource_type' => $resource_type,
+      'cacheability' => $actual_metadata,
+    ];
+    $this->getNormalizer()->normalize(new JsonApiDocumentTopLevel($this->node), 'api_json', $context);
+    $this->assertArraySubset($expected_metadata->getCacheTags(), $actual_metadata->getCacheTags());
+    $this->assertArraySubset($expected_metadata->getCacheContexts(), $actual_metadata->getCacheContexts());
+    $this->assertSame($expected_metadata->getCacheMaxAge(), $actual_metadata->getCacheMaxAge());
+  }
+
+  /**
+   * Provides test cases for asserting cacheable metadata behavior.
+   */
+  public function testCacheableMetadataProvider() {
+    $cacheable_metadata = function ($metadata) {
+      return CacheableMetadata::createFromRenderArray(['#cache' => $metadata]);
+    };
+
+    return [
+      [
+        floatval(\Drupal::VERSION) < 8.5
+        ? $cacheable_metadata([])
+        : $cacheable_metadata(['contexts' => ['languages:language_interface']]),
+        ['node--article' => 'body'],
+      ],
+    ];
+  }
+
+  /**
+   * Decorates a request with sparse fieldsets and includes.
+   */
+  protected function decorateRequest(Request $request, array $fields = NULL, array $includes = NULL) {
+    $parameters = new ParameterBag();
+    $parameters->add($fields ? ['fields' => $fields] : []);
+    $parameters->add($includes ? ['include' => $includes] : []);
+    $request->query = $parameters;
+    return $request;
+  }
+
+  /**
+   * Helper to load the normalizer.
+   */
+  protected function getNormalizer() {
+    return $this->container->get('serializer.normalizer.jsonapi_document_toplevel.jsonapi');
+  }
+
+  /**
    * Generates the prophecies for the mocked entity request.
    *
    * @param string $entity_type_id
