Skip to content

Commit

Permalink
Add support for JSON LD breadcrumb (#30)
Browse files Browse the repository at this point in the history
  • Loading branch information
timReynolds authored and garmeeh committed Dec 28, 2018
1 parent c1d7dd7 commit 5d619a7
Show file tree
Hide file tree
Showing 7 changed files with 280 additions and 15 deletions.
47 changes: 47 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -492,6 +492,7 @@ Google has excellent content on JSON-LD -> [HERE](https://developers.google.com/
Below you will find a very basic page implementing each of the available JSON-LD types:

- [Article](#article)
- [Breadcrumb](#breadcrumb)
- [Blog](#blog)
- [Course](#course)
- [Local Business](#local-business)
Expand Down Expand Up @@ -528,6 +529,52 @@ export default () => (
);
```

### Breadcrumb

```jsx
import React from 'react';
import { BreadcrumbJsonLb } from 'next-seo';

export default () => (
<>
<h1>Breadcrumb JSON-LD</h1>
<BreadcrumbJsonLd
itemListElements={[
{
position: 1,
name: 'Books',
item: 'https://example.com/books',
},
{
position: 2,
name: 'Authors',
item: 'https://example.com/books/authors',
},
{
position: 3,
name: 'Ann Leckie',
item: 'https://example.com/books/authors/annleckie',
},
{
position: 4,
name: 'Ancillary Justice',
item: 'https://example.com/books/authors/ancillaryjustice',
},
]}
/>
</>
);
```

**Required properties**

| Property | Info |
| --------------------------- | -------------------------------------------------------------------------------------------------------- |
| `itemListElements` | |
| `itemListElements.position` | The position of the breadcrumb in the breadcrumb trail. Position 1 signifies the beginning of the trail. |
| `itemListElements.name` | The title of the breadcrumb displayed for the user. |
| `itemListElements.item` | The URL to the webpage that represents the breadcrumb. |

### Blog

```jsx
Expand Down
88 changes: 73 additions & 15 deletions e2e/cypress/e2e/jsonld.spec.js
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
import { assertSchema } from '@cypress/schema-tools';
import schemas from '../schemas';

const expectedJSONResults = 7;
const expectedJSONResults = 8;

const articleLdJsonIndex = 0;
const breadcrumbLdJsonIndex = 1;
const blogLdJsonIndex = 2;
const courseLdJsonIndex = 3;
const localBusinessLdJsonIndex = 4;
const logoLdJsonIndex = 5;
const productLdJsonIndex = 6;
const socialProfileLdJsonIndex = 7;

describe('Validates JSON-LD For:', () => {
it('Article', () => {
cy.visit('http://localhost:3000/jsonld');
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
const jsonLD = JSON.parse(tags[articleLdJsonIndex].innerHTML);
assertSchema(schemas)('Article', '1.0.0')(jsonLD);
});
});
Expand All @@ -19,7 +28,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[0].innerHTML);
const jsonLD = JSON.parse(tags[articleLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'Article',
Expand Down Expand Up @@ -52,12 +61,61 @@ describe('Validates JSON-LD For:', () => {
});
});

it('Breadcrumb', () => {
cy.visit('http://localhost:3000/jsonld');
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[breadcrumbLdJsonIndex].innerHTML);
assertSchema(schemas)('Breadcrumb', '1.0.0')(jsonLD);
});
});

it('Breadcrumb Matches', () => {
cy.visit('http://localhost:3000/jsonld');
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[breadcrumbLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Books',
item: 'https://example.com/books',
},
{
'@type': 'ListItem',
position: 2,
name: 'Authors',
item: 'https://example.com/books/authors',
},
{
'@type': 'ListItem',
position: 3,
name: 'Ann Leckie',
item: 'https://example.com/books/authors/annleckie',
},
{
'@type': 'ListItem',
position: 4,
name: 'Ancillary Justice',
item: 'https://example.com/books/authors/ancillaryjustice',
},
],
});
});
});

it('Blog', () => {
cy.visit('http://localhost:3000/jsonld');
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[1].innerHTML);
const jsonLD = JSON.parse(tags[blogLdJsonIndex].innerHTML);
assertSchema(schemas)('Blog', '1.0.0')(jsonLD);
});
});
Expand All @@ -67,7 +125,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[1].innerHTML);
const jsonLD = JSON.parse(tags[blogLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'Blog',
Expand Down Expand Up @@ -97,7 +155,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[2].innerHTML);
const jsonLD = JSON.parse(tags[courseLdJsonIndex].innerHTML);
assertSchema(schemas)('Course', '1.0.0')(jsonLD);
});
});
Expand All @@ -107,7 +165,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[2].innerHTML);
const jsonLD = JSON.parse(tags[courseLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'Course',
Expand All @@ -127,7 +185,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[3].innerHTML);
const jsonLD = JSON.parse(tags[localBusinessLdJsonIndex].innerHTML);
assertSchema(schemas)('Local Business', '1.0.0')(jsonLD);
});
});
Expand All @@ -137,7 +195,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[3].innerHTML);
const jsonLD = JSON.parse(tags[localBusinessLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'Store',
Expand Down Expand Up @@ -174,7 +232,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[4].innerHTML);
const jsonLD = JSON.parse(tags[logoLdJsonIndex].innerHTML);
assertSchema(schemas)('Logo', '1.0.0')(jsonLD);
});
});
Expand All @@ -184,7 +242,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[4].innerHTML);
const jsonLD = JSON.parse(tags[logoLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'Organization',
Expand All @@ -199,7 +257,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[5].innerHTML);
const jsonLD = JSON.parse(tags[productLdJsonIndex].innerHTML);
assertSchema(schemas)('Product', '1.0.0')(jsonLD);
});
});
Expand All @@ -209,7 +267,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[5].innerHTML);
const jsonLD = JSON.parse(tags[productLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org/',
'@type': 'Product',
Expand Down Expand Up @@ -268,7 +326,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[6].innerHTML);
const jsonLD = JSON.parse(tags[socialProfileLdJsonIndex].innerHTML);
assertSchema(schemas)('Social Profile', '1.0.0')(jsonLD);
});
});
Expand All @@ -278,7 +336,7 @@ describe('Validates JSON-LD For:', () => {
cy.get('head script[type="application/ld+json"]')
.should('have.length', expectedJSONResults)
.then(tags => {
const jsonLD = JSON.parse(tags[6].innerHTML);
const jsonLD = JSON.parse(tags[socialProfileLdJsonIndex].innerHTML);
expect(jsonLD).to.deep.equal({
'@context': 'http://schema.org',
'@type': 'Person',
Expand Down
86 changes: 86 additions & 0 deletions e2e/cypress/schemas/breadcrumb-schema.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
import { versionSchemas } from '@cypress/schema-tools';

const breadcrumb100 = {
version: {
major: 1,
minor: 0,
patch: 0,
},
schema: {
type: 'object',
title: 'Breadcrumb',
description: 'An example schema describing JSON-LD for type: Breadcrumb',
properties: {
'@context': {
type: 'string',
description: 'Schema.org context',
},
'@type': {
type: 'string',
description: 'BreadcrumbList',
},
itemListElement: {
type: 'array',
item: {
type: 'object',
properties: {
'@type': {
type: 'string',
description: 'ListItem',
},
item: {
type: 'string',
description:
'The URL to the webpage that represents the breadcrumb.',
},
name: {
type: 'string',
description:
'The title of the breadcrumb displayed for the user.',
},
position: {
type: 'string',
description:
'The position of the breadcrumb in the breadcrumb trail. Position 1 signifies the beginning of the trail.',
},
},
},
},
},
required: true,
additionalProperties: false,
},
example: {
'@context': 'http://schema.org',
'@type': 'BreadcrumbList',
itemListElement: [
{
'@type': 'ListItem',
position: 1,
name: 'Books',
item: 'https://example.com/books',
},
{
'@type': 'ListItem',
position: 2,
name: 'Authors',
item: 'https://example.com/books/authors',
},
{
'@type': 'ListItem',
position: 3,
name: 'Ann Leckie',
item: 'https://example.com/books/authors/annleckie',
},
{
'@type': 'ListItem',
position: 4,
name: 'Ancillary Justice',
item: 'https://example.com/books/authors/ancillaryjustice',
},
],
},
};

const breadcrumbVersions = versionSchemas(breadcrumb100);
export default breadcrumbVersions;
2 changes: 2 additions & 0 deletions e2e/cypress/schemas/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { combineSchemas } from '@cypress/schema-tools';

import articleVersions from './article-schema';
import breadCrumbVersions from './breadcrumb-schema';
import blogVersions from './blog-schema';
import courseVersions from './course-schema';
import localBusiness from './local-business-schema';
Expand All @@ -10,6 +11,7 @@ import socialProfileVersions from './social-profile-schema';

const schemas = combineSchemas(
articleVersions,
breadCrumbVersions,
blogVersions,
courseVersions,
localBusiness,
Expand Down
Loading

0 comments on commit 5d619a7

Please sign in to comment.