mirror of
https://github.com/smartxworks/sunmao-ui.git
synced 2025-03-25 21:20:38 +08:00
test(runtime): add merge state test
This commit is contained in:
parent
da066b4519
commit
3381d0b412
@ -12,7 +12,34 @@
|
||||
"type": "test/v1/tester",
|
||||
"properties": {
|
||||
"testId": "tester",
|
||||
"text": "2333"
|
||||
"text": "{{input.value}}{{input2.value}}{{input3.value}}"
|
||||
},
|
||||
"traits": []
|
||||
},
|
||||
{
|
||||
"id": "input",
|
||||
"type": "test/v1/input",
|
||||
"properties": {
|
||||
"testId": "",
|
||||
"defaultValue": "foo"
|
||||
},
|
||||
"traits": []
|
||||
},
|
||||
{
|
||||
"id": "input2",
|
||||
"type": "test/v1/input",
|
||||
"properties": {
|
||||
"testId": "",
|
||||
"defaultValue": "bar"
|
||||
},
|
||||
"traits": []
|
||||
},
|
||||
{
|
||||
"id": "input3",
|
||||
"type": "test/v1/input",
|
||||
"properties": {
|
||||
"testId": "",
|
||||
"defaultValue": "baz"
|
||||
},
|
||||
"traits": []
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
import { StrictMode } from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { RegistryInterface } from '@sunmao-ui/runtime';
|
||||
import { sunmaoChakraUILib } from '@sunmao-ui/chakra-ui-lib';
|
||||
@ -43,10 +42,5 @@ export default function renderApp(options: Options = {}) {
|
||||
traits.forEach(t => registry.registerTrait(t));
|
||||
modules.forEach(m => registry.registerModule(m));
|
||||
|
||||
ReactDOM.render(
|
||||
<StrictMode>
|
||||
<Editor />
|
||||
</StrictMode>,
|
||||
container
|
||||
);
|
||||
ReactDOM.render(<Editor />, container);
|
||||
}
|
||||
|
@ -3,14 +3,26 @@ import { render, fireEvent, screen, waitFor, act } from '@testing-library/react'
|
||||
import produce from 'immer';
|
||||
import { times } from 'lodash';
|
||||
import { initSunmaoUI } from '../../src';
|
||||
import { destroyTimesMap } from '../../src/components/test/Tester';
|
||||
import { renderTimesMap } from '../../src/components/test/Tester';
|
||||
import {
|
||||
SingleComponentSchema,
|
||||
ComponentSchemaChangeSchema,
|
||||
HiddenTraitSchema,
|
||||
MergeStateSchema,
|
||||
} from './mockSchema.spec';
|
||||
|
||||
const SingleComponentRenderTimes = '2';
|
||||
|
||||
function clear() {
|
||||
for (const key in renderTimesMap) {
|
||||
delete renderTimesMap[key];
|
||||
}
|
||||
for (const key in destroyTimesMap) {
|
||||
delete destroyTimesMap[key];
|
||||
}
|
||||
}
|
||||
|
||||
describe('single component condition', () => {
|
||||
it('only render one time', () => {
|
||||
const { App } = initSunmaoUI();
|
||||
@ -20,6 +32,7 @@ describe('single component condition', () => {
|
||||
expect(screen.getByTestId('single')?.textContent).toEqual(SingleComponentRenderTimes);
|
||||
expect(screen.getByTestId('single-destroy')?.textContent).toEqual('0');
|
||||
unmount();
|
||||
clear();
|
||||
});
|
||||
});
|
||||
|
||||
@ -41,6 +54,7 @@ describe('after the schema changes', () => {
|
||||
expect(screen.getByTestId('staticComponent-destroy')?.textContent).toEqual('0');
|
||||
expect(screen.getByTestId('dynamicComponent-destroy')?.textContent).toEqual('0');
|
||||
unmount();
|
||||
clear();
|
||||
});
|
||||
});
|
||||
|
||||
@ -54,9 +68,38 @@ describe('hidden trait condition', () => {
|
||||
expect(stateManager.store['input1']).toBeUndefined();
|
||||
|
||||
unmount();
|
||||
clear();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when component merge state synchronously', () => {
|
||||
it('it will not cause extra render', () => {
|
||||
const { App, stateManager } = initSunmaoUI();
|
||||
const { unmount } = render(<App options={MergeStateSchema} />);
|
||||
expect(screen.getByTestId('tester')?.textContent).toEqual(SingleComponentRenderTimes);
|
||||
expect(screen.getByTestId('tester-text')?.textContent).toEqual('foo-bar-baz');
|
||||
expect(stateManager.store['input'].value).toBe('foo');
|
||||
|
||||
unmount();
|
||||
clear();
|
||||
});
|
||||
|
||||
it(`the components' order will not cause extra render`, () => {
|
||||
const newMergeStateSchema = produce(MergeStateSchema, draft => {
|
||||
const temp = draft.spec.components[0];
|
||||
draft.spec.components[0] = draft.spec.components[1];
|
||||
draft.spec.components[1] = temp;
|
||||
});
|
||||
const { App, stateManager } = initSunmaoUI();
|
||||
const { unmount } = render(<App options={newMergeStateSchema} />);
|
||||
expect(screen.getByTestId('tester')?.textContent).toEqual(SingleComponentRenderTimes);
|
||||
expect(screen.getByTestId('tester-text')?.textContent).toEqual('foo-bar-baz');
|
||||
expect(stateManager.store['input'].value).toBe('foo');
|
||||
|
||||
unmount();
|
||||
clear();
|
||||
});
|
||||
});
|
||||
// expect(screen.getByTestId('tester1-text')?.textContent).toEqual('0');
|
||||
|
||||
// expect(screen.getByTestId('tester1')?.textContent).toEqual('3');
|
||||
|
@ -52,73 +52,6 @@ export const ComponentSchemaChangeSchema: Application = {
|
||||
},
|
||||
};
|
||||
|
||||
export const MockSchema: Application = {
|
||||
version: 'sunmao/v1',
|
||||
kind: 'Application',
|
||||
metadata: {
|
||||
name: 'some App',
|
||||
},
|
||||
spec: {
|
||||
components: [
|
||||
{
|
||||
id: 'tester1',
|
||||
type: 'test/v1/tester',
|
||||
properties: {
|
||||
testId: 'tester1',
|
||||
text: '{{state0.value}}',
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: 'button1',
|
||||
type: 'test/v1/button',
|
||||
properties: {
|
||||
testId: 'button1',
|
||||
},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/event',
|
||||
properties: {
|
||||
handlers: [
|
||||
{
|
||||
type: 'click',
|
||||
componentId: 'state0',
|
||||
method: {
|
||||
name: 'setValue',
|
||||
parameters: {
|
||||
key: 'value',
|
||||
value: '{{state0.value + 1}}',
|
||||
},
|
||||
},
|
||||
disabled: false,
|
||||
wait: {
|
||||
type: 'delay',
|
||||
time: 0,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
id: 'state0',
|
||||
type: 'core/v1/dummy',
|
||||
properties: {},
|
||||
traits: [
|
||||
{
|
||||
type: 'core/v1/state',
|
||||
properties: {
|
||||
key: 'value',
|
||||
initialValue: '0',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const HiddenTraitSchema: Application = {
|
||||
version: 'sunmao/v1',
|
||||
kind: 'Application',
|
||||
@ -155,3 +88,51 @@ export const HiddenTraitSchema: Application = {
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export const MergeStateSchema: Application = {
|
||||
version: 'sunmao/v1',
|
||||
kind: 'Application',
|
||||
metadata: {
|
||||
name: 'some App',
|
||||
},
|
||||
spec: {
|
||||
components: [
|
||||
{
|
||||
id: 'tester',
|
||||
type: 'test/v1/tester',
|
||||
properties: {
|
||||
testId: 'tester',
|
||||
text: '{{input.value}}-{{input2.value}}-{{input3.value}}',
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: 'input',
|
||||
type: 'test/v1/input',
|
||||
properties: {
|
||||
testId: '',
|
||||
defaultValue: 'foo',
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: 'input2',
|
||||
type: 'test/v1/input',
|
||||
properties: {
|
||||
testId: '',
|
||||
defaultValue: 'bar',
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
{
|
||||
id: 'input3',
|
||||
type: 'test/v1/input',
|
||||
properties: {
|
||||
testId: '',
|
||||
defaultValue: 'baz',
|
||||
},
|
||||
traits: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
};
|
||||
|
@ -9,7 +9,6 @@
|
||||
<select></select>
|
||||
<div id="root"></div>
|
||||
<script type="module">
|
||||
import './wdyr';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { initSunmaoUI } from './src';
|
||||
@ -32,19 +31,14 @@
|
||||
ReactDOM.unmountComponentAtNode(rootEl);
|
||||
const { App, registry } = initSunmaoUI({ libs: [sunmaoChakraUILib] });
|
||||
const { app, modules = [] } = example.value;
|
||||
window.registry = registry;
|
||||
modules.forEach(m => {
|
||||
registry.registerModule(m);
|
||||
});
|
||||
ReactDOM.render(
|
||||
React.createElement(
|
||||
React.StrictMode,
|
||||
ChakraProvider,
|
||||
null,
|
||||
React.createElement(
|
||||
ChakraProvider,
|
||||
null,
|
||||
React.createElement(App, { options: app }, null)
|
||||
)
|
||||
React.createElement(App, { options: app }, null)
|
||||
),
|
||||
rootEl
|
||||
);
|
||||
|
@ -177,7 +177,7 @@ export const ImplWrapperMain = React.forwardRef<HTMLDivElement, ImplWrapperProps
|
||||
}
|
||||
);
|
||||
|
||||
ImplWrapperMain.whyDidYouRender = true;
|
||||
// ImplWrapperMain.whyDidYouRender = true;
|
||||
|
||||
// This hook will only run unmount function when unmount, not every time when unmount function changes.
|
||||
const useDidUnmount = (fn: Function) => {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { implementRuntimeComponent } from '../../utils/buildKit';
|
||||
import { Type } from '@sinclair/typebox';
|
||||
import { useState , useEffect } from 'react';
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
export default implementRuntimeComponent({
|
||||
version: 'test/v1',
|
||||
@ -33,7 +33,7 @@ export default implementRuntimeComponent({
|
||||
const [value, setValue] = useState(defaultValue || '');
|
||||
useEffect(() => {
|
||||
mergeState({ value });
|
||||
});
|
||||
}, [mergeState, value]);
|
||||
return (
|
||||
<input data-testid={testId} value={value} onChange={e => setValue(e.target.value)} />
|
||||
);
|
||||
|
@ -4,8 +4,8 @@ import { useEffect } from 'react';
|
||||
|
||||
(window as any).renderTimesMap = {};
|
||||
(window as any).destroyTimesMap = {};
|
||||
const renderTimesMap = (window as any).renderTimesMap;
|
||||
const destroyTimesMap = (window as any).destroyTimesMap;
|
||||
export const renderTimesMap = (window as any).renderTimesMap;
|
||||
export const destroyTimesMap = (window as any).destroyTimesMap;
|
||||
|
||||
export default implementRuntimeComponent({
|
||||
version: 'test/v1',
|
||||
@ -34,7 +34,6 @@ export default implementRuntimeComponent({
|
||||
},
|
||||
})(({ testId, text }) => {
|
||||
renderTimesMap[testId] = (renderTimesMap[testId] || 0) + 1;
|
||||
console.log('testId', renderTimesMap);
|
||||
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
|
39
packages/runtime/src/components/test/TimeoutTrait.tsx
Normal file
39
packages/runtime/src/components/test/TimeoutTrait.tsx
Normal file
@ -0,0 +1,39 @@
|
||||
import { createTrait } from '@sunmao-ui/core';
|
||||
import { Static, Type } from '@sinclair/typebox';
|
||||
import { TraitImplFactory } from '../../types';
|
||||
|
||||
const TimeoutTraitPropertiesSpec = Type.Object({
|
||||
value: Type.String(),
|
||||
});
|
||||
|
||||
const TimeoutTrait: TraitImplFactory<Static<typeof TimeoutTraitPropertiesSpec>> = () => {
|
||||
// This trait will merge it property value in its state after 50ms
|
||||
return ({ value, mergeState }) => {
|
||||
setTimeout(() => {
|
||||
console.log('timeout: ', value);
|
||||
mergeState({ result: value });
|
||||
}, 50);
|
||||
|
||||
return {
|
||||
props: null,
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export default {
|
||||
...createTrait({
|
||||
version: 'test/v1',
|
||||
metadata: {
|
||||
name: 'timeout',
|
||||
description: 'for test',
|
||||
},
|
||||
spec: {
|
||||
properties: TimeoutTraitPropertiesSpec,
|
||||
methods: [],
|
||||
state: Type.Object({
|
||||
result: Type.String(),
|
||||
}),
|
||||
},
|
||||
}),
|
||||
factory: TimeoutTrait,
|
||||
};
|
@ -15,6 +15,7 @@ import CoreIframe from '../components/core/Iframe';
|
||||
import TestButton from '../components/test/Button';
|
||||
import TestTester from '../components/test/Tester';
|
||||
import TestInput from '../components/test/Input';
|
||||
import TimeoutTrait from '../components/test/TimeoutTrait';
|
||||
|
||||
// traits
|
||||
import CoreArrayState from '../traits/core/ArrayState';
|
||||
@ -255,6 +256,7 @@ export function initRegistry(
|
||||
registry.registerComponent(TestTester);
|
||||
registry.registerComponent(TestButton);
|
||||
registry.registerComponent(TestInput);
|
||||
registry.registerTrait(TimeoutTrait);
|
||||
|
||||
registry.registerTrait(CoreState);
|
||||
registry.registerTrait(CoreArrayState);
|
||||
|
Loading…
x
Reference in New Issue
Block a user