reblend-testing-library
Version:
Simple and complete Reblendjs testing utilities that encourage good testing practices.
271 lines (264 loc) • 8.23 kB
JavaScript
"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);
});
});