Skip to content

Commit

Permalink
fix: throw when <PrismicLink>'s field or document prop value is…
Browse files Browse the repository at this point in the history
… missing required properties (#153)

* fix: throw when `<PrismicLink>`'s `field` or `document` prop value is missing required properties

* docs: update `missing-link-properties` message [skip ci]

* docs: add `target` property recommendation [skip ci]

* docs: reformat `missing-link-properties` [skip ci]
  • Loading branch information
angeloashmore authored May 26, 2022
1 parent c21caf0 commit 349529e
Show file tree
Hide file tree
Showing 3 changed files with 146 additions and 0 deletions.
65 changes: 65 additions & 0 deletions messages/missing-link-properties.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Missing Link properties

`<PrismicLink>` requires specific properties in the provided field or document to render properly. This requirement extends to [Link][link-fields], [Link to Media][link-fields], and [Content Relationship][link-fields] fields.

If the required properties are missing, `<PrismicLink>` will not render the link.

**Note**: When using Prismic's [Rest API][rest-api] (the default when using `@prismicio/client`), the required fields are automatically included. When using Prismic's [GraphQL API][graphql-api], you must include these fields in your query.

## Required Properties

### With the `field` prop

The following properties are requried when using the `field` prop with a Link, Link to Media, or Content Relationship field:

- `link_type` (or `_linkType` when using Prismic's [GraphQL API][graphql-api])
- `id`
- `url`
- `uid` (only if your website uses a [Link Resolver][link-resolver] that uses a document's UID field)

The following properties are not required, but are recommended:

- `target`

**Example**:

```tsx
<PrismicLink field={doc.data.linkField}>Click me</PrismicLink>
```

### With the `document` prop

The following properties are requried when using the `document` prop with a Prismic document:

- `id`
- `url`
- `uid` (only if your website uses a [Link Resolver][link-resolver] that uses a document's UID field)

**Example**:

```tsx
<PrismicLink document={doc}>Click me</PrismicLink>
```

## GraphQL Example

When using Prismic's [GraphQL API][graphql-api], Link fields must be queried with at least the following properties:

```diff
{
page(uid: "home", lang: "en-us") {
linkField {
+ _linkType
+ id
+ url
+ uid # only required if your website uses a Link Resolver that uses a document's UID field.
+ target # not required, but recommended for automatic `target` handling
}
}
}
```

[link-fields]: https://prismic.io/docs/core-concepts/link-content-relationship
[link-resolver]: https://prismic.io/docs/core-concepts/link-resolver-route-resolver
[rest-api]: https://prismic.io/docs/technologies/rest-api-technical-reference
[graphql-api]: https://prismic.io/docs/technologies/graphql
32 changes: 32 additions & 0 deletions src/PrismicLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as prismicH from "@prismicio/helpers";
import * as prismicT from "@prismicio/types";

import { __PRODUCTION__ } from "./lib/__PRODUCTION__";
import { devMsg } from "./lib/devMsg";
import { isInternalURL } from "./lib/isInternalURL";

import { usePrismicContext } from "./usePrismicContext";
Expand Down Expand Up @@ -135,6 +136,37 @@ const _PrismicLink = <
): JSX.Element | null => {
const context = usePrismicContext();

if (!__PRODUCTION__) {
if ("field" in props && props.field) {
if (
!("link_type" in props.field) ||
!("url" in props.field || "id" in props.field)
) {
console.error(
`[PrismicLink] This "field" prop value caused an error to be thrown.\n`,
props.field,
);
throw new Error(
`[PrismicLink] The provided field is missing required properties to properly render a link. The link may not render. For more details, see ${devMsg(
"missing-link-properties",
)}`,
);
}
} else if ("document" in props && props.document) {
if (!("url" in props.document || "id" in props.document)) {
console.error(
`[PrismicLink] This "document" prop value caused an error to be thrown.\n`,
props.document,
);
throw new Error(
`[PrismicLink] The provided document is missing required properties to properly render a link. The link may not render. For more details, see ${devMsg(
"missing-link-properties",
)}`,
);
}
}
}

const linkResolver = props.linkResolver || context.linkResolver;

let href: string | null | undefined;
Expand Down
49 changes: 49 additions & 0 deletions test/PrismicLink.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as prismicT from "@prismicio/types";
import * as prismicH from "@prismicio/helpers";
import * as prismicM from "@prismicio/mock";
import * as React from "react";
import * as sinon from "sinon";

import { renderJSON } from "./__testutils__/renderJSON";

Expand Down Expand Up @@ -430,3 +431,51 @@ test("forwards ref to external component", (t) => {
t.is(spanRef?.tagName, "span");
t.is(customComponentRef?.tagName, "input");
});

test.serial(
"throws error if properties are missing from a given field",
(t) => {
const field = {} as prismicT.FilledLinkToDocumentField;

const consoleErrorStub = sinon.stub(console, "error");

t.throws(
() => {
renderJSON(<PrismicLink field={field} />);
},
{ message: /missing-link-properties/ },
);

consoleErrorStub.restore();

t.true(
consoleErrorStub.calledWithMatch(
/this "field" prop value caused an error to be thrown./i,
),
);
},
);

test.serial(
"throws error if properties are missing from a given document",
(t) => {
const document = {} as prismicT.PrismicDocument;

const consoleErrorStub = sinon.stub(console, "error");

t.throws(
() => {
renderJSON(<PrismicLink document={document} />);
},
{ message: /missing-link-properties/ },
);

consoleErrorStub.restore();

t.true(
consoleErrorStub.calledWithMatch(
/this "document" prop value caused an error to be thrown./i,
),
);
},
);

0 comments on commit 349529e

Please sign in to comment.