2
0
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:
Bowen Tan 2022-06-09 14:55:09 +08:00
parent da066b4519
commit 3381d0b412
10 changed files with 168 additions and 89 deletions
examples/box
packages
editor/src
runtime

@ -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 () => {

@ -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);