diff --git a/frontend/language/src/nb.json b/frontend/language/src/nb.json index b1ec7114244..8d4f4500ad1 100644 --- a/frontend/language/src/nb.json +++ b/frontend/language/src/nb.json @@ -807,6 +807,7 @@ "schema_editor.add_reference.prompt": "Oppgi navnet på typen det skal refereres til.", "schema_editor.add_reference.type_does_not_exist": "Typen {{reference}} eksisterer ikke.", "schema_editor.add_string": "Legg til tekst", + "schema_editor.add_type": "Legg til type", "schema_editor.all_of": "Alle i", "schema_editor.any_of": "Noen av", "schema_editor.array": "Liste", diff --git a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx index 1cdfe5ba660..1c4976365cd 100644 --- a/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx +++ b/frontend/packages/schema-editor/src/components/NodePanel/HeadingRow/HeadingRow.tsx @@ -10,6 +10,7 @@ import { isNodeValidParent, ObjectKind, ROOT_POINTER, + SchemaModel, } from '@altinn/schema-model'; import { useTranslation } from 'react-i18next'; import { StudioButton, StudioDeleteButton, StudioDropdownMenu } from '@studio/components'; @@ -89,13 +90,13 @@ const AddNodeMenu = ({ schemaPointer }: AddNodeMenuProps) => { }; const useAddNodeMenuItems = (schemaPointer: string): AddNodeMenuItemProps[] => { - const { setSelectedUniquePointer, schemaModel } = useSchemaEditorAppContext(); + const { setSelectedUniquePointer } = useSchemaEditorAppContext(); const addNode = useAddProperty(); const addAndSelectNode = (...params: Parameters) => { const newPointer = addNode(...params); if (newPointer) { - const newUniquePointer = schemaModel.getUniquePointer(newPointer); + const newUniquePointer = SchemaModel.getUniquePointer(newPointer); setSelectedUniquePointer(newUniquePointer); } }; diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.test.ts b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.test.ts index 7a7a711c11f..ef6ac3048e6 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.test.ts +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.test.ts @@ -1,5 +1,11 @@ import type { ReferenceNode } from '@altinn/schema-model'; -import { extractNameFromPointer, isReference, SchemaModel } from '@altinn/schema-model'; +import { + ROOT_POINTER, + extractNameFromPointer, + isReference, + SchemaModel, +} from '@altinn/schema-model'; + import { definitionNodeMock, combinationNodeMock, @@ -12,6 +18,15 @@ import { useAddReference } from './useAddReference'; import type { SavableSchemaModel } from '../../../classes/SavableSchemaModel'; import { ArrayUtils } from '@studio/pure-functions'; +// Test data: +const nameOfDefinition = extractNameFromPointer(definitionNodeMock.schemaPointer); +const uniqueRootNodePointer = SchemaModel.getUniquePointer(ROOT_POINTER); +const schemaPointerOfParent = combinationNodeMock.schemaPointer; +const uniquePointerOfParent = SchemaModel.getUniquePointer( + schemaPointerOfParent, + uniqueRootNodePointer, +); + describe('useAddReference', () => { const setup = () => { const save = jest.fn(); @@ -24,14 +39,12 @@ describe('useAddReference', () => { it('Adds a reference to the given position', () => { const { add, save } = setup(); - const nameOfDefinition = extractNameFromPointer(definitionNodeMock.schemaPointer); - const pointerOfParent = combinationNodeMock.schemaPointer; const indexInNewParent = 1; - const target: ItemPosition = { parentId: pointerOfParent, index: indexInNewParent }; + const target: ItemPosition = { parentId: uniquePointerOfParent, index: indexInNewParent }; add(nameOfDefinition, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; - const childrenOfNewParent = savedModel.getChildNodes(pointerOfParent); + const childrenOfNewParent = savedModel.getChildNodes(schemaPointerOfParent); const addedChild = childrenOfNewParent[indexInNewParent]; expect(isReference(addedChild)).toBe(true); const addedReferenceNode = addedChild as ReferenceNode; @@ -40,14 +53,12 @@ describe('useAddReference', () => { it('Adds a reference to the end if the given position is -1', () => { const { add, save } = setup(); - const nameOfDefinition = extractNameFromPointer(definitionNodeMock.schemaPointer); - const pointerOfParent = combinationNodeMock.schemaPointer; const givenIndex = -1; - const target: ItemPosition = { parentId: pointerOfParent, index: givenIndex }; + const target: ItemPosition = { parentId: uniquePointerOfParent, index: givenIndex }; add(nameOfDefinition, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; - const childrenOfNewParent = savedModel.getChildNodes(pointerOfParent); + const childrenOfNewParent = savedModel.getChildNodes(schemaPointerOfParent); const addedChild = ArrayUtils.last(childrenOfNewParent); expect(isReference(addedChild)).toBe(true); const addedReferenceNode = addedChild as ReferenceNode; @@ -56,14 +67,12 @@ describe('useAddReference', () => { it('Adds a reference to the end if the given position is the same as the number of elements', () => { const { add, save } = setup(); - const nameOfDefinition = extractNameFromPointer(definitionNodeMock.schemaPointer); - const pointerOfParent = combinationNodeMock.schemaPointer; const givenIndex = combinationNodeMock.children.length; - const target: ItemPosition = { parentId: pointerOfParent, index: givenIndex }; + const target: ItemPosition = { parentId: uniquePointerOfParent, index: givenIndex }; add(nameOfDefinition, target); expect(save).toHaveBeenCalledTimes(1); const savedModel: SavableSchemaModel = save.mock.lastCall[0]; - const childrenOfNewParent = savedModel.getChildNodes(pointerOfParent); + const childrenOfNewParent = savedModel.getChildNodes(schemaPointerOfParent); const addedChild = ArrayUtils.last(childrenOfNewParent); expect(isReference(addedChild)).toBe(true); const addedReferenceNode = addedChild as ReferenceNode; diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts index 14d8d6817a5..5b46ca551a9 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useAddReference.ts @@ -1,23 +1,25 @@ import type { HandleAdd, ItemPosition } from 'app-shared/types/dndTypes'; import { useCallback } from 'react'; import type { NodePosition } from '@altinn/schema-model'; +import { SchemaModel } from '@altinn/schema-model'; import { calculatePositionInFullList } from '../utils'; import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; import { useSchemaEditorAppContext } from '@altinn/schema-editor/hooks/useSchemaEditorAppContext'; export const useAddReference = (): HandleAdd => { - const { setSelectedUniquePointer, schemaModel } = useSchemaEditorAppContext(); + const { setSelectedUniquePointer } = useSchemaEditorAppContext(); const savableModel = useSavableSchemaModel(); return useCallback( (reference: string, position: ItemPosition) => { const index = calculatePositionInFullList(savableModel, position); - const target: NodePosition = { parentPointer: position.parentId, index }; - const schemaPointer = savableModel.getFinalNode(target.parentPointer).schemaPointer; + const parentPointer = savableModel.getSchemaPointerByUniquePointer(position.parentId); + const target: NodePosition = { parentPointer, index }; + const { schemaPointer } = savableModel.getFinalNode(target.parentPointer); const refName = savableModel.generateUniqueChildName(schemaPointer, 'ref'); const ref = savableModel.addReference(refName, reference, target); - const uniquePointer = schemaModel.getUniquePointer(ref.schemaPointer); + const uniquePointer = SchemaModel.getUniquePointer(ref.schemaPointer); setSelectedUniquePointer(uniquePointer); }, - [savableModel, setSelectedUniquePointer, schemaModel], + [savableModel, setSelectedUniquePointer], ); }; diff --git a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts index 3afbd23b4ae..7b87dc5fd03 100644 --- a/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts +++ b/frontend/packages/schema-editor/src/components/SchemaEditor/hooks/useMoveProperty.ts @@ -1,7 +1,7 @@ import type { HandleMove, ItemPosition } from 'app-shared/types/dndTypes'; import { useCallback } from 'react'; import type { NodePosition } from '@altinn/schema-model'; -import { extractNameFromPointer, isCombination } from '@altinn/schema-model'; +import { SchemaModel, extractNameFromPointer, isCombination } from '@altinn/schema-model'; import { calculatePositionInFullList } from '../utils'; import { useSavableSchemaModel } from '../../../hooks/useSavableSchemaModel'; import { useTranslation } from 'react-i18next'; @@ -38,7 +38,7 @@ export const useMoveProperty = (): HandleMove => { } else { const movedNode = savableModel.moveNode(schemaPointer, target); if (selectedUniquePointer === uniquePointer) { - const movedUniquePointer = savableModel.getUniquePointer( + const movedUniquePointer = SchemaModel.getUniquePointer( movedNode.schemaPointer, position.parentId, ); diff --git a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx index 73c4b4abc1b..2337ed09ae7 100644 --- a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/ActionButtons/AddPropertyMenu.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { useAddProperty } from '../../../../hooks/useAddProperty'; import type { FieldType, ObjectKind } from '@altinn/schema-model'; -import { useSavableSchemaModel } from '../../../../hooks/useSavableSchemaModel'; +import { SchemaModel } from '@altinn/schema-model'; import { useSchemaEditorAppContext } from '@altinn/schema-editor/hooks/useSchemaEditorAppContext'; import { AddPropertiesMenu } from '../../../AddPropertiesMenu'; import { useTranslation } from 'react-i18next'; @@ -14,7 +14,6 @@ interface AddPropertyMenuProps { export const AddPropertyMenu = ({ schemaPointer, uniquePointer }: AddPropertyMenuProps) => { const { setSelectedUniquePointer } = useSchemaEditorAppContext(); - const savableModel = useSavableSchemaModel(); const { t } = useTranslation(); const addProperty = useAddProperty(); @@ -22,7 +21,7 @@ export const AddPropertyMenu = ({ schemaPointer, uniquePointer }: AddPropertyMen const addPropertyAndClose = (kind: ObjectKind, fieldType?: FieldType) => { const childPointer = addProperty(kind, fieldType, schemaPointer); if (childPointer) { - const uniqueChildPointer = savableModel.getUniquePointer(childPointer, uniquePointer); + const uniqueChildPointer = SchemaModel.getUniquePointer(childPointer, uniquePointer); setSelectedUniquePointer(uniqueChildPointer); } }; diff --git a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/SchemaNode.tsx b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/SchemaNode.tsx index bd960ac7755..e657d385049 100644 --- a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/SchemaNode.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaNode/SchemaNode.tsx @@ -1,7 +1,12 @@ import type { ReactElement, ReactNode } from 'react'; import React from 'react'; -import type { SchemaModel, UiSchemaNode } from '@altinn/schema-model'; -import { extractNameFromPointer, isNodeValidParent, isReference } from '@altinn/schema-model'; +import type { UiSchemaNode } from '@altinn/schema-model'; +import { + SchemaModel, + extractNameFromPointer, + isNodeValidParent, + isReference, +} from '@altinn/schema-model'; import { DragAndDropTree } from 'app-shared/components/DragAndDropTree'; import { renderSchemaNodeList } from '../renderSchemaNodeList'; import { renderIcon } from './renderIcon'; @@ -28,7 +33,7 @@ export const SchemaNode = ({ ? '' : extractNameFromPointer(schemaPointer); const index = savableModel.getIndexOfChildNode(schemaPointer); - const uniquePointer = savableModel.getUniquePointer(schemaPointer, uniqueParentPointer); + const uniquePointer = SchemaModel.getUniquePointer(schemaPointer, uniqueParentPointer); const title = label || t('schema_editor.tree.combination_child_title', { index }); const labelWrapper = (labelComponent: ReactNode) => ( diff --git a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaTree.tsx b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaTree.tsx index ed0cd2dfd09..7f257722c53 100644 --- a/frontend/packages/schema-editor/src/components/SchemaTree/SchemaTree.tsx +++ b/frontend/packages/schema-editor/src/components/SchemaTree/SchemaTree.tsx @@ -4,6 +4,7 @@ import { renderSchemaNodeList } from './renderSchemaNodeList'; import { useTranslation } from 'react-i18next'; import { useSavableSchemaModel } from '../../hooks/useSavableSchemaModel'; import { useSchemaEditorAppContext } from '../../hooks/useSchemaEditorAppContext'; +import { SchemaModel } from '@altinn/schema-model/lib/SchemaModel'; export interface SchemaTreeProps { schemaPointer?: string; @@ -11,7 +12,7 @@ export interface SchemaTreeProps { export const SchemaTree = ({ schemaPointer }: SchemaTreeProps) => { const savableModel = useSavableSchemaModel(); - const uniquePointer = savableModel.getUniquePointer(schemaPointer); + const uniquePointer = SchemaModel.getUniquePointer(schemaPointer); const { selectedUniquePointer, setSelectedUniquePointer } = useSchemaEditorAppContext(); const { t } = useTranslation(); diff --git a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx index cd653d53d5d..54e6a29226d 100644 --- a/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx +++ b/frontend/packages/schema-editor/src/components/TypesInspector/TypesInspector.tsx @@ -3,6 +3,7 @@ import React from 'react'; import { StudioButton } from '@studio/components'; import { PlusIcon } from '@studio/icons'; import type { UiSchemaNode } from '@altinn/schema-model'; +import { SchemaModel } from '@altinn/schema-model'; import classes from './TypesInspector.module.css'; import { Divider } from 'app-shared/primitives'; import { useTranslation } from 'react-i18next'; @@ -25,7 +26,7 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { const setSelectedType = (schemaPointer: string) => { setSelectedTypePointer(schemaPointer); - const uniquePointer = schemaModel.getUniquePointer(schemaPointer); + const uniquePointer = SchemaModel.getUniquePointer(schemaPointer); setSelectedUniquePointer(uniquePointer); }; @@ -58,6 +59,7 @@ export const TypesInspector = ({ schemaItems }: TypesInspectorProps) => { variant='tertiary' icon={} onClick={handleAddDefinition} + title={t('schema_editor.add_type')} /> diff --git a/frontend/packages/schema-model/src/lib/SchemaModel.test.ts b/frontend/packages/schema-model/src/lib/SchemaModel.test.ts index 566e8271a1f..d21c553844f 100644 --- a/frontend/packages/schema-model/src/lib/SchemaModel.test.ts +++ b/frontend/packages/schema-model/src/lib/SchemaModel.test.ts @@ -169,7 +169,7 @@ describe('SchemaModel', () => { describe('getUniquePointer', () => { it('Returns the unique pointer when called on the root node', () => { const expectedUniqueRootPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}`; - expect(schemaModel.getUniquePointer(rootNodeMock.schemaPointer)).toEqual( + expect(SchemaModel.getUniquePointer(rootNodeMock.schemaPointer)).toEqual( expectedUniqueRootPointer, ); }); @@ -177,7 +177,7 @@ describe('SchemaModel', () => { it('Returns the unique pointer when called on a property node', () => { const expectedUniquePointer = `${UNIQUE_POINTER_PREFIX}${referenceToObjectNodeMock.schemaPointer}`; - expect(schemaModel.getUniquePointer(referenceToObjectNodeMock.schemaPointer)).toEqual( + expect(SchemaModel.getUniquePointer(referenceToObjectNodeMock.schemaPointer)).toEqual( expectedUniquePointer, ); }); @@ -187,13 +187,13 @@ describe('SchemaModel', () => { const expectedUniqueGrandchildPointer = `${UNIQUE_POINTER_PREFIX}${ROOT_POINTER}/properties/referenceToParent/properties/child/properties/grandchild`; expect( - schemaModel.getUniquePointer( + SchemaModel.getUniquePointer( defNodeWithChildrenChildMock.schemaPointer, referenceToObjectNodeMock.schemaPointer, ), ).toEqual(expectedUniqueChildPointer); expect( - schemaModel.getUniquePointer( + SchemaModel.getUniquePointer( defNodeWithChildrenGrandchildMock.schemaPointer, expectedUniqueChildPointer, ), @@ -203,7 +203,7 @@ describe('SchemaModel', () => { it('Returns a pointer reflecting the path to a given node in a reference to a combination', () => { const { schemaPointer } = combinationDefNodeChild1Mock; const uniquePointerOfParent = referenceToCombinationDefNodeMock.schemaPointer; - const result = schemaModel.getUniquePointer(schemaPointer, uniquePointerOfParent); + const result = SchemaModel.getUniquePointer(schemaPointer, uniquePointerOfParent); const expectedResult = `${UNIQUE_POINTER_PREFIX}#/properties/referenceToCombinationDef/oneOf/0`; expect(result).toEqual(expectedResult); }); diff --git a/frontend/packages/schema-model/src/lib/SchemaModel.ts b/frontend/packages/schema-model/src/lib/SchemaModel.ts index 1255b3d132e..56a858d912a 100644 --- a/frontend/packages/schema-model/src/lib/SchemaModel.ts +++ b/frontend/packages/schema-model/src/lib/SchemaModel.ts @@ -85,7 +85,7 @@ export class SchemaModel { } public getSchemaPointerByUniquePointer(uniquePointer: string): string { - const pointer = this.removeUniquePointerPrefix(uniquePointer); + const pointer = SchemaModel.removeUniquePointerPrefix(uniquePointer); if (this.hasNode(pointer)) return pointer; const parentSchemaPointer = this.getParentSchemaPointerByUniquePointer(pointer); @@ -108,15 +108,15 @@ export class SchemaModel { return this.getNodeByUniquePointer(parentUniquePointer); } - private removeUniquePointerPrefix(uniquePointer: string): string { + private static removeUniquePointerPrefix(uniquePointer: string): string { return StringUtils.removeStart(uniquePointer, UNIQUE_POINTER_PREFIX); } - public getUniquePointer(schemaPointer: string, uniqueParentPointer?: string): string { + public static getUniquePointer(schemaPointer: string, uniqueParentPointer?: string): string { if (!uniqueParentPointer || !isDefinitionPointer(schemaPointer)) return `${UNIQUE_POINTER_PREFIX}${schemaPointer}`; const category = extractCategoryFromPointer(schemaPointer); - const parentPointer = this.removeUniquePointerPrefix(uniqueParentPointer); + const parentPointer = SchemaModel.removeUniquePointerPrefix(uniqueParentPointer); return `${UNIQUE_POINTER_PREFIX}${parentPointer}/${category}/${extractNameFromPointer(schemaPointer)}`; } diff --git a/frontend/testing/playwright/pages/DataModelPage.ts b/frontend/testing/playwright/pages/DataModelPage.ts index 2e8bd11fffc..a664fcbee98 100644 --- a/frontend/testing/playwright/pages/DataModelPage.ts +++ b/frontend/testing/playwright/pages/DataModelPage.ts @@ -4,6 +4,7 @@ import type { Environment } from '../helpers/StudioEnvironment'; import path from 'path'; import { expect } from '@playwright/test'; import { DataTestId } from '../enum/DataTestId'; +import { droppableListId, typeItemId } from '@studio/testing/testids'; export class DataModelPage extends BasePage { constructor(page: Page, environment?: Environment) { @@ -38,13 +39,13 @@ export class DataModelPage extends BasePage { public async clickOnAddPropertyButton(): Promise { await this.page - .getByRole('button', { name: this.textMock('schema_editor.add') }) + .getByRole('button', { name: this.textMock('schema_editor.add_node_of_type') }) .first() .click(); } public async clickOnObjectAddPropertyButton(): Promise { - await this.page.getByTitle(this.textMock('schema_editor.add')).click(); + await this.page.getByTitle(this.textMock('schema_editor.add_node_of_type')).click(); } public async clickOnAddObjectPropertyMenuItem(): Promise { @@ -58,7 +59,12 @@ export class DataModelPage extends BasePage { } public async checkThatTreeItemPropertyExistsOnScreen(name: string): Promise { - await this.page.getByRole('treeitem', { name }).isVisible(); + const treeItem = this.getTreeItemProperty(name); + await expect(treeItem).toBeVisible(); + } + + private getTreeItemProperty(name: string): Locator { + return this.page.getByRole('treeitem', { name }); } public async clearNameField(): Promise { @@ -184,4 +190,35 @@ export class DataModelPage extends BasePage { private getTypeCombobox(): Locator { return this.page.getByRole('combobox', { name: this.textMock('schema_editor.type') }); } + + public async addType(): Promise { + await this.getAddTypeButton().click(); + } + + private getAddTypeButton(): Locator { + return this.page.getByRole('button', { name: this.textMock('schema_editor.add_type') }); + } + + public async verifyThatTypeIsVisible(typeName: string): Promise { + const typeItem = this.getTypeItem(typeName); + await expect(typeItem).toBeVisible(); + } + + public getTypeItem(name: string): Locator { + const pointer = '#/$defs/' + name; + return this.page.getByTestId(typeItemId(pointer)); + } + + public getDroppableList(parentName: string): Locator { + return this.page.getByTitle(parentName).getByTestId(droppableListId); + } + + public async clickOnBackToDataModelButton(): Promise { + await this.getBackToDataModelButton().click(); + } + + private getBackToDataModelButton(): Locator { + const name = this.textMock('schema_editor.back_to_data_model'); + return this.page.getByRole('button', { name }); + } } diff --git a/frontend/testing/playwright/tests/data-model/data-model.spec.ts b/frontend/testing/playwright/tests/data-model/data-model.spec.ts index 708260e31b7..e43bbbe2be0 100644 --- a/frontend/testing/playwright/tests/data-model/data-model.spec.ts +++ b/frontend/testing/playwright/tests/data-model/data-model.spec.ts @@ -121,3 +121,29 @@ test('Allows to upload and then delete an XSD file', async ({ page, testAppName await dataModelPage.clickOnConfirmDeleteDataModelButton(); await dataModelPage.checkThatDataModelOptionDoesNotExists(dataModelName); }); + +test('Adding a type and dragging it into an object', async ({ page, testAppName }) => { + // Load the data model page + const dataModelPage = new DataModelPage(page, { app: testAppName }); + await dataModelPage.loadDataModelPage(); + await dataModelPage.verifyDataModelPage(); + + // Add a new type + await dataModelPage.addType(); + await dataModelPage.clickOnBackToDataModelButton(); + const expectedTypeName = 'name0'; + await dataModelPage.verifyThatTypeIsVisible(expectedTypeName); + + // Add an object + await dataModelPage.clickOnAddPropertyButton(); + await dataModelPage.clickOnAddObjectPropertyMenuItem(); + const expectedObjectName = 'name1'; + await dataModelPage.checkThatTreeItemPropertyExistsOnScreen(expectedObjectName); + + // Drag the type into the object + const typeItem = dataModelPage.getTypeItem(expectedTypeName); + const objectDropArea = dataModelPage.getDroppableList(expectedObjectName); + await dataModelPage.dragAndDropManually(typeItem, objectDropArea); + const expectedReferenceName = 'ref0'; + await dataModelPage.checkThatTreeItemPropertyExistsOnScreen(expectedReferenceName); +});