mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-03-19 15:01:06 +08:00
Merge branch 'develop' into plugins-actions
This commit is contained in:
commit
5ec469bc25
16
.pnp.cjs
generated
16
.pnp.cjs
generated
@ -3236,6 +3236,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
"packageLocation": "./packages/docs/",
|
||||
"packageDependencies": [
|
||||
["@lowdefy/docs", "workspace:packages/docs"],
|
||||
["@swc/core", "npm:1.2.135"],
|
||||
["@swc/jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:0.2.17"],
|
||||
["jest", "virtual:babee6e81435a5d101529cd67f2c6b175f4db37a4ab0b58df15adf73dd11be8917ac14caf44ab4e6882a92c61661055072365b349016e85173e049f006fc2305#npm:27.4.7"]
|
||||
],
|
||||
"linkType": "SOFT",
|
||||
@ -3570,7 +3572,7 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
["react", "npm:18.0.0-rc.0"],
|
||||
["react-dom", "virtual:573fe255dffc9c89f4f7aa60da718603753ee98acc55d6772bbd0ebdcf07f9183fb8e54b4f3f2246c538a14ead402db8d2e076039c667d1538702638a0cc87b8#npm:18.0.0-rc.0"],
|
||||
["react-icons", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:4.3.1"],
|
||||
["swr", "virtual:b951ea20ab6cada5f665e8389a50d828047e6b6f10e6ebaddde1e74a94868ec6ec703ff140742f295ef663cf92da1bc80fe9bbeaab30196cba0e992f38cd19ea#npm:1.2.0"],
|
||||
["swr", "virtual:b951ea20ab6cada5f665e8389a50d828047e6b6f10e6ebaddde1e74a94868ec6ec703ff140742f295ef663cf92da1bc80fe9bbeaab30196cba0e992f38cd19ea#npm:1.1.2"],
|
||||
["yargs", "npm:17.3.1"]
|
||||
],
|
||||
"linkType": "SOFT",
|
||||
@ -17837,17 +17839,17 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
|
||||
}]
|
||||
]],
|
||||
["swr", [
|
||||
["npm:1.2.0", {
|
||||
"packageLocation": "./.yarn/cache/swr-npm-1.2.0-1529e39a5c-9858cbd184.zip/node_modules/swr/",
|
||||
["npm:1.1.2", {
|
||||
"packageLocation": "./.yarn/cache/swr-npm-1.1.2-8ec1c9a7ac-84bf222c66.zip/node_modules/swr/",
|
||||
"packageDependencies": [
|
||||
["swr", "npm:1.2.0"]
|
||||
["swr", "npm:1.1.2"]
|
||||
],
|
||||
"linkType": "SOFT",
|
||||
}],
|
||||
["virtual:b951ea20ab6cada5f665e8389a50d828047e6b6f10e6ebaddde1e74a94868ec6ec703ff140742f295ef663cf92da1bc80fe9bbeaab30196cba0e992f38cd19ea#npm:1.2.0", {
|
||||
"packageLocation": "./.yarn/__virtual__/swr-virtual-7bd309a097/0/cache/swr-npm-1.2.0-1529e39a5c-9858cbd184.zip/node_modules/swr/",
|
||||
["virtual:b951ea20ab6cada5f665e8389a50d828047e6b6f10e6ebaddde1e74a94868ec6ec703ff140742f295ef663cf92da1bc80fe9bbeaab30196cba0e992f38cd19ea#npm:1.1.2", {
|
||||
"packageLocation": "./.yarn/__virtual__/swr-virtual-9bbb3471f0/0/cache/swr-npm-1.1.2-8ec1c9a7ac-84bf222c66.zip/node_modules/swr/",
|
||||
"packageDependencies": [
|
||||
["swr", "virtual:b951ea20ab6cada5f665e8389a50d828047e6b6f10e6ebaddde1e74a94868ec6ec703ff140742f295ef663cf92da1bc80fe9bbeaab30196cba0e992f38cd19ea#npm:1.2.0"],
|
||||
["swr", "virtual:b951ea20ab6cada5f665e8389a50d828047e6b6f10e6ebaddde1e74a94868ec6ec703ff140742f295ef663cf92da1bc80fe9bbeaab30196cba0e992f38cd19ea#npm:1.1.2"],
|
||||
["@types/react", null],
|
||||
["react", "npm:18.0.0-rc.0"]
|
||||
],
|
||||
|
BIN
.yarn/cache/swr-npm-1.1.2-8ec1c9a7ac-84bf222c66.zip
vendored
Normal file
BIN
.yarn/cache/swr-npm-1.1.2-8ec1c9a7ac-84bf222c66.zip
vendored
Normal file
Binary file not shown.
BIN
.yarn/cache/swr-npm-1.2.0-1529e39a5c-9858cbd184.zip
vendored
BIN
.yarn/cache/swr-npm-1.2.0-1529e39a5c-9858cbd184.zip
vendored
Binary file not shown.
@ -32,6 +32,10 @@
|
||||
"scripts": {
|
||||
"build": "lerna run build",
|
||||
"build:dev": "NODE_ENV=development lerna run build",
|
||||
"build:plugins": "yarn build:blocks && yarn build:connections && yarn build:operators",
|
||||
"build:blocks": "lerna run --scope '@lowdefy/blocks-*' build",
|
||||
"build:connections": "lerna run --scope '@lowdefy/connection-*' build",
|
||||
"build:operators": "lerna run --scope '@lowdefy/operators-*' build",
|
||||
"clean": "lerna run clean",
|
||||
"lerna:version": "lerna version --no-git-tag-version",
|
||||
"lerna:publish": "lerna publish from-git",
|
||||
@ -40,6 +44,7 @@
|
||||
"start:server-dev": "yarn workspace @lowdefy/server-dev start --package-manager yarn --config-directory ../../app",
|
||||
"start": "yarn workspace @lowdefy/server build:lowdefy --config-directory ../../app && yarn && yarn workspace @lowdefy/server build:next && yarn workspace @lowdefy/server start",
|
||||
"start:dev": "yarn workspace @lowdefy/server build:lowdefy --config-directory ../../app && yarn && yarn workspace @lowdefy/server dev",
|
||||
"start:dev-docs": "yarn workspace @lowdefy/server build:lowdefy --config-directory ../docs && yarn && yarn workspace @lowdefy/server dev",
|
||||
"test": "lerna run test"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
33
packages/api/src/context/readConfigFile.test.js
Normal file
33
packages/api/src/context/readConfigFile.test.js
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
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 { getFileExtension } from '@lowdefy/node-utils';
|
||||
|
||||
jest.mock('@lowdefy/node-utils', () => {
|
||||
return {
|
||||
getFileExtension,
|
||||
readFile: jest.fn(),
|
||||
};
|
||||
});
|
||||
|
||||
test('readConfigFile', async () => {
|
||||
const nodeUtils = await import('@lowdefy/node-utils');
|
||||
nodeUtils.mockImplementation(() => Promise.resove('config value'));
|
||||
const createReadConfigFile = (await import('./readConfigFile.js')).default;
|
||||
const readConfigFile = createReadConfigFile({ buildDirectory: '/build' });
|
||||
const res = await readConfigFile('file');
|
||||
expect(res).toEqual('config value');
|
||||
});
|
@ -39,6 +39,11 @@ async function validateConfig({ components }) {
|
||||
if (type.isNone(components.config.theme)) {
|
||||
components.config.theme = {};
|
||||
}
|
||||
if (type.isString(components.config.basePath)) {
|
||||
if (components.config.basePath[0] !== '/') {
|
||||
throw Error('Base path must start with "/".');
|
||||
}
|
||||
}
|
||||
validate({
|
||||
schema: lowdefySchema.definitions.authConfig,
|
||||
data: components.config.auth,
|
||||
|
@ -155,3 +155,31 @@ test('validateConfig config error when protected or public are false.', async ()
|
||||
'Public pages can not be set to false.'
|
||||
);
|
||||
});
|
||||
|
||||
test('validateConfig config error when basePath does not start with "/".', async () => {
|
||||
let components = {
|
||||
config: {
|
||||
basePath: '/base',
|
||||
},
|
||||
};
|
||||
const result = await validateConfig({ components, context });
|
||||
expect(result).toEqual({
|
||||
config: {
|
||||
auth: {
|
||||
pages: {
|
||||
roles: {},
|
||||
},
|
||||
},
|
||||
basePath: '/base',
|
||||
theme: {},
|
||||
},
|
||||
});
|
||||
components = {
|
||||
config: {
|
||||
basePath: 'base',
|
||||
},
|
||||
};
|
||||
await expect(validateConfig({ components, context })).rejects.toThrow(
|
||||
'Base path must start with "/".'
|
||||
);
|
||||
});
|
||||
|
@ -598,6 +598,13 @@ export default {
|
||||
auth: {
|
||||
$ref: '#/definitions/authConfig',
|
||||
},
|
||||
basePath: {
|
||||
type: 'string',
|
||||
description: 'App base path to apply to all routes. Base path must start with "/".',
|
||||
errorMessage: {
|
||||
type: 'App "config.basePath" should be a string.',
|
||||
},
|
||||
},
|
||||
homePageId: {
|
||||
type: 'string',
|
||||
description:
|
||||
|
@ -123,6 +123,20 @@ _ref:
|
||||
|
||||
- `basePath: string`: The base path setting for the application. This variable is used to prefix route paths for example `${basePath}/public/logo-square-light-theme.png`. The default base path is ''.
|
||||
- `blockId: string`: The block's id within the Lowdefy app, this is useful for setting a unique `id` on DOM elements.
|
||||
- `components: object`: Helper React components that are exposed to blocks to use internally.
|
||||
- `Icon`: component`: Lowdefy standard Icon React component to render build in icons.
|
||||
- `Link`: component`: Lowdefy standard Link React component used as links to pages or external urls. The following props apply:
|
||||
- `ariaLabel: string`: Arial-label to apply to link tag.
|
||||
- `back: boolean`: When the link is clicked, trigger the browser back.
|
||||
- `home: boolean`: When the link is clicked, route to the home page.
|
||||
- `input: object`: When the link is clicked, pass data as the input object to the next Lowdefy page. Can only be used with pageId link and newTab false. See [Input]( TODO: Link to input page? ).
|
||||
- `newTab: boolean`: When the link is clicked, open the page in a new browser tab.
|
||||
- `pageId: string`: When the link is clicked, route to the provided Lowdefy page.
|
||||
- `rel: string`: Overwrite `<a/>` tag property.
|
||||
- `replace: boolean`: Prevent adding a new entry into browser history by replacing the url instead of pushing into history. Can only be used with pageId link and newTab false.
|
||||
- `scroll: boolean`: Disable scrolling to the top of the page after page transition. Can only be used with pageId link and newTab false.
|
||||
- `url: string`: When the link is clicked, route to an external url.
|
||||
- `urlQuery: object`: When the link is clicked, pass data as a url query to the next Lowdefy page. See [url query]( TODO: Link to url query page? ).
|
||||
- `content: object`: Passed to `container` and `context` block categories. The `content` object with methods to render sub blocks into content areas. The method name is the same as the area key, for example, 'content.content()` renders a blocks default `content` area.
|
||||
- `events: object`: All events defined on the block in the Lowdefy app config.
|
||||
- `[event_key]: object`: Event keys gives a handle name to the event details.
|
||||
|
@ -42,6 +42,7 @@ _ref:
|
||||
|
||||
The config object has the following properties:
|
||||
|
||||
- `basePath: string`: Set the base path to serve the Lowdefy application from. This will route all pages under `https://example.com/<base-path>/<page-id>` instead of the default `https://example.com/<page-id>`. The basePath value must start with "/".
|
||||
- `homePageId: string`: The pageId of the page that should be loaded when a user loads the app without a pageId in the url route. This is the page that is loaded when you navigate to `yourdomain.com`.
|
||||
- `experimental_initPageId: string`: The pageId of the page that should be loaded when app is initialized. User is then redirected to requeted page. You can use onInit/onInitAsync/onEnter/onEnterAsync events to fetch and prepare global variables for other parts of the app.
|
||||
|
||||
|
@ -32,7 +32,7 @@ _ref:
|
||||
|
||||
The Lowdefy server can be configured using the following environment variables:
|
||||
|
||||
- `LOWDEFY_SERVER_BASE_PATH`: Set the base path to serve the Lowdefy application from. This will serve the application under `https://example.com/<base-path>`instead of `https://example.com`, and all pages under `https://example.com/<base-path>/<page-id>` instead of the default `https://example.com/<page-id>`.
|
||||
- `LOWDEFY_BASE_PATH`: Set the base path to serve the Lowdefy application from. This will serve the application under `https://example.com/<base-path>`instead of `https://example.com`, and all pages under `https://example.com/<base-path>/<page-id>` instead of the default `https://example.com/<page-id>`.
|
||||
- `LOWDEFY_SERVER_BUILD_DIRECTORY`: The directory of the built Lowdefy configuration (The output of `lowdefy build`, usually found at `./.lowdefy/build` in your project repository). The default is `./build` (or `/home/node/lowdefy/build`).
|
||||
- `LOWDEFY_SERVER_PUBLIC_DIRECTORY`: The directory of the public assets to be served. The default is `./public` (or `/home/node/lowdefy/public`).
|
||||
- `LOWDEFY_SERVER_PORT`: The port (inside the container) at which to run the server. The default is `3000`.
|
||||
|
@ -105,7 +105,7 @@ _ref:
|
||||
|
||||
The following environment variables can be specified:
|
||||
|
||||
- `LOWDEFY_SERVER_BASE_PATH`: Set the base path to serve the Lowdefy application from. This will serve the application under `https://example.com/<base-path>`instead of `https://example.com`, and all pages under `https://example.com/<base-path>/<page-id>` instead of the default `https://example.com/<page-id>`.
|
||||
- `LOWDEFY_BASE_PATH`: Set the base path to serve the Lowdefy application from. This will serve the application under `https://example.com/<base-path>`instead of `https://example.com`, and all pages under `https://example.com/<base-path>/<page-id>` instead of the default `https://example.com/<page-id>`.
|
||||
- `LOWDEFY_SERVER_BUILD_DIRECTORY`: The directory of the built Lowdefy configuration (The output of `lowdefy build`, usually found at `./.lowdefy/build` in your project repository). The default is `./.lowdefy/build`.
|
||||
- `LOWDEFY_SERVER_PORT`: The port at which to run the server. The default is `3000`.
|
||||
- `LOWDEFY_SERVER_PUBLIC_DIRECTORY`: The directory of the public assets to be served. The default is `./public`.
|
||||
|
@ -7,6 +7,7 @@ export default {
|
||||
'<rootDir>/.lowdefy/',
|
||||
'<rootDir>/jest.config.js',
|
||||
'<rootDir>/coverage/',
|
||||
'<rootDir>/howto/',
|
||||
],
|
||||
coverageReporters: [['lcov', { projectRoot: '../..' }], 'text', 'clover'],
|
||||
errorOnDeprecated: true,
|
||||
@ -15,5 +16,9 @@ export default {
|
||||
'<rootDir>/.lowdefy/',
|
||||
'<rootDir>/jest.config.js',
|
||||
'<rootDir>/coverage/',
|
||||
'<rootDir>/howto/',
|
||||
],
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': ['@swc/jest', { configFile: '../../.swcrc.test' }],
|
||||
},
|
||||
};
|
||||
|
@ -32,6 +32,8 @@
|
||||
"test": "jest --coverage"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@swc/core": "1.2.135",
|
||||
"@swc/jest": "0.2.17",
|
||||
"jest": "27.4.7"
|
||||
},
|
||||
"publishConfig": {
|
||||
|
@ -16,32 +16,42 @@
|
||||
|
||||
import { type, urlQuery as urlQueryFn } from '@lowdefy/helpers';
|
||||
|
||||
function createLink({ backLink, lowdefy, newOriginLink, sameOriginLink }) {
|
||||
function link({ back, home, input, newTab, pageId, url, urlQuery }) {
|
||||
let pathname = pageId;
|
||||
if (back) {
|
||||
return backLink();
|
||||
function createLink({ backLink, disabledLink, lowdefy, newOriginLink, noLink, sameOriginLink }) {
|
||||
function link(props) {
|
||||
if (props.disabled === true) {
|
||||
return disabledLink(props);
|
||||
}
|
||||
const lowdefyUrlQuery = type.isNone(urlQuery) ? '' : `?${urlQueryFn.stringify(urlQuery)}`;
|
||||
if (home) {
|
||||
if (lowdefy.home.configured) {
|
||||
pathname = '';
|
||||
pageId = lowdefy.home.pageId;
|
||||
} else {
|
||||
pathname = lowdefy.home.pageId;
|
||||
pageId = lowdefy.home.pageId;
|
||||
}
|
||||
if ([!props.pageId, !props.back, !props.home, !props.url].filter((v) => !v).length > 1) {
|
||||
throw Error(
|
||||
`Invalid Link: To avoid ambiguity, only one of 'back', 'home', 'pageId' or 'url' can be defined.`
|
||||
);
|
||||
}
|
||||
if (!type.isNone(pathname)) {
|
||||
if (!type.isNone(input)) {
|
||||
lowdefy.inputs[pageId] = input;
|
||||
}
|
||||
return sameOriginLink(`/${pathname}${lowdefyUrlQuery}`, newTab);
|
||||
if (props.back === true) {
|
||||
// Cannot set input or urlQuery on back
|
||||
return backLink(props);
|
||||
}
|
||||
if (!type.isNone(url)) {
|
||||
return newOriginLink(`${url}${lowdefyUrlQuery}`, newTab);
|
||||
const lowdefyUrlQuery = type.isNone(props.urlQuery)
|
||||
? ''
|
||||
: `?${urlQueryFn.stringify(props.urlQuery)}`;
|
||||
if (props.home === true) {
|
||||
lowdefy.inputs[`page:${lowdefy.home.pageId}`] = props.input || {};
|
||||
return sameOriginLink({
|
||||
href: `/${lowdefy.home.configured ? '' : lowdefy.home.pageId}${lowdefyUrlQuery}`,
|
||||
...props,
|
||||
});
|
||||
}
|
||||
throw new Error(`Invalid Link.`);
|
||||
if (type.isString(props.pageId)) {
|
||||
lowdefy.inputs[`page:${props.pageId}`] = props.input || {};
|
||||
return sameOriginLink({ href: `/${props.pageId}${lowdefyUrlQuery}`, ...props });
|
||||
}
|
||||
if (type.isString(props.url)) {
|
||||
const protocol = props.url.includes(':') ? '' : 'https://';
|
||||
return newOriginLink({
|
||||
href: `${protocol}${props.url}${lowdefyUrlQuery}`,
|
||||
...props,
|
||||
});
|
||||
}
|
||||
return noLink(props);
|
||||
}
|
||||
return link;
|
||||
}
|
||||
|
@ -1,12 +1,16 @@
|
||||
import createLink from '../src/createLink.js';
|
||||
|
||||
const mockBackLink = jest.fn();
|
||||
const mockDisabledLink = jest.fn();
|
||||
const mockNewOriginLink = jest.fn();
|
||||
const mockNoLink = jest.fn();
|
||||
const mockSameOriginLink = jest.fn();
|
||||
|
||||
beforeEach(() => {
|
||||
mockBackLink.mockReset();
|
||||
mockDisabledLink.mockReset();
|
||||
mockNewOriginLink.mockReset();
|
||||
mockNoLink.mockReset();
|
||||
mockSameOriginLink.mockReset();
|
||||
});
|
||||
|
||||
@ -14,17 +18,34 @@ test('createLink, link with pageId', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ pageId: 'page_1' });
|
||||
link({ pageId: 'page_1', urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
['/page_1', undefined],
|
||||
['/page_1?p=3', undefined],
|
||||
[
|
||||
{
|
||||
href: '/page_1',
|
||||
pageId: 'page_1',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
href: '/page_1?p=3',
|
||||
pageId: 'page_1',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -32,17 +53,36 @@ test('createLink, link with pageId new tab', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ pageId: 'page_1', newTab: true });
|
||||
link({ pageId: 'page_1', newTab: true, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
['/page_1', true],
|
||||
['/page_1?p=3', true],
|
||||
[
|
||||
{
|
||||
href: '/page_1',
|
||||
pageId: 'page_1',
|
||||
newTab: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
href: '/page_1?p=3',
|
||||
pageId: 'page_1',
|
||||
newTab: true,
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
@ -50,145 +90,366 @@ test('createLink, link with pageId with inputs', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ pageId: 'page_1', input: { a: 1 } });
|
||||
link({ pageId: 'page_2', input: { a: 2 }, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
['/page_1', undefined],
|
||||
['/page_2?p=3', undefined],
|
||||
[
|
||||
{
|
||||
href: '/page_1',
|
||||
input: {
|
||||
a: 1,
|
||||
},
|
||||
pageId: 'page_1',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
href: '/page_2?p=3',
|
||||
input: {
|
||||
a: 2,
|
||||
},
|
||||
pageId: 'page_2',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(lowdefy.inputs).toEqual({
|
||||
page_1: { a: 1 },
|
||||
page_2: { a: 2 },
|
||||
'page:page_1': { a: 1 },
|
||||
'page:page_2': { a: 2 },
|
||||
});
|
||||
});
|
||||
|
||||
test('createLink, link with url', () => {
|
||||
test('createLink, link with url and protocol', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ url: 'http://localhost:8080/test' });
|
||||
link({ url: 'http://localhost:8080/test', urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([
|
||||
['http://localhost:8080/test', undefined],
|
||||
['http://localhost:8080/test?p=3', undefined],
|
||||
[
|
||||
{
|
||||
href: 'http://localhost:8080/test',
|
||||
url: 'http://localhost:8080/test',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
href: 'http://localhost:8080/test?p=3',
|
||||
url: 'http://localhost:8080/test',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
test('createLink, link with url new tab', () => {
|
||||
test('createLink, link with url new tab and protocol', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ url: 'http://localhost:8080/test', newTab: true });
|
||||
link({ url: 'http://localhost:8080/test', newTab: true, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([
|
||||
['http://localhost:8080/test', true],
|
||||
['http://localhost:8080/test?p=3', true],
|
||||
[
|
||||
{
|
||||
href: 'http://localhost:8080/test',
|
||||
url: 'http://localhost:8080/test',
|
||||
newTab: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
href: 'http://localhost:8080/test?p=3',
|
||||
url: 'http://localhost:8080/test',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
newTab: true,
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
test('createLink, link with home', () => {
|
||||
const lowdefy = { inputs: {}, homePageId: 'home' };
|
||||
test('createLink, link with url and no protocol', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ url: 'external.com/test', newTab: true });
|
||||
link({ url: 'external.com/test', newTab: true, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
href: 'https://external.com/test',
|
||||
url: 'external.com/test',
|
||||
newTab: true,
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
href: 'https://external.com/test?p=3',
|
||||
url: 'external.com/test',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
newTab: true,
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
test('createLink, link with home, not configured', () => {
|
||||
const lowdefy = { inputs: {}, home: { pageId: 'home', configured: false } };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ home: true });
|
||||
link({ home: true, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
['/home', undefined],
|
||||
['/home?p=3', undefined],
|
||||
[
|
||||
{
|
||||
home: true,
|
||||
href: '/home',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
home: true,
|
||||
href: '/home?p=3',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('createLink, link with home new tab', () => {
|
||||
const lowdefy = { inputs: {}, homePageId: 'home' };
|
||||
test('createLink, link with home, configured', () => {
|
||||
const lowdefy = { inputs: {}, home: { pageId: 'home', configured: true } };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ home: true });
|
||||
link({ home: true, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
home: true,
|
||||
href: '/',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
home: true,
|
||||
href: '/?p=3',
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('createLink, link with home new tab, not configured', () => {
|
||||
const lowdefy = { inputs: {}, home: { pageId: 'home' } };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ home: true, newTab: true });
|
||||
link({ home: true, newTab: true, urlQuery: { p: 3 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
['/home', true],
|
||||
['/home?p=3', true],
|
||||
[{ home: true, href: '/home', newTab: true }],
|
||||
[
|
||||
{
|
||||
home: true,
|
||||
href: '/home?p=3',
|
||||
newTab: true,
|
||||
urlQuery: {
|
||||
p: 3,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
||||
test('createLink, link with home with inputs', () => {
|
||||
const lowdefy = { inputs: {}, homePageId: 'home' };
|
||||
test('createLink, link with home with inputs, not configured', () => {
|
||||
const lowdefy = { inputs: {}, home: { pageId: 'home' } };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ home: true, input: { a: 1 } });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([['/home', undefined]]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
home: true,
|
||||
href: '/home',
|
||||
input: {
|
||||
a: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(lowdefy.inputs).toEqual({
|
||||
home: { a: 1 },
|
||||
'page:home': { a: 1 },
|
||||
});
|
||||
});
|
||||
|
||||
test('createLink, link to throw if no params', () => {
|
||||
const lowdefy = { inputs: {}, homePageId: 'home' };
|
||||
test('createLink, no params calls noLink', () => {
|
||||
const lowdefy = { inputs: {}, home: { pageId: 'home' } };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
expect(() => link({})).toThrowErrorMatchingInlineSnapshot(`"Invalid Link."`);
|
||||
link({});
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([[{}]]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
test('createLink, disabled calls disabledLink', () => {
|
||||
const lowdefy = { inputs: {}, home: { pageId: 'home' } };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ disabled: true, home: true });
|
||||
expect(mockBackLink.mock.calls).toEqual([]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
disabled: true,
|
||||
home: true,
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
test('createLink, link with back', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
link({ back: true });
|
||||
expect(mockBackLink.mock.calls).toEqual([[]]);
|
||||
expect(mockBackLink.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
back: true,
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(mockDisabledLink.mock.calls).toEqual([]);
|
||||
expect(mockNoLink.mock.calls).toEqual([]);
|
||||
expect(mockNewOriginLink.mock.calls).toEqual([]);
|
||||
expect(mockSameOriginLink.mock.calls).toEqual([]);
|
||||
});
|
||||
|
||||
test('createLink, link with back equal to false is invalid', () => {
|
||||
test('createLink, link with more than one parameter is invalid.', () => {
|
||||
const lowdefy = { inputs: {} };
|
||||
const link = createLink({
|
||||
backLink: mockBackLink,
|
||||
disabledLink: mockDisabledLink,
|
||||
lowdefy,
|
||||
newOriginLink: mockNewOriginLink,
|
||||
noLink: mockNoLink,
|
||||
sameOriginLink: mockSameOriginLink,
|
||||
});
|
||||
expect(() => link({ back: false })).toThrowErrorMatchingInlineSnapshot(`"Invalid Link."`);
|
||||
expect(() => link({ back: true, home: true })).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Invalid Link: To avoid ambiguity, only one of 'back', 'home', 'pageId' or 'url' can be defined."`
|
||||
);
|
||||
});
|
||||
|
@ -3,11 +3,11 @@ export default {
|
||||
collectCoverage: true,
|
||||
collectCoverageFrom: ['src/**/*.js'],
|
||||
coverageDirectory: 'coverage',
|
||||
coveragePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/test/', '<rootDir>/dist/index.js'],
|
||||
coveragePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/test/', '<rootDir>/src/index.js'],
|
||||
coverageReporters: [['lcov', { projectRoot: '../..' }], 'text', 'clover'],
|
||||
errorOnDeprecated: true,
|
||||
testEnvironment: 'jsdom',
|
||||
testPathIgnorePatterns: ['<rootDir>/dist/'],
|
||||
testPathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/src/index.js'],
|
||||
transform: {
|
||||
'^.+\\.(t|j)sx?$': ['@swc/jest', { configFile: '../../.swcrc.test' }],
|
||||
},
|
||||
|
@ -19,26 +19,7 @@ import { type, get } from '@lowdefy/helpers';
|
||||
import { Breadcrumb } from 'antd';
|
||||
import { blockDefaultProps } from '@lowdefy/block-utils';
|
||||
|
||||
const ItemLink = ({ basePath, children, className, link, Link }) => {
|
||||
if (type.isString(link.pageId)) {
|
||||
return (
|
||||
<Link href={`${basePath}/${link.pageId}`} className={className}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
if (type.isString(link.url)) {
|
||||
return (
|
||||
<Link href={link.url} className={className}>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
return <span className={className}>{children}</span>;
|
||||
};
|
||||
|
||||
const BreadcrumbBlock = ({
|
||||
basePath,
|
||||
blockId,
|
||||
events,
|
||||
components: { Icon, Link },
|
||||
@ -61,30 +42,33 @@ const BreadcrumbBlock = ({
|
||||
(() => methods.triggerEvent({ name: onClickActionName, event: { link, index } }))
|
||||
}
|
||||
>
|
||||
<ItemLink
|
||||
basePath={basePath}
|
||||
<Link
|
||||
id={`${blockId}_${index}`}
|
||||
className={methods.makeCssClass([
|
||||
{
|
||||
cursor: events[onClickActionName] && 'pointer',
|
||||
},
|
||||
link.style,
|
||||
])}
|
||||
link={link}
|
||||
Link={Link}
|
||||
{...link}
|
||||
>
|
||||
{link.icon && (
|
||||
<Icon
|
||||
blockId={`${blockId}_${index}_icon`}
|
||||
events={events}
|
||||
properties={{
|
||||
name: type.isString(link.icon) && link.icon,
|
||||
...(type.isObject(link.icon) ? link.icon : {}),
|
||||
style: { paddingRight: 8, ...(link.icon.style || {}) },
|
||||
}}
|
||||
/>
|
||||
{(defaultTitle) => (
|
||||
<>
|
||||
{link.icon && (
|
||||
<Icon
|
||||
blockId={`${blockId}_${index}_icon`}
|
||||
events={events}
|
||||
properties={{
|
||||
name: type.isString(link.icon) && link.icon,
|
||||
...(type.isObject(link.icon) ? link.icon : {}),
|
||||
style: { paddingRight: 8, ...(link.icon.style || {}) },
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{type.isString(link) ? link : link.label || defaultTitle}
|
||||
</>
|
||||
)}
|
||||
{type.isString(link) ? link : link.label || link.pageId || link.url || `Link ${index}`}
|
||||
</ItemLink>
|
||||
</Link>
|
||||
</Breadcrumb.Item>
|
||||
))}
|
||||
</Breadcrumb>
|
||||
|
@ -28,26 +28,8 @@ const getDefaultMenu = (menus, menuId = 'default', links) => {
|
||||
return menu.links || [];
|
||||
};
|
||||
|
||||
const getTitle = (id, properties, defaultTitle) =>
|
||||
(properties && properties.title) || defaultTitle || id;
|
||||
|
||||
const MenuTitle = ({ basePath, id, Link, linkStyle, makeCssClass, pageId, properties, url }) => {
|
||||
if (type.isString(pageId)) {
|
||||
return (
|
||||
<Link href={`${basePath}/${pageId}`} className={makeCssClass([linkStyle])}>
|
||||
{getTitle(id, properties, pageId)}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
if (url) {
|
||||
return (
|
||||
<Link href={url} className={makeCssClass([linkStyle])}>
|
||||
{getTitle(id, properties, url)}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
return <span className={makeCssClass([linkStyle])}>{getTitle(id, properties)}</span>;
|
||||
};
|
||||
const getTitle = ({ id, properties, pageId, url }) =>
|
||||
(properties && properties.title) || pageId || url || id;
|
||||
|
||||
const getNestedColors = (menuColor, background) => {
|
||||
const fontColor = color(menuColor, 6);
|
||||
@ -69,7 +51,6 @@ const getNestedColors = (menuColor, background) => {
|
||||
};
|
||||
|
||||
const MenuComp = ({
|
||||
basePath,
|
||||
blockId,
|
||||
components: { Icon, Link },
|
||||
events,
|
||||
@ -218,14 +199,13 @@ const MenuComp = ({
|
||||
])}
|
||||
key={`${link.pageId || link.id}_${i}`}
|
||||
title={
|
||||
<MenuTitle
|
||||
basePath={basePath}
|
||||
Link={Link}
|
||||
linkStyle={methods.makeCssClass(link.style, true)}
|
||||
id={link.id}
|
||||
makeCssClass={methods.makeCssClass}
|
||||
properties={link.properties}
|
||||
/>
|
||||
<Link
|
||||
id={`${link.pageId || link.id}_${i}`}
|
||||
className={methods.makeCssClass(link.style, true)}
|
||||
{...link}
|
||||
>
|
||||
{getTitle(link)}
|
||||
</Link>
|
||||
}
|
||||
icon={
|
||||
link.properties &&
|
||||
@ -253,14 +233,13 @@ const MenuComp = ({
|
||||
<Menu.ItemGroup
|
||||
key={`${subLink.pageId || subLink.id}_${j}`}
|
||||
title={
|
||||
<MenuTitle
|
||||
basePath={basePath}
|
||||
Link={Link}
|
||||
linkStyle={methods.makeCssClass(subLink.style, true)}
|
||||
id={subLink.id}
|
||||
makeCssClass={methods.makeCssClass}
|
||||
properties={subLink.properties}
|
||||
/>
|
||||
<Link
|
||||
id={`${subLink.pageId || subLink.id}_${j}`}
|
||||
className={methods.makeCssClass(subLink.style, true)}
|
||||
{...subLink}
|
||||
>
|
||||
{getTitle(subLink)}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{subLink.links.map((subLinkGroup, k) => {
|
||||
@ -288,16 +267,13 @@ const MenuComp = ({
|
||||
)
|
||||
}
|
||||
>
|
||||
<MenuTitle
|
||||
basePath={basePath}
|
||||
Link={Link}
|
||||
linkStyle={methods.makeCssClass(subLinkGroup.style, true)}
|
||||
id={subLinkGroup.id}
|
||||
makeCssClass={methods.makeCssClass}
|
||||
pageId={subLinkGroup.pageId}
|
||||
properties={subLinkGroup.properties}
|
||||
url={subLinkGroup.url}
|
||||
/>
|
||||
<Link
|
||||
id={`${subLinkGroup.pageId || subLinkGroup.id}_${k}`}
|
||||
className={methods.makeCssClass(subLinkGroup.style, true)}
|
||||
{...subLinkGroup}
|
||||
>
|
||||
{getTitle(subLinkGroup)}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
})}
|
||||
@ -320,16 +296,13 @@ const MenuComp = ({
|
||||
)
|
||||
}
|
||||
>
|
||||
<MenuTitle
|
||||
basePath={basePath}
|
||||
Link={Link}
|
||||
linkStyle={methods.makeCssClass(subLink.style, true)}
|
||||
id={subLink.id}
|
||||
makeCssClass={methods.makeCssClass}
|
||||
pageId={subLink.pageId}
|
||||
properties={subLink.properties}
|
||||
url={subLink.url}
|
||||
/>
|
||||
<Link
|
||||
id={`${subLink.pageId || subLink.id}_${j}`}
|
||||
className={methods.makeCssClass(subLink.style, true)}
|
||||
{...subLink}
|
||||
>
|
||||
{getTitle(subLink)}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
@ -353,16 +326,13 @@ const MenuComp = ({
|
||||
)
|
||||
}
|
||||
>
|
||||
<MenuTitle
|
||||
basePath={basePath}
|
||||
Link={Link}
|
||||
linkStyle={methods.makeCssClass(link.style, true)}
|
||||
id={link.id}
|
||||
makeCssClass={methods.makeCssClass}
|
||||
pageId={link.pageId}
|
||||
properties={link.properties}
|
||||
url={link.url}
|
||||
/>
|
||||
<Link
|
||||
id={`${link.pageId || link.id}_${i}`}
|
||||
className={methods.makeCssClass(link.style, true)}
|
||||
{...link}
|
||||
>
|
||||
{getTitle(link)}
|
||||
</Link>
|
||||
</Menu.Item>
|
||||
);
|
||||
}
|
||||
|
@ -32,7 +32,6 @@ const PageHeaderMenu = ({
|
||||
components: { Icon, Link },
|
||||
content,
|
||||
events,
|
||||
homePageId,
|
||||
menus,
|
||||
methods,
|
||||
pageId,
|
||||
@ -116,10 +115,9 @@ const PageHeaderMenu = ({
|
||||
])}
|
||||
content={{
|
||||
// TODO: use next/image
|
||||
// TODO: Link to home=true
|
||||
content: () => (
|
||||
<>
|
||||
<Link href={`${homePageId}`}>
|
||||
<Link home={true}>
|
||||
<img
|
||||
src={
|
||||
(properties.logo && properties.logo.src) ||
|
||||
|
@ -35,7 +35,6 @@ const PageSiderMenu = ({
|
||||
components: { Icon, Link },
|
||||
events,
|
||||
content,
|
||||
homePageId,
|
||||
menus,
|
||||
methods,
|
||||
pageId,
|
||||
@ -117,7 +116,6 @@ const PageSiderMenu = ({
|
||||
properties={{ style: mergeObjects([{ minHeight: '100vh' }, properties.style]) }}
|
||||
content={{
|
||||
// TODO: use next/image
|
||||
// TODO: Link to home=true
|
||||
content: () => (
|
||||
<>
|
||||
<Header
|
||||
@ -167,7 +165,7 @@ const PageSiderMenu = ({
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<Link href={`${basePath}/${homePageId}`}>
|
||||
<Link home={true}>
|
||||
<img
|
||||
src={
|
||||
(properties.logo && properties.logo.src) ||
|
||||
|
@ -15,28 +15,9 @@
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { get, type } from '@lowdefy/helpers';
|
||||
import { get } from '@lowdefy/helpers';
|
||||
import { blockDefaultProps } from '@lowdefy/block-utils';
|
||||
|
||||
const Strong = ({ children, strong }) => (strong ? <b>{children}</b> : <>{children}</>);
|
||||
const Tag = ({ blockId, children, className, disabled, href, Link, newTab, onClick, rel }) =>
|
||||
disabled ? (
|
||||
<span id={blockId} className={className}>
|
||||
{children}
|
||||
</span>
|
||||
) : (
|
||||
<Link
|
||||
id={blockId}
|
||||
className={className}
|
||||
href={href}
|
||||
onClick={onClick}
|
||||
rel={rel || 'noopener noreferrer'}
|
||||
target={newTab ? '_blank' : '_self'}
|
||||
>
|
||||
{children}
|
||||
</Link>
|
||||
);
|
||||
|
||||
const AnchorBlock = ({
|
||||
blockId,
|
||||
events,
|
||||
@ -45,38 +26,33 @@ const AnchorBlock = ({
|
||||
methods,
|
||||
properties,
|
||||
}) => {
|
||||
const title = type.isNone(properties.title)
|
||||
? type.isNone(properties.href)
|
||||
? properties.href
|
||||
: blockId
|
||||
: properties.title;
|
||||
const showLoading = get(events, 'onClick.loading') || loading;
|
||||
const disabled = properties.disabled || showLoading;
|
||||
return (
|
||||
<Tag
|
||||
blockId={blockId}
|
||||
<Link
|
||||
id={blockId}
|
||||
className={methods.makeCssClass([
|
||||
properties.style,
|
||||
disabled && { color: '#BEBEBE', cursor: 'not-allowed' },
|
||||
])}
|
||||
disabled={disabled}
|
||||
href={properties.href}
|
||||
Link={Link}
|
||||
rel={properties.rel}
|
||||
newTab={properties.newTab}
|
||||
onClick={() => methods.triggerEvent({ name: 'onClick' })}
|
||||
{...properties}
|
||||
>
|
||||
<Strong strong={properties.strong}>
|
||||
{properties.icon && (
|
||||
<Icon
|
||||
blockId={`${blockId}_icon`}
|
||||
events={events}
|
||||
properties={showLoading ? { name: 'LoadingOutlined', spin: true } : properties.icon}
|
||||
/>
|
||||
)}
|
||||
{` ${title}`}
|
||||
</Strong>
|
||||
</Tag>
|
||||
{(defaultTitle) => (
|
||||
<>
|
||||
{properties.icon &&
|
||||
(
|
||||
<Icon
|
||||
blockId={`${blockId}_icon`}
|
||||
events={events}
|
||||
properties={showLoading ? { name: 'LoadingOutlined', spin: true } : properties.icon}
|
||||
/>
|
||||
) + ` `}
|
||||
{properties.title || defaultTitle}
|
||||
</>
|
||||
)}
|
||||
</Link>
|
||||
);
|
||||
};
|
||||
|
||||
|
@ -15,17 +15,18 @@
|
||||
*/
|
||||
|
||||
import _index from './_index.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
};
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('args calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
_index(input);
|
||||
test('_index calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
_index({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -15,22 +15,23 @@
|
||||
*/
|
||||
|
||||
import actions from './actions.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const input = {
|
||||
actions: {
|
||||
action_id: {
|
||||
response: 'returned from action',
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('actions calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
actions({
|
||||
actions: {
|
||||
action_id: {
|
||||
response: 'returned from action',
|
||||
},
|
||||
},
|
||||
},
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
};
|
||||
|
||||
test('actions calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
actions(input);
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -15,18 +15,19 @@
|
||||
*/
|
||||
|
||||
import event from './event.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
event: { event: true },
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
};
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('event calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
event(input);
|
||||
test('event calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
event({
|
||||
arrayIndices: [0],
|
||||
event: { event: true },
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -14,226 +14,29 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { WebParser } from '@lowdefy/operators';
|
||||
import event_log from './event_log.js';
|
||||
|
||||
const arrayIndices = [1];
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
const context = {
|
||||
_internal: {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
},
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
state: { state: true },
|
||||
};
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_event_log in array', async () => {
|
||||
const input = { a: { _event_log: '1.blockId' } };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
a: 'block_b',
|
||||
test('request_details calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
event_log({
|
||||
eventLog: [{ eventName: 'test' }],
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log full state', async () => {
|
||||
const input = { _event_log: true };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([
|
||||
{
|
||||
blockId: 'block_a',
|
||||
actionName: 'name_a',
|
||||
response: [{ data: ['a', 'b'] }],
|
||||
ts: new Date(0),
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
blockId: 'block_b',
|
||||
actionName: 'name_b',
|
||||
ts: new Date(1),
|
||||
error: [{ error: 'error', message: 'broken', name: 'e' }],
|
||||
},
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
object: [{ eventName: 'test' }],
|
||||
operator: '_event_log',
|
||||
params: 'params',
|
||||
},
|
||||
],
|
||||
]);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log null', async () => {
|
||||
const input = { _event_log: null };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _event_log params must be of type string, integer, boolean or object. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_event_log param object key', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
key: '0.actionName',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual('name_a');
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log param object all', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
all: true,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([
|
||||
{
|
||||
blockId: 'block_a',
|
||||
actionName: 'name_a',
|
||||
response: [{ data: ['a', 'b'] }],
|
||||
ts: new Date(0),
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
blockId: 'block_b',
|
||||
actionName: 'name_b',
|
||||
ts: new Date(1),
|
||||
error: [{ error: 'error', message: 'broken', name: 'e' }],
|
||||
},
|
||||
]);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log param object all and key', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
all: true,
|
||||
key: 'string',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([
|
||||
{
|
||||
blockId: 'block_a',
|
||||
actionName: 'name_a',
|
||||
response: [{ data: ['a', 'b'] }],
|
||||
ts: new Date(0),
|
||||
status: 'success',
|
||||
},
|
||||
{
|
||||
blockId: 'block_b',
|
||||
actionName: 'name_b',
|
||||
ts: new Date(1),
|
||||
error: [{ error: 'error', message: 'broken', name: 'e' }],
|
||||
},
|
||||
]);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log param object invalid', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
other: true,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _event_log.key must be of type string or integer. Received: {"other":true} at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_event_log param array', async () => {
|
||||
const input = {
|
||||
_event_log: ['string'],
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _event_log params must be of type string, integer, boolean or object. Received: ["string"] at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_event_log param object with string default', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
key: 'notFound',
|
||||
default: 'defaultValue',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual('defaultValue');
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log param object with zero default', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
key: 'notFound',
|
||||
default: 0,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(0);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log param object with false default', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
key: 'notFound',
|
||||
default: false,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_event_log param object with no default', async () => {
|
||||
const input = {
|
||||
_event_log: {
|
||||
key: 'notFound',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
@ -13,26 +13,20 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import _global from './global.js';
|
||||
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
let lowdefyOperators;
|
||||
let global;
|
||||
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
lowdefyGlobal: { lowdefyGlobal: true },
|
||||
params: 'params',
|
||||
};
|
||||
|
||||
beforeEach(async () => {
|
||||
lowdefyOperators = await import('@lowdefy/operators');
|
||||
global = (await import('./global.js')).default;
|
||||
});
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('global calls getFromObject', async () => {
|
||||
global(input);
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
_global({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
lowdefyGlobal: { lowdefyGlobal: true },
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -15,18 +15,19 @@
|
||||
*/
|
||||
|
||||
import input from './input.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const inputParams = {
|
||||
arrayIndices: [0],
|
||||
input: { input: true },
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
};
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('input calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
input(inputParams);
|
||||
test('input calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
input({
|
||||
arrayIndices: [0],
|
||||
input: { input: true },
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -31,6 +31,7 @@ const validProperties = [
|
||||
'hash',
|
||||
];
|
||||
|
||||
// TODO: Fix with new router and link
|
||||
function _location({ arrayIndices, context, location, params }) {
|
||||
if (!window || !window.location) {
|
||||
throw new Error(
|
||||
|
@ -15,7 +15,10 @@
|
||||
*/
|
||||
|
||||
import location from './location.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
Object.defineProperty(window, 'location', {
|
||||
@ -43,8 +46,8 @@ const input = {
|
||||
params: 'origin',
|
||||
};
|
||||
|
||||
test('location calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
test('location calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
location(input);
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { WebParser } from '@lowdefy/operators';
|
||||
import _menu from './menu.js';
|
||||
|
||||
const arrayIndices = [1];
|
||||
|
||||
@ -24,7 +25,17 @@ const context = {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
menus: [
|
||||
{
|
||||
menuId: 'default',
|
||||
},
|
||||
{
|
||||
menuId: 'm_1',
|
||||
},
|
||||
{
|
||||
menuId: 'm_2',
|
||||
},
|
||||
],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
},
|
||||
@ -35,11 +46,15 @@ const context = {
|
||||
state: { state: true },
|
||||
};
|
||||
|
||||
const operators = {
|
||||
_menu,
|
||||
};
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_menu using string menuId', async () => {
|
||||
const input = { a: { _menu: 'default' } };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
@ -52,7 +67,7 @@ test('_menu using string menuId', async () => {
|
||||
|
||||
test('_menu using index', async () => {
|
||||
const input = { a: { _menu: 1 } };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
@ -65,7 +80,7 @@ test('_menu using index', async () => {
|
||||
|
||||
test('_menu in object', async () => {
|
||||
const input = { a: { _menu: 'default' } };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
@ -78,7 +93,7 @@ test('_menu in object', async () => {
|
||||
|
||||
test('_menu full menus', async () => {
|
||||
const input = { _menu: true };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([
|
||||
@ -97,7 +112,7 @@ test('_menu full menus', async () => {
|
||||
|
||||
test('_menu null', async () => {
|
||||
const input = { _menu: null };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
@ -114,7 +129,7 @@ test('_menu param object value', async () => {
|
||||
value: 'm_2',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({ menuId: 'm_2' });
|
||||
@ -127,7 +142,7 @@ test('_menu param object index', async () => {
|
||||
index: 2,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({ menuId: 'm_2' });
|
||||
@ -140,7 +155,7 @@ test('_menu params object value not string', async () => {
|
||||
value: 1,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
@ -157,7 +172,7 @@ test('_menu params object index not number', async () => {
|
||||
index: 'a',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
@ -174,7 +189,7 @@ test('_menu param object all', async () => {
|
||||
all: true,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([
|
||||
@ -198,7 +213,7 @@ test('_menu param object all and value', async () => {
|
||||
value: 'default',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([
|
||||
@ -221,7 +236,7 @@ test('_menu param object invalid', async () => {
|
||||
other: true,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
|
@ -15,6 +15,11 @@
|
||||
*/
|
||||
|
||||
import { WebParser } from '@lowdefy/operators';
|
||||
import _request from './request.js';
|
||||
|
||||
const operators = {
|
||||
_request,
|
||||
};
|
||||
|
||||
const arrayIndices = [1];
|
||||
|
||||
@ -30,7 +35,23 @@ const context = {
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
requests: {
|
||||
arr: {
|
||||
response: [{ a: 'request a1' }, { a: 'request a2' }],
|
||||
loading: false,
|
||||
error: [],
|
||||
},
|
||||
number: {
|
||||
response: 500,
|
||||
loading: false,
|
||||
error: [],
|
||||
},
|
||||
string: {
|
||||
response: 'request String',
|
||||
loading: false,
|
||||
error: [],
|
||||
},
|
||||
},
|
||||
state: { state: true },
|
||||
};
|
||||
|
||||
@ -38,7 +59,7 @@ console.error = () => {};
|
||||
|
||||
test('_request by id', async () => {
|
||||
const input = { a: { _request: 'string' } };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
@ -49,7 +70,7 @@ test('_request by id', async () => {
|
||||
|
||||
test('_request true gives null', async () => {
|
||||
const input = { _request: true };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
@ -62,7 +83,7 @@ test('_request true gives null', async () => {
|
||||
|
||||
test('_request return full array', async () => {
|
||||
const input = { _request: 'arr' };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual([{ a: 'request a1' }, { a: 'request a2' }]);
|
||||
@ -71,7 +92,7 @@ test('_request return full array', async () => {
|
||||
|
||||
test('_request return number', async () => {
|
||||
const input = { _request: 'number' };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(500);
|
||||
@ -80,7 +101,7 @@ test('_request return number', async () => {
|
||||
|
||||
test('_request null', async () => {
|
||||
const input = { _request: null };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
@ -93,7 +114,7 @@ test('_request null', async () => {
|
||||
|
||||
test('_request loading true', async () => {
|
||||
const input = { _request: 'not_loaded' };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
@ -102,7 +123,7 @@ test('_request loading true', async () => {
|
||||
|
||||
test('_request dot notation', async () => {
|
||||
const input = { _request: 'arr.0.a' };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual('request a1');
|
||||
@ -111,7 +132,7 @@ test('_request dot notation', async () => {
|
||||
|
||||
test('_request dot notation with arrayindices', async () => {
|
||||
const input = { _request: 'arr.$.a' };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual('request a2');
|
||||
@ -120,7 +141,7 @@ test('_request dot notation with arrayindices', async () => {
|
||||
|
||||
test('_request dot notation returns null if ', async () => {
|
||||
const input = { _request: 'returnsNull.key' };
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
|
@ -14,182 +14,41 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { WebParser } from '@lowdefy/operators';
|
||||
import request_details from './request_details.js';
|
||||
|
||||
const arrayIndices = [1];
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
const context = {
|
||||
_internal: {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
test('request_details calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
request_details({
|
||||
requests: {
|
||||
request_id: {
|
||||
response: 'returned from action',
|
||||
loading: false,
|
||||
error: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
state: { state: true },
|
||||
};
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_request_details in object', async () => {
|
||||
const input = { _request_details: 'string' };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({ loading: false, response: 'request String' });
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details all requests', async () => {
|
||||
const input = { _request_details: true };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
not_loaded: { loading: true, response: 'fail' },
|
||||
string: { loading: false, response: 'request String' },
|
||||
number: { loading: false, response: 500 },
|
||||
arr: { loading: false, response: [{ a: 'request a1' }, { a: 'request a2' }] },
|
||||
returnsNull: { loading: false, response: null },
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details null', async () => {
|
||||
const input = { _request_details: null };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _request_details params must be of type string, integer, boolean or object. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_request_details nested', async () => {
|
||||
const input = { _request_details: 'string.response' };
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual('request String');
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details param object key', async () => {
|
||||
const input = {
|
||||
_request_details: {
|
||||
key: 'string',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({ loading: false, response: 'request String' });
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details param object all', async () => {
|
||||
const input = {
|
||||
_request_details: {
|
||||
all: true,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
not_loaded: { loading: true, response: 'fail' },
|
||||
string: { loading: false, response: 'request String' },
|
||||
number: { loading: false, response: 500 },
|
||||
arr: { loading: false, response: [{ a: 'request a1' }, { a: 'request a2' }] },
|
||||
returnsNull: { loading: false, response: null },
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details param object all and key', async () => {
|
||||
const input = {
|
||||
_request_details: {
|
||||
all: true,
|
||||
key: 'string',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual({
|
||||
not_loaded: { loading: true, response: 'fail' },
|
||||
string: { loading: false, response: 'request String' },
|
||||
number: { loading: false, response: 500 },
|
||||
arr: { loading: false, response: [{ a: 'request a1' }, { a: 'request a2' }] },
|
||||
returnsNull: { loading: false, response: null },
|
||||
});
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details param object invalid', async () => {
|
||||
const input = {
|
||||
_request_details: {
|
||||
other: true,
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _request_details.key must be of type string or integer. Received: {"other":true} at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_request_details param array', async () => {
|
||||
const input = {
|
||||
_request_details: ['string'],
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _request_details params must be of type string, integer, boolean or object. Received: ["string"] at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_request_details param object with string default', async () => {
|
||||
const input = {
|
||||
_request_details: {
|
||||
key: 'notFound',
|
||||
default: 'defaultValue',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual('defaultValue');
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_request_details param object with no default', async () => {
|
||||
const input = {
|
||||
_request_details: {
|
||||
key: 'notFound',
|
||||
},
|
||||
};
|
||||
const parser = new WebParser({ context });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId', arrayIndices });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
object: {
|
||||
request_id: {
|
||||
response: 'returned from action',
|
||||
loading: false,
|
||||
error: [],
|
||||
},
|
||||
},
|
||||
operator: '_request_details',
|
||||
params: 'params',
|
||||
},
|
||||
],
|
||||
]);
|
||||
});
|
||||
|
@ -15,18 +15,19 @@
|
||||
*/
|
||||
|
||||
import state from './state.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
state: { state: true },
|
||||
};
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('state calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
state(input);
|
||||
test('state calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
state({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
state: { state: true },
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -15,19 +15,21 @@
|
||||
*/
|
||||
|
||||
import url_query from './url_query.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
secrets: { secrets: true },
|
||||
urlQuery: { urlQuery: true },
|
||||
};
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('url_query calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
url_query(input);
|
||||
const input = {};
|
||||
|
||||
test('url_query calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
url_query({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
urlQuery: { urlQuery: true },
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -15,17 +15,18 @@
|
||||
*/
|
||||
|
||||
import payload from './payload.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
const input = {
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
payload: { payload: true },
|
||||
};
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('payload calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
payload(input);
|
||||
test('payload calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
payload({
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
payload: { payload: true },
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -15,12 +15,15 @@
|
||||
*/
|
||||
|
||||
import secret from './secret.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('secret calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
test('secret calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
secret({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
@ -41,8 +44,8 @@ test('secret calls getFromObject', () => {
|
||||
]);
|
||||
});
|
||||
|
||||
test('secret default value', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
test('secret default value', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
secret({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
@ -72,8 +75,8 @@ test('secret get all is not allowed', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('secret OpenID Connect and JSON web token secrets are filtered out', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
test('secret OpenID Connect and JSON web token secrets are filtered out', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
secret({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
|
@ -13,34 +13,69 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { NodeParser, WebParser } from '@lowdefy/operators';
|
||||
import _and from './and.js';
|
||||
|
||||
import and from './and.js';
|
||||
const operators = {
|
||||
_and,
|
||||
};
|
||||
|
||||
const location = 'location';
|
||||
|
||||
test('_and false', () => {
|
||||
expect(and({ params: [0, 0], location })).toEqual(false);
|
||||
expect(and({ params: [0, 1], location })).toEqual(false);
|
||||
expect(and({ params: [1, 2, 3, 0], location })).toEqual(false);
|
||||
expect(and({ params: [false, false], location })).toEqual(false);
|
||||
expect(and({ params: [false, true], location })).toEqual(false);
|
||||
expect(_and({ params: [0, 0], location })).toEqual(false);
|
||||
expect(_and({ params: [0, 1], location })).toEqual(false);
|
||||
expect(_and({ params: [1, 2, 3, 0], location })).toEqual(false);
|
||||
expect(_and({ params: [false, false], location })).toEqual(false);
|
||||
expect(_and({ params: [false, true], location })).toEqual(false);
|
||||
});
|
||||
test('_and true', () => {
|
||||
expect(and({ params: [1, 2], location })).toEqual(true);
|
||||
expect(and({ params: [1, 2, 3], location })).toEqual(true);
|
||||
expect(and({ params: [true, true], location })).toEqual(true);
|
||||
expect(_and({ params: [1, 2], location })).toEqual(true);
|
||||
expect(_and({ params: [1, 2, 3], location })).toEqual(true);
|
||||
expect(_and({ params: [true, true], location })).toEqual(true);
|
||||
});
|
||||
test('_and errors', () => {
|
||||
expect(() => and({ params: 'hello', location })).toThrow(
|
||||
expect(() => _and({ params: 'hello', location })).toThrow(
|
||||
'Operator Error: _and takes an array type. Received: "hello" at location.'
|
||||
);
|
||||
expect(() => and({ params: null, location })).toThrow(
|
||||
expect(() => _and({ params: null, location })).toThrow(
|
||||
'Operator Error: _and takes an array type. Received: null at location.'
|
||||
);
|
||||
expect(() => and({ params: true, location })).toThrow(
|
||||
expect(() => _and({ params: true, location })).toThrow(
|
||||
'Operator Error: _and takes an array type. Received: true at location.'
|
||||
);
|
||||
expect(() => and({ params: false, location })).toThrow(
|
||||
expect(() => _and({ params: false, location })).toThrow(
|
||||
'Operator Error: _and takes an array type. Received: false at location.'
|
||||
);
|
||||
});
|
||||
|
||||
test('_and evaluated in NodeParser', async () => {
|
||||
const input = { a: { _and: [true, true] } };
|
||||
const parser = new NodeParser({ operators, payload: {}, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: true });
|
||||
});
|
||||
|
||||
test('_and evaluated in WebParser', async () => {
|
||||
const context = {
|
||||
_internal: {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
},
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
state: { state: true },
|
||||
};
|
||||
const input = { a: { _and: [true, true] } };
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: true });
|
||||
});
|
||||
|
@ -13,7 +13,11 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
jest.mock('@lowdefy/operators');
|
||||
import args from './args.js';
|
||||
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
const input = {
|
||||
args: [{ args: true }],
|
||||
@ -23,9 +27,13 @@ const input = {
|
||||
};
|
||||
|
||||
test('args calls getFromObject', async () => {
|
||||
const args = await import('./args.js');
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
args.default(input);
|
||||
args({
|
||||
args: [{ args: true }],
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -16,7 +16,7 @@
|
||||
|
||||
import date from './date.js';
|
||||
|
||||
const location = 'locationId';
|
||||
const location = 'location';
|
||||
|
||||
test('_date now', () => {
|
||||
const RealDate = Date;
|
||||
@ -57,19 +57,19 @@ test('_date negative int', () => {
|
||||
test('_date null', () => {
|
||||
expect(() => date({ params: null, location })).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _date.__default accepts one of the following types: number, string.
|
||||
Received: {\\"_date.__default\\":null} at locationId."
|
||||
Received: {\\"_date.__default\\":null} at location."
|
||||
`);
|
||||
});
|
||||
|
||||
test('_date invalid operator type', () => {
|
||||
expect(() => date({ params: {}, location })).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _date.__default accepts one of the following types: number, string.
|
||||
Received: {\\"_date.__default\\":{}} at locationId."
|
||||
Received: {\\"_date.__default\\":{}} at location."
|
||||
`);
|
||||
});
|
||||
|
||||
test('_date invalid string', () => {
|
||||
expect(() => date({ params: 'abc', location })).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Operator Error: _date.__default - abc could not resolve as a valid javascript date. Received: {\\"_date.__default\\":\\"abc\\"} at locationId."`
|
||||
`"Operator Error: _date.__default - abc could not resolve as a valid javascript date. Received: {\\"_date.__default\\":\\"abc\\"} at location."`
|
||||
);
|
||||
});
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
import eq from './eq.js';
|
||||
|
||||
const location = 'location';
|
||||
|
||||
test('_eq false', () => {
|
||||
expect(eq({ params: [1, 2], location })).toEqual(false);
|
||||
expect(eq({ params: [0, 1], location })).toEqual(false);
|
||||
@ -41,4 +43,7 @@ test('_eq errors', () => {
|
||||
expect(() => eq({ params: false, location })).toThrow(
|
||||
'Operator Error: _eq takes an array type as input. Received: false at location.'
|
||||
);
|
||||
expect(() => eq({ params: [1, 2, 3], location })).toThrow(
|
||||
'Operator Error: _eq takes an array of length 2 as input. Received: [1,2,3] at location.'
|
||||
);
|
||||
});
|
||||
|
@ -15,12 +15,15 @@
|
||||
*/
|
||||
import { NodeParser, WebParser } from '@lowdefy/operators';
|
||||
import _function from './function.js';
|
||||
import _args from './args.js';
|
||||
import _payload from '../server/payload.js';
|
||||
import _state from '../client/state.js';
|
||||
|
||||
const operators = {
|
||||
_test: jest.fn(() => 'test'),
|
||||
_error: jest.fn(() => {
|
||||
throw new Error('Test error.');
|
||||
}),
|
||||
_args,
|
||||
_function,
|
||||
_payload,
|
||||
_state,
|
||||
};
|
||||
|
||||
const state = {
|
||||
@ -37,25 +40,34 @@ const payload = {
|
||||
const location = 'location';
|
||||
|
||||
const context = {
|
||||
lowdefy: { inputs: {} },
|
||||
_internal: {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
},
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
state,
|
||||
operators,
|
||||
};
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('NodeParser, _function that gets from payload', async () => {
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const params = { __payload: 'string' };
|
||||
const fn = _function({ location, params, parser });
|
||||
expect(fn).toBeInstanceOf(Function);
|
||||
expect(fn()).toEqual('Some String');
|
||||
expect(fn()).toEqual('Some String');
|
||||
});
|
||||
|
||||
test('NodeParser, _function gives args as an array', async () => {
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const params = { __args: true };
|
||||
const fn = _function({ location, params, parser });
|
||||
@ -64,7 +76,7 @@ test('NodeParser, _function gives args as an array', async () => {
|
||||
});
|
||||
|
||||
test('NodeParser, _function throws on parser errors', async () => {
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const params = { __payload: [] };
|
||||
const fn = _function({ location, params, parser });
|
||||
@ -74,7 +86,7 @@ test('NodeParser, _function throws on parser errors', async () => {
|
||||
});
|
||||
|
||||
test('WebParser, _function that gets from state', async () => {
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const params = { __state: 'string' };
|
||||
const fn = _function({ location, params, parser });
|
||||
@ -84,7 +96,7 @@ test('WebParser, _function that gets from state', async () => {
|
||||
});
|
||||
|
||||
test('WebParser, _function gives args as an array', async () => {
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const params = { __args: true };
|
||||
const fn = _function({ location, params, parser });
|
||||
@ -93,7 +105,7 @@ test('WebParser, _function gives args as an array', async () => {
|
||||
});
|
||||
|
||||
test('WebParser, _function throws on parser errors', async () => {
|
||||
const parser = new WebParser({ context });
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const params = { __state: [] };
|
||||
const fn = _function({ location, params, parser });
|
||||
|
@ -14,19 +14,21 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
import get from './get.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
|
||||
test('_get calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
const input = {
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
test('_get calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
get({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: {
|
||||
from: { a: 1 },
|
||||
key: 'a',
|
||||
},
|
||||
};
|
||||
get.default(input);
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
@ -52,7 +54,6 @@ test('_get returns null if from is null', () => {
|
||||
key: 'a',
|
||||
},
|
||||
};
|
||||
get(input);
|
||||
expect(get(input)).toBe(null);
|
||||
});
|
||||
|
||||
@ -66,7 +67,6 @@ test('_get returns default value if from is null', () => {
|
||||
default: 'default',
|
||||
},
|
||||
};
|
||||
get(input);
|
||||
expect(get(input)).toBe('default');
|
||||
});
|
||||
|
||||
|
@ -13,122 +13,33 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
// import { NodeParser } from '@lowdefy/operators';
|
||||
|
||||
import _if from './if.js';
|
||||
|
||||
const location = 'location';
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_if', async () => {
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
let res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: true,
|
||||
then: 1,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(1);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: false,
|
||||
then: 1,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(2);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
then: 1,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _if takes a boolean type for parameter test. Received: {"then":1,"else":2} at locationId.],
|
||||
]
|
||||
`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: false,
|
||||
then: 1,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(undefined);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: true,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(undefined);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: {
|
||||
a: [1, 3],
|
||||
},
|
||||
then: 1,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _if takes a boolean type for parameter test. Received: {"test":{"a":[1,3]},"then":1,"else":2} at locationId.],
|
||||
]
|
||||
`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: 'True',
|
||||
then: 1,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _if takes a boolean type for parameter test. Received: {"test":"True","then":1,"else":2} at locationId.],
|
||||
]
|
||||
`);
|
||||
res = parser.parse({
|
||||
input: {
|
||||
_if: {
|
||||
test: 1,
|
||||
then: 1,
|
||||
else: 2,
|
||||
},
|
||||
},
|
||||
location: 'locationId',
|
||||
});
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _if takes a boolean type for parameter test. Received: {"test":1,"then":1,"else":2} at locationId.],
|
||||
]
|
||||
`);
|
||||
test('_if then', () => {
|
||||
expect(_if({ params: { test: true, then: 1, else: 2 }, location })).toEqual(1);
|
||||
expect(_if({ params: { test: true, else: 2 }, location })).toEqual(undefined);
|
||||
});
|
||||
test('_if else', () => {
|
||||
expect(_if({ params: { test: false, then: 1, else: 2 }, location })).toEqual(2);
|
||||
expect(_if({ params: { test: false, then: 1 }, location })).toEqual(undefined);
|
||||
});
|
||||
test('_if errors', () => {
|
||||
expect(() => _if({ params: { then: 1, else: 2 }, location })).toThrow(
|
||||
'Operator Error: _if takes a boolean type for parameter test. Received: {"then":1,"else":2} at location.'
|
||||
);
|
||||
expect(() => _if({ params: { test: { a: [1, 3] }, then: 1, else: 2 }, location })).toThrow(
|
||||
'Operator Error: _if takes a boolean type for parameter test. Received: {"test":{"a":[1,3]},"then":1,"else":2} at location.'
|
||||
);
|
||||
expect(() => _if({ params: { test: 'True', then: 1, else: 2 }, location })).toThrow(
|
||||
'Operator Error: _if takes a boolean type for parameter test. Received: {"test":"True","then":1,"else":2} at location.'
|
||||
);
|
||||
expect(() => _if({ params: { test: 1, then: 1, else: 2 }, location })).toThrow(
|
||||
'Operator Error: _if takes a boolean type for parameter test. Received: {"test":1,"then":1,"else":2} at location.'
|
||||
);
|
||||
});
|
||||
|
@ -15,7 +15,9 @@
|
||||
*/
|
||||
|
||||
/* eslint-disable max-classes-per-file */
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import _log from './log.js';
|
||||
|
||||
const location = 'location';
|
||||
|
||||
const logger = console.log;
|
||||
const mockLogger = jest.fn();
|
||||
@ -27,91 +29,36 @@ afterAll(() => {
|
||||
console.log = logger;
|
||||
});
|
||||
|
||||
test('_log a string', async () => {
|
||||
const input = { a: { _log: 'value' } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: 'value',
|
||||
});
|
||||
test('_log a string', () => {
|
||||
expect(_log({ params: 'value', location })).toEqual('value');
|
||||
expect(mockLogger).toHaveBeenCalledWith('value');
|
||||
});
|
||||
|
||||
test('_log a number', async () => {
|
||||
const input = { a: { _log: 1 } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: 1,
|
||||
});
|
||||
test('_log a number', () => {
|
||||
expect(_log({ params: 1, location })).toEqual(1);
|
||||
expect(mockLogger).toHaveBeenCalledWith(1);
|
||||
});
|
||||
|
||||
test('_log a null', async () => {
|
||||
const input = { a: { _log: null } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: null,
|
||||
});
|
||||
test('_log a null', () => {
|
||||
expect(_log({ params: null, location })).toEqual(null);
|
||||
expect(mockLogger).toHaveBeenCalledWith(null);
|
||||
});
|
||||
|
||||
// TODO: Confirm if this is expected behaviour??
|
||||
test('_log a undefined', async () => {
|
||||
const input = { a: { _log: undefined } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: {},
|
||||
});
|
||||
expect(mockLogger).not.toHaveBeenCalled();
|
||||
test('_log an undefined', () => {
|
||||
expect(_log({ params: undefined, location })).toEqual(undefined);
|
||||
expect(mockLogger).toHaveBeenCalledWith(undefined);
|
||||
});
|
||||
|
||||
test('_log a 0', async () => {
|
||||
const input = { a: { _log: 0 } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: 0,
|
||||
});
|
||||
test('_log a 0', () => {
|
||||
expect(_log({ params: 0, location })).toEqual(0);
|
||||
expect(mockLogger).toHaveBeenCalledWith(0);
|
||||
});
|
||||
|
||||
test('_log a false', async () => {
|
||||
const input = { a: { _log: false } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: false,
|
||||
});
|
||||
test('_log a false', () => {
|
||||
expect(_log({ params: false, location })).toEqual(false);
|
||||
expect(mockLogger).toHaveBeenCalledWith(false);
|
||||
});
|
||||
|
||||
test('_log a object', async () => {
|
||||
const input = { a: { _log: { b: 1 } } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: { b: 1 },
|
||||
});
|
||||
test('_log an object', () => {
|
||||
expect(_log({ params: { b: 1 }, location })).toEqual({ b: 1 });
|
||||
expect(mockLogger).toHaveBeenCalledWith({ b: 1 });
|
||||
});
|
||||
|
||||
test('_log a array', async () => {
|
||||
const input = { a: { _log: [{ b: 1 }] } };
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual({
|
||||
a: [{ b: 1 }],
|
||||
});
|
||||
test('_log an array', () => {
|
||||
expect(_log({ params: [{ b: 1 }], location })).toEqual([{ b: 1 }]);
|
||||
expect(mockLogger).toHaveBeenCalledWith([{ b: 1 }]);
|
||||
});
|
||||
|
@ -13,48 +13,20 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import _not from './not.js';
|
||||
|
||||
const arr0 = [0, 0];
|
||||
const arr1 = [0, 1];
|
||||
const arr2 = [1, 2];
|
||||
const arr3 = [1, 2, 3];
|
||||
const arr30 = [1, 2, 3, 0];
|
||||
const string = 'hello';
|
||||
const Null = null;
|
||||
const True = true;
|
||||
const False = false;
|
||||
const location = 'location';
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_not', async () => {
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
let res = parser.parse({ input: { _not: arr0 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: arr1 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: arr2 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: arr3 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: arr30 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: string }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: Null }, location: 'locationId' });
|
||||
expect(res.output).toEqual(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: True }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _not: False }, location: 'locationId' });
|
||||
expect(res.output).toEqual(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_not returns true', () => {
|
||||
expect(_not({ params: 0, location })).toEqual(true);
|
||||
expect(_not({ params: null, location })).toEqual(true);
|
||||
expect(_not({ params: false, location })).toEqual(true);
|
||||
});
|
||||
test('_not returns false', () => {
|
||||
expect(_not({ params: 1, location })).toEqual(false);
|
||||
expect(_not({ params: true, location })).toEqual(false);
|
||||
expect(_not({ params: [0, 0], location })).toEqual(false);
|
||||
expect(_not({ params: 'string', location })).toEqual(false);
|
||||
});
|
||||
|
@ -56,7 +56,7 @@ test('_number valid functions', () => {
|
||||
);
|
||||
expect(
|
||||
_number({ methodName: 'toLocaleString', params: [123456.789, 'de-DE'], location: 'locationId' })
|
||||
).toBe('123,456.789');
|
||||
).toBe('123.456,789');
|
||||
expect(
|
||||
_number({ methodName: 'toPrecision', params: [5.123456, 2], location: 'locationId' })
|
||||
).toBe('5.1');
|
||||
|
@ -15,6 +15,25 @@
|
||||
*/
|
||||
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import _args from './args.js';
|
||||
import _function from './function.js';
|
||||
import _json from './json.js';
|
||||
import _not from './not.js';
|
||||
import _payload from '../server/payload.js';
|
||||
import _operator from './operator.js';
|
||||
import _state from '../client/state.js';
|
||||
|
||||
const operators = {
|
||||
_args,
|
||||
_function,
|
||||
_json,
|
||||
_not,
|
||||
_payload,
|
||||
_operator,
|
||||
_state,
|
||||
};
|
||||
|
||||
const location = 'location';
|
||||
|
||||
const payload = {
|
||||
string: 'Some String',
|
||||
@ -26,9 +45,9 @@ console.error = () => {};
|
||||
|
||||
test('_operator, _payload', async () => {
|
||||
const input = { a: { _operator: { name: '_payload', params: 'string' } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({
|
||||
a: 'Some String',
|
||||
});
|
||||
@ -37,83 +56,83 @@ test('_operator, _payload', async () => {
|
||||
|
||||
test('_operator.name invalid', async () => {
|
||||
const input = { a: { _operator: { name: '_a' } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: null });
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _operator - Invalid operator name. Received: {"name":"_a"} at locationId.],
|
||||
[Error: Operator Error: _operator - Invalid operator name. Received: {"name":"_a"} at location.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_operator.name not allowed to include "experimental"', async () => {
|
||||
const input = { a: { _operator: { name: '_experimental_op' } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: null });
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: Experimental operators cannot be used with _operator. Received: {"name":"_experimental_op"} at locationId.],
|
||||
[Error: Operator Error: Experimental operators cannot be used with _operator. Received: {"name":"_experimental_op"} at location.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_operator.name not a string', async () => {
|
||||
const input = { a: { _operator: { name: 1 } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: null });
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _operator.name must be a valid operator name as string. Received: {"name":1} at locationId.],
|
||||
[Error: Operator Error: _operator.name must be a valid operator name as string. Received: {"name":1} at location.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_operator with value not a object', async () => {
|
||||
const input = { a: { _operator: 'a' } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: null });
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _operator.name must be a valid operator name as string. Received: "a" at locationId.],
|
||||
[Error: Operator Error: _operator.name must be a valid operator name as string. Received: "a" at location.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_operator cannot be set to _operator', async () => {
|
||||
const input = { a: { _operator: { name: '_operator' } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: null });
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _operator.name cannot be set to _operator to infinite avoid loop reference. Received: {"name":"_operator"} at locationId.],
|
||||
[Error: Operator Error: _operator.name cannot be set to _operator to infinite avoid loop reference. Received: {"name":"_operator"} at location.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_operator, _not with no params', async () => {
|
||||
const input = { a: { _operator: { name: '_not' } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: true });
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_operator, _json.parse with params', async () => {
|
||||
const input = { a: { _operator: { name: '_json.parse', params: '[{ "a": "a1"}]' } } };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({
|
||||
a: [{ a: 'a1' }],
|
||||
});
|
||||
|
@ -13,64 +13,69 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import { NodeParser, WebParser } from '@lowdefy/operators';
|
||||
import _or from './or.js';
|
||||
|
||||
const arr0 = [0, 0];
|
||||
const arr1 = [0, 1];
|
||||
const arr2 = [1, 2];
|
||||
const arr3 = [1, 2, 3];
|
||||
const arr30 = [1, 2, 3, 0];
|
||||
const string = 'hello';
|
||||
const Null = null;
|
||||
const True = true;
|
||||
const False = false;
|
||||
const operators = {
|
||||
_or,
|
||||
};
|
||||
|
||||
console.error = () => {};
|
||||
const location = 'location';
|
||||
|
||||
test('_or', async () => {
|
||||
const parser = new NodeParser();
|
||||
await parser.init();
|
||||
let res = parser.parse({ input: { _or: arr0 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _or: arr1 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _or: arr2 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _or: arr3 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _or: arr30 }, location: 'locationId' });
|
||||
expect(res.output).toEqual(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
res = parser.parse({ input: { _or: string }, location: 'locationId' });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _or takes an array type. Received: "hello" at locationId.],
|
||||
]
|
||||
`);
|
||||
res = parser.parse({ input: { _or: Null }, location: 'locationId' });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _or takes an array type. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
res = parser.parse({ input: { _or: True }, location: 'locationId' });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _or takes an array type. Received: true at locationId.],
|
||||
]
|
||||
`);
|
||||
res = parser.parse({ input: { _or: False }, location: 'locationId' });
|
||||
expect(res.output).toEqual(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _or takes an array type. Received: false at locationId.],
|
||||
]
|
||||
`);
|
||||
test('_or false', () => {
|
||||
expect(_or({ params: [0, 0], location })).toEqual(false);
|
||||
expect(_or({ params: [false, false], location })).toEqual(false);
|
||||
});
|
||||
test('_or true', () => {
|
||||
expect(_or({ params: [0, 1], location })).toEqual(true);
|
||||
expect(_or({ params: [1, 2], location })).toEqual(true);
|
||||
expect(_or({ params: [1, 2, 3], location })).toEqual(true);
|
||||
expect(_or({ params: [1, 2, 3, 0], location })).toEqual(true);
|
||||
expect(_or({ params: [true, true], location })).toEqual(true);
|
||||
expect(_or({ params: [false, true], location })).toEqual(true);
|
||||
});
|
||||
test('_or errors', () => {
|
||||
expect(() => _or({ params: 'hello', location })).toThrow(
|
||||
'Operator Error: _or takes an array type. Received: "hello" at location.'
|
||||
);
|
||||
expect(() => _or({ params: null, location })).toThrow(
|
||||
'Operator Error: _or takes an array type. Received: null at location.'
|
||||
);
|
||||
expect(() => _or({ params: true, location })).toThrow(
|
||||
'Operator Error: _or takes an array type. Received: true at location.'
|
||||
);
|
||||
expect(() => _or({ params: false, location })).toThrow(
|
||||
'Operator Error: _or takes an array type. Received: false at location.'
|
||||
);
|
||||
});
|
||||
|
||||
test('_or evaluated in NodeParser', async () => {
|
||||
const input = { a: { _or: [true, false] } };
|
||||
const parser = new NodeParser({ operators, payload: {}, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: true });
|
||||
});
|
||||
|
||||
test('_or evaluated in WebParser', async () => {
|
||||
const context = {
|
||||
_internal: {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
},
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
state: { state: true },
|
||||
};
|
||||
const input = { a: { _or: [true, false] } };
|
||||
const parser = new WebParser({ context, operators });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual({ a: true });
|
||||
});
|
||||
|
@ -13,129 +13,77 @@
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
import _regex from './regex.js';
|
||||
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
|
||||
const state = {
|
||||
string: 'Some String',
|
||||
number: 42,
|
||||
arr: [{ a: 'a1' }, { a: 'a2' }],
|
||||
};
|
||||
const location = 'location';
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_regex with on, pass', async () => {
|
||||
const input = { _regex: { pattern: '^a$', on: 'a' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_regex with on, pass', () => {
|
||||
expect(_regex({ params: { on: 'a', pattern: '^a$' }, location })).toEqual(true);
|
||||
});
|
||||
|
||||
test('_regex with on, fail', async () => {
|
||||
const input = { _regex: { pattern: '^a$', on: 'b' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_regex with on, fail', () => {
|
||||
expect(_regex({ params: { on: 'b', pattern: '^a$' }, location })).toEqual(false);
|
||||
});
|
||||
|
||||
// NOTE: key not supported by NodeParser
|
||||
// test('_regex with key, pass', async () => {
|
||||
// const input = { _regex: { pattern: '^Some String$', key: 'string' } };
|
||||
// const parser = new NodeParser({ state });
|
||||
// await parser.init();
|
||||
// const res = parser.parse({ input, location: 'locationId' });
|
||||
// expect(res.output).toBe(true);
|
||||
// expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
// });
|
||||
|
||||
// test('_regex with key, fail', async () => {
|
||||
// const input = { _regex: { pattern: '^a$', key: 'string' } };
|
||||
// const parser = new NodeParser({ state });
|
||||
// await parser.init();
|
||||
// const res = parser.parse({ input, location: 'locationId' });
|
||||
// expect(res.output).toBe(false);
|
||||
// expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
// });
|
||||
|
||||
test('_regex with null on', async () => {
|
||||
const input = { _regex: { pattern: '^a$', on: null } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_regex with null on', () => {
|
||||
expect(_regex({ params: { on: null, pattern: '^a$' }, location })).toEqual(false);
|
||||
});
|
||||
|
||||
test('_regex with nonexistent key', async () => {
|
||||
const input = { _regex: { pattern: '^a$', key: 'notThere' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_regex with on, pass', () => {
|
||||
expect(_regex({ params: { on: 'a', pattern: '^a$' }, location })).toEqual(true);
|
||||
});
|
||||
|
||||
test('_regex with nonexistent key', async () => {
|
||||
const input = { _regex: { pattern: '^a$', key: null } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _regex.key must be a string. Received: {"pattern":"^a$","key":null} at locationId.],
|
||||
]
|
||||
`);
|
||||
test('_regex with key, pass', () => {
|
||||
expect(
|
||||
_regex({
|
||||
params: { key: 'string', pattern: '^Some String$' },
|
||||
location,
|
||||
state: { string: 'Some String' },
|
||||
})
|
||||
).toEqual(true);
|
||||
});
|
||||
|
||||
test('_regex null', async () => {
|
||||
const input = { _regex: null };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _regex.pattern must be a string. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
test('_regex with key, fail', () => {
|
||||
expect(
|
||||
_regex({
|
||||
params: { key: 'string', pattern: '^a$' },
|
||||
location,
|
||||
state: { string: 'Some String' },
|
||||
})
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
test('_regex with non-string on', async () => {
|
||||
const input = { _regex: { pattern: '^a$', on: 5 } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _regex.on must be a string. Received: {"pattern":"^a$","on":5} at locationId.],
|
||||
]
|
||||
`);
|
||||
test('_regex with nonexistent', () => {
|
||||
expect(
|
||||
_regex({
|
||||
params: { key: 'notThere', pattern: '^a$' },
|
||||
location,
|
||||
state: { string: 'Some String' },
|
||||
})
|
||||
).toEqual(false);
|
||||
});
|
||||
|
||||
test('_regex flags', async () => {
|
||||
const input = { _regex: { pattern: 'a', on: 'A', flags: 'i' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_regex with null key', () => {
|
||||
expect(() =>
|
||||
_regex({
|
||||
params: { key: null, pattern: '^a$' },
|
||||
location,
|
||||
state: { string: 'Some String' },
|
||||
})
|
||||
).toThrow(
|
||||
'Operator Error: _regex.key must be a string. Received: {"key":null,"pattern":"^a$"} at location.'
|
||||
);
|
||||
});
|
||||
|
||||
test('_regex invalid flags', async () => {
|
||||
const input = { _regex: { pattern: 'a', on: 'a', flags: 1 } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _regex failed to execute RegExp.test. Received: {"pattern":"a","on":"a","flags":1} at locationId.],
|
||||
]
|
||||
`);
|
||||
test('_regex null', () => {
|
||||
expect(() => _regex({ params: null, location })).toThrow(
|
||||
'Operator Error: _regex.pattern must be a string. Received: null at location.'
|
||||
);
|
||||
});
|
||||
test('_regex with non-string on', () => {
|
||||
expect(() => _regex({ params: { pattern: '^a$', on: 5 }, location })).toThrow(
|
||||
'Operator Error: _regex.on must be a string. Received: {"pattern":"^a$","on":5} at location.'
|
||||
);
|
||||
});
|
||||
test('_regex flags', () => {
|
||||
expect(_regex({ params: { on: 'A', pattern: '^a$', flags: 'i' }, location })).toEqual(true);
|
||||
});
|
||||
test('_regex invalid flags', () => {
|
||||
expect(() => _regex({ params: { pattern: '^a$', on: 'A', flags: 1 }, location })).toThrow(
|
||||
'Operator Error: _regex failed to execute RegExp.test. Received: {"pattern":"^a$","on":"A","flags":1} at location.'
|
||||
);
|
||||
});
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import string from './string.js';
|
||||
const location = 'locationId';
|
||||
const location = 'location';
|
||||
|
||||
describe('_string.charAt', () => {
|
||||
const methodName = 'charAt';
|
||||
@ -51,7 +51,7 @@ describe('_string.charAt', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.charAt must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.charAt\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.charAt\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -61,7 +61,7 @@ describe('_string.charAt', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.charAt must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.charAt\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.charAt\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -71,7 +71,7 @@ describe('_string.charAt', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.charAt accepts one of the following types: array, object.
|
||||
Received: {\\"_string.charAt\\":null} at locationId."
|
||||
Received: {\\"_string.charAt\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -124,7 +124,7 @@ describe('_string.concat', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.concat must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.concat\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.concat\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -134,7 +134,7 @@ describe('_string.concat', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.concat accepts one of the following types: array.
|
||||
Received: {\\"_string.concat\\":\\"abc\\"} at locationId."
|
||||
Received: {\\"_string.concat\\":\\"abc\\"} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -144,7 +144,7 @@ describe('_string.concat', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.concat accepts one of the following types: array.
|
||||
Received: {\\"_string.concat\\":null} at locationId."
|
||||
Received: {\\"_string.concat\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -190,7 +190,7 @@ describe('_string.endsWith', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.endsWith must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.endsWith\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.endsWith\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -200,7 +200,7 @@ describe('_string.endsWith', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.endsWith must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.endsWith\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.endsWith\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -210,7 +210,7 @@ describe('_string.endsWith', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.endsWith accepts one of the following types: array, object.
|
||||
Received: {\\"_string.endsWith\\":null} at locationId."
|
||||
Received: {\\"_string.endsWith\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -256,7 +256,7 @@ describe('_string.includes', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.includes must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.includes\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.includes\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -266,7 +266,7 @@ describe('_string.includes', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.includes must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.includes\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.includes\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -276,7 +276,7 @@ describe('_string.includes', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.includes accepts one of the following types: array, object.
|
||||
Received: {\\"_string.includes\\":null} at locationId."
|
||||
Received: {\\"_string.includes\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -329,7 +329,7 @@ describe('_string.indexOf', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.indexOf must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.indexOf\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.indexOf\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -339,7 +339,7 @@ describe('_string.indexOf', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.indexOf must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.indexOf\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.indexOf\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -349,7 +349,7 @@ describe('_string.indexOf', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.indexOf accepts one of the following types: array, object.
|
||||
Received: {\\"_string.indexOf\\":null} at locationId."
|
||||
Received: {\\"_string.indexOf\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -395,7 +395,7 @@ describe('_string.lastIndexOf', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.lastIndexOf must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.lastIndexOf\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.lastIndexOf\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -405,7 +405,7 @@ describe('_string.lastIndexOf', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.lastIndexOf must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.lastIndexOf\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.lastIndexOf\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -415,7 +415,7 @@ describe('_string.lastIndexOf', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.lastIndexOf accepts one of the following types: array, object.
|
||||
Received: {\\"_string.lastIndexOf\\":null} at locationId."
|
||||
Received: {\\"_string.lastIndexOf\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -485,7 +485,7 @@ describe('_string.match', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.match must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.match\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.match\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -495,7 +495,7 @@ describe('_string.match', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.match must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.match\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.match\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -505,7 +505,7 @@ describe('_string.match', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.match accepts one of the following types: array, object.
|
||||
Received: {\\"_string.match\\":null} at locationId."
|
||||
Received: {\\"_string.match\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -536,7 +536,7 @@ describe('_string.normalize', () => {
|
||||
location,
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(
|
||||
`"Operator Error: _string.normalize - The normalization form should be one of NFC, NFD, NFKC, NFKD. Received: {\\"_string.normalize\\":[\\"Amélie\\",2]} at locationId."`
|
||||
`"Operator Error: _string.normalize - The normalization form should be one of NFC, NFD, NFKC, NFKD. Received: {\\"_string.normalize\\":[\\"Amélie\\",2]} at location."`
|
||||
);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -546,7 +546,7 @@ describe('_string.normalize', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.normalize must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.normalize\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.normalize\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -556,7 +556,7 @@ describe('_string.normalize', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.normalize must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.normalize\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.normalize\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -566,7 +566,7 @@ describe('_string.normalize', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.normalize accepts one of the following types: array, object.
|
||||
Received: {\\"_string.normalize\\":null} at locationId."
|
||||
Received: {\\"_string.normalize\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -605,7 +605,7 @@ describe('_string.padEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.padEnd must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.padEnd\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.padEnd\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -615,7 +615,7 @@ describe('_string.padEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.padEnd must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.padEnd\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.padEnd\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -625,7 +625,7 @@ describe('_string.padEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.padEnd accepts one of the following types: array, object.
|
||||
Received: {\\"_string.padEnd\\":null} at locationId."
|
||||
Received: {\\"_string.padEnd\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -664,7 +664,7 @@ describe('_string.padStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.padStart must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.padStart\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.padStart\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -674,7 +674,7 @@ describe('_string.padStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.padStart must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.padStart\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.padStart\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -684,7 +684,7 @@ describe('_string.padStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.padStart accepts one of the following types: array, object.
|
||||
Received: {\\"_string.padStart\\":null} at locationId."
|
||||
Received: {\\"_string.padStart\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -716,7 +716,7 @@ describe('_string.repeat', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.repeat must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.repeat\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.repeat\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -726,7 +726,7 @@ describe('_string.repeat', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.repeat must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.repeat\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.repeat\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -736,7 +736,7 @@ describe('_string.repeat', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.repeat accepts one of the following types: array, object.
|
||||
Received: {\\"_string.repeat\\":null} at locationId."
|
||||
Received: {\\"_string.repeat\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -775,7 +775,7 @@ describe('_string.replace', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.replace must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.replace\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.replace\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -785,7 +785,7 @@ describe('_string.replace', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.replace must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.replace\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.replace\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -795,7 +795,7 @@ describe('_string.replace', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.replace accepts one of the following types: array, object.
|
||||
Received: {\\"_string.replace\\":null} at locationId."
|
||||
Received: {\\"_string.replace\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -841,7 +841,7 @@ describe('_string.search', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.search must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.search\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.search\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -851,7 +851,7 @@ describe('_string.search', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.search must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.search\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.search\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -861,7 +861,7 @@ describe('_string.search', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.search accepts one of the following types: array, object.
|
||||
Received: {\\"_string.search\\":null} at locationId."
|
||||
Received: {\\"_string.search\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -907,7 +907,7 @@ describe('_string.slice', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.slice must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.slice\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.slice\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -917,7 +917,7 @@ describe('_string.slice', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.slice must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.slice\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.slice\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -927,7 +927,7 @@ describe('_string.slice', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.slice accepts one of the following types: array, object.
|
||||
Received: {\\"_string.slice\\":null} at locationId."
|
||||
Received: {\\"_string.slice\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -966,7 +966,7 @@ describe('_string.split', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.split must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.split\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.split\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -976,7 +976,7 @@ describe('_string.split', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.split must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.split\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.split\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -986,7 +986,7 @@ describe('_string.split', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.split accepts one of the following types: array, object.
|
||||
Received: {\\"_string.split\\":null} at locationId."
|
||||
Received: {\\"_string.split\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1032,7 +1032,7 @@ describe('_string.startsWith', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.startsWith must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.startsWith\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.startsWith\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1042,7 +1042,7 @@ describe('_string.startsWith', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.startsWith must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.startsWith\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.startsWith\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1052,7 +1052,7 @@ describe('_string.startsWith', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.startsWith accepts one of the following types: array, object.
|
||||
Received: {\\"_string.startsWith\\":null} at locationId."
|
||||
Received: {\\"_string.startsWith\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1098,7 +1098,7 @@ describe('_string.substring', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.substring must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.substring\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.substring\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1108,7 +1108,7 @@ describe('_string.substring', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.substring must be evaluated on an string instance. For named args provide an string instance to the \\"on\\" property, for listed args provide and string instance as the first element in the operator argument array.
|
||||
Received: {\\"_string.substring\\":{\\"on\\":true}} at locationId."
|
||||
Received: {\\"_string.substring\\":{\\"on\\":true}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1118,7 +1118,7 @@ describe('_string.substring', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.substring accepts one of the following types: array, object.
|
||||
Received: {\\"_string.substring\\":null} at locationId."
|
||||
Received: {\\"_string.substring\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1143,7 +1143,7 @@ describe('_string.toLowerCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toLowerCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toLowerCase\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.toLowerCase\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1153,7 +1153,7 @@ describe('_string.toLowerCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toLowerCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toLowerCase\\":[\\"abc\\"]} at locationId."
|
||||
Received: {\\"_string.toLowerCase\\":[\\"abc\\"]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1163,7 +1163,7 @@ describe('_string.toLowerCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toLowerCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toLowerCase\\":{\\"on\\":\\"abc\\"}} at locationId."
|
||||
Received: {\\"_string.toLowerCase\\":{\\"on\\":\\"abc\\"}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1173,7 +1173,7 @@ describe('_string.toLowerCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toLowerCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toLowerCase\\":null} at locationId."
|
||||
Received: {\\"_string.toLowerCase\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1198,7 +1198,7 @@ describe('_string.toUpperCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toUpperCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toUpperCase\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.toUpperCase\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1208,7 +1208,7 @@ describe('_string.toUpperCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toUpperCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toUpperCase\\":[\\"abc\\"]} at locationId."
|
||||
Received: {\\"_string.toUpperCase\\":[\\"abc\\"]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1218,7 +1218,7 @@ describe('_string.toUpperCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toUpperCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toUpperCase\\":{\\"on\\":\\"abc\\"}} at locationId."
|
||||
Received: {\\"_string.toUpperCase\\":{\\"on\\":\\"abc\\"}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1228,7 +1228,7 @@ describe('_string.toUpperCase', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.toUpperCase accepts one of the following types: string.
|
||||
Received: {\\"_string.toUpperCase\\":null} at locationId."
|
||||
Received: {\\"_string.toUpperCase\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1253,7 +1253,7 @@ describe('_string.trim', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trim accepts one of the following types: string.
|
||||
Received: {\\"_string.trim\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.trim\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1263,7 +1263,7 @@ describe('_string.trim', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trim accepts one of the following types: string.
|
||||
Received: {\\"_string.trim\\":[\\"abc\\"]} at locationId."
|
||||
Received: {\\"_string.trim\\":[\\"abc\\"]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1273,7 +1273,7 @@ describe('_string.trim', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trim accepts one of the following types: string.
|
||||
Received: {\\"_string.trim\\":{\\"on\\":\\"abc\\"}} at locationId."
|
||||
Received: {\\"_string.trim\\":{\\"on\\":\\"abc\\"}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1283,7 +1283,7 @@ describe('_string.trim', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trim accepts one of the following types: string.
|
||||
Received: {\\"_string.trim\\":null} at locationId."
|
||||
Received: {\\"_string.trim\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1308,7 +1308,7 @@ describe('_string.trimEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimEnd accepts one of the following types: string.
|
||||
Received: {\\"_string.trimEnd\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.trimEnd\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1318,7 +1318,7 @@ describe('_string.trimEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimEnd accepts one of the following types: string.
|
||||
Received: {\\"_string.trimEnd\\":[\\"abc\\"]} at locationId."
|
||||
Received: {\\"_string.trimEnd\\":[\\"abc\\"]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1328,7 +1328,7 @@ describe('_string.trimEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimEnd accepts one of the following types: string.
|
||||
Received: {\\"_string.trimEnd\\":{\\"on\\":\\"abc\\"}} at locationId."
|
||||
Received: {\\"_string.trimEnd\\":{\\"on\\":\\"abc\\"}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1338,7 +1338,7 @@ describe('_string.trimEnd', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimEnd accepts one of the following types: string.
|
||||
Received: {\\"_string.trimEnd\\":null} at locationId."
|
||||
Received: {\\"_string.trimEnd\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1363,7 +1363,7 @@ describe('_string.trimStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimStart accepts one of the following types: string.
|
||||
Received: {\\"_string.trimStart\\":[1,2]} at locationId."
|
||||
Received: {\\"_string.trimStart\\":[1,2]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1373,7 +1373,7 @@ describe('_string.trimStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimStart accepts one of the following types: string.
|
||||
Received: {\\"_string.trimStart\\":[\\"abc\\"]} at locationId."
|
||||
Received: {\\"_string.trimStart\\":[\\"abc\\"]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1383,7 +1383,7 @@ describe('_string.trimStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimStart accepts one of the following types: string.
|
||||
Received: {\\"_string.trimStart\\":{\\"on\\":\\"abc\\"}} at locationId."
|
||||
Received: {\\"_string.trimStart\\":{\\"on\\":\\"abc\\"}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1393,7 +1393,7 @@ describe('_string.trimStart', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.trimStart accepts one of the following types: string.
|
||||
Received: {\\"_string.trimStart\\":null} at locationId."
|
||||
Received: {\\"_string.trimStart\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
@ -1418,7 +1418,7 @@ describe('_string.length', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.length accepts one of the following types: string.
|
||||
Received: {\\"_string.length\\":{\\"on\\":\\"231\\"}} at locationId."
|
||||
Received: {\\"_string.length\\":{\\"on\\":\\"231\\"}} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1428,7 +1428,7 @@ describe('_string.length', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.length accepts one of the following types: string.
|
||||
Received: {\\"_string.length\\":[\\"1\\"]} at locationId."
|
||||
Received: {\\"_string.length\\":[\\"1\\"]} at location."
|
||||
`);
|
||||
expect(() =>
|
||||
string({
|
||||
@ -1438,22 +1438,22 @@ describe('_string.length', () => {
|
||||
})
|
||||
).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.length accepts one of the following types: string.
|
||||
Received: {\\"_string.length\\":null} at locationId."
|
||||
Received: {\\"_string.length\\":null} at location."
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
test('_string called with no method or params', () => {
|
||||
expect(() => string({ location: 'locationId' })).toThrowErrorMatchingInlineSnapshot(`
|
||||
expect(() => string({ location: 'location' })).toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.undefined is not supported, use one of the following: charAt, concat, endsWith, includes, indexOf, lastIndexOf, match, normalize, padEnd, padStart, repeat, replace, search, slice, split, startsWith, substring, toLowerCase, toUpperCase, trim, trimEnd, trimStart, length.
|
||||
Received: {\\"_string.undefined\\":undefined} at locationId."
|
||||
Received: {\\"_string.undefined\\":undefined} at location."
|
||||
`);
|
||||
});
|
||||
|
||||
test('_string invalid method', () => {
|
||||
expect(() => string({ params: ['a'], methodName: 'X', location: 'locationId' }))
|
||||
expect(() => string({ params: ['a'], methodName: 'X', location: 'location' }))
|
||||
.toThrowErrorMatchingInlineSnapshot(`
|
||||
"Operator Error: _string.X is not supported, use one of the following: charAt, concat, endsWith, includes, indexOf, lastIndexOf, match, normalize, padEnd, padStart, repeat, replace, search, slice, split, startsWith, substring, toLowerCase, toUpperCase, trim, trimEnd, trimStart, length.
|
||||
Received: {\\"_string.X\\":[\\"a\\"]} at locationId."
|
||||
Received: {\\"_string.X\\":[\\"a\\"]} at location."
|
||||
`);
|
||||
});
|
||||
|
@ -15,6 +15,15 @@
|
||||
*/
|
||||
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import _type from './type.js';
|
||||
import _date from './date.js';
|
||||
|
||||
const operators = {
|
||||
_date,
|
||||
_type,
|
||||
};
|
||||
|
||||
const location = 'location';
|
||||
|
||||
const state = {
|
||||
string: 'Some String',
|
||||
@ -25,136 +34,79 @@ const state = {
|
||||
|
||||
console.error = () => {};
|
||||
|
||||
test('_type with on, pass', async () => {
|
||||
const input = { _type: { type: 'string', on: 'a' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_type with on, pass', () => {
|
||||
expect(_type({ params: { type: 'string', on: 'a' }, location })).toEqual(true);
|
||||
});
|
||||
test('_type with on, fail', () => {
|
||||
expect(_type({ params: { type: 'number', on: 'a' }, location })).toEqual(false);
|
||||
});
|
||||
test('_type with key, pass', () => {
|
||||
expect(_type({ params: { type: 'string', key: 'string' }, location, state })).toEqual(true);
|
||||
});
|
||||
test('_type with key, fail', () => {
|
||||
expect(_type({ params: { type: 'string', key: 'number' }, location, state })).toEqual(false);
|
||||
});
|
||||
test('_type with null on, pass', () => {
|
||||
expect(_type({ params: { type: 'null', on: null }, location })).toEqual(true);
|
||||
});
|
||||
test('_type with null on, fail', () => {
|
||||
expect(_type({ params: { type: 'boolean', on: null }, location })).toEqual(false);
|
||||
});
|
||||
test('_type with nonexistent key', () => {
|
||||
expect(_type({ params: { type: 'boolean', key: 'notThere' }, location, state })).toEqual(false);
|
||||
});
|
||||
test('_type with null key', () => {
|
||||
expect(_type({ params: { type: 'boolean', key: null }, location, state })).toEqual(false);
|
||||
});
|
||||
test('_type null', () => {
|
||||
expect(() => _type({ params: null, location })).toThrow(
|
||||
'Operator Error: _type.type must be a string. Received: null at location.'
|
||||
);
|
||||
});
|
||||
test('_type with non-string on', () => {
|
||||
expect(_type({ params: { type: 'number', on: 5 }, location })).toEqual(true);
|
||||
});
|
||||
test('_type with unknown type', () => {
|
||||
expect(() => _type({ params: { type: 'strings' }, location })).toThrow(
|
||||
'Operator Error: "strings" is not a valid _type test. Received: {"type":"strings"} at location.'
|
||||
);
|
||||
});
|
||||
test('_type date on string date fail', () => {
|
||||
expect(_type({ params: { type: 'date', on: '2019-11-28T08:10:09.844Z' }, location })).toEqual(
|
||||
false
|
||||
);
|
||||
});
|
||||
test('_type date on date object pass', () => {
|
||||
expect(_type({ params: { type: 'date', on: new Date() }, location })).toEqual(true);
|
||||
});
|
||||
|
||||
test('_type with on, fail', async () => {
|
||||
const input = { _type: { type: 'number', on: 'b' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
test('_type array', () => {
|
||||
expect(_type({ params: { type: 'array', key: 'arr' }, location, state })).toEqual(true);
|
||||
});
|
||||
test('_type object', () => {
|
||||
expect(_type({ params: { type: 'object', on: { key: 'value' } }, location, state })).toEqual(
|
||||
true
|
||||
);
|
||||
});
|
||||
test('_type primitive', () => {
|
||||
expect(_type({ params: { type: 'primitive', on: 'Primitive string' }, location, state })).toEqual(
|
||||
true
|
||||
);
|
||||
});
|
||||
test('_type integer', () => {
|
||||
expect(_type({ params: { type: 'integer', on: 42 }, location, state })).toEqual(true);
|
||||
});
|
||||
test('_type undefined', () => {
|
||||
expect(_type({ params: { type: 'undefined', on: undefined }, location, state })).toEqual(true);
|
||||
});
|
||||
test('_type none', () => {
|
||||
expect(_type({ params: { type: 'none' }, location, state })).toEqual(true);
|
||||
});
|
||||
|
||||
// NOTE: key not supported by NodeParser
|
||||
// test('_type with key, pass', async () => {
|
||||
// const input = { _type: { type: 'string', key: 'string' } };
|
||||
// const parser = new NodeParser({ state });
|
||||
// await parser.init();
|
||||
// const res = parser.parse({ input, location: 'locationId' });
|
||||
// expect(res.output).toBe(true);
|
||||
// expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
// });
|
||||
|
||||
// test('_type with key, fail', async () => {
|
||||
// const input = { _type: { type: 'number', key: 'string' } };
|
||||
// const parser = new NodeParser({ state });
|
||||
// await parser.init();
|
||||
// const res = parser.parse({ input, location: 'locationId' });
|
||||
// expect(res.output).toBe(false);
|
||||
// expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
// });
|
||||
|
||||
test('_type with null on pass', async () => {
|
||||
const input = { _type: { type: 'null', on: null } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
test('_type with null on fail', async () => {
|
||||
const input = { _type: { type: 'boolean', on: null } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_type with nonexistent key', async () => {
|
||||
const input = { _type: { type: 'string', key: 'notThere' } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_type with nonexistent key', async () => {
|
||||
const input = { _type: { type: 'string', key: null } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_type null', async () => {
|
||||
const input = { _type: null };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: _type.type must be a string. Received: null at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_type with non-string on', async () => {
|
||||
const input = { _type: { type: 'number', on: 5 } };
|
||||
const parser = new NodeParser({ state });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_type with unknown type', async () => {
|
||||
const input = { _type: 'strings' };
|
||||
const parser = new NodeParser({ state, arrayIndices: [] });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
expect(res.errors).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
[Error: Operator Error: "strings" is not a valid _type test. Received: "strings" at locationId.],
|
||||
]
|
||||
`);
|
||||
});
|
||||
|
||||
test('_type date with on packed date pass', async () => {
|
||||
test('_type date with on packed date pass and calls NodeParser', async () => {
|
||||
const input = { _type: { type: 'date', on: { _date: Date.now() } } };
|
||||
const parser = new NodeParser({ state, arrayIndices: [] });
|
||||
const parser = new NodeParser({ operators, payload: {}, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, id: '1', location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_type date on string date fail', async () => {
|
||||
const input = { _type: { type: 'date', on: '2019-11-28T08:10:09.844Z' } };
|
||||
const parser = new NodeParser({ state, arrayIndices: [] });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, id: '1', location: 'locationId' });
|
||||
expect(res.output).toBe(false);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
});
|
||||
|
||||
test('_type date on date object pass', async () => {
|
||||
const input = { _type: { type: 'date', on: new Date() } };
|
||||
const parser = new NodeParser({ state, arrayIndices: [] });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, id: '1', location: 'locationId' });
|
||||
expect(res.output).toBe(true);
|
||||
expect(res.errors).toMatchInlineSnapshot(`Array []`);
|
||||
const res = parser.parse({ input, location });
|
||||
expect(res.output).toEqual(true);
|
||||
});
|
||||
|
@ -15,7 +15,9 @@
|
||||
*/
|
||||
|
||||
import user from './user.js';
|
||||
jest.mock('@lowdefy/operators');
|
||||
jest.mock('@lowdefy/operators', () => ({
|
||||
getFromObject: jest.fn(),
|
||||
}));
|
||||
|
||||
const input = {
|
||||
arrayIndices: [0],
|
||||
@ -24,9 +26,14 @@ const input = {
|
||||
user: { name: 'first name' },
|
||||
};
|
||||
|
||||
test('user calls getFromObject', () => {
|
||||
const lowdefyOperators = import('@lowdefy/operators');
|
||||
user(input);
|
||||
test('user calls getFromObject', async () => {
|
||||
const lowdefyOperators = await import('@lowdefy/operators');
|
||||
user({
|
||||
arrayIndices: [0],
|
||||
location: 'location',
|
||||
params: 'params',
|
||||
user: { name: 'first name' },
|
||||
});
|
||||
expect(lowdefyOperators.getFromObject.mock.calls).toEqual([
|
||||
[
|
||||
{
|
||||
|
@ -14,24 +14,11 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { NodeParser, WebParser } from '@lowdefy/operators';
|
||||
import { NodeParser } from '@lowdefy/operators';
|
||||
import _nunjucks from './nunjucks.js';
|
||||
|
||||
const arrayIndices = [1];
|
||||
|
||||
const context = {
|
||||
_internal: {
|
||||
lowdefy: {
|
||||
inputs: { id: true },
|
||||
lowdefyGlobal: { global: true },
|
||||
menus: [{ menus: true }],
|
||||
urlQuery: { urlQuery: true },
|
||||
user: { user: true },
|
||||
},
|
||||
},
|
||||
eventLog: [{ eventLog: true }],
|
||||
id: 'id',
|
||||
requests: [{ requests: true }],
|
||||
state: { state: true },
|
||||
const operators = {
|
||||
_nunjucks,
|
||||
};
|
||||
|
||||
const payload = {
|
||||
@ -44,7 +31,7 @@ console.error = () => {};
|
||||
|
||||
test('_nunjucks string template', async () => {
|
||||
const input = { _nunjucks: 'String with {{ string }} embedded' };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual('String with Some String embedded');
|
||||
@ -53,7 +40,7 @@ test('_nunjucks string template', async () => {
|
||||
|
||||
test('_nunjucks null', async () => {
|
||||
const input = { _nunjucks: null };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
@ -64,7 +51,7 @@ test('_nunjucks { template: , on: }', async () => {
|
||||
const input = {
|
||||
_nunjucks: { template: 'String with {{ string }} embedded', on: { string: 'test' } },
|
||||
};
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toEqual('String with test embedded');
|
||||
@ -73,7 +60,7 @@ test('_nunjucks { template: , on: }', async () => {
|
||||
|
||||
test('_nunjucks template not a string', async () => {
|
||||
const input = { _nunjucks: ['String with {{ string }} embedded'] };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
@ -84,7 +71,7 @@ test('_nunjucks params on template not a string', async () => {
|
||||
const input = {
|
||||
_nunjucks: { template: ['String with {{ string }} embedded'], on: { string: 'test' } },
|
||||
};
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
@ -95,7 +82,7 @@ test('_nunjucks on not a object', async () => {
|
||||
const input = {
|
||||
_nunjucks: { template: 'String with {{ string }} embedded', on: [{ string: 'test' }] },
|
||||
};
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe('String with embedded');
|
||||
@ -106,7 +93,7 @@ test('_nunjucks on null', async () => {
|
||||
const input = {
|
||||
_nunjucks: { template: 'String with {{ string }} embedded', on: null },
|
||||
};
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe('String with embedded');
|
||||
@ -115,7 +102,7 @@ test('_nunjucks on null', async () => {
|
||||
|
||||
test('_nunjucks invalid template', async () => {
|
||||
const input = { _nunjucks: 'String with {{ string embedded' };
|
||||
const parser = new NodeParser({ payload });
|
||||
const parser = new NodeParser({ operators, payload, secrets: {}, user: {} });
|
||||
await parser.init();
|
||||
const res = parser.parse({ input, location: 'locationId' });
|
||||
expect(res.output).toBe(null);
|
||||
|
@ -7,6 +7,7 @@ module.exports = withLess({
|
||||
modifyVars: lowdefyConfig.theme.lessVariables,
|
||||
},
|
||||
},
|
||||
basePath: process.env.LOWDEFY_BASE_PATH || lowdefyConfig.basePath,
|
||||
// reactStrictMode: true,
|
||||
webpack: (config, { isServer }) => {
|
||||
if (!isServer) {
|
||||
|
@ -70,7 +70,7 @@
|
||||
"react": "18.0.0-rc.0",
|
||||
"react-dom": "18.0.0-rc.0",
|
||||
"react-icons": "4.3.1",
|
||||
"swr": "1.2.0",
|
||||
"swr": "1.1.2",
|
||||
"yargs": "17.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
@ -1,7 +1,9 @@
|
||||
const withLess = require('next-with-less');
|
||||
const lowdefyConfig = require('./build/config.json');
|
||||
|
||||
// TODO: Trance env and args from cli that is required on the server.
|
||||
module.exports = withLess({
|
||||
basePath: process.env.LOWDEFY_BASE_PATH || lowdefyConfig.basePath,
|
||||
lessLoaderOptions: {
|
||||
lessOptions: {
|
||||
modifyVars: lowdefyConfig.theme.lessVariables,
|
||||
|
@ -20,15 +20,14 @@ 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';
|
||||
import components from './components.js';
|
||||
|
||||
const LowdefyContext = ({ children }) => {
|
||||
const lowdefy = {
|
||||
_internal: {
|
||||
const LowdefyContext = ({ children, lowdefy }) => {
|
||||
if (!lowdefy._internal) {
|
||||
lowdefy._internal = {
|
||||
actions,
|
||||
blockComponents,
|
||||
callRequest,
|
||||
components,
|
||||
components: {},
|
||||
document,
|
||||
operators,
|
||||
updaters: {},
|
||||
@ -38,14 +37,14 @@ const LowdefyContext = ({ children }) => {
|
||||
return () => undefined;
|
||||
},
|
||||
link: () => undefined,
|
||||
},
|
||||
contexts: {},
|
||||
inputs: {},
|
||||
lowdefyGlobal: {},
|
||||
};
|
||||
};
|
||||
lowdefy.contexts = {};
|
||||
lowdefy.inputs = {};
|
||||
lowdefy.lowdefyGlobal = {};
|
||||
}
|
||||
lowdefy._internal.updateBlock = (blockId) =>
|
||||
lowdefy._internal.updaters[blockId] && lowdefy._internal.updaters[blockId]();
|
||||
return <>{children(lowdefy)}</>;
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export default LowdefyContext;
|
||||
|
@ -16,25 +16,29 @@
|
||||
|
||||
import React from 'react';
|
||||
|
||||
import { urlQuery } from '@lowdefy/helpers';
|
||||
import { useRouter } from 'next/router';
|
||||
|
||||
import Context from './Context.js';
|
||||
import Head from './Head.js';
|
||||
import Block from './block/Block.js';
|
||||
import setupLink from '../utils/setupLink.js';
|
||||
import createComponents from './createComponents.js';
|
||||
|
||||
const LoadingBlock = () => <div>Loading...</div>;
|
||||
|
||||
const Page = ({ lowdefy, pageConfig, rootConfig }) => {
|
||||
const router = useRouter();
|
||||
lowdefy._internal.basePath = router.basePath;
|
||||
lowdefy._internal.pathname = router.pathname;
|
||||
lowdefy._internal.query = router.query;
|
||||
lowdefy._internal.router = router;
|
||||
lowdefy._internal.link = setupLink({ lowdefy });
|
||||
lowdefy._internal.link = setupLink(lowdefy);
|
||||
lowdefy._internal.components = createComponents(lowdefy);
|
||||
|
||||
lowdefy.basePath = lowdefy._internal.router.basePath;
|
||||
lowdefy.home = rootConfig.home;
|
||||
lowdefy.lowdefyGlobal = rootConfig.lowdefyGlobal;
|
||||
lowdefy.menus = rootConfig.menus;
|
||||
lowdefy.urlQuery = urlQuery.parse(window.location.search.slice(1));
|
||||
|
||||
return (
|
||||
<Context config={pageConfig} lowdefy={lowdefy}>
|
||||
{(context, loading) => {
|
||||
|
@ -64,12 +64,10 @@ const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
setValue: block.setValue,
|
||||
triggerEvent: block.triggerEvent,
|
||||
})}
|
||||
// TODO: React throws a basePath warning
|
||||
basePath={lowdefy._internal.basePath}
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={block.blockId}
|
||||
components={lowdefy._internal.components}
|
||||
events={block.eval.events}
|
||||
homePageId={lowdefy.home.pageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={lowdefy.menus}
|
||||
@ -98,11 +96,10 @@ const CategorySwitch = ({ block, Blocks, context, lowdefy }) => {
|
||||
registerMethod: block.registerMethod,
|
||||
triggerEvent: block.triggerEvent,
|
||||
})}
|
||||
basePath={lowdefy._internal.basePath}
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={block.blockId}
|
||||
components={lowdefy._internal.components}
|
||||
events={block.eval.events}
|
||||
homePageId={lowdefy.home.pageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={lowdefy.menus}
|
||||
|
@ -65,12 +65,11 @@ const Container = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
registerMethod: block.registerMethod,
|
||||
triggerEvent: block.triggerEvent,
|
||||
})}
|
||||
basePath={lowdefy._internal.basePath}
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={block.blockId}
|
||||
components={lowdefy._internal.components}
|
||||
content={content}
|
||||
events={block.eval.events}
|
||||
homePageId={lowdefy.home.pageId}
|
||||
key={block.blockId}
|
||||
loading={block.loading}
|
||||
menus={lowdefy.menus}
|
||||
|
@ -72,11 +72,10 @@ const List = ({ block, Blocks, Component, context, lowdefy }) => {
|
||||
triggerEvent: block.triggerEvent,
|
||||
unshiftItem: block.unshiftItem,
|
||||
})}
|
||||
basePath={lowdefy._internal.basePath}
|
||||
basePath={lowdefy.basePath}
|
||||
blockId={block.blockId}
|
||||
components={lowdefy._internal.components}
|
||||
events={block.eval.events}
|
||||
homePageId={lowdefy.home.pageId}
|
||||
key={block.blockId}
|
||||
list={contentList}
|
||||
loading={block.loading}
|
||||
|
@ -14,12 +14,16 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import Link from 'next/link';
|
||||
import { createIcon } from '@lowdefy/block-utils';
|
||||
|
||||
import createLinkComponent from './createLinkComponent.js';
|
||||
import icons from '../../build/plugins/icons.js';
|
||||
|
||||
export default {
|
||||
Link,
|
||||
Icon: createIcon(icons),
|
||||
const createComponents = (lowdefy) => {
|
||||
return {
|
||||
Link: createLinkComponent(lowdefy),
|
||||
Icon: createIcon(icons),
|
||||
};
|
||||
};
|
||||
|
||||
export default createComponents;
|
92
packages/server/src/components/createLinkComponent.js
Normal file
92
packages/server/src/components/createLinkComponent.js
Normal file
@ -0,0 +1,92 @@
|
||||
import React from 'react';
|
||||
import NextLink from 'next/link';
|
||||
import { createLink } from '@lowdefy/engine';
|
||||
import { type } from '@lowdefy/helpers';
|
||||
|
||||
const createLinkComponent = (lowdefy) => {
|
||||
const backLink = ({ ariaLabel, children, className, id, rel }) => (
|
||||
<a
|
||||
id={id}
|
||||
onClick={() => lowdefy._internal.router.back()}
|
||||
className={className}
|
||||
rel={rel}
|
||||
aria-label={ariaLabel || 'back'}
|
||||
>
|
||||
{type.isFunction(children) ? children(id) : children}
|
||||
</a>
|
||||
);
|
||||
const newOriginLink = ({
|
||||
ariaLabel,
|
||||
children,
|
||||
className,
|
||||
href,
|
||||
id,
|
||||
newTab,
|
||||
pageId,
|
||||
rel,
|
||||
url,
|
||||
}) => {
|
||||
return (
|
||||
<a
|
||||
id={id}
|
||||
aria-label={ariaLabel}
|
||||
className={className}
|
||||
href={href}
|
||||
rel={rel || (newTab && 'noopener noreferrer')}
|
||||
target={newTab && '_blank'}
|
||||
>
|
||||
{type.isFunction(children) ? children(pageId || url || id) : children}
|
||||
</a>
|
||||
);
|
||||
};
|
||||
const sameOriginLink = ({
|
||||
ariaLabel,
|
||||
children,
|
||||
className,
|
||||
href,
|
||||
id,
|
||||
newTab,
|
||||
pageId,
|
||||
rel,
|
||||
replace,
|
||||
scroll,
|
||||
url,
|
||||
}) => {
|
||||
if (newTab) {
|
||||
return (
|
||||
<a
|
||||
id={id}
|
||||
aria-label={ariaLabel}
|
||||
className={className}
|
||||
href={`${window.location.origin}${lowdefy.basePath}${href}`}
|
||||
rel={rel || 'noopener noreferrer'}
|
||||
target="_blank"
|
||||
>
|
||||
{type.isFunction(children) ? children(pageId || url || id) : children}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<NextLink href={href} replace={replace} scroll={scroll}>
|
||||
<a id={id} aria-label={ariaLabel} className={className} rel={rel}>
|
||||
{type.isFunction(children) ? children(pageId || url || id) : children}
|
||||
</a>
|
||||
</NextLink>
|
||||
);
|
||||
};
|
||||
const noLink = ({ className, children, id }) => (
|
||||
<span id={id} className={className}>
|
||||
{type.isFunction(children) ? children(id) : children}
|
||||
</span>
|
||||
);
|
||||
return createLink({
|
||||
backLink,
|
||||
lowdefy,
|
||||
newOriginLink,
|
||||
sameOriginLink,
|
||||
noLink,
|
||||
disabledLink: noLink,
|
||||
});
|
||||
};
|
||||
|
||||
export default createLinkComponent;
|
@ -22,12 +22,14 @@ import LowdefyContext from '../components/LowdefyContext.js';
|
||||
|
||||
import '../../build/plugins/styles.less';
|
||||
|
||||
const lowdefy = {};
|
||||
|
||||
function App({ Component, pageProps }) {
|
||||
return (
|
||||
<ErrorBoundary>
|
||||
<Suspense>
|
||||
<LowdefyContext>
|
||||
{(lowdefy) => <Component lowdefy={lowdefy} {...pageProps} />}
|
||||
<LowdefyContext lowdefy={lowdefy}>
|
||||
<Component lowdefy={lowdefy} {...pageProps} />
|
||||
</LowdefyContext>
|
||||
</Suspense>
|
||||
</ErrorBoundary>
|
||||
|
@ -19,6 +19,7 @@ import { createApiContext, getPageConfig, getRootConfig } from '@lowdefy/api';
|
||||
import Page from '../components/Page.js';
|
||||
|
||||
export async function getServerSideProps() {
|
||||
// TODO: is this build directory configurable from the cli?
|
||||
const apiContext = await createApiContext({ buildDirectory: './build' });
|
||||
const rootConfig = await getRootConfig(apiContext);
|
||||
const { home } = rootConfig;
|
||||
|
@ -16,29 +16,30 @@
|
||||
|
||||
import { createLink } from '@lowdefy/engine';
|
||||
|
||||
function setupLink({ lowdefy }) {
|
||||
function setupLink(lowdefy) {
|
||||
const { router, window } = lowdefy._internal;
|
||||
const sameOriginLink = (path, newTab) => {
|
||||
const backLink = () => router.back();
|
||||
const disabledLink = () => {};
|
||||
const newOriginLink = ({ href, newTab }) => {
|
||||
if (newTab) {
|
||||
return window.open(`${window.location.origin}${lowdefy.basePath}${path}`, '_blank').focus();
|
||||
return window.open(href, '_blank').focus();
|
||||
} else {
|
||||
return window.location.assign(href);
|
||||
}
|
||||
};
|
||||
const sameOriginLink = ({ href, newTab }) => {
|
||||
if (newTab) {
|
||||
return window.open(`${window.location.origin}${lowdefy.basePath}${href}`, '_blank').focus();
|
||||
} else {
|
||||
// Next handles the basePath here.
|
||||
return router.push({
|
||||
pathname: path,
|
||||
// TODO: Do we handle urlQuery as a param here?
|
||||
// query: {},
|
||||
pathname: href, // href includes the urlQuery as defined by engine
|
||||
});
|
||||
}
|
||||
};
|
||||
const newOriginLink = (path, newTab) => {
|
||||
if (newTab) {
|
||||
return window.open(path, '_blank').focus();
|
||||
} else {
|
||||
return (window.location.href = path);
|
||||
}
|
||||
const noLink = () => {
|
||||
throw new Error(`Invalid Link.`);
|
||||
};
|
||||
const backLink = () => window.history.back();
|
||||
return createLink({ backLink, lowdefy, newOriginLink, sameOriginLink });
|
||||
return createLink({ backLink, disabledLink, lowdefy, newOriginLink, noLink, sameOriginLink });
|
||||
}
|
||||
|
||||
export default setupLink;
|
||||
|
@ -30,7 +30,6 @@ const lowdefyProps = [
|
||||
'components',
|
||||
'content',
|
||||
'eventLog',
|
||||
'homePageId',
|
||||
'list',
|
||||
'loading',
|
||||
'menus',
|
||||
|
@ -14,10 +14,10 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
function cachedPromises(getter) {
|
||||
function createCachedPromises(getter) {
|
||||
const cache = new Map();
|
||||
|
||||
function getCachedPromise(key) {
|
||||
function cachedPromises(key) {
|
||||
if (cache.has(key)) {
|
||||
return Promise.resolve(cache.get(key));
|
||||
}
|
||||
@ -26,7 +26,7 @@ function cachedPromises(getter) {
|
||||
return Promise.resolve(promise);
|
||||
}
|
||||
|
||||
return getCachedPromise;
|
||||
return cachedPromises;
|
||||
}
|
||||
|
||||
export default cachedPromises;
|
||||
export default createCachedPromises;
|
||||
|
52
packages/utils/helpers/src/cachedPromises.test.js
Normal file
52
packages/utils/helpers/src/cachedPromises.test.js
Normal file
@ -0,0 +1,52 @@
|
||||
/*
|
||||
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 createCachedPromises from './cachedPromises.js';
|
||||
import wait from './wait.js';
|
||||
|
||||
test('cachedPromises calls getter with key', async () => {
|
||||
const getter = jest.fn(() => Promise.resolve('value'));
|
||||
const cachedGetter = createCachedPromises(getter);
|
||||
const promise = cachedGetter('key');
|
||||
expect(`${promise}`).toEqual('[object Promise]');
|
||||
const result = await promise;
|
||||
expect(result).toEqual('value');
|
||||
expect(getter.mock.calls).toEqual([['key']]);
|
||||
});
|
||||
|
||||
test('cachedPromises only calls getter once', async () => {
|
||||
const getter = jest.fn(() => Promise.resolve('value'));
|
||||
const cachedGetter = createCachedPromises(getter);
|
||||
const result1 = await cachedGetter('key');
|
||||
expect(result1).toEqual('value');
|
||||
const result2 = await cachedGetter('key');
|
||||
expect(result2).toEqual('value');
|
||||
expect(getter.mock.calls).toEqual([['key']]);
|
||||
});
|
||||
|
||||
test('getter is called once if first call has not yet resolved', async () => {
|
||||
const getter = jest.fn(async () => {
|
||||
await wait(10);
|
||||
return 'value';
|
||||
});
|
||||
const cachedGetter = createCachedPromises(getter);
|
||||
const promise1 = cachedGetter('key');
|
||||
const promise2 = cachedGetter('key');
|
||||
expect(getter.mock.calls).toEqual([['key']]);
|
||||
await promise1;
|
||||
await promise2;
|
||||
expect(getter.mock.calls).toEqual([['key']]);
|
||||
});
|
@ -20,7 +20,7 @@ function getConfigFromEnv() {
|
||||
logLevel: process.env.LOWDEFY_SERVER_LOG_LEVEL,
|
||||
publicDirectory: process.env.LOWDEFY_SERVER_PUBLIC_DIRECTORY,
|
||||
port: process.env.LOWDEFY_SERVER_PORT && parseInt(process.env.LOWDEFY_SERVER_PORT),
|
||||
serverBasePath: process.env.LOWDEFY_SERVER_BASE_PATH,
|
||||
basePath: process.env.LOWDEFY_BASE_PATH,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ test('Get config from env', () => {
|
||||
buildDirectory: 'build',
|
||||
publicDirectory: 'public',
|
||||
port: 8080,
|
||||
serverBasePath: 'base',
|
||||
basePath: 'base',
|
||||
});
|
||||
});
|
||||
|
||||
|
12
yarn.lock
12
yarn.lock
@ -2362,6 +2362,8 @@ __metadata:
|
||||
version: 0.0.0-use.local
|
||||
resolution: "@lowdefy/docs@workspace:packages/docs"
|
||||
dependencies:
|
||||
"@swc/core": 1.2.135
|
||||
"@swc/jest": 0.2.17
|
||||
jest: 27.4.7
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@ -2635,7 +2637,7 @@ __metadata:
|
||||
react: 18.0.0-rc.0
|
||||
react-dom: 18.0.0-rc.0
|
||||
react-icons: 4.3.1
|
||||
swr: 1.2.0
|
||||
swr: 1.1.2
|
||||
yargs: 17.3.1
|
||||
languageName: unknown
|
||||
linkType: soft
|
||||
@ -14607,12 +14609,12 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"swr@npm:1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "swr@npm:1.2.0"
|
||||
"swr@npm:1.1.2":
|
||||
version: 1.1.2
|
||||
resolution: "swr@npm:1.1.2"
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||
checksum: 9858cbd1849fea5d4d9c63c90b8115ffdc27ddd5500d37f43d6fe58fc57777846fc8e9bf2b12a954b5e8328eac38ecccfa16c5a08afe00a48dfb828516e208f7
|
||||
checksum: 84bf222c667bf4f94bf9bcaf51f11443d69eb6feb82649c06ef8e576c51f52269872dbda4b926f267fd79cfeaf7bd84c6a62d519db25fe2af1fb811e75163e94
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user