Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: LiveBlogPosting #1471

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ Remember, every time you make a change to the library you will need to re-run `y

To run Cypress:

First compile all your changes to `nex-seo` made in the `src` directory:
First compile all your changes to `next-seo` made in the `src` directory:

```
yarn build
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
60 changes: 60 additions & 0 deletions cypress/e2e/article.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,4 +132,64 @@ describe('Article JSON-LD', () => {
});
});
});

it('matches schema when type LiveBlogPosting', () => {
Cypress.log({ message: 'azerty' });
cy.visit('http://localhost:3000/jsonld/liveBlogPosting');
cy.get('head script[type="application/ld+json"]').then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
assertSchema(schemas)('LiveBlogPosting', '1.0.0')(jsonLD);
});
});

it('renders with all props when type LiveBlogPosting', () => {
cy.visit('http://localhost:3000/jsonld/liveBlogPosting');
cy.get('head script[type="application/ld+json"]').then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'https://schema.org',
'@type': 'LiveBlogPosting',
datePublished: '2023-11-03T11:00:00+02:00',
description:
'Follow the announcements made during the 2023 Next.js Conf.',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': 'https://example.com/liveblog',
},
headline: 'Next.js Conf live coverage',
image: [
'https://example.com/photos/1x1/photo.jpg',
'https://example.com/photos/4x3/photo.jpg',
'https://example.com/photos/16x9/photo.jpg',
],
dateModified: '2023-11-03T19:00:00+02:00',
author: {
'@type': 'Person',
name: 'Jane Blogs',
},
coverageStartTime: '2023-11-03T11:00:00+02:00',
coverageEndTime: '2023-11-03T19:00:00+02:00',
liveBlogUpdate: [
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The liveBlogUpdate items could contain plenty of additional props because they are instances of BlogPosting but I decided to keep it short.

{
'@type': 'BlogPosting',
headline: 'Next.js 14: No New APIs',
articleBody: 'Lorem ipsum dolor sit amet …',
datePublished: '2023-11-03T18:15:00+02:00',
},
{
'@type': 'BlogPosting',
headline: 'A faster, more personalized web.',
articleBody: 'Lorem ipsum dolor sit amet …',
datePublished: '2023-11-03T11:30:00+02:00',
},
{
'@type': 'BlogPosting',
headline: 'Conference will start soon',
articleBody: 'In a few hours …',
datePublished: '2023-11-03T11:00:00+02:00',
},
],
});
});
});
});
3 changes: 1 addition & 2 deletions cypress/schemas/blog-schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,5 @@ const blog100 = {
description: 'This is a mighty good description of this blog.',
},
};

const blogVersions = versionSchemas(blog100);
export default blogVersions;
export { blogVersions as default, blog100 };
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Needed to reuse the schema inside the liveblog-schema.js

3 changes: 2 additions & 1 deletion cypress/schemas/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { combineSchemas } from '@cypress/schema-tools';
import articleVersions from './article-schema';
import breadCrumbVersions from './breadcrumb-schema';
import blogVersions from './blog-schema';
import liveBlogVersions from './liveblog-schema';
import courseVersions from './course-schema';
import localBusiness from './local-business-schema';
import logoVersions from './logo-schema';
Expand Down Expand Up @@ -30,11 +31,11 @@ import imageVersions from './image-schema';
import campgroundVersions from './campground-schema';
import parkVersions from './park-schema';


const schemas = combineSchemas(
articleVersions,
breadCrumbVersions,
blogVersions,
liveBlogVersions,
courseVersions,
localBusiness,
logoVersions,
Expand Down
72 changes: 72 additions & 0 deletions cypress/schemas/liveblog-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { versionSchemas } from '@cypress/schema-tools';
import { blog100 } from './blog-schema';

const liveblog100 = {
...blog100,
schema: {
...blog100.schema,
title: 'LiveBlogPosting',
description:
'An example schema describing JSON-LD for type: LiveBlogPosting',
properties: {
...blog100.schema.properties,
coverageStartTime: {
type: 'string',
description:
'The time when the live blog will begin covering the Event. ' +
"Note that coverage may begin before the Event's start time. The LiveBlogPosting may also be created before coverage begins.",
},
coverageEndTime: {
type: 'string',
description:
'The time when the live blog will stop covering the Event. Note that coverage may continue after the Event concludes.',
},
liveBlogUpdate: {
type: 'array',
items: {
...blog100.schema,
required: ['@type'],
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not all the properties of BlogPosting are required, where could I find out which props are really required in this context ?

additionalProperties: true,
},
description: 'Array of blog posting updates',
},
},
},
example: {
...blog100.example,
'@type': 'LiveBlogPosting',
dateModified: '2024-05-08T22:15:00+02:00',
datePublished: '2024-05-08T11:13:18+02:00',
mainEntityOfPage: {
'@type': 'WebPage',
'@id': 'https://example.com/liveblog',
},
headline: 'LiveBlog headline',
coverageStartTime: '2024-05-08T09:00:01+02:00',
coverageEndTime: '2024-05-09T09:00:01+02:00',
liveBlogUpdate: [
{
'@type': 'BlogPosting',
datePublished: '2024-05-08T22:15:00+02:00',
headline: 'Final update',
articleBody: 'See you soon',
},
{
'@type': 'BlogPosting',
datePublished: '2024-05-08T09:00:00+02:00',
headline: 'Hello',
articleBody: 'Live coverage demo.',
},
],
},
};

// Despite the liveBlogUpdate's required config, we must
['author', 'mainEntityOfPage'].forEach(key => {
liveblog100.schema.properties.liveBlogUpdate.items.properties[
key
].required = false;
});
Comment on lines +65 to +69
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even with required: ['@type'],, the properties:

  • author
  • mainEntityOfPage

are still reported as missing in the E2E tests. As we are using instances BlogPosting as children of liveBlogUpdate these should be optional.


const liveBlogVersions = versionSchemas(liveblog100);
export default liveBlogVersions;
49 changes: 49 additions & 0 deletions e2e/pages/jsonld/liveBlogPosting.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { ArticleJsonLd } from '../../..';

function LiveBlogPosting() {
return (
<>
<h1>LiveBlogPosting</h1>
<ArticleJsonLd
type="LiveBlogPosting"
url="https://example.com/liveblog"
title="Next.js Conf live coverage"
images={[
'https://example.com/photos/1x1/photo.jpg',
'https://example.com/photos/4x3/photo.jpg',
'https://example.com/photos/16x9/photo.jpg',
]}
datePublished="2023-11-03T11:00:00+02:00"
dateModified="2023-11-03T19:00:00+02:00"
authorName="Jane Blogs"
description="Follow the announcements made during the 2023 Next.js Conf."
coverageStartTime="2023-11-03T11:00:00+02:00"
coverageEndTime="2023-11-03T19:00:00+02:00"
liveBlogUpdate={[
// From newer to older updates of type BlogPosting
{
'@type': 'BlogPosting',
headline: 'Next.js 14: No New APIs',
articleBody: 'Lorem ipsum dolor sit amet …',
datePublished: '2023-11-03T18:15:00+02:00',
},
{
'@type': 'BlogPosting',
headline: 'A faster, more personalized web.',
articleBody: 'Lorem ipsum dolor sit amet …',
datePublished: '2023-11-03T11:30:00+02:00',
},
{
'@type': 'BlogPosting',
headline: 'Conference will start soon',
articleBody: 'In a few hours …',
datePublished: '2023-11-03T11:00:00+02:00',
},
]}
Comment on lines +23 to +43
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the correct way to declare the BlogPosting updates ? Feedbacks are welcome 👍

/>
</>
);
}

export default LiveBlogPosting;
2 changes: 1 addition & 1 deletion src/jsonld/article.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { setPublisher } from 'src/utils/schema/setPublisher';
import { ArticleAuthor } from 'src/types';

export interface ArticleJsonLdProps extends JsonLdProps {
type?: 'Article' | 'BlogPosting' | 'NewsArticle' | 'Blog';
type?: 'Article' | 'BlogPosting' | 'LiveBlogPosting' | 'NewsArticle' | 'Blog';
url: string;
title: string;
images: ReadonlyArray<string>;
Expand Down