diff --git a/README.md b/README.md
index 126f659..3569c77 100644
--- a/README.md
+++ b/README.md
@@ -19,13 +19,24 @@ npm i --save-dev react-assert
### Usage
+Imports:
+
```javascript
import React from "react";
import TestRenderer from "react-test-renderer";
+import assert from "node:assert/strict";
+import mockFunction from "mock-fn";
+
+import {
+ assertComponents,
+ mockComponent,
+ TestErrorBoundary,
+} from "react-assert";
+```
-// 1. import
-import { assertComponents, mockComponent } from "react-assert";
+Components:
+```javascript
function SubComponent() {
return
Sub
;
}
@@ -43,7 +54,11 @@ function MyComponent(props) {
}
MyComponent.displayName = "MyComponent";
MyComponent.SubComp = SubComponent;
+```
+Tests:
+
+```javascript
describe("MyComponent", () => {
it("should render nested components", () => {
//given
@@ -53,7 +68,7 @@ describe("MyComponent", () => {
const result = TestRenderer.create().root;
//then
- // 2. call assertComponents to check expected components tree
+ // call assertComponents to check expected components tree
assertComponents(
result.children,
@@ -65,7 +80,7 @@ describe("MyComponent", () => {
it("should render mock components", () => {
//given
- // 3. use mockComponent to mock nested components
+ // use mockComponent to mock nested components
MyComponent.SubComp = mockComponent(SubComponent);
const { SubComp } = MyComponent;
const text = "Hello";
@@ -82,5 +97,33 @@ describe("MyComponent", () => {
);
});
+
+ it("should render error details if error during render", () => {
+ //given
+ // suppress intended error
+ // see: https://github.com/facebook/react/issues/11098#issuecomment-412682721
+ const savedConsoleError = console.error;
+ const consoleErrorMock = mockFunction(() => {
+ console.error = savedConsoleError;
+ });
+ console.error = consoleErrorMock;
+
+ const ErrorComp = () => {
+ throw Error("test error");
+ return <>{"Not rendered"}>;
+ };
+
+ //when
+ const result = TestRenderer.create(
+
+
+
+ ).root;
+
+ //then
+ assert.deepEqual(consoleErrorMock.times, 1);
+ assert.deepEqual(console.error, savedConsoleError);
+ assertComponents(result.children, {"Error: test error"}
);
+ });
});
```
diff --git a/index.d.ts b/index.d.ts
index 9d224bf..a424cd1 100644
--- a/index.d.ts
+++ b/index.d.ts
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { Component } from "react";
import TestRenderer from "react-test-renderer";
export function assertComponent(
@@ -14,3 +14,9 @@ export function assertComponents(
export function mockComponent<
T = React.FunctionComponent | React.ComponentClass
>(comp: T, name?: string): T;
+
+interface State {
+ error?: object;
+}
+
+export class TestErrorBoundary extends Component {}
diff --git a/index.mjs b/index.mjs
index 8cc64f3..6d37a06 100644
--- a/index.mjs
+++ b/index.mjs
@@ -1,3 +1,4 @@
export { default as assertComponent } from "./src/assertComponent.mjs";
export { default as assertComponents } from "./src/assertComponents.mjs";
export { default as mockComponent } from "./src/mockComponent.mjs";
+export { default as TestErrorBoundary } from "./src/TestErrorBoundary.mjs";
diff --git a/package.json b/package.json
index 3cf780c..18630b5 100644
--- a/package.json
+++ b/package.json
@@ -42,6 +42,7 @@
"@types/react": "^17.0.1",
"@types/react-test-renderer": "^17.0.1",
"c8": "^7.13.0",
+ "mock-fn": "^1.0.0",
"prettier": "^2.8.8",
"react": "^17.0.1",
"react-test-renderer": "^17.0.1",
diff --git a/src/TestErrorBoundary.mjs b/src/TestErrorBoundary.mjs
new file mode 100644
index 0000000..8e41923
--- /dev/null
+++ b/src/TestErrorBoundary.mjs
@@ -0,0 +1,42 @@
+import React, { Component } from "react";
+
+const h = React.createElement;
+
+/**
+ * @typedef State
+ * @prop {object} [error]
+ */
+
+/**
+ * @extends Component
+ */
+class TestErrorBoundary extends Component {
+ /** @type {State} */
+ state = {
+ error: undefined,
+ };
+
+ /**
+ * @param {any} props
+ */
+ constructor(props) {
+ super(props);
+ }
+
+ /**
+ * @param {object} [error]
+ */
+ componentDidCatch(error) {
+ this.setState({
+ error,
+ });
+ }
+
+ render() {
+ const error = this.state.error;
+ return error ? h("div", null, `${error}`) : this.props.children;
+ }
+}
+TestErrorBoundary.displayName = "TestErrorBoundary";
+
+export default TestErrorBoundary;
diff --git a/test/TestErrorBoundary.test.mjs b/test/TestErrorBoundary.test.mjs
new file mode 100644
index 0000000..d786a1d
--- /dev/null
+++ b/test/TestErrorBoundary.test.mjs
@@ -0,0 +1,52 @@
+import React from "react";
+import TestRenderer from "react-test-renderer";
+import assert from "node:assert/strict";
+import mockFunction from "mock-fn";
+import { assertComponents, TestErrorBoundary } from "../index.mjs";
+
+const h = React.createElement;
+
+const { describe, it } = await (async () => {
+ // @ts-ignore
+ return process.isBun // @ts-ignore
+ ? Promise.resolve({ describe: (_, fn) => fn(), it: test })
+ : import("node:test");
+})();
+
+describe("TestErrorBoundary.test.mjs", () => {
+ it("should render children if no errors", () => {
+ //when
+ const result = TestRenderer.create(
+ h(TestErrorBoundary, null, "some child")
+ ).root;
+
+ //then
+ assertComponents(result.children, "some child");
+ });
+
+ it("should render error details if error during render", () => {
+ //given
+ // suppress intended error
+ // see: https://github.com/facebook/react/issues/11098#issuecomment-412682721
+ const savedConsoleError = console.error;
+ const consoleErrorMock = mockFunction(() => {
+ console.error = savedConsoleError;
+ });
+ console.error = consoleErrorMock;
+
+ const ErrorComp = () => {
+ throw Error("test error");
+ return h(React.Fragment);
+ };
+
+ //when
+ const result = TestRenderer.create(
+ h(TestErrorBoundary, null, h(ErrorComp))
+ ).root;
+
+ //then
+ assert.deepEqual(consoleErrorMock.times, 1);
+ assert.deepEqual(console.error, savedConsoleError);
+ assertComponents(result.children, h("div", null, "Error: test error"));
+ });
+});
diff --git a/test/all.mjs b/test/all.mjs
index 28b4a6a..53a9a03 100644
--- a/test/all.mjs
+++ b/test/all.mjs
@@ -2,3 +2,4 @@ await import("./testRenderer.test.mjs");
await import("./assertComponent.test.mjs");
await import("./assertComponents.test.mjs");
await import("./mockComponent.test.mjs");
+await import("./TestErrorBoundary.test.mjs");