Skip to content

Commit 3e0e475

Browse files
committed
fix tests
1 parent fc97856 commit 3e0e475

File tree

4 files changed

+78
-34
lines changed

4 files changed

+78
-34
lines changed

src/components/Json/Json.test.tsx

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { fireEvent, render } from '@testing-library/react'
22
import { describe, expect, it } from 'vitest'
33
import Json from './Json.js'
4+
import { isPrimitive, shouldObjectCollapse } from './helpers.js'
45

56
describe('Json Component', () => {
67
it('renders primitive types correctly', () => {
@@ -19,39 +20,81 @@ describe('Json Component', () => {
1920
expect(getByText('"bar"')).toBeDefined()
2021
})
2122

23+
it.for([['foo', 'bar']])('collapses any array', (array) => {
24+
const { queryByText } = render(<Json json={array} />)
25+
expect(queryByText('▶')).toBeDefined()
26+
expect(queryByText('▼')).toBeNull()
27+
})
28+
2229
it('renders an object', () => {
2330
const { getByText } = render(<Json json={{ key: 'value' }} />)
2431
expect(getByText('key:')).toBeDefined()
2532
expect(getByText('"value"')).toBeDefined()
2633
})
2734

2835
it('renders nested objects', () => {
36+
const { getByText } = render(<Json json={{ obj: { arr: [314, '42'] } }} />)
37+
expect(getByText('obj:')).toBeDefined()
38+
expect(getByText('arr:')).toBeDefined()
39+
expect(getByText('314')).toBeDefined()
40+
expect(getByText('"42"')).toBeDefined()
41+
})
42+
43+
it('collapses non-primitive nested objects', () => {
2944
const { getByText } = render(<Json json={{ obj: { arr: [314, null] } }} />)
3045
expect(getByText('obj:')).toBeDefined()
3146
expect(getByText('arr:')).toBeDefined()
3247
expect(getByText('314')).toBeDefined()
33-
expect(getByText('null')).toBeDefined()
48+
expect(getByText('...')).toBeDefined()
3449
})
3550

3651
it('toggles array collapse state', () => {
37-
const { getByText, queryByText } = render(<Json json={['foo', 'bar']} />)
52+
const { getByText, queryByText } = render(<Json json={['foo', null]} />)
3853
expect(getByText('"foo"')).toBeDefined()
39-
expect(getByText('"bar"')).toBeDefined()
54+
expect(queryByText('null')).toBeNull()
55+
fireEvent.click(getByText('▶'))
56+
expect(getByText('null')).toBeDefined()
4057
fireEvent.click(getByText('▼'))
41-
expect(queryByText('0: 1')).toBeNull()
42-
fireEvent.click(getByText('[...]'))
4358
expect(getByText('"foo"')).toBeDefined()
44-
expect(getByText('"bar"')).toBeDefined()
59+
expect(queryByText('null')).toBeNull()
4560
})
4661

4762
it('toggles object collapse state', () => {
4863
const { getByText, queryByText } = render(<Json json={{ key: 'value' }} />)
4964
expect(getByText('key:')).toBeDefined()
5065
expect(getByText('"value"')).toBeDefined()
51-
fireEvent.click(getByText(''))
66+
fireEvent.click(getByText(''))
5267
expect(queryByText('key: "value"')).toBeNull()
53-
fireEvent.click(getByText('{...}'))
68+
fireEvent.click(getByText(''))
5469
expect(getByText('key:')).toBeDefined()
5570
expect(getByText('"value"')).toBeDefined()
5671
})
5772
})
73+
74+
describe('isPrimitive', () => {
75+
it('returns true only for primitive types', () => {
76+
expect(isPrimitive('test')).toBe(true)
77+
expect(isPrimitive(42)).toBe(true)
78+
expect(isPrimitive(true)).toBe(true)
79+
expect(isPrimitive(1n)).toBe(true)
80+
expect(isPrimitive(null)).toBe(false)
81+
expect(isPrimitive(undefined)).toBe(false)
82+
expect(isPrimitive({})).toBe(false)
83+
expect(isPrimitive([])).toBe(false)
84+
})
85+
})
86+
87+
describe('shouldObjectCollapse', () => {
88+
it('returns true for objects with all primitive values', () => {
89+
expect(shouldObjectCollapse({ a: 1, b: 'test' })).toBe(true)
90+
})
91+
92+
it('returns false for objects with non-primitive values', () => {
93+
expect(shouldObjectCollapse({ a: 1, b: {} })).toBe(false)
94+
})
95+
96+
it('returns true for large objects', () => {
97+
const largeObject = Object.fromEntries(Array.from({ length: 101 }, (_, i) => [`key${i}`, i]))
98+
expect(shouldObjectCollapse(largeObject)).toBe(true)
99+
})
100+
})

src/components/Json/Json.tsx

Lines changed: 2 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { ReactNode, useState } from 'react'
22
import styles from './Json.module.css'
3+
import { isPrimitive, shouldObjectCollapse } from './helpers.js'
34

45
interface JsonProps {
56
json: unknown
@@ -36,15 +37,6 @@ function JsonContent({ json, label }: JsonProps): ReactNode {
3637
return div
3738
}
3839

39-
function isPrimitive(value: unknown): boolean {
40-
return (
41-
value !== undefined &&
42-
!Array.isArray(value) &&
43-
typeof value !== 'object' &&
44-
typeof value !== 'function'
45-
)
46-
}
47-
4840
function CollapsedArray({ array }: {array: unknown[]}): ReactNode {
4941
// the character count is approximate, but it should be enough
5042
// to avoid showing too many entries
@@ -148,21 +140,8 @@ function CollapsedObject({ obj }: {obj: object}): ReactNode {
148140
)
149141
}
150142

151-
function shouldCollapse(obj: object): boolean {
152-
const values = Object.values(obj)
153-
if (
154-
// if all the values are primitive
155-
values.every(value => isPrimitive(value))
156-
// if the object has too many entries
157-
|| values.length >= 100
158-
) {
159-
return true
160-
}
161-
return false
162-
}
163-
164143
function JsonObject({ obj, label }: { obj: object, label?: string }): ReactNode {
165-
const [collapsed, setCollapsed] = useState(shouldCollapse(obj))
144+
const [collapsed, setCollapsed] = useState(shouldObjectCollapse(obj))
166145
const key = label ? <span className={styles.key}>{label}: </span> : ''
167146
if (collapsed) {
168147
return <div className={styles.clickable} onClick={() => { setCollapsed(false) }}>

src/components/Json/helpers.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
export function isPrimitive(value: unknown): boolean {
2+
return (
3+
value !== undefined &&
4+
!Array.isArray(value) &&
5+
typeof value !== 'object' &&
6+
typeof value !== 'function'
7+
)
8+
}
9+
10+
export function shouldObjectCollapse(obj: object): boolean {
11+
const values = Object.values(obj)
12+
if (
13+
// if all the values are primitive
14+
values.every(value => isPrimitive(value))
15+
// if the object has too many entries
16+
|| values.length >= 100
17+
) {
18+
return true
19+
}
20+
return false
21+
}

src/components/JsonView/JsonView.test.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,9 @@ globalThis.fetch = vi.fn()
1313
describe('JsonView Component', () => {
1414
const encoder = new TextEncoder()
1515

16-
it('renders json content as nested lists', async () => {
17-
const body = encoder.encode('{"key":"value"}').buffer as ArrayBuffer
16+
it('renders json content as nested lists (if not collapsed)', async () => {
17+
const text = '{"key":["value"]}'
18+
const body = encoder.encode(text).buffer as ArrayBuffer
1819
const source: FileSource = {
1920
resolveUrl: 'testKey0',
2021
kind: 'file',
@@ -25,7 +26,7 @@ describe('JsonView Component', () => {
2526
vi.mocked(fetch).mockResolvedValueOnce({
2627
status: 200,
2728
headers: new Headers({ 'Content-Length': body.byteLength.toString() }),
28-
text: () => Promise.resolve('{"key":"value"}'),
29+
text: () => Promise.resolve(text),
2930
} as Response)
3031

3132
const { findByRole, findByText } = render(

0 commit comments

Comments
 (0)