UNPKG

reblend-testing-library

Version:

Simple and complete Reblendjs testing utilities that encourage good testing practices.

271 lines (264 loc) 8.23 kB
"use strict"; var _reblendjs = require("reblendjs"); var _ = require("../"); describe("render API", () => { let originalConfig; beforeEach(() => { // Grab the existing configuration so we can restore // it at the end of the test (0, _.configure)(existingConfig => { originalConfig = existingConfig; // Don't change the existing config return {}; }); }); afterEach(() => { (0, _.configure)(originalConfig); }); test("renders div into document", async () => { const ref = (0, _reblendjs.useRef)(); const { container } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)("div", { ref: ref })); expect(container.firstChild).toBe(ref.current); }); test("works great with reblendjs portals", async () => { class MyPortal extends _reblendjs.Reblend { initState(...args) { super.initState(...args); this.portalNode = document.createElement("div"); this.portalNode.dataset.testid = "my-portal"; } componentDidMount() { document.body.appendChild(this.portalNode); } componentWillUnmount() { this.portalNode.parentNode.removeChild(this.portalNode); } html() { return _reblendjs.Reblend.construct.bind(this)(_reblendjs.Portal, { portal: this.portalNode }, _reblendjs.Reblend.construct.bind(this)(Greet, { greeting: "Hello", subject: "World" }), ","); } } class Greet extends _reblendjs.Reblend { static ELEMENT_NAME = "Greet"; constructor() { super(); } async initState() {} async initProps({ greeting, subject }) { this.props = {}; this.props.greeting = greeting; this.props.subject = subject; } async html() { return _reblendjs.Reblend.construct.bind(this)("div", null, _reblendjs.Reblend.construct.bind(this)("strong", null, this.props.greeting, " ", this.props.subject)); } } /* @Reblend: Transformed from function to class */ const { unmount } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)(MyPortal, null)); expect(_.screen.getByText("Hello World")).toBeInTheDocument(); const portalNode = _.screen.getByTestId("my-portal"); expect(portalNode).toBeInTheDocument(); await unmount(); expect(portalNode).not.toBeInTheDocument(); }); test("returns baseElement which defaults to document.body", async () => { const { baseElement } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)("div", null)); expect(baseElement).toBe(document.body); }); test("supports fragments", async () => { class Test extends _reblendjs.Reblend { html() { return _reblendjs.Reblend.construct.bind(this)("div", null, _reblendjs.Reblend.construct.bind(this)("code", null, "DocumentFragment"), " is pretty cool!"); } } const { asFragment } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)(Test, null)); expect(asFragment()).toMatchSnapshot(); }); test("renders options.wrapper around node", async () => { //@reblendComponent class WrapperComponent extends _reblendjs.Reblend { static ELEMENT_NAME = "WrapperComponent"; constructor() { super(); } async initState() {} async initProps({ children }) { this.props = {}; this.props.children = children; } async html() { return _reblendjs.Reblend.construct.bind(this)("div", { "data-testid": "wrapper" }, this.props.children); } } /* @Reblend: Transformed from function to class */ const { container } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)("div", { "data-testid": "inner" }), { wrapper: WrapperComponent }); expect(_.screen.getByTestId("wrapper")).toBeInTheDocument(); expect(container.firstChild).toMatchInlineSnapshot(` <div reblendcomponent="WrapperComponent" > <div data-testid="wrapper" > <div data-testid="inner" > </div> </div> </div> `); }); test("renders", async () => { const spy = jest.fn(); //@reblendComponent class Component extends _reblendjs.Reblend { static ELEMENT_NAME = "Component"; constructor() { super(); } async initState() { this.props.spy(); } async initProps({ spy }) { this.props = {}; this.props.spy = spy; } async html() { return _reblendjs.Reblend.construct.bind(this)(_reblendjs.Reblend, null); } } /* @Reblend: Transformed from function to class */ await (0, _.render)(_reblendjs.Reblend.construct.bind(this)(Component, { spy: spy })); expect(spy).toHaveBeenCalledTimes(1); }); test("flushes useEffect cleanup functions sync on unmount()", async () => { const spy = jest.fn(); //@reblendComponent class Component extends _reblendjs.Reblend { static ELEMENT_NAME = "Component"; constructor() { super(); } async initState() { _reblendjs.useEffect.bind(this)(() => this.props.spy, (() => []).bind(this)); } async initProps({ spy }) { this.props = {}; this.props.spy = spy; } async html() { return _reblendjs.Reblend.construct.bind(this)(_reblendjs.Reblend, null); } } /* @Reblend: Transformed from function to class */ const { unmount } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)(Component, { spy: spy })); expect(spy).toHaveBeenCalledTimes(0); await unmount(); expect(spy).toHaveBeenCalledTimes(1); }); test("can be called multiple times on the same container", async () => { const container = document.createElement("div"); const { unmount } = await (0, _.render)(_reblendjs.Reblend.construct.bind(this)("strong", null), { container }); expect(container).toContainHTML("<strong></strong>"); await (0, _.render)(_reblendjs.Reblend.construct.bind(this)("em", null), { container }); expect(container).toContainHTML("<em></em>"); await unmount(); expect(container).toBeEmptyDOMElement(); }); /* test('The UI should be interactive', async () => { //@reblendComponent function App() { const [clicked, handleClick] = useReducer(n => n + 1, 0) return ( <button type="button" onClick={handleClick}> clicked:{clicked} </button> ) } const ui = <App /> const container = document.createElement('div') document.body.appendChild(container) container.innerHTML = await Reblend.renderToString(ui) expect(container).toHaveTextContent('clicked:0') await render(ui, {container}) fireEvent.click(container.querySelector('button')) expect(container).toHaveTextContent('clicked:1') }) */ test("Render with a wrapper", async () => { const wrapperComponentMountEffect = jest.fn(); const ui = _reblendjs.Reblend.construct.bind(this)("div", null); //@reblendComponent class WrapperComponent extends _reblendjs.Reblend { static ELEMENT_NAME = "WrapperComponent"; constructor() { super(); } async initState() { _reblendjs.useEffect.bind(this)(() => { wrapperComponentMountEffect(); }); } async initProps({ children }) { this.props = {}; this.props.children = children; } async html() { return _reblendjs.Reblend.construct.bind(this)(_reblendjs.Reblend, null, this.props.children); } } /* @Reblend: Transformed from function to class */ const container = document.createElement("div"); document.body.appendChild(container); container.innerHTML = await _reblendjs.Reblend.renderToString(ui); await (0, _.render)(ui, { container, wrapper: WrapperComponent }); expect(wrapperComponentMountEffect).toHaveBeenCalledTimes(1); }); });