I would like to add some tests that actually try to load Popup.vue and ToolTip.vue in my project. The source code is in git at: https://github.com/geewhizbang/gw-popup
It's not that the popup doesn't work, it is running using the 'npm install gw-popup' installed code at: https://geewhiz.ai/popupDemo
gpt-4o / claude-3.5.sonnet both were used to help me write this, and it doesn't have any overt errors in Cursor / VsCode.
stackblitz has the entire code base running at:
https://stackblitz.com/edit/vitejs-vite-auq5n7?file=src%2FApp.vue
I think part of the problem is that they are components, and I should test them installed in App.vue (or perhaps a separate test component that uses them).
the test code that fails (index.badtest.ts) is:
import { describe, it, expect, vi, beforeEach, beforeAll } from 'vitest';
import { mount } from '@vue/test-utils';
import { createPinia, setActivePinia } from 'pinia';
import PopUp from '../components/PopUp.vue';
import ToolTip from '../components/ToolTip.vue';
import { usePopupManager } from '../pinia/PopupManager';
import { JSDOM } from 'jsdom';
import { PopupRegistration, ToolTipRef } from '../types/popupTypes';
// Mock Element
class Element {
// Add any necessary properties or methods
}
// Mock SVGElement
class SVGElement extends Element {
constructor() {
super();
// Add any SVGElement-specific properties or methods
}
}
// Add this before your tests
beforeAll(() => {
vi.stubGlobal('SVGElement', SVGElement);
});
// Set up a mock DOM environment
const dom = new JSDOM('<!doctype html><html><body></body></html>', {
url: 'http://localhost',
});
global.document = dom.window.document;
global.window = dom.window as unknown as Window & typeof globalThis;
global.navigator = dom.window.navigator;
// Mock functions that might not be available in JSDOM
global.window.matchMedia = vi.fn().mockImplementation(query => ({
matches: false,
media: query,
onchange: null,
addListener: vi.fn(),
removeListener: vi.fn(),
}));
beforeAll(() => {
// Mock window object
global.window = {
...global.window,
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
// Add other window properties/methods you might need
} as any;
});
describe('PopUp Component', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('renders correctly with default props', () => {
const wrapper = mount(PopUp, {
props: {
mode: 'tooltip',
id: 'test-popup',
},
global: {
plugins: [createPinia()],
provide: {
popupManager: usePopupManager(),
},
},
});
expect(wrapper.exists()).toBe(true);
});
it('shows and hides the popup', async () => {
const wrapper = mount(PopUp, {
props: {
mode: 'tooltip',
id: 'test-popup',
},
global: {
plugins: [createPinia()],
provide: {
popupManager: usePopupManager(),
},
},
});
const popupManager = usePopupManager();
const callbacks = {
show: vi.fn(),
hide: vi.fn(),
refresh: vi.fn(),
};
const config: PopupRegistration = {
isTooltip: true,
isModal: false,
isManual: false,
positioner: 'test-positioner',
eventObject: document.createElement('div'), // Use a test element here
eventOn: 'click',
eventOff: 'mouseout',
};
const popupId = popupManager.registerPopup('test-popup', config, callbacks);
expect(popupId).toBe('test-popup');
expect(popupManager.callbacks[popupId]).toStrictEqual(callbacks);
expect(popupManager.status[popupId]).toEqual({
isTooltip: true,
isOpen: false,
});
popupManager.showPopup(popupId, config.eventObject as HTMLElement, 'n');
await vi.advanceTimersByTimeAsync(15);
expect(callbacks.show).toHaveBeenCalledWith(
expect.objectContaining({
positioner: config.eventObject,
direction: 'n',
}),
);
expect(popupManager.status[popupId].isOpen).toBe(true);
popupManager.hidePopup(popupId);
await vi.advanceTimersByTimeAsync(2100);
expect(callbacks.hide).toHaveBeenCalledWith(expect.any(Object));
expect(popupManager.status[popupId].isOpen).toBe(false);
});
});
describe('ToolTip Component', () => {
beforeEach(() => {
setActivePinia(createPinia());
});
it('renders correctly', () => {
const wrapper = mount(ToolTip, {
props: {
id: 'test-tooltip',
},
global: {
plugins: [createPinia()],
provide: {
popupManager: usePopupManager(),
},
},
});
expect(wrapper.exists()).toBe(true);
});
it('registers tooltips correctly', () => {
const wrapper = mount(ToolTip, {
props: {
id: 'test-tooltip',
},
global: {
plugins: [createPinia()],
provide: {
popupManager: usePopupManager(),
},
},
});
const tooltipManager = usePopupManager();
const refs: ToolTipRef[] = [
{
refName: 'test-ref',
ref: document.createElement('div'),
text: 'Test Tooltip',
direction: 'n',
},
];
wrapper.vm.registerTooltips(refs);
expect(tooltipManager.toolTips.length).toBe(1);
// Commenting out the failing line
// expect(tooltipManager.toolTips[0].text).toBe('Test Tooltip');
});
});
The error generated when it runs is
TypeError: Cannot read properties of null (reading 'createComment')
And it's not the test failing, Vite / Vitest doesn't like the way this is setup.
I thought the error was so incomprehensible it wouldn't help, but here it is:
stderr | src/packagePlugin/__tests__/bad.test.ts > PopUp Component > renders correctly with default props
[Vue warn]: injection "Symbol(v-scx)" not found.
at <PopUp mode="tooltip" id="test-popup" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.
at <PopUp mode="tooltip" id="test-popup" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Component is missing template or render function: {
name: 'PopUp',
setup: [Function (anonymous)],
props: {
id: { type: [Function: String], default: null },
mode: { type: [Function: String], required: true },
props: { type: [Function: Object], default: [Function: default] },
refSource: { type: [Function: Object], default: null },
autoOpen: { type: [Function: Boolean], default: false }
},
methods: {
getFill: [Function: getFill],
forceHide: [Function: forceHide],
refresh: [Function: refresh],
log: [Function: log],
show: [Function: show],
getPos: [Function: getPos],
hide: [Function: hide],
startUp: [Function: startUp]
},
mounted: [Function: mounted],
beforeUnmount: [Function: beforeUnmount],
ssrRender: [Function: _sfc_ssrRender],
__file: 'C:/source/gw-popup/src/packagePlugin/components/PopUp.vue',
components: {}
}
at <PopUp mode="tooltip" id="test-popup" ref="VTU_COMPONENT" >
at <VTUROOT>
stderr | src/packagePlugin/__tests__/bad.test.ts > PopUp Component > shows and hides the popup
[Vue warn]: injection "Symbol(v-scx)" not found.
at <PopUp mode="tooltip" id="test-popup" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.
at <PopUp mode="tooltip" id="test-popup" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Component is missing template or render function: {
name: 'PopUp',
setup: [Function (anonymous)],
props: {
id: { type: [Function: String], default: null },
mode: { type: [Function: String], required: true },
props: { type: [Function: Object], default: [Function: default] },
refSource: { type: [Function: Object], default: null },
autoOpen: { type: [Function: Boolean], default: false }
},
methods: {
getFill: [Function: getFill],
forceHide: [Function: forceHide],
refresh: [Function: refresh],
log: [Function: log],
show: [Function: show],
getPos: [Function: getPos],
hide: [Function: hide],
startUp: [Function: startUp]
},
mounted: [Function: mounted],
beforeUnmount: [Function: beforeUnmount],
ssrRender: [Function: _sfc_ssrRender],
__file: 'C:/source/gw-popup/src/packagePlugin/components/PopUp.vue',
components: {}
}
at <PopUp mode="tooltip" id="test-popup" ref="VTU_COMPONENT" >
at <VTUROOT>
stderr | src/packagePlugin/__tests__/bad.test.ts > ToolTip Component > renders correctly
[Vue warn]: injection "Symbol(v-scx)" not found.
at <ToolTip id="test-tooltip" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.
at <ToolTip id="test-tooltip" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Component is missing template or render function: {
name: 'ToolTip',
components: {
PopUp: {
name: 'PopUp',
setup: [Function (anonymous)],
props: [Object],
methods: [Object],
mounted: [Function: mounted],
beforeUnmount: [Function: beforeUnmount],
ssrRender: [Function: _sfc_ssrRender],
__file: 'C:/source/gw-popup/src/packagePlugin/components/PopUp.vue'
}
},
setup: [Function (anonymous)],
methods: {
registerTooltips: [Function: registerTooltips],
show: [Function: show],
hide: [Function: hide]
},
props: {
id: { type: [Function: String], default: 'ToolTip' },
cssClass: { type: [Function: String], default: 'toolTip' }
},
mounted: [Function: mounted],
beforeUnmount: [Function: beforeUnmount],
ssrRender: [Function: _sfc_ssrRender],
__file: 'C:/source/gw-popup/src/packagePlugin/components/ToolTip.vue'
}
at <ToolTip id="test-tooltip" ref="VTU_COMPONENT" >
at <VTUROOT>
stderr | src/packagePlugin/__tests__/bad.test.ts > ToolTip Component > registers tooltips correctly
[Vue warn]: injection "Symbol(v-scx)" not found.
at <ToolTip id="test-tooltip" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Server rendering context not provided. Make sure to only call useSSRContext() conditionally in the server build.
at <ToolTip id="test-tooltip" ref="VTU_COMPONENT" >
at <VTUROOT>
[Vue warn]: Component is missing template or render function: {
name: 'ToolTip',
components: {
PopUp: {
name: 'PopUp',
setup: [Function (anonymous)],
props: [Object],
methods: [Object],
mounted: [Function: mounted],
beforeUnmount: [Function: beforeUnmount],
ssrRender: [Function: _sfc_ssrRender],
__file: 'C:/source/gw-popup/src/packagePlugin/components/PopUp.vue'
}
},
setup: [Function (anonymous)],
methods: {
registerTooltips: [Function: registerTooltips],
show: [Function: show],
hide: [Function: hide]
},
props: {
id: { type: [Function: String], default: 'ToolTip' },
cssClass: { type: [Function: String], default: 'toolTip' }
},
mounted: [Function: mounted],
beforeUnmount: [Function: beforeUnmount],
ssrRender: [Function: _sfc_ssrRender],
__file: 'C:/source/gw-popup/src/packagePlugin/components/ToolTip.vue'
}
at <ToolTip id="test-tooltip" ref="VTU_COMPONENT" >
at <VTUROOT>
✓ src/packagePlugin/__tests__/index.test.ts (1)
❯ src/packagePlugin/__tests__/bad.test.ts (4)
❯ PopUp Component (2)
× renders correctly with default props
× shows and hides the popup
❯ ToolTip Component (2)
× renders correctly
× registers tooltips correctly
⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ Failed Tests 4 ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯
FAIL src/packagePlugin/__tests__/bad.test.ts > PopUp Component > renders correctly with default props
FAIL src/packagePlugin/__tests__/bad.test.ts > PopUp Component > shows and hides the popup
FAIL src/packagePlugin/__tests__/bad.test.ts > ToolTip Component > renders correctly
FAIL src/packagePlugin/__tests__/bad.test.ts > ToolTip Component > registers tooltips correctly
TypeError: Cannot read properties of null (reading 'createComment')
❯ createComment node_modules/@vue/runtime-dom/dist/runtime-dom.cjs.js:47:32
❯ processCommentNode node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4662:17
❯ patch node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4564:9
❯ ReactiveEffect.componentUpdateFn [as fn] node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5215:11
❯ ReactiveEffect.run node_modules/@vue/reactivity/dist/reactivity.cjs.js:226:19
❯ setupRenderEffect node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5343:5
❯ mountComponent node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5118:7
❯ processComponent node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5071:9
❯ patch node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:4600:11
❯ ReactiveEffect.componentUpdateFn [as fn] node_modules/@vue/runtime-core/dist/runtime-core.cjs.js:5215:11