From 5bed0317be0e9374a5adb8e626e21cf5753da829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AD=99=E4=B8=80=E5=86=B0?= <14512567+sunyibing@user.noreply.gitee.com> Date: Fri, 23 Aug 2024 11:55:19 +0800 Subject: [PATCH] test: add API-2.0 tests --- packages/inula-next/test/conditional.test.tsx | 117 ++++ packages/inula-next/test/context.test.tsx | 126 ++++ packages/inula-next/test/customHook.test.tsx | 356 ++++++++++++ packages/inula-next/test/event.test.tsx | 543 ++++++++++++++++++ packages/inula-next/test/for.test.tsx | 73 ++- packages/inula-next/test/jsxSlice.test.tsx | 274 +++++++++ packages/inula-next/test/props.test.tsx | 190 ++++++ packages/inula-next/test/rendering.test.tsx | 20 + 8 files changed, 1698 insertions(+), 1 deletion(-) create mode 100644 packages/inula-next/test/event.test.tsx diff --git a/packages/inula-next/test/conditional.test.tsx b/packages/inula-next/test/conditional.test.tsx index ab2b4b41..0724ddf6 100644 --- a/packages/inula-next/test/conditional.test.tsx +++ b/packages/inula-next/test/conditional.test.tsx @@ -146,3 +146,120 @@ describe('conditional rendering', () => { expect(container.innerHTML).toMatchInlineSnapshot(`"

hello world 2

"`); }); }); + +describe('additional conditional rendering tests', () => { + it('Should correctly render content based on a single if condition', ({ container }) => { + let set: (num: number) => void; + + function App() { + let count = 0; + set = (val: number) => { + count = val; + }; + return ( +
+ 5}>Count is greater than 5 +
+ ); + } + + render(App, container); + expect(container.innerHTML).toBe('
'); + set(6); + expect(container.innerHTML).toBe('
Count is greater than 5
'); + }); + + it('Should correctly render content based on if-else conditions', ({ container }) => { + let set: (num: number) => void; + + function App() { + let count = 0; + set = (val: number) => { + count = val; + }; + return ( +
+ Count is even + Count is odd +
+ ); + } + + render(App, container); + expect(container.innerHTML).toBe('
Count is even
'); + set(1); + expect(container.innerHTML).toBe('
Count is odd
'); + set(2); + expect(container.innerHTML).toBe('
Count is even
'); + }); + + it('Should correctly render content based on if-else-if-else conditions', ({ container }) => { + let set: (num: number) => void; + + function App() { + let count = 0; + set = (val: number) => { + count = val; + }; + return ( +
+ 10}>Count is greater than 10 + 5}>Count is greater than 5 but not greater than 10 + 0}>Count is greater than 0 but not greater than 5 + Count is 0 or negative +
+ ); + } + + render(App, container); + expect(container.innerHTML).toBe('
Count is 0 or negative
'); + set(3); + expect(container.innerHTML).toBe('
Count is greater than 0 but not greater than 5
'); + set(7); + expect(container.innerHTML).toBe('
Count is greater than 5 but not greater than 10
'); + set(11); + expect(container.innerHTML).toBe('
Count is greater than 10
'); + }); + + it('Should correctly handle nested conditional rendering', ({ container }) => { + let set: (obj: { x: number; y: number }) => void; + + function App() { + let state = { x: 0, y: 0 }; + set = (val: { x: number; y: number }) => { + state = val; + }; + return ( +
+ 0}> + X is positive + 0}> +
Both X and Y are positive
+
+ +
X is positive but Y is not
+
+
+ + X is not positive + 0}> +
X is not positive but Y is
+
+ +
Neither X nor Y are positive
+
+
+
+ ); + } + + render(App, container); + expect(container.innerHTML).toBe('
X is not positive
Neither X nor Y are positive
'); + set({ x: 1, y: 0 }); + expect(container.innerHTML).toBe('
X is positive
X is positive but Y is not
'); + set({ x: 1, y: 1 }); + expect(container.innerHTML).toBe('
X is positive
Both X and Y are positive
'); + set({ x: 0, y: 1 }); + expect(container.innerHTML).toBe('
X is not positive
X is not positive but Y is
'); + }); +}); diff --git a/packages/inula-next/test/context.test.tsx b/packages/inula-next/test/context.test.tsx index 5b24c8ad..4541bbb8 100644 --- a/packages/inula-next/test/context.test.tsx +++ b/packages/inula-next/test/context.test.tsx @@ -219,4 +219,130 @@ describe('context', () => { container.querySelector('button').click(); expect(container.querySelector('div').textContent).toBe('Count: 1'); }); + it('Should correctly create and provide context', ({ container }) => { + const ThemeContext = createContext('light'); + + function App() { + return ( + + + + ); + } + + function Child() { + const { theme } = useContext(ThemeContext); + return
Current theme: {theme}
; + } + + render(App, container); + expect(container.innerHTML).toBe('
Current theme: dark
'); + }); + + it('Should correctly consume context in child components', ({ container }) => { + const UserContext = createContext({ name: '', age: 0 }); + + function App() { + return ( + + + + ); + } + + function Parent() { + return ( +
+ + +
+ ); + } + + function Child1() { + const { name } = useContext(UserContext); + return
Name: {name}
; + } + + function Child2() { + const { age } = useContext(UserContext); + return
Age: {age}
; + } + + render(App, container); + expect(container.innerHTML).toBe('
Name: Alice
Age: 30
'); + }); + + it('Should correctly update context and re-render consumers', ({ container }) => { + const CountContext = createContext(0); + + function App() { + let count = 0; + const increment = () => { + count += 1; + }; + + return ( + + + + + ); + } + + function Counter() { + const { count } = useContext(CountContext); + return
Count: {count}
; + } + + render(App, container); + expect(container.querySelector('div').textContent).toBe('Count: 0'); + + container.querySelector('button').click(); + expect(container.querySelector('div').textContent).toBe('Count: 1'); + }); + + it('Should handle nested contexts correctly', ({ container }) => { + const ThemeContext = createContext('light'); + const LanguageContext = createContext('en'); + + function App() { + return ( + + + + + + ); + } + + function Child() { + const { theme } = useContext(ThemeContext); + const { language } = useContext(LanguageContext); + return ( +
+ Theme: {theme}, Language: {language} +
+ ); + } + + render(App, container); + expect(container.innerHTML).toBe('
Theme: dark, Language: fr
'); + }); + + it('Should use default value when no provider is present', ({ container }) => { + const DefaultContext = createContext({ message: 'Default message' }); + + function App() { + return ; + } + + function Child() { + const { message } = useContext(DefaultContext); + return
{message}
; + } + + render(App, container); + expect(container.innerHTML).toBe('
Default message
'); + }); }); diff --git a/packages/inula-next/test/customHook.test.tsx b/packages/inula-next/test/customHook.test.tsx index 81cc46cf..b8a2e970 100644 --- a/packages/inula-next/test/customHook.test.tsx +++ b/packages/inula-next/test/customHook.test.tsx @@ -366,3 +366,359 @@ describe('Custom Hook Tests', () => { }); }); }); + +describe('Hook and Watch Combined Tests', () => { + it('should update watched value when hook state changes', ({ container }) => { + let setCount; + function useCounter(initial = 0) { + let count = initial; + setCount = n => { + count = n; + }; + return { count }; + } + + function TestComponent() { + const { count } = useCounter(0); + let watchedCount = 0; + + watch(() => { + watchedCount = count * 2; + }); + + return
{watchedCount}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
0
'); + setCount(5); + expect(container.innerHTML).toBe('
10
'); + }); + + it('should handle multiple watches in a custom hook', ({ container }) => { + let setX, setY; + function usePosition() { + let x = 0, + y = 0; + setX = newX => { + x = newX; + }; + setY = newY => { + y = newY; + }; + + let position = ''; + watch(() => { + position = `(${x},${y})`; + }); + + let quadrant = 0; + watch(() => { + quadrant = x >= 0 && y >= 0 ? 1 : x < 0 && y >= 0 ? 2 : x < 0 && y < 0 ? 3 : 4; + }); + + return { position, quadrant }; + } + + function TestComponent() { + const { position, quadrant } = usePosition(); + return ( +
+ {position} Q{quadrant} +
+ ); + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
(0,0) Q1
'); + setX(-5); + setY(10); + expect(container.innerHTML).toBe('
(-5,10) Q2
'); + }); + + it('should correctly handle watch dependencies in hooks', ({ container }) => { + let setItems; + function useFilteredList(initialItems = []) { + let items = initialItems; + setItems = newItems => { + items = newItems; + }; + + let evenItems = []; + let oddItems = []; + + watch(() => { + evenItems = items.filter(item => item % 2 === 0); + }); + + watch(() => { + oddItems = items.filter(item => item % 2 !== 0); + }); + + return { evenItems, oddItems }; + } + + function TestComponent() { + const { evenItems, oddItems } = useFilteredList([1, 2, 3, 4, 5]); + return ( +
+ Even: {evenItems.join(',')} Odd: {oddItems.join(',')} +
+ ); + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
Even: 2,4 Odd: 1,3,5
'); + setItems([2, 4, 6, 8, 10]); + expect(container.innerHTML).toBe('
Even: 2,4,6,8,10 Odd:
'); + }); +}); + +describe('Advanced Hook Tests', () => { + // Hook return tests + describe('Hook Return Tests', () => { + it('should handle expression return', ({ container }) => { + function useExpression(a: number, b: number) { + return a + b * 2; + } + + function TestComponent() { + const result = useExpression(3, 4); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
11
'); + }); + + it('should handle object spread return', ({ container }) => { + function useObjectSpread(obj: object) { + return { ...obj, newProp: 'added' }; + } + + function TestComponent() { + const result = useObjectSpread({ existingProp: 'original' }); + return
{JSON.stringify(result)}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
{"existingProp":"original","newProp":"added"}
'); + }); + + it('should handle function call return', ({ container }) => { + function useFunction() { + const innerFunction = () => 42; + return innerFunction(); + } + + function TestComponent() { + const result = useFunction(); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
42
'); + }); + + it('should handle conditional expression return', ({ container }) => { + function useConditional(condition: boolean) { + return condition ? 'True' : 'False'; + } + + function TestComponent() { + const result = useConditional(true); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
True
'); + }); + + it('should handle array computation return', ({ container }) => { + function useArrayComputation(arr: number[]) { + return arr.reduce((sum, num) => sum + num, 0); + } + + function TestComponent() { + const result = useArrayComputation([1, 2, 3, 4, 5]); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
15
'); + }); + + it('should handle ternary expression return', ({ container }) => { + function useTernary(value: number) { + return value > 5 ? 'High' : value < 0 ? 'Low' : 'Medium'; + } + + function TestComponent() { + const result = useTernary(7); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
High
'); + }); + + it('should handle member expression return', ({ container }) => { + function useMemberExpression(obj: { prop: string }) { + return obj.prop; + } + + function TestComponent() { + const result = useMemberExpression({ prop: 'test' }); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
test
'); + }); + }); + + // Hook input tests + describe('Hook Input Tests', () => { + it('should handle expression input', ({ container }) => { + function useExpression(value: number) { + return value * 2; + } + + function TestComponent() { + const result = useExpression(3 + 4); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
14
'); + }); + + it('should handle object spread input', ({ container }) => { + function useObjectSpread(obj: { a: number; b: number }) { + return obj.a + obj.b; + } + + function TestComponent() { + const baseObj = { a: 1, c: 3 }; + const result = useObjectSpread({ ...baseObj, b: 2 }); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
3
'); + }); + + it('should handle function call input', ({ container }) => { + function useFunction(value: number) { + return value * 2; + } + + function getValue() { + return 21; + } + + function TestComponent() { + const result = useFunction(getValue()); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
42
'); + }); + + it('should handle conditional expression input', ({ container }) => { + function useConditional(value: string) { + return `Received: ${value}`; + } + + function TestComponent() { + const condition = true; + const result = useConditional(condition ? 'Yes' : 'No'); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
Received: Yes
'); + }); + + it('should handle array computation input', ({ container }) => { + function useArraySum(sum: number) { + return `Sum: ${sum}`; + } + + function TestComponent() { + const numbers = [1, 2, 3, 4, 5]; + const result = useArraySum(numbers.reduce((sum, num) => sum + num, 0)); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
Sum: 15
'); + }); + + it('should handle ternary expression input', ({ container }) => { + function useStatus(status: string) { + return `Current status: ${status}`; + } + + function TestComponent() { + const value = 7; + const result = useStatus(value > 5 ? 'High' : value < 0 ? 'Low' : 'Medium'); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
Current status: High
'); + }); + + it('should handle member expression input', ({ container }) => { + function useName(name: string) { + return `Hello, ${name}!`; + } + + function TestComponent() { + const user = { name: 'Alice' }; + const result = useName(user.name); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
Hello, Alice!
'); + }); + }); + + // Additional tests + describe('Additional Hook Tests', () => { + it('should handle input based on other variables', ({ container }) => { + function useComputed(value: number) { + return value * 2; + } + + function TestComponent() { + let baseValue = 5; + let multiplier = 3; + const result = useComputed(baseValue * multiplier); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
30
'); + }); + + it('should handle function input and output', ({ container }) => { + function useFunction(fn: (x: number) => number) { + return (y: number) => fn(y) * 2; + } + + function TestComponent() { + const inputFn = (x: number) => x + 1; + const resultFn = useFunction(inputFn); + const result = resultFn(5); + return
{result}
; + } + + render(TestComponent, container); + expect(container.innerHTML).toBe('
12
'); + }); + }); +}); diff --git a/packages/inula-next/test/event.test.tsx b/packages/inula-next/test/event.test.tsx new file mode 100644 index 00000000..1e7dddf5 --- /dev/null +++ b/packages/inula-next/test/event.test.tsx @@ -0,0 +1,543 @@ +/* + * Copyright (c) 2024 Huawei Technologies Co.,Ltd. + * + * openInula is licensed under Mulan PSL v2. + * You can use this software according to the terms and conditions of the Mulan PSL v2. + * You may obtain a copy of Mulan PSL v2 at: + * + * http://license.coscl.org.cn/MulanPSL2 + * + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PSL v2 for more details. + */ +import { describe, expect, vi } from 'vitest'; +import { domTest as it } from './utils'; +import { render } from '../src'; + +vi.mock('../src/scheduler', async () => { + return { + schedule: (task: () => void) => { + task(); + }, + }; +}); + +describe('Event Handling', () => { + it('Should correctly handle onClick events', ({ container }) => { + let clicked = false; + function App() { + const handleClick = () => { + clicked = true; + }; + return ; + } + + render(App, container); + const button = container.querySelector('button'); + button.click(); + expect(clicked).toBe(true); + }); + + it.fails('Should correctly handle onMouseOver events', ({ container }) => { + let hovered = false; + function App() { + const handleMouseOver = () => { + hovered = true; + }; + return
Hover me
; + } + + render(App, container); + const div = container.querySelector('div'); + div.dispatchEvent(new MouseEvent('mouseover')); + expect(hovered).toBe(true); + }); + + it('Should correctly handle onKeyPress events', ({ container }) => { + let keypressed = ''; + function App() { + const handleKeyPress = event => { + keypressed = event.key; + }; + return ; + } + + render(App, container); + const input = container.querySelector('input'); + const event = new KeyboardEvent('keypress', { key: 'A' }); + input.dispatchEvent(event); + expect(keypressed).toBe('A'); + }); + + it('Should correctly handle onSubmit events', ({ container }) => { + let submitted = false; + function App() { + const handleSubmit = event => { + event.preventDefault(); + submitted = true; + }; + return ( +
+ +
+ ); + } + + render(App, container); + const form = container.querySelector('form'); + form.dispatchEvent(new Event('submit')); + expect(submitted).toBe(true); + }); + + it.fails('Should correctly handle custom events', ({ container }) => { + let customEventData = null; + function App() { + const handleCustomEvent = event => { + customEventData = event.detail; + }; + return
Custom event target
; + } + + render(App, container); + const div = container.querySelector('div'); + const customEvent = new CustomEvent('customEvent', { detail: { message: 'Hello, Custom Event!' } }); + div.dispatchEvent(customEvent); + expect(customEventData).toEqual({ message: 'Hello, Custom Event!' }); + }); + + it('Should correctly handle events when the handler is a variable', ({ container }) => { + let count = 0; + function App() { + const incrementCount = () => { + count++; + }; + return ; + } + + render(App, container); + const button = container.querySelector('button'); + button.click(); + expect(count).toBe(1); + }); + + it('Should correctly handle events when the handler is an expression returning a function', ({ container }) => { + let lastClicked = ''; + function App() { + const createHandler = buttonName => () => { + lastClicked = buttonName; + }; + return ( +
+ + +
+ ); + } + + render(App, container); + const buttons = container.querySelectorAll('button'); + buttons[0].click(); + expect(lastClicked).toBe('Button A'); + buttons[1].click(); + expect(lastClicked).toBe('Button B'); + }); +}); + +describe('event emission', () => { + it('should handle emit to parent', ({ container }) => { + function AnswerButton({ onYes, onNo }) { + return ( + <> + + + {/**/} + + ); + } + function App() { + let isHappy = false; + + function onAnswerNo() { + isHappy = false; + } + + function onAnswerYes() { + isHappy = true; + } + + return ( + <> +

Are you happy?

+ +

{isHappy ? 'yes' : 'no'}

+ + ); + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
+

+ Are you happy? +

+ +

+ no +

+
+ `); + container.querySelector('button')?.click(); + expect(container).toMatchInlineSnapshot(` +
+

+ Are you happy? +

+ +

+ yes +

+
+ `); + }); + it('should correctly emit events to parent component', ({ container }) => { + function Child({ onEvent }) { + return ; + } + + function App() { + let eventReceived = '1'; + + function handleEvent(event) { + eventReceived = event; + } + + return ( + <> + +

{eventReceived}

+ + ); + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
+ +

+ 1 +

+
+ `); + + container.querySelector('button')?.click(); + expect(container).toMatchInlineSnapshot(` +
+ +

+ clicked +

+
+ `); + }); + + it('should correctly update parent state based on emitted events', ({ container }) => { + function Counter({ onIncrement, onDecrement }) { + return ( +
+ + +
+ ); + } + + function App() { + let count = 0; + + function increment() { + count += 1; + } + + function decrement() { + count -= 1; + } + + return ( + <> + +

Count:{count}

+ + ); + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
+
+ + +
+

+ Count: + 0 +

+
+ `); + + container.querySelectorAll('button')[0]?.click(); + expect(container).toMatchInlineSnapshot(` +
+
+ + +
+

+ Count: + 1 +

+
+ `); + + container.querySelectorAll('button')[1]?.click(); + expect(container).toMatchInlineSnapshot(` +
+
+ + +
+

+ Count: + 0 +

+
+ `); + }); + + it('should correctly handle multiple event emissions', ({ container }) => { + function MultiButton({ onClickA, onClickB, onClickC }) { + return ( +
+ + + +
+ ); + } + + function App() { + let lastClicked = 'A'; + + function handleClick(button) { + lastClicked = button; + } + + return ( + <> + handleClick('A')} + onClickB={() => handleClick('B')} + onClickC={() => handleClick('C')} + /> +

Last clicked:{lastClicked}

+ + ); + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
+
+ + + +
+

+ Last clicked: + A +

+
+ `); + + container.querySelectorAll('button')[1]?.click(); + expect(container).toMatchInlineSnapshot(` +
+
+ + + +
+

+ Last clicked: + B +

+
+ `); + }); + + it('should handle both arrow functions and function variables', ({ container }) => { + function Child({ onEventA, onEventB }) { + return ( +
+ + +
+ ); + } + + function App() { + let eventResult = '1'; + + const handleEventA = () => { + eventResult = 'Arrow function called'; + }; + + function handleEventB() { + eventResult = 'Function variable called'; + } + + return ( + <> + +

{eventResult}

+ + ); + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
+
+ + +
+

+ 1 +

+
+ `); + + container.querySelectorAll('button')[0]?.click(); + expect(container).toMatchInlineSnapshot(` +
+
+ + +
+

+ Arrow function called +

+
+ `); + + container.querySelectorAll('button')[1]?.click(); + expect(container).toMatchInlineSnapshot(` +
+
+ + +
+

+ Function variable called +

+
+ `); + }); + + it('should handle multi-layer event functions', ({ container }) => { + function GrandChild({ onEvent }) { + return ; + } + + function Child({ onParentEvent }) { + function handleChildEvent(message) { + onParentEvent(`Child received: ${message}`); + } + + return ; + } + + function App() { + let message = '1'; + + function handleAppEvent(receivedMessage) { + message = `App received: ${receivedMessage}`; + } + + return ( + <> + +

{message}

+ + ); + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
+ +

+ 1 +

+
+ `); + + container.querySelector('button')?.click(); + expect(container).toMatchInlineSnapshot(` +
+ +

+ App received: Child received: GrandChild clicked +

+
+ `); + }); +}); diff --git a/packages/inula-next/test/for.test.tsx b/packages/inula-next/test/for.test.tsx index 577c4ad6..be988581 100644 --- a/packages/inula-next/test/for.test.tsx +++ b/packages/inula-next/test/for.test.tsx @@ -132,7 +132,7 @@ describe('for', () => { render(MyComp, container); expect(container.innerHTML).toBe('
1
2
3
4
'); }); - // this test has error, need to be comment + // it.fails('should transform last map to for" ', ({ container }) => { // function MyComp() { // let arr = [1, 2, 3]; @@ -150,4 +150,75 @@ describe('for', () => { // render(MyComp, container); // expect(container.innerHTML).toBe('
1
2
3
4
'); // }); + it('Should correctly render a single-level loop of elements', ({ container }) => { + function App() { + const fruits = ['Apple', 'Banana', 'Cherry']; + return {fruit =>
  • {fruit}
  • }
    ; + } + + render(App, container); + expect(container.innerHTML).toMatchInlineSnapshot(`"
  • Apple
  • Banana
  • Cherry
  • "`); + }); + + it('Should correctly render nested loops of elements', ({ container }) => { + function App() { + const matrix = [ + [1, 2], + [3, 4], + [5, 6], + ]; + return ( + + {row => ( +
    + {cell => {cell}} +
    + )} +
    + ); + } + + render(App, container); + expect(container.innerHTML).toMatchInlineSnapshot( + `"
    12
    34
    56
    "` + ); + }); + + it('Should correctly render loops with complex data structures', ({ container }) => { + function App() { + const users = [ + { id: 1, name: 'Alice', hobbies: ['reading', 'gaming'] }, + { id: 2, name: 'Bob', hobbies: ['cycling', 'photography'] }, + ]; + return ( + + {user => ( +
    +

    {user.name}

    +
      + {hobby =>
    • {hobby}
    • }
      +
    +
    + )} +
    + ); + } + + render(App, container); + expect(container.innerHTML).toMatchInlineSnapshot( + `"

    Alice

    • reading
    • gaming

    Bob

    • cycling
    • photography
    "` + ); + }); + + it('Should correctly render when for tag input is an array map', ({ container }) => { + function App() { + const numbers = [1, 2, 3, 4, 5]; + return n * 2)}>{doubledNumber => {doubledNumber}}; + } + + render(App, container); + expect(container.innerHTML).toMatchInlineSnapshot( + `"246810"` + ); + }); }); diff --git a/packages/inula-next/test/jsxSlice.test.tsx b/packages/inula-next/test/jsxSlice.test.tsx index c5a6caee..bd0479ae 100644 --- a/packages/inula-next/test/jsxSlice.test.tsx +++ b/packages/inula-next/test/jsxSlice.test.tsx @@ -407,3 +407,277 @@ describe('JSX Element Usage in Various Contexts', () => { }); }); }); + +describe('JSX Element Attributes', () => { + it('should correctly initialize attributes', ({ container }) => { + function App() { + return ( +
    + Content +
    + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Content
    '); + }); + + it('should correctly update attributes', ({ container }) => { + function App() { + let className = 'initial'; + + function updateClass() { + className = 'updated'; + } + + return ( + <> +
    Content
    + + + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Content
    '); + + container.querySelector('button')?.click(); + expect(container.innerHTML).toBe('
    Content
    '); + }); + + it('should correctly render attributes dependent on variables', ({ container }) => { + function App() { + let className = 'initial'; + let b = className; + function updateClass() { + className = 'updated'; + } + + return ( + <> +
    Content
    + + + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Content
    '); + + container.querySelector('button')?.click(); + expect(container.innerHTML).toBe('
    Content
    '); + }); + + it('should correctly render attributes with expressions', ({ container }) => { + function App() { + const count = 5; + return
    Content
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Content
    '); + }); + + it('should correctly render boolean attributes', ({ container }) => { + function App() { + const disabled = true; + return ; + } + render(App, container); + expect(container.innerHTML).toBe(''); + }); + + it.fails('should correctly render attributes without values', ({ container }) => { + function App() { + const checked = true; + return ; + } + render(App, container); + expect(container.innerHTML).toBe(''); + }); + + it.fails('should correctly spread multiple attributes', ({ container }) => { + function App() { + const props = { + id: 'test-id', + className: 'test-class', + 'data-test': 'test-data', + }; + return
    Content
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Content
    '); + }); + + it.fails('should correctly handle attribute spreading and individual props', ({ container }) => { + function App() { + const props = { + id: 'base-id', + className: 'base-class', + }; + return ( +
    + Content +
    + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Content
    '); + }); +}); + +describe('JSX Element Inline Styles', () => { + it('should correctly apply inline styles to an element', ({ container }) => { + function App() { + return
    Styled content
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Styled content
    '); + }); + + it('should correctly apply multiple inline styles to an element', ({ container }) => { + function App() { + return
    Multiple styles
    ; + } + render(App, container); + expect(container.innerHTML).toBe( + '
    Multiple styles
    ' + ); + }); + + it('should correctly apply styles from a variable', ({ container }) => { + function App() { + const styleObj = { color: 'green', padding: '5px' }; + return
    Variable style
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Variable style
    '); + }); + + it('should correctly update styles', ({ container }) => { + function App() { + let style = { color: 'purple' }; + + function updateStyle() { + style = { color: 'orange', fontSize: '24px' }; + } + + return ( + <> +
    Updatable style
    + + + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Updatable style
    '); + + container.querySelector('button')?.click(); + expect(container.innerHTML).toBe( + '
    Updatable style
    ' + ); + }); + + it('should correctly apply styles from an expression', ({ container }) => { + function App() { + const size = 18; + return
    Expression style
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Expression style
    '); + }); + + it('should correctly merge style objects', ({ container }) => { + function App() { + const baseStyle = { color: 'red', fontSize: '16px' }; + const additionalStyle = { fontSize: '20px', fontWeight: 'bold' }; + return
    Merged styles
    ; + } + render(App, container); + expect(container.innerHTML).toBe( + '
    Merged styles
    ' + ); + }); + + it('should correctly apply styles from a function call', ({ container }) => { + function getStyles(color: string) { + return { color, border: `1px solid ${color}` }; + } + function App() { + return
    Function style
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Function style
    '); + }); + + it('should correctly apply styles based on a condition', ({ container }) => { + function App() { + const isActive = true; + const style = isActive + ? { backgroundColor: 'green', color: 'white' } + : { backgroundColor: 'gray', color: 'black' }; + return
    Conditional style
    ; + } + render(App, container); + expect(container.innerHTML).toBe('
    Conditional style
    '); + }); + + it('should correctly apply styles based on an array of conditions', ({ container }) => { + function App() { + const conditions = [true, false, true]; + const style = { + color: conditions[0] ? 'red' : 'blue', + fontWeight: conditions[1] ? 'bold' : 'normal', + fontSize: conditions[2] ? '20px' : '16px', + }; + return
    Array condition style
    ; + } + render(App, container); + expect(container.innerHTML).toBe( + '
    Array condition style
    ' + ); + }); + + it('should correctly apply styles using ternary and binary expressions', ({ container }) => { + function App() { + const isPrimary = true; + const isLarge = true; + return ( +
    + Ternary and binary style +
    + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Ternary and binary style
    '); + }); + + it('should correctly apply styles using member expressions', ({ container }) => { + const theme = { + colors: { + primary: 'blue', + secondary: 'green', + }, + sizes: { + small: '12px', + medium: '16px', + large: '20px', + }, + }; + function App() { + return ( +
    + Member expression style +
    + ); + } + render(App, container); + expect(container.innerHTML).toBe('
    Member expression style
    '); + }); +}); diff --git a/packages/inula-next/test/props.test.tsx b/packages/inula-next/test/props.test.tsx index dc59bb60..87923919 100644 --- a/packages/inula-next/test/props.test.tsx +++ b/packages/inula-next/test/props.test.tsx @@ -136,3 +136,193 @@ describe('props', () => { }); }); }); + +describe('extended prop tests', () => { + it('should correctly pass and render string props', ({ container }) => { + function Child({ text }) { + return

    {text}

    ; + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +

    + Hello, world! +

    +
    + `); + }); + + it('should correctly pass and render number props', ({ container }) => { + function Child({ number }) { + return {number}; + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    + + 42 + +
    + `); + }); + + it('should correctly pass and render boolean props', ({ container }) => { + function Child({ isActive }) { + return
    {isActive ? 'Active' : 'Inactive'}
    ; + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +
    + Active +
    +
    + `); + }); + + it.fails('should correctly pass and render array props', ({ container }) => { + function Child({ items }) { + return ( +
      + {items.map((item, index) => ( +
    • {item}
    • + ))} +
    + ); + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +
      +
    • Apple
    • +
    • Banana
    • +
    • Cherry
    • +
    +
    + `); + }); + + it.fails('should correctly pass and render object props', ({ container }) => { + function Child({ person }) { + return ( +
    + {person.name}, {person.age} +
    + ); + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +
    + Alice, 30 +
    +
    + `); + }); + + it('should correctly handle default prop values', ({ container }) => { + function Child({ message = 'Default message' }) { + return

    {message}

    ; + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +

    + Default message +

    +
    + `); + }); + + it.fails('should correctly spread props', ({ container }) => { + function Child(props) { + return ( +
    + {props.a} {props.b} {props.c} +
    + ); + } + + function App() { + const extraProps = { b: 'World', c: '!' }; + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +
    + Hello World ! +
    +
    + `); + }); + + it.fails('should handle props without values', ({ container }) => { + function Child({ isDisabled }) { + return ; + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    + +
    + `); + }); + + it('should handle props with expressions', ({ container }) => { + function Child({ result }) { + return
    {result}
    ; + } + + function App() { + return ; + } + + render(App, container); + expect(container).toMatchInlineSnapshot(` +
    +
    + 7 +
    +
    + `); + }); +}); diff --git a/packages/inula-next/test/rendering.test.tsx b/packages/inula-next/test/rendering.test.tsx index 68149c34..2dc50d42 100644 --- a/packages/inula-next/test/rendering.test.tsx +++ b/packages/inula-next/test/rendering.test.tsx @@ -116,6 +116,26 @@ describe('rendering', () => { expect(h1.style.color).toBe('red'); }); + it.fails('should apply styles number correctly', ({ container }) => { + function App() { + return

    hello world!!!

    ; + } + + render(App, container); + const h1 = container.querySelector('h1'); + expect(h1.style.fontSize).toBe('12px'); + }); + + it('should apply styles empty correctly', ({ container }) => { + function App() { + return

    hello world!!!

    ; + } + + render(App, container); + const h1 = container.querySelector('h1'); + expect(h1.style.fontSize).toBe(''); + }); + it('should apply multiple styles correctly', ({ container }) => { function App() { return

    hello world!!!

    ; -- Gitee