Repository: garmeeh/next-seo
Pull request #1479 (2024-08-13 20:05:05)

feat: Allow QAPage to set URL for author
## Description of Change(s):
---
Allow `QAPage` to set author URL if exists. Right now the current behavior would only set the name for the author but in order to improve the SEO we allow now setting the author with name and url if object is passed on (or you can just set the author as a string and it will set the proper structure with the name only) by reusing the `setAuthor` function logic.

---

To help get PR's merged faster, the following is required:

[x] Updated the documentation
[x] Unit/Cypress test covering all cases

Please link to relevant Google Docs or schema.org docs for what you are adding so we can review.
https://developers.google.com/search/docs/appearance/structured-data/qapage

Please have a read of the Contributing Guide for full details.

https://github.com/garmeeh/next-seo/blob/master/CONTRIBUTING.md

## Before

![image](https://github.com/user-attachments/assets/696dea5c-b05f-4612-aa82-c21c453f44f0)

## After

![image](https://github.com/user-attachments/assets/e0f52ce7-172b-44f4-98b1-7a47d0336941)



amadeusj5: Hi @garmeeh, can you check this out please? 🙏🏽 
amadeusj5: Hi @garmeeh any change you can take a look at this? it's a minor change but it will be really helpful for me 🙏🏽 
garmeeh: Hey @amadeusj5 I'll get this released for you this week. 

Could you take a look at the failing tests?
amadeusj5: Hi @garmeeh, test updated. Thanks in advance 🙏🏽 
garmeeh: Amazing. I've set the tests to run. I will release over the weekend then. 

Patch:
diff --git a/README.md b/README.md
index 15ca910..6c2d38f 100644
--- a/README.md
+++ b/README.md
@@ -61,7 +61,7 @@ If you are using **`pages`** directory then `NextSeo` is **exactly what you need
     - [dangerouslySetAllPagesToNoFollow](#dangerouslysetallpagestonofollow)
     - [robotsProps](#robotsprops)
     - [Twitter](#twitter)
-    - [facebook](#facebook)
+    - [Facebook](#facebook)
     - [Canonical URL](#canonical-url)
     - [Alternate](#alternate)
     - [Additional Meta Tags](#additional-meta-tags)
@@ -2673,7 +2673,10 @@ const Page = () => (
         answerCount: 3,
         upvoteCount: 26,
         dateCreated: '2016-07-23T21:11Z',
-        author: { name: 'New Baking User' },
+        author: {
+          name: 'New Baking User',
+          url: 'https://example.com/bakinguser',
+        },
         acceptedAnswer: {
           text: '1 pound (lb) is equal to 16 ounces (oz).',
           dateCreated: '2016-11-02T21:11Z',
@@ -2681,6 +2684,7 @@ const Page = () => (
           url: 'https://example.com/question1#acceptedAnswer',
           author: {
             name: 'SomeUser',
+            url: 'https://example.com/someuser',
           },
         },
         suggestedAnswer: [
@@ -2691,6 +2695,7 @@ const Page = () => (
             url: 'https://example.com/question1#suggestedAnswer1',
             author: {
               name: 'AnotherUser',
+              url: 'https://example.com/anotheruser',
             },
           },
           {
@@ -2700,6 +2705,7 @@ const Page = () => (
             url: 'https://example.com/question1#suggestedAnswer2',
             author: {
               name: 'ConfusedUser',
+              url: 'https://example.com/confuseduser',
             },
           },
         ],
diff --git a/src/jsonld/qaPage.tsx b/src/jsonld/qaPage.tsx
index 5d335e7..cdc3b67 100644
--- a/src/jsonld/qaPage.tsx
+++ b/src/jsonld/qaPage.tsx
@@ -20,12 +20,12 @@ function QAPageJsonLd({
     mainEntity: {
       ...mainEntity,
       '@type': 'Question',
-      author: setAuthor(mainEntity.author?.name),
+      author: setAuthor(mainEntity.author),
       ...(mainEntity.acceptedAnswer && {
         acceptedAnswer: {
           ...mainEntity.acceptedAnswer,
           '@type': 'Answer',
-          author: setAuthor(mainEntity.acceptedAnswer?.author?.name),
+          author: setAuthor(mainEntity.acceptedAnswer?.author),
         },
       }),
       ...(mainEntity.suggestedAnswer && {
@@ -34,7 +34,7 @@ function QAPageJsonLd({
             ...rest,
             '@type': 'Answer',
             upvoteCount: upvoteCount || 0,
-            author: setAuthor(rest.author?.name),
+            author: setAuthor(rest.author),
           }),
         ),
       }),
diff --git a/src/types.ts b/src/types.ts
index dbfe2ab..ac9ddd0 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -53,6 +53,7 @@ export type StepDetails = {
 
 export interface Person {
   name: string;
+  url?: string;
 }
 export interface Answer {
   text: string;


Test patch:
diff --git a/cypress/e2e/qaPage.spec.js b/cypress/e2e/qaPage.spec.js
index e8e91e7..ec82bd6 100644
--- a/cypress/e2e/qaPage.spec.js
+++ b/cypress/e2e/qaPage.spec.js
@@ -26,6 +26,7 @@ describe('QaPage JSON-LD', () => {
           author: {
             '@type': 'Person',
             name: 'New Baking User',
+            url: 'https://example.com/user1',
           },
           acceptedAnswer: {
             text: '1 pound (lb) is equal to 16 ounces (oz).',
@@ -35,6 +36,7 @@ describe('QaPage JSON-LD', () => {
             author: {
               '@type': 'Person',
               name: 'SomeUser',
+              url: 'https://example.com/SomeUser',
             },
             '@type': 'Answer',
           },
@@ -46,6 +48,7 @@ describe('QaPage JSON-LD', () => {
               author: {
                 '@type': 'Person',
                 name: 'AnotherUser',
+                url: 'https://example.com/AnotherUser',
               },
               '@type': 'Answer',
               upvoteCount: 42,
@@ -57,6 +60,7 @@ describe('QaPage JSON-LD', () => {
               author: {
                 '@type': 'Person',
                 name: 'ConfusedUser',
+                url: 'https://example.com/ConfusedUser',
               },
               '@type': 'Answer',
               upvoteCount: 0,
diff --git a/e2e/pages/jsonld/qaPage.tsx b/e2e/pages/jsonld/qaPage.tsx
index 216f120..50ef8b6 100644
--- a/e2e/pages/jsonld/qaPage.tsx
+++ b/e2e/pages/jsonld/qaPage.tsx
@@ -1,4 +1,3 @@
-import React from 'react';
 import { QAPageJsonLd } from '../../..';
 
 function QaPage() {
@@ -12,7 +11,7 @@ function QaPage() {
           answerCount: 3,
           upvoteCount: 26,
           dateCreated: '2016-07-23T21:11Z',
-          author: { name: 'New Baking User' },
+          author: { name: 'New Baking User', url: 'https://example.com/user1' },
           acceptedAnswer: {
             text: '1 pound (lb) is equal to 16 ounces (oz).',
             dateCreated: '2016-11-02T21:11Z',
@@ -20,6 +19,7 @@ function QaPage() {
             url: 'https://example.com/question1#acceptedAnswer',
             author: {
               name: 'SomeUser',
+              url: 'https://example.com/SomeUser',
             },
           },
           suggestedAnswer: [
@@ -30,6 +30,7 @@ function QaPage() {
               url: 'https://example.com/question1#suggestedAnswer1',
               author: {
                 name: 'AnotherUser',
+                url: 'https://example.com/AnotherUser',
               },
             },
             {
@@ -39,6 +40,7 @@ function QaPage() {
               url: 'https://example.com/question1#suggestedAnswer2',
               author: {
                 name: 'ConfusedUser',
+                url: 'https://example.com/ConfusedUser',
               },
             },
           ],
diff --git a/src/jsonld/__tests__/qaPage.spec.tsx b/src/jsonld/__tests__/qaPage.spec.tsx
new file mode 100644
index 0000000..33f4faa
--- /dev/null
+++ b/src/jsonld/__tests__/qaPage.spec.tsx
@@ -0,0 +1,74 @@
+import { render, screen } from '@testing-library/react';
+import React from 'react';
+
+import QAPageJsonLd, { QAPageJsonLdProps } from '../qaPage';
+
+describe('QAPage JSON-LD', () => {
+  it('renders author with given URL', () => {
+    const props: QAPageJsonLdProps = {
+      mainEntity: {
+        '@type': 'Question',
+        name: 'nameString',
+        text: 'textString',
+        author: {
+          name: 'johndoe',
+          url: 'https://example.com/author/johndoe',
+        },
+      },
+      scriptId: 'jsonld-qa-page',
+    };
+
+    render(<QAPageJsonLd {...props} />);
+
+    const script = screen.getByTestId('jsonld-qa-page');
+
+    const expected = {
+      '@context': 'https://schema.org',
+      '@type': 'QAPage',
+      mainEntity: {
+        '@type': 'Question',
+        name: 'nameString',
+        text: 'textString',
+        author: {
+          '@type': 'Person',
+          name: 'johndoe',
+          url: 'https://example.com/author/johndoe',
+        },
+      },
+    };
+
+    expect(script.innerHTML).toEqual(JSON.stringify(expected));
+  });
+
+  it('renders author default JSON with name only', () => {
+    const props: QAPageJsonLdProps = {
+      mainEntity: {
+        '@type': 'Question',
+        name: 'nameString',
+        text: 'textString',
+        author: 'johndoe',
+      },
+      scriptId: 'jsonld-qa-page',
+    };
+
+    render(<QAPageJsonLd {...props} />);
+
+    const script = screen.getByTestId('jsonld-qa-page');
+
+    const expected = {
+      '@context': 'https://schema.org',
+      '@type': 'QAPage',
+      mainEntity: {
+        '@type': 'Question',
+        name: 'nameString',
+        text: 'textString',
+        author: {
+          '@type': 'Person',
+          name: 'johndoe',
+        },
+      },
+    };
+
+    expect(script.innerHTML).toEqual(JSON.stringify(expected));
+  });
+});