UNPKG

@ray-core/runtime

Version:

Ray 是一个全新的基于 React 的小程序开发框架

606 lines (605 loc) 26.9 kB
var __extends = (this && this.__extends) || (function () { var extendStatics = function (d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; }; return extendStatics(d, b); }; return function (d, b) { if (typeof b !== "function" && b !== null) throw new TypeError("Class extends value " + String(b) + " is not a constructor or null"); extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); }; })(); var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (_) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __read = (this && this.__read) || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; import * as React from 'react'; import './helpers/setupGlobals'; import View from './helpers/View'; import Input from './helpers/Input'; import render from '../render'; import { reset as resetInstanceId } from '../instanceId'; import Container from '../Container'; import { useNativeEffect } from '../hooks'; function delay(ms) { if (typeof ms !== 'number') { throw new Error('Must specify ms'); } return new Promise(function (resolve) { setTimeout(function () { resolve(); }, ms); }); } var p = { setData: function (state, callback) { setTimeout(function () { if (typeof callback === 'function') { callback(); } }); }, }; describe('wechat remax render', function () { afterEach(function () { resetInstanceId(); }); it('render correctly', function () { var Page = function () { return React.createElement(View, { className: "foo" }, "hello"); }; var container = new Container(p); render(React.createElement(Page, null), container); expect(container.root).toMatchSnapshot(); }); it('insert new element', function () { var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { list: [1, 3], }; return _this; } Page.prototype.update = function () { this.setState({ list: [1, 2, 3], }); }; Page.prototype.render = function () { var list = this.state.list; return (React.createElement(View, null, list.map(function (i) { return (React.createElement(View, { key: i }, i)); }))); }; return Page; }(React.Component)); var container = new Container(p); var page = React.createRef(); render(React.createElement(Page, { ref: page }), container); expect(container.root).toMatchSnapshot(); page.current.update(); expect(container.root).toMatchSnapshot(); }); it("change elements' order", function () { var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { list: [1, 2, 3], }; return _this; } Page.prototype.updateA = function () { this.setState({ list: [2, 1, 3], }); }; Page.prototype.updateB = function () { this.setState({ list: [2, 3, 1], }); }; Page.prototype.render = function () { var list = this.state.list; return (React.createElement(View, null, list.map(function (i) { return (React.createElement(View, { key: i }, i)); }))); }; return Page; }(React.Component)); var container = new Container(p); var page = React.createRef(); render(React.createElement(Page, { ref: page }), container); expect(container.root).toMatchSnapshot(); page.current.updateA(); expect(container.root).toMatchSnapshot(); page.current.updateB(); expect(container.root).toMatchSnapshot(); }); it('umount component', function () { var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { show: true, }; return _this; } Page.prototype.hide = function () { this.setState({ show: false }); }; Page.prototype.render = function () { return React.createElement(View, null, this.state.show && React.createElement(View, null, "foo")); }; return Page; }(React.Component)); var container = new Container(p); var page = React.createRef(); render(React.createElement(Page, { ref: page }), container); expect(container.root).toMatchSnapshot(); page.current.hide(); expect(container.root).toMatchSnapshot(); }); it('renders style', function () { var Page = function () { return React.createElement(View, { style: { width: '100px', height: '100px' } }, "hello"); }; var container = new Container(p); render(React.createElement(Page, null), container); expect(container.root).toMatchSnapshot(); }); it('renders vendor prefix style', function () { var Page = function () { return React.createElement(View, { style: { WebkitLineClamp: 2, height: '100px' } }, "hello"); }; var container = new Container(p); render(React.createElement(Page, null), container); expect(container.root).toMatchSnapshot(); }); it('renders empty style', function () { var Page = function () { return React.createElement(View, { style: undefined }, "hello"); }; var container = new Container(p); render(React.createElement(Page, null), container); expect(container.root).toMatchSnapshot(); }); it('renders conditional fragment correctly', function () { var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { show: false, }; return _this; } Page.prototype.show = function () { this.setState({ show: true }); }; Page.prototype.render = function () { if (this.state.show) { return React.createElement(View, null, "foo"); } return (React.createElement(React.Fragment, null, React.createElement(View, null, "one"), React.createElement(View, null, "two"))); }; return Page; }(React.Component)); var container = new Container(p); var page = React.createRef(); render(React.createElement(Page, { ref: page }), container); expect(container.root).toMatchSnapshot(); page.current.show(); expect(container.root).toMatchSnapshot(); }); it('render native component correctly', function () { var NativeComponent = function (_a) { var fooBar = _a.fooBar, onClick = _a.onClick, className = _a.className; return React.createElement('native-component', { fooBar: fooBar, className: className, onClick: onClick, }); }; var actions = []; var p = { setData: function (data) { return actions.push(data); }, }; var container = new Container(p); render(React.createElement(NativeComponent, { fooBar: "fooBar", onClick: function () { return void 0; }, className: "class" }), container); expect(actions).toMatchSnapshot(); }); it('remove and add children', function () { return __awaiter(void 0, void 0, void 0, function () { var logs, App, container, app; return __generator(this, function (_a) { switch (_a.label) { case 0: logs = []; App = /** @class */ (function (_super) { __extends(App, _super); function App() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { toggle: false, }; return _this; } App.prototype.toggle = function () { this.setState({ toggle: true, }); }; App.prototype.render = function () { var toggle = this.state.toggle; return (React.createElement(React.Fragment, null, React.createElement(View, { id: "1" }, React.createElement(View, { id: "2" }, toggle ? React.createElement(View, { id: "3" }, "a") : React.createElement(View, { id: "3" }, "b")), !toggle && React.createElement(View, { id: "5" }, "safeAreaHeight")))); }; return App; }(React.Component)); container = new Container({ setData: function (action) { logs.push(action); }, }); app = React.createRef(); render(React.createElement(App, { ref: app }), container); app.current.toggle(); return [4 /*yield*/, delay(100)]; case 1: _a.sent(); expect(logs.pop()).toEqual({ 'root.nodes.6.children': [3], 'root.nodes.6.nodes.3.nodes.2.nodes.1': { id: 1, text: 'a', type: 'plain-text', }, 'root.nodes.6.nodes.5': null, }); return [2 /*return*/]; } }); }); }); it('swaps items', function () { var logs = []; var App = /** @class */ (function (_super) { __extends(App, _super); function App() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { list: ['a', 'b'], }; return _this; } App.prototype.swap = function () { var list = this.state.list; this.setState({ list: [list[1], list[0]], }); }; App.prototype.render = function () { var list = this.state.list; return (React.createElement(View, { id: "1" }, list.map(function (item, index) { return (React.createElement(View, { key: item }, index, item)); }))); }; return App; }(React.Component)); var container = new Container({ setData: function (action) { logs.push(action); }, }); var app = React.createRef(); render(React.createElement(App, { ref: app }), container); expect(logs.pop()).toMatchSnapshot(); app.current.swap(); expect(logs.pop()).toMatchSnapshot(); app.current.swap(); expect(logs.pop()).toMatchSnapshot(); }); it("does not update deleted node's children node", function () { return __awaiter(void 0, void 0, void 0, function () { var logs, App, container, app; return __generator(this, function (_a) { switch (_a.label) { case 0: logs = []; App = /** @class */ (function (_super) { __extends(App, _super); function App() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { a: true, b: true, }; return _this; } App.prototype.toggle = function () { this.setState({ b: false, }); this.setState({ a: false, }); }; App.prototype.render = function () { var _a = this.state, a = _a.a, b = _a.b; // eslint-disable-next-line prettier/prettier return React.createElement(View, { id: "a" }, a && React.createElement(View, { id: "b" }, b ? React.createElement(View, { id: "c" }, "a") : 'b')); }; return App; }(React.Component)); container = new Container({ setData: function (action) { logs.push(action); }, }); app = React.createRef(); render(React.createElement(App, { ref: app }), container); app.current.toggle(); return [4 /*yield*/, delay(100)]; case 1: _a.sent(); expect(logs.pop()).toEqual({ 'root.nodes.4.children': [], 'root.nodes.4.nodes.3': null, }); return [2 /*return*/]; } }); }); }); it('does not update deleted node', function () { return __awaiter(void 0, void 0, void 0, function () { var logs, App, container, app; return __generator(this, function (_a) { switch (_a.label) { case 0: logs = []; App = /** @class */ (function (_super) { __extends(App, _super); function App() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { a: true, b: true, }; return _this; } App.prototype.toggle = function () { this.setState({ b: false, }); this.setState({ a: false, }); }; App.prototype.render = function () { var _a = this.state, a = _a.a, b = _a.b; return React.createElement(View, null, a && React.createElement(View, { style: { color: b ? 'red' : 'green' } }, "foo")); }; return App; }(React.Component)); container = new Container({ setData: function (action) { logs.push(action); }, }); app = React.createRef(); render(React.createElement(App, { ref: app }), container); app.current.toggle(); return [4 /*yield*/, delay(100)]; case 1: _a.sent(); expect(logs.pop()).toEqual({ 'root.nodes.3.children': [], 'root.nodes.3.nodes.2': null, }); return [2 /*return*/]; } }); }); }); it('create proxy for onClick callback', function () { var view = React.createRef(); var handleClick = function (event) { expect(event.stopPropagation).not.toBeUndefined(); }; var handleAnimationStart = function (event) { expect(event.stopPropagation).toBeUndefined(); }; var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { return _super !== null && _super.apply(this, arguments) || this; } Page.prototype.render = function () { return React.createElement(View, { ref: view, onClick: handleClick, onAnimationStart: handleAnimationStart }); }; return Page; }(React.Component)); var container = new Container(p); render(React.createElement(Page, null), container); function findFn(name) { var fnKeys = Object.keys(view.current.container.context); var fnKey = fnKeys.find(function (key) { return key.indexOf(name) !== -1; }) || ''; return view.current.container.context[fnKey]; } var newHandleClick = findFn('onClick'); var newHandleAnimationStart = findFn('onAnimationStart'); newHandleClick({}); newHandleAnimationStart({}); }); it('useEffect works', function (done) { var Page = function () { React.useEffect(function () { done(); }); return React.createElement(View, null, "app"); }; var container = new Container(p); render(React.createElement(Page, null), container); }); it('pure rerender when props changed', function (done) { var payload = []; var context = { setData: function (data) { payload.push(data); }, }; var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { value: 'foo', }; return _this; } Page.prototype.setValue = function (value) { this.setState({ value: value }); }; Page.prototype.render = function () { return (React.createElement(View, { style: { width: '32px' } }, React.createElement(Input, { value: this.state.value }))); }; return Page; }(React.Component)); var container = new Container(context); var page = React.createRef(); render(React.createElement(Page, { ref: page }), container); expect.assertions(2); page.current.setValue('bar'); setTimeout(function () { expect(payload).toHaveLength(2); expect(payload[1]).toMatchInlineSnapshot("\n Object {\n \"root.nodes.2.nodes.1.props.value\": \"bar\",\n }\n "); done(); }, 5); }); it('pure rerender when props delete', function (done) { var payload = []; var context = { setData: function (data) { payload.push(data); }, }; var Page = /** @class */ (function (_super) { __extends(Page, _super); function Page() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { value: 'foo', }; return _this; } Page.prototype.setValue = function (value) { this.setState({ value: value }); }; Page.prototype.render = function () { return (React.createElement(View, { style: { width: '32px' } }, !this.state.value ? React.createElement(Input, null) : React.createElement(Input, { value: this.state.value }))); }; return Page; }(React.Component)); var container = new Container(context); var page = React.createRef(); render(React.createElement(Page, { ref: page }), container); expect.assertions(2); page.current.setValue(undefined); setTimeout(function () { expect(payload).toHaveLength(2); expect(payload).toMatchInlineSnapshot("\n Array [\n Object {\n \"root.children\": Array [\n 2,\n ],\n \"root.nodes.2\": Object {\n \"children\": Array [\n 1,\n ],\n \"id\": 2,\n \"nodes\": Object {\n \"1\": Object {\n \"children\": Array [],\n \"id\": 1,\n \"props\": Object {\n \"value\": \"foo\",\n },\n \"text\": undefined,\n \"type\": \"input\",\n },\n },\n \"props\": Object {\n \"style\": \"width:32rpx;\",\n },\n \"text\": undefined,\n \"type\": \"view\",\n },\n },\n Object {\n \"root.nodes.2.nodes.1.props.value\": null,\n },\n ]\n "); done(); }, 5); }); it('useNativeEffect once works', function (done) { var count = 0; var Page = function () { var _a = __read(React.useState(0), 2), width = _a[0], setWidth = _a[1]; useNativeEffect(function () { count += 1; setTimeout(function () { if (count === 1) { done(); } }, 500); }, []); React.useEffect(function () { setTimeout(function () { setWidth(100); }, 100); }, []); return React.createElement(View, null, width); }; var container = new Container(p); render(React.createElement(Page, null), container); }); it('useNativeEffect deps works', function (done) { var count = 0; var Page = function () { var _a = __read(React.useState(0), 2), width = _a[0], setWidth = _a[1]; var _b = __read(React.useState(0), 2), height = _b[0], setheight = _b[1]; useNativeEffect(function () { count += 1; if (count === 2) { done(); } }, [width]); React.useEffect(function () { setheight(100); setTimeout(function () { setWidth(100); }, 1000); }, []); return (React.createElement(View, null, width, height)); }; var container = new Container(p); render(React.createElement(Page, null), container); }); });