@nuxt/test-utils
Version:
Test utilities for Nuxt
116 lines (115 loc) • 3.92 kB
JavaScript
import { i as wrapperSuspended, n as patchWrapperSetProps, t as cleanupAll } from "../suspended-DDMM5DdJ.mjs";
import { config, mount } from "@vue/test-utils";
import { page, server, utils } from "vitest/browser";
//#region src/browser/pure.ts
const mountedWrappers = /* @__PURE__ */ new Set();
let idx = 0;
function ensureTestIdAttribute(element) {
const attributeId = server.config.browser.locators.testIdAttribute;
if (!element.hasAttribute(attributeId)) element.setAttribute(attributeId, `__vitest_${idx++}__`);
}
/**
* `render` allows you to mount any vue component within the vitest browser mode.
*
* ```ts
* import { page } from 'vitest/browser'
* import { render } from '@nuxt/test-utils/browser'
*
* it('can render', async () => {
* const screen = await render(App, { route: '/' })
*
* const title = screen.getByRole('heading')
* await expect.element(title).toHaveTextContent('Index')
* })
*
* it('can render with page', async () => {
* const screen = await page.render(App, { route: '/' })
*
* const title = screen.getByRole('heading')
* await expect.element(title).toHaveTextContent('Index')
* })
* ```
*
* @param component the component to be tested
* @param options optional options to set up your component
*/
async function render(component, options = {}) {
const { container, baseElement, wrapper } = await mountWrapperSuspended(component, options);
ensureTestIdAttribute(container);
ensureTestIdAttribute(baseElement);
const { debug, getElementLocatorSelectors } = utils;
const renderResult = {
container,
baseElement,
locator: page.elementLocator(container),
get setupState() {
return wrapper.setupState;
},
debug: (el = container, maxLength, options) => debug(el, maxLength, options),
unmount: async () => {
wrapper.unmount();
mountedWrappers.delete(wrapper);
await mark(renderResult.locator, "nuxt.unmount", renderResult.unmount);
},
emitted: ((eventName) => wrapper.emitted(eventName)),
rerender: async (props) => {
await wrapper.setProps(props);
await mark(renderResult.locator, "nuxt.rerender", renderResult.rerender);
},
...getElementLocatorSelectors(container)
};
return renderResult;
}
function cleanup() {
mountedWrappers.forEach((wrapper) => {
wrapper.unmount();
mountedWrappers.delete(wrapper);
});
cleanupAll();
}
async function mark(locator, name, fn) {
if (!locator.mark) return;
const error = new Error(name);
if ("captureStackTrace" in Error) Error.captureStackTrace(error, fn);
return locator.mark(name, error);
}
/**
* `@vue/test-utils` mounts into a `div` of its own inside `attachTo`. Removing that div keeps the
* rendered markup a direct child of the container, so locators and snapshots see the component's
* own DOM.
*/
function unwrapNode(node) {
if (node && typeof node.replaceWith === "function") node.replaceWith(...node.childNodes);
}
async function mountWrapperSuspended(component, options = {}) {
const { container: containerOption, baseElement: baseElementOption, ...wrapperOptions } = options;
const baseElement = baseElementOption || document.body;
const createdContainer = containerOption ? void 0 : baseElement.appendChild(document.createElement("div"));
const container = containerOption || createdContainer;
const suspendedOptions = {
...wrapperOptions,
attachTo: container
};
const { wrapper, setProps, cleanup } = await wrapperSuspended(component, suspendedOptions, {
wrapperFn: mount,
suspendedHelperName: "BrowserSuspendedHelper",
clonedComponentName: "BrowserSuspendedComponent",
stubRouterLink: false
});
patchWrapperSetProps(wrapper, setProps);
const _unmount = wrapper.unmount.bind(wrapper);
wrapper.unmount = () => {
_unmount();
cleanup();
createdContainer?.remove();
};
mountedWrappers.add(wrapper);
unwrapNode(wrapper.element.parentElement);
return {
container,
baseElement,
wrapper
};
}
//#endregion
export { cleanup, config, render };