Im currently writing Unit test for a Vue component. The component renders the floorplan of a office. For that it generates an svg with the tables of the office. These are saved in a json.
The Vue component (FYI: Table refers to a desk):
import { onMounted, ref, watch } from 'vue';
import { json2SVG } from '@/converter/DbObjects2SvgParser';
import { useWallStore } from '@/stores/walls';
import { usePlaceStore } from '@/stores/tables';
import type { Wall } from '@/stores/walls';
import type { Place } from '@/stores/tables';
const wallsStore = useWallStore();
const wallsFromStore = ref<Wall[]>([]);
const tablesStore = usePlaceStore();
const tablesFromStore = ref<Place[]>([]);
let tables: HTMLCollectionOf<Element> = document.getElementsByClassName('main');
const selectedTable = ref<HTMLTableElement | null>(null);
const testSvg = ref<SVGElement>();
const mapContainer = ref<HTMLDivElement>();
const imageHeight = ref(585);
const imageWidth = ref(1200);
const emit = defineEmits(['tableSelected']);
const props = defineProps(['placeIdFromButton']);
function placeClick(event: Event) {
const target = event.target as HTMLTableElement;
changeSelectedTable(target);
emit('tableSelected', target.id);
}
function changeSelectedTable(targetTable: HTMLTableElement) {
if (selectedTable.value) {
selectedTable.value.style.fill = ''; // Reset the previous selected table
}
targetTable.style.fill = 'white';
selectedTable.value = targetTable;
}
watch(props, () => {
console.log('watcher')
for (let i = 0; i < tables.length; i++) {
const table = tables[i];
if (table.id == props.placeIdFromButton) {
changeSelectedTable(table as HTMLTableElement);
}
}
});
onMounted(async () => {
await wallsStore.fetchWalls();
wallsFromStore.value = wallsStore.walls;
await tablesStore.fetchPlaces();
tablesFromStore.value = tablesStore.places;
/* parsing from json to DB */
// TODO should be moved into architect-app
//const parsingWalls = walls2DBParser(plan, "http://localhost:3000/walls")
//const parsingTables = tables2DBParser(plan, "http://localhost:3000/tables")
if (testSvg.value instanceof SVGElement) {
if (typeof document !== 'undefined'){
json2SVG(testSvg.value, wallsFromStore.value, tablesFromStore.value);
}
} else {
console.error('The element with ID "testSvg" is not an SVG element or does not exist.');
}
if (mapContainer.value) {
imageHeight.value = mapContainer.value.clientHeight - 10;
// imageWidth.value = mapContainer.clientWidth;
} else {
console.error('The element with ID "map-container" does not exist.');
}
tables = document.getElementsByClassName('table');
for (const table of tables) {
table.addEventListener('click', placeClick);
}
});
</script>
<template>
<div class="container" id="test">
<div class="map-container" id="map-container" ref="mapContainer">
<!--Map class="svgmap"/-->
<svg class="svg-field" id="testSvg" ref="testSvg"
:width="imageWidth" :height="imageHeight"
viewBox='-75 -50 193 150'
style="background: white"
>
<line class="testline1"
x1="-50" y1="-50"
x2="100" y2="100"
stroke="green"
></line>
<!--circle id="99" cx="-120" cy="-10" r="3" onclick="$setup.testClick($event.target.id)" ></circle>
<circle id="99" cx="-110" cy="-20" r="3" onclick="{console.log($ event.target)}" ></circle-->
</svg>
</div>
</div>
</template>
<style lang="scss">
@use '@/assets/themes/itemisVariables';
.svgmap {
object-fit: cover;
width: 100%;
height: 100%;
}
.map-container {
overflow: auto;
border-style: solid;
border-color: itemisVariables.$itemisGrey;
}
.svg-field {
background-color: itemisVariables.$itemisGrey;
}
.testline {
stroke: yellow;
}
.wall {
stroke: itemisVariables.$itemisDarkBlue;
}
.table {
stroke: itemisVariables.$itemisDarkBlue;
fill: itemisVariables.$itemisBlue;
r: 5;
transition: fill 0.5s ease;
}
.table:hover {
fill: itemisVariables.$itemisGrey;
animation: pulse-color 1s infinite;
}
@keyframes pulse {
0% {
fill: itemisVariables.$itemisGrey;
}
50% {
fill: itemisVariables.$itemisBlue;
opacity: 0.7;
}
100% {
fill: itemisVariables.$itemisGrey;
}
}
</style>
My test:
import { describe, it, expect, beforeEach, vi } from 'vitest';
import { flushPromises, mount, shallowMount } from '@vue/test-utils';
import { nextTick } from 'vue';
import ImagePart03 from '@/views/NewReservation_03/ImagePart03.vue';
import { createPinia, setActivePinia } from 'pinia';
beforeEach(async () => {
setActivePinia(createPinia());
await nextTick();
})
describe('TagesberichteTag', () => {
const shallowMountCut = () => {
const cut = shallowMount(ImagePart03);
return {
findMapContainer: () => cut.find('.map-container'),
findFirstTable: () => cut.find('[id="1"]'),
findHeader: () => cut.find('.header'),
findPhrase: () => cut.find('.phrase')
};
};
it('renders map container', () => {
const { findMapContainer } = shallowMountCut();
expect(findMapContainer().exists()).toBe(true);
});
it('renders table', async () => {
await flushPromises()
await nextTick()
const { findFirstTable } = shallowMountCut();
await nextTick()
await flushPromises()
expect(findFirstTable().exists()).toBe(true);
});
});
Db2Objects2SvgParser.ts:
import type { Wall } from '@/stores/walls';
import type { Place } from '@/stores/tables';
const SCALE = 10;
export const json2SVG = (svg: SVGElement, wallsFromDB: Wall[], tablesFromDB: Place[]): SVGElement => {
const svgWalls = wallObjectsIntoSVGElementSParser(wallsFromDB);
svg.append(svgWalls);
const svgTables = tableObjectsIntoSVGElementSParser(tablesFromDB);
svg.append(svgTables);
return svg;
};
export const wallObjectsIntoSVGElementSParser = (wallsFromDB: Wall[]) => {
const sgvWallsGroup: SVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'g');
sgvWallsGroup.setAttribute('id', 'walls');
for (const wall of wallsFromDB) {
const svgWall = svgWallFromDBWallcreate(wall);
sgvWallsGroup.appendChild(svgWall);
}
return sgvWallsGroup;
};
export const svgWallFromDBWallcreate = (wall: Wall) => {
const wallElement = document.createElementNS('http://www.w3.org/2000/svg', 'line');
wallElement.setAttribute('x1', (wall.coordsA.x * SCALE).toString());
wallElement.setAttribute('y1', (wall.coordsA.y * SCALE).toString());
wallElement.setAttribute('x2', (wall.coordsB.x * SCALE).toString());
wallElement.setAttribute('y2', (wall.coordsB.y * SCALE).toString());
wallElement.setAttribute('stroke', 'green');
wallElement.setAttribute('class', 'wall');
return wallElement;
};
export const tableObjectsIntoSVGElementSParser = (tablesFromDB: Place[]) => {
const svgTablesGroup: SVGElement = document.createElementNS('http://www.w3.org/2000/svg', 'g');
svgTablesGroup.setAttribute('id', 'tables');
let tableIndex = 0;
for (const table of tablesFromDB) {
const svgTable = svgTableFromDBTableCreate(table);
tableIndex++;
const tableIndexString = tableIndex.toString();
svgTable.setAttribute('id', tableIndexString);
svgTablesGroup.appendChild(svgTable);
}
return svgTablesGroup;
};
export const svgTableFromDBTableCreate = (table: Place) => {
const tableElement = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
tableElement.setAttribute('r', '2');
tableElement.setAttribute('cx', (table.pos.x * SCALE).toString());
tableElement.setAttribute('cy', (table.pos.y * SCALE).toString());
tableElement.setAttribute('fill', 'red');
tableElement.setAttribute('stroke', 'green');
tableElement.setAttribute('stroke-width', '1');
tableElement.setAttribute('class', table.type);
//tableElement.setAttribute("onclick", "console.log($event.target)");
return tableElement;
};
Using intelliJ’s debugger I’ve found this error and I think this is the reason why im not able to find the table using its Id in my test:
ReferenceError: __vite_ssr_import_2__ is not defined
at eval (eval at json2SVG (/Users/userName/IdeaProjects/rare/Frontend/src/converter/DbObjects2SvgParser.ts:12:3), <anonymous>:1:1)
at Module.json2SVG (/Users/userName/IdeaProjects/rare/Frontend/src/converter/DbObjects2SvgParser.ts:12:3)
at /Users/userName/IdeaProjects/rare/Frontend/src/views/NewReservation_03/ImagePart03.vue:65:5
at processTicksAndRejections (node:internal/process/task_queues:95:5)