diff --git a/packages/next-drupal/tests/NextDrupal/resource-methods.test.ts b/packages/next-drupal/tests/NextDrupal/resource-methods.test.ts index 0a2765ca..e790aa25 100644 --- a/packages/next-drupal/tests/NextDrupal/resource-methods.test.ts +++ b/packages/next-drupal/tests/NextDrupal/resource-methods.test.ts @@ -330,6 +330,7 @@ describe("getResource()", () => { test("throws an error if revision access is forbidden", async () => { const drupal = new NextDrupal(BASE_URL) + spyOnFetch({ responseBody: mocks.resources.node.forbidden, status: 403 }) await expect( drupal.getResource( @@ -501,6 +502,10 @@ describe("getResourceByPath()", () => { test("throws an error if revision access is forbidden", async () => { const drupal = new NextDrupal(BASE_URL) + spyOnFetch({ + responseBody: mocks.resources.subRequests.forbidden, + status: 207, + }) await expect( drupal.getResourceByPath( diff --git a/packages/next-drupal/tests/NextDrupalPages/pages-router-methods.test.ts b/packages/next-drupal/tests/NextDrupalPages/pages-router-methods.test.ts index 1ef3f2c7..456ee032 100644 --- a/packages/next-drupal/tests/NextDrupalPages/pages-router-methods.test.ts +++ b/packages/next-drupal/tests/NextDrupalPages/pages-router-methods.test.ts @@ -889,29 +889,6 @@ describe("getResourceFromContext()", () => { ) }) - test("throws an error if revision access is forbidden", async () => { - const drupal = new NextDrupalPages(BASE_URL) - - const context: GetStaticPropsContext = { - previewData: { - resourceVersion: "id:1", - }, - params: { - slug: ["recipes", "deep-mediterranean-quiche"], - }, - } - - await expect( - drupal.getResourceFromContext("node--recipe", context, { - params: { - "fields[node--recipe]": "title", - }, - }) - ).rejects.toThrow( - "403 Forbidden\nThe current user is not allowed to GET the selected resource. The user does not have access to the requested version." - ) - }) - test("makes un-authenticated requests by default", async () => { const drupal = new NextDrupalPages(BASE_URL) const drupalFetchSpy = spyOnDrupalFetch(drupal) diff --git a/packages/next-drupal/tests/utils/mocks/data.ts b/packages/next-drupal/tests/utils/mocks/data.ts index dd539705..c6be6fa6 100644 --- a/packages/next-drupal/tests/utils/mocks/data.ts +++ b/packages/next-drupal/tests/utils/mocks/data.ts @@ -235,7 +235,330 @@ const resources = { }, }, }, + node: { + ok: { + jsonapi: { + meta: { + links: { + self: { + href: "http://jsonapi.org/format/1.0/", + }, + }, + }, + version: "1.0", + }, + data: { + type: "node--recipe", + id: "71e04ead-4cc7-416c-b9ca-60b635fdc50f", + attributes: { + changed: "2022-03-25T08:02:17+00:00", + content_translation_outdated: false, + content_translation_source: "und", + created: "2022-03-21T10:52:42+00:00", + default_langcode: true, + drupal_internal__nid: 1, + drupal_internal__vid: 37, + field_cooking_time: 30, + field_difficulty: "medium", + field_ingredients: [ + "For the pastry:", + "280g plain flour", + "140g butter", + "Cold water", + "For the filling:", + "1 onion", + "2 garlic cloves", + "Half a courgette", + "450ml soya milk", + "500g grated parmesan", + "2 eggs", + "200g sun dried tomatoes", + "100g feta", + ], + field_number_of_servings: 8, + field_preparation_time: 40, + field_recipe_instruction: { + format: "basic_html", + processed: + "
  1. Preheat the oven to 400°F/200°C. Starting with the pastry; rub the flour and butter together in a bowl until crumbling like breadcrumbs. Add water, a little at a time, until it forms a dough.
  2. \n" + + "
  3. Roll out the pastry on a floured board and gently spread over your tin. Place in the fridge for 20 minutes before blind baking for a further 10.
  4. \n" + + "
  5. Whilst the pastry is cooling, chop and gently cook the onions, garlic and courgette.
  6. \n" + + "
  7. In a large bowl, add the soya milk, half the parmesan, and the eggs. Gently mix.
  8. \n" + + "
  9. Once the pastry is cooked, spread the onions, garlic and sun dried tomatoes over the base and pour the eggs mix over. Sprinkle the remaining parmesan and careful lay the feta over the top. Bake for 30 minutes or until golden brown.
  10. \n" + + "
", + value: + "
    \n" + + "\t
  1. Preheat the oven to 400°F/200°C. Starting with the pastry; rub the flour and butter together in a bowl until crumbling like breadcrumbs. Add water, a little at a time, until it forms a dough.
  2. \n" + + "\t
  3. Roll out the pastry on a floured board and gently spread over your tin. Place in the fridge for 20 minutes before blind baking for a further 10.
  4. \n" + + "\t
  5. Whilst the pastry is cooling, chop and gently cook the onions, garlic and courgette.
  6. \n" + + "\t
  7. In a large bowl, add the soya milk, half the parmesan, and the eggs. Gently mix.
  8. \n" + + "\t
  9. Once the pastry is cooked, spread the onions, garlic and sun dried tomatoes over the base and pour the eggs mix over. Sprinkle the remaining parmesan and careful lay the feta over the top. Bake for 30 minutes or until golden brown.
  10. \n" + + "
", + }, + field_summary: { + format: "basic_html", + processed: + "

An Italian inspired quiche with sun dried tomatoes and courgette. A perfect light meal for a summer's day.

", + value: + "

An Italian inspired quiche with sun dried tomatoes and courgette. A perfect light meal for a summer's day.

", + }, + langcode: "en", + moderation_state: "published", + path: { + alias: "/recipes/deep-mediterranean-quiche", + langcode: "en", + pid: 67, + }, + promote: true, + revision_log: null, + revision_timestamp: "2022-03-25T08:02:17+00:00", + revision_translation_affected: true, + status: true, + sticky: false, + title: "Deep mediterranean quiche - edited", + }, + relationships: { + field_media_image: { + data: { + id: "bbfe9d97-2da2-432b-a22c-0396c08e06ca", + meta: { + drupal_internal__target_id: 1, + }, + type: "media--image", + }, + links: { + related: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/field_media_image?resourceVersion=id%3A37", + }, + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/relationships/field_media_image?resourceVersion=id%3A37", + }, + }, + }, + field_recipe_category: { + data: [ + { + id: "a6c02fe4-67bf-462c-90cb-32281a07efe4", + meta: { + drupal_internal__target_id: 31, + }, + type: "taxonomy_term--recipe_category", + }, + ], + links: { + related: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/field_recipe_category?resourceVersion=id%3A37", + }, + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/relationships/field_recipe_category?resourceVersion=id%3A37", + }, + }, + }, + field_tags: { + data: [ + { + id: "46258827-cfad-4813-99dc-287c4cb41117", + meta: { + drupal_internal__target_id: 22, + }, + type: "taxonomy_term--tags", + }, + { + id: "f32a4d84-0568-4bfd-8be3-8217d36efb6d", + meta: { + drupal_internal__target_id: 13, + }, + type: "taxonomy_term--tags", + }, + ], + links: { + related: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/field_tags?resourceVersion=id%3A37", + }, + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/relationships/field_tags?resourceVersion=id%3A37", + }, + }, + }, + node_type: { + data: { + id: "9b70a287-cade-454f-be8b-dea7b9a37c7a", + meta: { + drupal_internal__target_id: "recipe", + }, + type: "node_type--node_type", + }, + links: { + related: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/node_type?resourceVersion=id%3A37", + }, + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/relationships/node_type?resourceVersion=id%3A37", + }, + }, + }, + revision_uid: { + data: { + id: "365cc7b5-ddc4-4b3b-939e-1494400aab4a", + meta: { + drupal_internal__target_id: 1, + }, + type: "user--user", + }, + links: { + related: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/revision_uid?resourceVersion=id%3A37", + }, + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/relationships/revision_uid?resourceVersion=id%3A37", + }, + }, + }, + uid: { + data: { + id: "9e4944e8-dd77-407a-8610-83e823b48b56", + meta: { + drupal_internal__target_id: 4, + }, + type: "user--user", + }, + links: { + related: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/uid?resourceVersion=id%3A37", + }, + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f/relationships/uid?resourceVersion=id%3A37", + }, + }, + }, + }, + links: { + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f?resourceVersion=id%3A37", + }, + }, + }, + links: { + self: { + href: "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f", + }, + }, + }, + forbidden: { + jsonapi: { + version: "1.0", + meta: { links: { self: { href: "http://jsonapi.org/format/1.0/" } } }, + }, + errors: [ + { + title: "Forbidden", + status: "403", + detail: + "The current user is not allowed to GET the selected resource. The user does not have access to the requested version.", + source: { pointer: "/data" }, + }, + ], + }, + }, + translatePath: { + jsonapi: { + basePath: "/en/jsonapi", + entryPoint: "https://example.com/en/jsonapi", + individual: + "https://example.com/en/jsonapi/node/recipe/71e04ead-4cc7-416c-b9ca-60b635fdc50f", + resourceName: "node--recipe", + }, + entity: { + bundle: "recipe", + canonical: "https://example.com/en/recipes/deep-mediterranean-quiche", + id: "1", + langcode: "en", + path: "/en/recipes/deep-mediterranean-quiche", + type: "node", + uuid: "71e04ead-4cc7-416c-b9ca-60b635fdc50f", + }, + isHomePath: false, + label: "Deep mediterranean quiche - edited", + resolved: "https://example.com/en/recipes/deep-mediterranean-quiche", + }, + subRequests: { + ok: { + router: { + body: "SEE REPLACEMENT BELOW", + headers: { + "cache-control": ["no-cache, private"], + "content-id": [""], + "content-type": ["application/json"], + date: ["Fri, 12 Apr 2024 16:44:53 GMT"], + status: [200], + "x-drupal-dynamic-cache": ["HIT"], + }, + }, + "resolvedResource#uri{0}": { + body: "SEE REPLACEMENT BELOW", + headers: { + "cache-control": ["no-cache, private"], + "content-id": [""], + "content-type": ["application/vnd.api+json"], + date: ["Fri, 12 Apr 2024 16:44:54 GMT"], + status: [200], + "x-drupal-dynamic-cache": ["HIT"], + }, + }, + }, + forbidden: { + router: { + body: "SEE REPLACEMENT BELOW", + headers: { + "cache-control": ["no-cache, private"], + "content-id": [""], + "content-type": ["application/json"], + date: ["Fri, 12 Apr 2024 16:44:53 GMT"], + status: [200], + "x-drupal-dynamic-cache": ["HIT"], + }, + }, + "resolvedResource#uri{0}": { + body: "SEE REPLACEMENT BELOW", + headers: { + "cache-control": ["no-cache, private"], + "content-id": [""], + "content-type": ["application/vnd.api+json"], + date: ["Fri, 12 Apr 2024 16:44:54 GMT"], + status: [403], + "x-drupal-dynamic-cache": ["MISS"], + }, + }, + }, + pathNotFound: { + router: { + body: JSON.stringify({ + message: "Unable to resolve path /path-does-not-exist.", + details: + "None of the available methods were able to find a match for this path.", + }), + headers: { + "cache-control": ["no-cache, private"], + "content-id": [""], + "content-type": ["application/json"], + date: ["Fri, 12 Apr 2024 16:44:54 GMT"], + status: [404], + "x-drupal-dynamic-cache": ["MISS"], + }, + }, + }, + }, } +// JSON-encode the subrequest body fields. +resources.subRequests.ok.router.body = JSON.stringify(resources.translatePath) +resources.subRequests.ok["resolvedResource#uri{0}"].body = JSON.stringify( + resources.node.ok +) +resources.subRequests.forbidden.router.body = JSON.stringify( + resources.translatePath +) +resources.subRequests.forbidden["resolvedResource#uri{0}"].body = + JSON.stringify(resources.node.forbidden) const menus = { menuItems: { @@ -319,10 +642,110 @@ const menus = { weight: "30", }, }, + { + type: "menu_link_content--menu_link_content", + id: "menu_link_content:c116329b-dd21-445d-ab44-9f89f940339c", + attributes: { + description: null, + enabled: true, + expanded: false, + menu_name: "main", + meta: { + entity_id: "1", + }, + options: [], + parent: "", + provider: "menu_link_content", + route: { + name: "entity.node.canonical", + parameters: { + node: "1", + }, + }, + title: "About", + url: "/en/about", + weight: 40, + }, + }, + { + type: "menu_link_content--menu_link_content", + id: "menu_link_content:87d2132d-a55c-4743-aebc-87c050c58ba3", + attributes: { + description: null, + enabled: true, + expanded: false, + menu_name: "main", + meta: { + entity_id: "3", + }, + options: [], + parent: "menu_link_content:c116329b-dd21-445d-ab44-9f89f940339c", + provider: "menu_link_content", + route: { + name: "entity.node.canonical", + parameters: { + node: "2", + }, + }, + title: "Locations", + url: "/en/about/locations", + weight: -10, + }, + }, + { + type: "menu_link_content--menu_link_content", + id: "menu_link_content:7b1de73b-2497-4634-854c-6ef6142b790b", + attributes: { + description: null, + enabled: true, + expanded: false, + menu_name: "main", + meta: { + entity_id: "2", + }, + options: [], + parent: "menu_link_content:c116329b-dd21-445d-ab44-9f89f940339c", + provider: "menu_link_content", + route: { + name: "entity.node.canonical", + parameters: { + node: "3", + }, + }, + title: "Team", + url: "/en/about/team", + weight: 0, + }, + }, + { + type: "menu_link_content--menu_link_content", + id: "menu_link_content:80b574f3-5271-4769-93c5-8ae406864b0c", + attributes: { + description: null, + enabled: true, + expanded: false, + menu_name: "main", + meta: { + entity_id: "4", + }, + options: [], + parent: "menu_link_content:7b1de73b-2497-4634-854c-6ef6142b790b", + provider: "menu_link_content", + route: { + name: "entity.node.canonical", + parameters: { + node: "4", + }, + }, + title: "Management", + url: "/en/about/team/management", + weight: 0, + }, + }, ], links: { self: { - href: "https://next-drupal-test.ddev.site/jsonapi/menu_items/main", + href: "https://example.com/jsonapi/menu_items/main", }, }, }, @@ -345,7 +768,7 @@ const menus = { 'The "menu" parameter was not converted for the path "/jsonapi/menu_items/{menu}" (route name: "jsonapi_menu_items.menu")', links: { via: { - href: "https://next-drupal-test.ddev.site/jsonapi/menu_items/INVALID", + href: "https://example.com/jsonapi/menu_items/INVALID", }, info: { href: "http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.5",