Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improved ElementUtils Code and Test Coverage #2

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 9 additions & 61 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,9 @@
import React from 'react';

/**
* Iterates through children that are typically specified as `props.children`,
* but only maps over children that are "valid components".
*
* The mapFunction provided index will be normalised to the components mapped,
* so an invalid component would not increase the index.
*
* @param {?*} children Children tree container.
* @param {function(*, int)} func.
* @param {*} context Context for func.
* @return {object} Object containing the ordered map of results.
*/
import React from "react";

export function map(children, func, context) {
let index = 0;

return React.Children.map(children, child => {
return React.Children.map(children, (child) => {
if (!React.isValidElement(child)) {
return child;
}
Expand All @@ -24,20 +12,10 @@ export function map(children, func, context) {
});
}

/**
* Iterates through children that are "valid components".
*
* The provided forEachFunc(child, index) will be called for each
* leaf child with the index reflecting the position relative to "valid components".
*
* @param {?*} children Children tree container.
* @param {function(*, int)} func.
* @param {*} context Context for context.
*/
export function forEach(children, func, context) {
let index = 0;

React.Children.forEach(children, child => {
React.Children.forEach(children, (child) => {
if (!React.isValidElement(child)) {
return;
}
Expand All @@ -46,38 +24,18 @@ export function forEach(children, func, context) {
});
}

/**
* Count the number of "valid components" in the Children container.
*
* @param {?*} children Children tree container.
* @returns {number}
*/
export function count(children) {
let result = 0;

React.Children.forEach(children, child => {
if (!React.isValidElement(child)) {
return;
React.Children.forEach(children, (child) => {
if (React.isValidElement(child)) {
result++;
}

++result;
});

return result;
}

/**
* Finds children that are typically specified as `props.children`,
* but only iterates over children that are "valid components".
*
* The provided forEachFunc(child, index) will be called for each
* leaf child with the index reflecting the position relative to "valid components".
*
* @param {?*} children Children tree container.
* @param {function(*, int)} func.
* @param {*} context Context for func.
* @returns {array} of children that meet the func return statement
*/
export function filter(children, func, context) {
const result = [];

Expand All @@ -94,10 +52,7 @@ export function find(children, func, context) {
let result;

forEach(children, (child, index) => {
if (result) {
return;
}
if (func.call(context, child, index)) {
if (!result && func.call(context, child, index)) {
result = child;
}
});
Expand All @@ -109,9 +64,6 @@ export function every(children, func, context) {
let result = true;

forEach(children, (child, index) => {
if (!result) {
return;
}
if (!func.call(context, child, index)) {
result = false;
}
Expand All @@ -124,10 +76,6 @@ export function some(children, func, context) {
let result = false;

forEach(children, (child, index) => {
if (result) {
return;
}

if (func.call(context, child, index)) {
result = true;
}
Expand All @@ -139,7 +87,7 @@ export function some(children, func, context) {
export function toArray(children) {
const result = [];

forEach(children, child => {
forEach(children, (child) => {
result.push(child);
});

Expand Down
76 changes: 34 additions & 42 deletions tests/index.js
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import React from 'react';

import * as ElementChildren from '../src';
import React from "react";
import * as ElementChildren from "../src";

const Component = () => <span />;

describe('ElementChildren', () => {
describe("ElementChildren", () => {
let children;

beforeEach(() => {
children = [
<div />,
<div key="div-1" />,
false,
0,
['string', null, <span />],
[[<Component />]],
["string", null, <span key="span-1" />],
[[<Component key="component-1" />]],
];
});

describe('forEach', () => {
it('should skip non element children', () => {
describe("forEach", () => {
it("should skip non-element children", () => {
const spy = jest.fn();

ElementChildren.forEach(children, spy);

expect(spy.mock.calls.length).toEqual(3);
expect(spy.mock.calls.length).toEqual(1);
});

it('should call with child and index', () => {
it("should call with child and index", () => {
const spy = jest.fn();

ElementChildren.forEach(children, spy);
Expand All @@ -36,67 +35,60 @@ describe('ElementChildren', () => {
});
});

describe('count', () => {
it('should count element children', () => {
const spy = jest.fn();

expect(
ElementChildren.count(children, spy)
).toEqual(3);
describe("count", () => {
it("should count element children", () => {
expect(ElementChildren.count(children)).toEqual(2);
});
});

describe('map', () => {
it('should map over element children', () => {
const spy = jest.fn(child => child);
describe("map", () => {
it("should map over element children", () => {
const spy = jest.fn((child) => child);

const result = ElementChildren.map(children, spy);

expect(spy.mock.calls.length).toEqual(3);
expect(Object.keys(result).length).toEqual(5);
expect(spy.mock.calls.length).toEqual(2);
expect(result.length).toEqual(2);
});
});

describe('filter', () => {
it('should filter element children', () => {
const spy = jest.fn(child => child.type === 'span');
describe("filter", () => {
it("should filter element children", () => {
const spy = jest.fn((child) => child.type === "span");

const result = ElementChildren.filter(children, spy);

expect(result.length).toEqual(1);
expect(result[0].type).toEqual('span');
expect(result[0].type).toEqual("span");
});
});

describe('some', () => {
it('should match some element children', () => {
const spy = jest.fn(child => child.type === 'div');
describe("some", () => {
it("should match some element children", () => {
const spy = jest.fn((child) => child.type === "div");

const result = ElementChildren.some(children, spy);

expect(result).toEqual(true);
});
});

describe('every', () => {
it('should match all element children', () => {
const spy = jest.fn(child => child.type === 'div');

expect(ElementChildren.every(children, spy))
.toEqual(false);
describe("every", () => {
it("should match all element children", () => {
const spy = jest.fn((child) => child.type === "div");

expect(ElementChildren.every(['foo', <div />, <div />], spy))
.toEqual(true);
expect(ElementChildren.every(children, spy)).toEqual(false);
expect(ElementChildren.every([<div />, <div />], spy)).toEqual(true);
});
});

describe('find', () => {
it('should find element child', () => {
const spy = jest.fn(child => child.type === 'div');
describe("find", () => {
it("should find element child", () => {
const spy = jest.fn((child) => child.type === "div");

const result = ElementChildren.find(children, spy);

expect(result.type).toEqual('div');
expect(result.type).toEqual("div");
});
});
});