/******************************************************************************** * Copyright (c) 2017-2018 TypeFox and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the Eclipse * Public License v. 2.0 are satisfied: GNU General Public License, version 2 * with the GNU Classpath Exception which is available at * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ /** @jsx svg */ import { svg } from '../lib/jsx'; import 'reflect-metadata'; import { expect, describe, it } from 'vitest'; import { Container } from 'inversify'; import { VNode } from 'snabbdom'; import { TYPES } from '../base/types'; import { IVNodePostprocessor } from '../base/views/vnode-postprocessor'; import { CircularNodeView, RectangularNodeView } from '../lib/svg-views'; import { CircularNode, RectangularNode, RectangularPort } from '../lib/model'; import { RenderingContext, ViewRegistry, configureModelElement } from '../base/views/view'; import { ModelRendererFactory } from '../base/views/viewer'; import { PolylineEdgeView, SGraphView } from './views'; import { SModelElementImpl, SParentElementImpl } from '../base/model/smodel'; import { IModelFactory } from '../base/model/smodel-factory'; import defaultModule from '../base/di.config'; import selectModule from '../features/select/di.config'; import moveModule from '../features/move/di.config'; import { SEdgeImpl, SGraphImpl, SNodeImpl, SPortImpl } from './sgraph'; import routingModule from '../features/routing/di.config'; import toHTML from 'snabbdom-to-html'; import { SEdge, SNode, SPort } from 'sprotty-protocol'; describe('graph views', () => { class CircleNodeView extends CircularNodeView { override render(node: SNodeImpl, renderContext: RenderingContext): VNode { const radius = this.getRadius(node); return ; } protected override getRadius(node: SNodeImpl) { return 40; } } const container = new Container(); container.load(defaultModule, selectModule, moveModule, routingModule); configureModelElement(container, 'graph', SGraphImpl, SGraphView); configureModelElement(container, 'node:circle', CircularNode, CircleNodeView); configureModelElement(container, 'edge:straight', SEdgeImpl, PolylineEdgeView); configureModelElement(container, 'port', SPortImpl, RectangularNodeView); const postprocessors = container.getAll(TYPES.IVNodePostprocessor); const context = container.get(TYPES.ModelRendererFactory)('hidden', postprocessors); const graphFactory = container.get(TYPES.IModelFactory); const viewRegistry = container.get(TYPES.ViewRegistry); it('render an empty graph', () => { const schema = { type: 'graph', id: 'mygraph', children: [] }; const graph = graphFactory.createRoot(schema) as SGraphImpl; const view = viewRegistry.get(graph.type); const vnode = view.render(graph, context); expect(toHTML(vnode)).to.be.equal(''); }); function createModel() { const node0 = { id: 'node0', type: 'node:circle', position: { x: 100, y: 100 }, size: { width: 80, height: 80 } }; const node1 = { id: 'node1', type: 'node:circle', position: { x: 200, y: 150 }, size: { width: 80, height: 80 }, selected: true }; const edge0 = { id: 'edge0', type: 'edge:straight', sourceId: 'node0', targetId: 'node1' }; const graph = graphFactory.createRoot({ id: 'graph', type: 'graph', children: [node0, node1, edge0] }) as SGraphImpl; return graph; } it('render a straight edge', () => { const graph = createModel(); const view = viewRegistry.get('edge:straight'); const vnode = view.render(graph.index.getById('edge0') as SEdgeImpl, context); expect(toHTML(vnode)).to.be.equal( ''); }); it('render a circle node', () => { const graph = createModel(); const view = viewRegistry.get('node:circle'); const vnode = view.render(graph.index.getById('node0') as SNodeImpl, context); expect(toHTML(vnode)).to.be.equal(''); }); it('render a whole graph', () => { const graph = createModel(); const vnode = context.renderElement(graph); const expectation = '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + '' + ''; expect(toHTML(vnode)).to.be.equal(expectation); }); }); describe('PolylineEdgeView', () => { const container = new Container(); container.load(defaultModule, routingModule); configureModelElement(container, 'graph', SGraphImpl, SGraphView); configureModelElement(container, 'node', RectangularNode, RectangularNodeView); configureModelElement(container, 'edge', SEdgeImpl, PolylineEdgeView); configureModelElement(container, 'edge:straight', SEdgeImpl, PolylineEdgeView); configureModelElement(container, 'port', RectangularPort, RectangularNodeView); const factory = container.get(TYPES.IModelFactory); const model = factory.createRoot({ type: 'graph', id: 'graph', children: [ { type: 'node', id: 'node1', position: { x: 10, y: 10 }, size: { width: 10, height: 10 }, children: [ { type: 'port', id: 'port1', position: { x: 10, y: 4 } } as SPort, { type: 'edge', id: 'edge1', sourceId: 'port1', targetId: 'port2' } as SEdge ] } as SNode, { type: 'node', id: 'node2', position: { x: 30, y: 20 }, size: { width: 10, height: 10 }, children: [ { type: 'port', id: 'port2', position: { x: -2, y: 4 } } as SPort, { type: 'edge', id: 'edge2', sourceId: 'port1', targetId: 'port2' } as SEdge ] } as SNode, ] }); const viewRegistry = container.get(TYPES.ViewRegistry); const edgeView = viewRegistry.get('edge:straight'); const context = { targetKind: 'hidden', viewRegistry, decorate: function(vnode: VNode, element: SModelElementImpl): VNode { return vnode; }, renderElement: function(element: SModelElementImpl): VNode { return ; }, renderChildren: function(element: SParentElementImpl): VNode[] { return []; } } as RenderingContext; it('correctly translates edge source and target position', () => { const edge = model.index.getById('edge1') as SEdgeImpl; const vnode = edgeView.render(edge, context); expect(toHTML(vnode)).to.equal(''); }); it('correctly translates edge target and source position', () => { const edge = model.index.getById('edge2') as SEdgeImpl; const vnode = edgeView.render(edge, context); expect(toHTML(vnode)).to.equal(''); }); });