diff --git a/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonAnonTest.php b/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonAnonTest.php
new file mode 100644
index 0000000..f6a067f
--- /dev/null
+++ b/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonAnonTest.php
@@ -0,0 +1,104 @@
+<?php
+
+namespace Drupal\Tests\hal\Functional\EntityResource\Shortcut;
+
+use Drupal\Core\Cache\Cache;
+use Drupal\Tests\hal\Functional\EntityResource\HalEntityNormalizationTrait;
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\Shortcut\ShortcutResourceTestBase;
+
+/**
+ * @group hal
+ */
+class ShortcutHalJsonAnonTest extends ShortcutResourceTestBase {
+
+  use HalEntityNormalizationTrait;
+  use AnonResourceTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['hal'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'hal_json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'application/hal+json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $expectedErrorMimeType = 'application/json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getExpectedNormalizedEntity() {
+	$default_normalization = parent::getExpectedNormalizedEntity();
+
+	$normalization = $this->applyHalFieldNormalization($default_normalization);
+
+	$author = User::load(0);
+	return  $normalization + [
+		'_links' => [
+		  'self' => [
+			'href' => $this->baseUrl . '/admin/config/user-interface/shortcut/link/1?_format=hal_json',
+		  ],
+		  'type' => [
+			'href' => $this->baseUrl . '/rest/type/shortcut/shortcut',
+		  ],
+		  $this->baseUrl . '/rest/relation/shortcut/shortcut/user_id' => [
+			[
+			  'href' => $this->baseUrl . '/user/0?_format=hal_json',
+			  'lang' => 'en',
+			],
+		  ],
+		],
+		'_embedded' => [
+		  $this->baseUrl . '/rest/relation/shortcut/shortcut/user_id' => [
+			[
+			  '_links' => [
+				'self' => [
+				  'href' => $this->baseUrl . '/user/0?_format=hal_json',
+				],
+				'type' => [
+				  'href' => $this->baseUrl . '/rest/type/user/user',
+				],
+			  ],
+			  'uuid' => [
+				['value' => $author->uuid()]
+			  ],
+			  'lang' => 'en',
+			],
+		  ],
+		],
+	  ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getNormalizedPostEntity() {
+	return parent::getNormalizedPostEntity() + [
+		'_links' => [
+		  'type' => [
+			'href' => $this->baseUrl . '/rest/type/shortcut/shortcut',
+		  ],
+		],
+	  ];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getExpectedCacheContexts() {
+    // The 'url.site' cache context is added for '_links' in the response.
+    return Cache::mergeContexts(parent::getExpectedCacheContexts(), ['url.site']);
+  }
+
+}
diff --git a/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonBasicAuthTest.php b/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonBasicAuthTest.php
new file mode 100644
index 0000000..b4e3655
--- /dev/null
+++ b/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonBasicAuthTest.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Drupal\Tests\hal\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\hal\Functional\HalJsonBasicAuthWorkaroundFor2805281Trait;
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+
+/**
+ * @group hal
+ */
+class ShortcutHalJsonBasicAuthTest extends ShortcutHalJsonAnonTest {
+
+  use BasicAuthResourceTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+  // @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
+  use HalJsonBasicAuthWorkaroundFor2805281Trait {
+    HalJsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
+  }
+
+}
diff --git a/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonCookieTest.php b/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonCookieTest.php
new file mode 100644
index 0000000..78fe3ae
--- /dev/null
+++ b/core/modules/hal/tests/src/Functional/EntityResource/Shortcut/ShortcutHalJsonCookieTest.php
@@ -0,0 +1,19 @@
+<?php
+
+namespace Drupal\Tests\hal\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+use Drupal\Tests\rest\Functional\EntityResource\Shortcut\ShortcutResourceTestBase;
+
+/**
+ * @group hal
+ */
+class ShortcutHalJsonCookieTest extends ShortcutHalJsonAnonTest {
+
+  use CookieResourceTestTrait;
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonAnonTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonAnonTest.php
new file mode 100644
index 0000000..bbeb2b4
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonAnonTest.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\AnonResourceTestTrait;
+
+/**
+ * @group rest
+ */
+class ShortcutJsonAnonTest extends ShortcutResourceTestBase {
+
+  use AnonResourceTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'application/json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $expectedErrorMimeType = 'application/json';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonBasicAuthTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonBasicAuthTest.php
new file mode 100644
index 0000000..e07664d
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonBasicAuthTest.php
@@ -0,0 +1,45 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\BasicAuthResourceTestTrait;
+use Drupal\Tests\rest\Functional\JsonBasicAuthWorkaroundFor2805281Trait;
+
+/**
+ * @group rest
+ */
+class ShortcutJsonBasicAuthTest extends ShortcutResourceTestBase {
+
+  use BasicAuthResourceTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['basic_auth'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'application/json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $expectedErrorMimeType = 'application/json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'basic_auth';
+
+  // @todo Fix in https://www.drupal.org/node/2805281: remove this trait usage.
+  use JsonBasicAuthWorkaroundFor2805281Trait {
+    JsonBasicAuthWorkaroundFor2805281Trait::assertResponseWhenMissingAuthentication insteadof BasicAuthResourceTestTrait;
+  }
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonCookieTest.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonCookieTest.php
new file mode 100644
index 0000000..bfcc0ec
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutJsonCookieTest.php
@@ -0,0 +1,34 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\Tests\rest\Functional\CookieResourceTestTrait;
+
+/**
+ * @group rest
+ */
+class ShortcutJsonCookieTest extends ShortcutResourceTestBase {
+
+  use CookieResourceTestTrait;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $format = 'json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $mimeType = 'application/json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $expectedErrorMimeType = 'application/json';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $auth = 'cookie';
+
+}
diff --git a/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutResourceTestBase.php b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutResourceTestBase.php
new file mode 100644
index 0000000..bf38f10
--- /dev/null
+++ b/core/modules/rest/tests/src/Functional/EntityResource/Shortcut/ShortcutResourceTestBase.php
@@ -0,0 +1,132 @@
+<?php
+
+namespace Drupal\Tests\rest\Functional\EntityResource\Shortcut;
+
+use Drupal\shortcut\Entity\Shortcut;
+use Drupal\Tests\rest\Functional\EntityResource\EntityResourceTestBase;
+
+/**
+ * ResourceTestBase for Shortcut entity.
+ */
+abstract class ShortcutResourceTestBase extends EntityResourceTestBase {
+
+  /**
+   * {@inheritdoc}
+   */
+  public static $modules = ['comment', 'shortcut'];
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $entityTypeId = 'shortcut';
+
+  /**
+   * {@inheritdoc}
+   */
+  protected static $patchProtectedFieldNames = [];
+
+  /**
+   * The Shortcut entity.
+   *
+   * @var \Drupal\Shortcut\ShortcutInterface
+   */
+  protected $entity;
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function setUpAuthorization($method) {
+	switch ($method) {
+	  case 'GET':
+		$this->grantPermissionsToTestedRole(['access shortcuts']);
+		break;
+	  case 'POST':
+	  case 'PATCH':
+	  case 'DELETE':
+		$this->grantPermissionsToTestedRole(['administer shortcuts']);
+		break;
+	}
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function createEntity() {
+	// Create shortcut.
+	$shortcut = Shortcut::create(array(
+	  'shortcut_set' => 'default',
+	  'title' => t('Comments'),
+	  'weight' => -20,
+	  'link' => array(
+		'uri' => 'internal:/admin/content/comment',
+	  ),
+	));
+	$shortcut->save();
+
+	return $shortcut;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getExpectedNormalizedEntity() {
+	return [
+	  'uuid' => [
+		[
+		  'value' => $this->entity->uuid(),
+		],
+	  ],
+	  'id' => [
+		[
+		  'value' => '1',
+		],
+	  ],
+	  'title' => [
+		[
+		  'value' => 'Comments',
+		],
+	  ],
+	  'shortcut_set' => [
+		[
+		  'value' => 'default',
+		],
+	  ],
+	  'link' => [
+		[
+		  'uri' => 'internal:/admin/content/comment',
+		  'title' => NULL,
+		  'options' => [],
+		],
+	  ],
+	  'weight' => [
+		[
+		  'value' => -20,
+		],
+	  ],
+	  'langcode' => [
+		[
+		  'value' => 'en',
+		],
+	  ],
+	];
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  protected function getNormalizedPostEntity() {
+	return [
+	  'name' => [
+		[
+		  'title' => 'Comments',
+		],
+	  ],
+	  'link' => [
+		[
+		  'uri' => 'internal:/admin/content/comment',
+		],
+	  ],
+	];
+  }
+
+}
