-
Hi there! I have a custom CodeBlock component that I'm passing into MDXProvider to use for But I'm struggling to figure out how to render my CodeBlock component with an example MDX snippet. Could you point me toward an example of what children I need to pass into the CodeBlock component? Here's what I have so far: // src/components/code-block/index.test.js
import React from "react"
import { render, screen } from "@testing-library/react"
import CodeBlock from "."
test("Displays the correct title", () => {
render(
<CodeBlock>
{/* How do I pass my test MDX snippet in here? */}
```js title="my-test-file.js"
const test = "hey there!";
```
</CodeBlock>
)
const element = screen.getByText("my-test-file.js")
expect(element).toBeDefined()
}) Running that test gives me the following error (which I'm assuming is because I'm not passing children into my CodeBlock component correctly?): ● Displays the correct title
TypeError: Cannot read properties of undefined (reading 'children')
15 | const CodeBlock = (props) => {
16 | console.log('code block props', props)
> 17 | const code = props.children.props.children.trim()
| ^
18 |
19 | const className = props.children.props.className || ""
20 | const language = className.replace(/language-/, "")
at children (src/components/code-block/index.js:17:37)
at renderWithHooks (node_modules/react-dom/cjs/react-dom.development.js:16305:18)
at mountIndeterminateComponent (node_modules/react-dom/cjs/react-dom.development.js:20074:13)
at beginWork (node_modules/react-dom/cjs/react-dom.development.js:21587:16)
at beginWork$1 (node_modules/react-dom/cjs/react-dom.development.js:27426:14)
at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:26560:12)
at workLoopSync (node_modules/react-dom/cjs/react-dom.development.js:26466:5)
at renderRootSync (node_modules/react-dom/cjs/react-dom.development.js:26434:7)
at recoverFromConcurrentError (node_modules/react-dom/cjs/react-dom.development.js:25850:20)
at performConcurrentWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:25750:22)
at flushActQueue (node_modules/react/cjs/react.development.js:2667:24)
at act (node_modules/react/cjs/react.development.js:2582:11)
at node_modules/@testing-library/react/dist/act-compat.js:63:25
at renderRoot (node_modules/@testing-library/react/dist/pure.js:159:26)
at render (node_modules/@testing-library/react/dist/pure.js:246:10)
at Object.<anonymous> (src/components/code-block/index.test.js:11:9)
(And here's the CodeBlock component, if it helps:) import React from "react"
import Highlight, { defaultProps } from "prism-react-renderer"
import theme from "prism-react-renderer/themes/nightOwl"
import {
container as containerStyles,
fileTitle as fileTitleStyles,
languageTag as languageTagStyles,
preWrapper as preWrapperStyles,
pre as preStyles,
code as codeStyles,
} from "./styles.module.css"
const CodeBlock = (props) => {
const code = props.children.props.children.trim()
const className = props.children.props.className || ""
const language = className.replace(/language-/, "")
const fileTitle = props.title || ""
return (
<div className={containerStyles}>
{fileTitle != "" && (
<div className={fileTitleStyles}>
<span aria-label="file">📄</span> {fileTitle}
</div>
)}
{language && <div className={languageTagStyles}>{language}</div>}
<div className={preWrapperStyles}>
<Highlight
{...defaultProps}
code={code}
language={language}
theme={theme}
>
{({ className, tokens, getLineProps, getTokenProps }) => (
<pre className={`${className} ${preStyles}`}>
{/* for each line in the code */}
{tokens.map((line, i) => (
<code
{...getLineProps({ line, key: i })}
className={codeStyles}
>
{/* for each token in the line */}
{line.map((token, key) => (
<span {...getTokenProps({ token, key })} />
))}
</code>
))}
</pre>
)}
</Highlight>
</div>
</div>
)
}
export default CodeBlock Thanks for your help! |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 5 replies
-
Hi there Megan! :) You are trying to use your component with MDX, but your tests don’t contain MDX. In your test, you are only using JSX, to call your component ( Your component does not accept a string as a child. Your component seems to only accept a single react node as a child, which is an element ( So React crashes: your test includes code that your component doesn’t accept. Your component crashes. You can either change your test to be like something that MDX would pass. <pre>
<code className="language-js">{'const test = "hey there!";'}</code>
</pre> And to use your component instead of a <CodeBlock>
<code className="language-js">{'const test = "hey there!";'}</code>
</CodeBlock> But you can also use MDX, so you can write actual MDX, instead of having to mock it: import * as runtime from 'react/jsx-runtime'
import {renderToStaticMarkup} from 'react-dom/server'
import {evaluate} from '@mdx-js/mdx'
const mdxModule = await evaluate(`
\`\`\`js title="my-test-file.js"
const test = "hey there!";
\`\`\`
`, {...runtime, development: false})
const MdxContent = mdxModule.default
assert.equal(
renderToStaticMarkup(<MdxContent components={{pre: CodeBlock}} />),
'the string you expect',
'should support my fancy component'
) However, you also seem to be wondering about the |
Beta Was this translation helpful? Give feedback.
Hi there Megan! :)
You are trying to use your component with MDX, but your tests don’t contain MDX.
In your test, you are only using JSX, to call your component (
<CodeBlock>…</CodeBlock>
), and you are choosing to pass it a single child (```js…```
), which is just a string of text.Your component does not accept a string as a child. Your component seems to only accept a single react node as a child, which is an element (
props.children.props
).So React crashes: your test includes code that your component doesn’t accept. Your component crashes.
You can either change your test to be like something that MDX would pass.
Here’s roughly what MDX would generate: