From b08ef1d3944503be83beffb006a284e4460660d9 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 4 Feb 2022 16:46:16 +0200 Subject: [PATCH 01/79] feat(actions-core): Refactored @lowdefy/engine and added actions-core package to plugins. --- packages/engine/src/actions/index.js | 49 --------------- .../plugins/actions/actions-core/README.md | 3 + .../actions/actions-core/jest.config.cjs | 14 +++++ .../plugins/actions/actions-core/package.json | 60 +++++++++++++++++++ .../actions/actions-core/src/actions.js | 47 +++++++++++++++ .../actions-core}/src/actions/CallMethod.js | 0 .../actions-core}/src/actions/JsAction.js | 0 .../actions/actions-core}/src/actions/Link.js | 0 .../actions-core}/src/actions/Login.js | 0 .../actions-core}/src/actions/Logout.js | 0 .../actions-core}/src/actions/Message.js | 0 .../actions-core}/src/actions/Request.js | 0 .../actions-core}/src/actions/Reset.js | 0 .../src/actions/ResetValidation.js | 0 .../actions-core}/src/actions/ScrollTo.js | 0 .../actions-core}/src/actions/SetGlobal.js | 0 .../actions-core}/src/actions/SetState.js | 0 .../actions-core}/src/actions/Throw.js | 0 .../actions-core}/src/actions/Validate.js | 0 .../actions/actions-core}/src/actions/Wait.js | 0 .../plugins/actions/actions-core/src/types.js | 20 +++++++ 21 files changed, 144 insertions(+), 49 deletions(-) delete mode 100644 packages/engine/src/actions/index.js create mode 100644 packages/plugins/actions/actions-core/README.md create mode 100644 packages/plugins/actions/actions-core/jest.config.cjs create mode 100644 packages/plugins/actions/actions-core/package.json create mode 100644 packages/plugins/actions/actions-core/src/actions.js rename packages/{engine => plugins/actions/actions-core}/src/actions/CallMethod.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/JsAction.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Link.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Login.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Logout.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Message.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Request.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Reset.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/ResetValidation.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/ScrollTo.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/SetGlobal.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/SetState.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Throw.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Validate.js (100%) rename packages/{engine => plugins/actions/actions-core}/src/actions/Wait.js (100%) create mode 100644 packages/plugins/actions/actions-core/src/types.js diff --git a/packages/engine/src/actions/index.js b/packages/engine/src/actions/index.js deleted file mode 100644 index d38e93686..000000000 --- a/packages/engine/src/actions/index.js +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import CallMethod from './CallMethod.js'; -import JsAction from './JsAction.js'; -import Link from './Link.js'; -import Login from './Login.js'; -import Logout from './Logout.js'; -import Message from './Message.js'; -import Request from './Request.js'; -import Reset from './Reset.js'; -import ResetValidation from './ResetValidation.js'; -import ScrollTo from './ScrollTo.js'; -import SetGlobal from './SetGlobal.js'; -import SetState from './SetState.js'; -import Throw from './Throw.js'; -import Validate from './Validate.js'; -import Wait from './Wait.js'; - -export default { - CallMethod, - JsAction, - Link, - Login, - Logout, - Message, - Request, - Reset, - ResetValidation, - ScrollTo, - SetGlobal, - SetState, - Throw, - Validate, - Wait, -}; diff --git a/packages/plugins/actions/actions-core/README.md b/packages/plugins/actions/actions-core/README.md new file mode 100644 index 000000000..27aa7532c --- /dev/null +++ b/packages/plugins/actions/actions-core/README.md @@ -0,0 +1,3 @@ +# Lowdefy Actions Core + +Core Lowdefy actions diff --git a/packages/plugins/actions/actions-core/jest.config.cjs b/packages/plugins/actions/actions-core/jest.config.cjs new file mode 100644 index 000000000..67c7bbf70 --- /dev/null +++ b/packages/plugins/actions/actions-core/jest.config.cjs @@ -0,0 +1,14 @@ +module.exports = { + clearMocks: true, + collectCoverage: true, + collectCoverageFrom: ['src/**/*.js'], + coverageDirectory: 'coverage', + coveragePathIgnorePatterns: ['/dist/', '/src/test', '/src/index.js'], + coverageReporters: [['lcov', { projectRoot: '../../../..' }], 'text', 'clover'], + errorOnDeprecated: true, + testEnvironment: 'jsdom', + testPathIgnorePatterns: ['/dist/', '/src/test'], + transform: { + '^.+\\.(t|j)sx?$': ['@swc/jest', { configFile: '../../../../.swcrc.test' }], + }, +}; diff --git a/packages/plugins/actions/actions-core/package.json b/packages/plugins/actions/actions-core/package.json new file mode 100644 index 000000000..3d231e02d --- /dev/null +++ b/packages/plugins/actions/actions-core/package.json @@ -0,0 +1,60 @@ +{ + "name": "@lowdefy/actions-core", + "version": "4.0.0-alpha.6", + "licence": "Apache-2.0", + "description": "", + "homepage": "https://lowdefy.com", + "keywords": [ + "lowdefy", + "lowdefy actions", + "lowdefy plugin" + ], + "bugs": { + "url": "https://github.com/lowdefy/lowdefy/issues" + }, + "contributors": [ + { + "name": "Sam Tolmay", + "url": "https://github.com/SamTolmay" + }, + { + "name": "Gerrie van Wyk", + "url": "https://github.com/Gervwyk" + }, + { + "name": "Sandile Memela", + "url": "https://github.com/sah-memela" + } + ], + "repository": { + "type": "git", + "url": "https://github.com/lowdefy/lowdefy.git" + }, + "type": "module", + "exports": { + "./actions": "./dist/actions.js", + "./types": "./dist/types.js" + }, + "files": [ + "dist/*" + ], + "scripts": { + "build": "yarn swc", + "clean": "rm -rf dist", + "prepare": "yarn build", + "swc": "swc src --out-dir dist --config-file ../../../../.swcrc --delete-dir-on-start --copy-files", + "test": "jest --coverage" + }, + "dependencies": { + "@lowdefy/helpers": "4.0.0-alpha.6" + }, + "devDependencies": { + "@swc/cli": "0.1.55", + "@swc/core": "1.2.135", + "@swc/jest": "0.2.17", + "jest": "27.4.7" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/plugins/actions/actions-core/src/actions.js b/packages/plugins/actions/actions-core/src/actions.js new file mode 100644 index 000000000..9a5b91c82 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions.js @@ -0,0 +1,47 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { default as CallMethod } from './actions/CallMethod.js'; +import { default as Link } from './actions/Link.js'; +import { default as Login } from './actions/Login.js'; +import { default as Logout } from './actions/Logout.js'; +import { default as Message } from './actions/Message.js'; +import { default as Request } from './actions/Request.js'; +import { default as Reset } from './actions/Reset.js'; +import { default as ResetValidation } from './actions/ResetValidation.js'; +import { default as ScrollTo } from './actions/ScrollTo.js'; +import { default as SetGlobal } from './actions/SetGlobal.js'; +import { default as SetState } from './actions/SetState.js'; +import { default as Throw } from './actions/Throw.js'; +import { default as Validate } from './actions/Validate.js'; +import { default as Wait } from './actions/Wait.js'; + +export default { + CallMethod, + Link, + Login, + Logout, + Message, + Request, + Reset, + ResetValidation, + ScrollTo, + SetGlobal, + SetState, + Throw, + Validate, + Wait, +}; diff --git a/packages/engine/src/actions/CallMethod.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.js similarity index 100% rename from packages/engine/src/actions/CallMethod.js rename to packages/plugins/actions/actions-core/src/actions/CallMethod.js diff --git a/packages/engine/src/actions/JsAction.js b/packages/plugins/actions/actions-core/src/actions/JsAction.js similarity index 100% rename from packages/engine/src/actions/JsAction.js rename to packages/plugins/actions/actions-core/src/actions/JsAction.js diff --git a/packages/engine/src/actions/Link.js b/packages/plugins/actions/actions-core/src/actions/Link.js similarity index 100% rename from packages/engine/src/actions/Link.js rename to packages/plugins/actions/actions-core/src/actions/Link.js diff --git a/packages/engine/src/actions/Login.js b/packages/plugins/actions/actions-core/src/actions/Login.js similarity index 100% rename from packages/engine/src/actions/Login.js rename to packages/plugins/actions/actions-core/src/actions/Login.js diff --git a/packages/engine/src/actions/Logout.js b/packages/plugins/actions/actions-core/src/actions/Logout.js similarity index 100% rename from packages/engine/src/actions/Logout.js rename to packages/plugins/actions/actions-core/src/actions/Logout.js diff --git a/packages/engine/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js similarity index 100% rename from packages/engine/src/actions/Message.js rename to packages/plugins/actions/actions-core/src/actions/Message.js diff --git a/packages/engine/src/actions/Request.js b/packages/plugins/actions/actions-core/src/actions/Request.js similarity index 100% rename from packages/engine/src/actions/Request.js rename to packages/plugins/actions/actions-core/src/actions/Request.js diff --git a/packages/engine/src/actions/Reset.js b/packages/plugins/actions/actions-core/src/actions/Reset.js similarity index 100% rename from packages/engine/src/actions/Reset.js rename to packages/plugins/actions/actions-core/src/actions/Reset.js diff --git a/packages/engine/src/actions/ResetValidation.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js similarity index 100% rename from packages/engine/src/actions/ResetValidation.js rename to packages/plugins/actions/actions-core/src/actions/ResetValidation.js diff --git a/packages/engine/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js similarity index 100% rename from packages/engine/src/actions/ScrollTo.js rename to packages/plugins/actions/actions-core/src/actions/ScrollTo.js diff --git a/packages/engine/src/actions/SetGlobal.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js similarity index 100% rename from packages/engine/src/actions/SetGlobal.js rename to packages/plugins/actions/actions-core/src/actions/SetGlobal.js diff --git a/packages/engine/src/actions/SetState.js b/packages/plugins/actions/actions-core/src/actions/SetState.js similarity index 100% rename from packages/engine/src/actions/SetState.js rename to packages/plugins/actions/actions-core/src/actions/SetState.js diff --git a/packages/engine/src/actions/Throw.js b/packages/plugins/actions/actions-core/src/actions/Throw.js similarity index 100% rename from packages/engine/src/actions/Throw.js rename to packages/plugins/actions/actions-core/src/actions/Throw.js diff --git a/packages/engine/src/actions/Validate.js b/packages/plugins/actions/actions-core/src/actions/Validate.js similarity index 100% rename from packages/engine/src/actions/Validate.js rename to packages/plugins/actions/actions-core/src/actions/Validate.js diff --git a/packages/engine/src/actions/Wait.js b/packages/plugins/actions/actions-core/src/actions/Wait.js similarity index 100% rename from packages/engine/src/actions/Wait.js rename to packages/plugins/actions/actions-core/src/actions/Wait.js diff --git a/packages/plugins/actions/actions-core/src/types.js b/packages/plugins/actions/actions-core/src/types.js new file mode 100644 index 000000000..cfb4e9247 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/types.js @@ -0,0 +1,20 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ +import * as actions from './actions.js'; + +export default { + actions: Object.keys(actions), +}; From 6838da620ebe25e813a2a74f5b740fa2c39c3324 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 4 Feb 2022 16:50:12 +0200 Subject: [PATCH 02/79] chore(plugins): Added "lowdefy plugin" keyword to plugins packages. --- packages/plugins/blocks/blocks-antd/package.json | 3 ++- packages/plugins/blocks/blocks-basic/package.json | 3 ++- packages/plugins/blocks/blocks-color-selectors/package.json | 3 ++- packages/plugins/blocks/blocks-echarts/package.json | 3 ++- packages/plugins/blocks/blocks-loaders/package.json | 3 ++- packages/plugins/blocks/blocks-markdown/package.json | 3 ++- .../plugins/connections/connection-axios-http/package.json | 3 ++- .../plugins/connections/connection-elasticsearch/package.json | 3 ++- .../plugins/connections/connection-google-sheets/package.json | 3 ++- packages/plugins/connections/connection-knex/package.json | 3 ++- packages/plugins/connections/connection-mongodb/package.json | 3 ++- packages/plugins/connections/connection-redis/package.json | 3 ++- packages/plugins/connections/connection-sendgrid/package.json | 3 ++- packages/plugins/connections/connection-stripe/package.json | 3 ++- packages/plugins/operators/operators-change-case/package.json | 3 ++- packages/plugins/operators/operators-diff/package.json | 3 ++- packages/plugins/operators/operators-js/package.json | 3 ++- packages/plugins/operators/operators-mql/package.json | 3 ++- packages/plugins/operators/operators-nunjucks/package.json | 3 ++- packages/plugins/operators/operators-uuid/package.json | 3 ++- packages/plugins/operators/operators-yaml/package.json | 3 ++- 21 files changed, 42 insertions(+), 21 deletions(-) diff --git a/packages/plugins/blocks/blocks-antd/package.json b/packages/plugins/blocks/blocks-antd/package.json index 954af05f0..e172aa27a 100644 --- a/packages/plugins/blocks/blocks-antd/package.json +++ b/packages/plugins/blocks/blocks-antd/package.json @@ -8,7 +8,8 @@ "lowdefy", "lowdefy blocks", "antd", - "ant design" + "ant design", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/blocks/blocks-basic/package.json b/packages/plugins/blocks/blocks-basic/package.json index 2d014470b..b3958c315 100644 --- a/packages/plugins/blocks/blocks-basic/package.json +++ b/packages/plugins/blocks/blocks-basic/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy blocks" + "lowdefy blocks", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/blocks/blocks-color-selectors/package.json b/packages/plugins/blocks/blocks-color-selectors/package.json index 2e9aa29cf..f2988e083 100644 --- a/packages/plugins/blocks/blocks-color-selectors/package.json +++ b/packages/plugins/blocks/blocks-color-selectors/package.json @@ -8,7 +8,8 @@ "lowdefy", "lowdefy blocks", "color picker", - "react-color" + "react-color", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/blocks/blocks-echarts/package.json b/packages/plugins/blocks/blocks-echarts/package.json index 3e2d07ed5..c258b2c18 100644 --- a/packages/plugins/blocks/blocks-echarts/package.json +++ b/packages/plugins/blocks/blocks-echarts/package.json @@ -8,7 +8,8 @@ "lowdefy", "lowdefy blocks", "echarts", - "charts" + "charts", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/blocks/blocks-loaders/package.json b/packages/plugins/blocks/blocks-loaders/package.json index 57863b94c..e813151f6 100644 --- a/packages/plugins/blocks/blocks-loaders/package.json +++ b/packages/plugins/blocks/blocks-loaders/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy blocks" + "lowdefy blocks", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/blocks/blocks-markdown/package.json b/packages/plugins/blocks/blocks-markdown/package.json index b7135471c..899228a9c 100644 --- a/packages/plugins/blocks/blocks-markdown/package.json +++ b/packages/plugins/blocks/blocks-markdown/package.json @@ -8,7 +8,8 @@ "lowdefy", "lowdefy blocks", "markdown", - "react-markdown" + "react-markdown", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-axios-http/package.json b/packages/plugins/connections/connection-axios-http/package.json index da7a64949..9674e8b95 100644 --- a/packages/plugins/connections/connection-axios-http/package.json +++ b/packages/plugins/connections/connection-axios-http/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-elasticsearch/package.json b/packages/plugins/connections/connection-elasticsearch/package.json index e2496983d..39e63f4f9 100644 --- a/packages/plugins/connections/connection-elasticsearch/package.json +++ b/packages/plugins/connections/connection-elasticsearch/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-google-sheets/package.json b/packages/plugins/connections/connection-google-sheets/package.json index 0c3a0e383..4114a4cec 100644 --- a/packages/plugins/connections/connection-google-sheets/package.json +++ b/packages/plugins/connections/connection-google-sheets/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-knex/package.json b/packages/plugins/connections/connection-knex/package.json index e00238b9b..2637c1a48 100644 --- a/packages/plugins/connections/connection-knex/package.json +++ b/packages/plugins/connections/connection-knex/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-mongodb/package.json b/packages/plugins/connections/connection-mongodb/package.json index b4bccce3a..5692b4139 100644 --- a/packages/plugins/connections/connection-mongodb/package.json +++ b/packages/plugins/connections/connection-mongodb/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-redis/package.json b/packages/plugins/connections/connection-redis/package.json index 405b0d200..118a28e95 100644 --- a/packages/plugins/connections/connection-redis/package.json +++ b/packages/plugins/connections/connection-redis/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-sendgrid/package.json b/packages/plugins/connections/connection-sendgrid/package.json index fe88c3003..49b94020d 100644 --- a/packages/plugins/connections/connection-sendgrid/package.json +++ b/packages/plugins/connections/connection-sendgrid/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/connections/connection-stripe/package.json b/packages/plugins/connections/connection-stripe/package.json index 904710adf..12788e07b 100644 --- a/packages/plugins/connections/connection-stripe/package.json +++ b/packages/plugins/connections/connection-stripe/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy connection" + "lowdefy connection", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-change-case/package.json b/packages/plugins/operators/operators-change-case/package.json index 2d62af7e0..3831f6446 100644 --- a/packages/plugins/operators/operators-change-case/package.json +++ b/packages/plugins/operators/operators-change-case/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-diff/package.json b/packages/plugins/operators/operators-diff/package.json index 9d762df1e..70027e48e 100644 --- a/packages/plugins/operators/operators-diff/package.json +++ b/packages/plugins/operators/operators-diff/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-js/package.json b/packages/plugins/operators/operators-js/package.json index 9af5b40c8..20c963eaa 100644 --- a/packages/plugins/operators/operators-js/package.json +++ b/packages/plugins/operators/operators-js/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-mql/package.json b/packages/plugins/operators/operators-mql/package.json index 0967b99e2..39e30db37 100644 --- a/packages/plugins/operators/operators-mql/package.json +++ b/packages/plugins/operators/operators-mql/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-nunjucks/package.json b/packages/plugins/operators/operators-nunjucks/package.json index ed7b65855..a5e59f160 100644 --- a/packages/plugins/operators/operators-nunjucks/package.json +++ b/packages/plugins/operators/operators-nunjucks/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-uuid/package.json b/packages/plugins/operators/operators-uuid/package.json index c9a7be22f..092d37d11 100644 --- a/packages/plugins/operators/operators-uuid/package.json +++ b/packages/plugins/operators/operators-uuid/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" diff --git a/packages/plugins/operators/operators-yaml/package.json b/packages/plugins/operators/operators-yaml/package.json index b444f4939..1122be351 100644 --- a/packages/plugins/operators/operators-yaml/package.json +++ b/packages/plugins/operators/operators-yaml/package.json @@ -6,7 +6,8 @@ "homepage": "https://lowdefy.com", "keywords": [ "lowdefy", - "lowdefy operator" + "lowdefy operator", + "lowdefy plugin" ], "bugs": { "url": "https://github.com/lowdefy/lowdefy/issues" From dd24ec6502d4887db9faafe0048b1931edb401d8 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 4 Feb 2022 16:52:46 +0200 Subject: [PATCH 03/79] chore(actions-core): Deleted JsAction action. --- .../actions-core/src/actions/JsAction.js | 61 ------------------- 1 file changed, 61 deletions(-) delete mode 100644 packages/plugins/actions/actions-core/src/actions/JsAction.js diff --git a/packages/plugins/actions/actions-core/src/actions/JsAction.js b/packages/plugins/actions/actions-core/src/actions/JsAction.js deleted file mode 100644 index 2a51f4360..000000000 --- a/packages/plugins/actions/actions-core/src/actions/JsAction.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ -import { type, serializer } from '@lowdefy/helpers'; - -import actionFns from './index.js'; - -async function JsAction({ context, event, params, arrayIndices, blockId }) { - if (!type.isString(params.name)) { - throw new Error(`JsAction requires a string for 'params.name'.`); - } - if (!type.isNone(params.args) && !type.isArray(params.args)) { - throw new Error(`JsAction requires a array for 'params.args'.`); - } - if (!type.isFunction(context.lowdefy.imports.jsActions[params.name])) { - throw new Error(`JsAction ${params.name} is not a function.`); - } - - const actions = {}; - Object.keys(actionFns).forEach((name) => { - actions[name] = (actionParams) => - actionFns[name]({ - arrayIndices, - blockId, - context, - event, - params: actionParams, - }); - }); - - return context.lowdefy.imports.jsActions[params.name]( - { - ...serializer.copy({ - global: context.lowdefy.lowdefyGlobal, - input: context.lowdefy.inputs[context.id], - state: context.state, - urlQuery: context.lowdefy.urlQuery, - user: context.lowdefy.user, - }), - actions, - contextId: context.id, - pageId: context.pageId, - requests: { ...context.requests }, - }, - ...(params.args || []) - ); -} - -export default JsAction; From 563900ba49e6025862e9444743a485952c0d2c1c Mon Sep 17 00:00:00 2001 From: Sandile Date: Mon, 7 Feb 2022 13:56:30 +0200 Subject: [PATCH 04/79] fix(actions-core): Refactored actions to use actions interface. --- .../actions-core/src/actions/CallMethod.js | 25 ++----------------- .../actions/actions-core/src/actions/Link.js | 12 ++------- .../actions/actions-core/src/actions/Login.js | 4 +-- .../actions-core/src/actions/Logout.js | 4 +-- .../actions-core/src/actions/Message.js | 9 ++----- .../actions-core/src/actions/Request.js | 4 +-- .../actions/actions-core/src/actions/Reset.js | 10 ++------ .../src/actions/ResetValidation.js | 6 ++--- .../actions-core/src/actions/ScrollTo.js | 11 ++------ .../actions-core/src/actions/SetGlobal.js | 10 ++------ .../actions-core/src/actions/SetState.js | 10 ++------ .../actions/actions-core/src/actions/Throw.js | 13 +++++++--- .../actions-core/src/actions/Validate.js | 14 ++--------- 13 files changed, 33 insertions(+), 99 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/CallMethod.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.js index d4770e5d9..17d003219 100644 --- a/packages/plugins/actions/actions-core/src/actions/CallMethod.js +++ b/packages/plugins/actions/actions-core/src/actions/CallMethod.js @@ -14,29 +14,8 @@ limitations under the License. */ -import { applyArrayIndices, type } from '@lowdefy/helpers'; - -// context, event, params - -async function CallMethod({ arrayIndices, context, params }) { - const { blockId, method, args = [] } = params; - const blockMethod = - context._internal.RootBlocks.map[applyArrayIndices(arrayIndices, blockId)].methods[method]; - if (!type.isArray(args)) { - throw new Error( - `Failed to call method "${method}" on block "${blockId}": "args" should be an array. Received "${JSON.stringify( - params - )}".` - ); - } - if (!type.isFunction(blockMethod)) { - throw new Error( - `Failed to call method "${method}" on block "${blockId}". Check if "${method}" is a valid block method for block "${blockId}". Received "${JSON.stringify( - params - )}".` - ); - } - return blockMethod(...args); +async function CallMethod({ methods: { callMethod }, params }) { + return callMethod({ params }); } export default CallMethod; diff --git a/packages/plugins/actions/actions-core/src/actions/Link.js b/packages/plugins/actions/actions-core/src/actions/Link.js index 56d8292c4..ade6ed5b8 100644 --- a/packages/plugins/actions/actions-core/src/actions/Link.js +++ b/packages/plugins/actions/actions-core/src/actions/Link.js @@ -14,16 +14,8 @@ limitations under the License. */ -import { type } from '@lowdefy/helpers'; - -async function Link({ context, params }) { - const linkParams = type.isString(params) ? { pageId: params } : params; - try { - context._internal.lowdefy._internal.link(linkParams); - } catch (error) { - console.log(error); - throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); - } +async function Link({ methods: { link }, params }) { + link({ params }); } export default Link; diff --git a/packages/plugins/actions/actions-core/src/actions/Login.js b/packages/plugins/actions/actions-core/src/actions/Login.js index 17f26dd21..cdb68f0f4 100644 --- a/packages/plugins/actions/actions-core/src/actions/Login.js +++ b/packages/plugins/actions/actions-core/src/actions/Login.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Login({ context, params }) { - return context._internal.lowdefy._internal.auth.login(params); +async function Login({ methods: { login }, params }) { + return login({ params }); } export default Login; diff --git a/packages/plugins/actions/actions-core/src/actions/Logout.js b/packages/plugins/actions/actions-core/src/actions/Logout.js index fcd658694..f7cec6d31 100644 --- a/packages/plugins/actions/actions-core/src/actions/Logout.js +++ b/packages/plugins/actions/actions-core/src/actions/Logout.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Logout({ context }) { - return context._internal.lowdefy._internal.auth.logout(); +async function Logout({ methods: { logout } }) { + return logout(); } export default Logout; diff --git a/packages/plugins/actions/actions-core/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js index 5d609101f..0493948f6 100644 --- a/packages/plugins/actions/actions-core/src/actions/Message.js +++ b/packages/plugins/actions/actions-core/src/actions/Message.js @@ -14,13 +14,8 @@ limitations under the License. */ -function Message({ context, params = {} }) { - context._internal.lowdefy._internal.displayMessage({ - content: params.content || 'Success', - duration: params.duration, - icon: params.icon, - status: params.status, - }); +function Message({ methods: { message }, params }) { + message({ params }); } export default Message; diff --git a/packages/plugins/actions/actions-core/src/actions/Request.js b/packages/plugins/actions/actions-core/src/actions/Request.js index ea8271cda..64804db72 100644 --- a/packages/plugins/actions/actions-core/src/actions/Request.js +++ b/packages/plugins/actions/actions-core/src/actions/Request.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Request({ actions, arrayIndices, context, event, params }) { - return context._internal.Requests.callRequests({ actions, arrayIndices, event, params }); +async function Request({ methods: { request }, params }) { + return request({ params }); } export default Request; diff --git a/packages/plugins/actions/actions-core/src/actions/Reset.js b/packages/plugins/actions/actions-core/src/actions/Reset.js index f5ec2a4f3..ffb020981 100644 --- a/packages/plugins/actions/actions-core/src/actions/Reset.js +++ b/packages/plugins/actions/actions-core/src/actions/Reset.js @@ -14,14 +14,8 @@ limitations under the License. */ -import { serializer } from '@lowdefy/helpers'; - -function Reset({ context }) { - context._internal.State.resetState(); - context._internal.RootBlocks.reset( - serializer.deserializeFromString(context._internal.State.frozenState) - ); - context._internal.update(); +function Reset({ methods: { reset } }) { + reset(); } export default Reset; diff --git a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js index 925d5024a..b554e9dc3 100644 --- a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js +++ b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js @@ -14,10 +14,8 @@ limitations under the License. */ -import getBlockMatcher from '../getBlockMatcher.js'; - -async function ResetValidation({ context, params }) { - context._internal.RootBlocks.resetValidation(getBlockMatcher(params)); +async function ResetValidation({ methods: { resetValidation }, params }) { + resetValidation({ params }); } export default ResetValidation; diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index 5e7c6bc1b..aedb0d954 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -14,15 +14,8 @@ limitations under the License. */ -async function ScrollTo({ context, params = {} }) { - if (params.blockId) { - const element = context._internal.lowdefy._internal.document.getElementById(params.blockId); - if (element) { - element.scrollIntoView(params.options); - } - } else { - context._internal.lowdefy._internal.window.scrollTo(params); - } +async function ScrollTo({ methods: { scrollTo }, params }) { + scrollTo({ params }); } export default ScrollTo; diff --git a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js index a49756574..75ce7302f 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js +++ b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js @@ -14,14 +14,8 @@ limitations under the License. */ -import { applyArrayIndices, set } from '@lowdefy/helpers'; - -async function SetGlobal({ arrayIndices, context, params }) { - Object.keys(params).forEach((key) => { - set(context._internal.lowdefy.lowdefyGlobal, applyArrayIndices(arrayIndices, key), params[key]); - }); - context._internal.RootBlocks.reset(); - context._internal.update(); +async function SetGlobal({ methods: { setGlobal }, params }) { + setGlobal({ params }); } export default SetGlobal; diff --git a/packages/plugins/actions/actions-core/src/actions/SetState.js b/packages/plugins/actions/actions-core/src/actions/SetState.js index 6b158d059..d1c34409e 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetState.js +++ b/packages/plugins/actions/actions-core/src/actions/SetState.js @@ -14,14 +14,8 @@ limitations under the License. */ -import { applyArrayIndices } from '@lowdefy/helpers'; - -async function SetState({ arrayIndices, context, params }) { - Object.keys(params).forEach((key) => { - context._internal.State.set(applyArrayIndices(arrayIndices, key), params[key]); - }); - context._internal.RootBlocks.reset(); - context._internal.update(); +async function SetState({ methods: { setState }, params }) { + setState({ params }); } export default SetState; diff --git a/packages/plugins/actions/actions-core/src/actions/Throw.js b/packages/plugins/actions/actions-core/src/actions/Throw.js index 158c3c5d8..c479118a7 100644 --- a/packages/plugins/actions/actions-core/src/actions/Throw.js +++ b/packages/plugins/actions/actions-core/src/actions/Throw.js @@ -13,24 +13,29 @@ See the License for the specific language governing permissions and limitations under the License. */ + import { type } from '@lowdefy/helpers'; class ThrowActionError extends Error { - constructor(message, { blockId, context, metaData }) { + constructor(message, { blockId, metaData, pageId }) { super(message); this.blockId = blockId; this.metaData = metaData; this.name = 'ThrowError'; - this.pageId = context.pageId; + this.pageId = pageId; } } -function Throw({ blockId, context, params = {} }) { +function Throw({ methods: { getBlockId, getPageId }, params }) { if (params.throw === false || type.isNone(params.throw)) { return; } if (params.throw === true) { - throw new ThrowActionError(params.message, { blockId, context, metaData: params.metaData }); + throw new ThrowActionError(params.message, { + blockId: getBlockId(), + metaData: params.metaData, + pageId: getPageId(), + }); } throw new Error(`Invalid Throw, check action params. Received "${JSON.stringify(params)}".`); } diff --git a/packages/plugins/actions/actions-core/src/actions/Validate.js b/packages/plugins/actions/actions-core/src/actions/Validate.js index 9e711d00c..2428f0113 100644 --- a/packages/plugins/actions/actions-core/src/actions/Validate.js +++ b/packages/plugins/actions/actions-core/src/actions/Validate.js @@ -14,18 +14,8 @@ limitations under the License. */ -import getBlockMatcher from '../getBlockMatcher.js'; - -async function Validate({ context, params }) { - const validationErrors = context.RootBlocks.validate(getBlockMatcher(params)); - if (validationErrors.length > 0) { - const error = new Error( - `Your input has ${validationErrors.length} validation error${ - validationErrors.length !== 1 ? 's' : '' - }.` - ); - throw error; - } +async function Validate({ methods: { validate }, params }) { + return validate({ params }); } export default Validate; From f28052cb510a0757310d20068105d193e2f6856c Mon Sep 17 00:00:00 2001 From: Sandile Date: Mon, 7 Feb 2022 14:05:10 +0200 Subject: [PATCH 05/79] feat(server): Added import for actions plugins to the lowdefy context. --- packages/server/src/components/LowdefyContext.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/server/src/components/LowdefyContext.js b/packages/server/src/components/LowdefyContext.js index 257d37240..4e967f5b5 100644 --- a/packages/server/src/components/LowdefyContext.js +++ b/packages/server/src/components/LowdefyContext.js @@ -16,6 +16,7 @@ import React from 'react'; +import actions from '../../build/plugins/actions.js'; import callRequest from '../utils/callRequest.js'; import blockComponents from '../../build/plugins/blocks.js'; import operators from '../../build/plugins/operatorsClient.js'; @@ -24,6 +25,7 @@ import components from './components.js'; const LowdefyContext = ({ children }) => { const lowdefy = { _internal: { + actions, blockComponents, callRequest, components, From 20133bb0589d35b1494cd3f996ff0ea5421ee560 Mon Sep 17 00:00:00 2001 From: Sandile Date: Mon, 7 Feb 2022 14:05:20 +0200 Subject: [PATCH 06/79] feat(server-dev): Added import for actions plugins to the lowdefy context. --- packages/server-dev/src/components/LowdefyContext.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/server-dev/src/components/LowdefyContext.js b/packages/server-dev/src/components/LowdefyContext.js index dd5dfd861..c9e3279b7 100644 --- a/packages/server-dev/src/components/LowdefyContext.js +++ b/packages/server-dev/src/components/LowdefyContext.js @@ -16,6 +16,7 @@ import React from 'react'; +import actions from '../../build/plugins/actions.js'; import callRequest from '../utils/callRequest.js'; import blockComponents from '../../build/plugins/blocks.js'; import operators from '../../build/plugins/operatorsClient.js'; @@ -24,6 +25,7 @@ import components from './components.js'; const LowdefyContext = ({ children }) => { const lowdefy = { _internal: { + actions, blockComponents, callRequest, components, From ebc27c7f38ed224189581c986e2f0c92a96756f0 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 11:30:07 +0200 Subject: [PATCH 07/79] chore(actions-core): Refactor action method parameters. --- packages/plugins/actions/actions-core/src/actions/CallMethod.js | 2 +- packages/plugins/actions/actions-core/src/actions/Link.js | 2 +- packages/plugins/actions/actions-core/src/actions/Login.js | 2 +- packages/plugins/actions/actions-core/src/actions/Message.js | 2 +- packages/plugins/actions/actions-core/src/actions/Request.js | 2 +- .../plugins/actions/actions-core/src/actions/ResetValidation.js | 2 +- packages/plugins/actions/actions-core/src/actions/ScrollTo.js | 2 +- packages/plugins/actions/actions-core/src/actions/SetGlobal.js | 2 +- packages/plugins/actions/actions-core/src/actions/SetState.js | 2 +- packages/plugins/actions/actions-core/src/actions/Validate.js | 2 +- 10 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/CallMethod.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.js index 17d003219..c2de291b8 100644 --- a/packages/plugins/actions/actions-core/src/actions/CallMethod.js +++ b/packages/plugins/actions/actions-core/src/actions/CallMethod.js @@ -15,7 +15,7 @@ */ async function CallMethod({ methods: { callMethod }, params }) { - return callMethod({ params }); + return callMethod(params); } export default CallMethod; diff --git a/packages/plugins/actions/actions-core/src/actions/Link.js b/packages/plugins/actions/actions-core/src/actions/Link.js index ade6ed5b8..30f0c4f3f 100644 --- a/packages/plugins/actions/actions-core/src/actions/Link.js +++ b/packages/plugins/actions/actions-core/src/actions/Link.js @@ -15,7 +15,7 @@ */ async function Link({ methods: { link }, params }) { - link({ params }); + link(params); } export default Link; diff --git a/packages/plugins/actions/actions-core/src/actions/Login.js b/packages/plugins/actions/actions-core/src/actions/Login.js index cdb68f0f4..0400a2a2f 100644 --- a/packages/plugins/actions/actions-core/src/actions/Login.js +++ b/packages/plugins/actions/actions-core/src/actions/Login.js @@ -15,7 +15,7 @@ */ async function Login({ methods: { login }, params }) { - return login({ params }); + return login(params); } export default Login; diff --git a/packages/plugins/actions/actions-core/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js index 0493948f6..0e3ec319e 100644 --- a/packages/plugins/actions/actions-core/src/actions/Message.js +++ b/packages/plugins/actions/actions-core/src/actions/Message.js @@ -15,7 +15,7 @@ */ function Message({ methods: { message }, params }) { - message({ params }); + message(params); } export default Message; diff --git a/packages/plugins/actions/actions-core/src/actions/Request.js b/packages/plugins/actions/actions-core/src/actions/Request.js index 64804db72..735272e8c 100644 --- a/packages/plugins/actions/actions-core/src/actions/Request.js +++ b/packages/plugins/actions/actions-core/src/actions/Request.js @@ -15,7 +15,7 @@ */ async function Request({ methods: { request }, params }) { - return request({ params }); + return request(params); } export default Request; diff --git a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js index b554e9dc3..f88e96c92 100644 --- a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js +++ b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js @@ -15,7 +15,7 @@ */ async function ResetValidation({ methods: { resetValidation }, params }) { - resetValidation({ params }); + resetValidation(params); } export default ResetValidation; diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index aedb0d954..84412c127 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -15,7 +15,7 @@ */ async function ScrollTo({ methods: { scrollTo }, params }) { - scrollTo({ params }); + scrollTo(params); } export default ScrollTo; diff --git a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js index 75ce7302f..ec81115ba 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js +++ b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js @@ -15,7 +15,7 @@ */ async function SetGlobal({ methods: { setGlobal }, params }) { - setGlobal({ params }); + setGlobal(params); } export default SetGlobal; diff --git a/packages/plugins/actions/actions-core/src/actions/SetState.js b/packages/plugins/actions/actions-core/src/actions/SetState.js index d1c34409e..fe51ea77f 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetState.js +++ b/packages/plugins/actions/actions-core/src/actions/SetState.js @@ -15,7 +15,7 @@ */ async function SetState({ methods: { setState }, params }) { - setState({ params }); + setState(params); } export default SetState; diff --git a/packages/plugins/actions/actions-core/src/actions/Validate.js b/packages/plugins/actions/actions-core/src/actions/Validate.js index 2428f0113..0548f6d92 100644 --- a/packages/plugins/actions/actions-core/src/actions/Validate.js +++ b/packages/plugins/actions/actions-core/src/actions/Validate.js @@ -15,7 +15,7 @@ */ async function Validate({ methods: { validate }, params }) { - return validate({ params }); + return validate(params); } export default Validate; From e3a32aae4079fe85124039c1ac736cffb784bd4a Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 11:33:23 +0200 Subject: [PATCH 08/79] feat(engine): Added action methods to Actions class. --- packages/engine/src/Actions.js | 22 +-- packages/engine/src/actions/callMethod.js | 40 ++++++ packages/engine/src/actions/getAction.js | 29 ++++ packages/engine/src/actions/getBlockId.js | 21 +++ packages/engine/src/actions/getEvent.js | 29 ++++ packages/engine/src/actions/getFromObject.js | 44 ++++++ packages/engine/src/actions/getGlobal.js | 29 ++++ packages/engine/src/actions/getInput.js | 29 ++++ packages/engine/src/actions/getPageId.js | 21 +++ packages/engine/src/actions/getRequest.js | 29 ++++ packages/engine/src/actions/getState.js | 29 ++++ packages/engine/src/actions/getUrlQuery.js | 29 ++++ packages/engine/src/actions/getUser.js | 29 ++++ packages/engine/src/actions/index.js | 135 ++++++++++++++++++ packages/engine/src/actions/link.js | 29 ++++ packages/engine/src/actions/login.js | 21 +++ packages/engine/src/actions/logout.js | 21 +++ packages/engine/src/actions/message.js | 26 ++++ packages/engine/src/actions/request.js | 21 +++ packages/engine/src/actions/reset.js | 27 ++++ .../engine/src/actions/resetValidation.js | 23 +++ packages/engine/src/actions/scrollTo.js | 28 ++++ packages/engine/src/actions/setGlobal.js | 27 ++++ packages/engine/src/actions/setState.js | 27 ++++ packages/engine/src/actions/validate.js | 31 ++++ 25 files changed, 788 insertions(+), 8 deletions(-) create mode 100644 packages/engine/src/actions/callMethod.js create mode 100644 packages/engine/src/actions/getAction.js create mode 100644 packages/engine/src/actions/getBlockId.js create mode 100644 packages/engine/src/actions/getEvent.js create mode 100644 packages/engine/src/actions/getFromObject.js create mode 100644 packages/engine/src/actions/getGlobal.js create mode 100644 packages/engine/src/actions/getInput.js create mode 100644 packages/engine/src/actions/getPageId.js create mode 100644 packages/engine/src/actions/getRequest.js create mode 100644 packages/engine/src/actions/getState.js create mode 100644 packages/engine/src/actions/getUrlQuery.js create mode 100644 packages/engine/src/actions/getUser.js create mode 100644 packages/engine/src/actions/index.js create mode 100644 packages/engine/src/actions/link.js create mode 100644 packages/engine/src/actions/login.js create mode 100644 packages/engine/src/actions/logout.js create mode 100644 packages/engine/src/actions/message.js create mode 100644 packages/engine/src/actions/request.js create mode 100644 packages/engine/src/actions/reset.js create mode 100644 packages/engine/src/actions/resetValidation.js create mode 100644 packages/engine/src/actions/scrollTo.js create mode 100644 packages/engine/src/actions/setGlobal.js create mode 100644 packages/engine/src/actions/setState.js create mode 100644 packages/engine/src/actions/validate.js diff --git a/packages/engine/src/Actions.js b/packages/engine/src/Actions.js index f483e455e..34e657518 100644 --- a/packages/engine/src/Actions.js +++ b/packages/engine/src/Actions.js @@ -15,7 +15,7 @@ */ import { type } from '@lowdefy/helpers'; -import actions from './actions/index.js'; +import { getMethods } from './actions/index.js'; class Actions { constructor(context) { @@ -24,7 +24,7 @@ class Actions { this.callActionLoop = this.callActionLoop.bind(this); this.callActions = this.callActions.bind(this); this.displayMessage = this.displayMessage.bind(this); - this.actions = actions; + this.actions = context._internal.lowdefy._internal.actions; } async callAsyncAction({ action, arrayIndices, block, event, index, responses }) { @@ -126,7 +126,7 @@ class Actions { } async callAction({ action, arrayIndices, block, event, index, responses }) { - if (!actions[action.type]) { + if (!this.actions[action.type]) { throw { error: new Error(`Invalid action type "${action.type}" at "${block.blockId}".`), type: action.type, @@ -155,12 +155,18 @@ class Actions { status: 'loading', }); try { - response = await actions[action.type]({ - arrayIndices, - blockId: block.blockId, - context: this.context, - event, + response = await this.actions[action.type]({ + methods: getMethods({ + actions: this.actions, + arrayIndices, + blockId: block.blockId, + context: this.context, + event, + responses, + }), + document: this.context._internal.lowdefy._internal.document, params: parsedAction.params, + window: this.context._internal.lowdefy._internal.window, }); } catch (error) { responses[action.id] = { error, index, type: action.type }; diff --git a/packages/engine/src/actions/callMethod.js b/packages/engine/src/actions/callMethod.js new file mode 100644 index 000000000..e4c076f51 --- /dev/null +++ b/packages/engine/src/actions/callMethod.js @@ -0,0 +1,40 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { applyArrayIndices, type } from '@lowdefy/helpers'; + +const callMethod = ({ arrayIndices, context, params }) => { + const { blockId, method, args = [] } = params; + const blockMethod = + context._internal.RootBlocks.map[applyArrayIndices(arrayIndices, blockId)].methods[method]; + if (!type.isArray(args)) { + throw new Error( + `Failed to call method "${method}" on block "${blockId}": "args" should be an array. Received "${JSON.stringify( + params + )}".` + ); + } + if (!type.isFunction(blockMethod)) { + throw new Error( + `Failed to call method "${method}" on block "${blockId}". Check if "${method}" is a valid block method for block "${blockId}". Received "${JSON.stringify( + params + )}".` + ); + } + return blockMethod(...args); +}; + +export default callMethod; diff --git a/packages/engine/src/actions/getAction.js b/packages/engine/src/actions/getAction.js new file mode 100644 index 000000000..4e234f168 --- /dev/null +++ b/packages/engine/src/actions/getAction.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getAction = ({ arrayIndices, location, params, responses }) => { + return getFromObject({ + arrayIndices, + location, + object: responses, + method: 'getAction', + params, + }); +}; + +export default getAction; diff --git a/packages/engine/src/actions/getBlockId.js b/packages/engine/src/actions/getBlockId.js new file mode 100644 index 000000000..7134e57f3 --- /dev/null +++ b/packages/engine/src/actions/getBlockId.js @@ -0,0 +1,21 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const getBlockId = ({ blockId }) => { + return blockId; +}; + +export default getBlockId; diff --git a/packages/engine/src/actions/getEvent.js b/packages/engine/src/actions/getEvent.js new file mode 100644 index 000000000..3bbe5f992 --- /dev/null +++ b/packages/engine/src/actions/getEvent.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getEvent = ({ arrayIndices, event, location, params }) => { + return getFromObject({ + arrayIndices, + location, + object: event, + method: 'getEvent', + params, + }); +}; + +export default getEvent; diff --git a/packages/engine/src/actions/getFromObject.js b/packages/engine/src/actions/getFromObject.js new file mode 100644 index 000000000..be0515003 --- /dev/null +++ b/packages/engine/src/actions/getFromObject.js @@ -0,0 +1,44 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { applyArrayIndices, get, serializer, type } from '@lowdefy/helpers'; + +const getFromObject = ({ arrayIndices, location, method, object, params }) => { + if (params === true) params = { all: true }; + if (type.isString(params) || type.isInt(params)) params = { key: params }; + if (!type.isObject(params)) { + throw new Error( + `Method Error: ${method} params must be of type string, integer, boolean or object. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + if (params.key === null) return get(params, 'default', { default: null, copy: true }); + if (params.all === true) return serializer.copy(object); + if (!type.isString(params.key) && !type.isInt(params.key)) { + throw new Error( + `Method Error: ${method} params.key must be of type string or integer. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + return get(object, applyArrayIndices(arrayIndices, params.key), { + default: get(params, 'default', { default: null, copy: true }), + copy: true, + }); +}; + +export default getFromObject; diff --git a/packages/engine/src/actions/getGlobal.js b/packages/engine/src/actions/getGlobal.js new file mode 100644 index 000000000..8d71c7ddf --- /dev/null +++ b/packages/engine/src/actions/getGlobal.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getGlobal = ({ arrayIndices, lowdefyGlobal, location, params }) => { + return getFromObject({ + arrayIndices, + location, + object: lowdefyGlobal, + method: 'getGlobal', + params, + }); +}; + +export default getGlobal; diff --git a/packages/engine/src/actions/getInput.js b/packages/engine/src/actions/getInput.js new file mode 100644 index 000000000..ace69cb1b --- /dev/null +++ b/packages/engine/src/actions/getInput.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getInput = ({ arrayIndices, input, location, params }) => { + return getFromObject({ + arrayIndices, + location, + object: input, + method: 'getInput', + params, + }); +}; + +export default getInput; diff --git a/packages/engine/src/actions/getPageId.js b/packages/engine/src/actions/getPageId.js new file mode 100644 index 000000000..f607bc1c3 --- /dev/null +++ b/packages/engine/src/actions/getPageId.js @@ -0,0 +1,21 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const getPageId = ({ pageId }) => { + return pageId; +}; + +export default getPageId; diff --git a/packages/engine/src/actions/getRequest.js b/packages/engine/src/actions/getRequest.js new file mode 100644 index 000000000..bf0300929 --- /dev/null +++ b/packages/engine/src/actions/getRequest.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getRequest = ({ arrayIndices, location, params, requests }) => { + return getFromObject({ + arrayIndices, + location, + object: requests, + method: 'getRequest', + params, + }); +}; + +export default getRequest; diff --git a/packages/engine/src/actions/getState.js b/packages/engine/src/actions/getState.js new file mode 100644 index 000000000..f1ff9eaa8 --- /dev/null +++ b/packages/engine/src/actions/getState.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getState = ({ arrayIndices, location, params, state }) => { + return getFromObject({ + arrayIndices, + location, + object: state, + method: 'getState', + params, + }); +}; + +export default getState; diff --git a/packages/engine/src/actions/getUrlQuery.js b/packages/engine/src/actions/getUrlQuery.js new file mode 100644 index 000000000..902d9b85d --- /dev/null +++ b/packages/engine/src/actions/getUrlQuery.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getUrlQuery = ({ arrayIndices, location, params, urlQuery }) => { + return getFromObject({ + arrayIndices, + location, + object: urlQuery, + method: 'getUrlQuery', + params, + }); +}; + +export default getUrlQuery; diff --git a/packages/engine/src/actions/getUser.js b/packages/engine/src/actions/getUser.js new file mode 100644 index 000000000..9de28e88e --- /dev/null +++ b/packages/engine/src/actions/getUser.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getFromObject from './getFromObject.js'; + +const getUser = ({ arrayIndices, location, params, user }) => { + return getFromObject({ + arrayIndices, + location, + object: user, + method: 'getUser', + params, + }); +}; + +export default getUser; diff --git a/packages/engine/src/actions/index.js b/packages/engine/src/actions/index.js new file mode 100644 index 000000000..387c942ff --- /dev/null +++ b/packages/engine/src/actions/index.js @@ -0,0 +1,135 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { default as callMethod } from './callMethod.js'; +import { default as getAction } from './getAction.js'; +import { default as getBlockId } from './getBlockId.js'; +import { default as getEvent } from './getEvent.js'; +import { default as getGlobal } from './getGlobal.js'; +import { default as getInput } from './getInput.js'; +import { default as getPageId } from './getPageId.js'; +import { default as getRequest } from './getRequest.js'; +import { default as getState } from './getState.js'; +import { default as getUrlQuery } from './getUrlQuery.js'; +import { default as getUser } from './getUser.js'; +import { default as link } from './link.js'; +import { default as login } from './login.js'; +import { default as logout } from './logout.js'; +import { default as message } from './message.js'; +import { default as request } from './request.js'; +import { default as reset } from './reset.js'; +import { default as resetValidation } from './resetValidation.js'; +import { default as scrollTo } from './scrollTo.js'; +import { default as setGlobal } from './setGlobal.js'; +import { default as setState } from './setState.js'; +import { default as validate } from './validate.js'; + +export const getMethods = ({ actions, arrayIndices, blockId, context, event }) => { + return { + callMethod: (params) => callMethod({ arrayIndices, context, params }), + getAction: (params) => getAction({ arrayIndices, location: blockId, params, responses }), + getBlockId: () => getBlockId({ blockId }), + getEvent: (params) => getEvent({ event, params }), + getGlobal: (params) => + getGlobal({ + arrayIndices, + lowdefyGlobal: context._internal.lowdefy.lowdefyGlobal || {}, + location: blockId, + params, + }), + getInput: (params) => + getInput({ + arrayIndices, + input: context._internal.lowdefy.inputs ? context._internal.lowdefy.inputs[context.id] : {}, + location: blockId, + params, + }), + getPageId: () => getPageId({ pageId: context.pageId }), + getRequest: (params) => + getRequest({ + arrayIndices, + requests: context.requests, + location: blockId, + params, + }), + getState: (params) => + getState({ + arrayIndices, + state: context.state, + location: blockId, + params, + }), + getUrlQuery: (params) => + getUrlQuery({ + arrayIndices, + urlQuery: context._internal.lowdefy.urlQuery || {}, + location: blockId, + params, + }), + getUser: (params) => + getUser({ + arrayIndices, + user: context._internal.lowdefy.user || {}, + location: blockId, + params, + }), + link: (params) => link({ context, params }), + login: (params) => login({ context, params }), + logout: () => logout({ context }), + message: (params) => message({ context, params }), + request: (params) => + request({ + actions, + arrayIndices, + context, + event, + params, + }), + reset: () => reset({ context }), + resetValidation: (params) => resetValidation({ context, params }), + scrollTo: (params) => { + scrollTo({ context, params }); + }, + setGlobal: (params) => setGlobal({ arrayIndices, context, params }), + setState: (params) => setState({ arrayIndices, context, params }), + validate: (params) => validate({ context, params }), + }; +}; + +export default { + callMethod, + getAction, + getBlockId, + getEvent, + getGlobal, + getInput, + getPageId, + getRequest, + getState, + getUrlQuery, + getUser, + link, + login, + logout, + message, + request, + reset, + resetValidation, + scrollTo, + setGlobal, + setState, + validate, +}; diff --git a/packages/engine/src/actions/link.js b/packages/engine/src/actions/link.js new file mode 100644 index 000000000..50f969788 --- /dev/null +++ b/packages/engine/src/actions/link.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { type } from '@lowdefy/helpers'; + +const link = ({ context, params }) => { + const linkParams = type.isString(params) ? { pageId: params } : params; + try { + context._internal.lowdefy._internal.link(linkParams); + } catch (error) { + console.log(error); + throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); + } +}; + +export default link; diff --git a/packages/engine/src/actions/login.js b/packages/engine/src/actions/login.js new file mode 100644 index 000000000..ae660973a --- /dev/null +++ b/packages/engine/src/actions/login.js @@ -0,0 +1,21 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const login = ({ context, params }) => { + return context._internal.lowdefy._internal.auth.login(params); +}; + +export default login; diff --git a/packages/engine/src/actions/logout.js b/packages/engine/src/actions/logout.js new file mode 100644 index 000000000..0665b5545 --- /dev/null +++ b/packages/engine/src/actions/logout.js @@ -0,0 +1,21 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const logout = ({ context }) => { + return context._internal.lowdefy._internal.auth.logout(); +}; + +export default logout; diff --git a/packages/engine/src/actions/message.js b/packages/engine/src/actions/message.js new file mode 100644 index 000000000..c2f5d3768 --- /dev/null +++ b/packages/engine/src/actions/message.js @@ -0,0 +1,26 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const message = ({ context, params = {} }) => { + context._internal.lowdefy._internal.displayMessage({ + content: params.content || 'Success', + duration: params.duration, + icon: params.icon, + status: params.status, + }); +}; + +export default message; diff --git a/packages/engine/src/actions/request.js b/packages/engine/src/actions/request.js new file mode 100644 index 000000000..ea9b0ab71 --- /dev/null +++ b/packages/engine/src/actions/request.js @@ -0,0 +1,21 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const request = ({ actions, arrayIndices, context, event, params }) => { + return context._internal.Requests.callRequests({ actions, arrayIndices, event, params }); +}; + +export default request; diff --git a/packages/engine/src/actions/reset.js b/packages/engine/src/actions/reset.js new file mode 100644 index 000000000..7ba155153 --- /dev/null +++ b/packages/engine/src/actions/reset.js @@ -0,0 +1,27 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { serializer } from '@lowdefy/helpers'; + +const reset = ({ context }) => { + context._internal.State.resetState(); + context._internal.RootBlocks.reset( + serializer.deserializeFromString(context._internal.State.frozenState) + ); + context._internal.update(); +}; + +export default reset; diff --git a/packages/engine/src/actions/resetValidation.js b/packages/engine/src/actions/resetValidation.js new file mode 100644 index 000000000..4604f819d --- /dev/null +++ b/packages/engine/src/actions/resetValidation.js @@ -0,0 +1,23 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getBlockMatcher from '../getBlockMatcher.js'; + +const resetValidation = ({ context, params }) => { + context._internal.RootBlocks.resetValidation(getBlockMatcher(params)); +}; + +export default resetValidation; diff --git a/packages/engine/src/actions/scrollTo.js b/packages/engine/src/actions/scrollTo.js new file mode 100644 index 000000000..02f606987 --- /dev/null +++ b/packages/engine/src/actions/scrollTo.js @@ -0,0 +1,28 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +const scrollTo = ({ context, params = {} }) => { + if (params.blockId) { + const element = context._internal.lowdefy._internal.document.getElementById(params.blockId); + if (element) { + element.scrollIntoView(params.options); + } + } else { + context._internal.lowdefy._internal.window.scrollTo(params); + } +}; + +export default scrollTo; diff --git a/packages/engine/src/actions/setGlobal.js b/packages/engine/src/actions/setGlobal.js new file mode 100644 index 000000000..68481f3c4 --- /dev/null +++ b/packages/engine/src/actions/setGlobal.js @@ -0,0 +1,27 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { applyArrayIndices, set } from '@lowdefy/helpers'; + +const setGlobal = ({ arrayIndices, context, params }) => { + Object.keys(params).forEach((key) => { + set(context._internal.lowdefy.lowdefyGlobal, applyArrayIndices(arrayIndices, key), params[key]); + }); + context._internal.RootBlocks.reset(); + context._internal.update(); +}; + +export default setGlobal; diff --git a/packages/engine/src/actions/setState.js b/packages/engine/src/actions/setState.js new file mode 100644 index 000000000..de029770e --- /dev/null +++ b/packages/engine/src/actions/setState.js @@ -0,0 +1,27 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { applyArrayIndices } from '@lowdefy/helpers'; + +const setState = ({ arrayIndices, context, params }) => { + Object.keys(params).forEach((key) => { + context._internal.State.set(applyArrayIndices(arrayIndices, key), params[key]); + }); + context._internal.RootBlocks.reset(); + context._internal.update(); +}; + +export default setState; diff --git a/packages/engine/src/actions/validate.js b/packages/engine/src/actions/validate.js new file mode 100644 index 000000000..ca3267e46 --- /dev/null +++ b/packages/engine/src/actions/validate.js @@ -0,0 +1,31 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import getBlockMatcher from '../getBlockMatcher.js'; + +const validate = ({ context, params }) => { + const validationErrors = context.RootBlocks.validate(getBlockMatcher(params)); + if (validationErrors.length > 0) { + const error = new Error( + `Your input has ${validationErrors.length} validation error${ + validationErrors.length !== 1 ? 's' : '' + }.` + ); + throw error; + } +}; + +export default validate; From bc79114c4bdab446e160a6867cdf4c2f121ea5b6 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 14:55:01 +0200 Subject: [PATCH 09/79] chore(actions-core): Refactor action function declarations. --- .../actions/actions-core/src/actions.js | 45 ++++++------------- .../actions-core/src/actions/CallMethod.js | 4 +- .../actions/actions-core/src/actions/Link.js | 4 +- .../actions/actions-core/src/actions/Login.js | 4 +- .../actions-core/src/actions/Logout.js | 4 +- .../actions-core/src/actions/Message.js | 4 +- .../actions-core/src/actions/Request.js | 6 +-- .../actions/actions-core/src/actions/Reset.js | 4 +- .../src/actions/ResetValidation.js | 4 +- .../actions-core/src/actions/ScrollTo.js | 4 +- .../actions-core/src/actions/SetGlobal.js | 4 +- .../actions-core/src/actions/SetState.js | 4 +- .../actions/actions-core/src/actions/Throw.js | 4 +- .../actions-core/src/actions/Validate.js | 4 +- .../actions/actions-core/src/actions/Wait.js | 4 +- 15 files changed, 43 insertions(+), 60 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions.js b/packages/plugins/actions/actions-core/src/actions.js index 9a5b91c82..faf9a5cb3 100644 --- a/packages/plugins/actions/actions-core/src/actions.js +++ b/packages/plugins/actions/actions-core/src/actions.js @@ -14,34 +14,17 @@ limitations under the License. */ -import { default as CallMethod } from './actions/CallMethod.js'; -import { default as Link } from './actions/Link.js'; -import { default as Login } from './actions/Login.js'; -import { default as Logout } from './actions/Logout.js'; -import { default as Message } from './actions/Message.js'; -import { default as Request } from './actions/Request.js'; -import { default as Reset } from './actions/Reset.js'; -import { default as ResetValidation } from './actions/ResetValidation.js'; -import { default as ScrollTo } from './actions/ScrollTo.js'; -import { default as SetGlobal } from './actions/SetGlobal.js'; -import { default as SetState } from './actions/SetState.js'; -import { default as Throw } from './actions/Throw.js'; -import { default as Validate } from './actions/Validate.js'; -import { default as Wait } from './actions/Wait.js'; - -export default { - CallMethod, - Link, - Login, - Logout, - Message, - Request, - Reset, - ResetValidation, - ScrollTo, - SetGlobal, - SetState, - Throw, - Validate, - Wait, -}; +export { default as CallMethod } from './actions/CallMethod.js'; +export { default as Link } from './actions/Link.js'; +export { default as Login } from './actions/Login.js'; +export { default as Logout } from './actions/Logout.js'; +export { default as Message } from './actions/Message.js'; +export { default as Request } from './actions/Request.js'; +export { default as Reset } from './actions/Reset.js'; +export { default as ResetValidation } from './actions/ResetValidation.js'; +export { default as ScrollTo } from './actions/ScrollTo.js'; +export { default as SetGlobal } from './actions/SetGlobal.js'; +export { default as SetState } from './actions/SetState.js'; +export { default as Throw } from './actions/Throw.js'; +export { default as Validate } from './actions/Validate.js'; +export { default as Wait } from './actions/Wait.js'; diff --git a/packages/plugins/actions/actions-core/src/actions/CallMethod.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.js index c2de291b8..b8500020b 100644 --- a/packages/plugins/actions/actions-core/src/actions/CallMethod.js +++ b/packages/plugins/actions/actions-core/src/actions/CallMethod.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function CallMethod({ methods: { callMethod }, params }) { +const CallMethod = ({ methods: { callMethod }, params }) => { return callMethod(params); -} +}; export default CallMethod; diff --git a/packages/plugins/actions/actions-core/src/actions/Link.js b/packages/plugins/actions/actions-core/src/actions/Link.js index 30f0c4f3f..1a587c43b 100644 --- a/packages/plugins/actions/actions-core/src/actions/Link.js +++ b/packages/plugins/actions/actions-core/src/actions/Link.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Link({ methods: { link }, params }) { +const Link = ({ methods: { link }, params }) => { link(params); -} +}; export default Link; diff --git a/packages/plugins/actions/actions-core/src/actions/Login.js b/packages/plugins/actions/actions-core/src/actions/Login.js index 0400a2a2f..54004a608 100644 --- a/packages/plugins/actions/actions-core/src/actions/Login.js +++ b/packages/plugins/actions/actions-core/src/actions/Login.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Login({ methods: { login }, params }) { +const Login = ({ methods: { login }, params }) => { return login(params); -} +}; export default Login; diff --git a/packages/plugins/actions/actions-core/src/actions/Logout.js b/packages/plugins/actions/actions-core/src/actions/Logout.js index f7cec6d31..9199cc709 100644 --- a/packages/plugins/actions/actions-core/src/actions/Logout.js +++ b/packages/plugins/actions/actions-core/src/actions/Logout.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Logout({ methods: { logout } }) { +const Logout = ({ methods: { logout } }) => { return logout(); -} +}; export default Logout; diff --git a/packages/plugins/actions/actions-core/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js index 0e3ec319e..95f3012da 100644 --- a/packages/plugins/actions/actions-core/src/actions/Message.js +++ b/packages/plugins/actions/actions-core/src/actions/Message.js @@ -14,8 +14,8 @@ limitations under the License. */ -function Message({ methods: { message }, params }) { +const Message = ({ methods: { message }, params }) => { message(params); -} +}; export default Message; diff --git a/packages/plugins/actions/actions-core/src/actions/Request.js b/packages/plugins/actions/actions-core/src/actions/Request.js index 735272e8c..842c786d6 100644 --- a/packages/plugins/actions/actions-core/src/actions/Request.js +++ b/packages/plugins/actions/actions-core/src/actions/Request.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Request({ methods: { request }, params }) { - return request(params); -} +const Request = async ({ methods: { request }, params }) => { + return await request(params); +}; export default Request; diff --git a/packages/plugins/actions/actions-core/src/actions/Reset.js b/packages/plugins/actions/actions-core/src/actions/Reset.js index ffb020981..efac40d8f 100644 --- a/packages/plugins/actions/actions-core/src/actions/Reset.js +++ b/packages/plugins/actions/actions-core/src/actions/Reset.js @@ -14,8 +14,8 @@ limitations under the License. */ -function Reset({ methods: { reset } }) { +const Reset = ({ methods: { reset } }) => { reset(); -} +}; export default Reset; diff --git a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js index f88e96c92..211095f2f 100644 --- a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js +++ b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function ResetValidation({ methods: { resetValidation }, params }) { +const ResetValidation = ({ methods: { resetValidation }, params }) => { resetValidation(params); -} +}; export default ResetValidation; diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index 84412c127..00930be03 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function ScrollTo({ methods: { scrollTo }, params }) { +const ScrollTo = ({ methods: { scrollTo }, params }) => { scrollTo(params); -} +}; export default ScrollTo; diff --git a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js index ec81115ba..96b46fff8 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js +++ b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function SetGlobal({ methods: { setGlobal }, params }) { +const SetGlobal = ({ methods: { setGlobal }, params }) => { setGlobal(params); -} +}; export default SetGlobal; diff --git a/packages/plugins/actions/actions-core/src/actions/SetState.js b/packages/plugins/actions/actions-core/src/actions/SetState.js index fe51ea77f..aec25e260 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetState.js +++ b/packages/plugins/actions/actions-core/src/actions/SetState.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function SetState({ methods: { setState }, params }) { +const SetState = ({ methods: { setState }, params }) => { setState(params); -} +}; export default SetState; diff --git a/packages/plugins/actions/actions-core/src/actions/Throw.js b/packages/plugins/actions/actions-core/src/actions/Throw.js index c479118a7..bfc4fde75 100644 --- a/packages/plugins/actions/actions-core/src/actions/Throw.js +++ b/packages/plugins/actions/actions-core/src/actions/Throw.js @@ -26,7 +26,7 @@ class ThrowActionError extends Error { } } -function Throw({ methods: { getBlockId, getPageId }, params }) { +const Throw = ({ methods: { getBlockId, getPageId }, params }) => { if (params.throw === false || type.isNone(params.throw)) { return; } @@ -38,7 +38,7 @@ function Throw({ methods: { getBlockId, getPageId }, params }) { }); } throw new Error(`Invalid Throw, check action params. Received "${JSON.stringify(params)}".`); -} +}; export default Throw; export { Throw, ThrowActionError }; diff --git a/packages/plugins/actions/actions-core/src/actions/Validate.js b/packages/plugins/actions/actions-core/src/actions/Validate.js index 0548f6d92..98bd595f0 100644 --- a/packages/plugins/actions/actions-core/src/actions/Validate.js +++ b/packages/plugins/actions/actions-core/src/actions/Validate.js @@ -14,8 +14,8 @@ limitations under the License. */ -async function Validate({ methods: { validate }, params }) { +const Validate = ({ methods: { validate }, params }) => { return validate(params); -} +}; export default Validate; diff --git a/packages/plugins/actions/actions-core/src/actions/Wait.js b/packages/plugins/actions/actions-core/src/actions/Wait.js index a835c4f28..513f4e6ef 100644 --- a/packages/plugins/actions/actions-core/src/actions/Wait.js +++ b/packages/plugins/actions/actions-core/src/actions/Wait.js @@ -16,11 +16,11 @@ import { type, wait } from '@lowdefy/helpers'; -async function Wait({ params }) { +const Wait = ({ params }) => { if (!type.isInt(params.ms)) { throw new Error(`Wait action "ms" param should be an integer.`); } return wait(params.ms); -} +}; export default Wait; From f405a5d0829a2fcffb768b70512fa31a6f037a26 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 14:56:54 +0200 Subject: [PATCH 10/79] chore(engine): Refactor getMethod function declaration. --- packages/engine/src/actions/index.js | 2 +- packages/engine/src/actions/request.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/engine/src/actions/index.js b/packages/engine/src/actions/index.js index 387c942ff..62ecb7524 100644 --- a/packages/engine/src/actions/index.js +++ b/packages/engine/src/actions/index.js @@ -37,7 +37,7 @@ import { default as setGlobal } from './setGlobal.js'; import { default as setState } from './setState.js'; import { default as validate } from './validate.js'; -export const getMethods = ({ actions, arrayIndices, blockId, context, event }) => { +export const getMethods = ({ actions, arrayIndices, blockId, context, event, responses }) => { return { callMethod: (params) => callMethod({ arrayIndices, context, params }), getAction: (params) => getAction({ arrayIndices, location: blockId, params, responses }), diff --git a/packages/engine/src/actions/request.js b/packages/engine/src/actions/request.js index ea9b0ab71..c1f7ee392 100644 --- a/packages/engine/src/actions/request.js +++ b/packages/engine/src/actions/request.js @@ -14,8 +14,8 @@ limitations under the License. */ -const request = ({ actions, arrayIndices, context, event, params }) => { - return context._internal.Requests.callRequests({ actions, arrayIndices, event, params }); +const request = async ({ actions, arrayIndices, context, event, params }) => { + return await context._internal.Requests.callRequests({ actions, arrayIndices, event, params }); }; export default request; From a144735e2cf7647db5e48b434a53c974d907b4f9 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 14:58:39 +0200 Subject: [PATCH 11/79] feat(build): Added @lowdefy/actions-core plugin to build process. --- .pnp.cjs | 23 +++++++++++++++ packages/build/package.json | 1 + packages/build/src/build/buildTypes.js | 12 ++++---- .../writePluginImports/writeActionImports.js | 29 +++++++++++++++++++ packages/build/src/index.js | 2 ++ .../build/src/scripts/generateDefaultTypes.js | 1 + yarn.lock | 16 ++++++++++ 7 files changed, 78 insertions(+), 6 deletions(-) create mode 100644 packages/build/src/build/writePluginImports/writeActionImports.js diff --git a/.pnp.cjs b/.pnp.cjs index 22a5f5b1f..9fce54d5d 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -54,6 +54,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "name": "@lowdefy/operators", "reference": "workspace:packages/operators" }, + { + "name": "@lowdefy/actions-core", + "reference": "workspace:packages/plugins/actions/actions-core" + }, { "name": "@lowdefy/blocks-antd", "reference": "workspace:packages/plugins/blocks/blocks-antd" @@ -178,6 +182,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "enableTopLevelFallback": true, "ignorePatternData": "(^(?:\\.yarn\\/sdks(?:\\/(?!\\.{1,2}(?:\\/|$))(?:(?:(?!(?:^|\\/)\\.{1,2}(?:\\/|$)).)*?)|$))$)", "fallbackExclusionList": [ + ["@lowdefy/actions-core", ["workspace:packages/plugins/actions/actions-core"]], ["@lowdefy/ajv", ["workspace:packages/utils/ajv"]], ["@lowdefy/api", ["workspace:packages/api"]], ["@lowdefy/block-dev", ["workspace:packages/utils/block-dev"]], @@ -2782,6 +2787,20 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "linkType": "HARD", }] ]], + ["@lowdefy/actions-core", [ + ["workspace:packages/plugins/actions/actions-core", { + "packageLocation": "./packages/plugins/actions/actions-core/", + "packageDependencies": [ + ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], + ["@lowdefy/helpers", "workspace:packages/utils/helpers"], + ["@swc/cli", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.1.55"], + ["@swc/core", "npm:1.2.135"], + ["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"], + ["jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:27.4.7"] + ], + "linkType": "SOFT", + }] + ]], ["@lowdefy/ajv", [ ["workspace:packages/utils/ajv", { "packageLocation": "./packages/utils/ajv/", @@ -3035,6 +3054,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/build/", "packageDependencies": [ ["@lowdefy/build", "workspace:packages/build"], + ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@lowdefy/ajv", "workspace:packages/utils/ajv"], ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], ["@lowdefy/blocks-basic", "workspace:packages/plugins/blocks/blocks-basic"], @@ -3486,8 +3506,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/server/", "packageDependencies": [ ["@lowdefy/server", "workspace:packages/server"], + ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@lowdefy/api", "workspace:packages/api"], ["@lowdefy/block-utils", "workspace:packages/utils/block-utils"], + ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], ["@lowdefy/build", "workspace:packages/build"], ["@lowdefy/engine", "workspace:packages/engine"], ["@lowdefy/helpers", "workspace:packages/utils/helpers"], @@ -3513,6 +3535,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/server-dev/", "packageDependencies": [ ["@lowdefy/server-dev", "workspace:packages/server-dev"], + ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@lowdefy/api", "workspace:packages/api"], ["@lowdefy/block-utils", "workspace:packages/utils/block-utils"], ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], diff --git a/packages/build/package.json b/packages/build/package.json index 8740696a8..88d976df2 100644 --- a/packages/build/package.json +++ b/packages/build/package.json @@ -56,6 +56,7 @@ "yargs": "17.3.1" }, "devDependencies": { + "@lowdefy/actions-core": "4.0.0-alpha.6", "@lowdefy/blocks-antd": "4.0.0-alpha.6", "@lowdefy/blocks-basic": "4.0.0-alpha.6", "@lowdefy/blocks-color-selectors": "4.0.0-alpha.6", diff --git a/packages/build/src/build/buildTypes.js b/packages/build/src/build/buildTypes.js index bd3443e8a..53a37c8d3 100644 --- a/packages/build/src/build/buildTypes.js +++ b/packages/build/src/build/buildTypes.js @@ -53,12 +53,12 @@ function buildTypes({ components, context }) { }, }; - // buildTypeClass({ - // counter: typeCounters.actions, - // definitions: context.types.actions, - // store: components.types.actions, - // typeClass: 'Action', - // }); + buildTypeClass(context, { + counter: typeCounters.actions, + definitions: context.types.actions, + store: components.types.actions, + typeClass: 'Action', + }); buildTypeClass(context, { counter: typeCounters.blocks, diff --git a/packages/build/src/build/writePluginImports/writeActionImports.js b/packages/build/src/build/writePluginImports/writeActionImports.js new file mode 100644 index 000000000..cc825530e --- /dev/null +++ b/packages/build/src/build/writePluginImports/writeActionImports.js @@ -0,0 +1,29 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import generateImportFile from './generateImportFile.js'; + +async function writeActionImports({ components, context }) { + await context.writeBuildArtifact( + 'plugins/actions.js', + generateImportFile({ + types: components.types.actions, + importPath: 'actions', + }) + ); +} + +export default writeActionImports; diff --git a/packages/build/src/index.js b/packages/build/src/index.js index 3c8e7832f..aed70be7a 100644 --- a/packages/build/src/index.js +++ b/packages/build/src/index.js @@ -38,6 +38,7 @@ import validateApp from './build/validateApp.js'; import validateConfig from './build/validateConfig.js'; import updateServerPackageJson from './build/updateServerPackageJson.js'; import writeApp from './build/writeApp.js'; +import writeActionImports from './build/writePluginImports/writeActionImports.js'; import writeBlockImports from './build/writePluginImports/writeBlockImports.js'; import writeConfig from './build/writeConfig.js'; import writeConnectionImports from './build/writePluginImports/writeConnectionImports.js'; @@ -105,6 +106,7 @@ async function build(options) { await writeGlobal({ components, context }); await writeMenus({ components, context }); await writeTypes({ components, context }); + await writeActionImports({ components, context }); await writeBlockImports({ components, context }); await writeConnectionImports({ components, context }); await writeOperatorImports({ components, context }); diff --git a/packages/build/src/scripts/generateDefaultTypes.js b/packages/build/src/scripts/generateDefaultTypes.js index 31d5aafdb..5d3deeb54 100644 --- a/packages/build/src/scripts/generateDefaultTypes.js +++ b/packages/build/src/scripts/generateDefaultTypes.js @@ -20,6 +20,7 @@ import { type } from '@lowdefy/helpers'; import { readFile, writeFile } from '@lowdefy/node-utils'; const defaultPackages = [ + '@lowdefy/actions-core', '@lowdefy/blocks-antd', '@lowdefy/blocks-basic', // '@lowdefy/blocks-color-selectors', diff --git a/yarn.lock b/yarn.lock index 36df58a5a..99a56e298 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1952,6 +1952,18 @@ __metadata: languageName: node linkType: hard +"@lowdefy/actions-core@4.0.0-alpha.6, @lowdefy/actions-core@workspace:packages/plugins/actions/actions-core": + version: 0.0.0-use.local + resolution: "@lowdefy/actions-core@workspace:packages/plugins/actions/actions-core" + dependencies: + "@lowdefy/helpers": 4.0.0-alpha.6 + "@swc/cli": 0.1.55 + "@swc/core": 1.2.135 + "@swc/jest": 0.2.17 + jest: 27.4.7 + languageName: unknown + linkType: soft + "@lowdefy/ajv@4.0.0-alpha.6, @lowdefy/ajv@workspace:packages/utils/ajv": version: 0.0.0-use.local resolution: "@lowdefy/ajv@workspace:packages/utils/ajv" @@ -2184,6 +2196,7 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/build@workspace:packages/build" dependencies: + "@lowdefy/actions-core": 4.0.0-alpha.6 "@lowdefy/ajv": 4.0.0-alpha.6 "@lowdefy/blocks-antd": 4.0.0-alpha.6 "@lowdefy/blocks-basic": 4.0.0-alpha.6 @@ -2585,6 +2598,7 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/server-dev@workspace:packages/server-dev" dependencies: + "@lowdefy/actions-core": 4.0.0-alpha.6 "@lowdefy/api": 4.0.0-alpha.6 "@lowdefy/block-utils": 4.0.0-alpha.6 "@lowdefy/blocks-antd": 4.0.0-alpha.6 @@ -2628,8 +2642,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/server@workspace:packages/server" dependencies: + "@lowdefy/actions-core": 4.0.0-alpha.6 "@lowdefy/api": 4.0.0-alpha.6 "@lowdefy/block-utils": 4.0.0-alpha.6 + "@lowdefy/blocks-antd": 4.0.0-alpha.6 "@lowdefy/build": 4.0.0-alpha.6 "@lowdefy/engine": 4.0.0-alpha.6 "@lowdefy/helpers": 4.0.0-alpha.6 From d00d39cd420ff9f36db0391362e8dae5efa85867 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 16:56:23 +0200 Subject: [PATCH 12/79] chore(actions-core): Refactored ScrollTo action. --- .../actions/actions-core/src/actions/ScrollTo.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index 00930be03..48b3631d6 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -14,8 +14,15 @@ limitations under the License. */ -const ScrollTo = ({ methods: { scrollTo }, params }) => { - scrollTo(params); +const ScrollTo = ({ document, params, window }) => { + if (params.blockId) { + const element = document.getElementById(params.blockId); + if (element) { + element.scrollIntoView(params.options); + } + } else { + window.scrollTo(params); + } }; export default ScrollTo; From a6468510508da2e3e733b508418bb432b48e804c Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 8 Feb 2022 16:56:47 +0200 Subject: [PATCH 13/79] chore(engine): Refactored action methods. --- packages/engine/src/Actions.js | 7 +- packages/engine/src/actions/callMethod.js | 44 +++--- packages/engine/src/actions/getAction.js | 22 +-- .../engine/src/actions/getActionMethods.js | 65 +++++++++ packages/engine/src/actions/getBlockId.js | 10 +- packages/engine/src/actions/getEvent.js | 22 +-- packages/engine/src/actions/getGlobal.js | 22 +-- packages/engine/src/actions/getInput.js | 22 +-- packages/engine/src/actions/getPageId.js | 10 +- packages/engine/src/actions/getRequest.js | 20 +-- packages/engine/src/actions/getState.js | 22 +-- packages/engine/src/actions/getUrlQuery.js | 22 +-- packages/engine/src/actions/getUser.js | 22 +-- packages/engine/src/actions/index.js | 135 ------------------ packages/engine/src/actions/link.js | 22 +-- packages/engine/src/actions/login.js | 10 +- packages/engine/src/actions/logout.js | 10 +- packages/engine/src/actions/message.js | 20 +-- packages/engine/src/actions/request.js | 10 +- packages/engine/src/actions/reset.js | 18 +-- .../engine/src/actions/resetValidation.js | 10 +- packages/engine/src/actions/scrollTo.js | 28 ---- packages/engine/src/actions/setGlobal.js | 20 ++- packages/engine/src/actions/setState.js | 18 +-- packages/engine/src/actions/validate.js | 26 ++-- 25 files changed, 292 insertions(+), 345 deletions(-) create mode 100644 packages/engine/src/actions/getActionMethods.js delete mode 100644 packages/engine/src/actions/index.js delete mode 100644 packages/engine/src/actions/scrollTo.js diff --git a/packages/engine/src/Actions.js b/packages/engine/src/Actions.js index 34e657518..8c9a5c141 100644 --- a/packages/engine/src/Actions.js +++ b/packages/engine/src/Actions.js @@ -15,7 +15,7 @@ */ import { type } from '@lowdefy/helpers'; -import { getMethods } from './actions/index.js'; +import getActionMethods from './actions/getActionMethods.js'; class Actions { constructor(context) { @@ -156,13 +156,12 @@ class Actions { }); try { response = await this.actions[action.type]({ - methods: getMethods({ - actions: this.actions, + methods: getActionMethods({ + actions: responses, arrayIndices, blockId: block.blockId, context: this.context, event, - responses, }), document: this.context._internal.lowdefy._internal.document, params: parsedAction.params, diff --git a/packages/engine/src/actions/callMethod.js b/packages/engine/src/actions/callMethod.js index e4c076f51..bb4a63d3a 100644 --- a/packages/engine/src/actions/callMethod.js +++ b/packages/engine/src/actions/callMethod.js @@ -16,25 +16,27 @@ import { applyArrayIndices, type } from '@lowdefy/helpers'; -const callMethod = ({ arrayIndices, context, params }) => { - const { blockId, method, args = [] } = params; - const blockMethod = - context._internal.RootBlocks.map[applyArrayIndices(arrayIndices, blockId)].methods[method]; - if (!type.isArray(args)) { - throw new Error( - `Failed to call method "${method}" on block "${blockId}": "args" should be an array. Received "${JSON.stringify( - params - )}".` - ); - } - if (!type.isFunction(blockMethod)) { - throw new Error( - `Failed to call method "${method}" on block "${blockId}". Check if "${method}" is a valid block method for block "${blockId}". Received "${JSON.stringify( - params - )}".` - ); - } - return blockMethod(...args); -}; +function createCallMethod({ arrayIndices, context }) { + return function callMethod(params) { + const { blockId, method, args = [] } = params; + const blockMethod = + context._internal.RootBlocks.map[applyArrayIndices(arrayIndices, blockId)].methods[method]; + if (!type.isArray(args)) { + throw new Error( + `Failed to call method "${method}" on block "${blockId}": "args" should be an array. Received "${JSON.stringify( + params + )}".` + ); + } + if (!type.isFunction(blockMethod)) { + throw new Error( + `Failed to call method "${method}" on block "${blockId}". Check if "${method}" is a valid block method for block "${blockId}". Received "${JSON.stringify( + params + )}".` + ); + } + return blockMethod(...args); + }; +} -export default callMethod; +export default createCallMethod; diff --git a/packages/engine/src/actions/getAction.js b/packages/engine/src/actions/getAction.js index 4e234f168..572934317 100644 --- a/packages/engine/src/actions/getAction.js +++ b/packages/engine/src/actions/getAction.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getAction = ({ arrayIndices, location, params, responses }) => { - return getFromObject({ - arrayIndices, - location, - object: responses, - method: 'getAction', - params, - }); -}; +function createGetAction({ actions, arrayIndices, blockId }) { + return function getAction(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: actions, + method: 'getAction', + params, + }); + }; +} -export default getAction; +export default createGetAction; diff --git a/packages/engine/src/actions/getActionMethods.js b/packages/engine/src/actions/getActionMethods.js new file mode 100644 index 000000000..856ffd00c --- /dev/null +++ b/packages/engine/src/actions/getActionMethods.js @@ -0,0 +1,65 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import createCallMethod from './callMethod.js'; +import createGetAction from './getAction.js'; +import createGetBlockId from './getBlockId.js'; +import createGetEvent from './getEvent.js'; +import createGetGlobal from './getGlobal.js'; +import createGetInput from './getInput.js'; +import createGetPageId from './getPageId.js'; +import createGetRequest from './getRequest.js'; +import createGetState from './getState.js'; +import createGetUrlQuery from './getUrlQuery.js'; +import createGetUser from './getUser.js'; +import createLink from './link.js'; +import createLogin from './login.js'; +import createLogout from './logout.js'; +import createMessage from './message.js'; +import createRequest from './request.js'; +import createReset from './reset.js'; +import createResetValidation from './resetValidation.js'; +import createSetGlobal from './setGlobal.js'; +import createSetState from './setState.js'; +import createValidate from './validate.js'; + +function getActionMethods(props) { + return { + callMethod: createCallMethod(props), + getAction: createGetAction(props), + getBlockId: createGetBlockId(props), + getEvent: createGetEvent(props), + getGlobal: createGetGlobal(props), + getInput: createGetInput(props), + getPageId: createGetPageId(props), + getRequest: createGetRequest(props), + getState: createGetState(props), + getUrlQuery: createGetUrlQuery(props), + getUser: createGetUser(props), + link: createLink(props), + login: createLogin(props), + logout: createLogout(props), + message: createMessage(props), + request: createRequest(props), + reset: createReset(props), + resetValidation: createResetValidation(props), + setGlobal: createSetGlobal(props), + setState: createSetState(props), + validate: createValidate(props), + }; +} + +export default getActionMethods; diff --git a/packages/engine/src/actions/getBlockId.js b/packages/engine/src/actions/getBlockId.js index 7134e57f3..1168f3bcc 100644 --- a/packages/engine/src/actions/getBlockId.js +++ b/packages/engine/src/actions/getBlockId.js @@ -14,8 +14,10 @@ limitations under the License. */ -const getBlockId = ({ blockId }) => { - return blockId; -}; +function createGetBlockId({ blockId }) { + return function getBlockId() { + return blockId; + }; +} -export default getBlockId; +export default createGetBlockId; diff --git a/packages/engine/src/actions/getEvent.js b/packages/engine/src/actions/getEvent.js index 3bbe5f992..51214f7f2 100644 --- a/packages/engine/src/actions/getEvent.js +++ b/packages/engine/src/actions/getEvent.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getEvent = ({ arrayIndices, event, location, params }) => { - return getFromObject({ - arrayIndices, - location, - object: event, - method: 'getEvent', - params, - }); -}; +function createGetEvent({ arrayIndices, blockId, event }) { + return function getEvent(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: event, + method: 'getEvent', + params, + }); + }; +} -export default getEvent; +export default createGetEvent; diff --git a/packages/engine/src/actions/getGlobal.js b/packages/engine/src/actions/getGlobal.js index 8d71c7ddf..09bbb8a9a 100644 --- a/packages/engine/src/actions/getGlobal.js +++ b/packages/engine/src/actions/getGlobal.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getGlobal = ({ arrayIndices, lowdefyGlobal, location, params }) => { - return getFromObject({ - arrayIndices, - location, - object: lowdefyGlobal, - method: 'getGlobal', - params, - }); -}; +function createGetGlobal({ arrayIndices, blockId, context }) { + return function getGlobal(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: context._internal.lowdefy.lowdefyGlobal || {}, + method: 'getGlobal', + params, + }); + }; +} -export default getGlobal; +export default createGetGlobal; diff --git a/packages/engine/src/actions/getInput.js b/packages/engine/src/actions/getInput.js index ace69cb1b..48b9e91ed 100644 --- a/packages/engine/src/actions/getInput.js +++ b/packages/engine/src/actions/getInput.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getInput = ({ arrayIndices, input, location, params }) => { - return getFromObject({ - arrayIndices, - location, - object: input, - method: 'getInput', - params, - }); -}; +function createGetInput({ arrayIndices, blockId, context }) { + return function getInput(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: context._internal.lowdefy.inputs ? context._internal.lowdefy.inputs[context.id] : {}, + method: 'getInput', + params, + }); + }; +} -export default getInput; +export default createGetInput; diff --git a/packages/engine/src/actions/getPageId.js b/packages/engine/src/actions/getPageId.js index f607bc1c3..362a99cc0 100644 --- a/packages/engine/src/actions/getPageId.js +++ b/packages/engine/src/actions/getPageId.js @@ -14,8 +14,10 @@ limitations under the License. */ -const getPageId = ({ pageId }) => { - return pageId; -}; +function createGetPageId({ context }) { + return function getPageId() { + return context.pageId; + }; +} -export default getPageId; +export default createGetPageId; diff --git a/packages/engine/src/actions/getRequest.js b/packages/engine/src/actions/getRequest.js index bf0300929..d4772e16e 100644 --- a/packages/engine/src/actions/getRequest.js +++ b/packages/engine/src/actions/getRequest.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getRequest = ({ arrayIndices, location, params, requests }) => { - return getFromObject({ - arrayIndices, - location, - object: requests, - method: 'getRequest', - params, - }); +const createGetRequest = ({ arrayIndices, blockId, context }) => { + return function getRequest(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: context.requests, + method: 'getRequest', + params, + }); + }; }; -export default getRequest; +export default createGetRequest; diff --git a/packages/engine/src/actions/getState.js b/packages/engine/src/actions/getState.js index f1ff9eaa8..5f1327970 100644 --- a/packages/engine/src/actions/getState.js +++ b/packages/engine/src/actions/getState.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getState = ({ arrayIndices, location, params, state }) => { - return getFromObject({ - arrayIndices, - location, - object: state, - method: 'getState', - params, - }); -}; +function createGetState({ arrayIndices, blockId, context }) { + return function getState(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: context.state, + method: 'getState', + params, + }); + }; +} -export default getState; +export default createGetState; diff --git a/packages/engine/src/actions/getUrlQuery.js b/packages/engine/src/actions/getUrlQuery.js index 902d9b85d..b63ef4609 100644 --- a/packages/engine/src/actions/getUrlQuery.js +++ b/packages/engine/src/actions/getUrlQuery.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getUrlQuery = ({ arrayIndices, location, params, urlQuery }) => { - return getFromObject({ - arrayIndices, - location, - object: urlQuery, - method: 'getUrlQuery', - params, - }); -}; +function createGetUrlQuery({ arrayIndices, blockId, context }) { + return function getUrlQuery(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: context._internal.lowdefy.urlQuery || {}, + method: 'getUrlQuery', + params, + }); + }; +} -export default getUrlQuery; +export default createGetUrlQuery; diff --git a/packages/engine/src/actions/getUser.js b/packages/engine/src/actions/getUser.js index 9de28e88e..94f06d59e 100644 --- a/packages/engine/src/actions/getUser.js +++ b/packages/engine/src/actions/getUser.js @@ -16,14 +16,16 @@ import getFromObject from './getFromObject.js'; -const getUser = ({ arrayIndices, location, params, user }) => { - return getFromObject({ - arrayIndices, - location, - object: user, - method: 'getUser', - params, - }); -}; +function createGetUser({ arrayIndices, blockId, context }) { + return function getUser(params) { + return getFromObject({ + arrayIndices, + location: blockId, + object: context._internal.lowdefy.user || {}, + method: 'getUser', + params, + }); + }; +} -export default getUser; +export default createGetUser; diff --git a/packages/engine/src/actions/index.js b/packages/engine/src/actions/index.js deleted file mode 100644 index 62ecb7524..000000000 --- a/packages/engine/src/actions/index.js +++ /dev/null @@ -1,135 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import { default as callMethod } from './callMethod.js'; -import { default as getAction } from './getAction.js'; -import { default as getBlockId } from './getBlockId.js'; -import { default as getEvent } from './getEvent.js'; -import { default as getGlobal } from './getGlobal.js'; -import { default as getInput } from './getInput.js'; -import { default as getPageId } from './getPageId.js'; -import { default as getRequest } from './getRequest.js'; -import { default as getState } from './getState.js'; -import { default as getUrlQuery } from './getUrlQuery.js'; -import { default as getUser } from './getUser.js'; -import { default as link } from './link.js'; -import { default as login } from './login.js'; -import { default as logout } from './logout.js'; -import { default as message } from './message.js'; -import { default as request } from './request.js'; -import { default as reset } from './reset.js'; -import { default as resetValidation } from './resetValidation.js'; -import { default as scrollTo } from './scrollTo.js'; -import { default as setGlobal } from './setGlobal.js'; -import { default as setState } from './setState.js'; -import { default as validate } from './validate.js'; - -export const getMethods = ({ actions, arrayIndices, blockId, context, event, responses }) => { - return { - callMethod: (params) => callMethod({ arrayIndices, context, params }), - getAction: (params) => getAction({ arrayIndices, location: blockId, params, responses }), - getBlockId: () => getBlockId({ blockId }), - getEvent: (params) => getEvent({ event, params }), - getGlobal: (params) => - getGlobal({ - arrayIndices, - lowdefyGlobal: context._internal.lowdefy.lowdefyGlobal || {}, - location: blockId, - params, - }), - getInput: (params) => - getInput({ - arrayIndices, - input: context._internal.lowdefy.inputs ? context._internal.lowdefy.inputs[context.id] : {}, - location: blockId, - params, - }), - getPageId: () => getPageId({ pageId: context.pageId }), - getRequest: (params) => - getRequest({ - arrayIndices, - requests: context.requests, - location: blockId, - params, - }), - getState: (params) => - getState({ - arrayIndices, - state: context.state, - location: blockId, - params, - }), - getUrlQuery: (params) => - getUrlQuery({ - arrayIndices, - urlQuery: context._internal.lowdefy.urlQuery || {}, - location: blockId, - params, - }), - getUser: (params) => - getUser({ - arrayIndices, - user: context._internal.lowdefy.user || {}, - location: blockId, - params, - }), - link: (params) => link({ context, params }), - login: (params) => login({ context, params }), - logout: () => logout({ context }), - message: (params) => message({ context, params }), - request: (params) => - request({ - actions, - arrayIndices, - context, - event, - params, - }), - reset: () => reset({ context }), - resetValidation: (params) => resetValidation({ context, params }), - scrollTo: (params) => { - scrollTo({ context, params }); - }, - setGlobal: (params) => setGlobal({ arrayIndices, context, params }), - setState: (params) => setState({ arrayIndices, context, params }), - validate: (params) => validate({ context, params }), - }; -}; - -export default { - callMethod, - getAction, - getBlockId, - getEvent, - getGlobal, - getInput, - getPageId, - getRequest, - getState, - getUrlQuery, - getUser, - link, - login, - logout, - message, - request, - reset, - resetValidation, - scrollTo, - setGlobal, - setState, - validate, -}; diff --git a/packages/engine/src/actions/link.js b/packages/engine/src/actions/link.js index 50f969788..9e59ab880 100644 --- a/packages/engine/src/actions/link.js +++ b/packages/engine/src/actions/link.js @@ -16,14 +16,16 @@ import { type } from '@lowdefy/helpers'; -const link = ({ context, params }) => { - const linkParams = type.isString(params) ? { pageId: params } : params; - try { - context._internal.lowdefy._internal.link(linkParams); - } catch (error) { - console.log(error); - throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); - } -}; +function createLink({ context }) { + return function link({ params }) { + const linkParams = type.isString(params) ? { pageId: params } : params; + try { + context._internal.lowdefy._internal.link(linkParams); + } catch (error) { + console.log(error); + throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); + } + }; +} -export default link; +export default createLink; diff --git a/packages/engine/src/actions/login.js b/packages/engine/src/actions/login.js index ae660973a..84e567a15 100644 --- a/packages/engine/src/actions/login.js +++ b/packages/engine/src/actions/login.js @@ -14,8 +14,10 @@ limitations under the License. */ -const login = ({ context, params }) => { - return context._internal.lowdefy._internal.auth.login(params); -}; +function createLogin({ context }) { + return function login(params) { + return context._internal.lowdefy._internal.auth.login(params); + }; +} -export default login; +export default createLogin; diff --git a/packages/engine/src/actions/logout.js b/packages/engine/src/actions/logout.js index 0665b5545..a1089041f 100644 --- a/packages/engine/src/actions/logout.js +++ b/packages/engine/src/actions/logout.js @@ -14,8 +14,10 @@ limitations under the License. */ -const logout = ({ context }) => { - return context._internal.lowdefy._internal.auth.logout(); -}; +function createLogout({ context }) { + return function logout() { + return context._internal.lowdefy._internal.auth.logout(); + }; +} -export default logout; +export default createLogout; diff --git a/packages/engine/src/actions/message.js b/packages/engine/src/actions/message.js index c2f5d3768..a519253fa 100644 --- a/packages/engine/src/actions/message.js +++ b/packages/engine/src/actions/message.js @@ -14,13 +14,15 @@ limitations under the License. */ -const message = ({ context, params = {} }) => { - context._internal.lowdefy._internal.displayMessage({ - content: params.content || 'Success', - duration: params.duration, - icon: params.icon, - status: params.status, - }); -}; +function createMessage({ context }) { + return function message(params = {}) { + context._internal.lowdefy._internal.displayMessage({ + content: params.content || 'Success', + duration: params.duration, + icon: params.icon, + status: params.status, + }); + }; +} -export default message; +export default createMessage; diff --git a/packages/engine/src/actions/request.js b/packages/engine/src/actions/request.js index c1f7ee392..87aa43b45 100644 --- a/packages/engine/src/actions/request.js +++ b/packages/engine/src/actions/request.js @@ -14,8 +14,10 @@ limitations under the License. */ -const request = async ({ actions, arrayIndices, context, event, params }) => { - return await context._internal.Requests.callRequests({ actions, arrayIndices, event, params }); -}; +function createRequest({ actions, arrayIndices, context, event }) { + return async function request(params) { + return await context._internal.Requests.callRequests({ actions, arrayIndices, event, params }); + }; +} -export default request; +export default createRequest; diff --git a/packages/engine/src/actions/reset.js b/packages/engine/src/actions/reset.js index 7ba155153..71a9099e7 100644 --- a/packages/engine/src/actions/reset.js +++ b/packages/engine/src/actions/reset.js @@ -16,12 +16,14 @@ import { serializer } from '@lowdefy/helpers'; -const reset = ({ context }) => { - context._internal.State.resetState(); - context._internal.RootBlocks.reset( - serializer.deserializeFromString(context._internal.State.frozenState) - ); - context._internal.update(); -}; +function createReset({ context }) { + return function reset() { + context._internal.State.resetState(); + context._internal.RootBlocks.reset( + serializer.deserializeFromString(context._internal.State.frozenState) + ); + context._internal.update(); + }; +} -export default reset; +export default createReset; diff --git a/packages/engine/src/actions/resetValidation.js b/packages/engine/src/actions/resetValidation.js index 4604f819d..4980f74bf 100644 --- a/packages/engine/src/actions/resetValidation.js +++ b/packages/engine/src/actions/resetValidation.js @@ -16,8 +16,10 @@ import getBlockMatcher from '../getBlockMatcher.js'; -const resetValidation = ({ context, params }) => { - context._internal.RootBlocks.resetValidation(getBlockMatcher(params)); -}; +function createResetValidation({ context }) { + return function resetValidation(params) { + context._internal.RootBlocks.resetValidation(getBlockMatcher(params)); + }; +} -export default resetValidation; +export default createResetValidation; diff --git a/packages/engine/src/actions/scrollTo.js b/packages/engine/src/actions/scrollTo.js deleted file mode 100644 index 02f606987..000000000 --- a/packages/engine/src/actions/scrollTo.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -const scrollTo = ({ context, params = {} }) => { - if (params.blockId) { - const element = context._internal.lowdefy._internal.document.getElementById(params.blockId); - if (element) { - element.scrollIntoView(params.options); - } - } else { - context._internal.lowdefy._internal.window.scrollTo(params); - } -}; - -export default scrollTo; diff --git a/packages/engine/src/actions/setGlobal.js b/packages/engine/src/actions/setGlobal.js index 68481f3c4..983eaa548 100644 --- a/packages/engine/src/actions/setGlobal.js +++ b/packages/engine/src/actions/setGlobal.js @@ -16,12 +16,18 @@ import { applyArrayIndices, set } from '@lowdefy/helpers'; -const setGlobal = ({ arrayIndices, context, params }) => { - Object.keys(params).forEach((key) => { - set(context._internal.lowdefy.lowdefyGlobal, applyArrayIndices(arrayIndices, key), params[key]); - }); - context._internal.RootBlocks.reset(); - context._internal.update(); +const createSetGlobal = ({ arrayIndices, context }) => { + return function setGlobal(params) { + Object.keys(params).forEach((key) => { + set( + context._internal.lowdefy.lowdefyGlobal, + applyArrayIndices(arrayIndices, key), + params[key] + ); + }); + context._internal.RootBlocks.reset(); + context._internal.update(); + }; }; -export default setGlobal; +export default createSetGlobal; diff --git a/packages/engine/src/actions/setState.js b/packages/engine/src/actions/setState.js index de029770e..b24c71241 100644 --- a/packages/engine/src/actions/setState.js +++ b/packages/engine/src/actions/setState.js @@ -16,12 +16,14 @@ import { applyArrayIndices } from '@lowdefy/helpers'; -const setState = ({ arrayIndices, context, params }) => { - Object.keys(params).forEach((key) => { - context._internal.State.set(applyArrayIndices(arrayIndices, key), params[key]); - }); - context._internal.RootBlocks.reset(); - context._internal.update(); -}; +function createSetState({ arrayIndices, context }) { + return function setState(params) { + Object.keys(params).forEach((key) => { + context._internal.State.set(applyArrayIndices(arrayIndices, key), params[key]); + }); + context._internal.RootBlocks.reset(); + context._internal.update(); + }; +} -export default setState; +export default createSetState; diff --git a/packages/engine/src/actions/validate.js b/packages/engine/src/actions/validate.js index ca3267e46..1e912aa3f 100644 --- a/packages/engine/src/actions/validate.js +++ b/packages/engine/src/actions/validate.js @@ -16,16 +16,18 @@ import getBlockMatcher from '../getBlockMatcher.js'; -const validate = ({ context, params }) => { - const validationErrors = context.RootBlocks.validate(getBlockMatcher(params)); - if (validationErrors.length > 0) { - const error = new Error( - `Your input has ${validationErrors.length} validation error${ - validationErrors.length !== 1 ? 's' : '' - }.` - ); - throw error; - } -}; +function createValidate({ context }) { + return function validate(params) { + const validationErrors = context.RootBlocks.validate(getBlockMatcher(params)); + if (validationErrors.length > 0) { + const error = new Error( + `Your input has ${validationErrors.length} validation error${ + validationErrors.length !== 1 ? 's' : '' + }.` + ); + throw error; + } + }; +} -export default validate; +export default createValidate; From dcfa3ea5034a49277c6475abdd4b9cb24e70b65b Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 10:13:25 +0200 Subject: [PATCH 14/79] chore(engine): Refactored link action method to only use _internal link method. --- packages/engine/src/actions/link.js | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/engine/src/actions/link.js b/packages/engine/src/actions/link.js index 9e59ab880..cdd863585 100644 --- a/packages/engine/src/actions/link.js +++ b/packages/engine/src/actions/link.js @@ -14,17 +14,9 @@ limitations under the License. */ -import { type } from '@lowdefy/helpers'; - function createLink({ context }) { return function link({ params }) { - const linkParams = type.isString(params) ? { pageId: params } : params; - try { - context._internal.lowdefy._internal.link(linkParams); - } catch (error) { - console.log(error); - throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); - } + context._internal.lowdefy._internal.link(params); }; } From 4bfc102663cc1cd1286421bd04b67137cfac0c25 Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 10:18:11 +0200 Subject: [PATCH 15/79] chore(actions-core): Refactor action function declarations. --- .../actions/actions-core/src/actions/CallMethod.js | 4 ++-- .../plugins/actions/actions-core/src/actions/Link.js | 10 +++++++++- .../plugins/actions/actions-core/src/actions/Login.js | 4 ++-- .../plugins/actions/actions-core/src/actions/Logout.js | 4 ++-- .../actions/actions-core/src/actions/Message.js | 4 ++-- .../actions/actions-core/src/actions/Request.js | 4 ++-- .../plugins/actions/actions-core/src/actions/Reset.js | 4 ++-- .../actions-core/src/actions/ResetValidation.js | 4 ++-- .../actions/actions-core/src/actions/ScrollTo.js | 4 ++-- .../actions/actions-core/src/actions/SetGlobal.js | 4 ++-- .../actions/actions-core/src/actions/SetState.js | 4 ++-- .../plugins/actions/actions-core/src/actions/Throw.js | 4 ++-- .../actions/actions-core/src/actions/Validate.js | 4 ++-- .../plugins/actions/actions-core/src/actions/Wait.js | 4 ++-- 14 files changed, 35 insertions(+), 27 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/CallMethod.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.js index b8500020b..33a9d8a9c 100644 --- a/packages/plugins/actions/actions-core/src/actions/CallMethod.js +++ b/packages/plugins/actions/actions-core/src/actions/CallMethod.js @@ -14,8 +14,8 @@ limitations under the License. */ -const CallMethod = ({ methods: { callMethod }, params }) => { +function CallMethod({ methods: { callMethod }, params }) { return callMethod(params); -}; +} export default CallMethod; diff --git a/packages/plugins/actions/actions-core/src/actions/Link.js b/packages/plugins/actions/actions-core/src/actions/Link.js index 1a587c43b..cfd94ea1a 100644 --- a/packages/plugins/actions/actions-core/src/actions/Link.js +++ b/packages/plugins/actions/actions-core/src/actions/Link.js @@ -14,8 +14,16 @@ limitations under the License. */ +import { type } from '@lowdefy/helpers'; + const Link = ({ methods: { link }, params }) => { - link(params); + const linkParams = type.isString(params) ? { pageId: params } : params; + try { + link(linkParams); + } catch (error) { + console.log(error); + throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); + } }; export default Link; diff --git a/packages/plugins/actions/actions-core/src/actions/Login.js b/packages/plugins/actions/actions-core/src/actions/Login.js index 54004a608..23e18b0c7 100644 --- a/packages/plugins/actions/actions-core/src/actions/Login.js +++ b/packages/plugins/actions/actions-core/src/actions/Login.js @@ -14,8 +14,8 @@ limitations under the License. */ -const Login = ({ methods: { login }, params }) => { +function Login({ methods: { login }, params }) { return login(params); -}; +} export default Login; diff --git a/packages/plugins/actions/actions-core/src/actions/Logout.js b/packages/plugins/actions/actions-core/src/actions/Logout.js index 9199cc709..2d339dbb0 100644 --- a/packages/plugins/actions/actions-core/src/actions/Logout.js +++ b/packages/plugins/actions/actions-core/src/actions/Logout.js @@ -14,8 +14,8 @@ limitations under the License. */ -const Logout = ({ methods: { logout } }) => { +function Logout({ methods: { logout } }) { return logout(); -}; +} export default Logout; diff --git a/packages/plugins/actions/actions-core/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js index 95f3012da..0e3ec319e 100644 --- a/packages/plugins/actions/actions-core/src/actions/Message.js +++ b/packages/plugins/actions/actions-core/src/actions/Message.js @@ -14,8 +14,8 @@ limitations under the License. */ -const Message = ({ methods: { message }, params }) => { +function Message({ methods: { message }, params }) { message(params); -}; +} export default Message; diff --git a/packages/plugins/actions/actions-core/src/actions/Request.js b/packages/plugins/actions/actions-core/src/actions/Request.js index 842c786d6..c81464f4d 100644 --- a/packages/plugins/actions/actions-core/src/actions/Request.js +++ b/packages/plugins/actions/actions-core/src/actions/Request.js @@ -14,8 +14,8 @@ limitations under the License. */ -const Request = async ({ methods: { request }, params }) => { +async function Request({ methods: { request }, params }) { return await request(params); -}; +} export default Request; diff --git a/packages/plugins/actions/actions-core/src/actions/Reset.js b/packages/plugins/actions/actions-core/src/actions/Reset.js index efac40d8f..ffb020981 100644 --- a/packages/plugins/actions/actions-core/src/actions/Reset.js +++ b/packages/plugins/actions/actions-core/src/actions/Reset.js @@ -14,8 +14,8 @@ limitations under the License. */ -const Reset = ({ methods: { reset } }) => { +function Reset({ methods: { reset } }) { reset(); -}; +} export default Reset; diff --git a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js index 211095f2f..fa7d7451f 100644 --- a/packages/plugins/actions/actions-core/src/actions/ResetValidation.js +++ b/packages/plugins/actions/actions-core/src/actions/ResetValidation.js @@ -14,8 +14,8 @@ limitations under the License. */ -const ResetValidation = ({ methods: { resetValidation }, params }) => { +function ResetValidation({ methods: { resetValidation }, params }) { resetValidation(params); -}; +} export default ResetValidation; diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index 48b3631d6..42fd3664d 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -14,7 +14,7 @@ limitations under the License. */ -const ScrollTo = ({ document, params, window }) => { +function ScrollTo({ document, params, window }) { if (params.blockId) { const element = document.getElementById(params.blockId); if (element) { @@ -23,6 +23,6 @@ const ScrollTo = ({ document, params, window }) => { } else { window.scrollTo(params); } -}; +} export default ScrollTo; diff --git a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js index 96b46fff8..1a6b8a034 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetGlobal.js +++ b/packages/plugins/actions/actions-core/src/actions/SetGlobal.js @@ -14,8 +14,8 @@ limitations under the License. */ -const SetGlobal = ({ methods: { setGlobal }, params }) => { +function SetGlobal({ methods: { setGlobal }, params }) { setGlobal(params); -}; +} export default SetGlobal; diff --git a/packages/plugins/actions/actions-core/src/actions/SetState.js b/packages/plugins/actions/actions-core/src/actions/SetState.js index aec25e260..bf90c7d40 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetState.js +++ b/packages/plugins/actions/actions-core/src/actions/SetState.js @@ -14,8 +14,8 @@ limitations under the License. */ -const SetState = ({ methods: { setState }, params }) => { +function SetState({ methods: { setState }, params }) { setState(params); -}; +} export default SetState; diff --git a/packages/plugins/actions/actions-core/src/actions/Throw.js b/packages/plugins/actions/actions-core/src/actions/Throw.js index bfc4fde75..c479118a7 100644 --- a/packages/plugins/actions/actions-core/src/actions/Throw.js +++ b/packages/plugins/actions/actions-core/src/actions/Throw.js @@ -26,7 +26,7 @@ class ThrowActionError extends Error { } } -const Throw = ({ methods: { getBlockId, getPageId }, params }) => { +function Throw({ methods: { getBlockId, getPageId }, params }) { if (params.throw === false || type.isNone(params.throw)) { return; } @@ -38,7 +38,7 @@ const Throw = ({ methods: { getBlockId, getPageId }, params }) => { }); } throw new Error(`Invalid Throw, check action params. Received "${JSON.stringify(params)}".`); -}; +} export default Throw; export { Throw, ThrowActionError }; diff --git a/packages/plugins/actions/actions-core/src/actions/Validate.js b/packages/plugins/actions/actions-core/src/actions/Validate.js index 98bd595f0..35191a65b 100644 --- a/packages/plugins/actions/actions-core/src/actions/Validate.js +++ b/packages/plugins/actions/actions-core/src/actions/Validate.js @@ -14,8 +14,8 @@ limitations under the License. */ -const Validate = ({ methods: { validate }, params }) => { +function Validate({ methods: { validate }, params }) { return validate(params); -}; +} export default Validate; diff --git a/packages/plugins/actions/actions-core/src/actions/Wait.js b/packages/plugins/actions/actions-core/src/actions/Wait.js index 513f4e6ef..d7d856897 100644 --- a/packages/plugins/actions/actions-core/src/actions/Wait.js +++ b/packages/plugins/actions/actions-core/src/actions/Wait.js @@ -16,11 +16,11 @@ import { type, wait } from '@lowdefy/helpers'; -const Wait = ({ params }) => { +function Wait({ params }) { if (!type.isInt(params.ms)) { throw new Error(`Wait action "ms" param should be an integer.`); } return wait(params.ms); -}; +} export default Wait; From 4558e81c2144d1d36b2a9d02a26ca25b0fca980e Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 16:23:22 +0200 Subject: [PATCH 16/79] chore(engine): Moved actions tests into action methods folder. --- .../engine/test/Actions/CallMethod.test.js | 602 --------- packages/engine/test/Actions/JsAction.test.js | 527 -------- packages/engine/test/Actions/Link.test.js | 197 --- packages/engine/test/Actions/Login.test.js | 87 -- packages/engine/test/Actions/Logout.test.js | 78 -- packages/engine/test/Actions/Message.test.js | 174 --- packages/engine/test/Actions/Request.test.js | 407 ------ packages/engine/test/Actions/Reset.test.js | 188 --- .../test/Actions/ResetValidation.test.js | 194 --- packages/engine/test/Actions/ScrollTo.test.js | 252 ---- .../engine/test/Actions/SetGlobal.test.js | 75 -- packages/engine/test/Actions/SetState.test.js | 248 ---- packages/engine/test/Actions/Throw.test.js | 565 -------- packages/engine/test/Actions/Validate.test.js | 1196 ----------------- packages/engine/test/Actions/Wait.test.js | 157 --- 15 files changed, 4947 deletions(-) delete mode 100644 packages/engine/test/Actions/CallMethod.test.js delete mode 100644 packages/engine/test/Actions/JsAction.test.js delete mode 100644 packages/engine/test/Actions/Link.test.js delete mode 100644 packages/engine/test/Actions/Login.test.js delete mode 100644 packages/engine/test/Actions/Logout.test.js delete mode 100644 packages/engine/test/Actions/Message.test.js delete mode 100644 packages/engine/test/Actions/Request.test.js delete mode 100644 packages/engine/test/Actions/Reset.test.js delete mode 100644 packages/engine/test/Actions/ResetValidation.test.js delete mode 100644 packages/engine/test/Actions/ScrollTo.test.js delete mode 100644 packages/engine/test/Actions/SetGlobal.test.js delete mode 100644 packages/engine/test/Actions/SetState.test.js delete mode 100644 packages/engine/test/Actions/Throw.test.js delete mode 100644 packages/engine/test/Actions/Validate.test.js delete mode 100644 packages/engine/test/Actions/Wait.test.js diff --git a/packages/engine/test/Actions/CallMethod.test.js b/packages/engine/test/Actions/CallMethod.test.js deleted file mode 100644 index 763352fb6..000000000 --- a/packages/engine/test/Actions/CallMethod.test.js +++ /dev/null @@ -1,602 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const lowdefy = {}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeAll(() => { - global.Date = mockDate; -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('CallMethod with no args, synchronous method', async () => { - const blockMethod = jest.fn((...args) => ({ args })); - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'textInput', method: 'blockMethod' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; - - textInput.registerMethod('blockMethod', blockMethod); - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'CallMethod', - index: 0, - response: { - args: [], - }, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(blockMethod.mock.calls).toEqual([[]]); -}); - -test('CallMethod method return a promise', async () => { - const timeout = (ms) => { - return new Promise((resolve) => setTimeout(resolve, ms)); - }; - const calls = []; - const blockMethod = async (...args) => { - calls.push(args); - await timeout(300); - return { args }; - }; - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'textInput', method: 'blockMethod', args: ['arg'] }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; - - textInput.registerMethod('blockMethod', blockMethod); - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'CallMethod', - index: 0, - response: { - args: ['arg'], - }, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(calls).toEqual([['arg']]); -}); - -test('CallMethod with args not an array', async () => { - const blockMethod = jest.fn((...args) => ({ args })); - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'textInput', method: 'blockMethod', args: 'arg' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; - - textInput.registerMethod('blockMethod', blockMethod); - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: { - args: 'arg', - blockId: 'textInput', - method: 'blockMethod', - }, - type: 'CallMethod', - }, - error: { - error: new Error( - 'Failed to call method "blockMethod" on block "textInput": "args" should be an array. Received "{"blockId":"textInput","method":"blockMethod","args":"arg"}".' - ), - index: 0, - type: 'CallMethod', - }, - }, - responses: { - a: { - type: 'CallMethod', - index: 0, - error: new Error( - 'Failed to call method "blockMethod" on block "textInput": "args" should be an array. Received "{"blockId":"textInput","method":"blockMethod","args":"arg"}".' - ), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(blockMethod.mock.calls).toEqual([]); -}); - -test('CallMethod with multiple positional args, synchronous method', async () => { - const blockMethod = jest.fn((...args) => ({ args })); - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'textInput', method: 'blockMethod', args: ['arg1', 'arg2'] }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; - - textInput.registerMethod('blockMethod', blockMethod); - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'CallMethod', - index: 0, - response: { - args: ['arg1', 'arg2'], - }, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(blockMethod.mock.calls).toEqual([['arg1', 'arg2']]); -}); - -test('CallMethod of block in array by explicit id', async () => { - const blockMethod0 = jest.fn((...args) => ({ args })); - const blockMethod1 = jest.fn((...args) => ({ args })); - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list:0', - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list.$.textInput:0', - blockId: 'list.$.textInput', - type: 'TextInput', - defaultValue: '123', - meta: { - category: 'input', - valueType: 'string', - }, - }, - ], - }, - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'list.0.textInput', method: 'blockMethod', args: ['arg'] }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { list: [{ textInput: '0' }, { textInput: '1' }] }, - }); - - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput0 = context._internal.RootBlocks.map['block:root:list.0.textInput:0']; - const textInput1 = context._internal.RootBlocks.map['block:root:list.1.textInput:0']; - - textInput0.registerMethod('blockMethod', blockMethod0); - textInput1.registerMethod('blockMethod', blockMethod1); - await button.triggerEvent({ name: 'onClick' }); - expect(blockMethod0.mock.calls).toEqual([['arg']]); - expect(blockMethod1.mock.calls).toEqual([]); -}); - -test('CallMethod of block in array by block with same indices and id pattern', async () => { - const blockMethod0 = jest.fn((...args) => ({ args })); - const blockMethod1 = jest.fn((...args) => ({ args })); - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list:0', - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list.$.textInput:0', - blockId: 'list.$.textInput', - type: 'TextInput', - defaultValue: '123', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:list.$.button:0', - blockId: 'list.$.button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { - blockId: 'list.$.textInput', - method: 'blockMethod', - args: ['arg'], - }, - }, - ], - }, - }, - ], - }, - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { list: [{ textInput: '0' }, { textInput: '1' }] }, - }); - - const textInput0 = context._internal.RootBlocks.map['block:root:list.0.textInput:0']; - const textInput1 = context._internal.RootBlocks.map['block:root:list.1.textInput:0']; - const button0 = context._internal.RootBlocks.map['block:root:list.0.button:0']; - const button1 = context._internal.RootBlocks.map['block:root:list.1.button:0']; - - textInput0.registerMethod('blockMethod', blockMethod0); - textInput1.registerMethod('blockMethod', blockMethod1); - await button1.triggerEvent({ name: 'onClick' }); - expect(blockMethod0.mock.calls).toEqual([]); - expect(blockMethod1.mock.calls).toEqual([['arg']]); - - await button0.triggerEvent({ name: 'onClick' }); - expect(blockMethod0.mock.calls).toEqual([['arg']]); - expect(blockMethod1.mock.calls).toEqual([['arg']]); -}); - -test('CallMethod with method does not exist', async () => { - const blockMethod = jest.fn((...args) => ({ args })); - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'textInput', method: 'no-method' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: { - blockId: 'textInput', - method: 'no-method', - }, - type: 'CallMethod', - }, - error: { - error: new Error( - 'Failed to call method "no-method" on block "textInput". Check if "no-method" is a valid block method for block "textInput". Received "{"blockId":"textInput","method":"no-method"}".' - ), - index: 0, - type: 'CallMethod', - }, - }, - responses: { - a: { - type: 'CallMethod', - index: 0, - error: new Error( - 'Failed to call method "no-method" on block "textInput". Check if "no-method" is a valid block method for block "textInput". Received "{"blockId":"textInput","method":"no-method"}".' - ), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(blockMethod.mock.calls).toEqual([]); -}); diff --git a/packages/engine/test/Actions/JsAction.test.js b/packages/engine/test/Actions/JsAction.test.js deleted file mode 100644 index 08d30c2bd..000000000 --- a/packages/engine/test/Actions/JsAction.test.js +++ /dev/null @@ -1,527 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; -import actionFns from '../../src/actions/index.js'; - -const pageId = 'one'; -const lowdefy = { pageId }; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeAll(() => { - global.Date = mockDate; -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('JsAction with no args, synchronous fn', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 'test_fn', - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const mockFn = jest.fn(() => 'js_fn'); - context.lowdefy.imports.jsActions.test_fn = mockFn; - const { button } = context.RootBlocks.map; - - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'JsAction', - index: 0, - response: 'js_fn', - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(mockFn).toHaveBeenCalledTimes(1); -}); - -test('JsAction with no args, async fn', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 'test_fn', - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const timeout = (ms) => { - return new Promise((resolve) => setTimeout(resolve, ms)); - }; - const fn = async () => { - await timeout(300); - return 'js_fn'; - }; - const mockFn = jest.fn().mockImplementation(fn); - context.lowdefy.imports.jsActions.test_fn = mockFn; - const { button } = context.RootBlocks.map; - - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'JsAction', - index: 0, - response: 'js_fn', - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(mockFn).toHaveBeenCalledTimes(1); -}); - -test('JsAction with args, synchronous fn', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 'test_fn', - args: [1, '2', new Date()], - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const mockFn = jest.fn((...args) => args); - context.lowdefy.imports.jsActions.test_fn = mockFn; - const { button } = context.RootBlocks.map; - - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toMatchInlineSnapshot(` - Object { - "blockId": "button", - "bounced": false, - "endTimestamp": Object { - "date": 0, - }, - "event": undefined, - "eventName": "onClick", - "responses": Object { - "a": Object { - "index": 0, - "response": Array [ - Object { - "actions": Object { - "CallMethod": [Function], - "JsAction": [Function], - "Link": [Function], - "Login": [Function], - "Logout": [Function], - "Message": [Function], - "Request": [Function], - "Reset": [Function], - "ResetValidation": [Function], - "ScrollTo": [Function], - "SetGlobal": [Function], - "SetState": [Function], - "Throw": [Function], - "Validate": [Function], - "Wait": [Function], - }, - "contextId": "test", - "input": Object {}, - "pageId": "root", - "requests": Object {}, - "state": Object {}, - "urlQuery": Object {}, - }, - 1, - "2", - Object { - "date": 0, - }, - ], - "type": "JsAction", - }, - }, - "startTimestamp": Object { - "date": 0, - }, - "success": true, - } - `); - expect(mockFn).toHaveBeenCalledTimes(1); -}); - -test('JsAction name not a string', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 1, - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: { - name: 1, - }, - type: 'JsAction', - }, - error: { - error: new Error(`JsAction requires a string for 'params.name'.`), - index: 0, - type: 'JsAction', - }, - }, - responses: { - a: { - type: 'JsAction', - index: 0, - error: new Error(`JsAction requires a string for 'params.name'.`), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); - -test('JsAction args not an array', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 'js_fn', - args: { a: 1 }, - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: { - args: { - a: 1, - }, - name: 'js_fn', - }, - type: 'JsAction', - }, - error: { - error: new Error(`JsAction requires a array for 'params.args'.`), - index: 0, - type: 'JsAction', - }, - }, - responses: { - a: { - type: 'JsAction', - index: 0, - error: new Error(`JsAction requires a array for 'params.args'.`), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); - -test('JsAction args not a function', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 'js_not_fn', - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: { - name: 'js_not_fn', - }, - type: 'JsAction', - }, - error: { - error: new Error(`JsAction js_not_fn is not a function.`), - index: 0, - type: 'JsAction', - }, - }, - responses: { - a: { - type: 'JsAction', - index: 0, - error: new Error(`JsAction js_not_fn is not a function.`), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); - -test('JsAction can use Lowdefy actions', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'JsAction', - params: { - name: 'test_fn', - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - - const fn = async ({ actions }) => { - actions.SetState({ answer: 42 }); - return actions; - }; - - const mockFn = jest.fn().mockImplementation(fn); - context.lowdefy.imports.jsActions.test_fn = mockFn; - const { button } = context.RootBlocks.map; - - const res = await button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ answer: 42 }); - expect(Object.keys(res.responses.a.response)).toEqual(Object.keys(actionFns)); -}); diff --git a/packages/engine/test/Actions/Link.test.js b/packages/engine/test/Actions/Link.test.js deleted file mode 100644 index 81b95a55f..000000000 --- a/packages/engine/test/Actions/Link.test.js +++ /dev/null @@ -1,197 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const lowdefy = { - _internal: { link: jest.fn() }, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeEach(() => { - global.Date = mockDate; - lowdefy._internal.link.mockReset(); -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('Link with string pageId params', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:root:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Link', params: 'pageId' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(lowdefy._internal.link.mock.calls).toEqual([ - [ - { - pageId: 'pageId', - }, - ], - ]); - expect(res.success).toBe(true); -}); - -test('Link with object params', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Link', params: { pageId: 'pageId', newTab: true } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(lowdefy._internal.link.mock.calls).toEqual([ - [ - { - pageId: 'pageId', - newTab: true, - }, - ], - ]); - expect(res.success).toBe(true); -}); - -test('Link error', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Link', params: { invalid: true } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - lowdefy._internal.link.mockImplementationOnce(() => { - throw new Error('Link test error'); - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(lowdefy._internal.link.mock.calls).toEqual([ - [ - { - invalid: true, - }, - ], - ]); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: { - invalid: true, - }, - type: 'Link', - }, - error: { - error: new Error('Invalid Link, check action params. Received "{"invalid":true}".'), - index: 0, - type: 'Link', - }, - }, - responses: { - a: { - type: 'Link', - error: new Error('Invalid Link, check action params. Received "{"invalid":true}".'), - index: 0, - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); diff --git a/packages/engine/test/Actions/Login.test.js b/packages/engine/test/Actions/Login.test.js deleted file mode 100644 index 2495aa595..000000000 --- a/packages/engine/test/Actions/Login.test.js +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -const lowdefy = { - auth: { - login: jest.fn(), - }, - pageId, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -beforeEach(() => { - global.Date = mockDate; - lowdefy.auth.login.mockReset(); -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('Login', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Login', - params: { input: { i: true }, pageId: 'pageId', urlQuery: { u: true } }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(lowdefy.auth.login.mock.calls).toEqual([ - [ - { - input: { i: true }, - pageId: 'pageId', - urlQuery: { u: true }, - }, - ], - ]); - expect(res.success).toBe(true); -}); diff --git a/packages/engine/test/Actions/Logout.test.js b/packages/engine/test/Actions/Logout.test.js deleted file mode 100644 index 5762d5057..000000000 --- a/packages/engine/test/Actions/Logout.test.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -const lowdefy = { - auth: { - logout: jest.fn(), - }, - pageId, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -beforeEach(() => { - global.Date = mockDate; - lowdefy.auth.logout.mockReset(); -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('Login', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Logout', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(lowdefy.auth.logout.mock.calls).toEqual([[]]); - expect(res.success).toBe(true); -}); diff --git a/packages/engine/test/Actions/Message.test.js b/packages/engine/test/Actions/Message.test.js deleted file mode 100644 index 925f63401..000000000 --- a/packages/engine/test/Actions/Message.test.js +++ /dev/null @@ -1,174 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -// Mock message -const mockMessage = jest.fn(() => () => undefined); - -const lowdefy = { - _internal: { - displayMessage: mockMessage, - }, -}; - -test('Message with content', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Message', - params: { content: 'test' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockMessage.mock.calls).toEqual([ - [ - { - content: 'test', - }, - ], - ]); -}); - -test('Message with all params', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Message', - params: { - content: 'content', - duration: 6, - icon: 'FireOutlined', - status: 'error', - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockMessage.mock.calls).toEqual([ - [ - { - content: 'content', - duration: 6, - icon: 'FireOutlined', - status: 'error', - }, - ], - ]); -}); - -test('Message with no params', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Message', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockMessage.mock.calls).toEqual([ - [ - { - content: 'Success', - }, - ], - ]); -}); diff --git a/packages/engine/test/Actions/Request.test.js b/packages/engine/test/Actions/Request.test.js deleted file mode 100644 index d9fbb4f72..000000000 --- a/packages/engine/test/Actions/Request.test.js +++ /dev/null @@ -1,407 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -// Mock apollo client -const mockReqResponses = { - req_one: { - id: 'req_one', - success: true, - response: 1, - }, - req_two: { - id: 'req_two', - success: true, - response: 2, - }, - req_error: new Error('Request error'), -}; - -const mockCallRequest = jest.fn(); -const mockCallRequestImp = ({ requestId }) => { - return new Promise((resolve, reject) => { - if (requestId === 'req_error') { - reject(mockReqResponses[requestId]); - } - resolve(mockReqResponses[requestId]); - }); -}; - -const pageId = 'one'; -const lowdefy = { - callRequest: mockCallRequest, - pageId, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeAll(() => { - global.Date = mockDate; -}); - -afterAll(() => { - global.Date = RealDate; -}); - -beforeEach(() => { - mockCallRequest.mockReset(); - mockCallRequest.mockImplementation(mockCallRequestImp); -}); - -test('Request call one request', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - requests: [ - { - requestId: 'req_one', - }, - ], - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Request', params: 'req_one' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const promise = button.triggerEvent({ name: 'onClick' }); - expect(context.requests.req_one).toEqual({ - error: [], - loading: true, - response: null, - }); - const res = await promise; - expect(context.requests.req_one).toEqual({ - error: [], - loading: false, - response: 1, - }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'Request', - index: 0, - response: [1], - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); - -test('Request call all requests', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - requests: [ - { - requestId: 'req_one', - }, - { - requestId: 'req_two', - }, - ], - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Request', params: { all: true } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const promise = button.triggerEvent({ name: 'onClick' }); - expect(context.requests).toEqual({ - req_one: { - error: [], - loading: true, - response: null, - }, - req_two: { - error: [], - loading: true, - response: null, - }, - }); - const res = await promise; - expect(context.requests).toEqual({ - req_one: { - error: [], - loading: false, - response: 1, - }, - req_two: { - error: [], - loading: false, - response: 2, - }, - }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'Request', - index: 0, - response: [1, 2], - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); - -test('Request call array of requests', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - requests: [ - { - requestId: 'req_one', - }, - { - requestId: 'req_two', - }, - ], - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Request', params: ['req_one', 'req_two'] }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const promise = button.triggerEvent({ name: 'onClick' }); - expect(context.requests).toEqual({ - req_one: { - error: [], - loading: true, - response: null, - }, - req_two: { - error: [], - loading: true, - response: null, - }, - }); - const res = await promise; - expect(context.requests).toEqual({ - req_one: { - error: [], - loading: false, - response: 1, - }, - req_two: { - error: [], - loading: false, - response: 2, - }, - }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - a: { - type: 'Request', - index: 0, - response: [1, 2], - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); - -test('Request pass if params are none', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - requests: [ - { - requestId: 'req_one', - }, - { - requestId: 'req_two', - }, - ], - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Request' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - await button.triggerEvent({ name: 'onClick' }); - expect(context.requests).toEqual({}); -}); - -test('Request call request error', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - requests: [ - { - requestId: 'req_error', - }, - ], - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Request', params: 'req_error' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - - expect(context.requests.req_error).toEqual({ - error: [new Error('Request error')], - loading: false, - response: null, - }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'a', - params: 'req_error', - type: 'Request', - }, - error: { - error: new Error('Request error'), - index: 0, - type: 'Request', - }, - }, - responses: { - a: { - type: 'Request', - index: 0, - error: new Error('Request error'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); -}); diff --git a/packages/engine/test/Actions/Reset.test.js b/packages/engine/test/Actions/Reset.test.js deleted file mode 100644 index 282ac7a93..000000000 --- a/packages/engine/test/Actions/Reset.test.js +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; -const lowdefy = { pageId }; - -test('Reset one field', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Reset' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - expect(context.state).toEqual({ textInput: 'init' }); - const { button, textInput } = context.RootBlocks.map; - - textInput.setValue('1'); - expect(context.state).toEqual({ textInput: '1' }); - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ textInput: 'init' }); -}); - -test('Reset on primitive array after adding item', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', - }, - areas: { - content: { - blocks: [ - { - blockId: 'list.$', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - ], - }, - }, - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Reset' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { list: ['init'] }, - }); - expect(context.state).toEqual({ list: ['init'] }); - const { button, list } = context.RootBlocks.map; - - list.pushItem(); - expect(context.state).toEqual({ list: ['init', null] }); - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ list: ['init'] }); -}); - -test('Reset on object array after removing item', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', - }, - areas: { - content: { - blocks: [ - { - blockId: 'list.$.textInput', - type: 'TextInput', - defaultValue: '123', - meta: { - category: 'input', - valueType: 'string', - }, - }, - ], - }, - }, - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'Reset' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { list: [{ textInput: 'init' }] }, - }); - - const { button, list } = context.RootBlocks.map; - - expect(context.state).toEqual({ list: [{ textInput: 'init' }] }); - list.removeItem(0); - expect(context.state).toEqual({ list: [] }); - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ list: [{ textInput: 'init' }] }); -}); diff --git a/packages/engine/test/Actions/ResetValidation.test.js b/packages/engine/test/Actions/ResetValidation.test.js deleted file mode 100644 index 55eb75b74..000000000 --- a/packages/engine/test/Actions/ResetValidation.test.js +++ /dev/null @@ -1,194 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -const closeLoader = jest.fn(); -const displayMessage = jest.fn(); -const lowdefy = { - displayMessage, - pageId, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeEach(() => { - displayMessage.mockReset(); - closeLoader.mockReset(); - displayMessage.mockImplementation(() => closeLoader); -}); - -beforeAll(() => { - global.Date = mockDate; -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('RestValidation after required field', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - required: true, - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - }, - ], - }, - }, - { - blockId: 'reset', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'reset', - type: 'ResetValidation', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, reset, text1 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['This field is required'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - type: 'Validate', - }, - error: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Your input has 1 validation error.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: ['This field is required'], - status: 'error', - warnings: [], - }); - expect(displayMessage.mock.calls).toEqual([ - [ - { - content: 'Your input has 1 validation error.', - duration: 6, - status: 'error', - }, - ], - ]); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); - await reset.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - endTimestamp: { - date: 0, - }, - error: { - action: { - id: 'validate', - type: 'Validate', - }, - error: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - startTimestamp: { - date: 0, - }, - success: false, - }); - expect(text1.eval.validation).toEqual({ - errors: ['This field is required'], - status: null, - warnings: [], - }); - expect(displayMessage.mock.calls).toEqual([]); -}); diff --git a/packages/engine/test/Actions/ScrollTo.test.js b/packages/engine/test/Actions/ScrollTo.test.js deleted file mode 100644 index 4b46d9d1f..000000000 --- a/packages/engine/test/Actions/ScrollTo.test.js +++ /dev/null @@ -1,252 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -// Mock document -const mockDocGetElementById = jest.fn(); -const mockElemScrollIntoView = jest.fn(); -const document = { - getElementById: mockDocGetElementById, -}; -const mockDocGetElementByIdImp = (id) => { - if (id === 'root') return { id, scrollIntoView: mockElemScrollIntoView }; -}; - -// Mock window -const mockWindowFocus = jest.fn(); -const mockWindowOpen = jest.fn(() => ({ focus: mockWindowFocus })); -const mockWindowScrollTo = jest.fn(); -const window = { - location: { href: '', origin: 'http://lowdefy.com' }, - open: mockWindowOpen, - scrollTo: mockWindowScrollTo, -}; - -const lowdefy = { - _internal: { - document, - window, - }, -}; - -beforeEach(() => { - mockWindowOpen.mockReset(); - mockWindowFocus.mockReset(); - mockWindowScrollTo.mockReset(); - mockDocGetElementById.mockReset(); - mockDocGetElementById.mockImplementation(mockDocGetElementByIdImp); - mockElemScrollIntoView.mockReset(); -}); - -test('ScrollTo with no params', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'ScrollTo' }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockWindowScrollTo.mock.calls).toEqual([[{}]]); -}); - -test('ScrollTo with no blockId', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'ScrollTo', params: { behavior: 'smooth', top: 0 } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockWindowScrollTo.mock.calls).toEqual([ - [ - { - behavior: 'smooth', - top: 0, - }, - ], - ]); -}); - -test('ScrollTo with blockId', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'ScrollTo', params: { blockId: 'root' } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockDocGetElementById.mock.calls).toEqual([['root']]); - expect(mockElemScrollIntoView.mock.calls).toEqual([[undefined]]); -}); - -test('ScrollTo with blockId and options', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'ScrollTo', - params: { blockId: 'root', options: { behavior: 'smooth' } }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - - expect(mockDocGetElementById.mock.calls).toEqual([['root']]); - expect(mockElemScrollIntoView.mock.calls).toEqual([ - [ - { - behavior: 'smooth', - }, - ], - ]); -}); - -test('ScrollTo with blockId, block not found', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'ScrollTo', params: { blockId: 'not_there' } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockDocGetElementById.mock.calls).toEqual([['not_there']]); - expect(mockElemScrollIntoView.mock.calls).toEqual([]); - expect(mockWindowScrollTo.mock.calls).toEqual([]); -}); diff --git a/packages/engine/test/Actions/SetGlobal.test.js b/packages/engine/test/Actions/SetGlobal.test.js deleted file mode 100644 index 7b85da5a4..000000000 --- a/packages/engine/test/Actions/SetGlobal.test.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -test('SetGlobal data to global', async () => { - const lowdefy = { - lowdefyGlobal: { x: 'old', init: 'init' }, - pageId, - }; - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'SetGlobal', - params: { str: 'hello', number: 13, arr: [1, 2, 3], x: 'new' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - - expect(context._internal.lowdefy.lowdefyGlobal).toEqual({ x: 'old', init: 'init' }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - - await button.triggerEvent({ name: 'onClick' }); - expect(context._internal.lowdefy.lowdefyGlobal).toEqual({ - init: 'init', - str: 'hello', - number: 13, - arr: [1, 2, 3], - x: 'new', - }); -}); - -test.todo('SetGlobal calls context update'); diff --git a/packages/engine/test/Actions/SetState.test.js b/packages/engine/test/Actions/SetState.test.js deleted file mode 100644 index f9121edda..000000000 --- a/packages/engine/test/Actions/SetState.test.js +++ /dev/null @@ -1,248 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -const lowdefy = { pageId }; - -test('SetState data to state', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'SetState', params: { x: [1, 2, 3] } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - expect(context.state).toEqual({ textInput: 'init' }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - expect(context.state).toEqual({ textInput: 'init' }); - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ textInput: 'init', x: [1, 2, 3] }); -}); - -test('SetState field to state and update block value', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'SetState', params: { textInput: 'new' } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - expect(context.state).toEqual({ textInput: 'init' }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; - - expect(context.state).toEqual({ textInput: 'init' }); - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ textInput: 'new' }); - expect(textInput.value).toEqual('new'); -}); - -test('SetState field to state with incorrect type - NOTE SetState IS NOT TYPE SAFE', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [{ id: 'a', type: 'SetState', params: { textInput: 1 } }], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { textInput: 'init' }, - }); - expect(context.state).toEqual({ textInput: 'init' }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; - - expect(context.state).toEqual({ textInput: 'init' }); - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ textInput: 1 }); - expect(textInput.value).toEqual(1); -}); - -test('SetState value on array and create new Blocks for array items', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list:0', - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list.$.textInput:0', - blockId: 'list.$.textInput', - type: 'TextInput', - defaultValue: '123', - meta: { - category: 'input', - valueType: 'string', - }, - }, - ], - }, - }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'SetState', - params: { list: [{ textInput: '0' }, { textInput: '1' }, { textInput: '2' }] }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - initState: { list: [{ textInput: 'init' }] }, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - - expect(context.state).toEqual({ list: [{ textInput: 'init' }] }); - - button.triggerEvent({ name: 'onClick' }); - expect(context.state).toEqual({ - list: [{ textInput: '0' }, { textInput: '1' }, { textInput: '2' }], - }); - - const textInput0 = context._internal.RootBlocks.map['block:root:list.0.textInput:0']; - const textInput1 = context._internal.RootBlocks.map['block:root:list.1.textInput:0']; - const textInput2 = context._internal.RootBlocks.map['block:root:list.2.textInput:0']; - - expect(textInput0.value).toEqual('0'); - expect(textInput1.value).toEqual('1'); - expect(textInput2.value).toEqual('2'); -}); diff --git a/packages/engine/test/Actions/Throw.test.js b/packages/engine/test/Actions/Throw.test.js deleted file mode 100644 index fdc90c7ce..000000000 --- a/packages/engine/test/Actions/Throw.test.js +++ /dev/null @@ -1,565 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; -import { ThrowActionError } from '../../src/actions/Throw.js'; - -const closeLoader = jest.fn(); -const displayMessage = jest.fn(); -const lowdefy = { - _internal: { - displayMessage, - }, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeEach(() => { - displayMessage.mockReset(); - closeLoader.mockReset(); - displayMessage.mockImplementation(() => closeLoader); -}); - -beforeAll(() => { - global.Date = mockDate; -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('Throw no params', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - response: undefined, - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: true, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); -}); - -test('Throw throw true no message or metaData', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - params: { throw: true }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Throw', - error: new ThrowActionError(undefined, { blockId: 'button', context: context }), - index: 0, - }, - action: { - id: 'throw', - type: 'Throw', - params: { throw: true }, - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - error: new ThrowActionError(undefined, { blockId: 'button', context: context }), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "", - "duration": 6, - "status": "error", - }, - ], - ] - `); -}); - -test('Throw throw true message no metaData', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - params: { throw: true, message: 'My error message' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Throw', - error: new ThrowActionError('My error message', { blockId: 'button', context: context }), - index: 0, - }, - action: { - id: 'throw', - type: 'Throw', - params: { throw: true, message: 'My error message' }, - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - error: new ThrowActionError('My error message', { blockId: 'button', context: context }), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "My error message", - "duration": 6, - "status": "error", - }, - ], - ] - `); -}); - -test('Throw throw true message metaData string', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - params: { throw: true, message: 'My error message', metaData: 'Meta string' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Throw', - error: new ThrowActionError('My error message', { - blockId: 'button', - context: context, - metaData: 'Meta string', - }), - index: 0, - }, - action: { - id: 'throw', - type: 'Throw', - params: { throw: true, message: 'My error message', metaData: 'Meta string' }, - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - error: new ThrowActionError('My error message', { - blockId: 'button', - context: context, - metaData: 'Meta string', - }), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "My error message", - "duration": 6, - "status": "error", - }, - ], - ] - `); -}); - -test('Throw throw true message metaData object', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - params: { throw: true, message: 'My error message', metaData: { key: 'value' } }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Throw', - error: new ThrowActionError('My error message', { - blockId: 'button', - context: context, - metaData: { key: 'value' }, - }), - index: 0, - }, - action: { - id: 'throw', - type: 'Throw', - params: { throw: true, message: 'My error message', metaData: { key: 'value' } }, - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - error: new ThrowActionError('My error message', { - blockId: 'button', - context: context, - metaData: 'Meta string', - }), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "My error message", - "duration": 6, - "status": "error", - }, - ], - ] - `); -}); - -test('Throw throw false', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - params: { throw: false }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - response: undefined, - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: true, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); -}); - -test('Throw throw invalid', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'throw', - type: 'Throw', - params: { throw: 'invalid' }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['block:root:button:0']; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Throw', - error: new Error('Invalid Throw, check action params. Received "{"throw":"invalid"}".'), - index: 0, - }, - action: { - id: 'throw', - type: 'Throw', - params: { throw: 'invalid' }, - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - throw: { - type: 'Throw', - error: new Error('Invalid Throw, check action params. Received "{"throw":"invalid"}".'), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Invalid Throw, check action params. Received \\"{\\"throw\\":\\"invalid\\"}\\".", - "duration": 6, - "status": "error", - }, - ], - ] - `); -}); diff --git a/packages/engine/test/Actions/Validate.test.js b/packages/engine/test/Actions/Validate.test.js deleted file mode 100644 index 106b11d24..000000000 --- a/packages/engine/test/Actions/Validate.test.js +++ /dev/null @@ -1,1196 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -const closeLoader = jest.fn(); -const displayMessage = jest.fn(); -const lowdefy = { - displayMessage, - pageId, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeEach(() => { - displayMessage.mockReset(); - closeLoader.mockReset(); - displayMessage.mockImplementation(() => closeLoader); -}); - -beforeAll(() => { - global.Date = mockDate; -}); - -afterAll(() => { - global.Date = RealDate; -}); - -test('Validate required field', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - required: true, - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text1 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['This field is required'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - type: 'Validate', - }, - error: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Your input has 1 validation error.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: ['This field is required'], - status: 'error', - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Your input has 1 validation error.", - "duration": 6, - "status": "error", - }, - ], - ] - `); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); - text1.setValue('text1'); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - index: 0, - response: undefined, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(displayMessage.mock.calls).toEqual([]); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); -}); - -test('Validate all fields', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'text2', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text2', key: 'text2' } }, - message: 'text2 does not match pattern "text2"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text1, text2 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - type: 'Validate', - }, - error: { - error: new Error('Your input has 2 validation errors.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Your input has 2 validation errors.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: 'error', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: 'error', - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Your input has 2 validation errors.", - "duration": 6, - "status": "error", - }, - ], - ] - `); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); - text1.setValue('text1'); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - type: 'Validate', - }, - error: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Your input has 1 validation error.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: 'error', - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Your input has 1 validation error.", - "duration": 6, - "status": "error", - }, - ], - ] - `); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); - text2.setValue('text2'); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - index: 0, - response: undefined, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); -}); - -test('Validate only one field', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'text2', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text2', key: 'text2' } }, - message: 'text2 does not match pattern "text2"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - params: 'text1', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text1, text2 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - params: 'text1', - type: 'Validate', - }, - error: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Your input has 1 validation error.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: 'error', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: null, - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Your input has 1 validation error.", - "duration": 6, - "status": "error", - }, - ], - ] - `); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); - text1.setValue('text1'); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - index: 0, - response: undefined, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: null, - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); -}); - -test('Validate list of fields', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'text2', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text2', key: 'text2' } }, - message: 'text2 does not match pattern "text2"', - }, - ], - }, - { - blockId: 'text3', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text3', key: 'text3' } }, - message: 'text3 does not match pattern "text3"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - params: ['text1', 'text2'], - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text1, text2, text3 } = context.RootBlocks.map; - text1.setValue('text1'); - expect(text1.eval.validation).toEqual({ - errors: [], - status: null, - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: null, - warnings: [], - }); - expect(text3.eval.validation).toEqual({ - errors: ['text3 does not match pattern "text3"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - params: ['text1', 'text2'], - type: 'Validate', - }, - error: { - error: new Error('Your input has 1 validation error.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Your input has 1 validation error.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Your input has 1 validation error.", - "duration": 6, - "status": "error", - }, - ], - ] - `); - displayMessage.mockReset(); - displayMessage.mockImplementation(() => closeLoader); - text2.setValue('text2'); - expect(text1.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: [], - status: 'success', - warnings: [], - }); - expect(text3.eval.validation).toEqual({ - errors: ['text3 does not match pattern "text3"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - index: 0, - response: undefined, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text3.eval.validation).toEqual({ - errors: ['text3 does not match pattern "text3"'], - status: null, - warnings: [], - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); -}); - -test('Invalid Validate params', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - params: 1, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - error: { - action: { - id: 'validate', - params: 1, - type: 'Validate', - }, - error: { - error: new Error('Invalid validate params.'), - index: 0, - type: 'Validate', - }, - }, - responses: { - validate: { - type: 'Validate', - index: 0, - error: new Error('Invalid validate params.'), - }, - }, - success: false, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(displayMessage.mock.calls).toMatchInlineSnapshot(` - Array [ - Array [ - Object { - "content": "Invalid validate params.", - "duration": 6, - "status": "error", - }, - ], - ] - `); -}); - -test('Validate does not fail on warnings', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - status: 'warning', - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text1 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: [], - status: null, - warnings: ['text1 does not match pattern "text1"'], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - index: 0, - }, - }, - success: true, - startTimestamp: { date: 0 }, - endTimestamp: { date: 0 }, - }); - expect(text1.eval.validation).toEqual({ - errors: [], - status: 'warning', - warnings: ['text1 does not match pattern "text1"'], - }); -}); - -test('Validate on nested objects using params.regex string', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'obj.text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'text2', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text2', key: 'text2' } }, - message: 'text2 does not match pattern "text2"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - params: { - regex: '^obj.*1$', - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, 'obj.text1': text1 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { type: 'Validate', error: new Error('Your input has 1 validation error.'), index: 0 }, - action: { id: 'validate', type: 'Validate', params: { regex: '^obj.*1$' } }, - }, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - error: new Error('Your input has 1 validation error.'), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: 'error', - warnings: [], - }); -}); - -test('Validate on nested objects using params.regex array', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'obj.text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'obj.abc1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'abc1', key: 'abc1' } }, - message: 'abc1 does not match pattern "abc1"', - }, - ], - }, - { - blockId: 'text2', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text2', key: 'text2' } }, - message: 'text2 does not match pattern "text2"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - params: { - regex: ['^obj.*1$'], - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text2, 'obj.text1': text1, 'obj.abc1': abc1 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Validate', - error: new Error('Your input has 2 validation errors.'), - index: 0, - }, - action: { id: 'validate', type: 'Validate', params: { regex: ['^obj.*1$'] } }, - }, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - error: new Error('Your input has 2 validation errors.'), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: 'error', - warnings: [], - }); - expect(abc1.eval.validation).toEqual({ - errors: ['abc1 does not match pattern "abc1"'], - status: 'error', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: null, - warnings: [], - }); -}); - -test('Validate on nested objects using params.regex array and blockIds', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'obj.text1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text1', key: 'text1' } }, - message: 'text1 does not match pattern "text1"', - }, - ], - }, - { - blockId: 'obj.abc1', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'abc1', key: 'abc1' } }, - message: 'abc1 does not match pattern "abc1"', - }, - ], - }, - { - blockId: 'text2', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', - }, - validate: [ - { - pass: { _regex: { pattern: 'text2', key: 'text2' } }, - message: 'text2 does not match pattern "text2"', - }, - ], - }, - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'validate', - type: 'Validate', - params: { - regex: ['^obj.*t1$'], - blockIds: ['text2'], - }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button, text2, 'obj.text1': text1, 'obj.abc1': abc1 } = context.RootBlocks.map; - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: null, - warnings: [], - }); - await button.triggerEvent({ name: 'onClick' }); - expect(button.Events.events.onClick.history[0]).toEqual({ - blockId: 'button', - bounced: false, - error: { - error: { - type: 'Validate', - error: new Error('Your input has 2 validation errors.'), - index: 0, - }, - action: { - id: 'validate', - type: 'Validate', - params: { regex: ['^obj.*t1$'], blockIds: ['text2'] }, - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - validate: { - type: 'Validate', - error: new Error('Your input has 2 validation errors.'), - index: 0, - }, - }, - endTimestamp: { date: 0 }, - startTimestamp: { date: 0 }, - success: false, - }); - expect(text1.eval.validation).toEqual({ - errors: ['text1 does not match pattern "text1"'], - status: 'error', - warnings: [], - }); - expect(text2.eval.validation).toEqual({ - errors: ['text2 does not match pattern "text2"'], - status: 'error', - warnings: [], - }); - expect(abc1.eval.validation).toEqual({ - errors: ['abc1 does not match pattern "abc1"'], - status: null, - warnings: [], - }); -}); diff --git a/packages/engine/test/Actions/Wait.test.js b/packages/engine/test/Actions/Wait.test.js deleted file mode 100644 index 589bfcd64..000000000 --- a/packages/engine/test/Actions/Wait.test.js +++ /dev/null @@ -1,157 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import testContext from '../testContext.js'; - -const pageId = 'one'; - -const lowdefy = { - auth: { - login: jest.fn(), - }, - pageId, -}; - -const RealDate = Date; -const mockDate = jest.fn(() => ({ date: 0 })); -mockDate.now = jest.fn(() => 0); - -// Comment out to use console -console.log = () => {}; -console.error = () => {}; - -beforeEach(() => { - global.Date = mockDate; - lowdefy.auth.login.mockReset(); -}); - -afterAll(() => { - global.Date = RealDate; -}); - -const timeout = (ms) => { - return new Promise((resolve) => setTimeout(resolve, ms)); -}; - -test('Wait', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Wait', - params: { ms: 500 }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - let resolved = false; - button.triggerEvent({ name: 'onClick' }).then(() => { - resolved = true; - }); - expect(resolved).toBe(false); - await timeout(100); - expect(resolved).toBe(false); - await timeout(300); - expect(resolved).toBe(false); - await timeout(150); - expect(resolved).toBe(true); -}); - -test('Wait ms not a integer', async () => { - const rootBlock = { - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Wait', - params: { ms: 1.1 }, - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const { button } = context.RootBlocks.map; - const res = await button.triggerEvent({ name: 'onClick' }); - expect(res).toEqual({ - blockId: 'button', - bounced: false, - endTimestamp: { date: 0 }, - error: { - action: { id: 'a', params: { ms: 1.1 }, type: 'Wait' }, - error: { - error: new Error('Wait action "ms" param should be an integer.'), - index: 0, - type: 'Wait', - }, - }, - event: undefined, - eventName: 'onClick', - responses: { - a: { - error: new Error('Wait action "ms" param should be an integer.'), - index: 0, - type: 'Wait', - }, - }, - startTimestamp: { date: 0 }, - success: false, - }); -}); From ddd849e2de6b9691041d098fe53ace1db5940451 Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 16:31:33 +0200 Subject: [PATCH 17/79] fix(engine): Updated callMethod action method to use action & block plugin config. --- .../engine/src/actions/callMethod.test.js | 606 ++++++++++++++++++ 1 file changed, 606 insertions(+) create mode 100644 packages/engine/src/actions/callMethod.test.js diff --git a/packages/engine/src/actions/callMethod.test.js b/packages/engine/src/actions/callMethod.test.js new file mode 100644 index 000000000..55ea44c39 --- /dev/null +++ b/packages/engine/src/actions/callMethod.test.js @@ -0,0 +1,606 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + CallMethod: ({ methods: { callMethod }, params }) => { + return callMethod(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + List: { meta: { category: 'list' } }, + TextInput: { meta: { category: 'input' } }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('CallMethod with no args, synchronous method', async () => { + const blockMethod = jest.fn((...args) => ({ args })); + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'blockMethod' }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock: rootBlock, + initState: { textInput: 'init' }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; + textInput.registerMethod('blockMethod', blockMethod); + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + type: 'CallMethod', + index: 0, + response: { + args: [], + }, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(blockMethod.mock.calls).toEqual([[]]); +}); + +test('CallMethod method return a promise', async () => { + const timeout = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); + }; + const calls = []; + const blockMethod = async (...args) => { + calls.push(args); + await timeout(300); + return { args }; + }; + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'blockMethod', args: ['arg'] }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; + textInput.registerMethod('blockMethod', blockMethod); + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + type: 'CallMethod', + index: 0, + response: { + args: ['arg'], + }, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(calls).toEqual([['arg']]); +}); + +test('CallMethod with args not an array', async () => { + const blockMethod = jest.fn((...args) => ({ args })); + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'blockMethod', args: 'arg' }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; + textInput.registerMethod('blockMethod', blockMethod); + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + args: 'arg', + blockId: 'block:root:textInput:0', + method: 'blockMethod', + }, + type: 'CallMethod', + }, + error: { + error: new Error( + 'Failed to call method "blockMethod" on block "block:root:textInput:0": "args" should be an array. Received "{"blockId":"block:root:textInput:0","method":"blockMethod","args":"arg"}".' + ), + index: 0, + type: 'CallMethod', + }, + }, + responses: { + a: { + type: 'CallMethod', + index: 0, + error: new Error( + 'Failed to call method "blockMethod" on block "block:root:textInput:0": "args" should be an array. Received "{"blockId":"block:root:textInput:0","method":"blockMethod","args":"arg"}".' + ), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(blockMethod.mock.calls).toEqual([]); +}); + +test('CallMethod with multiple positional args, synchronous method', async () => { + const blockMethod = jest.fn((...args) => ({ args })); + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:textInput:0', + method: 'blockMethod', + args: ['arg1', 'arg2'], + }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; + textInput.registerMethod('blockMethod', blockMethod); + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + type: 'CallMethod', + index: 0, + response: { + args: ['arg1', 'arg2'], + }, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(blockMethod.mock.calls).toEqual([['arg1', 'arg2']]); +}); + +test('CallMethod of block in array by explicit id', async () => { + const blockMethod0 = jest.fn((...args) => ({ args })); + const blockMethod1 = jest.fn((...args) => ({ args })); + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:list:0', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:list.$.textInput:0', + blockId: 'list.$.textInput', + type: 'TextInput', + defaultValue: '123', + meta: { + category: 'input', + valueType: 'string', + }, + }, + ], + }, + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:list.0.textInput:0', + method: 'blockMethod', + args: ['arg'], + }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { list: [{ textInput: '0' }, { textInput: '1' }] }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput0 = context._internal.RootBlocks.map['block:root:list.0.textInput:0']; + const textInput1 = context._internal.RootBlocks.map['block:root:list.1.textInput:0']; + textInput0.registerMethod('blockMethod', blockMethod0); + textInput1.registerMethod('blockMethod', blockMethod1); + await button.triggerEvent({ name: 'onClick' }); + expect(blockMethod0.mock.calls).toEqual([['arg']]); + expect(blockMethod1.mock.calls).toEqual([]); +}); + +test('CallMethod of block in array by block with same indices and id pattern', async () => { + const blockMethod0 = jest.fn((...args) => ({ args })); + const blockMethod1 = jest.fn((...args) => ({ args })); + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:list:0', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:list.$.textInput:0', + blockId: 'list.$.textInput', + type: 'TextInput', + defaultValue: '123', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:list.$.button:0', + blockId: 'list.$.button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:list.$.textInput:0', + method: 'blockMethod', + args: ['arg'], + }, + }, + ], + }, + }, + ], + }, + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { list: [{ textInput: '0' }, { textInput: '1' }] }, + }); + const textInput0 = context._internal.RootBlocks.map['block:root:list.0.textInput:0']; + const textInput1 = context._internal.RootBlocks.map['block:root:list.1.textInput:0']; + const button0 = context._internal.RootBlocks.map['block:root:list.0.button:0']; + const button1 = context._internal.RootBlocks.map['block:root:list.1.button:0']; + textInput0.registerMethod('blockMethod', blockMethod0); + textInput1.registerMethod('blockMethod', blockMethod1); + await button1.triggerEvent({ name: 'onClick' }); + expect(blockMethod0.mock.calls).toEqual([]); + expect(blockMethod1.mock.calls).toEqual([['arg']]); + await button0.triggerEvent({ name: 'onClick' }); + expect(blockMethod0.mock.calls).toEqual([['arg']]); + expect(blockMethod1.mock.calls).toEqual([['arg']]); +}); + +test('CallMethod with method does not exist', async () => { + const blockMethod = jest.fn((...args) => ({ args })); + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + type: 'TextInput', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'no-method' }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + blockId: 'block:root:textInput:0', + method: 'no-method', + }, + type: 'CallMethod', + }, + error: { + error: new Error( + 'Failed to call method "no-method" on block "block:root:textInput:0". Check if "no-method" is a valid block method for block "block:root:textInput:0". Received "{"blockId":"block:root:textInput:0","method":"no-method"}".' + ), + index: 0, + type: 'CallMethod', + }, + }, + responses: { + a: { + type: 'CallMethod', + index: 0, + error: new Error( + 'Failed to call method "no-method" on block "block:root:textInput:0". Check if "no-method" is a valid block method for block "block:root:textInput:0". Received "{"blockId":"block:root:textInput:0","method":"no-method"}".' + ), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(blockMethod.mock.calls).toEqual([]); +}); From c8524c6742d3f45109f15ace6e2d84b6114b92d8 Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 16:33:57 +0200 Subject: [PATCH 18/79] fix(engine): Updated testContext to use rootBlock config. --- packages/engine/test/testContext.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/test/testContext.js b/packages/engine/test/testContext.js index 3db82e74c..45862f7ba 100644 --- a/packages/engine/test/testContext.js +++ b/packages/engine/test/testContext.js @@ -50,7 +50,7 @@ const testContext = async ({ lowdefy, operators, rootBlock, initState = {} }) => _internal.Actions = new Actions(ctx); _internal.Requests = new Requests(ctx); _internal.RootBlocks = new Blocks({ - areas: { root: { blocks: [_internal.rootBlock] } }, + areas: _internal.rootBlock, context: ctx, }); _internal.RootBlocks.init(); From 3bc1fa46bb5a1837bedb60079326559cbb961b9a Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 16:43:55 +0200 Subject: [PATCH 19/79] chore(engine): Updated callMethod action method to use action & block plugin config. --- packages/engine/src/actions/callMethod.test.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/packages/engine/src/actions/callMethod.test.js b/packages/engine/src/actions/callMethod.test.js index 55ea44c39..82ba43feb 100644 --- a/packages/engine/src/actions/callMethod.test.js +++ b/packages/engine/src/actions/callMethod.test.js @@ -52,7 +52,6 @@ test('CallMethod with no args, synchronous method', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, @@ -131,7 +130,6 @@ test('CallMethod method return a promise', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, @@ -202,7 +200,6 @@ test('CallMethod with args not an array', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, @@ -291,7 +288,6 @@ test('CallMethod with multiple positional args, synchronous method', async () => const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, @@ -367,7 +363,6 @@ test('CallMethod of block in array by explicit id', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, @@ -444,7 +439,6 @@ test('CallMethod of block in array by block with same indices and id pattern', a const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, @@ -524,7 +518,6 @@ test('CallMethod with method does not exist', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', - type: 'TextInput', meta: { category: 'container', }, From 1306698ebbd9fe6b41c77628da70c2b7f95a4e13 Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 17:00:44 +0200 Subject: [PATCH 20/79] fix(engine): Updated link action method test to use action & block plugin config. --- packages/engine/src/actions/link.js | 2 +- packages/engine/src/actions/link.test.js | 197 +++++++++++++++++++++++ 2 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 packages/engine/src/actions/link.test.js diff --git a/packages/engine/src/actions/link.js b/packages/engine/src/actions/link.js index cdd863585..c3b7ef57e 100644 --- a/packages/engine/src/actions/link.js +++ b/packages/engine/src/actions/link.js @@ -15,7 +15,7 @@ */ function createLink({ context }) { - return function link({ params }) { + return function link(params) { context._internal.lowdefy._internal.link(params); }; } diff --git a/packages/engine/src/actions/link.test.js b/packages/engine/src/actions/link.test.js new file mode 100644 index 000000000..21437bd34 --- /dev/null +++ b/packages/engine/src/actions/link.test.js @@ -0,0 +1,197 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Link: ({ methods: { link }, params }) => { + return link(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + List: { meta: { category: 'list' } }, + TextInput: { meta: { category: 'input' } }, + }, + link: jest.fn(), + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; + lowdefy._internal.link.mockReset(); +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('Link with string pageId params', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Link', params: 'pageId' }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(lowdefy._internal.link.mock.calls).toEqual([['pageId']]); + expect(res.success).toBe(true); +}); + +test('Link with object params', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Link', params: { pageId: 'pageId', newTab: true } }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(lowdefy._internal.link.mock.calls).toEqual([ + [ + { + pageId: 'pageId', + newTab: true, + }, + ], + ]); + expect(res.success).toBe(true); +}); + +test('Link error', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Link', params: { invalid: true } }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + lowdefy._internal.link.mockImplementationOnce(() => { + throw new Error('Link test error'); + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(lowdefy._internal.link.mock.calls).toEqual([ + [ + { + invalid: true, + }, + ], + ]); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + invalid: true, + }, + type: 'Link', + }, + error: { + error: new Error('Link test error'), + index: 0, + type: 'Link', + }, + }, + responses: { + a: { + type: 'Link', + error: new Error('Link test error'), + index: 0, + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); +}); From 4cbd863cfe8f2b325dc3e9bea4d54d1f4c1d97b7 Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 17:10:38 +0200 Subject: [PATCH 21/79] fix(engine): Updated login action method test to use action & block plugin config. --- packages/engine/src/actions/login.test.js | 93 +++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 packages/engine/src/actions/login.test.js diff --git a/packages/engine/src/actions/login.test.js b/packages/engine/src/actions/login.test.js new file mode 100644 index 000000000..ac807817c --- /dev/null +++ b/packages/engine/src/actions/login.test.js @@ -0,0 +1,93 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Login: ({ methods: { login }, params }) => { + return login(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + auth: { + login: jest.fn(), + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +beforeEach(() => { + global.Date = mockDate; + lowdefy._internal.auth.login.mockReset(); +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('Login', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Login', + params: { input: { i: true }, pageId: 'pageId', urlQuery: { u: true } }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(lowdefy._internal.auth.login.mock.calls).toEqual([ + [ + { + input: { i: true }, + pageId: 'pageId', + urlQuery: { u: true }, + }, + ], + ]); + expect(res.success).toBe(true); +}); From e120fe88beb39fb59661151c15429c4d926782be Mon Sep 17 00:00:00 2001 From: Sandile Date: Wed, 9 Feb 2022 17:17:55 +0200 Subject: [PATCH 22/79] fix(engine): Updated logout action method test to use action & block plugin config. --- packages/engine/src/actions/logout.test.js | 84 ++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 packages/engine/src/actions/logout.test.js diff --git a/packages/engine/src/actions/logout.test.js b/packages/engine/src/actions/logout.test.js new file mode 100644 index 000000000..3b6717f88 --- /dev/null +++ b/packages/engine/src/actions/logout.test.js @@ -0,0 +1,84 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Logout: ({ methods: { logout } }) => { + return logout(); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + auth: { + logout: jest.fn(), + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +beforeEach(() => { + global.Date = mockDate; + lowdefy._internal.auth.logout.mockReset(); +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('Logout', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Logout', + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(lowdefy._internal.auth.logout.mock.calls).toEqual([[]]); + expect(res.success).toBe(true); +}); From 48cd2515e51ba769437dd3509f55b68f571a0757 Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 10:10:34 +0200 Subject: [PATCH 23/79] fix(engine): Updated message action method test to use action & block plugin config. --- .pnp.cjs | 6 +- packages/engine/src/actions/message.test.js | 176 ++++++++++++++++++++ yarn.lock | 6 +- 3 files changed, 182 insertions(+), 6 deletions(-) create mode 100644 packages/engine/src/actions/message.test.js diff --git a/.pnp.cjs b/.pnp.cjs index 9fce54d5d..b8b06183e 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2792,7 +2792,10 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/plugins/actions/actions-core/", "packageDependencies": [ ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], + ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], + ["@lowdefy/engine", "workspace:packages/engine"], ["@lowdefy/helpers", "workspace:packages/utils/helpers"], + ["@lowdefy/operators", "workspace:packages/operators"], ["@swc/cli", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.1.55"], ["@swc/core", "npm:1.2.135"], ["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"], @@ -3506,10 +3509,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/server/", "packageDependencies": [ ["@lowdefy/server", "workspace:packages/server"], - ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@lowdefy/api", "workspace:packages/api"], ["@lowdefy/block-utils", "workspace:packages/utils/block-utils"], - ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], ["@lowdefy/build", "workspace:packages/build"], ["@lowdefy/engine", "workspace:packages/engine"], ["@lowdefy/helpers", "workspace:packages/utils/helpers"], @@ -3535,7 +3536,6 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/server-dev/", "packageDependencies": [ ["@lowdefy/server-dev", "workspace:packages/server-dev"], - ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@lowdefy/api", "workspace:packages/api"], ["@lowdefy/block-utils", "workspace:packages/utils/block-utils"], ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], diff --git a/packages/engine/src/actions/message.test.js b/packages/engine/src/actions/message.test.js new file mode 100644 index 000000000..6df7e2d17 --- /dev/null +++ b/packages/engine/src/actions/message.test.js @@ -0,0 +1,176 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +// Mock message +const mockMessage = jest.fn(() => () => undefined); + +const lowdefy = { + _internal: { + actions: { + Message: ({ methods: { message }, params }) => { + return message(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + displayMessage: mockMessage, + }, +}; + +test('Message with content', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Message', + params: { content: 'test' }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockMessage.mock.calls).toEqual([ + [ + { + content: 'test', + }, + ], + ]); +}); + +test('Message with all params', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Message', + params: { + content: 'content', + duration: 6, + icon: 'FireOutlined', + status: 'error', + }, + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockMessage.mock.calls).toEqual([ + [ + { + content: 'content', + duration: 6, + icon: 'FireOutlined', + status: 'error', + }, + ], + ]); +}); + +test('Message with no params', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Message', + }, + ], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockMessage.mock.calls).toEqual([ + [ + { + content: 'Success', + }, + ], + ]); +}); diff --git a/yarn.lock b/yarn.lock index 99a56e298..0edbec2ef 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1956,7 +1956,10 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/actions-core@workspace:packages/plugins/actions/actions-core" dependencies: + "@lowdefy/blocks-antd": 4.0.0-alpha.6 + "@lowdefy/engine": 4.0.0-alpha.6 "@lowdefy/helpers": 4.0.0-alpha.6 + "@lowdefy/operators": 4.0.0-alpha.6 "@swc/cli": 0.1.55 "@swc/core": 1.2.135 "@swc/jest": 0.2.17 @@ -2598,7 +2601,6 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/server-dev@workspace:packages/server-dev" dependencies: - "@lowdefy/actions-core": 4.0.0-alpha.6 "@lowdefy/api": 4.0.0-alpha.6 "@lowdefy/block-utils": 4.0.0-alpha.6 "@lowdefy/blocks-antd": 4.0.0-alpha.6 @@ -2642,10 +2644,8 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/server@workspace:packages/server" dependencies: - "@lowdefy/actions-core": 4.0.0-alpha.6 "@lowdefy/api": 4.0.0-alpha.6 "@lowdefy/block-utils": 4.0.0-alpha.6 - "@lowdefy/blocks-antd": 4.0.0-alpha.6 "@lowdefy/build": 4.0.0-alpha.6 "@lowdefy/engine": 4.0.0-alpha.6 "@lowdefy/helpers": 4.0.0-alpha.6 From d2bd2f5fc207eeb15ec86559dc4bec726e037071 Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 12:51:35 +0200 Subject: [PATCH 24/79] fix(engine): Updated request action method test to use action & block plugin config. --- packages/engine/src/Requests.js | 2 +- packages/engine/src/actions/request.test.js | 400 ++++++++++++++++++++ 2 files changed, 401 insertions(+), 1 deletion(-) create mode 100644 packages/engine/src/actions/request.test.js diff --git a/packages/engine/src/Requests.js b/packages/engine/src/Requests.js index d7d83aeb8..87654d53d 100644 --- a/packages/engine/src/Requests.js +++ b/packages/engine/src/Requests.js @@ -31,7 +31,7 @@ class Requests { } callRequests({ actions, arrayIndices, event, params } = {}) { - if (params.all === true) { + if (type.isObject(params) && params.all === true) { return Promise.all( Object.keys(this.requestConfig).map((requestId) => this.callRequest({ requestId, event, arrayIndices }) diff --git a/packages/engine/src/actions/request.test.js b/packages/engine/src/actions/request.test.js new file mode 100644 index 000000000..1203f28bf --- /dev/null +++ b/packages/engine/src/actions/request.test.js @@ -0,0 +1,400 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +// Mock apollo client +const mockReqResponses = { + req_one: { + id: 'req_one', + success: true, + response: 1, + }, + req_two: { + id: 'req_two', + success: true, + response: 2, + }, + req_error: new Error('Request error'), +}; + +const mockCallRequest = jest.fn(); +const mockCallRequestImp = ({ requestId }) => { + if (requestId === 'req_error') throw mockReqResponses['req_error']; + return mockReqResponses[requestId]; +}; + +const lowdefy = { + _internal: { + actions: { + Request: ({ methods: { request }, params }) => { + return request(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + callRequest: mockCallRequest, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +beforeEach(() => { + mockCallRequest.mockReset(); + mockCallRequest.mockImplementation(mockCallRequestImp); +}); + +test('Request call one request', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: 'req_one' }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const promise = button.triggerEvent({ name: 'onClick' }); + expect(context.requests.req_one).toEqual({ + error: [], + loading: true, + response: null, + }); + const res = await promise; + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + type: 'Request', + index: 0, + response: [1], + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); +}); + +test('Request call all requests', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + { + requestId: 'req_two', + }, + ], + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: { all: true } }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const promise = button.triggerEvent({ name: 'onClick' }); + expect(context.requests).toEqual({ + req_one: { + error: [], + loading: true, + response: null, + }, + req_two: { + error: [], + loading: true, + response: null, + }, + }); + const res = await promise; + expect(context.requests).toEqual({ + req_one: { + error: [], + loading: false, + response: 1, + }, + req_two: { + error: [], + loading: false, + response: 2, + }, + }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + type: 'Request', + index: 0, + response: [1, 2], + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); +}); + +test('Request call array of requests', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + { + requestId: 'req_two', + }, + ], + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: ['req_one', 'req_two'] }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const promise = button.triggerEvent({ name: 'onClick' }); + expect(context.requests).toEqual({ + req_one: { + error: [], + loading: true, + response: null, + }, + req_two: { + error: [], + loading: true, + response: null, + }, + }); + const res = await promise; + expect(context.requests).toEqual({ + req_one: { + error: [], + loading: false, + response: 1, + }, + req_two: { + error: [], + loading: false, + response: 2, + }, + }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + type: 'Request', + index: 0, + response: [1, 2], + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); +}); + +test('Request pass if params are none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + { + requestId: 'req_two', + }, + ], + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request' }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(context.requests).toEqual({}); +}); + +test('Request call request error', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_error', + }, + ], + areas: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: 'req_error' }], + }, + }, + ], + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(context.requests.req_error).toEqual({ + error: [new Error('Request error')], + loading: false, + response: null, + }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: 'req_error', + type: 'Request', + }, + error: { + error: new Error('Request error'), + index: 0, + type: 'Request', + }, + }, + responses: { + a: { + type: 'Request', + index: 0, + error: new Error('Request error'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); +}); From 328c579386003f707df4c2c3e787947c4514c865 Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 13:26:07 +0200 Subject: [PATCH 25/79] chore(engine): Update areas param for Blocks in testContext. --- .../engine/src/actions/callMethod.test.js | 466 +++++++++--------- packages/engine/src/actions/link.test.js | 84 ++-- packages/engine/src/actions/login.test.js | 40 +- packages/engine/src/actions/logout.test.js | 38 +- packages/engine/src/actions/message.test.js | 126 ++--- packages/engine/src/actions/request.test.js | 144 +++--- packages/engine/test/testContext.js | 2 +- 7 files changed, 472 insertions(+), 428 deletions(-) diff --git a/packages/engine/src/actions/callMethod.test.js b/packages/engine/src/actions/callMethod.test.js index 82ba43feb..c3271809d 100644 --- a/packages/engine/src/actions/callMethod.test.js +++ b/packages/engine/src/actions/callMethod.test.js @@ -56,35 +56,37 @@ test('CallMethod with no args, synchronous method', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'blockMethod' }, + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'blockMethod' }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -134,35 +136,41 @@ test('CallMethod method return a promise', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:textInput:0', + method: 'blockMethod', + args: ['arg'], + }, + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'blockMethod', args: ['arg'] }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -204,35 +212,37 @@ test('CallMethod with args not an array', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'blockMethod', args: 'arg' }, + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'blockMethod', args: 'arg' }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -292,39 +302,41 @@ test('CallMethod with multiple positional args, synchronous method', async () => category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { - blockId: 'block:root:textInput:0', - method: 'blockMethod', - args: ['arg1', 'arg2'], + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:textInput:0', + method: 'blockMethod', + args: ['arg1', 'arg2'], + }, }, - }, - ], + ], + }, }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -367,55 +379,57 @@ test('CallMethod of block in array by explicit id', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:list:0', - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', + content: { + blocks: [ + { + id: 'block:root:list:0', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:list.$.textInput:0', + blockId: 'list.$.textInput', + type: 'TextInput', + defaultValue: '123', + meta: { + category: 'input', + valueType: 'string', + }, + }, + ], + }, + }, }, - areas: { - content: { - blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ { - id: 'block:root:list.$.textInput:0', - blockId: 'list.$.textInput', - type: 'TextInput', - defaultValue: '123', - meta: { - category: 'input', - valueType: 'string', + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:list.0.textInput:0', + method: 'blockMethod', + args: ['arg'], }, }, ], }, }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { - blockId: 'block:root:list.0.textInput:0', - method: 'blockMethod', - args: ['arg'], - }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -443,55 +457,57 @@ test('CallMethod of block in array by block with same indices and id pattern', a category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:list:0', - blockId: 'list', - type: 'List', - meta: { - category: 'list', - valueType: 'array', - }, - areas: { - content: { - blocks: [ - { - id: 'block:root:list.$.textInput:0', - blockId: 'list.$.textInput', - type: 'TextInput', - defaultValue: '123', - meta: { - category: 'input', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:list:0', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:list.$.textInput:0', + blockId: 'list.$.textInput', + type: 'TextInput', + defaultValue: '123', + meta: { + category: 'input', + valueType: 'string', + }, }, - }, - { - id: 'block:root:list.$.button:0', - blockId: 'list.$.button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { - blockId: 'block:root:list.$.textInput:0', - method: 'blockMethod', - args: ['arg'], + { + id: 'block:root:list.$.button:0', + blockId: 'list.$.button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { + blockId: 'block:root:list.$.textInput:0', + method: 'blockMethod', + args: ['arg'], + }, }, - }, - ], + ], + }, }, - }, - ], + ], + }, }, }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -522,35 +538,37 @@ test('CallMethod with method does not exist', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:textInput:0', - blockId: 'textInput', - type: 'TextInput', - meta: { - category: 'input', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, }, - }, - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'CallMethod', + params: { blockId: 'block:root:textInput:0', method: 'no-method' }, + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'no-method' }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ diff --git a/packages/engine/src/actions/link.test.js b/packages/engine/src/actions/link.test.js index 21437bd34..551e7464b 100644 --- a/packages/engine/src/actions/link.test.js +++ b/packages/engine/src/actions/link.test.js @@ -57,20 +57,22 @@ test('Link with string pageId params', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Link', params: 'pageId' }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Link', params: 'pageId' }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -91,20 +93,22 @@ test('Link with object params', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Link', params: { pageId: 'pageId', newTab: true } }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Link', params: { pageId: 'pageId', newTab: true } }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -132,20 +136,22 @@ test('Link error', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Link', params: { invalid: true } }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Link', params: { invalid: true } }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ diff --git a/packages/engine/src/actions/login.test.js b/packages/engine/src/actions/login.test.js index ac807817c..ebdf4b1af 100644 --- a/packages/engine/src/actions/login.test.js +++ b/packages/engine/src/actions/login.test.js @@ -52,26 +52,28 @@ test('Login', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Login', + params: { input: { i: true }, pageId: 'pageId', urlQuery: { u: true } }, + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'Login', - params: { input: { i: true }, pageId: 'pageId', urlQuery: { u: true } }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ diff --git a/packages/engine/src/actions/logout.test.js b/packages/engine/src/actions/logout.test.js index 3b6717f88..10c98c0ac 100644 --- a/packages/engine/src/actions/logout.test.js +++ b/packages/engine/src/actions/logout.test.js @@ -52,25 +52,27 @@ test('Logout', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Logout', + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'Logout', - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ diff --git a/packages/engine/src/actions/message.test.js b/packages/engine/src/actions/message.test.js index 6df7e2d17..8750e2210 100644 --- a/packages/engine/src/actions/message.test.js +++ b/packages/engine/src/actions/message.test.js @@ -41,26 +41,28 @@ test('Message with content', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Message', + params: { content: 'test' }, + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'Message', - params: { content: 'test' }, - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -86,31 +88,33 @@ test('Message with all params', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', - }, - events: { - onClick: [ - { - id: 'a', - type: 'Message', - params: { - content: 'content', - duration: 6, - icon: 'FireOutlined', - status: 'error', + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Message', + params: { + content: 'content', + duration: 6, + icon: 'FireOutlined', + status: 'error', + }, }, - }, - ], + ], + }, }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -139,25 +143,27 @@ test('Message with no params', async () => { category: 'container', }, areas: { - blocks: [ - { - id: 'block:root:button:0', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Message', + }, + ], + }, }, - events: { - onClick: [ - { - id: 'a', - type: 'Message', - }, - ], - }, - }, - ], + ], + }, }, }; const context = await testContext({ diff --git a/packages/engine/src/actions/request.test.js b/packages/engine/src/actions/request.test.js index 1203f28bf..2df56f03e 100644 --- a/packages/engine/src/actions/request.test.js +++ b/packages/engine/src/actions/request.test.js @@ -56,8 +56,8 @@ const mockDate = jest.fn(() => ({ date: 0 })); mockDate.now = jest.fn(() => 0); // Comment out to use console -console.log = () => {}; -console.error = () => {}; +// console.log = () => {}; +// console.error = () => {}; beforeAll(() => { global.Date = mockDate; @@ -84,20 +84,22 @@ test('Request call one request', async () => { }, ], areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: 'req_one' }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Request', params: 'req_one' }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -145,20 +147,22 @@ test('Request call all requests', async () => { }, ], areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: { all: true } }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Request', params: { all: true } }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -225,20 +229,22 @@ test('Request call array of requests', async () => { }, ], areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: ['req_one', 'req_two'] }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Request', params: ['req_one', 'req_two'] }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -305,20 +311,22 @@ test('Request pass if params are none', async () => { }, ], areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request' }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Request' }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ @@ -342,20 +350,22 @@ test('Request call request error', async () => { }, ], areas: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - valueType: 'string', + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Request', params: 'req_error' }], + }, }, - events: { - onClick: [{ id: 'a', type: 'Request', params: 'req_error' }], - }, - }, - ], + ], + }, }, }; const context = await testContext({ diff --git a/packages/engine/test/testContext.js b/packages/engine/test/testContext.js index 45862f7ba..4e45cdf32 100644 --- a/packages/engine/test/testContext.js +++ b/packages/engine/test/testContext.js @@ -50,7 +50,7 @@ const testContext = async ({ lowdefy, operators, rootBlock, initState = {} }) => _internal.Actions = new Actions(ctx); _internal.Requests = new Requests(ctx); _internal.RootBlocks = new Blocks({ - areas: _internal.rootBlock, + areas: _internal.rootBlock.areas, context: ctx, }); _internal.RootBlocks.init(); From d46add8f05279253cf99955315e6acda9b42a516 Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 13:43:17 +0200 Subject: [PATCH 26/79] fix(engine): Updated reset action method test to use action & block plugin config. --- packages/engine/src/actions/reset.test.js | 209 ++++++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 packages/engine/src/actions/reset.test.js diff --git a/packages/engine/src/actions/reset.test.js b/packages/engine/src/actions/reset.test.js new file mode 100644 index 000000000..327a10f9d --- /dev/null +++ b/packages/engine/src/actions/reset.test.js @@ -0,0 +1,209 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Reset: ({ methods: { reset } }) => { + return reset(); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + List: { meta: { category: 'list', valueType: 'array' } }, + TextInput: { meta: { category: 'input', valueType: 'string' } }, + }, + }, +}; + +test('Reset one field', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'textInput', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Reset' }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + expect(context.state).toEqual({ textInput: 'init' }); + const button = context._internal.RootBlocks.map['button']; + const textInput = context._internal.RootBlocks.map['textInput']; + textInput.setValue('1'); + expect(context.state).toEqual({ textInput: '1' }); + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ textInput: 'init' }); +}); + +test('Reset on primitive array after adding item', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'list', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'list.$', + blockId: 'list.$', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + ], + }, + }, + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Reset' }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { list: ['init'] }, + }); + expect(context.state).toEqual({ list: ['init'] }); + const button = context._internal.RootBlocks.map['button']; + const list = context._internal.RootBlocks.map['list']; + list.pushItem(); + expect(context.state).toEqual({ list: ['init', null] }); + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ list: ['init'] }); +}); + +test('Reset on object array after removing item', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'list', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'list.$.textInput', + blockId: 'list.$.textInput', + type: 'TextInput', + defaultValue: '123', + meta: { + category: 'input', + valueType: 'string', + }, + }, + ], + }, + }, + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'Reset' }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { list: [{ textInput: 'init' }] }, + }); + + const button = context._internal.RootBlocks.map['button']; + const list = context._internal.RootBlocks.map['list']; + + expect(context.state).toEqual({ list: [{ textInput: 'init' }] }); + list.removeItem(0); + expect(context.state).toEqual({ list: [] }); + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ list: [{ textInput: 'init' }] }); +}); From 576e3a9fe8234a61ed5f3237ea44cc309e4cb27d Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 15:35:17 +0200 Subject: [PATCH 27/79] fix(engine): Fixed validate action method context reference. --- .pnp.cjs | 3 --- packages/engine/src/actions/validate.js | 2 +- yarn.lock | 3 --- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/.pnp.cjs b/.pnp.cjs index b8b06183e..8a227abe0 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2792,10 +2792,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/plugins/actions/actions-core/", "packageDependencies": [ ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], - ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], - ["@lowdefy/engine", "workspace:packages/engine"], ["@lowdefy/helpers", "workspace:packages/utils/helpers"], - ["@lowdefy/operators", "workspace:packages/operators"], ["@swc/cli", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.1.55"], ["@swc/core", "npm:1.2.135"], ["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"], diff --git a/packages/engine/src/actions/validate.js b/packages/engine/src/actions/validate.js index 1e912aa3f..384609fa2 100644 --- a/packages/engine/src/actions/validate.js +++ b/packages/engine/src/actions/validate.js @@ -18,7 +18,7 @@ import getBlockMatcher from '../getBlockMatcher.js'; function createValidate({ context }) { return function validate(params) { - const validationErrors = context.RootBlocks.validate(getBlockMatcher(params)); + const validationErrors = context._internal.RootBlocks.validate(getBlockMatcher(params)); if (validationErrors.length > 0) { const error = new Error( `Your input has ${validationErrors.length} validation error${ diff --git a/yarn.lock b/yarn.lock index 0edbec2ef..b91a4f965 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1956,10 +1956,7 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/actions-core@workspace:packages/plugins/actions/actions-core" dependencies: - "@lowdefy/blocks-antd": 4.0.0-alpha.6 - "@lowdefy/engine": 4.0.0-alpha.6 "@lowdefy/helpers": 4.0.0-alpha.6 - "@lowdefy/operators": 4.0.0-alpha.6 "@swc/cli": 0.1.55 "@swc/core": 1.2.135 "@swc/jest": 0.2.17 From 107a1a50000d9ca731370cc41bca2e5f7d564bad Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 15:35:51 +0200 Subject: [PATCH 28/79] fix(engine): Updated resetValidation action method test to use new plugin config. --- .../src/actions/resetValidation.test.js | 261 ++++++++++++++++++ 1 file changed, 261 insertions(+) create mode 100644 packages/engine/src/actions/resetValidation.test.js diff --git a/packages/engine/src/actions/resetValidation.test.js b/packages/engine/src/actions/resetValidation.test.js new file mode 100644 index 000000000..f20274396 --- /dev/null +++ b/packages/engine/src/actions/resetValidation.test.js @@ -0,0 +1,261 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { get, type } from '@lowdefy/helpers'; + +import testContext from '../../test/testContext.js'; + +const closeLoader = jest.fn(); +const displayMessage = jest.fn(); +const lowdefy = { + _internal: { + actions: { + ResetValidation: ({ methods: { resetValidation }, params }) => { + return resetValidation(params); + }, + Validate: ({ methods: { validate }, params }) => { + return validate(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + TextInput: { meta: { category: 'input', valueType: 'string' } }, + }, + displayMessage, + operators: { + _not: ({ params }) => { + return !params; + }, + _type: ({ location, params, state }) => { + const typeName = type.isObject(params) ? params.type : params; + if (!type.isString(typeName)) { + throw new Error( + `Operator Error: _type.type must be a string. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + const on = Object.prototype.hasOwnProperty.call(params, 'on') + ? params.on + : get(state, get(params, 'key', { default: location })); + switch (typeName) { + case 'string': + return type.isString(on); + case 'array': + return type.isArray(on); + case 'date': + return type.isDate(on); // Testing for date is problematic due to stringify + case 'object': + return type.isObject(on); + case 'boolean': + return type.isBoolean(on); + case 'number': + return type.isNumber(on); + case 'integer': + return type.isInt(on); + case 'null': + return type.isNull(on); + case 'undefined': + return type.isUndefined(on); + case 'none': + return type.isNone(on); + case 'primitive': + return type.isPrimitive(on); + default: + throw new Error( + `Operator Error: "${typeName}" is not a valid _type test. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + displayMessage.mockReset(); + closeLoader.mockReset(); + displayMessage.mockImplementation(() => closeLoader); +}); + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('RestValidation after required field', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'text1', + blockId: 'text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + required: true, + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + }, + ], + }, + }, + { + id: 'reset', + blockId: 'reset', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'reset', + type: 'ResetValidation', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const reset = context._internal.RootBlocks.map['reset']; + const text1 = context._internal.RootBlocks.map['text1']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['This field is required'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + type: 'Validate', + }, + error: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Your input has 1 validation error.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: ['This field is required'], + status: 'error', + warnings: [], + }); + expect(displayMessage.mock.calls).toEqual([ + [ + { + content: 'Your input has 1 validation error.', + duration: 6, + status: 'error', + }, + ], + ]); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); + await reset.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { + date: 0, + }, + error: { + action: { + id: 'validate', + type: 'Validate', + }, + error: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + startTimestamp: { + date: 0, + }, + success: false, + }); + expect(text1.eval.validation).toEqual({ + errors: ['This field is required'], + status: null, + warnings: [], + }); + expect(displayMessage.mock.calls).toEqual([]); +}); From f8962c6451e92c467ae882c55ac0859e92ca2ba0 Mon Sep 17 00:00:00 2001 From: Sandile Date: Thu, 10 Feb 2022 17:18:43 +0200 Subject: [PATCH 29/79] fix(engine): Updated validate action method test to use new plugin config. --- .pnp.cjs | 1 + packages/engine/package.json | 1 + .../src/actions/resetValidation.test.js | 3 + packages/engine/src/actions/validate.test.js | 1346 +++++++++++++++++ yarn.lock | 1 + 5 files changed, 1352 insertions(+) create mode 100644 packages/engine/src/actions/validate.test.js diff --git a/.pnp.cjs b/.pnp.cjs index 8a227abe0..160643831 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -3246,6 +3246,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@lowdefy/engine", "workspace:packages/engine"], ["@lowdefy/helpers", "workspace:packages/utils/helpers"], ["@lowdefy/operators", "workspace:packages/operators"], + ["@lowdefy/operators-js", "workspace:packages/plugins/operators/operators-js"], ["@swc/cli", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.1.55"], ["@swc/core", "npm:1.2.135"], ["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"], diff --git a/packages/engine/package.json b/packages/engine/package.json index 548492451..b193d18f3 100644 --- a/packages/engine/package.json +++ b/packages/engine/package.json @@ -42,6 +42,7 @@ "@lowdefy/operators": "4.0.0-alpha.6" }, "devDependencies": { + "@lowdefy/operators-js": "4.0.0-alpha.6", "@swc/cli": "0.1.55", "@swc/core": "1.2.135", "@swc/jest": "0.2.17", diff --git a/packages/engine/src/actions/resetValidation.test.js b/packages/engine/src/actions/resetValidation.test.js index f20274396..dc1a3c979 100644 --- a/packages/engine/src/actions/resetValidation.test.js +++ b/packages/engine/src/actions/resetValidation.test.js @@ -16,6 +16,9 @@ import { get, type } from '@lowdefy/helpers'; +// TODO: issue importing plugin packages with jest due to jest es module resolution #https://github.com/facebook/jest/issues/9771 +// import { _not, _type } from '@lowdefy/operators-js/operators/client'; + import testContext from '../../test/testContext.js'; const closeLoader = jest.fn(); diff --git a/packages/engine/src/actions/validate.test.js b/packages/engine/src/actions/validate.test.js new file mode 100644 index 000000000..e09971f24 --- /dev/null +++ b/packages/engine/src/actions/validate.test.js @@ -0,0 +1,1346 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { get, type } from '@lowdefy/helpers'; + +import testContext from '../../test/testContext.js'; + +const closeLoader = jest.fn(); +const displayMessage = jest.fn(); +const lowdefy = { + _internal: { + actions: { + Validate: ({ methods: { validate }, params }) => { + return validate(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + TextInput: { meta: { category: 'input', valueType: 'string' } }, + }, + displayMessage, + operators: { + _not: ({ params }) => { + return !params; + }, + _type: ({ location, params, state }) => { + const typeName = type.isObject(params) ? params.type : params; + if (!type.isString(typeName)) { + throw new Error( + `Operator Error: _type.type must be a string. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + const on = Object.prototype.hasOwnProperty.call(params, 'on') + ? params.on + : get(state, get(params, 'key', { default: location })); + switch (typeName) { + case 'string': + return type.isString(on); + case 'array': + return type.isArray(on); + case 'date': + return type.isDate(on); // Testing for date is problematic due to stringify + case 'object': + return type.isObject(on); + case 'boolean': + return type.isBoolean(on); + case 'number': + return type.isNumber(on); + case 'integer': + return type.isInt(on); + case 'null': + return type.isNull(on); + case 'undefined': + return type.isUndefined(on); + case 'none': + return type.isNone(on); + case 'primitive': + return type.isPrimitive(on); + default: + throw new Error( + `Operator Error: "${typeName}" is not a valid _type test. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + }, + _regex: ({ location, params, state }) => { + const pattern = type.isObject(params) ? params.pattern : params; + if (!type.isString(pattern)) { + throw new Error( + `Operator Error: _regex.pattern must be a string. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + let on = !type.isUndefined(params.on) ? params.on : get(state, location); + if (!type.isUndefined(params.key)) { + if (!type.isString(params.key)) { + throw new Error( + `Operator Error: _regex.key must be a string. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + on = get(state, params.key); + } + if (type.isNone(on)) { + return false; + } + if (!type.isString(on)) { + throw new Error( + `Operator Error: _regex.on must be a string. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + try { + const re = new RegExp(pattern, params.flags || 'gm'); + return re.test(on); + } catch (e) { + // log e to LowdefyError + throw new Error( + `Operator Error: _regex failed to execute RegExp.test. Received: ${JSON.stringify( + params + )} at ${location}.` + ); + } + }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + displayMessage.mockReset(); + closeLoader.mockReset(); + displayMessage.mockImplementation(() => closeLoader); +}); + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('Validate required field', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'text1', + blockId: 'text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + required: true, + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text1 = context._internal.RootBlocks.map['text1']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['This field is required'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + type: 'Validate', + }, + error: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Your input has 1 validation error.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: ['This field is required'], + status: 'error', + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Your input has 1 validation error.", + "duration": 6, + "status": "error", + }, + ], + ] + `); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); + text1.setValue('text1'); + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + index: 0, + response: undefined, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(displayMessage.mock.calls).toEqual([]); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); +}); + +test('Validate all fields', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'text1', + blockId: 'text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'text2', + blockId: 'text2', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text2', key: 'text2' } }, + message: 'text2 does not match pattern "text2"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text1 = context._internal.RootBlocks.map['text1']; + const text2 = context._internal.RootBlocks.map['text2']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + type: 'Validate', + }, + error: { + error: new Error('Your input has 2 validation errors.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Your input has 2 validation errors.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: 'error', + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Your input has 2 validation errors.", + "duration": 6, + "status": "error", + }, + ], + ] + `); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); + text1.setValue('text1'); + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + type: 'Validate', + }, + error: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Your input has 1 validation error.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: 'error', + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Your input has 1 validation error.", + "duration": 6, + "status": "error", + }, + ], + ] + `); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); + text2.setValue('text2'); + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + index: 0, + response: undefined, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); +}); + +test('Validate only one field', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'text1', + blockId: 'text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'text2', + blockId: 'text2', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text2', key: 'text2' } }, + message: 'text2 does not match pattern "text2"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + params: 'text1', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text1 = context._internal.RootBlocks.map['text1']; + const text2 = context._internal.RootBlocks.map['text2']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + params: 'text1', + type: 'Validate', + }, + error: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Your input has 1 validation error.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: null, + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Your input has 1 validation error.", + "duration": 6, + "status": "error", + }, + ], + ] + `); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); + text1.setValue('text1'); + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + index: 0, + response: undefined, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: null, + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); +}); + +test('Validate list of fields', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'text1', + blockId: 'text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'text2', + blockId: 'text2', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text2', key: 'text2' } }, + message: 'text2 does not match pattern "text2"', + }, + ], + }, + { + id: 'text3', + blockId: 'text3', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text3', key: 'text3' } }, + message: 'text3 does not match pattern "text3"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + params: ['text1', 'text2'], + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text1 = context._internal.RootBlocks.map['text1']; + const text2 = context._internal.RootBlocks.map['text2']; + const text3 = context._internal.RootBlocks.map['text3']; + text1.setValue('text1'); + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: 'error', + warnings: [], + }); + expect(text3.eval.validation).toEqual({ + errors: ['text3 does not match pattern "text3"'], + status: null, + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + params: ['text1', 'text2'], + type: 'Validate', + }, + error: { + error: new Error('Your input has 1 validation error.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Your input has 1 validation error.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Your input has 1 validation error.", + "duration": 6, + "status": "error", + }, + ], + ] + `); + displayMessage.mockReset(); + displayMessage.mockImplementation(() => closeLoader); + text2.setValue('text2'); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: [], + status: 'success', + warnings: [], + }); + expect(text3.eval.validation).toEqual({ + errors: ['text3 does not match pattern "text3"'], + status: null, + warnings: [], + }); + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + index: 0, + response: undefined, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text3.eval.validation).toEqual({ + errors: ['text3 does not match pattern "text3"'], + status: null, + warnings: [], + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); +}); + +test('Invalid Validate params', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + params: 1, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'validate', + params: 1, + type: 'Validate', + }, + error: { + error: new Error('Invalid validate params.'), + index: 0, + type: 'Validate', + }, + }, + responses: { + validate: { + type: 'Validate', + index: 0, + error: new Error('Invalid validate params.'), + }, + }, + success: false, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Invalid validate params.", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); + +test('Validate does not fail on warnings', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'text1', + blockId: 'text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + status: 'warning', + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text1 = context._internal.RootBlocks.map['text1']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'warning', + warnings: ['text1 does not match pattern "text1"'], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + index: 0, + }, + }, + success: true, + startTimestamp: { date: 0 }, + endTimestamp: { date: 0 }, + }); + expect(text1.eval.validation).toEqual({ + errors: [], + status: 'warning', + warnings: ['text1 does not match pattern "text1"'], + }); +}); + +test('Validate on nested objects using params.regex string', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'obj.text1', + blockId: 'obj.text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'text2', + blockId: 'text2', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text2', key: 'text2' } }, + message: 'text2 does not match pattern "text2"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + params: { + regex: '^obj.*1$', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text1 = context._internal.RootBlocks.map['obj.text1']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { type: 'Validate', error: new Error('Your input has 1 validation error.'), index: 0 }, + action: { id: 'validate', type: 'Validate', params: { regex: '^obj.*1$' } }, + }, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + error: new Error('Your input has 1 validation error.'), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); +}); + +test('Validate on nested objects using params.regex array', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'obj.text1', + blockId: 'obj.text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'obj.abc1', + blockId: 'obj.abc1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'abc1', key: 'abc1' } }, + message: 'abc1 does not match pattern "abc1"', + }, + ], + }, + { + id: 'text2', + blockId: 'text2', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text2', key: 'text2' } }, + message: 'text2 does not match pattern "text2"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + params: { + regex: ['^obj.*1$'], + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text2 = context._internal.RootBlocks.map['text2']; + const text1 = context._internal.RootBlocks.map['obj.text1']; + const abc1 = context._internal.RootBlocks.map['obj.abc1']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Validate', + error: new Error('Your input has 2 validation errors.'), + index: 0, + }, + action: { id: 'validate', type: 'Validate', params: { regex: ['^obj.*1$'] } }, + }, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + error: new Error('Your input has 2 validation errors.'), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(abc1.eval.validation).toEqual({ + errors: ['abc1 does not match pattern "abc1"'], + status: 'error', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: null, + warnings: [], + }); +}); + +test('Validate on nested objects using params.regex array and blockIds', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'obj.text1', + blockId: 'obj.text1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text1', key: 'text1' } }, + message: 'text1 does not match pattern "text1"', + }, + ], + }, + { + id: 'obj.abc1', + blockId: 'obj.abc1', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'abc1', key: 'abc1' } }, + message: 'abc1 does not match pattern "abc1"', + }, + ], + }, + { + id: 'text2', + blockId: 'text2', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + validate: [ + { + pass: { _regex: { pattern: 'text2', key: 'text2' } }, + message: 'text2 does not match pattern "text2"', + }, + ], + }, + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'validate', + type: 'Validate', + params: { + regex: ['^obj.*t1$'], + blockIds: ['text2'], + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + operators: lowdefy._internal.operators, + }); + const button = context._internal.RootBlocks.map['button']; + const text2 = context._internal.RootBlocks.map['text2']; + const text1 = context._internal.RootBlocks.map['obj.text1']; + const abc1 = context._internal.RootBlocks.map['obj.abc1']; + await button.triggerEvent({ name: 'onClick' }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Validate', + error: new Error('Your input has 2 validation errors.'), + index: 0, + }, + action: { + id: 'validate', + type: 'Validate', + params: { regex: ['^obj.*t1$'], blockIds: ['text2'] }, + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + validate: { + type: 'Validate', + error: new Error('Your input has 2 validation errors.'), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(text1.eval.validation).toEqual({ + errors: ['text1 does not match pattern "text1"'], + status: 'error', + warnings: [], + }); + expect(text2.eval.validation).toEqual({ + errors: ['text2 does not match pattern "text2"'], + status: 'error', + warnings: [], + }); + expect(abc1.eval.validation).toEqual({ + errors: ['abc1 does not match pattern "abc1"'], + status: null, + warnings: [], + }); +}); diff --git a/yarn.lock b/yarn.lock index b91a4f965..90afdda82 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2370,6 +2370,7 @@ __metadata: dependencies: "@lowdefy/helpers": 4.0.0-alpha.6 "@lowdefy/operators": 4.0.0-alpha.6 + "@lowdefy/operators-js": 4.0.0-alpha.6 "@swc/cli": 0.1.55 "@swc/core": 1.2.135 "@swc/jest": 0.2.17 From 91fa543969a33e119df23b716d04acca55edcaf0 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 09:49:25 +0200 Subject: [PATCH 30/79] fix(engine): Update set global action method global object reference. --- packages/engine/src/actions/setGlobal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/actions/setGlobal.js b/packages/engine/src/actions/setGlobal.js index 983eaa548..81baaa737 100644 --- a/packages/engine/src/actions/setGlobal.js +++ b/packages/engine/src/actions/setGlobal.js @@ -20,7 +20,7 @@ const createSetGlobal = ({ arrayIndices, context }) => { return function setGlobal(params) { Object.keys(params).forEach((key) => { set( - context._internal.lowdefy.lowdefyGlobal, + context._internal.lowdefy._internal.lowdefyGlobal, applyArrayIndices(arrayIndices, key), params[key] ); From ceceec34da9973d054d2138232832b2fd5aeb5aa Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 09:50:53 +0200 Subject: [PATCH 31/79] fix(engine): Updated setGlobal action method test to use new plugin config. --- packages/engine/src/actions/setGlobal.test.js | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 packages/engine/src/actions/setGlobal.test.js diff --git a/packages/engine/src/actions/setGlobal.test.js b/packages/engine/src/actions/setGlobal.test.js new file mode 100644 index 000000000..c5c9a7b2a --- /dev/null +++ b/packages/engine/src/actions/setGlobal.test.js @@ -0,0 +1,80 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +test('SetGlobal data to global', async () => { + const lowdefy = { + _internal: { + actions: { + SetGlobal: ({ methods: { setGlobal }, params }) => { + return setGlobal(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + lowdefyGlobal: { x: 'old', init: 'init' }, + }, + }; + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'SetGlobal', + params: { str: 'hello', number: 13, arr: [1, 2, 3], x: 'new' }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + expect(context._internal.lowdefy._internal.lowdefyGlobal).toEqual({ x: 'old', init: 'init' }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(context._internal.lowdefy._internal.lowdefyGlobal).toEqual({ + init: 'init', + str: 'hello', + number: 13, + arr: [1, 2, 3], + x: 'new', + }); +}); + +test.todo('SetGlobal calls context update'); From 27838bcf75bba256d13f7a72b1bfd6e1d41bceeb Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 09:55:44 +0200 Subject: [PATCH 32/79] fix(engine): Updated setState action method test to use new plugin config. --- packages/engine/src/actions/setState.test.js | 259 +++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 packages/engine/src/actions/setState.test.js diff --git a/packages/engine/src/actions/setState.test.js b/packages/engine/src/actions/setState.test.js new file mode 100644 index 000000000..8f1bd5bf3 --- /dev/null +++ b/packages/engine/src/actions/setState.test.js @@ -0,0 +1,259 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + SetState: ({ methods: { setState }, params }) => { + return setState(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + List: { meta: { category: 'list', valueType: 'array' } }, + TextInput: { meta: { category: 'input', valueType: 'string' } }, + }, + }, +}; + +test('SetState data to state', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'SetState', params: { x: [1, 2, 3] } }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + expect(context.state).toEqual({ textInput: 'init' }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + expect(context.state).toEqual({ textInput: 'init' }); + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ textInput: 'init', x: [1, 2, 3] }); +}); + +test('SetState field to state and update block value', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'SetState', params: { textInput: 'new' } }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + expect(context.state).toEqual({ textInput: 'init' }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; + + expect(context.state).toEqual({ textInput: 'init' }); + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ textInput: 'new' }); + expect(textInput.value).toEqual('new'); +}); + +test('SetState field to state with incorrect type - NOTE SetState IS NOT TYPE SAFE', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:textInput:0', + blockId: 'textInput', + type: 'TextInput', + meta: { + category: 'input', + valueType: 'string', + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'SetState', params: { textInput: 1 } }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { textInput: 'init' }, + }); + expect(context.state).toEqual({ textInput: 'init' }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + const textInput = context._internal.RootBlocks.map['block:root:textInput:0']; + + expect(context.state).toEqual({ textInput: 'init' }); + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ textInput: 1 }); + expect(textInput.value).toEqual(1); +}); + +test('SetState value on array and create new Blocks for array items', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:list:0', + blockId: 'list', + type: 'List', + meta: { + category: 'list', + valueType: 'array', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:list.$.textInput:0', + blockId: 'list.$.textInput', + type: 'TextInput', + defaultValue: '123', + meta: { + category: 'input', + valueType: 'string', + }, + }, + ], + }, + }, + }, + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'SetState', + params: { list: [{ textInput: '0' }, { textInput: '1' }, { textInput: '2' }] }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { list: [{ textInput: 'init' }] }, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + + expect(context.state).toEqual({ list: [{ textInput: 'init' }] }); + + button.triggerEvent({ name: 'onClick' }); + expect(context.state).toEqual({ + list: [{ textInput: '0' }, { textInput: '1' }, { textInput: '2' }], + }); + + const textInput0 = context._internal.RootBlocks.map['block:root:list.0.textInput:0']; + const textInput1 = context._internal.RootBlocks.map['block:root:list.1.textInput:0']; + const textInput2 = context._internal.RootBlocks.map['block:root:list.2.textInput:0']; + + expect(textInput0.value).toEqual('0'); + expect(textInput1.value).toEqual('1'); + expect(textInput2.value).toEqual('2'); +}); From 25b656f115da074b7da266ce81c0bc975db2c109 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 10:51:40 +0200 Subject: [PATCH 33/79] fix(actions-core): Updated ScrollTo action to include param error handling. --- .../plugins/actions/actions-core/src/actions/ScrollTo.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index 42fd3664d..68524d2c7 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -14,8 +14,12 @@ limitations under the License. */ +import { type } from '@lowdefy/helpers'; + function ScrollTo({ document, params, window }) { - if (params.blockId) { + if (!type.isObject(params)) { + throw new Error(`Invalid ScrollTo, check action params. Received "${JSON.stringify(params)}".`); + } else if (params.blockId) { const element = document.getElementById(params.blockId); if (element) { element.scrollIntoView(params.options); From 2f6189b6405ccaa1e0ffbf055669970f60300476 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 10:58:58 +0200 Subject: [PATCH 34/79] fix(actions-core): Added testContext for action testing. --- .pnp.cjs | 2 + .../plugins/actions/actions-core/package.json | 2 + .../actions-core/src/actions/testContext.js | 71 +++++++++++++++++++ yarn.lock | 2 + 4 files changed, 77 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/testContext.js diff --git a/.pnp.cjs b/.pnp.cjs index 160643831..865f0b23f 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2792,7 +2792,9 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/plugins/actions/actions-core/", "packageDependencies": [ ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], + ["@lowdefy/engine", "workspace:packages/engine"], ["@lowdefy/helpers", "workspace:packages/utils/helpers"], + ["@lowdefy/operators", "workspace:packages/operators"], ["@swc/cli", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.1.55"], ["@swc/core", "npm:1.2.135"], ["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"], diff --git a/packages/plugins/actions/actions-core/package.json b/packages/plugins/actions/actions-core/package.json index 3d231e02d..cc68c5d06 100644 --- a/packages/plugins/actions/actions-core/package.json +++ b/packages/plugins/actions/actions-core/package.json @@ -49,6 +49,8 @@ "@lowdefy/helpers": "4.0.0-alpha.6" }, "devDependencies": { + "@lowdefy/engine": "4.0.0-alpha.6", + "@lowdefy/operators": "4.0.0-alpha.6", "@swc/cli": "0.1.55", "@swc/core": "1.2.135", "@swc/jest": "0.2.17", diff --git a/packages/plugins/actions/actions-core/src/actions/testContext.js b/packages/plugins/actions/actions-core/src/actions/testContext.js new file mode 100644 index 000000000..dd8a1b196 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/testContext.js @@ -0,0 +1,71 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { WebParser } from '@lowdefy/operators'; + +import { Actions } from '@lowdefy/engine'; +import { Blocks } from '@lowdefy/engine'; +import { Requests } from '@lowdefy/engine'; +import { State } from '@lowdefy/engine'; + +const testContext = async ({ lowdefy, operators, rootBlock, initState = {} }) => { + const testLowdefy = { + inputs: { test: {} }, + urlQuery: {}, + ...lowdefy, + _internal: { + displayMessage: () => () => undefined, + updateBlock: () => {}, + ...lowdefy._internal, + }, + }; + const ctx = { + id: 'test', + pageId: rootBlock.blockId, + eventLog: [], + requests: {}, + state: {}, + _internal: { + lowdefy: testLowdefy, + rootBlock, + }, + }; + const _internal = ctx._internal; + _internal.parser = new WebParser({ context: ctx, contexts: {}, operators: operators || {} }); + await _internal.parser.init(); + _internal.State = new State(ctx); + _internal.Actions = new Actions(ctx); + _internal.Requests = new Requests(ctx); + _internal.RootBlocks = new Blocks({ + areas: _internal.rootBlock.areas, + context: ctx, + }); + _internal.RootBlocks.init(); + _internal.update = () => { + _internal.RootBlocks.update(); + }; + if (initState) { + Object.keys(initState).forEach((key) => { + _internal.State.set(key, initState[key]); + }); + _internal.RootBlocks.reset(); + } + _internal.update(); + _internal.State.freezeState(); + return ctx; +}; + +export default testContext; diff --git a/yarn.lock b/yarn.lock index 90afdda82..9cbca4ed8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1956,7 +1956,9 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/actions-core@workspace:packages/plugins/actions/actions-core" dependencies: + "@lowdefy/engine": 4.0.0-alpha.6 "@lowdefy/helpers": 4.0.0-alpha.6 + "@lowdefy/operators": 4.0.0-alpha.6 "@swc/cli": 0.1.55 "@swc/core": 1.2.135 "@swc/jest": 0.2.17 From ae202f2d1db7f5e56c60d4da384c2f15d8a53a18 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 11:01:00 +0200 Subject: [PATCH 35/79] fix(actions-core): Updated ScrollTo action tests. --- .../actions-core/src/actions/ScrollTo.test.js | 260 ++++++++++++++++++ 1 file changed, 260 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js new file mode 100644 index 000000000..1716eea5a --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js @@ -0,0 +1,260 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; + +import ScrollTo from './ScrollTo.js'; + +// Mock document +const mockDocGetElementById = jest.fn(); +const mockElemScrollIntoView = jest.fn(); +const document = { + getElementById: mockDocGetElementById, +}; +const mockDocGetElementByIdImp = (id) => { + if (id === 'root') return { id, scrollIntoView: mockElemScrollIntoView }; +}; + +// Mock window +const mockWindowFocus = jest.fn(); +const mockWindowOpen = jest.fn(() => ({ focus: mockWindowFocus })); +const mockWindowScrollTo = jest.fn(); +const window = { + location: { href: '', origin: 'http://lowdefy.com' }, + open: mockWindowOpen, + scrollTo: mockWindowScrollTo, +}; + +const lowdefy = { + _internal: { + actions: { + ScrollTo, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + document, + window, + }, +}; + +beforeEach(() => { + mockWindowOpen.mockReset(); + mockWindowFocus.mockReset(); + mockWindowScrollTo.mockReset(); + mockDocGetElementById.mockReset(); + mockDocGetElementById.mockImplementation(mockDocGetElementByIdImp); + mockElemScrollIntoView.mockReset(); +}); + +test('ScrollTo with no params', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'ScrollTo' }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockWindowScrollTo.mock.calls).toEqual([]); +}); + +test('ScrollTo with no blockId', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'ScrollTo', params: { behavior: 'smooth', top: 0 } }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockWindowScrollTo.mock.calls).toEqual([ + [ + { + behavior: 'smooth', + top: 0, + }, + ], + ]); +}); + +test('ScrollTo with blockId', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'ScrollTo', params: { blockId: 'root' } }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockDocGetElementById.mock.calls).toEqual([['root']]); + expect(mockElemScrollIntoView.mock.calls).toEqual([[undefined]]); +}); + +test('ScrollTo with blockId and options', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'ScrollTo', + params: { blockId: 'root', options: { behavior: 'smooth' } }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + + expect(mockDocGetElementById.mock.calls).toEqual([['root']]); + expect(mockElemScrollIntoView.mock.calls).toEqual([ + [ + { + behavior: 'smooth', + }, + ], + ]); +}); + +test('ScrollTo with blockId, block not found', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [{ id: 'a', type: 'ScrollTo', params: { blockId: 'not_there' } }], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + button.triggerEvent({ name: 'onClick' }); + expect(mockDocGetElementById.mock.calls).toEqual([['not_there']]); + expect(mockElemScrollIntoView.mock.calls).toEqual([]); + expect(mockWindowScrollTo.mock.calls).toEqual([]); +}); From ccf4fd14c3a112f74d89939166db0e17972c95a7 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 11:19:16 +0200 Subject: [PATCH 36/79] fix(actions-core): Updated Throw action tests to use new plugin config. --- .../actions-core/src/actions/Throw.test.js | 592 ++++++++++++++++++ .../actions-core/src/actions/testContext.js | 6 +- 2 files changed, 593 insertions(+), 5 deletions(-) create mode 100644 packages/plugins/actions/actions-core/src/actions/Throw.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Throw.test.js b/packages/plugins/actions/actions-core/src/actions/Throw.test.js new file mode 100644 index 000000000..20afd060e --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Throw.test.js @@ -0,0 +1,592 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import { Throw, ThrowActionError } from './Throw.js'; + +const closeLoader = jest.fn(); +const displayMessage = jest.fn(); +const lowdefy = { + _internal: { + actions: { + Throw, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + displayMessage, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + displayMessage.mockReset(); + closeLoader.mockReset(); + displayMessage.mockImplementation(() => closeLoader); +}); + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('Throw no params', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'throw', + type: 'Throw', + }, + error: { + error: new TypeError("Cannot read properties of undefined (reading 'throw')"), + index: 0, + type: 'Throw', + }, + }, + responses: { + throw: { + error: new TypeError("Cannot read properties of undefined (reading 'throw')"), + type: 'Throw', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Cannot read properties of undefined (reading 'throw')", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); + +test('Throw throw true no message or metaData', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + params: { throw: true }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Throw', + error: new ThrowActionError(undefined, { blockId: 'button', context: context }), + index: 0, + }, + action: { + id: 'throw', + type: 'Throw', + params: { throw: true }, + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + throw: { + type: 'Throw', + error: new ThrowActionError(undefined, { blockId: 'button', context: context }), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); + +test('Throw throw true message no metaData', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + params: { throw: true, message: 'My error message' }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Throw', + error: new ThrowActionError('My error message', { blockId: 'button', context: context }), + index: 0, + }, + action: { + id: 'throw', + type: 'Throw', + params: { throw: true, message: 'My error message' }, + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + throw: { + type: 'Throw', + error: new ThrowActionError('My error message', { blockId: 'button', context: context }), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "My error message", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); + +test('Throw throw true message metaData string', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + params: { throw: true, message: 'My error message', metaData: 'Meta string' }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Throw', + error: new ThrowActionError('My error message', { + blockId: 'button', + context: context, + metaData: 'Meta string', + }), + index: 0, + }, + action: { + id: 'throw', + type: 'Throw', + params: { throw: true, message: 'My error message', metaData: 'Meta string' }, + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + throw: { + type: 'Throw', + error: new ThrowActionError('My error message', { + blockId: 'button', + context: context, + metaData: 'Meta string', + }), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "My error message", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); + +test('Throw throw true message metaData object', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + params: { throw: true, message: 'My error message', metaData: { key: 'value' } }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Throw', + error: new ThrowActionError('My error message', { + blockId: 'button', + context: context, + metaData: { key: 'value' }, + }), + index: 0, + }, + action: { + id: 'throw', + type: 'Throw', + params: { throw: true, message: 'My error message', metaData: { key: 'value' } }, + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + throw: { + type: 'Throw', + error: new ThrowActionError('My error message', { + blockId: 'button', + context: context, + metaData: 'Meta string', + }), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "My error message", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); + +test('Throw throw false', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + params: { throw: false }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + throw: { + type: 'Throw', + response: undefined, + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: true, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(`Array []`); +}); + +test('Throw throw invalid', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'throw', + type: 'Throw', + params: { throw: 'invalid' }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + error: { + error: { + type: 'Throw', + error: new Error('Invalid Throw, check action params. Received "{"throw":"invalid"}".'), + index: 0, + }, + action: { + id: 'throw', + type: 'Throw', + params: { throw: 'invalid' }, + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + throw: { + type: 'Throw', + error: new Error('Invalid Throw, check action params. Received "{"throw":"invalid"}".'), + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); + expect(displayMessage.mock.calls).toMatchInlineSnapshot(` + Array [ + Array [ + Object { + "content": "Invalid Throw, check action params. Received \\"{\\"throw\\":\\"invalid\\"}\\".", + "duration": 6, + "status": "error", + }, + ], + ] + `); +}); diff --git a/packages/plugins/actions/actions-core/src/actions/testContext.js b/packages/plugins/actions/actions-core/src/actions/testContext.js index dd8a1b196..c15ebb132 100644 --- a/packages/plugins/actions/actions-core/src/actions/testContext.js +++ b/packages/plugins/actions/actions-core/src/actions/testContext.js @@ -14,13 +14,9 @@ limitations under the License. */ +import { Actions, Blocks, Requests, State } from '@lowdefy/engine'; import { WebParser } from '@lowdefy/operators'; -import { Actions } from '@lowdefy/engine'; -import { Blocks } from '@lowdefy/engine'; -import { Requests } from '@lowdefy/engine'; -import { State } from '@lowdefy/engine'; - const testContext = async ({ lowdefy, operators, rootBlock, initState = {} }) => { const testLowdefy = { inputs: { test: {} }, From abb74afc8e68e32960cb1c50f7930e79bbcfbed8 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 11:25:20 +0200 Subject: [PATCH 37/79] fix(actions-core): Updated Wait action tests to use new plugin config. --- .../actions-core/src/actions/Wait.test.js | 166 ++++++++++++++++++ 1 file changed, 166 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Wait.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Wait.test.js b/packages/plugins/actions/actions-core/src/actions/Wait.test.js new file mode 100644 index 000000000..07fc72077 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Wait.test.js @@ -0,0 +1,166 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; + +import Wait from './Wait.js'; + +const lowdefy = { + _internal: { + actions: { + Wait, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + auth: { + login: jest.fn(), + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; + lowdefy._internal.auth.login.mockReset(); +}); + +afterAll(() => { + global.Date = RealDate; +}); + +const timeout = (ms) => { + return new Promise((resolve) => setTimeout(resolve, ms)); +}; + +test('Wait', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Wait', + params: { ms: 500 }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + let resolved = false; + button.triggerEvent({ name: 'onClick' }).then(() => { + resolved = true; + }); + expect(resolved).toBe(false); + await timeout(100); + expect(resolved).toBe(false); + await timeout(300); + expect(resolved).toBe(false); + await timeout(150); + expect(resolved).toBe(true); +}); + +test('Wait ms not a integer', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Wait', + params: { ms: 1.1 }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', params: { ms: 1.1 }, type: 'Wait' }, + error: { + error: new Error('Wait action "ms" param should be an integer.'), + index: 0, + type: 'Wait', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error('Wait action "ms" param should be an integer.'), + index: 0, + type: 'Wait', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); From f9333e5a4fd3e7a47100000de1c9ee70488f37ca Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:10:31 +0200 Subject: [PATCH 38/79] feat(actions-core): Added CallMethod action test. --- .../src/actions/CallMethod.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/CallMethod.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js new file mode 100644 index 000000000..8817835f9 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import CallMethod from './CallMethod.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + CallMethod: (props) => CallMethod({ ...props, methods: { callMethod: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('CallMethod action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'CallMethod', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From d04cc031d9e831c18f01b96a1ae7a05851d92cb6 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:30:31 +0200 Subject: [PATCH 39/79] feat(actions-core): Added Link action test. --- .../actions-core/src/actions/Link.test.js | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Link.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Link.test.js b/packages/plugins/actions/actions-core/src/actions/Link.test.js new file mode 100644 index 000000000..cfa02e2f8 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Link.test.js @@ -0,0 +1,163 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Link from './Link.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Link, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + link: (params) => { + if (params.pageId === 'error') { + throw new Error('Param error'); + } else mockActionMethod(params); + }, + }, +}; + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Link', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([[{ pageId: 'call' }]]); +}); + +test('error params action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Link', + params: 'error', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'action', + type: 'Link', + params: 'error', + }, + error: { + error: new Error('Invalid Link, check action params. Received ""error"".'), + index: 0, + type: 'Link', + }, + }, + responses: { + action: { + error: new Error('Invalid Link, check action params. Received ""error"".'), + type: 'Link', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); +}); From ba6ac71731b24c3a003585b5fe4ab4763c40e186 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:34:08 +0200 Subject: [PATCH 40/79] feat(actions-core): Added Login action test. --- .../actions-core/src/actions/Login.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Login.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Login.test.js b/packages/plugins/actions/actions-core/src/actions/Login.test.js new file mode 100644 index 000000000..88ce02e99 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Login.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Login from './Login.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Login: (props) => Login({ ...props, methods: { login: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Login action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Login', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From b67e77d56c415b9349b84b31a49d505dda2af2ff Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:36:18 +0200 Subject: [PATCH 41/79] feat(actions-core): Added Logout action test. --- .../actions-core/src/actions/Logout.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Logout.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Logout.test.js b/packages/plugins/actions/actions-core/src/actions/Logout.test.js new file mode 100644 index 000000000..c76c5f340 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Logout.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Logout from './Logout.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Logout: (props) => Logout({ ...props, methods: { logout: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Logout action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Logout', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([[]]); +}); From 0404c0d326c18d9447349520fe0e6c64d2512023 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:37:37 +0200 Subject: [PATCH 42/79] feat(actions-core): Added Message action test. --- .../actions-core/src/actions/Message.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Message.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Message.test.js b/packages/plugins/actions/actions-core/src/actions/Message.test.js new file mode 100644 index 000000000..2213aafe3 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Message.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Message from './Message.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Message: (props) => Message({ ...props, methods: { message: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Message action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Message', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From 696d8163c1a8128e8ec3e0704e16378b173039c5 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:39:29 +0200 Subject: [PATCH 43/79] feat(actions-core): Added Request action test. --- .../actions-core/src/actions/Request.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Request.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Request.test.js b/packages/plugins/actions/actions-core/src/actions/Request.test.js new file mode 100644 index 000000000..7c53f9614 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Request.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Request from './Request.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Request: (props) => Request({ ...props, methods: { request: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Request action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Request', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From c53d111da0811d7822b122641d5cc36d9e61a384 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:40:42 +0200 Subject: [PATCH 44/79] feat(actions-core): Added Reset action test. --- .../actions-core/src/actions/Reset.test.js | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Reset.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Reset.test.js b/packages/plugins/actions/actions-core/src/actions/Reset.test.js new file mode 100644 index 000000000..da09a93f7 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Reset.test.js @@ -0,0 +1,74 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Reset from './Reset.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Reset: (props) => Reset({ ...props, methods: { reset: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Reset action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Reset', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([[]]); +}); From b5fc49915bdfabca2721c71cf5d5653ee62d27b9 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:42:53 +0200 Subject: [PATCH 45/79] feat(actions-core): Added ResetValidation action test. --- .../src/actions/ResetValidation.test.js | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js new file mode 100644 index 000000000..33aec3faf --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js @@ -0,0 +1,76 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import ResetValidation from './ResetValidation.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + ResetValidation: (props) => + ResetValidation({ ...props, methods: { resetValidation: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('ResetValidation action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'ResetValidation', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From 66c8218578a3f3da77c9b722ef3141d205262499 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:46:47 +0200 Subject: [PATCH 46/79] feat(actions-core): Added SetGlobal action test. --- .../src/actions/SetGlobal.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js new file mode 100644 index 000000000..b491bb976 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import SetGlobal from './SetGlobal.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + SetGlobal: (props) => SetGlobal({ ...props, methods: { setGlobal: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('SetGlobal action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'SetGlobal', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From bfab2e4b6602c9b2ecf7e720dda7f49725ecb0af Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:47:56 +0200 Subject: [PATCH 47/79] feat(actions-core): Added SetState action test. --- .../actions-core/src/actions/SetState.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/SetState.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/SetState.test.js b/packages/plugins/actions/actions-core/src/actions/SetState.test.js new file mode 100644 index 000000000..c9fc78b81 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/SetState.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import SetState from './SetState.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + SetState: (props) => SetState({ ...props, methods: { setState: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('SetState action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'SetState', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From 171aec380b7be3ee9ce2d003e2359bf80c82af4a Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 12:50:37 +0200 Subject: [PATCH 48/79] feat(actions-core): Added Validate action test. --- .../actions-core/src/actions/Validate.test.js | 75 +++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 packages/plugins/actions/actions-core/src/actions/Validate.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Validate.test.js b/packages/plugins/actions/actions-core/src/actions/Validate.test.js new file mode 100644 index 000000000..07bf6006b --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/Validate.test.js @@ -0,0 +1,75 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from './testContext.js'; +import Validate from './Validate.js'; + +const mockActionMethod = jest.fn(); + +const lowdefy = { + _internal: { + actions: { + Validate: (props) => Validate({ ...props, methods: { validate: mockActionMethod } }), + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Validate action invocation', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'action', + type: 'Validate', + params: 'call', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + await button.triggerEvent({ name: 'onClick' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From e24d40408ff73e7b251ce2777e263d4099bf7f26 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 13:37:19 +0200 Subject: [PATCH 49/79] chore(actions-core): Simplify action tests. --- .../src/actions/CallMethod.test.js | 49 +----------------- .../actions-core/src/actions/Login.test.js | 49 +----------------- .../actions-core/src/actions/Logout.test.js | 49 +----------------- .../actions-core/src/actions/Message.test.js | 49 +----------------- .../actions-core/src/actions/Request.test.js | 49 +----------------- .../actions-core/src/actions/Reset.test.js | 48 +----------------- .../src/actions/ResetValidation.test.js | 50 +------------------ .../actions-core/src/actions/ScrollTo.test.js | 4 ++ .../src/actions/SetGlobal.test.js | 49 +----------------- .../actions-core/src/actions/SetState.test.js | 49 +----------------- .../actions-core/src/actions/Validate.test.js | 49 +----------------- 11 files changed, 14 insertions(+), 480 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js b/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js index 8817835f9..02fb41024 100644 --- a/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js +++ b/packages/plugins/actions/actions-core/src/actions/CallMethod.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import CallMethod from './CallMethod.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - CallMethod: (props) => CallMethod({ ...props, methods: { callMethod: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('CallMethod action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'CallMethod', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + CallMethod({ methods: { callMethod: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/Login.test.js b/packages/plugins/actions/actions-core/src/actions/Login.test.js index 88ce02e99..22bbe59bc 100644 --- a/packages/plugins/actions/actions-core/src/actions/Login.test.js +++ b/packages/plugins/actions/actions-core/src/actions/Login.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import Login from './Login.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - Login: (props) => Login({ ...props, methods: { login: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('Login action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'Login', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + Login({ methods: { login: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/Logout.test.js b/packages/plugins/actions/actions-core/src/actions/Logout.test.js index c76c5f340..e0f94a6b0 100644 --- a/packages/plugins/actions/actions-core/src/actions/Logout.test.js +++ b/packages/plugins/actions/actions-core/src/actions/Logout.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import Logout from './Logout.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - Logout: (props) => Logout({ ...props, methods: { logout: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('Logout action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'Logout', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + Logout({ methods: { logout: mockActionMethod } }); expect(mockActionMethod.mock.calls).toEqual([[]]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/Message.test.js b/packages/plugins/actions/actions-core/src/actions/Message.test.js index 2213aafe3..28d0cee47 100644 --- a/packages/plugins/actions/actions-core/src/actions/Message.test.js +++ b/packages/plugins/actions/actions-core/src/actions/Message.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import Message from './Message.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - Message: (props) => Message({ ...props, methods: { message: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('Message action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'Message', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + Message({ methods: { message: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/Request.test.js b/packages/plugins/actions/actions-core/src/actions/Request.test.js index 7c53f9614..f183a9ad6 100644 --- a/packages/plugins/actions/actions-core/src/actions/Request.test.js +++ b/packages/plugins/actions/actions-core/src/actions/Request.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import Request from './Request.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - Request: (props) => Request({ ...props, methods: { request: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('Request action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'Request', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + Request({ methods: { request: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/Reset.test.js b/packages/plugins/actions/actions-core/src/actions/Reset.test.js index da09a93f7..6dc1429e2 100644 --- a/packages/plugins/actions/actions-core/src/actions/Reset.test.js +++ b/packages/plugins/actions/actions-core/src/actions/Reset.test.js @@ -14,61 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import Reset from './Reset.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - Reset: (props) => Reset({ ...props, methods: { reset: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('Reset action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'Reset', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + Reset({ methods: { reset: mockActionMethod } }); expect(mockActionMethod.mock.calls).toEqual([[]]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js b/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js index 33aec3faf..da1786160 100644 --- a/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js +++ b/packages/plugins/actions/actions-core/src/actions/ResetValidation.test.js @@ -14,63 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import ResetValidation from './ResetValidation.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - ResetValidation: (props) => - ResetValidation({ ...props, methods: { resetValidation: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('ResetValidation action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'ResetValidation', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + ResetValidation({ methods: { resetValidation: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js index 1716eea5a..c9aa7d396 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js @@ -51,6 +51,10 @@ const lowdefy = { }, }; +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + beforeEach(() => { mockWindowOpen.mockReset(); mockWindowFocus.mockReset(); diff --git a/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js b/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js index b491bb976..0f6906997 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js +++ b/packages/plugins/actions/actions-core/src/actions/SetGlobal.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import SetGlobal from './SetGlobal.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - SetGlobal: (props) => SetGlobal({ ...props, methods: { setGlobal: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('SetGlobal action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'SetGlobal', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + SetGlobal({ methods: { setGlobal: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/SetState.test.js b/packages/plugins/actions/actions-core/src/actions/SetState.test.js index c9fc78b81..bd9b5c2ea 100644 --- a/packages/plugins/actions/actions-core/src/actions/SetState.test.js +++ b/packages/plugins/actions/actions-core/src/actions/SetState.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import SetState from './SetState.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - SetState: (props) => SetState({ ...props, methods: { setState: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('SetState action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'SetState', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + SetState({ methods: { setState: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); diff --git a/packages/plugins/actions/actions-core/src/actions/Validate.test.js b/packages/plugins/actions/actions-core/src/actions/Validate.test.js index 07bf6006b..28165cb26 100644 --- a/packages/plugins/actions/actions-core/src/actions/Validate.test.js +++ b/packages/plugins/actions/actions-core/src/actions/Validate.test.js @@ -14,62 +14,15 @@ limitations under the License. */ -import testContext from './testContext.js'; import Validate from './Validate.js'; const mockActionMethod = jest.fn(); -const lowdefy = { - _internal: { - actions: { - Validate: (props) => Validate({ ...props, methods: { validate: mockActionMethod } }), - }, - blockComponents: { - Button: { meta: { category: 'display' } }, - }, - }, -}; - beforeEach(() => { mockActionMethod.mockReset(); }); test('Validate action invocation', async () => { - const rootBlock = { - id: 'block:root:root:0', - blockId: 'root', - meta: { - category: 'container', - }, - areas: { - content: { - blocks: [ - { - id: 'button', - blockId: 'button', - type: 'Button', - meta: { - category: 'display', - }, - events: { - onClick: [ - { - id: 'action', - type: 'Validate', - params: 'call', - }, - ], - }, - }, - ], - }, - }, - }; - const context = await testContext({ - lowdefy, - rootBlock, - }); - const button = context._internal.RootBlocks.map['button']; - await button.triggerEvent({ name: 'onClick' }); + Validate({ methods: { validate: mockActionMethod }, params: 'call' }); expect(mockActionMethod.mock.calls).toEqual([['call']]); }); From abbf7cc75e2db012ce7542986c9b890a70e6f2b9 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:24:34 +0200 Subject: [PATCH 50/79] chore(engine): Refactor action method names to be the same as export. --- .../{callMethod.js => createCallMethod.js} | 0 ...ethod.test.js => createCallMethod.test.js} | 2 +- .../{message.js => createDisplayMessage.js} | 6 +-- ...e.test.js => createDisplayMessage.test.js} | 0 .../{getAction.js => createGetActions.js} | 6 +-- .../{getBlockId.js => createGetBlockId.js} | 0 .../{getEvent.js => createGetEvent.js} | 0 .../{getGlobal.js => createGetGlobal.js} | 0 .../{getInput.js => createGetInput.js} | 0 .../{getPageId.js => createGetPageId.js} | 0 .../{getRequest.js => createGetRequest.js} | 0 .../{getState.js => createGetState.js} | 0 .../{getUrlQuery.js => createGetUrlQuery.js} | 0 .../actions/{getUser.js => createGetUser.js} | 0 .../src/actions/{link.js => createLink.js} | 0 .../{link.test.js => createLink.test.js} | 0 .../src/actions/{login.js => createLogin.js} | 0 .../{login.test.js => createLogin.test.js} | 0 .../actions/{logout.js => createLogout.js} | 0 .../{logout.test.js => createLogout.test.js} | 0 .../actions/{request.js => createRequest.js} | 0 ...{request.test.js => createRequest.test.js} | 0 .../src/actions/{reset.js => createReset.js} | 0 .../{reset.test.js => createReset.test.js} | 0 ...Validation.js => createResetValidation.js} | 0 ....test.js => createResetValidation.test.js} | 0 .../{setGlobal.js => createSetGlobal.js} | 0 ...Global.test.js => createSetGlobal.test.js} | 0 .../{setState.js => createSetState.js} | 0 ...etState.test.js => createSetState.test.js} | 0 .../{validate.js => createValidate.js} | 0 ...alidate.test.js => createValidate.test.js} | 0 .../engine/src/actions/getActionMethods.js | 46 +++++++++---------- 33 files changed, 30 insertions(+), 30 deletions(-) rename packages/engine/src/actions/{callMethod.js => createCallMethod.js} (100%) rename packages/engine/src/actions/{callMethod.test.js => createCallMethod.test.js} (99%) rename packages/engine/src/actions/{message.js => createDisplayMessage.js} (85%) rename packages/engine/src/actions/{message.test.js => createDisplayMessage.test.js} (100%) rename packages/engine/src/actions/{getAction.js => createGetActions.js} (85%) rename packages/engine/src/actions/{getBlockId.js => createGetBlockId.js} (100%) rename packages/engine/src/actions/{getEvent.js => createGetEvent.js} (100%) rename packages/engine/src/actions/{getGlobal.js => createGetGlobal.js} (100%) rename packages/engine/src/actions/{getInput.js => createGetInput.js} (100%) rename packages/engine/src/actions/{getPageId.js => createGetPageId.js} (100%) rename packages/engine/src/actions/{getRequest.js => createGetRequest.js} (100%) rename packages/engine/src/actions/{getState.js => createGetState.js} (100%) rename packages/engine/src/actions/{getUrlQuery.js => createGetUrlQuery.js} (100%) rename packages/engine/src/actions/{getUser.js => createGetUser.js} (100%) rename packages/engine/src/actions/{link.js => createLink.js} (100%) rename packages/engine/src/actions/{link.test.js => createLink.test.js} (100%) rename packages/engine/src/actions/{login.js => createLogin.js} (100%) rename packages/engine/src/actions/{login.test.js => createLogin.test.js} (100%) rename packages/engine/src/actions/{logout.js => createLogout.js} (100%) rename packages/engine/src/actions/{logout.test.js => createLogout.test.js} (100%) rename packages/engine/src/actions/{request.js => createRequest.js} (100%) rename packages/engine/src/actions/{request.test.js => createRequest.test.js} (100%) rename packages/engine/src/actions/{reset.js => createReset.js} (100%) rename packages/engine/src/actions/{reset.test.js => createReset.test.js} (100%) rename packages/engine/src/actions/{resetValidation.js => createResetValidation.js} (100%) rename packages/engine/src/actions/{resetValidation.test.js => createResetValidation.test.js} (100%) rename packages/engine/src/actions/{setGlobal.js => createSetGlobal.js} (100%) rename packages/engine/src/actions/{setGlobal.test.js => createSetGlobal.test.js} (100%) rename packages/engine/src/actions/{setState.js => createSetState.js} (100%) rename packages/engine/src/actions/{setState.test.js => createSetState.test.js} (100%) rename packages/engine/src/actions/{validate.js => createValidate.js} (100%) rename packages/engine/src/actions/{validate.test.js => createValidate.test.js} (100%) diff --git a/packages/engine/src/actions/callMethod.js b/packages/engine/src/actions/createCallMethod.js similarity index 100% rename from packages/engine/src/actions/callMethod.js rename to packages/engine/src/actions/createCallMethod.js diff --git a/packages/engine/src/actions/callMethod.test.js b/packages/engine/src/actions/createCallMethod.test.js similarity index 99% rename from packages/engine/src/actions/callMethod.test.js rename to packages/engine/src/actions/createCallMethod.test.js index c3271809d..110843e97 100644 --- a/packages/engine/src/actions/callMethod.test.js +++ b/packages/engine/src/actions/createCallMethod.test.js @@ -91,7 +91,7 @@ test('CallMethod with no args, synchronous method', async () => { }; const context = await testContext({ lowdefy, - rootBlock: rootBlock, + rootBlock, initState: { textInput: 'init' }, }); const button = context._internal.RootBlocks.map['block:root:button:0']; diff --git a/packages/engine/src/actions/message.js b/packages/engine/src/actions/createDisplayMessage.js similarity index 85% rename from packages/engine/src/actions/message.js rename to packages/engine/src/actions/createDisplayMessage.js index a519253fa..dfc8257c8 100644 --- a/packages/engine/src/actions/message.js +++ b/packages/engine/src/actions/createDisplayMessage.js @@ -14,8 +14,8 @@ limitations under the License. */ -function createMessage({ context }) { - return function message(params = {}) { +function createDisplayMessage({ context }) { + return function displayMessage(params = {}) { context._internal.lowdefy._internal.displayMessage({ content: params.content || 'Success', duration: params.duration, @@ -25,4 +25,4 @@ function createMessage({ context }) { }; } -export default createMessage; +export default createDisplayMessage; diff --git a/packages/engine/src/actions/message.test.js b/packages/engine/src/actions/createDisplayMessage.test.js similarity index 100% rename from packages/engine/src/actions/message.test.js rename to packages/engine/src/actions/createDisplayMessage.test.js diff --git a/packages/engine/src/actions/getAction.js b/packages/engine/src/actions/createGetActions.js similarity index 85% rename from packages/engine/src/actions/getAction.js rename to packages/engine/src/actions/createGetActions.js index 572934317..e7a5e5198 100644 --- a/packages/engine/src/actions/getAction.js +++ b/packages/engine/src/actions/createGetActions.js @@ -16,8 +16,8 @@ import getFromObject from './getFromObject.js'; -function createGetAction({ actions, arrayIndices, blockId }) { - return function getAction(params) { +function createGetActions({ actions, arrayIndices, blockId }) { + return function getActions(params) { return getFromObject({ arrayIndices, location: blockId, @@ -28,4 +28,4 @@ function createGetAction({ actions, arrayIndices, blockId }) { }; } -export default createGetAction; +export default createGetActions; diff --git a/packages/engine/src/actions/getBlockId.js b/packages/engine/src/actions/createGetBlockId.js similarity index 100% rename from packages/engine/src/actions/getBlockId.js rename to packages/engine/src/actions/createGetBlockId.js diff --git a/packages/engine/src/actions/getEvent.js b/packages/engine/src/actions/createGetEvent.js similarity index 100% rename from packages/engine/src/actions/getEvent.js rename to packages/engine/src/actions/createGetEvent.js diff --git a/packages/engine/src/actions/getGlobal.js b/packages/engine/src/actions/createGetGlobal.js similarity index 100% rename from packages/engine/src/actions/getGlobal.js rename to packages/engine/src/actions/createGetGlobal.js diff --git a/packages/engine/src/actions/getInput.js b/packages/engine/src/actions/createGetInput.js similarity index 100% rename from packages/engine/src/actions/getInput.js rename to packages/engine/src/actions/createGetInput.js diff --git a/packages/engine/src/actions/getPageId.js b/packages/engine/src/actions/createGetPageId.js similarity index 100% rename from packages/engine/src/actions/getPageId.js rename to packages/engine/src/actions/createGetPageId.js diff --git a/packages/engine/src/actions/getRequest.js b/packages/engine/src/actions/createGetRequest.js similarity index 100% rename from packages/engine/src/actions/getRequest.js rename to packages/engine/src/actions/createGetRequest.js diff --git a/packages/engine/src/actions/getState.js b/packages/engine/src/actions/createGetState.js similarity index 100% rename from packages/engine/src/actions/getState.js rename to packages/engine/src/actions/createGetState.js diff --git a/packages/engine/src/actions/getUrlQuery.js b/packages/engine/src/actions/createGetUrlQuery.js similarity index 100% rename from packages/engine/src/actions/getUrlQuery.js rename to packages/engine/src/actions/createGetUrlQuery.js diff --git a/packages/engine/src/actions/getUser.js b/packages/engine/src/actions/createGetUser.js similarity index 100% rename from packages/engine/src/actions/getUser.js rename to packages/engine/src/actions/createGetUser.js diff --git a/packages/engine/src/actions/link.js b/packages/engine/src/actions/createLink.js similarity index 100% rename from packages/engine/src/actions/link.js rename to packages/engine/src/actions/createLink.js diff --git a/packages/engine/src/actions/link.test.js b/packages/engine/src/actions/createLink.test.js similarity index 100% rename from packages/engine/src/actions/link.test.js rename to packages/engine/src/actions/createLink.test.js diff --git a/packages/engine/src/actions/login.js b/packages/engine/src/actions/createLogin.js similarity index 100% rename from packages/engine/src/actions/login.js rename to packages/engine/src/actions/createLogin.js diff --git a/packages/engine/src/actions/login.test.js b/packages/engine/src/actions/createLogin.test.js similarity index 100% rename from packages/engine/src/actions/login.test.js rename to packages/engine/src/actions/createLogin.test.js diff --git a/packages/engine/src/actions/logout.js b/packages/engine/src/actions/createLogout.js similarity index 100% rename from packages/engine/src/actions/logout.js rename to packages/engine/src/actions/createLogout.js diff --git a/packages/engine/src/actions/logout.test.js b/packages/engine/src/actions/createLogout.test.js similarity index 100% rename from packages/engine/src/actions/logout.test.js rename to packages/engine/src/actions/createLogout.test.js diff --git a/packages/engine/src/actions/request.js b/packages/engine/src/actions/createRequest.js similarity index 100% rename from packages/engine/src/actions/request.js rename to packages/engine/src/actions/createRequest.js diff --git a/packages/engine/src/actions/request.test.js b/packages/engine/src/actions/createRequest.test.js similarity index 100% rename from packages/engine/src/actions/request.test.js rename to packages/engine/src/actions/createRequest.test.js diff --git a/packages/engine/src/actions/reset.js b/packages/engine/src/actions/createReset.js similarity index 100% rename from packages/engine/src/actions/reset.js rename to packages/engine/src/actions/createReset.js diff --git a/packages/engine/src/actions/reset.test.js b/packages/engine/src/actions/createReset.test.js similarity index 100% rename from packages/engine/src/actions/reset.test.js rename to packages/engine/src/actions/createReset.test.js diff --git a/packages/engine/src/actions/resetValidation.js b/packages/engine/src/actions/createResetValidation.js similarity index 100% rename from packages/engine/src/actions/resetValidation.js rename to packages/engine/src/actions/createResetValidation.js diff --git a/packages/engine/src/actions/resetValidation.test.js b/packages/engine/src/actions/createResetValidation.test.js similarity index 100% rename from packages/engine/src/actions/resetValidation.test.js rename to packages/engine/src/actions/createResetValidation.test.js diff --git a/packages/engine/src/actions/setGlobal.js b/packages/engine/src/actions/createSetGlobal.js similarity index 100% rename from packages/engine/src/actions/setGlobal.js rename to packages/engine/src/actions/createSetGlobal.js diff --git a/packages/engine/src/actions/setGlobal.test.js b/packages/engine/src/actions/createSetGlobal.test.js similarity index 100% rename from packages/engine/src/actions/setGlobal.test.js rename to packages/engine/src/actions/createSetGlobal.test.js diff --git a/packages/engine/src/actions/setState.js b/packages/engine/src/actions/createSetState.js similarity index 100% rename from packages/engine/src/actions/setState.js rename to packages/engine/src/actions/createSetState.js diff --git a/packages/engine/src/actions/setState.test.js b/packages/engine/src/actions/createSetState.test.js similarity index 100% rename from packages/engine/src/actions/setState.test.js rename to packages/engine/src/actions/createSetState.test.js diff --git a/packages/engine/src/actions/validate.js b/packages/engine/src/actions/createValidate.js similarity index 100% rename from packages/engine/src/actions/validate.js rename to packages/engine/src/actions/createValidate.js diff --git a/packages/engine/src/actions/validate.test.js b/packages/engine/src/actions/createValidate.test.js similarity index 100% rename from packages/engine/src/actions/validate.test.js rename to packages/engine/src/actions/createValidate.test.js diff --git a/packages/engine/src/actions/getActionMethods.js b/packages/engine/src/actions/getActionMethods.js index 856ffd00c..7ebd92fd9 100644 --- a/packages/engine/src/actions/getActionMethods.js +++ b/packages/engine/src/actions/getActionMethods.js @@ -14,32 +14,32 @@ limitations under the License. */ -import createCallMethod from './callMethod.js'; -import createGetAction from './getAction.js'; -import createGetBlockId from './getBlockId.js'; -import createGetEvent from './getEvent.js'; -import createGetGlobal from './getGlobal.js'; -import createGetInput from './getInput.js'; -import createGetPageId from './getPageId.js'; -import createGetRequest from './getRequest.js'; -import createGetState from './getState.js'; -import createGetUrlQuery from './getUrlQuery.js'; -import createGetUser from './getUser.js'; -import createLink from './link.js'; -import createLogin from './login.js'; -import createLogout from './logout.js'; -import createMessage from './message.js'; -import createRequest from './request.js'; -import createReset from './reset.js'; -import createResetValidation from './resetValidation.js'; -import createSetGlobal from './setGlobal.js'; -import createSetState from './setState.js'; -import createValidate from './validate.js'; +import createCallMethod from './createCallMethod.js'; +import createGetActions from './createGetActions.js'; +import createGetBlockId from './createGetBlockId.js'; +import createGetEvent from './createGetEvent.js'; +import createGetGlobal from './createGetGlobal.js'; +import createGetInput from './createGetInput.js'; +import createGetPageId from './createGetPageId.js'; +import createGetRequest from './createGetRequest.js'; +import createGetState from './createGetState.js'; +import createGetUrlQuery from './createGetUrlQuery.js'; +import createGetUser from './createGetUser.js'; +import createLink from './createLink.js'; +import createLogin from './createLogin.js'; +import createLogout from './createLogout.js'; +import createDisplayMessage from './createDisplayMessage.js'; +import createRequest from './createRequest.js'; +import createReset from './createReset.js'; +import createResetValidation from './createResetValidation.js'; +import createSetGlobal from './createSetGlobal.js'; +import createSetState from './createSetState.js'; +import createValidate from './createValidate.js'; function getActionMethods(props) { return { callMethod: createCallMethod(props), - getAction: createGetAction(props), + getActions: createGetActions(props), getBlockId: createGetBlockId(props), getEvent: createGetEvent(props), getGlobal: createGetGlobal(props), @@ -52,7 +52,7 @@ function getActionMethods(props) { link: createLink(props), login: createLogin(props), logout: createLogout(props), - message: createMessage(props), + message: createDisplayMessage(props), request: createRequest(props), reset: createReset(props), resetValidation: createResetValidation(props), From e2cd39f14777531475fbbb0e5b093fa4938e4e8a Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:33:07 +0200 Subject: [PATCH 51/79] chore(engine): Removed getGlobal default object: lowdefyGlobal. --- packages/engine/src/actions/createGetGlobal.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/actions/createGetGlobal.js b/packages/engine/src/actions/createGetGlobal.js index 09bbb8a9a..cb17ae4a6 100644 --- a/packages/engine/src/actions/createGetGlobal.js +++ b/packages/engine/src/actions/createGetGlobal.js @@ -21,7 +21,7 @@ function createGetGlobal({ arrayIndices, blockId, context }) { return getFromObject({ arrayIndices, location: blockId, - object: context._internal.lowdefy.lowdefyGlobal || {}, + object: context._internal.lowdefy.lowdefyGlobal, method: 'getGlobal', params, }); From 2e3ecdf0863ea9ec370235c83e7e1ce10a358298 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:39:30 +0200 Subject: [PATCH 52/79] chore(engine): Removed getInput object default. --- packages/engine/src/actions/createGetInput.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/actions/createGetInput.js b/packages/engine/src/actions/createGetInput.js index 48b9e91ed..01016fc32 100644 --- a/packages/engine/src/actions/createGetInput.js +++ b/packages/engine/src/actions/createGetInput.js @@ -21,7 +21,7 @@ function createGetInput({ arrayIndices, blockId, context }) { return getFromObject({ arrayIndices, location: blockId, - object: context._internal.lowdefy.inputs ? context._internal.lowdefy.inputs[context.id] : {}, + object: context._internal.lowdefy.inputs[context.id], method: 'getInput', params, }); From 4de9b0e377dee2e85631bf73af33eb3df9ab0bb7 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:40:46 +0200 Subject: [PATCH 53/79] chore(engine): Removed getGetUrlQuery object default. --- packages/engine/src/actions/createGetUrlQuery.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/actions/createGetUrlQuery.js b/packages/engine/src/actions/createGetUrlQuery.js index b63ef4609..22e45b930 100644 --- a/packages/engine/src/actions/createGetUrlQuery.js +++ b/packages/engine/src/actions/createGetUrlQuery.js @@ -21,7 +21,7 @@ function createGetUrlQuery({ arrayIndices, blockId, context }) { return getFromObject({ arrayIndices, location: blockId, - object: context._internal.lowdefy.urlQuery || {}, + object: context._internal.lowdefy.urlQuery, method: 'getUrlQuery', params, }); From 9988b3051a0949d568d59c97d611c40e21cceb41 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:47:39 +0200 Subject: [PATCH 54/79] chore(engine): Remove comments to silence errors and logs from createRequest test. --- packages/engine/src/actions/createRequest.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/engine/src/actions/createRequest.test.js b/packages/engine/src/actions/createRequest.test.js index 2df56f03e..d9f8830a8 100644 --- a/packages/engine/src/actions/createRequest.test.js +++ b/packages/engine/src/actions/createRequest.test.js @@ -56,8 +56,8 @@ const mockDate = jest.fn(() => ({ date: 0 })); mockDate.now = jest.fn(() => 0); // Comment out to use console -// console.log = () => {}; -// console.error = () => {}; +console.log = () => {}; +console.error = () => {}; beforeAll(() => { global.Date = mockDate; From 18a2385dfe2e86dd0c9cb9c6ed103470518a5613 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:56:41 +0200 Subject: [PATCH 55/79] chore(engine): Refactor displayMessage action params. --- packages/engine/src/actions/createDisplayMessage.js | 7 +------ .../plugins/actions/actions-core/src/actions/Message.js | 7 ++++++- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/engine/src/actions/createDisplayMessage.js b/packages/engine/src/actions/createDisplayMessage.js index dfc8257c8..f8c6b9e05 100644 --- a/packages/engine/src/actions/createDisplayMessage.js +++ b/packages/engine/src/actions/createDisplayMessage.js @@ -16,12 +16,7 @@ function createDisplayMessage({ context }) { return function displayMessage(params = {}) { - context._internal.lowdefy._internal.displayMessage({ - content: params.content || 'Success', - duration: params.duration, - icon: params.icon, - status: params.status, - }); + context._internal.lowdefy._internal.displayMessage(params); }; } diff --git a/packages/plugins/actions/actions-core/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js index 0e3ec319e..a18dfacd1 100644 --- a/packages/plugins/actions/actions-core/src/actions/Message.js +++ b/packages/plugins/actions/actions-core/src/actions/Message.js @@ -15,7 +15,12 @@ */ function Message({ methods: { message }, params }) { - message(params); + message({ + content: params.content || 'Success', + duration: params.duration, + icon: params.icon, + status: params.status, + }); } export default Message; From 66e5e2a699c09cbe70da4778e022535f7956f2d1 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 15:58:54 +0200 Subject: [PATCH 56/79] chore(engine): Removed object default from getUser action params. --- packages/engine/src/actions/createGetUser.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/engine/src/actions/createGetUser.js b/packages/engine/src/actions/createGetUser.js index 94f06d59e..1e3fe896e 100644 --- a/packages/engine/src/actions/createGetUser.js +++ b/packages/engine/src/actions/createGetUser.js @@ -21,7 +21,7 @@ function createGetUser({ arrayIndices, blockId, context }) { return getFromObject({ arrayIndices, location: blockId, - object: context._internal.lowdefy.user || {}, + object: context._internal.lowdefy.user, method: 'getUser', params, }); From 4f838cf0a144424c2e84723b46b8b8b04be9c76b Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:15:26 +0200 Subject: [PATCH 57/79] chore(engine): Reorder triggerEvents in validate and resetValidation methods. --- packages/engine/src/actions/createResetValidation.test.js | 4 ++-- packages/engine/src/actions/createValidate.test.js | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/engine/src/actions/createResetValidation.test.js b/packages/engine/src/actions/createResetValidation.test.js index dc1a3c979..2fba74eb8 100644 --- a/packages/engine/src/actions/createResetValidation.test.js +++ b/packages/engine/src/actions/createResetValidation.test.js @@ -174,12 +174,12 @@ test('RestValidation after required field', async () => { const button = context._internal.RootBlocks.map['button']; const reset = context._internal.RootBlocks.map['reset']; const text1 = context._internal.RootBlocks.map['text1']; - await button.triggerEvent({ name: 'onClick' }); expect(text1.eval.validation).toEqual({ errors: ['This field is required'], - status: 'error', + status: null, warnings: [], }); + await button.triggerEvent({ name: 'onClick' }); expect(button.Events.events.onClick.history[0]).toEqual({ blockId: 'button', bounced: false, diff --git a/packages/engine/src/actions/createValidate.test.js b/packages/engine/src/actions/createValidate.test.js index e09971f24..5c087413c 100644 --- a/packages/engine/src/actions/createValidate.test.js +++ b/packages/engine/src/actions/createValidate.test.js @@ -339,12 +339,12 @@ test('Validate all fields', async () => { const button = context._internal.RootBlocks.map['button']; const text1 = context._internal.RootBlocks.map['text1']; const text2 = context._internal.RootBlocks.map['text2']; - await button.triggerEvent({ name: 'onClick' }); expect(text1.eval.validation).toEqual({ errors: ['text1 does not match pattern "text1"'], - status: 'error', + status: null, warnings: [], }); + await button.triggerEvent({ name: 'onClick' }); expect(button.Events.events.onClick.history[0]).toEqual({ blockId: 'button', bounced: false, From a03128fc268e8dc582dd884bb04b70140f162c72 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:18:20 +0200 Subject: [PATCH 58/79] chore(actions-core): Separated guard and if-else statement in ScrollTo action. --- packages/plugins/actions/actions-core/src/actions/ScrollTo.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js index 68524d2c7..ced67980e 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.js @@ -19,7 +19,8 @@ import { type } from '@lowdefy/helpers'; function ScrollTo({ document, params, window }) { if (!type.isObject(params)) { throw new Error(`Invalid ScrollTo, check action params. Received "${JSON.stringify(params)}".`); - } else if (params.blockId) { + } + if (params.blockId) { const element = document.getElementById(params.blockId); if (element) { element.scrollIntoView(params.options); From 6c3abb71e8e82612c18148c00add90d6d8e1f36f Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:44:21 +0200 Subject: [PATCH 59/79] feat(engine): BREAKING CHANGE - The Message action was renamed to DisplayMessage. BREAKING CHANGE: The Message action was renamed to DisplayMessage. --- .../src/actions/createDisplayMessage.test.js | 19 +++++++------ .../engine/src/actions/getActionMethods.js | 2 +- .../actions/actions-core/src/actions.js | 2 +- .../src/actions/DisplayMessage.js | 27 ++++++++++++++++++ .../src/actions/DisplayMessage.test.js | 28 +++++++++++++++++++ 5 files changed, 68 insertions(+), 10 deletions(-) create mode 100644 packages/plugins/actions/actions-core/src/actions/DisplayMessage.js create mode 100644 packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js diff --git a/packages/engine/src/actions/createDisplayMessage.test.js b/packages/engine/src/actions/createDisplayMessage.test.js index 8750e2210..170565b72 100644 --- a/packages/engine/src/actions/createDisplayMessage.test.js +++ b/packages/engine/src/actions/createDisplayMessage.test.js @@ -22,8 +22,11 @@ const mockMessage = jest.fn(() => () => undefined); const lowdefy = { _internal: { actions: { - Message: ({ methods: { message }, params }) => { - return message(params); + DisplayMessage: ({ methods: { displayMessage }, params }) => { + return displayMessage({ + ...params, + content: params ? params.content : 'Success', + }); }, }, blockComponents: { @@ -33,7 +36,7 @@ const lowdefy = { }, }; -test('Message with content', async () => { +test('DisplayMessage with content', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', @@ -55,7 +58,7 @@ test('Message with content', async () => { onClick: [ { id: 'a', - type: 'Message', + type: 'DisplayMessage', params: { content: 'test' }, }, ], @@ -80,7 +83,7 @@ test('Message with content', async () => { ]); }); -test('Message with all params', async () => { +test('DisplayMessage with all params', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', @@ -102,7 +105,7 @@ test('Message with all params', async () => { onClick: [ { id: 'a', - type: 'Message', + type: 'DisplayMessage', params: { content: 'content', duration: 6, @@ -135,7 +138,7 @@ test('Message with all params', async () => { ]); }); -test('Message with no params', async () => { +test('DisplayMessage with no params', async () => { const rootBlock = { id: 'block:root:root:0', blockId: 'root', @@ -157,7 +160,7 @@ test('Message with no params', async () => { onClick: [ { id: 'a', - type: 'Message', + type: 'DisplayMessage', }, ], }, diff --git a/packages/engine/src/actions/getActionMethods.js b/packages/engine/src/actions/getActionMethods.js index 7ebd92fd9..b776727a3 100644 --- a/packages/engine/src/actions/getActionMethods.js +++ b/packages/engine/src/actions/getActionMethods.js @@ -39,6 +39,7 @@ import createValidate from './createValidate.js'; function getActionMethods(props) { return { callMethod: createCallMethod(props), + displayMessage: createDisplayMessage(props), getActions: createGetActions(props), getBlockId: createGetBlockId(props), getEvent: createGetEvent(props), @@ -52,7 +53,6 @@ function getActionMethods(props) { link: createLink(props), login: createLogin(props), logout: createLogout(props), - message: createDisplayMessage(props), request: createRequest(props), reset: createReset(props), resetValidation: createResetValidation(props), diff --git a/packages/plugins/actions/actions-core/src/actions.js b/packages/plugins/actions/actions-core/src/actions.js index faf9a5cb3..9335c7304 100644 --- a/packages/plugins/actions/actions-core/src/actions.js +++ b/packages/plugins/actions/actions-core/src/actions.js @@ -18,7 +18,7 @@ export { default as CallMethod } from './actions/CallMethod.js'; export { default as Link } from './actions/Link.js'; export { default as Login } from './actions/Login.js'; export { default as Logout } from './actions/Logout.js'; -export { default as Message } from './actions/Message.js'; +export { default as DisplayMessage } from './actions/DisplayMessage.js'; export { default as Request } from './actions/Request.js'; export { default as Reset } from './actions/Reset.js'; export { default as ResetValidation } from './actions/ResetValidation.js'; diff --git a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js new file mode 100644 index 000000000..fa5c22271 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js @@ -0,0 +1,27 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import { type } from '@lowdefy/helpers'; + +function DisplayMessage({ methods: { displayMessage }, params }) { + let defaultParams = params; + if (type.isObject(params)) { + defaultParams = { ...defaultParams, content: params.content || 'Success' }; + } + displayMessage(defaultParams); +} + +export default DisplayMessage; diff --git a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js new file mode 100644 index 000000000..8db50cfd6 --- /dev/null +++ b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js @@ -0,0 +1,28 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import DisplayMessage from './DisplayMessage.js'; + +const mockActionMethod = jest.fn(); + +beforeEach(() => { + mockActionMethod.mockReset(); +}); + +test('Message action invocation', async () => { + DisplayMessage({ methods: { displayMessage: mockActionMethod }, params: 'call' }); + expect(mockActionMethod.mock.calls).toEqual([['call']]); +}); From a9bfe65f42094d53cd4eee60aa34fbd0a5e180a6 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:44:33 +0200 Subject: [PATCH 60/79] feat(actions-core): BREAKING CHANGE - The Message action was renamed to DisplayMessage. --- .../actions-core/src/actions/Message.js | 26 ----------------- .../actions-core/src/actions/Message.test.js | 28 ------------------- 2 files changed, 54 deletions(-) delete mode 100644 packages/plugins/actions/actions-core/src/actions/Message.js delete mode 100644 packages/plugins/actions/actions-core/src/actions/Message.test.js diff --git a/packages/plugins/actions/actions-core/src/actions/Message.js b/packages/plugins/actions/actions-core/src/actions/Message.js deleted file mode 100644 index a18dfacd1..000000000 --- a/packages/plugins/actions/actions-core/src/actions/Message.js +++ /dev/null @@ -1,26 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -function Message({ methods: { message }, params }) { - message({ - content: params.content || 'Success', - duration: params.duration, - icon: params.icon, - status: params.status, - }); -} - -export default Message; diff --git a/packages/plugins/actions/actions-core/src/actions/Message.test.js b/packages/plugins/actions/actions-core/src/actions/Message.test.js deleted file mode 100644 index 28d0cee47..000000000 --- a/packages/plugins/actions/actions-core/src/actions/Message.test.js +++ /dev/null @@ -1,28 +0,0 @@ -/* - Copyright 2020-2021 Lowdefy, Inc - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -import Message from './Message.js'; - -const mockActionMethod = jest.fn(); - -beforeEach(() => { - mockActionMethod.mockReset(); -}); - -test('Message action invocation', async () => { - Message({ methods: { message: mockActionMethod }, params: 'call' }); - expect(mockActionMethod.mock.calls).toEqual([['call']]); -}); From d79d832d4817891df5f01de96d5b325d6bfa5236 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:45:00 +0200 Subject: [PATCH 61/79] chore(actions-core): Changed Link Action function declaration. --- packages/plugins/actions/actions-core/src/actions/Link.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/Link.js b/packages/plugins/actions/actions-core/src/actions/Link.js index cfd94ea1a..1859970fd 100644 --- a/packages/plugins/actions/actions-core/src/actions/Link.js +++ b/packages/plugins/actions/actions-core/src/actions/Link.js @@ -16,7 +16,7 @@ import { type } from '@lowdefy/helpers'; -const Link = ({ methods: { link }, params }) => { +function Link({ methods: { link }, params }) { const linkParams = type.isString(params) ? { pageId: params } : params; try { link(linkParams); @@ -24,6 +24,6 @@ const Link = ({ methods: { link }, params }) => { console.log(error); throw new Error(`Invalid Link, check action params. Received "${JSON.stringify(params)}".`); } -}; +} export default Link; From 32c0b7c96f07e16c5a4b16b8501ea44da3f2ba76 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:49:55 +0200 Subject: [PATCH 62/79] fix(engine): Changed method action from getRequest to getRequestDetails. --- .../{createGetRequest.js => createGetRequestDetails.js} | 8 ++++---- packages/engine/src/actions/getActionMethods.js | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) rename packages/engine/src/actions/{createGetRequest.js => createGetRequestDetails.js} (79%) diff --git a/packages/engine/src/actions/createGetRequest.js b/packages/engine/src/actions/createGetRequestDetails.js similarity index 79% rename from packages/engine/src/actions/createGetRequest.js rename to packages/engine/src/actions/createGetRequestDetails.js index d4772e16e..a35125ae3 100644 --- a/packages/engine/src/actions/createGetRequest.js +++ b/packages/engine/src/actions/createGetRequestDetails.js @@ -16,16 +16,16 @@ import getFromObject from './getFromObject.js'; -const createGetRequest = ({ arrayIndices, blockId, context }) => { - return function getRequest(params) { +const createGetRequestDetails = ({ arrayIndices, blockId, context }) => { + return function getRequestDetails(params) { return getFromObject({ arrayIndices, location: blockId, object: context.requests, - method: 'getRequest', + method: 'getRequestDetails', params, }); }; }; -export default createGetRequest; +export default createGetRequestDetails; diff --git a/packages/engine/src/actions/getActionMethods.js b/packages/engine/src/actions/getActionMethods.js index b776727a3..bc67a5d51 100644 --- a/packages/engine/src/actions/getActionMethods.js +++ b/packages/engine/src/actions/getActionMethods.js @@ -21,7 +21,7 @@ import createGetEvent from './createGetEvent.js'; import createGetGlobal from './createGetGlobal.js'; import createGetInput from './createGetInput.js'; import createGetPageId from './createGetPageId.js'; -import createGetRequest from './createGetRequest.js'; +import createGetRequestDetails from './createGetRequestDetails.js'; import createGetState from './createGetState.js'; import createGetUrlQuery from './createGetUrlQuery.js'; import createGetUser from './createGetUser.js'; @@ -46,7 +46,7 @@ function getActionMethods(props) { getGlobal: createGetGlobal(props), getInput: createGetInput(props), getPageId: createGetPageId(props), - getRequest: createGetRequest(props), + getRequestDetails: createGetRequestDetails(props), getState: createGetState(props), getUrlQuery: createGetUrlQuery(props), getUser: createGetUser(props), From 140218075f0f9ce00c0e930a7b18db5629bb1ab0 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 16:59:17 +0200 Subject: [PATCH 63/79] fix(actions-core): Added scrollTo with no params error test. --- .../actions-core/src/actions/ScrollTo.test.js | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js b/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js index c9aa7d396..f4bd3f9cd 100644 --- a/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js +++ b/packages/plugins/actions/actions-core/src/actions/ScrollTo.test.js @@ -64,6 +64,18 @@ beforeEach(() => { mockElemScrollIntoView.mockReset(); }); +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + test('ScrollTo with no params', async () => { const rootBlock = { id: 'block:root:root:0', @@ -95,8 +107,34 @@ test('ScrollTo with no params', async () => { rootBlock, }); const button = context._internal.RootBlocks.map['block:root:button:0']; - button.triggerEvent({ name: 'onClick' }); - expect(mockWindowScrollTo.mock.calls).toEqual([]); + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { + id: 'a', + type: 'ScrollTo', + }, + error: { + error: new Error('Invalid ScrollTo, check action params. Received "undefined".'), + index: 0, + type: 'ScrollTo', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error('Invalid ScrollTo, check action params. Received "undefined".'), + index: 0, + type: 'ScrollTo', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); }); test('ScrollTo with no blockId', async () => { From b854e66b5cc70d00a7f5886e31c980e8acc9ffbb Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 17:11:43 +0200 Subject: [PATCH 64/79] chore(engine): Updated link action test method. --- packages/engine/src/actions/createLink.test.js | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/engine/src/actions/createLink.test.js b/packages/engine/src/actions/createLink.test.js index 551e7464b..4ebefe085 100644 --- a/packages/engine/src/actions/createLink.test.js +++ b/packages/engine/src/actions/createLink.test.js @@ -14,13 +14,23 @@ limitations under the License. */ +import { type } from '@lowdefy/helpers'; + import testContext from '../../test/testContext.js'; const lowdefy = { _internal: { actions: { Link: ({ methods: { link }, params }) => { - return link(params); + const linkParams = type.isString(params) ? { pageId: params } : params; + try { + link(linkParams); + } catch (error) { + console.log(error); + throw new Error( + `Invalid Link, check action params. Received "${JSON.stringify(params)}".` + ); + } }, }, blockComponents: { @@ -81,7 +91,7 @@ test('Link with string pageId params', async () => { }); const button = context._internal.RootBlocks.map['block:root:button:0']; const res = await button.triggerEvent({ name: 'onClick' }); - expect(lowdefy._internal.link.mock.calls).toEqual([['pageId']]); + expect(lowdefy._internal.link.mock.calls).toEqual([[{ pageId: 'pageId' }]]); expect(res.success).toBe(true); }); @@ -184,7 +194,7 @@ test('Link error', async () => { type: 'Link', }, error: { - error: new Error('Link test error'), + error: new Error('Invalid Link, check action params. Received "{"invalid":true}".'), index: 0, type: 'Link', }, @@ -192,7 +202,7 @@ test('Link error', async () => { responses: { a: { type: 'Link', - error: new Error('Link test error'), + error: new Error('Invalid Link, check action params. Received "{"invalid":true}".'), index: 0, }, }, From 10cc7ea143367268448da45e4e1a973424cbe127 Mon Sep 17 00:00:00 2001 From: Sandile Date: Fri, 11 Feb 2022 17:14:11 +0200 Subject: [PATCH 65/79] chore(engine): Updated request action test method. --- packages/engine/src/actions/createRequest.test.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/engine/src/actions/createRequest.test.js b/packages/engine/src/actions/createRequest.test.js index d9f8830a8..32a6ce199 100644 --- a/packages/engine/src/actions/createRequest.test.js +++ b/packages/engine/src/actions/createRequest.test.js @@ -34,7 +34,12 @@ const mockReqResponses = { const mockCallRequest = jest.fn(); const mockCallRequestImp = ({ requestId }) => { if (requestId === 'req_error') throw mockReqResponses['req_error']; - return mockReqResponses[requestId]; + return new Promise((resolve, reject) => { + if (requestId === 'req_error') { + reject(mockReqResponses[requestId]); + } + resolve(mockReqResponses[requestId]); + }); }; const lowdefy = { From 46ad3c07982dacb481b1513750db19b55fe89382 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 12:31:08 +0200 Subject: [PATCH 66/79] fix(engine): Reverted index based block id change in callMethod action test. --- .../src/actions/createCallMethod.test.js | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/packages/engine/src/actions/createCallMethod.test.js b/packages/engine/src/actions/createCallMethod.test.js index 110843e97..71a57eafd 100644 --- a/packages/engine/src/actions/createCallMethod.test.js +++ b/packages/engine/src/actions/createCallMethod.test.js @@ -80,7 +80,7 @@ test('CallMethod with no args, synchronous method', async () => { { id: 'a', type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'blockMethod' }, + params: { blockId: 'textInput', method: 'blockMethod' }, }, ], }, @@ -161,7 +161,7 @@ test('CallMethod method return a promise', async () => { id: 'a', type: 'CallMethod', params: { - blockId: 'block:root:textInput:0', + blockId: 'textInput', method: 'blockMethod', args: ['arg'], }, @@ -236,7 +236,7 @@ test('CallMethod with args not an array', async () => { { id: 'a', type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'blockMethod', args: 'arg' }, + params: { blockId: 'textInput', method: 'blockMethod', args: 'arg' }, }, ], }, @@ -271,7 +271,7 @@ test('CallMethod with args not an array', async () => { }, error: { error: new Error( - 'Failed to call method "blockMethod" on block "block:root:textInput:0": "args" should be an array. Received "{"blockId":"block:root:textInput:0","method":"blockMethod","args":"arg"}".' + 'Failed to call method "blockMethod" on block "textInput": "args" should be an array. Received "{"blockId":"textInput","method":"blockMethod","args":"arg"}".' ), index: 0, type: 'CallMethod', @@ -282,7 +282,7 @@ test('CallMethod with args not an array', async () => { type: 'CallMethod', index: 0, error: new Error( - 'Failed to call method "blockMethod" on block "block:root:textInput:0": "args" should be an array. Received "{"blockId":"block:root:textInput:0","method":"blockMethod","args":"arg"}".' + 'Failed to call method "blockMethod" on block "textInput": "args" should be an array. Received "{"blockId":"textInput","method":"blockMethod","args":"arg"}".' ), }, }, @@ -327,7 +327,7 @@ test('CallMethod with multiple positional args, synchronous method', async () => id: 'a', type: 'CallMethod', params: { - blockId: 'block:root:textInput:0', + blockId: 'textInput', method: 'blockMethod', args: ['arg1', 'arg2'], }, @@ -420,7 +420,7 @@ test('CallMethod of block in array by explicit id', async () => { id: 'a', type: 'CallMethod', params: { - blockId: 'block:root:list.0.textInput:0', + blockId: 'list.0.textInput', method: 'blockMethod', args: ['arg'], }, @@ -494,7 +494,7 @@ test('CallMethod of block in array by block with same indices and id pattern', a id: 'a', type: 'CallMethod', params: { - blockId: 'block:root:list.$.textInput:0', + blockId: 'list.$.textInput', method: 'blockMethod', args: ['arg'], }, @@ -562,7 +562,7 @@ test('CallMethod with method does not exist', async () => { { id: 'a', type: 'CallMethod', - params: { blockId: 'block:root:textInput:0', method: 'no-method' }, + params: { blockId: 'textInput', method: 'no-method' }, }, ], }, @@ -594,7 +594,7 @@ test('CallMethod with method does not exist', async () => { }, error: { error: new Error( - 'Failed to call method "no-method" on block "block:root:textInput:0". Check if "no-method" is a valid block method for block "block:root:textInput:0". Received "{"blockId":"block:root:textInput:0","method":"no-method"}".' + 'Failed to call method "no-method" on block "textInput". Check if "no-method" is a valid block method for block "textInput". Received "{"blockId":"textInput","method":"no-method"}".' ), index: 0, type: 'CallMethod', @@ -605,7 +605,7 @@ test('CallMethod with method does not exist', async () => { type: 'CallMethod', index: 0, error: new Error( - 'Failed to call method "no-method" on block "block:root:textInput:0". Check if "no-method" is a valid block method for block "block:root:textInput:0". Received "{"blockId":"block:root:textInput:0","method":"no-method"}".' + 'Failed to call method "no-method" on block "textInput". Check if "no-method" is a valid block method for block "textInput". Received "{"blockId":"textInput","method":"no-method"}".' ), }, }, From 1d70f64983922070916537c0a81b4ed343810365 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 14:29:33 +0200 Subject: [PATCH 67/79] feat(actions-core): Updated DisplayMessage action and tests to include edge cases. --- .pnp.cjs | 41 ++- .../jest-npm-27.4.7-cdda9da561-28ce948b30.zip | Bin 0 -> 3590 bytes .../src/actions/DisplayMessage.js | 19 +- .../src/actions/DisplayMessage.test.js | 333 +++++++++++++++++- yarn.lock | 24 +- 5 files changed, 396 insertions(+), 21 deletions(-) create mode 100644 .yarn/cache/jest-npm-27.4.7-cdda9da561-28ce948b30.zip diff --git a/.pnp.cjs b/.pnp.cjs index ef9ea868d..ab3486ee8 100755 --- a/.pnp.cjs +++ b/.pnp.cjs @@ -2810,7 +2810,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ["@swc/cli", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.1.55"], ["@swc/core", "npm:1.2.135"], ["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"], - ["jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:27.4.7"] + ["jest", "virtual:42e288f3c714e1d86d12bf40fb17a72864641a713e0a167e85a3dab47534d11bcd2e71357e431b2f4737000bc9432f95c60dff0c9bfb212cd46e1f0f5bf0ad9f#npm:27.4.7"] ], "linkType": "SOFT", }] @@ -3070,8 +3070,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { "packageLocation": "./packages/build/", "packageDependencies": [ ["@lowdefy/build", "workspace:packages/build"], - ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@jest/globals", "npm:27.5.1"], + ["@lowdefy/actions-core", "workspace:packages/plugins/actions/actions-core"], ["@lowdefy/ajv", "workspace:packages/utils/ajv"], ["@lowdefy/blocks-antd", "workspace:packages/plugins/blocks/blocks-antd"], ["@lowdefy/blocks-basic", "workspace:packages/plugins/blocks/blocks-basic"], @@ -10506,6 +10506,13 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { }] ]], ["jest", [ + ["npm:27.4.7", { + "packageLocation": "./.yarn/cache/jest-npm-27.4.7-cdda9da561-28ce948b30.zip/node_modules/jest/", + "packageDependencies": [ + ["jest", "npm:27.4.7"] + ], + "linkType": "SOFT", + }], ["npm:27.5.1", { "packageLocation": "./.yarn/cache/jest-npm-27.5.1-bacad4fe2a-96f1d69042.zip/node_modules/jest/", "packageDependencies": [ @@ -10513,6 +10520,22 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) { ], "linkType": "SOFT", }], + ["virtual:42e288f3c714e1d86d12bf40fb17a72864641a713e0a167e85a3dab47534d11bcd2e71357e431b2f4737000bc9432f95c60dff0c9bfb212cd46e1f0f5bf0ad9f#npm:27.4.7", { + "packageLocation": "./.yarn/__virtual__/jest-virtual-4325f46d83/0/cache/jest-npm-27.4.7-cdda9da561-28ce948b30.zip/node_modules/jest/", + "packageDependencies": [ + ["jest", "virtual:42e288f3c714e1d86d12bf40fb17a72864641a713e0a167e85a3dab47534d11bcd2e71357e431b2f4737000bc9432f95c60dff0c9bfb212cd46e1f0f5bf0ad9f#npm:27.4.7"], + ["@jest/core", "virtual:af105d7a2bc799821f67e8114057f53830abc6c7c9faa96846247605351f361b4158d347970d00ebc3c04dbab6e46e1c1e24df193c1caf1f7d80a00c65068a2a#npm:27.5.1"], + ["@types/node-notifier", null], + ["import-local", "npm:3.1.0"], + ["jest-cli", "virtual:af105d7a2bc799821f67e8114057f53830abc6c7c9faa96846247605351f361b4158d347970d00ebc3c04dbab6e46e1c1e24df193c1caf1f7d80a00c65068a2a#npm:27.5.1"], + ["node-notifier", null] + ], + "packagePeers": [ + "@types/node-notifier", + "node-notifier" + ], + "linkType": "HARD", + }], ["virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:27.5.1", { "packageLocation": "./.yarn/__virtual__/jest-virtual-af105d7a2b/0/cache/jest-npm-27.5.1-bacad4fe2a-96f1d69042.zip/node_modules/jest/", "packageDependencies": [ @@ -23634,7 +23657,7 @@ module.exports = require("path");; /************************************************************************/ /******/ // The module cache /******/ var __webpack_module_cache__ = {}; -/******/ +/******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ // Check if module is in cache @@ -23648,14 +23671,14 @@ module.exports = require("path");; /******/ // no module.loaded needed /******/ exports: {} /******/ }; -/******/ +/******/ /******/ // Execute the module function /******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); -/******/ +/******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } -/******/ +/******/ /************************************************************************/ /******/ /* webpack/runtime/compat get default export */ /******/ (() => { @@ -23668,7 +23691,7 @@ module.exports = require("path");; /******/ return getter; /******/ }; /******/ })(); -/******/ +/******/ /******/ /* webpack/runtime/define property getters */ /******/ (() => { /******/ // define getter functions for harmony exports @@ -23680,12 +23703,12 @@ module.exports = require("path");; /******/ } /******/ }; /******/ })(); -/******/ +/******/ /******/ /* webpack/runtime/hasOwnProperty shorthand */ /******/ (() => { /******/ __webpack_require__.o = (obj, prop) => (Object.prototype.hasOwnProperty.call(obj, prop)) /******/ })(); -/******/ +/******/ /************************************************************************/ var __webpack_exports__ = {}; // This entry need to be wrapped in an IIFE because it need to be in strict mode. diff --git a/.yarn/cache/jest-npm-27.4.7-cdda9da561-28ce948b30.zip b/.yarn/cache/jest-npm-27.4.7-cdda9da561-28ce948b30.zip new file mode 100644 index 0000000000000000000000000000000000000000..feec693d575f9fc5fb0fc56a4cf82699783260bc GIT binary patch literal 3590 zcmaJ^2{_by7amK=xMUgIj6EhAG@>XX!^kotCX|V6V;u$;iBYyJpM5Ek(%6OUdkEQb zQ&}>yXDP*4lBJM4D))Z5>df=}m*+X>ea@V7e(!nzdOCFUAi%brDd;=!?cv9TnR+KU z5LkHv(~RmXxzP$89G9gZIm>MSNQW8CQ8^fbdWW@A4D1Sgcdy-*4Av7UE1svP27Ks z+%I#n731rbJoF%Xp;zfi7Gbt)eU!1i*cfrTV$9O7W@c#YgWZ$3;%;4A?trC3Re-vC zvy05S=TB=4LSLf$0_I8YXWrvDLIsRR#w@e_0KO6Bkm0KVV6cIW0xvOxu|B-gyQCDy zAK(s`S(GCX+Oj0sJ>YFlp#M-;Iri3azK{(H8J`4?Yc@o7 zx;Q<3LL|D_uIdS`)kZbMd;-I1KBLBFFOj<*-?K6;Xlo2o_U~g`UIZ8O|1SUj+*{s~>#0GlZDF*AggO;p^f>KIK~HGhmDVzW3nyS-OVAm>NYCp$ z8hL60M%o zm*Z754ZU7|w8op~m6SJ(Ym;Q_JDN>_YMH!=UbOg>C2pB?P>G#}m8WOXDDX(EK%1FE z#u0IiTwwZQlDW2%GKpyXKl-W!PAOcvVG103Sfm#fP=y#WwtKZOC8B_sHx*MpU?Fui z*o4zxVtjoeZgbzSN1SWVk+rlZ>>Bem`=y~7s_z9F0D%9OG27=u+QAJS^Ox=uI4g4X zYuKe?JNB+gI#wnFP6>>KeodhXv75)_9IxW7Bh8Pkmh_CDCsnUrtWWYdf0HneIQu4| zA;Eww2V_q0sR>n#V7&EUF^8FwG)m}V=s_?rC5n84E6ls6^^Z3a9kqol)nX@66`jaT zykbpgdpu9TQGUwH9%>F|A>&o)%T_q2DN8GO3`n`%XV5inqi%KDazlr)$-OLz$ zohNWm(C9jB?h-a<=^B!CMN}Nfc}>#T``s~zW6lKi*sq@P1%pR&@>Y(Ye7CMEQmf{I z!WN6iOhyn^r78Mwv(OSuzhiSyL zF*DuX7$QA*D?&68{o?79*Bl@Dj7G%!`p(?(Pz4}Xa3o9uywgVQA{#9whjDd!O}_+t z2z?oD9w|sVAZC@HkjkUt_9e#o_5{Pe7P>g5ji-uHIg8#OIck#^CXwlZr_8@jnwXfO zug|f#^+H25?oT^(fZOzR5?t609K9R@bLGvx-*!6`-EW8(KZ_T2FOdE^Rm7ir(D!5b zX`AN;>8o?~OU|2zzc*ork+Xe|pHieUGJGEZAh2gST`a8d7Pi*ZNp&U!8K9$+;jDG< zE(kq`a3GX5GmLK4gj95=)Kuoec!_|+=8r0#LI*m13!NHLDFxoiNvk#+w+~*n(FeH= zA!?(?>FhX0s}Jl$gW`i3=lqCv7Y&n3@M+F#Hy#ruz02HNVZGUR&%F1qA4=mKSb4)G zE2yT`RU8bRV|IUe+D@ANlZrUfrs0ib(6OjROH;_1#tq+!cY5NkO2`Mf9tQww=Bl!>rd0AaE_)le}eNC6%Hzm!JiGaY-Lf$Ol zjf$(w8Xhk_wjK_Imp64gf~xQK!)_K3*C!Zk(XU`J2-!ouQ$}4< zVR;v2WUrK+ukS3E!OX`ui+EfR5*f&7rUwc~ZN{h#W6OjnCs3t)6C^ectt|=WLk;EG zNdAcFv#VKyU=t_vs#>MuY<4oEsOQrGKz)@ij5>>d$f51A4K2- zy~YHK2u{)2gCIvVQt{M7q2nnEXNkk*JGm({mPY4X|W*pwv5%5B-~Kk zTYkVjaH{!_nrG^X@3*8HJ+kMvPFYRzLNJdOH)aznVBoBo7XgX+HE02jak+U0+Um|8 z-3=!54lubqD$J0@<+$F|f{ zEJ7VU$ev?|L8_{wk)1|hH5t~R)l~_WsxHLfwMy;Oeey=G!qVMC)phng&%}}j zu@?|zOfSRqfIMs1(Fu-EY^X0GV~4%u}1x~ z-g~W%F2hz#eJSHYxtfJfj8Q&=zbir+c!$@bHL6X?HhdbmR6GQ=i`qtL99L z@d0q_8DwZmg+K#Jjh(@PGY|V%(hwVpCuqHg9G_)#ozgEiBLVYue>h^7yZvJ)XwsPJviYkoy_*3W)9sNCihqret>7Dot z|4Vzu|IpRH`v=?VX2&S1EOdLN@m=fuoXT#s^ACnU;+Ggdw)5}O*_H%5Mp3n+uKWL1 z<@*rspzPFUw?x=M$?#A44a%;RcEENo$bZ2o)Rp<)l>UER?oMns>-~#`qkeV$7waDm j+zqt*c>W7S58MlA*J0Ju*|&c?1W5h0QyEyCY5VPOUE7-j literal 0 HcmV?d00001 diff --git a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js index fa5c22271..9e7379a51 100644 --- a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js +++ b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js @@ -17,11 +17,22 @@ import { type } from '@lowdefy/helpers'; function DisplayMessage({ methods: { displayMessage }, params }) { - let defaultParams = params; - if (type.isObject(params)) { - defaultParams = { ...defaultParams, content: params.content || 'Success' }; + if (!type.isObject(params) && !type.isNone(params)) { + throw new Error( + `Invalid DisplayMessage, check action params. Params must be an object, received "${JSON.stringify( + params + )}".` + ); + } + if (type.isNull(params) || type.isUndefined(params)) { + displayMessage({ content: 'Success' }); + } + if (type.isObject(params)) { + displayMessage({ + ...params, + content: type.isNone(params.content) ? 'Success' : params.content, + }); } - displayMessage(defaultParams); } export default DisplayMessage; diff --git a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js index 8db50cfd6..52d2d2e03 100644 --- a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js +++ b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.test.js @@ -14,15 +14,338 @@ limitations under the License. */ +import testContext from './testContext.js'; import DisplayMessage from './DisplayMessage.js'; -const mockActionMethod = jest.fn(); +const displayMessage = jest.fn(); +const lowdefy = { + _internal: { + actions: { + DisplayMessage, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + displayMessage, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; beforeEach(() => { - mockActionMethod.mockReset(); + displayMessage.mockReset(); }); -test('Message action invocation', async () => { - DisplayMessage({ methods: { displayMessage: mockActionMethod }, params: 'call' }); - expect(mockActionMethod.mock.calls).toEqual([['call']]); +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('DisplayMessage params is not object', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'a', + type: 'DisplayMessage', + params: 1, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + type: 'DisplayMessage', + params: 1, + }, + error: { + error: new Error( + 'Invalid DisplayMessage, check action params. Params must be an object, received "1".' + ), + index: 0, + type: 'DisplayMessage', + }, + }, + responses: { + a: { + error: new Error( + 'Invalid DisplayMessage, check action params. Params must be an object, received "1".' + ), + type: 'DisplayMessage', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('DisplayMessage params is null or undefined', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'a', + type: 'DisplayMessage', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: undefined, + type: 'DisplayMessage', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: true, + }); + expect(displayMessage.mock.calls).toEqual([[{ content: 'Success' }]]); +}); + +test('DisplayMessage params.content is none', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'a', + type: 'DisplayMessage', + params: { + status: 'info', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: undefined, + type: 'DisplayMessage', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: true, + }); + expect(displayMessage.mock.calls).toEqual([[{ content: 'Success', status: 'info' }]]); +}); + +test('DisplayMessage params.content is ""', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'a', + type: 'DisplayMessage', + params: { + content: '', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: undefined, + type: 'DisplayMessage', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: true, + }); + expect(displayMessage.mock.calls).toEqual([[{ content: '' }]]); +}); + +test('DisplayMessage params.content is falsy', async () => { + const rootBlock = { + id: 'block:root:root:0', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'block:root:button:0', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + }, + events: { + onClick: [ + { + id: 'a', + type: 'DisplayMessage', + params: { + content: 0, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['block:root:button:0']; + await button.triggerEvent({ name: 'onClick' }); + expect(button.Events.events.onClick.history[0]).toEqual({ + blockId: 'button', + bounced: false, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: undefined, + type: 'DisplayMessage', + index: 0, + }, + }, + endTimestamp: { date: 0 }, + startTimestamp: { date: 0 }, + success: true, + }); + expect(displayMessage.mock.calls).toEqual([[{ content: 0 }]]); }); diff --git a/yarn.lock b/yarn.lock index f83565e5c..39e68f408 100644 --- a/yarn.lock +++ b/yarn.lock @@ -960,7 +960,7 @@ __metadata: languageName: node linkType: hard -"@jest/core@npm:^27.5.1": +"@jest/core@npm:^27.4.7, @jest/core@npm:^27.5.1": version: 27.5.1 resolution: "@jest/core@npm:27.5.1" dependencies: @@ -2213,8 +2213,8 @@ __metadata: version: 0.0.0-use.local resolution: "@lowdefy/build@workspace:packages/build" dependencies: - "@lowdefy/actions-core": 4.0.0-alpha.6 "@jest/globals": 27.5.1 + "@lowdefy/actions-core": 4.0.0-alpha.6 "@lowdefy/ajv": 4.0.0-alpha.6 "@lowdefy/blocks-antd": 4.0.0-alpha.6 "@lowdefy/blocks-basic": 4.0.0-alpha.6 @@ -8560,7 +8560,7 @@ __metadata: languageName: node linkType: hard -"jest-cli@npm:^27.5.1": +"jest-cli@npm:^27.4.7, jest-cli@npm:^27.5.1": version: 27.5.1 resolution: "jest-cli@npm:27.5.1" dependencies: @@ -9011,6 +9011,24 @@ __metadata: languageName: node linkType: hard +"jest@npm:27.4.7": + version: 27.4.7 + resolution: "jest@npm:27.4.7" + dependencies: + "@jest/core": ^27.4.7 + import-local: ^3.0.2 + jest-cli: ^27.4.7 + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + bin: + jest: bin/jest.js + checksum: 28ce948b30c074907393f37553acac4422d0f60190776e62b3403e4c742d33dd6012e3a20748254a43e38b5b4ce52d813b13a3a5be1d43d6d12429bd08ce1a23 + languageName: node + linkType: hard + "jest@npm:27.5.1": version: 27.5.1 resolution: "jest@npm:27.5.1" From 578be12da8b52aaaa7d841a957ac1f8d14f79a3b Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 15:07:28 +0200 Subject: [PATCH 68/79] chore(actions-core): Bumped jest to 27.5.1. --- packages/plugins/actions/actions-core/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/actions/actions-core/package.json b/packages/plugins/actions/actions-core/package.json index cc68c5d06..91ead86c5 100644 --- a/packages/plugins/actions/actions-core/package.json +++ b/packages/plugins/actions/actions-core/package.json @@ -54,7 +54,7 @@ "@swc/cli": "0.1.55", "@swc/core": "1.2.135", "@swc/jest": "0.2.17", - "jest": "27.4.7" + "jest": "27.5.1" }, "publishConfig": { "access": "public" From 3d85e26ac5b5f33897032d04ebd6e20ab1944168 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 15:09:14 +0200 Subject: [PATCH 69/79] fix(actions-core): Changed param type check in DisplayMessage action. --- .../plugins/actions/actions-core/src/actions/DisplayMessage.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js index 9e7379a51..6b240a6f0 100644 --- a/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js +++ b/packages/plugins/actions/actions-core/src/actions/DisplayMessage.js @@ -24,7 +24,7 @@ function DisplayMessage({ methods: { displayMessage }, params }) { )}".` ); } - if (type.isNull(params) || type.isUndefined(params)) { + if (type.isNone(params)) { displayMessage({ content: 'Success' }); } if (type.isObject(params)) { From c79c7ed11da18923395aa8385fb542b5a41c7f96 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 16:12:27 +0200 Subject: [PATCH 70/79] feat(engine): Added getActions action method test. --- .../engine/src/actions/createGetActions.js | 2 +- .../src/actions/createGetActions.test.js | 540 ++++++++++++++++++ 2 files changed, 541 insertions(+), 1 deletion(-) create mode 100644 packages/engine/src/actions/createGetActions.test.js diff --git a/packages/engine/src/actions/createGetActions.js b/packages/engine/src/actions/createGetActions.js index e7a5e5198..ed1c299d8 100644 --- a/packages/engine/src/actions/createGetActions.js +++ b/packages/engine/src/actions/createGetActions.js @@ -22,7 +22,7 @@ function createGetActions({ actions, arrayIndices, blockId }) { arrayIndices, location: blockId, object: actions, - method: 'getAction', + method: 'getActions', params, }); }; diff --git a/packages/engine/src/actions/createGetActions.test.js b/packages/engine/src/actions/createGetActions.test.js new file mode 100644 index 000000000..7c57a069a --- /dev/null +++ b/packages/engine/src/actions/createGetActions.test.js @@ -0,0 +1,540 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getActions }, params }) => { + return getActions(params); + }, + Custom: () => 'response', + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getActions params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Custom', + params: true, + }, + { + id: 'b', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'response', + index: 0, + type: 'Custom', + }, + b: { + response: { + a: { + index: 0, + response: 'response', + type: 'Custom', + }, + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getActions params is a', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Custom', + params: true, + }, + { + id: 'b', + type: 'Action', + params: 'a', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'response', + index: 0, + type: 'Custom', + }, + b: { + response: { + index: 0, + response: 'response', + type: 'Custom', + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getActions params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getActions params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getActions params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getActions params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Custom', + params: true, + }, + { + id: 'b', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'response', + index: 0, + type: 'Custom', + }, + b: { + response: 'defaulto', + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getActions params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Custom', + params: true, + }, + { + id: 'b', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'response', + index: 0, + type: 'Custom', + }, + b: { + response: { + a: { + index: 0, + response: 'response', + type: 'Custom', + }, + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getActions params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getActions params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getActions params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getActions params.key is a', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Custom', + params: true, + }, + { + id: 'b', + type: 'Action', + params: { + key: 'a', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'response', + index: 0, + type: 'Custom', + }, + b: { + response: { + index: 0, + response: 'response', + type: 'Custom', + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 5802217d3c6b20af5412af2a491f1b9f7852c175 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 16:18:12 +0200 Subject: [PATCH 71/79] feat(engine): Added getBlockId action method test. --- .../src/actions/createGetBlockId.test.js | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 packages/engine/src/actions/createGetBlockId.test.js diff --git a/packages/engine/src/actions/createGetBlockId.test.js b/packages/engine/src/actions/createGetBlockId.test.js new file mode 100644 index 000000000..ac6907ab4 --- /dev/null +++ b/packages/engine/src/actions/createGetBlockId.test.js @@ -0,0 +1,100 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getBlockId }, params }) => { + return getBlockId(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getBlockId no params', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'button', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 602e114040dcf51cf9f0c259d84a62ab847c2b0d Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 16:21:04 +0200 Subject: [PATCH 72/79] feat(engine): Added getPageId action method test. --- .../src/actions/createGetPageId.test.js | 100 ++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 packages/engine/src/actions/createGetPageId.test.js diff --git a/packages/engine/src/actions/createGetPageId.test.js b/packages/engine/src/actions/createGetPageId.test.js new file mode 100644 index 000000000..723a97ca5 --- /dev/null +++ b/packages/engine/src/actions/createGetPageId.test.js @@ -0,0 +1,100 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getPageId }, params }) => { + return getPageId(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getPageId no params', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'root', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 031535c553e1f2c7806e810d8b609f3fb3550de3 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 16:44:30 +0200 Subject: [PATCH 73/79] feat(engine): Added getEvent action method test. --- .../engine/src/actions/createGetEvent.test.js | 471 ++++++++++++++++++ 1 file changed, 471 insertions(+) create mode 100644 packages/engine/src/actions/createGetEvent.test.js diff --git a/packages/engine/src/actions/createGetEvent.test.js b/packages/engine/src/actions/createGetEvent.test.js new file mode 100644 index 000000000..fdce57535 --- /dev/null +++ b/packages/engine/src/actions/createGetEvent.test.js @@ -0,0 +1,471 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getEvent }, params }) => { + return getEvent(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getEvent params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: { + some: 'data', + }, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getEvent params is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: 'some', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: { some: 'data' }, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: 'data', + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getEvent params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getEvent params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: { some: 'data' }, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getEvent params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getEvent params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: { some: 'data' }, + eventName: 'onClick', + responses: { + a: { + response: 'defaulto', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getEvent params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: { some: 'data' }, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getEvent params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: { some: 'data' }, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getEvent params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getEvent params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getEvent params.key is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: 'some', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick', event: { some: 'data' } }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: { some: 'data' }, + eventName: 'onClick', + responses: { + a: { + response: 'data', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 61d23a282ab98202b0b431f7043e381fad7a87c7 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 16:49:20 +0200 Subject: [PATCH 74/79] feat(engine): Added getGlobal action method test. --- .../src/actions/createGetGlobal.test.js | 472 ++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 packages/engine/src/actions/createGetGlobal.test.js diff --git a/packages/engine/src/actions/createGetGlobal.test.js b/packages/engine/src/actions/createGetGlobal.test.js new file mode 100644 index 000000000..097bc58b3 --- /dev/null +++ b/packages/engine/src/actions/createGetGlobal.test.js @@ -0,0 +1,472 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getGlobal }, params }) => { + return getGlobal(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, + lowdefyGlobal: { + some: 'data', + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getGlobal params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getGlobal params is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: 'some', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: 'data', + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getGlobal params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getGlobal params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getGlobal params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getGlobal params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'defaulto', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getGlobal params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getGlobal params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getGlobal params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getGlobal params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getGlobal params.key is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: 'some', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'data', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 5578f46978ae78189b90e0ce39c1133add59499d Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 17:02:12 +0200 Subject: [PATCH 75/79] feat(engine): Added getInput action method test. --- .../engine/src/actions/createGetInput.test.js | 473 ++++++++++++++++++ 1 file changed, 473 insertions(+) create mode 100644 packages/engine/src/actions/createGetInput.test.js diff --git a/packages/engine/src/actions/createGetInput.test.js b/packages/engine/src/actions/createGetInput.test.js new file mode 100644 index 000000000..8d06027cd --- /dev/null +++ b/packages/engine/src/actions/createGetInput.test.js @@ -0,0 +1,473 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getInput }, params }) => { + return getInput(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, + inputs: { + test: { some: 'data' }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getInput params is true', async () => { + const rootBlock = { + id: 'rooto', + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getInput params is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: 'some', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: 'data', + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getInput params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getInput params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getInput params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getInput params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'defaulto', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getInput params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getInput params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getInput params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getInput params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getInput params.key is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: 'some', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'data', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 6665f2eaa06c604fedb4de64d0fb414d153af6b4 Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 17:11:23 +0200 Subject: [PATCH 76/79] feat(engine): Added getUrlQuery action method test. --- .../engine/src/actions/createGetInput.test.js | 1 - .../src/actions/createGetUrlQuery.test.js | 472 ++++++++++++++++++ 2 files changed, 472 insertions(+), 1 deletion(-) create mode 100644 packages/engine/src/actions/createGetUrlQuery.test.js diff --git a/packages/engine/src/actions/createGetInput.test.js b/packages/engine/src/actions/createGetInput.test.js index 8d06027cd..99afe9790 100644 --- a/packages/engine/src/actions/createGetInput.test.js +++ b/packages/engine/src/actions/createGetInput.test.js @@ -50,7 +50,6 @@ afterAll(() => { test('getInput params is true', async () => { const rootBlock = { - id: 'rooto', blockId: 'root', meta: { category: 'container', diff --git a/packages/engine/src/actions/createGetUrlQuery.test.js b/packages/engine/src/actions/createGetUrlQuery.test.js new file mode 100644 index 000000000..25fa5f701 --- /dev/null +++ b/packages/engine/src/actions/createGetUrlQuery.test.js @@ -0,0 +1,472 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getUrlQuery }, params }) => { + return getUrlQuery(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, + urlQuery: { + some: 'data', + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getUrlQuery params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUrlQuery params is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: 'some', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: 'data', + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUrlQuery params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getUrlQuery params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getUrlQuery params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getUrlQuery params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'defaulto', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUrlQuery params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUrlQuery params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getUrlQuery params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getUrlQuery params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getUrlQuery params.key is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: 'some', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'data', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From f7156f5e6f9ebf1178821b46f73ddeba6e6d134a Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 17:12:20 +0200 Subject: [PATCH 77/79] feat(engine): Added getUser action method test. --- .../engine/src/actions/createGetUser.test.js | 472 ++++++++++++++++++ 1 file changed, 472 insertions(+) create mode 100644 packages/engine/src/actions/createGetUser.test.js diff --git a/packages/engine/src/actions/createGetUser.test.js b/packages/engine/src/actions/createGetUser.test.js new file mode 100644 index 000000000..8d5a0a7d0 --- /dev/null +++ b/packages/engine/src/actions/createGetUser.test.js @@ -0,0 +1,472 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getUser }, params }) => { + return getUser(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, + user: { + some: 'data', + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getUser params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUser params is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: 'some', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: 'data', + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUser params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getUser params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getUser params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getUser params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'defaulto', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUser params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getUser params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getUser params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getUser params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getUser params.key is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: 'some', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'data', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 384d2645d7f6b56bc9e17937f6d5e82c2c45adbe Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 17:14:31 +0200 Subject: [PATCH 78/79] feat(engine): Added getState action method test. --- .../engine/src/actions/createGetState.test.js | 476 ++++++++++++++++++ 1 file changed, 476 insertions(+) create mode 100644 packages/engine/src/actions/createGetState.test.js diff --git a/packages/engine/src/actions/createGetState.test.js b/packages/engine/src/actions/createGetState.test.js new file mode 100644 index 000000000..ec7b256eb --- /dev/null +++ b/packages/engine/src/actions/createGetState.test.js @@ -0,0 +1,476 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getState }, params }) => { + return getState(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeEach(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +test('getState params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getState params is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: 'some', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: 'data', + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getState params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'a', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getState params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + error: new Error( + 'Method Error: getState params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getState params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'defaulto', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getState params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: { some: 'data' }, + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getState params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'a', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getState params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + responses: { + a: { + error: new Error( + 'Method Error: getState params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getState params.key is some', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { + id: 'a', + type: 'Action', + params: { + key: 'some', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + initState: { some: 'data' }, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + response: 'data', + index: 0, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); From 55519c5c5945ccb2d754ff38798f8917a49bfb5a Mon Sep 17 00:00:00 2001 From: Sandile Date: Tue, 15 Feb 2022 17:33:34 +0200 Subject: [PATCH 79/79] feat(engine): Added getRequestDetails action method test. --- .../actions/createGetRequestDetails.test.js | 595 ++++++++++++++++++ 1 file changed, 595 insertions(+) create mode 100644 packages/engine/src/actions/createGetRequestDetails.test.js diff --git a/packages/engine/src/actions/createGetRequestDetails.test.js b/packages/engine/src/actions/createGetRequestDetails.test.js new file mode 100644 index 000000000..af183201c --- /dev/null +++ b/packages/engine/src/actions/createGetRequestDetails.test.js @@ -0,0 +1,595 @@ +/* + Copyright 2020-2021 Lowdefy, Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +import testContext from '../../test/testContext.js'; + +// Mock apollo client +const mockReqResponses = { + req_one: { + id: 'req_one', + success: true, + response: 1, + }, + req_error: new Error('Request error'), +}; + +const mockCallRequest = jest.fn(); +const mockCallRequestImp = ({ requestId }) => { + return new Promise((resolve, reject) => { + if (requestId === 'req_error') { + reject(mockReqResponses[requestId]); + } + resolve(mockReqResponses[requestId]); + }); +}; + +const lowdefy = { + _internal: { + actions: { + Action: ({ methods: { getRequestDetails }, params }) => { + return getRequestDetails(params); + }, + Request: ({ methods: { request }, params }) => { + return request(params); + }, + }, + blockComponents: { + Button: { meta: { category: 'display' } }, + }, + callRequest: mockCallRequest, + }, +}; + +const RealDate = Date; +const mockDate = jest.fn(() => ({ date: 0 })); +mockDate.now = jest.fn(() => 0); + +// Comment out to use console +console.log = () => {}; +console.error = () => {}; + +beforeAll(() => { + global.Date = mockDate; +}); + +afterAll(() => { + global.Date = RealDate; +}); + +beforeEach(() => { + mockCallRequest.mockReset(); + mockCallRequest.mockImplementation(mockCallRequestImp); +}); + +test('getRequestDetails params is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + params: true, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + response: { + req_one: { + error: [], + loading: false, + response: 1, + }, + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getRequestDetails params is req_one', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + params: 'req_one', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + response: { + error: [], + loading: false, + response: 1, + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getRequestDetails params is none', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + error: { + action: { id: 'b', type: 'Action' }, + error: { + error: new Error( + 'Method Error: getRequestDetails params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 1, + type: 'Action', + }, + }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + error: new Error( + 'Method Error: getRequestDetails params must be of type string, integer, boolean or object. Received: undefined at button.' + ), + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getRequestDetails params.key is null', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + params: { + key: null, + default: 'defaulto', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + response: 'defaulto', + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getRequestDetails params.all is true', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + params: { + all: true, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + response: { + req_one: { + error: [], + loading: false, + response: 1, + }, + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +}); + +test('getRequestDetails params.key is not string or int', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + params: { + key: {}, + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + error: { + action: { + id: 'b', + params: { + key: {}, + }, + type: 'Action', + }, + error: { + error: new Error( + 'Method Error: getRequestDetails params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 1, + type: 'Action', + }, + }, + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + error: new Error( + 'Method Error: getRequestDetails params.key must be of type string or integer. Received: {"key":{}} at button.' + ), + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: false, + }); +}); + +test('getRequestDetails params.key is req_one', async () => { + const rootBlock = { + blockId: 'root', + meta: { + category: 'container', + }, + requests: [ + { + requestId: 'req_one', + }, + ], + areas: { + content: { + blocks: [ + { + id: 'button', + blockId: 'button', + type: 'Button', + meta: { + category: 'display', + valueType: 'string', + }, + events: { + onClick: [ + { id: 'a', type: 'Request', params: ['req_one'] }, + { + id: 'b', + type: 'Action', + params: { + key: 'req_one', + }, + }, + ], + }, + }, + ], + }, + }, + }; + const context = await testContext({ + lowdefy, + rootBlock, + }); + const button = context._internal.RootBlocks.map['button']; + const res = await button.triggerEvent({ name: 'onClick' }); + expect(res).toEqual({ + blockId: 'button', + bounced: false, + endTimestamp: { date: 0 }, + event: undefined, + eventName: 'onClick', + responses: { + a: { + index: 0, + response: [1], + type: 'Request', + }, + b: { + response: { + error: [], + loading: false, + response: 1, + }, + index: 1, + type: 'Action', + }, + }, + startTimestamp: { date: 0 }, + success: true, + }); +});