Skip to content

Commit

Permalink
test: added test cases for helper functions and zustand store
Browse files Browse the repository at this point in the history
  • Loading branch information
JairajJangle committed Jul 15, 2023
1 parent 0df57db commit 20dfaeb
Show file tree
Hide file tree
Showing 13 changed files with 1,296 additions and 459 deletions.
File renamed without changes.
1 change: 1 addition & 0 deletions jest.setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
import '@testing-library/jest-native/extend-expect';
15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,24 +66,29 @@
"@react-native-community/eslint-config": "^3.0.2",
"@release-it/conventional-changelog": "^5.0.0",
"@shopify/flash-list": "1.x.x",
"@testing-library/jest-native": "^5.4.2",
"@testing-library/react-native": "^12.1.2",
"@types/color": "^3.0.3",
"@types/jest": "^28.1.2",
"@types/jest": "^29.5.3",
"@types/react": "~17.0.21",
"@types/react-native": "0.70.0",
"@types/react-native-vector-icons": "^6.4.13",
"@types/react-test-renderer": "^18.0.0",
"commitlint": "^17.0.2",
"del-cli": "^5.0.0",
"eslint": "^8.4.1",
"eslint-config-prettier": "^8.5.0",
"eslint-plugin-prettier": "^4.0.0",
"jest": "^28.1.1",
"jest": "^29.6.1",
"pod-install": "^0.1.0",
"prettier": "^2.0.5",
"react": "18.2.0",
"react-native": "0.72.1",
"react-native-builder-bob": "^0.20.0",
"react-native-paper": "5.x.x",
"react-test-renderer": "^18.2.0",
"release-it": "^15.0.0",
"ts-jest": "^29.1.1",
"turbo": "^1.10.7",
"typescript": "^5.0.2"
},
Expand All @@ -103,6 +108,12 @@
"packageManager": "^yarn@1.22.15",
"jest": {
"preset": "react-native",
"setupFilesAfterEnv": [
"./jest.setup.ts"
],
"transformIgnorePatterns": [
"node_modules/(?!(jest-)?react-native|@react-native-community|@react-navigation|@react-native/js-polyfills)"
],
"modulePathIgnorePatterns": [
"<rootDir>/example/node_modules",
"<rootDir>/lib/"
Expand Down
125 changes: 125 additions & 0 deletions src/__mocks__/generateTree.mock.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
import { TreeNode, __FlattenedTreeNode__ } from "../types/treeView.types";

export const tree3d2b = [
{
"id": "1",
"name": "node1",
"children": [
{
"id": "1.1",
"name": "node1.1",
"children": [
{
"id": "1.1.1",
"name": "node1.1.1"
},
{
"id": "1.1.2",
"name": "node1.1.2"
}
]
},
{
"id": "1.2",
"name": "node1.2",
"children": [
{
"id": "1.2.1",
"name": "node1.2.1"
},
{
"id": "1.2.2",
"name": "node1.2.2"
}
]
}
]
},
{
"id": "2",
"name": "node2",
"children": [
{
"id": "2.1",
"name": "node2.1",
"children": [
{
"id": "2.1.1",
"name": "node2.1.1"
},
{
"id": "2.1.2",
"name": "node2.1.2"
}
]
},
{
"id": "2.2",
"name": "node2.2",
"children": [
{
"id": "2.2.1",
"name": "node2.2.1"
},
{
"id": "2.2.2",
"name": "node2.2.2"
}
]
}
]
}
];

export function generateTree(
depth: number,
breadth: number,
prefix: string = ''
): TreeNode[] {
let nodes: TreeNode[] = [];

for (let i = 1; i <= breadth; i++) {
let node: TreeNode = {
id: `${prefix}${i}`,
name: `node${prefix}${i}`
};

if (depth > 1) {
node.children = generateTree(depth - 1, breadth, `${prefix}${i}.`);
}

nodes.push(node);
}

return nodes;
}

export function generateExpectedFlatTree(
nodes: TreeNode[],
expandedIds: Set<string>,
level: number = 0
): __FlattenedTreeNode__[] {
let flattened: __FlattenedTreeNode__[] = [];
for (let node of nodes) {
flattened.push({ ...node, level: level });
if (node.children && expandedIds.has(node.id)) {
flattened = [
...flattened,
...generateExpectedFlatTree(node.children, expandedIds, level + 1)
];
}
}
return flattened;
}

export function createRandomNumberSet() {
let randomNumbers = new Set<string>();

while (randomNumbers.size < 10) {
// Random number between 0 and 99
let randomNumber = Math.floor(Math.random() * 100);
randomNumbers.add(randomNumber.toString());
}

return randomNumbers;
}
24 changes: 24 additions & 0 deletions src/__mocks__/zustand.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { act } from '@testing-library/react-native';
import { StateCreator } from 'zustand';

const { create: actualCreate } = jest.requireActual('zustand');

// a variable to hold reset functions for all stores declared in the app
const storeResetFns = new Set<() => void>();

// when creating a store, we get its initial state, create a reset function and add it in the set
export const create = <S>(createState: StateCreator<S>) => {
const store = actualCreate(createState);
const initialState = store.getState();
storeResetFns.add(() => store.setState(initialState, true));
return store;
};

// Reset all stores after each test run
beforeEach(async () => {
await act(() =>
storeResetFns.forEach(resetFn => {
resetFn();
})
);
});
157 changes: 157 additions & 0 deletions src/__tests__/expandCollapse.helper.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
jest.mock('zustand');

import { useTreeViewStore } from '../store/treeView.store';
import { tree3d2b } from "../__mocks__/generateTree.mock";
import {
collapseAll,
expandAll,
handleToggleExpand,
initializeNodeMaps
} from '../helpers';
import { act } from 'react-test-renderer';
import { TreeNode } from '../types/treeView.types';

describe('expandAll', () => {
beforeEach(() => {
useTreeViewStore.setState(useTreeViewStore.getState(), true);

// Setup mock tree
useTreeViewStore.getState().updateInitialTreeViewData(tree3d2b);
initializeNodeMaps(tree3d2b);
});

it('calls expandAll on initial tree(all collapsed)', () => {
act(() => {
expandAll();
});

const { expanded, nodeMap } = useTreeViewStore.getState();

// Convert nodeMap.keys() iterator to a Set for comparison
const nodeKeys = new Set(nodeMap.keys());
expect(expanded).toEqual(nodeKeys);
});

it('expands all node in tree with some nodes which are already expanded', () => {
act(() => {
handleToggleExpand('1');
handleToggleExpand('2');
handleToggleExpand('1.1');
handleToggleExpand('1.2');
handleToggleExpand('1.1');

expandAll();
});

const { expanded, nodeMap } = useTreeViewStore.getState();

// Convert nodeMap.keys() iterator to a Set for comparison
const nodeKeys = new Set(nodeMap.keys());
expect(expanded).toEqual(nodeKeys);
});
});

describe('collapseAll', () => {
beforeEach(() => {
useTreeViewStore.setState(useTreeViewStore.getState(), true);

// Setup mock tree
useTreeViewStore.getState().updateInitialTreeViewData(tree3d2b);
initializeNodeMaps(tree3d2b);
});

it('calls collapseAll on initial tree(all collapsed)', () => {
act(() => {
collapseAll();
});

const { expanded } = useTreeViewStore.getState();
expect(expanded).toEqual(new Set<string>());
});

it('collapses all node in tree with some nodes which are already expanded', () => {
act(() => {
handleToggleExpand('1');
handleToggleExpand('2');
handleToggleExpand('1.1');
handleToggleExpand('1.2');
handleToggleExpand('1.1');

collapseAll();
});

const { expanded } = useTreeViewStore.getState();

expect(expanded).toEqual(new Set<string>());
});
});

describe('handleToggleExpand', () => {
beforeEach(() => {
useTreeViewStore.setState(useTreeViewStore.getState(), true);
});

test('handleToggleExpand correctly toggles the expanded state of a tree node', () => {
const initialData: TreeNode[] = [
{
id: '1',
name: 'Node 1',
children: [
{
id: '1.1',
name: 'Node 1.1'
},
{
id: '1.2',
name: 'Node 1.2',
children: [{
id: '1.2.1',
name: 'Node 1.2.1'
}]
},
],
},
{
id: '2',
name: 'Node 2'
},
];

act(() => {
useTreeViewStore.getState().updateInitialTreeViewData(initialData);
initializeNodeMaps(initialData);
});

act(() => {
handleToggleExpand('1');
});

// Node '1' should now be expanded
let { expanded } = useTreeViewStore.getState();
expect(expanded.has('1')).toBeTruthy();

act(() => {
handleToggleExpand('1.2');
});

// Node '1.2' should now be expanded, Node '1'(parent) should remain expanded
expanded = useTreeViewStore.getState().expanded;
expect(expanded.has('1.2')).toBeTruthy();
expect(expanded.has('1')).toBeTruthy();

act(() => {
handleToggleExpand('1');
handleToggleExpand('2');
});

// Node '1' and its descendants should now be collapsed but Node '2' should remain expanded
expanded = useTreeViewStore.getState().expanded;

expect(expanded.has('1')).toBeFalsy();
expect(expanded.has('1.1')).toBeFalsy();
expect(expanded.has('1.2')).toBeFalsy();
expect(expanded.has('1.2.1')).toBeFalsy();

expect(expanded.has('2')).toBeTruthy();
});
});
Loading

0 comments on commit 20dfaeb

Please sign in to comment.