UNPKG

@applicaster/zapp-react-native-utils

Version:

Applicaster Zapp React Native utilities package

361 lines (292 loc) 11.7 kB
jest.mock("../../../logger", () => { const mockLogError = jest.fn(); return { createLogger: jest.fn(() => ({ log_error: mockLogError, })), __mockLogError: mockLogError, // Export for test access }; }); import { calculateReadingTime } from "../utils"; // @ts-ignore - Access the mock import { __mockLogError } from "../../../logger"; describe("calculateReadingTime", () => { // Default parameters for reference const DEFAULT_WPM = 140; const DEFAULT_MIN_PAUSE = 500; const DEFAULT_DELAY = 700; beforeEach(() => { (__mockLogError as jest.Mock).mockClear(); }); describe("Type Safety", () => { it("should accept and process string input", () => { const result = calculateReadingTime("Hello world"); expect(result).toBeGreaterThan(0); expect(__mockLogError).not.toHaveBeenCalled(); }); it("should accept and process number input", () => { const result = calculateReadingTime(12345); expect(result).toBeGreaterThan(0); expect(__mockLogError).not.toHaveBeenCalled(); }); it("should return 0 and log error for null", () => { expect(calculateReadingTime(null as any)).toBe(0); expect(__mockLogError).toHaveBeenCalledWith( "Invalid text input for reading time calculation got: null" ); }); it("should return 0 and log error for undefined", () => { expect(calculateReadingTime(undefined as any)).toBe(0); expect(__mockLogError).toHaveBeenCalledWith( "Invalid text input for reading time calculation got: undefined" ); }); it("should return 0 and log error for boolean", () => { calculateReadingTime(true as any); expect(__mockLogError).toHaveBeenCalledWith( "Invalid text input for reading time calculation got: true" ); (__mockLogError as jest.Mock).mockClear(); calculateReadingTime(false as any); expect(__mockLogError).toHaveBeenCalledWith( "Invalid text input for reading time calculation got: false" ); }); it("should return 0 and log error for object", () => { const obj = { text: "hello" }; calculateReadingTime(obj as any); expect(__mockLogError).toHaveBeenCalledWith( `Invalid text input for reading time calculation got: ${obj}` ); }); it("should return 0 and log error for array", () => { const arr = [1, 2, 3]; calculateReadingTime(arr as any); expect(__mockLogError).toHaveBeenCalledWith( `Invalid text input for reading time calculation got: ${arr}` ); }); it("should return 0 and log error for function", () => { const fn = () => "text"; calculateReadingTime(fn as any); expect(__mockLogError).toHaveBeenCalled(); expect((__mockLogError as jest.Mock).mock.calls[0][0]).toContain( "Invalid text input for reading time calculation got:" ); }); it("should return 0 and log error for symbol", () => { const sym = Symbol("test"); calculateReadingTime(sym as any); expect(__mockLogError).toHaveBeenCalled(); expect((__mockLogError as jest.Mock).mock.calls[0][0]).toBe( `Invalid text input for reading time calculation got: ${String(sym)}` ); }); }); describe("Empty and Whitespace Handling", () => { it("should return 0 for empty string", () => { expect(calculateReadingTime("")).toBe(0); }); it("should return 0 for whitespace-only string", () => { expect(calculateReadingTime(" ")).toBe(0); expect(calculateReadingTime("\n")).toBe(0); expect(calculateReadingTime("\t")).toBe(0); expect(calculateReadingTime(" \n\t ")).toBe(0); }); it("should handle leading and trailing whitespace", () => { const withWhitespace = calculateReadingTime(" hello "); const withoutWhitespace = calculateReadingTime("hello"); expect(withWhitespace).toBe(withoutWhitespace); }); }); describe("Number Input Handling", () => { it("should convert number 0 to string and process", () => { const result = calculateReadingTime(0); // "0" is one word expect(result).toBeGreaterThan(0); }); it("should convert positive numbers to string", () => { const result = calculateReadingTime(123); // "123" is one word expect(result).toBeGreaterThan(0); }); it("should convert negative numbers to string", () => { const result = calculateReadingTime(-456); // "-456" is processed as words expect(result).toBeGreaterThan(0); }); it("should convert decimal numbers to string", () => { const result = calculateReadingTime(3.14); // "3.14" is processed as words expect(result).toBeGreaterThan(0); }); it("should handle NaN", () => { const result = calculateReadingTime(NaN); // NaN is typeof "number", so it converts to "NaN" string expect(result).toBeGreaterThan(0); }); it("should handle Infinity", () => { const result = calculateReadingTime(Infinity); // Infinity is typeof "number", converts to "Infinity" string expect(result).toBeGreaterThan(0); }); }); describe("Word Counting", () => { it("should count single word", () => { const result = calculateReadingTime("Hello"); const expectedTime = Math.max( DEFAULT_MIN_PAUSE, (1 / DEFAULT_WPM) * 60 * 1000 ); expect(result).toBe(expectedTime + DEFAULT_DELAY); }); it("should count multiple words separated by spaces", () => { const result = calculateReadingTime("Hello world test"); // 3 words const expectedTime = Math.max( DEFAULT_MIN_PAUSE, (3 / DEFAULT_WPM) * 60 * 1000 ); expect(result).toBe(expectedTime + DEFAULT_DELAY); }); it("should handle words with punctuation", () => { const result = calculateReadingTime("Hello, world! How are you?"); // Should split on punctuation and count words expect(result).toBeGreaterThan(DEFAULT_MIN_PAUSE + DEFAULT_DELAY); }); it("should handle alphanumeric boundaries", () => { const result = calculateReadingTime("test123abc"); // Should split on alphanumeric boundaries expect(result).toBeGreaterThan(DEFAULT_MIN_PAUSE + DEFAULT_DELAY); }); it("should handle long text", () => { const longText = "word ".repeat(200); // 200 words const result = calculateReadingTime(longText); const expectedTime = (200 / DEFAULT_WPM) * 60 * 1000 + DEFAULT_DELAY; expect(result).toBeCloseTo(expectedTime, -1); // Within 10ms }); }); describe("Minimum Pause", () => { it("should return minimum pause + delay for very short text", () => { const result = calculateReadingTime("Hi"); // 1 word, calculation would be less than minimum pause expect(result).toBe(DEFAULT_MIN_PAUSE + DEFAULT_DELAY); }); it("should respect custom minimum pause", () => { const customMinPause = 1000; const result = calculateReadingTime("Hi", DEFAULT_WPM, customMinPause); expect(result).toBeGreaterThanOrEqual(customMinPause); }); it("should exceed minimum pause for longer text", () => { const longText = "word ".repeat(50); // 50 words const result = calculateReadingTime(longText); const calculatedTime = (50 / DEFAULT_WPM) * 60 * 1000; expect(result).toBe(calculatedTime + DEFAULT_DELAY); expect(result).toBeGreaterThan(DEFAULT_MIN_PAUSE + DEFAULT_DELAY); }); }); describe("Custom Parameters", () => { it("should respect custom words per minute", () => { const text = "word ".repeat(140); // 140 words const fastReading = calculateReadingTime(text, 280); // 2x speed const normalReading = calculateReadingTime(text, 140); // normal speed // Faster reading should take less time expect(fastReading).toBeLessThan(normalReading); }); it("should respect custom announcement delay", () => { const text = "Hello world"; const shortDelay = calculateReadingTime( text, DEFAULT_WPM, DEFAULT_MIN_PAUSE, 100 ); const longDelay = calculateReadingTime( text, DEFAULT_WPM, DEFAULT_MIN_PAUSE, 1000 ); expect(longDelay - shortDelay).toBe(900); }); it("should work with all custom parameters", () => { const result = calculateReadingTime("test", 200, 1000, 500); expect(result).toBeGreaterThanOrEqual(1500); // minimum pause + delay }); }); describe("Real-world Use Cases", () => { it("should handle accessibility announcement text", () => { const announcement = "New message from John Doe"; const result = calculateReadingTime(announcement); expect(result).toBeGreaterThan(0); expect(result).toBeLessThan(10000); // Less than 10 seconds }); it("should handle button labels", () => { const label = "Submit"; const result = calculateReadingTime(label); expect(result).toBe(DEFAULT_MIN_PAUSE + DEFAULT_DELAY); }); it("should handle form error messages", () => { const error = "Please enter a valid email address"; const result = calculateReadingTime(error); expect(result).toBeGreaterThan(DEFAULT_MIN_PAUSE); }); it("should handle article titles", () => { const title = "Breaking News: Major Update Released"; const result = calculateReadingTime(title); expect(result).toBeGreaterThan(DEFAULT_MIN_PAUSE + DEFAULT_DELAY); }); it("should handle notification text", () => { const notification = "You have 3 new messages"; const result = calculateReadingTime(notification); expect(result).toBeGreaterThan(0); }); }); describe("Edge Cases", () => { it("should handle text with special characters", () => { const result = calculateReadingTime("@#$%^&*()"); expect(result).toBeGreaterThanOrEqual(0); }); it("should handle text with emojis", () => { const result = calculateReadingTime("Hello 👋 World 🌍"); expect(result).toBeGreaterThan(0); }); it("should handle text with newlines", () => { const result = calculateReadingTime("Line 1\nLine 2\nLine 3"); expect(result).toBeGreaterThan(0); }); it("should handle mixed alphanumeric text", () => { const result = calculateReadingTime( "Version 1.2.3 released on 2024-01-01" ); expect(result).toBeGreaterThan(0); }); it("should handle very large numbers", () => { const result = calculateReadingTime(Number.MAX_SAFE_INTEGER); expect(result).toBeGreaterThan(0); }); it("should return consistent results for same input", () => { const text = "Consistent test"; const result1 = calculateReadingTime(text); const result2 = calculateReadingTime(text); const result3 = calculateReadingTime(text); expect(result1).toBe(result2); expect(result2).toBe(result3); }); }); describe("Performance Characteristics", () => { it("should handle empty input efficiently", () => { const start = Date.now(); calculateReadingTime(""); const duration = Date.now() - start; expect(duration).toBeLessThan(10); // Should be nearly instant }); it("should handle large text efficiently", () => { const largeText = "word ".repeat(10000); const start = Date.now(); calculateReadingTime(largeText); const duration = Date.now() - start; expect(duration).toBeLessThan(100); // Should complete in less than 100ms }); }); });