Skip to content

Commit 743ba6c

Browse files
justin808claude
andcommitted
test: Add comprehensive tests for JavaScript debug logging
Add comprehensive test coverage for the debug logging features implemented in PR #1934 (Part 2 of 3 in the improvement series). The tests verify: - logComponentRegistration option for opt-in component registration logging - debugMode option for detailed debug output including component sizes - Performance metrics tracking using performance.now() with Date.now() fallback - Non-intrusive behavior with zero production impact - Option validation and reset functionality All tests pass and ensure the feature works as expected without affecting normal component registration functionality. Related to #1834 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent 23be9a9 commit 743ba6c

File tree

1 file changed

+248
-0
lines changed

1 file changed

+248
-0
lines changed
Lines changed: 248 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,248 @@
1+
/* eslint-disable react/jsx-filename-extension */
2+
3+
import * as React from 'react';
4+
import ComponentRegistry from '../src/ComponentRegistry.ts';
5+
import ReactOnRails from '../src/ReactOnRails.client.ts';
6+
7+
describe('Debug Logging', () => {
8+
let consoleLogSpy;
9+
10+
beforeEach(() => {
11+
// Clear registries before each test
12+
ComponentRegistry.clear();
13+
14+
// Reset options to defaults
15+
ReactOnRails.resetOptions();
16+
17+
// Spy on console.log
18+
consoleLogSpy = jest.spyOn(console, 'log').mockImplementation(() => {});
19+
});
20+
21+
afterEach(() => {
22+
// Restore console.log
23+
consoleLogSpy.mockRestore();
24+
});
25+
26+
describe('logComponentRegistration option', () => {
27+
it('does not log when logComponentRegistration is false (default)', () => {
28+
const TestComponent = () => <div>Test</div>;
29+
30+
ReactOnRails.register({ TestComponent });
31+
32+
expect(consoleLogSpy).not.toHaveBeenCalled();
33+
});
34+
35+
it('logs component registration when logComponentRegistration is true', () => {
36+
ReactOnRails.setOptions({ logComponentRegistration: true });
37+
38+
const TestComponent = () => <div>Test</div>;
39+
ReactOnRails.register({ TestComponent });
40+
41+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Component registration logging enabled');
42+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Registering 1 component(s): TestComponent');
43+
expect(consoleLogSpy).toHaveBeenCalledWith(
44+
expect.stringMatching(/\[ReactOnRails\] Component registration completed in \d+\.\d+ms/),
45+
);
46+
});
47+
48+
it('logs multiple components registration', () => {
49+
ReactOnRails.setOptions({ logComponentRegistration: true });
50+
51+
const Component1 = () => <div>One</div>;
52+
const Component2 = () => <div>Two</div>;
53+
const Component3 = () => <div>Three</div>;
54+
55+
ReactOnRails.register({ Component1, Component2, Component3 });
56+
57+
expect(consoleLogSpy).toHaveBeenCalledWith(
58+
'[ReactOnRails] Registering 3 component(s): Component1, Component2, Component3',
59+
);
60+
expect(consoleLogSpy).toHaveBeenCalledWith(
61+
expect.stringMatching(/\[ReactOnRails\] Component registration completed in \d+\.\d+ms/),
62+
);
63+
});
64+
65+
it('measures registration timing using performance.now() when available', () => {
66+
ReactOnRails.setOptions({ logComponentRegistration: true });
67+
68+
const TestComponent = () => <div>Test</div>;
69+
ReactOnRails.register({ TestComponent });
70+
71+
// Verify timing was logged in milliseconds with 2 decimal places
72+
expect(consoleLogSpy).toHaveBeenCalledWith(
73+
expect.stringMatching(/\[ReactOnRails\] Component registration completed in \d+\.\d{2}ms/),
74+
);
75+
});
76+
});
77+
78+
describe('debugMode option', () => {
79+
it('does not log when debugMode is false (default)', () => {
80+
const TestComponent = () => <div>Test</div>;
81+
82+
ReactOnRails.register({ TestComponent });
83+
84+
expect(consoleLogSpy).not.toHaveBeenCalled();
85+
});
86+
87+
it('logs when debugMode is enabled', () => {
88+
ReactOnRails.setOptions({ debugMode: true });
89+
90+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Debug mode enabled');
91+
});
92+
93+
it('logs component registration details when debugMode is true', () => {
94+
ReactOnRails.setOptions({ debugMode: true });
95+
96+
const TestComponent = () => <div>Test</div>;
97+
ReactOnRails.register({ TestComponent });
98+
99+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Registering 1 component(s): TestComponent');
100+
expect(consoleLogSpy).toHaveBeenCalledWith(
101+
expect.stringMatching(/\[ReactOnRails\] Component registration completed in \d+\.\d+ms/),
102+
);
103+
expect(consoleLogSpy).toHaveBeenCalledWith(
104+
expect.stringMatching(/\[ReactOnRails\] Registered: TestComponent \(~\d+\.\d+ chars\)/),
105+
);
106+
});
107+
108+
it('logs individual component sizes in debug mode', () => {
109+
ReactOnRails.setOptions({ debugMode: true });
110+
111+
const SmallComponent = () => <div>S</div>;
112+
const LargerComponent = () => (
113+
<div>
114+
<p>This is a larger component with more content</p>
115+
<p>And another paragraph to make it bigger</p>
116+
</div>
117+
);
118+
119+
ReactOnRails.register({ SmallComponent, LargerComponent });
120+
121+
// Check that individual component registrations are logged with size info
122+
expect(consoleLogSpy).toHaveBeenCalledWith(
123+
expect.stringMatching(/\[ReactOnRails\] Registered: SmallComponent \(~\d+\.\d+ chars\)/),
124+
);
125+
expect(consoleLogSpy).toHaveBeenCalledWith(
126+
expect.stringMatching(/\[ReactOnRails\] Registered: LargerComponent \(~\d+\.\d+ chars\)/),
127+
);
128+
});
129+
130+
it('logs all registration info when both debugMode and logComponentRegistration are enabled', () => {
131+
ReactOnRails.setOptions({
132+
debugMode: true,
133+
logComponentRegistration: true,
134+
});
135+
136+
const TestComponent = () => <div>Test</div>;
137+
ReactOnRails.register({ TestComponent });
138+
139+
// Should log both general info and detailed component info
140+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Debug mode enabled');
141+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Component registration logging enabled');
142+
expect(consoleLogSpy).toHaveBeenCalledWith('[ReactOnRails] Registering 1 component(s): TestComponent');
143+
expect(consoleLogSpy).toHaveBeenCalledWith(
144+
expect.stringMatching(/\[ReactOnRails\] Component registration completed in \d+\.\d+ms/),
145+
);
146+
expect(consoleLogSpy).toHaveBeenCalledWith(
147+
expect.stringMatching(/\[ReactOnRails\] Registered: TestComponent \(~\d+\.\d+ chars\)/),
148+
);
149+
});
150+
});
151+
152+
describe('performance fallback', () => {
153+
it('falls back to Date.now() when performance is not available', () => {
154+
// Save original performance object
155+
const originalPerformance = global.performance;
156+
157+
// Remove performance temporarily
158+
delete global.performance;
159+
160+
ReactOnRails.setOptions({ logComponentRegistration: true });
161+
162+
const TestComponent = () => <div>Test</div>;
163+
ReactOnRails.register({ TestComponent });
164+
165+
// Should still log timing information
166+
expect(consoleLogSpy).toHaveBeenCalledWith(
167+
expect.stringMatching(/\[ReactOnRails\] Component registration completed in \d+\.\d+ms/),
168+
);
169+
170+
// Restore performance
171+
global.performance = originalPerformance;
172+
});
173+
});
174+
175+
describe('option validation', () => {
176+
it('accepts valid debugMode option', () => {
177+
expect(() => ReactOnRails.setOptions({ debugMode: true })).not.toThrow();
178+
expect(() => ReactOnRails.setOptions({ debugMode: false })).not.toThrow();
179+
});
180+
181+
it('accepts valid logComponentRegistration option', () => {
182+
expect(() => ReactOnRails.setOptions({ logComponentRegistration: true })).not.toThrow();
183+
expect(() => ReactOnRails.setOptions({ logComponentRegistration: false })).not.toThrow();
184+
});
185+
186+
it('can retrieve options via option() method', () => {
187+
ReactOnRails.setOptions({ debugMode: true, logComponentRegistration: true });
188+
189+
expect(ReactOnRails.option('debugMode')).toBe(true);
190+
expect(ReactOnRails.option('logComponentRegistration')).toBe(true);
191+
});
192+
193+
it('resetOptions() resets debug options to defaults', () => {
194+
ReactOnRails.setOptions({ debugMode: true, logComponentRegistration: true });
195+
ReactOnRails.resetOptions();
196+
197+
expect(ReactOnRails.option('debugMode')).toBe(false);
198+
expect(ReactOnRails.option('logComponentRegistration')).toBe(false);
199+
});
200+
});
201+
202+
describe('non-intrusive logging', () => {
203+
it('does not affect component registration functionality', () => {
204+
ReactOnRails.setOptions({ debugMode: true, logComponentRegistration: true });
205+
206+
const TestComponent = () => <div>Test</div>;
207+
ReactOnRails.register({ TestComponent });
208+
209+
// Component should still be properly registered
210+
const registered = ReactOnRails.getComponent('TestComponent');
211+
expect(registered.name).toBe('TestComponent');
212+
expect(registered.component).toBe(TestComponent);
213+
});
214+
215+
it('does not affect multiple component registration', () => {
216+
ReactOnRails.setOptions({ debugMode: true });
217+
218+
const Comp1 = () => <div>1</div>;
219+
const Comp2 = () => <div>2</div>;
220+
const Comp3 = () => <div>3</div>;
221+
222+
ReactOnRails.register({ Comp1, Comp2, Comp3 });
223+
224+
// All components should be registered correctly
225+
expect(ReactOnRails.registeredComponents().size).toBe(3);
226+
expect(ReactOnRails.getComponent('Comp1').component).toBe(Comp1);
227+
expect(ReactOnRails.getComponent('Comp2').component).toBe(Comp2);
228+
expect(ReactOnRails.getComponent('Comp3').component).toBe(Comp3);
229+
});
230+
});
231+
232+
describe('zero production impact', () => {
233+
it('has minimal overhead when debug options are disabled', () => {
234+
const TestComponent = () => <div>Test</div>;
235+
236+
// Register without debug options
237+
const startTime = performance.now();
238+
ReactOnRails.register({ TestComponent });
239+
const endTime = performance.now();
240+
241+
// No console logging should occur
242+
expect(consoleLogSpy).not.toHaveBeenCalled();
243+
244+
// Registration should complete quickly (sanity check, not a strict performance test)
245+
expect(endTime - startTime).toBeLessThan(100);
246+
});
247+
});
248+
});

0 commit comments

Comments
 (0)