Skip to content

Commit

Permalink
fix: render markdown tables correctly
Browse files Browse the repository at this point in the history
* Add the remark-gfm plugin
* Render autolink literals, strikethrough, tasklist and tables
  • Loading branch information
victorgcramos authored Aug 24, 2021
1 parent 54cbd2e commit 084889b
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 14 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"react-file-reader": "https://github.com/pgonzalez-santiago/react-file-reader",
"react-file-reader-input": "https://github.com/ngokevin/react-file-reader-input.git",
"react-infinite-scroller": "^1.2.4",
"react-markdown": "^6.0.2",
"react-markdown": "^6.0.3",
"react-mde": "^10.3.0-alpha1",
"react-redux": "^7.2.2",
"react-router-dom": "^4.2.2",
Expand All @@ -38,6 +38,7 @@
"redux": "^4.0.5",
"redux-form": "^8.3.7",
"redux-thunk": "^2.2.0",
"remark-gfm": "1.0.0",
"reselect": "^4.0.0",
"showdown": "^1.9.1",
"source-map-explorer": "^1.8.0",
Expand Down
2 changes: 2 additions & 0 deletions src/components/Markdown/Markdown.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React from "react";
import PropTypes from "prop-types";
import ReactMarkdown from "react-markdown";
import gfm from "remark-gfm";
import { customComponents } from "./helpers";
import "./styles.css";

Expand All @@ -16,6 +17,7 @@ const MarkdownRenderer = ({
className="markdown-body"
skipHtml={true}
unwrapDisallowed={true}
remarkPlugins={[gfm]}
components={customComponents(renderImages)}
disallowedElements={disallowedElements}>
{body}
Expand Down
61 changes: 56 additions & 5 deletions src/components/Markdown/test/Markdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ import {
ThemeProvider,
DEFAULT_LIGHT_THEME_NAME
} from "pi-ui";
import { shallow } from "enzyme";

const maliciousBodyText =
"![clickforxss](javascript:alert('XSS')) [clickforxss](javascript:alert('XSS'))";
import { shallow, mount } from "enzyme";
import * as mockData from "./mock";

describe("Test Markdown", () => {
it("should filter potencial 'XSS' attackers", () => {
const wrapper = shallow(
<ThemeProvider
themes={{ [DEFAULT_LIGHT_THEME_NAME]: defaultLightTheme }}
defaultThemeName={DEFAULT_LIGHT_THEME_NAME}>
<Markdown body={maliciousBodyText} />
<Markdown body={mockData.maliciousBodyText} />
</ThemeProvider>
);
wrapper.find("LinkRenderer").forEach((el) => {
Expand All @@ -25,4 +23,57 @@ describe("Test Markdown", () => {
);
});
});
it("should render tables correctly", () => {
const wrapper = mount(<Markdown body={mockData.tableText} />);
expect(wrapper.find("th")).toHaveLength(4);
expect(wrapper.find("tr")).toHaveLength(7);
});
it("should render headers correctly", () => {
const wrapper = mount(<Markdown body={mockData.headersText} />);
expect(wrapper.find("h1")).toHaveLength(1);
expect(wrapper.find("h2")).toHaveLength(1);
expect(wrapper.find("h3")).toHaveLength(1);
expect(wrapper.find("h4")).toHaveLength(1);
expect(wrapper.find("h5")).toHaveLength(1);
expect(wrapper.find("h6")).toHaveLength(1);
});
it("should render unordered lists correctly", () => {
const wrapper = mount(<Markdown body={mockData.unorderedListText} />);
const unorderedList = wrapper.find("ul");
expect(unorderedList).toBeDefined();
expect(unorderedList.find("li")).toHaveLength(4);
});
it("should render ordered lists correctly", () => {
const wrapper = mount(<Markdown body={mockData.orderedListText} />);
const orderedList = wrapper.find("ol");
expect(orderedList).toHaveLength(2);

const parent = orderedList.at(0);
expect(parent.find("li")).toHaveLength(5);

const sublist = orderedList.at(1);
expect(sublist.find("li")).toHaveLength(2);
});
it("should render blockquotes correctly", () => {
const wrapper = mount(<Markdown body={mockData.blockQuotesText} />);
const parent = wrapper.find("blockquote").at(0);
expect(wrapper.find("blockquote")).toHaveLength(2);
expect(parent.children().find("blockquote")).toHaveLength(1);
});
it("should rener codeblocks correctly", () => {
const wrapper = mount(<Markdown body={mockData.codeBlocksText} />);
expect(wrapper.find("code")).toHaveLength(1);
expect(wrapper.find("pre")).toHaveLength(1);
});
it("should not render disabled elements", () => {
const wrapper = mount(
<Markdown body={mockData.headersText} disallowedElements={["h1", "h2"]} />
);
expect(wrapper.contains("h1")).toBe(false);
expect(wrapper.contains("h2")).toBe(false);
expect(wrapper.find("h3")).toHaveLength(1);
expect(wrapper.find("h4")).toHaveLength(1);
expect(wrapper.find("h5")).toHaveLength(1);
expect(wrapper.find("h6")).toHaveLength(1);
});
});
47 changes: 47 additions & 0 deletions src/components/Markdown/test/mock.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
export const maliciousBodyText =
"![clickforxss](javascript:alert('XSS')) [clickforxss](javascript:alert('XSS'))";

export const tableText = `| Area | Spent | Allocated | Remaining |
| :------------------ | -----: | ---------: | ----------: |
| Decred Journal | $7,320 | $11,340 | **$4,020** |
| website translation | $0 | $1,680 | **$1,680** |
| articles/content | $1,445 | $4,410 | **$2,965** |
| video content | $1,940 | $10,080 | **$8,140** |
| software | $3,945 | $1,260 | **-$2,685** |
| management | $40 | $360 | **$320** |`;

export const headersText = `# header 1
## header 2
### header 3
#### header 4
##### header 5
###### header 6
`;

export const unorderedListText = `
* Item 1
* Item 2
* Item 2a
* Item 2b
`;

export const orderedListText = `
1. Item 1
1. Item 2
1. Item 3
1. Item 3a
1. Item 3b
`;

export const blockQuotesText = `
> Quote 1
>
>> Quote 2.
`;

export const codeBlocksText = `
\`\`\`
let message = 'Hello world';
alert(message);
\`\`\`
`;
Loading

0 comments on commit 084889b

Please sign in to comment.