Skip to content

Commit

Permalink
fix: serialize script elements wrapped in components
Browse files Browse the repository at this point in the history
  • Loading branch information
keplersj committed Nov 21, 2019
1 parent f98247e commit b565405
Show file tree
Hide file tree
Showing 6 changed files with 176 additions and 15 deletions.
31 changes: 31 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions package.json
Expand Up @@ -51,6 +51,7 @@
"@types/jest": "^24.0.17",
"@types/node": "^12.7.2",
"@types/react": "^16.8.25",
"@types/react-test-renderer": "^16.9.1",
"@typescript-eslint/eslint-plugin": "^2.0.0",
"@typescript-eslint/parser": "^2.0.0",
"eslint": "^6.1.0",
Expand All @@ -63,6 +64,7 @@
"jest-runner-prettier": "^0.3.1",
"prettier": "^1.18.2",
"react": "^16.9.0",
"react-test-renderer": "^16.12.0",
"semantic-release": "^15.13.21",
"ts-jest": "^24.0.2",
"typescript": "^3.5.3"
Expand Down
54 changes: 54 additions & 0 deletions src/__snapshots__/index.test.tsx.snap
Expand Up @@ -8,6 +8,60 @@ exports[`Serialization function serializes a JSON+LD script element with data se
</script>
`;

exports[`Serialization function serializes a script element created using React.createElement 1`] = `
<script
type="application/ld+json"
>
Object {
"@context": "http://schema.org",
"@id": "https://example.dev/example_thing",
"@type": "Thing",
}
</script>
`;

exports[`Serialization function serializes a script element with data correctly 1`] = `
<script
type="application/ld+json"
>
Object {
"@context": "http://schema.org",
"@id": "https://example.dev/example_thing",
"@type": "Thing",
}
</script>
`;

exports[`Serialization function serializes a script element wrapped in a component 1`] = `
<div>
<div>
<script
type="application/ld+json"
>
Object {
"@context": "http://schema.org",
"@id": "https://example.dev/example_thing",
"@type": "Thing",
}
</script>
</div>
</div>
`;

exports[`Serialization function serializes a wrapped script element with data correctly 1`] = `
<div>
<script
type="application/ld+json"
>
Object {
"@context": "http://schema.org",
"@id": "https://example.dev/example_thing",
"@type": "Thing",
}
</script>
</div>
`;

exports[`Serialization module matches expectations 1`] = `
Object {
"print": [Function],
Expand Down
82 changes: 82 additions & 0 deletions src/index.test.tsx
@@ -1,4 +1,5 @@
import * as React from "react";
import renderer from "react-test-renderer";
import serializer from ".";

describe("Serializer test function", () => {
Expand Down Expand Up @@ -65,6 +66,87 @@ describe("Serialization function", () => {

expect(ldScriptElement).toMatchSnapshot();
});

it("serializes a script element with data correctly", () => {
expect.addSnapshotSerializer(serializer);

const element = (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "http://schema.org",
"@type": "Thing",
"@id": "https://example.dev/example_thing"
})
}}
/>
);

expect(element).toMatchSnapshot();
});

it("serializes a wrapped script element with data correctly", () => {
expect.addSnapshotSerializer(serializer);

const element = (
<div>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "http://schema.org",
"@type": "Thing",
"@id": "https://example.dev/example_thing"
})
}}
/>
</div>
);

expect(element).toMatchSnapshot();
});

it("serializes a script element created using React.createElement", () => {
expect.addSnapshotSerializer(serializer);

const element = React.createElement("script", {
type: "application/ld+json",
dangerouslySetInnerHTML: {
__html: JSON.stringify({
"@context": "http://schema.org",
"@type": "Thing",
"@id": "https://example.dev/example_thing"
})
}
});

expect(element).toMatchSnapshot();
});

it("serializes a script element wrapped in a component", () => {
expect.addSnapshotSerializer(serializer);

const Component = () => (
<div>
<div>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{
__html: JSON.stringify({
"@context": "http://schema.org",
"@type": "Thing",
"@id": "https://example.dev/example_thing"
})
}}
/>
</div>
</div>
);

const tree = renderer.create(<Component />).toJSON();
expect(tree).toMatchSnapshot();
});
});

describe("Serialization module", () => {
Expand Down
16 changes: 4 additions & 12 deletions src/index.tsx
@@ -1,22 +1,14 @@
/* eslint-disable @typescript-eslint/no-explicit-any */

import * as React from "react";

function hasValidProps(val: any): boolean {
return Boolean(
val.props.dangerouslySetInnerHTML &&
val.props.type &&
val.props.type === "application/ld+json"
);
}

const JSONLDSerializer: jest.SnapshotSerializerPlugin = {
test(val) {
return Boolean(
val &&
React.isValidElement(val) &&
// React.isValidElement(val) && // Previously we were using this API to shortcut testing if an object was a React object, but this produces false negatives on <script/> elements wrapped in Components. While it might take longer to fail on some tests, it should produce a negligable effect.
val.type === "script" &&
hasValidProps(val)
val.props.dangerouslySetInnerHTML &&
val.props.type &&
val.props.type === "application/ld+json"
);
},

Expand Down
6 changes: 3 additions & 3 deletions tsconfig.json
Expand Up @@ -8,9 +8,9 @@
// "allowJs": true, /* Allow javascript files to be compiled. */
// "checkJs": true, /* Report errors in .js files. */
"jsx": "react" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */,
// "declaration": true, /* Generates corresponding '.d.ts' file. */
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
// "sourceMap": true, /* Generates corresponding '.map' file. */
"declaration": true /* Generates corresponding '.d.ts' file. */,
"declarationMap": true /* Generates a sourcemap for each corresponding '.d.ts' file. */,
"sourceMap": true /* Generates corresponding '.map' file. */,
// "outFile": "./", /* Concatenate and emit output to single file. */
"outDir": "./dist" /* Redirect output structure to the directory. */,
// "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
Expand Down

0 comments on commit b565405

Please sign in to comment.