Skip to content

Commit

Permalink
Added assertComponents
Browse files Browse the repository at this point in the history
  • Loading branch information
viktor-podzigun committed Jun 1, 2023
1 parent 441209b commit 98f74dd
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 25 deletions.
1 change: 1 addition & 0 deletions index.mjs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { default as assertComponent } from "./src/assertComponent.mjs";
export { default as assertComponents } from "./src/assertComponents.mjs";
37 changes: 20 additions & 17 deletions src/assertComponent.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,29 @@ import assert from "node:assert/strict";
* @param { import('react').ReactElement | string } expectedElement
*/
function assertComponent(result, expectedElement) {
assertComponentImpl(
typeof expectedElement === "string"
? expectedElement
: Object(expectedElement.type).toString(),
result,
expectedElement
);
assertComponentImpl("", result, expectedElement);
}

/**
* @param { string } name
* @param { string } path
* @param { import('./assertComponent').TestInstance | string } result
* @param { import('./assertComponent').TestInstance | string } expectedElement
*/
function assertComponentImpl(name, result, expectedElement) {
function assertComponentImpl(path, result, expectedElement) {
const name =
typeof expectedElement === "string"
? expectedElement
: expectedElement.type.displayName
? expectedElement.type.displayName
: expectedElement.type;

const pathName = path ? `${path} > ${name}` : Object(name).toString();

if (typeof result === "string" || typeof expectedElement === "string") {
assert.deepEqual(
result,
expectedElement,
`Elements doesn't match for ${name}` +
`Element doesn't match for ${pathName}` +
`\n\tactual: ${result}` +
`\n\texpected: ${expectedElement}`
);
Expand All @@ -34,7 +37,7 @@ function assertComponentImpl(name, result, expectedElement) {
assert.deepEqual(
result.type,
expectedElement.type,
`Components types doesn't match for ${name}` +
`Component type doesn't match for ${pathName}` +
`\n\tactual: ${
result.type.displayName ? result.type.displayName : result.type
}` +
Expand All @@ -47,15 +50,15 @@ function assertComponentImpl(name, result, expectedElement) {

Object.keys(expectedElement.props)
.filter((p) => {
return p != "children" && p != "assertWrapped" && p != "assertPlain";
return p != "children";
})
.forEach((attr) => {
const resultValue = result.props[attr];
const expectedValue = expectedElement.props[attr];
if (typeof expectedValue === "object" && !Array.isArray(expectedValue)) {
assertObject(`${name}.${attr}`, resultValue, expectedValue);
assertObject(`${pathName}.${attr}`, resultValue, expectedValue);
} else {
assertAttrValue(`${name}.${attr}`, resultValue, expectedValue);
assertAttrValue(`${pathName}.${attr}`, resultValue, expectedValue);
}
});

Expand All @@ -73,20 +76,20 @@ function assertComponentImpl(name, result, expectedElement) {
: Object(child.type).toString();
});
assert.fail(
`Expected no children for ${name}, but got: ${resultChildren}`
`Expected no children for ${pathName}, but got: ${resultChildren}`
);
}
} else {
assert.deepEqual(
children.length,
expectedChildren.length,
`Children count doesn't match for ${name}` +
`Children count doesn't match for ${pathName}` +
`\n\tactual: ${children.length}` +
`\n\texpected: ${expectedChildren.length}`
);

expectedChildren.forEach((expected, i) => {
assertComponentImpl(name, children[i], expected);
assertComponentImpl(pathName, children[i], expected);
});
}
}
Expand Down
22 changes: 22 additions & 0 deletions src/assertComponents.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import assert from "node:assert/strict";
import assertComponent from "./assertComponent.mjs";

/**
* @param { (import('react-test-renderer').ReactTestInstance | string)[] } results
* @param { (import('react').ReactElement | string)[] } expectedElements
*/
function assertComponents(results, ...expectedElements) {
assert.deepEqual(
results.length,
expectedElements.length,
`Components count doesn't match` +
`\n\tactual: ${results.length}` +
`\n\texpected: ${expectedElements.length}`
);

expectedElements.forEach((expected, i) => {
assertComponent(results[i], expected);
});
}

export default assertComponents;
1 change: 1 addition & 0 deletions test/all.mjs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
await import("./testRenderer.test.mjs");
await import("./assertComponent.test.mjs");
await import("./assertComponents.test.mjs");
16 changes: 8 additions & 8 deletions test/assertComponent.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -114,32 +114,32 @@ describe("assertComponent.test.mjs", () => {
//then
assert.deepEqual(
resError?.message,
"Elements doesn't match for p" +
"Element doesn't match for p > comp2" +
"\n\tactual: comp" +
"\n\texpected: comp2"
);
});

it("should fail if child types doesn't match", () => {
it("should fail if root element doesn't match", () => {
//given
const Comp = () => {
return h("p", {}, h("comp"));
return h("comp");
};
const comp = TestRenderer.create(h(Comp)).root.children[0];
/** @type {Error?} */
let resError = null;

//when
try {
assertComponent(comp, h("p", {}, h("comp2")));
assertComponent(comp, h("comp2"));
} catch (error) {
resError = error;
}

//then
assert.deepEqual(
resError?.message,
"Components types doesn't match for p" +
"Component type doesn't match for comp2" +
"\n\tactual: comp" +
"\n\texpected: comp2"
);
Expand All @@ -164,7 +164,7 @@ describe("assertComponent.test.mjs", () => {
//then
assert.deepEqual(
resError?.message,
"Components types doesn't match for p" +
"Component type doesn't match for p > TestComp2" +
"\n\tactual: TestComp" +
"\n\texpected: TestComp2"
);
Expand All @@ -173,7 +173,7 @@ describe("assertComponent.test.mjs", () => {
it("should fail if non-empty", () => {
//given
const Comp = () => {
return h("p", {}, h(TestComp));
return h("p", {}, "test_text", h("div"), h(TestComp));
};
const comp = TestRenderer.create(h(Comp)).root.children[0];
/** @type {Error?} */
Expand All @@ -189,7 +189,7 @@ describe("assertComponent.test.mjs", () => {
//then
assert.deepEqual(
resError?.message,
"Expected no children for p, but got: TestComp"
"Expected no children for p, but got: test_text,div,TestComp"
);
});

Expand Down
64 changes: 64 additions & 0 deletions test/assertComponents.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React from "react";
import TestRenderer from "react-test-renderer";
import { assertComponents } from "../index.mjs";
import { TestComp, TestComp2 } from "./testComponents.mjs";

import { strict as assert } from "node:assert";
const { describe, it } = await (async () => {
// @ts-ignore
return process.isBun // @ts-ignore
? Promise.resolve({ describe: (_, fn) => fn(), it: test })
: import("node:test");
})();

const h = React.createElement;

describe("assertComponents.test.mjs", () => {
it("should fail if components count doesn't match", () => {
//given
const Comp = () => {
return h(React.Fragment, null, "test_text", h("div"), h(TestComp));
};
const comp = TestRenderer.create(h(Comp)).root;
/** @type {Error?} */
let resError = null;

//when
try {
assertComponents(comp.children, h("div"), "test_text");
} catch (error) {
resError = error;
}

//then
assert.deepEqual(
resError?.message,
"Components count doesn't match\n\tactual: 3\n\texpected: 2"
);
});

it("should fail if component child doesn't match", () => {
//given
const Comp = () => {
return h("p", {}, h("comp"), h(TestComp));
};
const comp = TestRenderer.create(h(Comp)).root;
/** @type {Error?} */
let resError = null;

//when
try {
assertComponents(comp.children, h("p", {}, h("comp"), h(TestComp2)));
} catch (error) {
resError = error;
}

//then
assert.deepEqual(
resError?.message,
"Component type doesn't match for p > TestComp2" +
"\n\tactual: TestComp" +
"\n\texpected: TestComp2"
);
});
});

0 comments on commit 98f74dd

Please sign in to comment.