diff --git a/src/helpers/tests/styles.test.ts b/src/helpers/tests/styles.test.ts new file mode 100644 index 0000000..cddb914 --- /dev/null +++ b/src/helpers/tests/styles.test.ts @@ -0,0 +1,49 @@ +import { describe, it, expect } from 'vitest'; +import { cn } from '../styles'; + +describe('cn function', () => { + it('should return an empty string when no arguments are provided', () => { + const result = cn(); + expect(result).toBe(''); + }); + + it('should return an empty string when all arguments are invalid values', () => { + const result = cn(undefined, null, false, ''); + expect(result).toBe(''); + }); + + it('should return a single class name when one valid string is provided', () => { + const result = cn('class1'); + expect(result).toBe('class1'); + }); + + it('should combine multiple class names into a single string separated by spaces', () => { + const result = cn('class1', 'class2', 'class3'); + expect(result).toBe('class1 class2 class3'); + }); + + it('should filter out invalid values and combine valid class names', () => { + const result = cn('class1', undefined, 'class2', null, false, 'class3', ''); + expect(result).toBe('class1 class2 class3'); + }); + + it('should handle a mix of valid and invalid class names', () => { + const result = cn('class1', '', false, null, 'class2'); + expect(result).toBe('class1 class2'); + }); + + it('should return an empty string when all class names are empty strings', () => { + const result = cn('', '', ''); + expect(result).toBe(''); + }); + + it('should handle single class name with leading and trailing spaces', () => { + const result = cn(' class1 '); + expect(result).toBe(' class1 '); + }); + + it('should handle class names with spaces in between', () => { + const result = cn('class1 class2', 'class3 class4'); + expect(result).toBe('class1 class2 class3 class4'); + }); +}); diff --git a/src/helpers/tests/wait.test.ts b/src/helpers/tests/wait.test.ts new file mode 100644 index 0000000..8314fe8 --- /dev/null +++ b/src/helpers/tests/wait.test.ts @@ -0,0 +1,67 @@ +import { describe, it, expect, vi } from 'vitest'; +import { waitUntil } from '../wait'; + +describe('waitUntil function', () => { + it('should resolve when the function returns true', async () => { + const mockFunc = vi + .fn() + .mockReturnValueOnce(false) + .mockReturnValueOnce(false) + .mockReturnValueOnce(true); + + await waitUntil(mockFunc, 50); + expect(mockFunc).toHaveBeenCalledTimes(3); + }); + + it('should reject if the function throws an error', async () => { + const mockFunc = vi + .fn() + .mockReturnValueOnce(false) + .mockImplementationOnce(() => { + throw new Error('Test error'); + }); + + await expect(waitUntil(mockFunc, 50)).rejects.toThrow('Test error'); + expect(mockFunc).toHaveBeenCalledTimes(2); + }); + + it('should repeatedly call the function at the specified interval', async () => { + const mockFunc = vi + .fn() + .mockReturnValueOnce(false) + .mockReturnValueOnce(false) + .mockReturnValueOnce(true); + + const interval = 100; + const startTime = Date.now(); + + await waitUntil(mockFunc, interval); + + const endTime = Date.now(); + const elapsedTime = endTime - startTime; + + expect(elapsedTime).toBeGreaterThanOrEqual(2 * interval); + expect(mockFunc).toHaveBeenCalledTimes(3); + }); + + it('should handle the function returning true on the first call', async () => { + const mockFunc = vi.fn().mockReturnValueOnce(true); + + await waitUntil(mockFunc, 50); + expect(mockFunc).toHaveBeenCalledTimes(1); + }); + + it('should handle the function never returning true (timeout simulation)', async () => { + const mockFunc = vi.fn().mockReturnValue(false); + + // Using a very short timeout to simulate test timeout + const timeoutPromise = new Promise((_, reject) => + setTimeout(() => reject(new Error('Test timeout')), 300), + ); + + await expect( + Promise.race([waitUntil(mockFunc, 50), timeoutPromise]), + ).rejects.toThrow('Test timeout'); + expect(mockFunc).toHaveBeenCalled(); + }); +}); diff --git a/src/helpers/wait.ts b/src/helpers/wait.ts index 1ee55e1..76ae92e 100644 --- a/src/helpers/wait.ts +++ b/src/helpers/wait.ts @@ -1,3 +1,10 @@ +/** + * Repeatedly calls a function at a specified interval until it returns `true`. + * + * @param {() => boolean} func - A function that returns a boolean. The interval will continue until this function returns `true`. + * @param {number} interval - The time, in milliseconds, between each call to `func`. + * @returns {Promise} A promise that resolves when `func` returns `true`, or rejects if an error is thrown during execution of `func`. + */ export function waitUntil( func: () => boolean, interval: number,