Files
undergroundwires f3571abeaf Bump dependencies to latest, hold ESLint
This commit updates the project's npm dependencies to their
latest versions.

Updates to the following dependencies are on hold due to compatibility
issues:

- `@typescript-eslint/eslint-plugin`:
  - Blocked by `@vue/eslint-config-airbnb-with-typescript`
    (vuejs/eslint-config-airbnb#63).
- `@typescript-eslint/parser`:
  - Blocked by `@vue/eslint-config-airbnb-with-typescript`
    (vuejs/eslint-config-airbnb#63).
- `@vue/eslint-config-typescript`:
  - Blocked by `@vue/eslint-config-airbnb-with-typescript`
    (vuejs/eslint-config-airbnb#63).
- `eslint`:
  - Blocked by `@vue/eslint-config-airbnb-with-typescript`
    (vuejs/eslint-config-airbnb#65).
  - Blocked by `@typescript-eslint/eslint-plugin` and
    `@typescript-eslint/parser`
    (typescript-eslint/typescript-eslint#8211).

These dependencies remain at their current major versions, and
their status is documented in the `package.json` to inform future
updates.

Other supporting changes:

- Moves `@types/markdown-it` to `devDependencies` which was incorrectly
  included in `dependencies`.
- Fix error in `TreeView.spec` tests, revealed by the version bump.
- Update `markdown-it` import to match the new file.
2024-04-14 22:38:47 +02:00

159 lines
4.1 KiB
TypeScript

import {
describe, it, expect,
} from 'vitest';
import { mount } from '@vue/test-utils';
import { defineComponent, shallowRef } from 'vue';
import TreeView from '@/presentation/components/Scripts/View/Tree/TreeView/TreeView.vue';
import type { TreeInputNodeData } from '@/presentation/components/Scripts/View/Tree/TreeView/Bindings/TreeInputNodeData';
import { provideDependencies } from '@/presentation/bootstrapping/DependencyProvider';
import { ApplicationContextStub } from '@tests/unit/shared/Stubs/ApplicationContextStub';
describe('TreeView', () => {
it('renders all provided root nodes correctly', async () => {
// arrange
const nodes = createSampleNodes();
const { wrapper } = mountWrapperComponent({
initialNodeData: nodes,
});
// act
await waitForStableDom(wrapper.element);
// assert
const expectedTotalRootNodes = nodes.length;
expect(wrapper.findAll('.node').length).to.equal(expectedTotalRootNodes, wrapper.html());
const rootNodeTexts = nodes.map((node) => (node.data as TreeInputMetadata).label);
rootNodeTexts.forEach((label) => {
expect(wrapper.text()).to.include(label);
});
});
// Regression test for a bug where updating the nodes prop caused uncaught exceptions.
it('updates nodes correctly when props change', async () => {
// arrange
const firstNodeLabel = 'Node 1';
const secondNodeLabel = 'Node 2';
const initialNodes: TreeInputNodeDataWithMetadata[] = [{ id: 'node1', data: { label: firstNodeLabel } }];
const updatedNodes: TreeInputNodeDataWithMetadata[] = [{ id: 'node2', data: { label: secondNodeLabel } }];
const { wrapper, nodes } = mountWrapperComponent({
initialNodeData: initialNodes,
});
// act
nodes.value = updatedNodes;
await waitForStableDom(wrapper.element);
// assert
expect(wrapper.text()).toContain(secondNodeLabel);
expect(wrapper.text()).not.toContain(firstNodeLabel);
});
});
function mountWrapperComponent(options?: {
readonly initialNodeData?: readonly TreeInputNodeDataWithMetadata[],
}) {
const nodes = shallowRef(options?.initialNodeData ?? createSampleNodes());
const wrapper = mount(defineComponent({
components: {
TreeView,
},
setup() {
provideDependencies(new ApplicationContextStub());
const selectedLeafNodeIds = shallowRef<readonly string[]>([]);
return {
nodes,
selectedLeafNodeIds,
};
},
template: `
<TreeView
:nodes="nodes"
:selectedLeafNodeIds="selectedLeafNodeIds"
>
<template v-slot:node-content="{ nodeMetadata }">
{{ nodeMetadata.label }}
</template>
</TreeView>
`,
}));
return {
wrapper,
nodes,
};
}
interface TreeInputMetadata {
readonly label: string;
}
type TreeInputNodeDataWithMetadata = TreeInputNodeData & { readonly data?: TreeInputMetadata };
function createSampleNodes(): TreeInputNodeDataWithMetadata[] {
return [
{
id: 'root1',
data: {
label: 'Root 1',
},
children: [
{
id: 'child1',
data: {
label: 'Child 1',
},
},
{
id: 'child2',
data: {
label: 'Child 2',
},
},
],
},
{
id: 'root2',
data: {
label: 'Root 2',
},
children: [
{
id: 'child3',
data: {
label: 'Child 3',
},
},
],
},
];
}
function waitForStableDom(rootElement, timeout = 3000, interval = 200): Promise<void> {
return new Promise((resolve, reject) => {
let lastTimeoutId: ReturnType<typeof setTimeout>;
const observer = new MutationObserver(() => {
if (lastTimeoutId) {
clearTimeout(lastTimeoutId);
}
lastTimeoutId = setTimeout(() => {
observer.disconnect();
resolve();
}, interval);
});
observer.observe(rootElement, {
attributes: true,
childList: true,
subtree: true,
characterData: true,
});
setTimeout(() => {
observer.disconnect();
reject(new Error('Timeout waiting for DOM to stabilize'));
}, timeout);
});
}