Added more componet store unit test converage. Added more fixtures. Refactored some component caching logic causing issus with testing in to the component store

This commit is contained in:
Dean 2024-01-29 15:21:52 +00:00
parent 92d2ad69cc
commit b73156e0c7
7 changed files with 696 additions and 99 deletions

View File

@ -4,7 +4,6 @@ import {
findAllMatchingComponents,
findComponent,
findComponentPath,
getComponentSettings,
} from "stores/builder/components/utils"
import {
currentAsset,
@ -281,7 +280,7 @@ export const getActionProviders = (
* Gets a datasource object for a certain data provider component
*/
export const getDatasourceForProvider = (asset, component) => {
const settings = getComponentSettings(component?._component)
const settings = componentStore.getComponentSettings(component?._component)
// If this component has a dataProvider setting, go up the stack and use it
const dataProviderSetting = settings.find(setting => {
@ -706,7 +705,7 @@ export const getEventContextBindings = ({
const definition =
componentDefinition ?? componentStore.getDefinition(component?._component)
const settings = getComponentSettings(component?._component)
const settings = componentStore.getComponentSettings(component?._component)
const eventSetting = settings.find(setting => setting.key === settingKey)
if (eventSetting?.context?.length) {
@ -1011,7 +1010,7 @@ export const buildFormSchema = (component, asset) => {
}
// Otherwise find all field component children
const settings = getComponentSettings(component._component)
const settings = componentStore.getComponentSettings(component._component)
const fieldSetting = settings.find(
setting => setting.key === "field" && setting.type.startsWith("field/")
)
@ -1037,7 +1036,7 @@ export const getAllStateVariables = () => {
let eventSettings = []
getAllAssets().forEach(asset => {
findAllMatchingComponents(asset.props, component => {
const settings = getComponentSettings(component._component)
const settings = componentStore.getComponentSettings(component._component)
settings
.filter(setting => setting.type === "event")
.forEach(setting => {

View File

@ -13,10 +13,9 @@
import { generate } from "shortid"
import DrawerBindableInput from "components/common/bindings/DrawerBindableInput.svelte"
import { LuceneUtils, Constants } from "@budibase/frontend-core"
import { selectedComponent } from "stores/builder"
import { selectedComponent, componentStore } from "stores/builder"
import { getComponentForSetting } from "components/design/settings/componentSettings"
import PropertyControl from "components/design/settings/controls/PropertyControl.svelte"
import { getComponentSettings } from "stores/builder/components/utils"
export let conditions = []
export let bindings = []
@ -56,11 +55,13 @@
]
let dragDisabled = true
$: settings = getComponentSettings($selectedComponent?._component)?.concat({
label: "Custom CSS",
key: "_css",
type: "text",
})
$: settings = componentStore
.getComponentSettings($selectedComponent?._component)
?.concat({
label: "Custom CSS",
key: "_css",
type: "text",
})
$: settingOptions = settings
.filter(setting => setting.supportsConditions !== false)
.map(setting => ({

View File

@ -5,20 +5,20 @@ import { Helpers } from "@budibase/bbui"
import analytics, { Events } from "analytics"
import { makePropSafe as safe } from "@budibase/string-templates"
import {
getComponentSettings,
findComponentPath,
findClosestMatchingComponent,
findComponent,
findComponentParent,
findAllMatchingComponents,
makeComponentUnique,
} from "../components/utils"
} from "stores/builder/components/utils"
import { getComponentFieldOptions } from "helpers/formFields"
import { selectedScreen } from "../screens"
import { screenStore, appStore, previewStore, tables } from "stores/builder"
import { buildFormSchema, getSchemaForDatasource } from "builder/dataBinding"
import {
BUDIBASE_INTERNAL_DB_ID,
DEFAULT_BB_DATASOURCE_ID,
DB_TYPE_INTERNAL,
DB_TYPE_EXTERNAL,
} from "constants/backend"
@ -26,10 +26,11 @@ import BudiStore from "../BudiStore"
import { Utils } from "@budibase/frontend-core"
export const INITIAL_COMPONENTS_STATE = {
components: [],
components: {},
customComponents: [],
selectedComponentId: null,
componentToPaste: null,
settingsCache: {},
}
export class ComponentStore extends BudiStore {
@ -63,6 +64,9 @@ export class ComponentStore extends BudiStore {
this.updateSetting = this.updateSetting.bind(this)
this.updateComponentSetting = this.updateComponentSetting.bind(this)
this.addParent = this.addParent.bind(this)
this.isCached = this.isCached.bind(this)
this.cacheSettings = this.cacheSettings.bind(this)
this.getComponentSettings = this.getComponentSettings.bind(this)
this.selected = derived(
[this.store, selectedScreen],
@ -112,14 +116,14 @@ export class ComponentStore extends BudiStore {
*/
async refreshDefinitions(appId) {
if (!appId) {
appId = get(this.store).appId
return
}
// Fetch definitions and filter out custom component definitions so we
// can flag them
const components = await API.fetchComponentLibDefinitions(appId)
const customComponents = Object.keys(components).filter(name =>
name.startsWith("plugin/")
const customComponents = Object.keys(components).filter(key =>
key.startsWith("plugin/")
)
// Update store
@ -136,17 +140,17 @@ export class ComponentStore extends BudiStore {
}
/**
*
* @param {string} componentName
* Retrieve the component definition object
* @param {string} componentType
* @example
* '@budibase/standard-components/container'
* @returns {object}
*/
getDefinition(componentName) {
if (!componentName) {
getDefinition(componentType) {
if (!componentType) {
return null
}
return get(this.store).components[componentName]
return get(this.store).components[componentType]
}
/**
@ -160,7 +164,7 @@ export class ComponentStore extends BudiStore {
// Try to use their own internal table first
let table = validTables.find(table => {
return (
table.sourceId !== BUDIBASE_INTERNAL_DB_ID &&
table.sourceId === BUDIBASE_INTERNAL_DB_ID &&
table.sourceType === DB_TYPE_INTERNAL
)
})
@ -171,7 +175,7 @@ export class ComponentStore extends BudiStore {
// Then try sample data
table = validTables.find(table => {
return (
table.sourceId === BUDIBASE_INTERNAL_DB_ID &&
table.sourceId === DEFAULT_BB_DATASOURCE_ID &&
table.sourceType === DB_TYPE_INTERNAL
)
})
@ -231,7 +235,7 @@ export class ComponentStore extends BudiStore {
return
}
const defaultDS = this.getDefaultDatasource()
const settings = getComponentSettings(component._component)
const settings = this.getComponentSettings(component._component)
const { parent, screen, useDefaultValues } = opts || {}
const treeId = parent?._id || component._id
if (!screen) {
@ -933,7 +937,7 @@ export class ComponentStore extends BudiStore {
return false
}
const settings = getComponentSettings(component._component)
const settings = this.getComponentSettings(component._component)
const updatedSetting = settings.find(setting => setting.key === name)
// Reset dependent fields
@ -1057,6 +1061,82 @@ export class ComponentStore extends BudiStore {
return state
})
}
/**
* Check if the components settings have been cached
* @param {string} componentType
* @example
* '@budibase/standard-components/container'
* @returns {boolean}
*/
isCached(componentType) {
const settings = get(this.store).settingsCache
return componentType in settings
}
/**
* Cache component settings
* @param {string} componentType
* @param {object} definition
* @example
* '@budibase/standard-components/container'
* @returns {boolean}
*/
cacheSettings(componentType, definition) {
let settings = []
if (definition && componentType) {
settings = definition.settings?.filter(setting => !setting.section) ?? []
definition.settings
?.filter(setting => setting.section)
.forEach(section => {
settings = settings.concat(
(section.settings || []).map(setting => ({
...setting,
section: section.name,
}))
)
})
this.update(state => ({
...state,
settingsCache: {
...state.settingsCache,
[componentType]: settings,
},
}))
}
}
/**
* Retrieve an array of the component settings.
* These settings are cached because they cannot change at run time.
*
* Searches a component's definition for a setting matching a certain predicate.
* @param {string} componentType
* @example
* '@budibase/standard-components/container'
* @returns {Array<object>}
*/
getComponentSettings(componentType) {
if (!componentType) {
return []
}
// Ensure whole component name is used
if (
!componentType.startsWith("plugin/") &&
!componentType.startsWith("@budibase")
) {
componentType = `@budibase/standard-components/${componentType}`
}
if (this.isCached(componentType)) {
return get(this.store).settingsCache[componentType]
} else {
const def = this.getDefinition(componentType)
this.cacheSettings(componentType, def)
return get(this.store).settingsCache[componentType]
}
}
}
export const componentStore = new ComponentStore()

View File

@ -1,4 +1,4 @@
import { componentStore } from "."
import { componentStore } from "stores/builder"
import { get } from "svelte/store"
import { Helpers } from "@budibase/bbui"
import {
@ -134,50 +134,6 @@ const searchComponentTree = (rootComponent, matchComponent) => {
return null
}
/**
* Searches a component's definition for a setting matching a certain predicate.
* These settings are cached because they cannot change at run time.
*/
let componentSettingCache = {}
export const getComponentSettings = componentType => {
if (!componentType) {
return []
}
// Ensure whole component name is used
if (
!componentType.startsWith("plugin/") &&
!componentType.startsWith("@budibase")
) {
componentType = `@budibase/standard-components/${componentType}`
}
// Check if we have cached this type already
if (componentSettingCache[componentType]) {
return componentSettingCache[componentType]
}
// Otherwise get the settings and cache them
const def = componentStore.getDefinition(componentType)
let settings = []
if (def) {
settings = def.settings?.filter(setting => !setting.section) ?? []
def.settings
?.filter(setting => setting.section)
.forEach(section => {
settings = settings.concat(
(section.settings || []).map(setting => ({
...setting,
section: section.name,
}))
)
})
}
componentSettingCache[componentType] = settings
return settings
}
/**
* Randomises a components ID's, including all child component IDs, and also
* updates all data bindings to still be valid.

View File

@ -1,13 +1,82 @@
import { it, expect, describe, beforeEach, vi } from "vitest"
import { get } from "svelte/store"
import { get, writable } from "svelte/store"
import {
INITIAL_COMPONENTS_STATE,
ComponentStore,
} from "stores/builder/components"
import { API } from "api"
import { appStore, tables } from "stores/builder"
import {
componentDefinitionMap,
getComponentFixture,
getScreenFixture,
pluginDefinitionMap,
clientFeaturesResp,
sampleTableDoc,
internalTableDoc,
userTableDoc,
externalTableDoc,
componentsToNested,
} from "./fixtures"
import {
DB_TYPE_INTERNAL,
DB_TYPE_EXTERNAL,
DEFAULT_BB_DATASOURCE_ID,
} from "constants/backend"
// Could move to fixtures
const COMP_PREFIX = "@budibase/standard-components"
vi.mock("api", () => {
return {
API: {
fetchComponentLibDefinitions: vi.fn(),
},
}
})
vi.mock("stores/builder", async () => {
const mockAppStore = writable()
const appStore = {
subscribe: mockAppStore.subscribe,
update: mockAppStore.update,
set: mockAppStore.set,
syncClientFeatures: vi.fn(),
}
const mockTableStore = writable()
const tables = {
subscribe: mockTableStore.subscribe,
update: mockTableStore.update,
set: mockTableStore.set,
}
return {
appStore,
tables,
}
})
// Simple base config for components and data sources
const baseInitialisation = ctx => {
// Init components
ctx.test.componentStore.update(state => ({
...state,
components: {
...componentDefinitionMap(),
},
}))
// Add datasources
tables.update(state => ({
...state,
list: [sampleTableDoc, internalTableDoc, userTableDoc, externalTableDoc],
}))
}
describe("Component store", () => {
beforeEach(ctx => {
vi.clearAllMocks()
vi.resetAllMocks()
const componentStore = new ComponentStore()
ctx.test = {}
ctx.test = {
@ -24,4 +93,379 @@ describe("Component store", () => {
it("Create base component store with defaults", ctx => {
expect(ctx.test.store).toStrictEqual(INITIAL_COMPONENTS_STATE)
})
it("Reset the component store to default", ctx => {
const container = getComponentFixture(`${COMP_PREFIX}/container`)
const pluginDefs = pluginDefinitionMap()
ctx.test.componentStore.update(state => ({
...state,
components: {
...componentDefinitionMap(),
...pluginDefs,
},
customComponents: Object.keys(pluginDefs),
componentToPaste: container.json(),
selectedComponentId: container._id,
}))
expect(ctx.test.store).not.toStrictEqual(INITIAL_COMPONENTS_STATE)
ctx.test.componentStore.reset()
expect(ctx.test.store).toStrictEqual(INITIAL_COMPONENTS_STATE)
})
it("Refresh the component definitions", async ctx => {
const componentDefs = componentDefinitionMap()
let mockAPIResponse = {
features: clientFeaturesResp,
...componentDefs,
}
const apiDefRequest = vi
.spyOn(API, "fetchComponentLibDefinitions")
.mockResolvedValue(mockAPIResponse)
const fakeAppId = "abc123"
const components = await ctx.test.componentStore.refreshDefinitions(
fakeAppId
)
expect(components).toStrictEqual(mockAPIResponse)
expect(ctx.test.store.components).toStrictEqual(mockAPIResponse)
expect(apiDefRequest).toBeCalled()
expect(appStore.syncClientFeatures).toBeCalledWith(clientFeaturesResp)
})
it("Refresh and sync component and plugin definitions", async ctx => {
const componentDefs = componentDefinitionMap()
const pluginDefs = pluginDefinitionMap()
let mockAPIResponse = {
features: clientFeaturesResp,
...componentDefs,
...pluginDefs,
}
const apiDefRequest = vi
.spyOn(API, "fetchComponentLibDefinitions")
.mockResolvedValue(mockAPIResponse)
const fakeAppId = "abc123"
const components = await ctx.test.componentStore.refreshDefinitions(
fakeAppId
)
expect(components).toStrictEqual(mockAPIResponse)
expect(ctx.test.store.components).toStrictEqual(mockAPIResponse)
expect(apiDefRequest).toBeCalled()
expect(appStore.syncClientFeatures).toBeCalledWith(clientFeaturesResp)
expect(ctx.test.store.customComponents).toStrictEqual(
Object.keys(pluginDefs)
)
})
it("Ignores definition sync if no appId is specified.", async ctx => {
const apiDefRequest = vi.spyOn(API, "fetchComponentLibDefinitions")
const components = await ctx.test.componentStore.refreshDefinitions()
expect(components).toBeUndefined()
expect(apiDefRequest).not.toBeCalled()
})
it("Retrieves component definitions by component type", ctx => {
const pluginDefs = pluginDefinitionMap()
const componentDefs = componentDefinitionMap()
ctx.test.componentStore.update(state => ({
...state,
components: {
...componentDefs,
...pluginDefs,
},
customComponents: Object.keys(pluginDefs),
}))
const def = ctx.test.componentStore.getDefinition(
"@budibase/standard-components/container"
)
expect(def).toStrictEqual(
componentDefs["@budibase/standard-components/container"]
)
const pluginDef = ctx.test.componentStore.getDefinition("plugin/budi-video")
expect(pluginDef).toStrictEqual(pluginDefs["plugin/budi-video"])
})
it("Handle missing or invalid component definition keys", ctx => {
const pluginDefs = pluginDefinitionMap()
const componentDefs = componentDefinitionMap()
ctx.test.componentStore.update(state => ({
...state,
components: {
...componentDefs,
...pluginDefs,
},
customComponents: Object.keys(pluginDefs),
}))
const def = ctx.test.componentStore.getDefinition(
"@budibase/standard-components/mystery"
)
expect(def).toBeUndefined()
const defEmpty = ctx.test.componentStore.getDefinition()
expect(defEmpty).toBeNull()
})
it("Select an appropriate default datasource - Internal Table ", ctx => {
tables.update(state => ({
...state,
list: [sampleTableDoc, internalTableDoc, userTableDoc, externalTableDoc],
}))
const table = ctx.test.componentStore.getDefaultDatasource()
expect(table.sourceType).toBe(DB_TYPE_INTERNAL)
expect(table.sourceId).not.toBe(DEFAULT_BB_DATASOURCE_ID)
})
it("Select an appropriate default datasource - Sample Table ", ctx => {
tables.update(state => ({
...state,
list: [sampleTableDoc, userTableDoc, externalTableDoc],
}))
const table = ctx.test.componentStore.getDefaultDatasource()
expect(table.sourceType).toBe(DB_TYPE_INTERNAL)
expect(table.sourceId).toBe(DEFAULT_BB_DATASOURCE_ID)
})
it("Select an appropriate default datasource - External Table ", ctx => {
tables.update(state => ({
...state,
list: [userTableDoc, externalTableDoc],
}))
const table = ctx.test.componentStore.getDefaultDatasource()
expect(table.sourceType).toBe(DB_TYPE_EXTERNAL)
})
it("Select an appropriate default datasource - No Table and ignore user table", ctx => {
tables.update(state => ({
...state,
list: [userTableDoc],
}))
const table = ctx.test.componentStore.getDefaultDatasource()
expect(table).toBeUndefined()
})
it("Apply no migrations if component is not a formblock", ctx => {
const comp = getComponentFixture(`${COMP_PREFIX}/container`).json()
const orig = { ...comp }
const migrated = ctx.test.componentStore.migrateSettings(orig)
expect(migrated).toBe(false)
expect(comp).toStrictEqual(orig)
})
it("Should initialise the buttons prop if it didnt exist", ctx => {
const formBlock = getComponentFixture(`${COMP_PREFIX}/formblock`).json()
const migrated = ctx.test.componentStore.migrateSettings(formBlock)
expect(migrated).toBe(true)
expect(formBlock.buttons).toEqual([])
})
it("Should initialise the buttons prop if it was nullified/reset", ctx => {
const formBlock = getComponentFixture(`${COMP_PREFIX}/formblock`).json()
formBlock.buttons = null
const migrated = ctx.test.componentStore.migrateSettings(formBlock)
expect(migrated).toBe(true)
expect(formBlock.buttons).toEqual([])
})
it("Should initialise formblock button position when not set", ctx => {
const formBlock = getComponentFixture(`${COMP_PREFIX}/formblock`).json()
const migrated = ctx.test.componentStore.migrateSettings(formBlock)
expect(migrated).toBe(true)
expect(formBlock.buttonPosition).toEqual("top")
})
it("Should ignore formblock migration if already initialised", ctx => {
const formBlock = getComponentFixture(`${COMP_PREFIX}/formblock`).json()
formBlock.buttonPosition = "bottom"
formBlock.buttons = []
const migrated = ctx.test.componentStore.migrateSettings(formBlock)
expect(migrated).toBe(false)
expect(formBlock.buttonPosition).toEqual("bottom")
})
it("enrichEmptySettings - initialise multifield type with schema keys", async ctx => {
const coreScreen = getScreenFixture()
baseInitialisation(ctx)
const componentDefs = componentDefinitionMap()
const targetCompDef =
componentDefs["@budibase/standard-components/rowexplorer"]
const comp = getComponentFixture(`${COMP_PREFIX}/rowexplorer`).json()
ctx.test.componentStore.enrichEmptySettings(comp, {
parent: null,
screen: coreScreen.json(),
useDefaultValues: true,
})
const multifieldKey = targetCompDef.settings[0].key
const multifieldOptions = comp[multifieldKey]
expect(multifieldOptions).toStrictEqual(
Object.keys(internalTableDoc.schema)
)
})
const enrichSettingsDS = (type, ctx) => {
const coreScreen = getScreenFixture()
baseInitialisation(ctx)
const componentDefs = componentDefinitionMap()
const targetCompDef = componentDefs[`${COMP_PREFIX}/${type}`]
const comp = getComponentFixture(`${COMP_PREFIX}/${type}`).json()
ctx.test.componentStore.enrichEmptySettings(comp, {
parent: null,
screen: coreScreen.json(),
useDefaultValues: true,
})
const settingKey = targetCompDef.settings[0].key
const settingValue = comp[settingKey]
expect(settingValue).toStrictEqual({
label: internalTableDoc.name,
tableId: internalTableDoc._id,
resourceId: internalTableDoc._id,
type: "table",
})
}
it("enrichEmptySettings - set default datasource for 'table' setting type", async ctx => {
enrichSettingsDS("formblock", ctx)
})
it("enrichEmptySettings - set default datasource for 'dataSource' setting type", async ctx => {
enrichSettingsDS("dataprovider", ctx)
})
it("enrichEmptySettings - set default datasource for type dataprovider", ctx => {
const coreScreen = getScreenFixture()
baseInitialisation(ctx)
const componentDefs = componentDefinitionMap()
const targetCompDef = componentDefs[`${COMP_PREFIX}/table`]
const providerOne = getComponentFixture(`${COMP_PREFIX}/dataprovider`)
const tableOne = getComponentFixture(`${COMP_PREFIX}/table`)
const components = Array(10)
.fill()
.map(() => getComponentFixture(`${COMP_PREFIX}/container`))
components.splice(5, 0, providerOne)
components.push(tableOne)
let nested = componentsToNested(components)
coreScreen.addChild(nested)
const comp = tableOne.json()
ctx.test.componentStore.enrichEmptySettings(comp, {
parent: null,
screen: coreScreen.json(),
useDefaultValues: true,
})
const settingKey = targetCompDef.settings[0].key
const settingValue = comp[settingKey]
expect(settingValue).toBe(`{{ literal [${providerOne.json()._id}] }}`)
})
it("enrichEmptySettings - set default datasource for type dataprovider - get closest provider", ctx => {
const coreScreen = getScreenFixture()
baseInitialisation(ctx)
const componentDefs = componentDefinitionMap()
const targetCompDef = componentDefs[`${COMP_PREFIX}/table`]
const providerOne = getComponentFixture(`${COMP_PREFIX}/dataprovider`)
const providerTwo = getComponentFixture(`${COMP_PREFIX}/dataprovider`)
const tableOne = getComponentFixture(`${COMP_PREFIX}/table`)
const components = Array(10)
.fill()
.map(() => getComponentFixture(`${COMP_PREFIX}/container`))
components.unshift(providerOne)
components.splice(5, 0, providerTwo)
components.push(tableOne)
let nested = componentsToNested(components)
coreScreen.addChild(nested)
const comp = tableOne.json()
ctx.test.componentStore.enrichEmptySettings(comp, {
parent: null,
screen: coreScreen.json(),
useDefaultValues: true,
})
const settingKey = targetCompDef.settings[0].key
const settingValue = comp[settingKey]
// Get the closest data provider in the tree.
expect(settingValue).toBe(`{{ literal [${providerTwo.json()._id}] }}`)
})
it("enrichEmptySettings - set default datasource for type dataprovider - no providers in tree", ctx => {
const coreScreen = getScreenFixture()
baseInitialisation(ctx)
const componentDefs = componentDefinitionMap()
const targetCompDef = componentDefs[`${COMP_PREFIX}/table`]
const tableOne = getComponentFixture(`${COMP_PREFIX}/table`)
const components = Array(10)
.fill()
.map(() => getComponentFixture(`${COMP_PREFIX}/container`))
components.push(tableOne)
let nested = componentsToNested(components)
coreScreen.addChild(nested)
const comp = tableOne.json()
ctx.test.componentStore.enrichEmptySettings(comp, {
parent: null,
screen: coreScreen.json(),
useDefaultValues: true,
})
const settingKey = targetCompDef.settings[0].key
const settingValue = comp[settingKey]
// The value should remain unset
expect(settingValue).toBeUndefined()
})
})

View File

@ -2,6 +2,12 @@ import { v4 } from "uuid"
import { Component } from "builder/store/screenTemplates/utils/Component"
import { Screen } from "builder/store/screenTemplates/utils/Screen"
import { get } from "svelte/store"
import {
BUDIBASE_INTERNAL_DB_ID,
DB_TYPE_INTERNAL,
DB_TYPE_EXTERNAL,
DEFAULT_BB_DATASOURCE_ID,
} from "constants/backend"
const getDocId = () => {
return v4().replace(/-/g, "")
@ -22,20 +28,90 @@ export const getComponentFixture = type => {
return new Component(type)
}
// Sample Definitions
export const COMPONENT_DEFINITIONS = {
form: {
name: "Form",
icon: "Form",
hasChildren: true,
illegalChildren: ["section", "form", "formblock"],
},
formblock: {
name: "Form Block",
block: true,
settings: [
{
type: "table",
key: "dataSource",
},
],
},
container: {
name: "Container",
},
rowexplorer: {
name: "Row Explorer",
settings: [
{
// combo unique to the row explorer
type: "multifield",
selectAllFields: true,
key: "detailFields",
},
],
},
dataprovider: {
name: "Data Provider",
settings: [
{
type: "dataSource",
},
],
},
table: {
name: "Table",
settings: [
{
type: "dataProvider",
key: "dataProvider",
},
],
},
stringfield: {
name: "Text Field",
settings: [
{
type: "field/string",
key: "field",
},
],
},
}
// Sample plugin definitions
export const PLUGIN_DEFINITIONS = {
"budi-video": {
component: "plugin/budi-video",
description: "Embedded video component. ",
friendlyName: "Budi Video",
icon: "VideoOutline",
name: "budi-video",
},
}
// Take a component array and turn it into a deeply nested tree
export const componentsToNested = components => {
let nested
do {
const current = components.pop()
if (!nested) {
nested = current
continue
}
//review this for the empty
current.addChild(nested)
nested = current
} while (components.length)
return nested
}
export const getFakeScreenPatch = store => {
@ -48,7 +124,7 @@ export const getFakeScreenPatch = store => {
}
}
export const componentMap = () => {
export const componentDefinitionMap = () => {
return Object.keys(COMPONENT_DEFINITIONS).reduce((acc, key) => {
const def = COMPONENT_DEFINITIONS[key]
acc[`@budibase/standard-components/${key}`] = def
@ -56,6 +132,14 @@ export const componentMap = () => {
}, {})
}
export const pluginDefinitionMap = () => {
return Object.keys(PLUGIN_DEFINITIONS).reduce((acc, key) => {
const def = PLUGIN_DEFINITIONS[key]
acc[`plugin/${key}`] = def
return acc
}, {})
}
export const getPluginFixture = pluginName => {
const fakeName = pluginName || v4().replace(/-/g, "")
return {
@ -145,15 +229,56 @@ export const clientFeaturesResp = {
sidePanel: true,
}
export const fetchDefinitionsResp = {
"@budibase/standard-components/text": {
component: "@budibase/standard-components/text",
},
"plugin/budi-video": {
component: "plugin/budi-video",
},
"plugin/budi-audio": {
component: "plugin/budi-audio",
},
features: clientFeaturesResp,
export const userTableDoc = {
_id: "ta_users",
type: "table",
name: "Users",
schema: {},
}
export const sampleTableDoc = {
_id: "ta_bb_employee",
type: "table",
name: "Employees",
sourceId: DEFAULT_BB_DATASOURCE_ID,
sourceType: DB_TYPE_INTERNAL,
primaryDisplay: "First Name",
schema: {
"First Name": {
name: "First Name",
type: "string",
},
"Last Name": {
name: "Last Name",
type: "string",
},
},
}
export const internalTableDoc = {
_id: "ta_db5ac9e254da415899adcec21a025b3f",
tableId: "ta_db5ac9e254da415899adcec21a025b3f",
type: "table",
name: "Media",
sourceId: BUDIBASE_INTERNAL_DB_ID,
sourceType: DB_TYPE_INTERNAL,
schema: {
MediaTitle: {
name: "MediaTitle",
type: "string",
},
MediaVersion: {
name: "MediaVersion",
type: "string",
},
},
}
export const externalTableDoc = {
type: "table",
_id: "datasource_plus_c5e6ae7fbe534da6917c44b284c54b45__Tester",
name: "Tester",
sourceId: "datasource_plus_c5e6ae7fbe534da6917c44b284c54b45",
sourceType: DB_TYPE_EXTERNAL,
sql: true,
}

View File

@ -8,9 +8,10 @@ import {
getScreenFixture,
getComponentFixture,
COMPONENT_DEFINITIONS,
componentMap,
componentDefinitionMap,
getScreenDocId,
getPluginFixture,
componentsToNested,
} from "./fixtures"
const COMP_PREFIX = "@budibase/standard-components"
@ -173,7 +174,7 @@ describe("Screens store", () => {
const defSpy = vi
.spyOn(componentStore, "getDefinition")
.mockImplementation(comp => {
const defMap = componentMap()
const defMap = componentDefinitionMap()
return defMap[comp]
})
@ -198,23 +199,14 @@ describe("Screens store", () => {
components.push(formTwo)
//Take the array and turn it into a deeply nested tree
let nested
do {
const current = components.pop()
if (!nested) {
nested = current
continue
}
current.addChild(nested)
nested = current
} while (components.length)
let nested = componentsToNested(components)
coreScreen.addChild(nested)
const defSpy = vi
.spyOn(componentStore, "getDefinition")
.mockImplementation(comp => {
const defMap = componentMap()
const defMap = componentDefinitionMap()
return defMap[comp]
})