test(splitArray): add unit tests for splitArray util

This commit is contained in:
Ilia Mashkov
2026-02-18 20:18:18 +03:00
parent 24ca2f6c41
commit ff71d1c8c9

View File

@@ -0,0 +1,405 @@
import {
describe,
expect,
it,
} from 'vitest';
import { splitArray } from './splitArray';
describe('splitArray', () => {
describe('Basic Functionality', () => {
it('should split an array into two arrays based on callback', () => {
const input = [1, 2, 3, 4, 5];
const [pass, fail] = splitArray(input, n => n > 2);
expect(pass).toEqual([3, 4, 5]);
expect(fail).toEqual([1, 2]);
});
it('should return two arrays', () => {
const result = splitArray([1, 2, 3], () => true);
expect(Array.isArray(result)).toBe(true);
expect(result).toHaveLength(2);
expect(Array.isArray(result[0])).toBe(true);
expect(Array.isArray(result[1])).toBe(true);
});
it('should preserve original array', () => {
const input = [1, 2, 3, 4, 5];
const original = [...input];
splitArray(input, n => n % 2 === 0);
expect(input).toEqual(original);
});
});
describe('Empty Array', () => {
it('should return two empty arrays for empty input', () => {
const [pass, fail] = splitArray([], () => true);
expect(pass).toEqual([]);
expect(fail).toEqual([]);
});
it('should handle empty array with falsy callback', () => {
const [pass, fail] = splitArray([], () => false);
expect(pass).toEqual([]);
expect(fail).toEqual([]);
});
});
describe('All Pass', () => {
it('should put all elements in pass array when callback returns true for all', () => {
const input = [1, 2, 3, 4, 5];
const [pass, fail] = splitArray(input, () => true);
expect(pass).toEqual([1, 2, 3, 4, 5]);
expect(fail).toEqual([]);
});
it('should put all elements in pass array using always-true condition', () => {
const input = ['a', 'b', 'c'];
const [pass, fail] = splitArray(input, s => s.length > 0);
expect(pass).toEqual(['a', 'b', 'c']);
expect(fail).toEqual([]);
});
});
describe('All Fail', () => {
it('should put all elements in fail array when callback returns false for all', () => {
const input = [1, 2, 3, 4, 5];
const [pass, fail] = splitArray(input, () => false);
expect(pass).toEqual([]);
expect(fail).toEqual([1, 2, 3, 4, 5]);
});
it('should put all elements in fail array using always-false condition', () => {
const input = ['a', 'b', 'c'];
const [pass, fail] = splitArray(input, s => s.length > 10);
expect(pass).toEqual([]);
expect(fail).toEqual(['a', 'b', 'c']);
});
});
describe('Mixed Results', () => {
it('should split even and odd numbers', () => {
const input = [1, 2, 3, 4, 5, 6];
const [even, odd] = splitArray(input, n => n % 2 === 0);
expect(even).toEqual([2, 4, 6]);
expect(odd).toEqual([1, 3, 5]);
});
it('should split positive and negative numbers', () => {
const input = [-3, -2, -1, 0, 1, 2, 3];
const [positive, negative] = splitArray(input, n => n >= 0);
expect(positive).toEqual([0, 1, 2, 3]);
expect(negative).toEqual([-3, -2, -1]);
});
it('should split strings by length', () => {
const input = ['a', 'ab', 'abc', 'abcd'];
const [long, short] = splitArray(input, s => s.length >= 3);
expect(long).toEqual(['abc', 'abcd']);
expect(short).toEqual(['a', 'ab']);
});
it('should split objects by property', () => {
interface Item {
id: number;
active: boolean;
}
const input: Item[] = [
{ id: 1, active: true },
{ id: 2, active: false },
{ id: 3, active: true },
{ id: 4, active: false },
];
const [active, inactive] = splitArray(input, item => item.active);
expect(active).toEqual([
{ id: 1, active: true },
{ id: 3, active: true },
]);
expect(inactive).toEqual([
{ id: 2, active: false },
{ id: 4, active: false },
]);
});
});
describe('Type Safety', () => {
it('should work with number arrays', () => {
const [pass, fail] = splitArray([1, 2, 3], n => n > 1);
expect(pass).toEqual([2, 3]);
expect(fail).toEqual([1]);
// Type check - should be numbers
const sum = pass[0] + pass[1];
expect(sum).toBe(5);
});
it('should work with string arrays', () => {
const [pass, fail] = splitArray(['a', 'bb', 'ccc'], s => s.length > 1);
expect(pass).toEqual(['bb', 'ccc']);
expect(fail).toEqual(['a']);
// Type check - should be strings
const concatenated = pass.join('');
expect(concatenated).toBe('bbccc');
});
it('should work with boolean arrays', () => {
const [pass, fail] = splitArray([true, false, true], b => b);
expect(pass).toEqual([true, true]);
expect(fail).toEqual([false]);
});
it('should work with generic objects', () => {
interface Person {
name: string;
age: number;
}
const people: Person[] = [
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
{ name: 'Charlie', age: 20 },
];
const [adults, minors] = splitArray(people, p => p.age >= 21);
expect(adults).toEqual([
{ name: 'Alice', age: 25 },
{ name: 'Bob', age: 30 },
]);
expect(minors).toEqual([{ name: 'Charlie', age: 20 }]);
});
it('should work with null and undefined', () => {
const input = [null, undefined, 1, 0, ''];
const [truthy, falsy] = splitArray(input, item => !!item);
expect(truthy).toEqual([1]);
expect(falsy).toEqual([null, undefined, 0, '']);
});
});
describe('Callback Functions', () => {
it('should support arrow function syntax', () => {
const [pass, fail] = splitArray([1, 2, 3, 4], x => x % 2 === 0);
expect(pass).toEqual([2, 4]);
expect(fail).toEqual([1, 3]);
});
it('should support regular function syntax', () => {
const [pass, fail] = splitArray([1, 2, 3, 4], function(x) {
return x % 2 === 0;
});
expect(pass).toEqual([2, 4]);
expect(fail).toEqual([1, 3]);
});
it('should support inline conditions', () => {
const input = [1, 2, 3, 4, 5];
const [greaterThan3, others] = splitArray(input, x => x > 3);
expect(greaterThan3).toEqual([4, 5]);
expect(others).toEqual([1, 2, 3]);
});
});
describe('Order Preservation', () => {
it('should maintain order within each resulting array', () => {
const input = [5, 1, 4, 2, 3];
const [greaterThan2, lessOrEqual] = splitArray(input, n => n > 2);
expect(greaterThan2).toEqual([5, 4, 3]);
expect(lessOrEqual).toEqual([1, 2]);
});
it('should preserve relative order for complex objects', () => {
interface Item {
id: number;
value: string;
}
const input: Item[] = [
{ id: 1, value: 'a' },
{ id: 2, value: 'b' },
{ id: 3, value: 'c' },
{ id: 4, value: 'd' },
];
const [evenIds, oddIds] = splitArray(input, item => item.id % 2 === 0);
expect(evenIds).toEqual([
{ id: 2, value: 'b' },
{ id: 4, value: 'd' },
]);
expect(oddIds).toEqual([
{ id: 1, value: 'a' },
{ id: 3, value: 'c' },
]);
});
});
describe('Edge Cases', () => {
it('should handle single element array (truthy)', () => {
const [pass, fail] = splitArray([1], () => true);
expect(pass).toEqual([1]);
expect(fail).toEqual([]);
});
it('should handle single element array (falsy)', () => {
const [pass, fail] = splitArray([1], () => false);
expect(pass).toEqual([]);
expect(fail).toEqual([1]);
});
it('should handle two element array', () => {
const [pass, fail] = splitArray([1, 2], n => n === 1);
expect(pass).toEqual([1]);
expect(fail).toEqual([2]);
});
it('should handle array with duplicate values', () => {
const [pass, fail] = splitArray([1, 1, 2, 2, 1, 1], n => n === 1);
expect(pass).toEqual([1, 1, 1, 1]);
expect(fail).toEqual([2, 2]);
});
it('should handle zero values', () => {
const [truthy, falsy] = splitArray([0, 1, 0, 2], Boolean);
expect(truthy).toEqual([1, 2]);
expect(falsy).toEqual([0, 0]);
});
it('should handle NaN values', () => {
const input = [1, NaN, 2, NaN, 3];
const [numbers, nans] = splitArray(input, n => !Number.isNaN(n));
expect(numbers).toEqual([1, 2, 3]);
expect(nans).toEqual([NaN, NaN]);
});
});
describe('Large Arrays', () => {
it('should handle large arrays efficiently', () => {
const largeArray = Array.from({ length: 10000 }, (_, i) => i);
const [even, odd] = splitArray(largeArray, n => n % 2 === 0);
expect(even).toHaveLength(5000);
expect(odd).toHaveLength(5000);
expect(even[0]).toBe(0);
expect(even[9999]).toBeUndefined();
expect(even[4999]).toBe(9998);
});
it('should maintain correct results for all elements in large array', () => {
const input = Array.from({ length: 1000 }, (_, i) => i);
const [multiplesOf3, others] = splitArray(input, n => n % 3 === 0);
// Verify counts
expect(multiplesOf3).toHaveLength(334); // 0, 3, 6, ..., 999
expect(others).toHaveLength(666);
// Verify all multiples of 3 are in correct array
multiplesOf3.forEach(n => {
expect(n % 3).toBe(0);
});
// Verify no multiples of 3 are in others
others.forEach(n => {
expect(n % 3).not.toBe(0);
});
});
});
describe('Real-World Use Cases', () => {
it('should separate valid from invalid emails', () => {
const emails = [
'valid@example.com',
'invalid',
'another@test.org',
'not-an-email',
'user@domain.co.uk',
];
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
const [valid, invalid] = splitArray(emails, email => emailRegex.test(email));
expect(valid).toEqual([
'valid@example.com',
'another@test.org',
'user@domain.co.uk',
]);
expect(invalid).toEqual(['invalid', 'not-an-email']);
});
it('should separate completed from pending tasks', () => {
interface Task {
id: number;
title: string;
completed: boolean;
}
const tasks: Task[] = [
{ id: 1, title: 'Task 1', completed: true },
{ id: 2, title: 'Task 2', completed: false },
{ id: 3, title: 'Task 3', completed: true },
{ id: 4, title: 'Task 4', completed: false },
];
const [completed, pending] = splitArray(tasks, task => task.completed);
expect(completed).toHaveLength(2);
expect(pending).toHaveLength(2);
expect(completed.every(t => t.completed)).toBe(true);
expect(pending.every(t => !t.completed)).toBe(true);
});
it('should separate adults from minors by age', () => {
interface Person {
name: string;
age: number;
}
const people: Person[] = [
{ name: 'Alice', age: 17 },
{ name: 'Bob', age: 25 },
{ name: 'Charlie', age: 16 },
{ name: 'Diana', age: 30 },
{ name: 'Eve', age: 18 },
];
const [adults, minors] = splitArray(people, person => person.age >= 18);
expect(adults).toEqual([
{ name: 'Bob', age: 25 },
{ name: 'Diana', age: 30 },
{ name: 'Eve', age: 18 },
]);
expect(minors).toEqual([
{ name: 'Alice', age: 17 },
{ name: 'Charlie', age: 16 },
]);
});
it('should separate truthy from falsy values', () => {
const mixed = [0, 1, false, true, '', 'hello', null, undefined, [], [0]];
const [truthy, falsy] = splitArray(mixed, Boolean);
expect(truthy).toEqual([1, true, 'hello', [], [0]]);
expect(falsy).toEqual([0, false, '', null, undefined]);
});
});
});