Skip to content

Commit 980e70e

Browse files
committed
Polish tests & code
1 parent 553c900 commit 980e70e

File tree

5 files changed

+224
-96
lines changed

5 files changed

+224
-96
lines changed

src/index.test.tsx

Lines changed: 41 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -170,21 +170,13 @@ describe('useLog', () => {
170170
expect(consoleLog).toBeCalledTimes(11)
171171
expect(consoleGroup).toBeCalledTimes(6)
172172
})
173-
174-
it('does not render anything in production', () => {
175-
process.env.NODE_ENV = 'production'
176-
177-
const { result } = renderHook(useLog)
178-
renderHook(() => result.current.log('Test'))
179-
expect(consoleLog).not.toBeCalled()
180-
})
181-
182173
it('renders hook with custom styles', () => {
183174
renderHook(() => {
184175
const { log } = useLog({ styles: { componentCSS: 'color: darkBlue;' } })
185176
log('Test')
186177
})
187178

179+
// first call, second parameter (css for component name) should be modified
188180
expect(consoleGroup.mock.calls[0][1]).toBe('color: darkBlue;')
189181
})
190182

@@ -194,7 +186,37 @@ describe('useLog', () => {
194186
log('Test', { styles: { componentCSS: 'color: darkRed;' } })
195187
})
196188

197-
expect(consoleGroup.mock.calls[1][1]).toBe('color: darkRed;')
189+
// first call, second parameter (css for component name) should be modified
190+
expect(consoleGroup.mock.calls[0][1]).toBe('color: darkRed;')
191+
})
192+
193+
it('renders log with custom styles for subValueCSS', () => {
194+
renderHook(() => {
195+
const { log } = useLog({ styles: { subValueCSS: 'color: darkBlue;' } })
196+
log('Test', { styles: { subValueCSS: 'color: darkRed;' } })
197+
})
198+
199+
// first call, third parameter (css for call time) should be modified
200+
expect(consoleGroup.mock.calls[0][2]).toBe('color: darkRed;')
201+
})
202+
203+
it('renders log with custom styles for changeCSS', () => {
204+
renderHook(() => {
205+
const { log } = useLog({ styles: { changeCSS: 'color: darkBlue;' } })
206+
log('Test', { styles: { changeCSS: 'color: darkRed;' } })
207+
})
208+
209+
// third call, third parameter (css for new value) should be modified
210+
expect(consoleLog.mock.calls[2][1]).toBe('color: darkRed;')
211+
})
212+
213+
it('does not render anything in production', () => {
214+
process.env.NODE_ENV = 'production'
215+
216+
const { result } = renderHook(useLog)
217+
renderHook(() => result.current.log('Test'))
218+
219+
expect(consoleLog).not.toBeCalled()
198220
})
199221

200222
it('renders anything in custom allowed environments', () => {
@@ -207,4 +229,13 @@ describe('useLog', () => {
207229

208230
expect(consoleLog).toBeCalled()
209231
})
232+
233+
it('falls back to production for empty node_env', () => {
234+
process.env.NODE_ENV = undefined
235+
236+
const { result } = renderHook(useLog)
237+
renderHook(() => result.current.log('Test'))
238+
239+
expect(consoleLog).not.toBeCalled()
240+
})
210241
})

src/index.tsx

Lines changed: 23 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,13 @@
11
import { useEffect, useRef } from 'react'
2+
import { UseLog, UseLogReturn, Log, PrintTypes, PrintProps } from './types'
3+
import { getComponentName, print } from './utils'
24

35
const CSS_COMPONENT = 'color: DodgerBlue'
46
const CSS_CHANGE = 'color: green; font-weight: bold;'
57
const CSS_SUB_VALUE = 'color: SlateGray; font-weight: thin;'
68

79
const ALLOWED_NODE_ENVS = ['dev', 'development']
810

9-
export interface UseLog {
10-
styles?: {
11-
componentCSS?: string
12-
changeCSS?: string
13-
subValueCSS?: string
14-
}
15-
environments?: string[]
16-
}
17-
18-
export type Log = UseLog
19-
20-
export interface UseLogReturn {
21-
log: <T>(value: T, props?: Log) => void
22-
}
23-
24-
interface PrintProps<T> {
25-
value: T
26-
prevValue?: T
27-
label: string
28-
group?: string
29-
type?: PrintTypes
30-
}
31-
32-
export enum PrintTypes {
33-
Mount = 'Mount',
34-
Unmount = 'Unmount',
35-
Change = 'Change',
36-
}
37-
3811
export function useLog({
3912
styles: {
4013
componentCSS = CSS_COMPONENT,
@@ -43,64 +16,26 @@ export function useLog({
4316
} = {},
4417
environments = ALLOWED_NODE_ENVS,
4518
}: UseLog = {}): UseLogReturn {
46-
const componentName =
47-
(function getComponentName() {
48-
try {
49-
throw new Error()
50-
} catch (error) {
51-
if (error instanceof Error) {
52-
const re = /(\w+)@|at (\w+) \(/g
53-
54-
re.exec(error?.stack ?? '')
55-
re.exec(error?.stack ?? '')
56-
const m = re.exec(error?.stack ?? '') ?? []
57-
58-
return String(m[1] || m[2])
59-
}
60-
}
61-
})() ?? ''
62-
63-
function getGroupLabel(type: PrintTypes): string {
64-
return `${String(type)} ${
65-
componentName ? 'in %c<' + String(componentName) + ' /> ' : '%c'
66-
}%c@ ${new Date().toLocaleTimeString()}`
67-
}
19+
const componentName = getComponentName()
6820

6921
function log<T>(value: T, props?: Log): void {
70-
const clonedValue = JSON.parse(JSON.stringify(value))
22+
const clonedValue = JSON.parse(JSON.stringify(value)) as T
7123
const prevValueRef = useRef<T>()
72-
73-
function print<T>({
74-
value,
75-
label,
76-
prevValue,
77-
type = PrintTypes.Change,
78-
group = getGroupLabel(type),
79-
}: PrintProps<T>): void {
80-
console.group(
81-
group,
82-
props?.styles?.componentCSS ?? componentCSS,
83-
props?.styles?.subValueCSS ?? subValueCSS,
84-
)
85-
86-
if (!('prevValue' in arguments[0])) {
87-
console.log(`${label.padStart(14, ' ')}: ${String(value)}`)
88-
} else {
89-
console.log(
90-
`Previous value: %c${String(arguments[0].prevValue)}`,
91-
props?.styles?.subValueCSS ?? subValueCSS,
92-
)
93-
console.log(
94-
` Current value: %c${String(value)}`,
95-
props?.styles?.changeCSS ?? changeCSS,
96-
)
97-
}
98-
99-
console.groupEnd()
24+
const printProps: Pick<
25+
PrintProps<T>,
26+
'value' | 'styles' | 'componentName'
27+
> = {
28+
value: clonedValue,
29+
styles: {
30+
componentCSS: props?.styles?.componentCSS ?? componentCSS,
31+
subValueCSS: props?.styles?.subValueCSS ?? subValueCSS,
32+
changeCSS: props?.styles?.changeCSS ?? changeCSS,
33+
},
34+
componentName,
10035
}
10136

102-
if (environments.includes(process.env.NODE_ENV ?? '')) {
103-
return (function logHooks() {
37+
if (environments.includes(process.env.NODE_ENV ?? 'production')) {
38+
function logHooks(): void {
10439
const isUnmounting = useRef(false)
10540
useEffect(function setIsUnmounting() {
10641
return function setIsUnmountingOnMount() {
@@ -111,18 +46,18 @@ export function useLog({
11146
useEffect(function onMount() {
11247
print({
11348
label: 'On mount',
114-
value: clonedValue,
11549
type: PrintTypes.Mount,
50+
...printProps,
11651
})
11752

11853
prevValueRef.current = value
11954

12055
return function onUnmount() {
12156
print({
12257
label: 'On unmount',
123-
value: clonedValue,
12458
type: PrintTypes.Unmount,
12559
prevValue: prevValueRef.current,
60+
...printProps,
12661
})
12762
}
12863
}, [])
@@ -131,16 +66,18 @@ export function useLog({
13166
function onChange() {
13267
print({
13368
label: 'On change',
134-
value: clonedValue,
13569
type: PrintTypes.Change,
13670
prevValue: prevValueRef.current,
71+
...printProps,
13772
})
13873

13974
prevValueRef.current = value
14075
},
14176
[value],
14277
)
143-
})()
78+
}
79+
80+
return logHooks()
14481
}
14582
}
14683

src/types.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
export interface Styles {
2+
componentCSS?: string
3+
changeCSS?: string
4+
subValueCSS?: string
5+
}
6+
7+
export interface UseLog {
8+
styles?: Styles
9+
environments?: string[]
10+
}
11+
12+
export type Log = UseLog
13+
14+
export interface UseLogReturn {
15+
log: <T>(value: T, props?: Log) => void
16+
}
17+
18+
export interface PrintProps<T> {
19+
value: T
20+
prevValue?: T
21+
label: string
22+
group?: string
23+
type?: PrintTypes
24+
styles?: Styles
25+
componentName: string
26+
}
27+
28+
export enum PrintTypes {
29+
Mount = 'Mount',
30+
Unmount = 'Unmount',
31+
Change = 'Change',
32+
}

src/utils.test.ts

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { getGroupLabel, getComponentName, print } from './utils'
2+
import { PrintProps, PrintTypes } from './types'
3+
4+
describe('utils', () => {
5+
describe('getGroupLabel', () => {
6+
it('renders', () => {
7+
expect(getGroupLabel(PrintTypes.Change)).toEqual(
8+
`Change %c%c@ ${new Date().toLocaleTimeString()}`,
9+
)
10+
})
11+
12+
it('renders with component name', () => {
13+
expect(getGroupLabel(PrintTypes.Mount, 'TestComponent')).toEqual(
14+
`Mount in %c<TestComponent /> %c@ ${new Date().toLocaleTimeString()}`,
15+
)
16+
})
17+
})
18+
19+
describe('getComponentName', () => {
20+
it('gets component name', () => {
21+
expect(getComponentName()).toEqual('_callCircusTest')
22+
})
23+
})
24+
25+
describe('print', () => {
26+
const consoleLog = jest.spyOn(console, 'log').mockImplementation(() => null)
27+
const consoleGroup = jest
28+
.spyOn(console, 'group')
29+
.mockImplementation(() => null)
30+
const consoleGroupEnd = jest
31+
.spyOn(console, 'groupEnd')
32+
.mockImplementation(() => null)
33+
34+
const printProps: PrintProps<string> = {
35+
value: 'Test Value',
36+
label: 'A Label',
37+
componentName: 'SomeComponentName',
38+
}
39+
40+
it('prints', () => {
41+
print(printProps)
42+
43+
expect(consoleGroup).toHaveBeenCalledWith(
44+
`Change in %c<SomeComponentName /> %c@ ${new Date().toLocaleTimeString()}`,
45+
undefined,
46+
undefined,
47+
)
48+
expect(consoleLog).toHaveBeenCalledWith(' A Label: Test Value')
49+
expect(consoleLog).toHaveBeenCalledTimes(1)
50+
expect(consoleGroupEnd).toHaveBeenCalled()
51+
})
52+
53+
it('prints previous value', () => {
54+
print({ ...printProps, prevValue: 'Some Previous value' })
55+
56+
expect(consoleGroup).toHaveBeenCalledWith(
57+
`Change in %c<SomeComponentName /> %c@ ${new Date().toLocaleTimeString()}`,
58+
undefined,
59+
undefined,
60+
)
61+
expect(consoleLog).toHaveBeenCalledWith(
62+
'Previous value: %cSome Previous value',
63+
undefined,
64+
)
65+
expect(consoleLog).toHaveBeenCalledWith(
66+
' Current value: %cTest Value',
67+
undefined,
68+
)
69+
expect(consoleLog).toHaveBeenCalledTimes(2)
70+
expect(consoleGroupEnd).toHaveBeenCalled()
71+
})
72+
})
73+
})

0 commit comments

Comments
 (0)