Skip to content

Commit 2af386f

Browse files
committed
feat(tests): add tests for Fragment, Suspense, and Activity components to verify styling prop handling
1 parent 3b8a4cb commit 2af386f

File tree

1 file changed

+90
-20
lines changed

1 file changed

+90
-20
lines changed

test/node.test.ts

Lines changed: 90 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Div, H1, Node, P, Portal, Root, Span, Text, ThemeProvider, type Theme, type NodeInstance } from '@src/main.js'
1+
import { Component, Div, H1, Node, P, Portal, Root, Span, Text, ThemeProvider, type Theme, type NodeInstance, Fragment, Suspense, Activity } from '@src/main.js'
22
import { act, cleanup, render } from '@testing-library/react'
33
import { createRef, useState } from 'react'
44
import { createSerializer, matchers } from '@emotion/jest'
@@ -12,7 +12,7 @@ afterEach(() => {
1212
})
1313

1414
describe('BaseNode - Core Functionality', () => {
15-
// Test Case 1: Basic Div rendering
15+
// Basic Div rendering
1616
it('should render an empty prop Div node', () => {
1717
const App = Div()
1818
const { container } = render(App.render())
@@ -33,7 +33,7 @@ describe('BaseNode - Core Functionality', () => {
3333
expect(getByText('Hello, World!')).toBeInTheDocument()
3434
})
3535

36-
// Test Case 2: Rendering different HTML elements
36+
// Rendering different HTML elements
3737
it('should render a paragraph (P) element', () => {
3838
const App = P('This is a paragraph.')
3939
const { getByText } = render(App.render())
@@ -55,7 +55,7 @@ describe('BaseNode - Core Functionality', () => {
5555
expect(getByText('Inline Text').tagName).toBe('SPAN')
5656
})
5757

58-
// Test Case 3: Applying basic CSS properties
58+
// Applying basic CSS properties
5959
it('should apply basic CSS properties to a Div', () => {
6060
const App = Div({
6161
children: 'Styled Div',
@@ -70,7 +70,7 @@ describe('BaseNode - Core Functionality', () => {
7070
expect(element).toHaveStyleRule('font-size', '20px')
7171
})
7272

73-
// Test Case 4: Applying `css` prop (Emotion.js)
73+
// Applying `css` prop (Emotion.js)
7474
it('should apply css prop for Emotion styling', () => {
7575
const App = Div({
7676
children: 'Emotion Styled Div',
@@ -82,7 +82,7 @@ describe('BaseNode - Core Functionality', () => {
8282
expect(element).toHaveStyleRule('padding', '10px')
8383
})
8484

85-
// Test Case 5: Handling multiple and nested children
85+
// Handling multiple and nested children
8686
it('should render multiple children', () => {
8787
const App = Div({
8888
children: [P('First paragraph'), P('Second paragraph')],
@@ -105,7 +105,7 @@ describe('BaseNode - Core Functionality', () => {
105105
expect(getByText('Nested Text').parentElement?.parentElement?.tagName).toBe('DIV')
106106
})
107107

108-
// Test Case 6: Handling function as children (render props)
108+
// Handling function as children (render props)
109109
it('should render content from a function as child with props and context from a Provider', () => {
110110
function DataProvider({ children }: { children: (props: { data: string[]; loading: boolean }) => any }) {
111111
const [data] = useState(['User 1', 'User 2'])
@@ -128,7 +128,7 @@ describe('BaseNode - Core Functionality', () => {
128128
expect(getByText('User 2')).toBeInTheDocument()
129129
})
130130

131-
// Test Case 7: Theme propagation and inheritance
131+
// Theme propagation and inheritance
132132
it('should propagate theme to children', () => {
133133
const myTheme: Theme = {
134134
mode: 'light',
@@ -228,7 +228,7 @@ describe('BaseNode - Core Functionality', () => {
228228
expect(computedStyles.color).toBe('rgb(255, 0, 0)')
229229
})
230230

231-
// Test Case 8: `createChildrenFirstNode` usage (e.g., Text)
231+
// `createChildrenFirstNode` usage (e.g., Text)
232232
it('should render Text component with children first', () => {
233233
const App = Text('Hello Text Component', { fontSize: '18px' })
234234
const { getByText } = render(App.render())
@@ -240,7 +240,7 @@ describe('BaseNode - Core Functionality', () => {
240240
}
241241
})
242242

243-
// Test Case 9: `Node` factory usage
243+
// `Node` factory usage
244244
it('should create and render a node using the Node factory', () => {
245245
const App = Node('span', { children: 'Node Factory Span', className: 'my-span' })
246246
const { getByText } = render(App.render())
@@ -252,7 +252,77 @@ describe('BaseNode - Core Functionality', () => {
252252
}
253253
})
254254

255-
// Test Case 10: Root component with default styles (Emotion-based)
255+
// Built-in React components (Fragment, Suspense, Activity)
256+
it('should not apply styling props to Fragment component', () => {
257+
const App = Fragment({
258+
children: Div({ children: 'Fragment Child' }),
259+
// These styling props should be ignored by Fragment
260+
backgroundColor: 'red',
261+
css: { border: '1px solid green' },
262+
})
263+
const { getByText, container } = render(App.render())
264+
265+
// Verify that the child is rendered
266+
const childElement = getByText('Fragment Child')
267+
expect(childElement).toBeInTheDocument()
268+
269+
// Verify that the Fragment itself does not have styling applied
270+
// React Fragment renders as a DocumentFragment, which does not have style properties
271+
expect(container.firstChild).not.toHaveStyleRule('background-color', 'red')
272+
expect(container.firstChild).not.toHaveStyleRule('border', '1px solid green')
273+
274+
// Verify that the child element does not inherit styles from the Fragment (as Fragment should ignore them)
275+
expect(childElement).not.toHaveStyleRule('background-color', 'red')
276+
expect(childElement).not.toHaveStyleRule('border', '1px solid green')
277+
})
278+
279+
it('should not apply styling props to Suspense component', () => {
280+
const App = Suspense({
281+
fallback: Div({ children: 'Loading...' }),
282+
children: Div({ children: 'Suspense Child' }),
283+
// These styling props should be ignored by Suspense
284+
backgroundColor: 'blue',
285+
css: { border: '1px solid yellow' },
286+
})
287+
const { getByText, container } = render(App.render())
288+
289+
// Verify that the child is rendered (or fallback if not yet resolved)
290+
const childElement = getByText('Suspense Child')
291+
expect(childElement).toBeInTheDocument()
292+
293+
// Verify that the Suspense component itself does not have styling applied
294+
// Suspense renders its children directly, or a fallback, and does not create a DOM element for itself
295+
expect(container.firstChild).not.toHaveStyleRule('background-color', 'blue')
296+
expect(container.firstChild).not.toHaveStyleRule('border', '1px solid yellow')
297+
298+
// Verify that the child element does not inherit styles from Suspense (as Suspense should ignore them)
299+
expect(childElement).not.toHaveStyleRule('background-color', 'blue')
300+
expect(childElement).not.toHaveStyleRule('border', '1px solid yellow')
301+
})
302+
303+
it('should not apply styling props to Activity component', () => {
304+
const App = Activity({
305+
children: Div({ children: 'Activity Child' }),
306+
// These styling props should be ignored by Activity
307+
backgroundColor: 'green',
308+
css: { border: '1px solid purple' },
309+
})
310+
const { getByText, container } = render(App.render())
311+
312+
// Verify that the child is rendered
313+
const childElement = getByText('Activity Child')
314+
expect(childElement).toBeInTheDocument()
315+
316+
// Verify that the Activity component itself does not have styling applied
317+
// Activity renders its children directly and does not create a DOM element for itself
318+
expect(container.firstChild).not.toHaveStyleRule('background-color', 'green')
319+
expect(container.firstChild).not.toHaveStyleRule('border', '1px solid purple')
320+
321+
// Verify that the child element does not inherit styles from Activity (as Activity should ignore them)
322+
expect(childElement).not.toHaveStyleRule('background-color', 'green')
323+
expect(childElement).not.toHaveStyleRule('border', '1px solid purple')
324+
})
325+
256326
it('should render Root component and apply styles via Emotion', () => {
257327
const App = Root({ children: 'Root Content' })
258328
const { getByText } = render(App.render())
@@ -261,7 +331,7 @@ describe('BaseNode - Core Functionality', () => {
261331
expect(element).toHaveStyleRule('display', 'flex')
262332
})
263333

264-
// Test Case 11: Props merging with nativeProps
334+
// Root component with default styles (Emotion-based)
265335
it('should merge nativeProps correctly', () => {
266336
const App = Div({
267337
children: 'Native Props Test',
@@ -275,7 +345,7 @@ describe('BaseNode - Core Functionality', () => {
275345
}
276346
})
277347

278-
// Test Case 12: Ref forwarding (basic check, full ref testing is complex)
348+
// Ref forwarding (basic check, full ref testing is complex)
279349
it('should allow ref to be passed', () => {
280350
const ref = createRef<HTMLDivElement>()
281351
const App = Div({ children: 'Ref Test', ref: ref })
@@ -284,7 +354,7 @@ describe('BaseNode - Core Functionality', () => {
284354
expect(ref.current).toHaveTextContent('Ref Test')
285355
})
286356

287-
// Test Case 13: toHaveStyle with inline styles
357+
// toHaveStyle with inline styles
288358
it('should apply inline styles correctly', () => {
289359
const App = Node('div', { children: 'Inline Styled Div', style: { backgroundColor: 'purple', border: '2px solid orange' } })
290360
const { getByText } = render(App.render())
@@ -296,7 +366,7 @@ describe('BaseNode - Core Functionality', () => {
296366
}
297367
})
298368

299-
// Test Case 14: expect custom props type safety (compile-time check)
369+
// expect custom props type safety (compile-time check)
300370
it('should apply custom props with type safety', () => {
301371
const Comp = Div<{ 'data-custom': string }>({ 'data-custom': 'custom-value', children: 'Custom Prop Div' })
302372
const { getByText } = render(Comp.render())
@@ -306,14 +376,14 @@ describe('BaseNode - Core Functionality', () => {
306376
}
307377
})
308378

309-
// Test Case 15: expect custom props type error (compile-time check)
379+
// expect custom props type error (compile-time check)
310380
it('should expect custom props type error', () => {
311381
// This line should cause a TypeScript error as intended
312382
// @ts-expect-error: 'data-custom' should be a string, not a number
313383
Div<{ 'data-custom': string }>({ 'data-custom': 2 })
314384
})
315385

316-
// Test Case 16: Portal System
386+
// Portal System
317387
it('should render content in a portal and unmount it', () => {
318388
const PortalContent = Div({ children: 'Portal Content' })
319389
const MyPortal = Portal(() => PortalContent)
@@ -330,7 +400,7 @@ describe('BaseNode - Core Functionality', () => {
330400
expect(document.body).not.toHaveTextContent('Portal Content')
331401
})
332402

333-
// Test Case 17: Display Name as expected (for debugging and React DevTools)
403+
// Display Name as expected (for debugging and React DevTools)
334404
it('should have correct display names for components', async () => {
335405
function hasDisplayName(type: any): type is { displayName: string } {
336406
return type && typeof type === 'object' && 'displayName' in type
@@ -370,7 +440,7 @@ describe('BaseNode - Core Functionality', () => {
370440
}
371441
})
372442

373-
// Test Case 18: Preserving Node instances in props and resolving themes
443+
// Preserving Node instances in props and resolving themes
374444
it('should preserve Node instances passed in props and resolve their themes correctly', () => {
375445
const theme: Theme = {
376446
mode: 'light',
@@ -426,7 +496,7 @@ describe('BaseNode - Core Functionality', () => {
426496
expect(window.getComputedStyle(elementTwo).color).toBe('rgb(0, 0, 255)')
427497
})
428498

429-
// Test Case 19: disableEmotion propagation
499+
// disableEmotion propagation
430500
it('should propagate disableEmotion to children and prevent styling', () => {
431501
const App = Div({
432502
disableEmotion: true,

0 commit comments

Comments
 (0)