@vitest/browser
Version:
Browser running for Vitest
274 lines (270 loc) • 8.49 kB
JavaScript
import { server, page } from '@vitest/browser/context';
import { I as Ivya, e as getByRoleSelector, c as getByAltTextSelector, f as getByLabelSelector, b as getByPlaceholderSelector, d as getByTestIdSelector, a as getByTextSelector, g as getByTitleSelector, h as getElementError } from './public-utils-J4vwTaki.js';
function ensureAwaited(promise) {
const test = (/* @__PURE__ */ getWorkerState()).current;
if (!test || test.type !== "test") {
return promise();
}
let awaited = false;
const sourceError = new Error("STACK_TRACE_ERROR");
test.onFinished ??= [];
test.onFinished.push(() => {
if (!awaited) {
const error = new Error(
`The call was not awaited. This method is asynchronous and must be awaited; otherwise, the call will not start to avoid unhandled rejections.`
);
error.stack = sourceError.stack?.replace(sourceError.message, error.message);
throw error;
}
});
let promiseResult;
return {
then(onFulfilled, onRejected) {
awaited = true;
return (promiseResult ||= promise()).then(onFulfilled, onRejected);
},
catch(onRejected) {
return (promiseResult ||= promise()).catch(onRejected);
},
finally(onFinally) {
return (promiseResult ||= promise()).finally(onFinally);
},
[Symbol.toStringTag]: "Promise"
};
}
// @__NO_SIDE_EFFECTS__
function getBrowserState() {
return window.__vitest_browser_runner__;
}
// @__NO_SIDE_EFFECTS__
function getWorkerState() {
const state = window.__vitest_worker__;
if (!state) {
throw new Error("Worker state is not found. This is an issue with Vitest. Please, open an issue.");
}
return state;
}
// @__NO_SIDE_EFFECTS__
function convertElementToCssSelector(element) {
if (!element || !(element instanceof Element)) {
throw new Error(
`Expected DOM element to be an instance of Element, received ${typeof element}`
);
}
return getUniqueCssSelector(element);
}
function escapeIdForCSSSelector(id) {
return id.split("").map((char) => {
const code = char.charCodeAt(0);
if (char === " " || char === "#" || char === "." || char === ":" || char === "[" || char === "]" || char === ">" || char === "+" || char === "~" || char === "\\") {
return `\\${char}`;
} else if (code >= 65536) {
return `\\${code.toString(16).toUpperCase().padStart(6, "0")} `;
} else if (code < 32 || code === 127) {
return `\\${code.toString(16).toUpperCase().padStart(2, "0")} `;
} else if (code >= 128) {
return `\\${code.toString(16).toUpperCase().padStart(2, "0")} `;
} else {
return char;
}
}).join("");
}
function getUniqueCssSelector(el) {
const path = [];
let parent;
let hasShadowRoot = false;
while (parent = getParent(el)) {
if (parent.shadowRoot) {
hasShadowRoot = true;
}
const tag = el.tagName;
if (el.id) {
path.push(`#${escapeIdForCSSSelector(el.id)}`);
} else if (!el.nextElementSibling && !el.previousElementSibling) {
path.push(tag.toLowerCase());
} else {
let index = 0;
let sameTagSiblings = 0;
let elementIndex = 0;
for (const sibling of parent.children) {
index++;
if (sibling.tagName === tag) {
sameTagSiblings++;
}
if (sibling === el) {
elementIndex = index;
}
}
if (sameTagSiblings > 1) {
path.push(`${tag.toLowerCase()}:nth-child(${elementIndex})`);
} else {
path.push(tag.toLowerCase());
}
}
el = parent;
}
return `${(/* @__PURE__ */ getBrowserState()).provider === "webdriverio" && hasShadowRoot ? ">>>" : ""}${path.reverse().join(" > ")}`;
}
function getParent(el) {
const parent = el.parentNode;
if (parent instanceof ShadowRoot) {
return parent.host;
}
return parent;
}
const selectorEngine = Ivya.create({
browser: ((name) => {
switch (name) {
case "edge":
case "chrome":
return "chromium";
case "safari":
return "webkit";
default:
return name;
}
})(server.config.browser.name),
testIdAttribute: server.config.browser.locators.testIdAttribute
});
class Locator {
_parsedSelector;
_container;
_pwSelector;
click(options = {}) {
return this.triggerCommand("__vitest_click", this.selector, options);
}
dblClick(options = {}) {
return this.triggerCommand("__vitest_dblClick", this.selector, options);
}
tripleClick(options = {}) {
return this.triggerCommand("__vitest_tripleClick", this.selector, options);
}
clear() {
return this.triggerCommand("__vitest_clear", this.selector);
}
hover(options) {
return this.triggerCommand("__vitest_hover", this.selector, options);
}
unhover(options) {
return this.triggerCommand("__vitest_hover", "html > body", options);
}
fill(text, options) {
return this.triggerCommand("__vitest_fill", this.selector, text, options);
}
async upload(files) {
const filesPromise = (Array.isArray(files) ? files : [files]).map(async (file) => {
if (typeof file === "string") {
return file;
}
const bas64String = await new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = () => reject(new Error(`Failed to read file: ${file.name}`));
reader.readAsDataURL(file);
});
return {
name: file.name,
mimeType: file.type,
base64: bas64String
};
});
return this.triggerCommand("__vitest_upload", this.selector, await Promise.all(filesPromise));
}
dropTo(target, options = {}) {
return this.triggerCommand(
"__vitest_dragAndDrop",
this.selector,
target.selector,
options
);
}
selectOptions(value) {
const values = (Array.isArray(value) ? value : [value]).map((v) => {
if (typeof v !== "string") {
const selector = "element" in v ? v.selector : selectorEngine.generateSelectorSimple(v);
return { element: selector };
}
return v;
});
return this.triggerCommand("__vitest_selectOptions", this.selector, values);
}
screenshot(options) {
return page.screenshot({
...options,
element: this
});
}
getByRole(role, options) {
return this.locator(getByRoleSelector(role, options));
}
getByAltText(text, options) {
return this.locator(getByAltTextSelector(text, options));
}
getByLabelText(text, options) {
return this.locator(getByLabelSelector(text, options));
}
getByPlaceholder(text, options) {
return this.locator(getByPlaceholderSelector(text, options));
}
getByTestId(testId) {
return this.locator(getByTestIdSelector(server.config.browser.locators.testIdAttribute, testId));
}
getByText(text, options) {
return this.locator(getByTextSelector(text, options));
}
getByTitle(title, options) {
return this.locator(getByTitleSelector(title, options));
}
query() {
const parsedSelector = this._parsedSelector || (this._parsedSelector = selectorEngine.parseSelector(this._pwSelector || this.selector));
return selectorEngine.querySelector(parsedSelector, document.documentElement, true);
}
element() {
const element = this.query();
if (!element) {
throw getElementError(this._pwSelector || this.selector, this._container || document.body);
}
return element;
}
elements() {
const parsedSelector = this._parsedSelector || (this._parsedSelector = selectorEngine.parseSelector(this._pwSelector || this.selector));
return selectorEngine.querySelectorAll(parsedSelector, document.documentElement);
}
all() {
return this.elements().map((element) => this.elementLocator(element));
}
nth(index) {
return this.locator(`nth=${index}`);
}
first() {
return this.nth(0);
}
last() {
return this.nth(-1);
}
toString() {
return this.selector;
}
toJSON() {
return this.selector;
}
get state() {
return getBrowserState();
}
get worker() {
return getWorkerState();
}
get rpc() {
return this.worker.rpc;
}
triggerCommand(command, ...args) {
const filepath = this.worker.filepath || this.worker.current?.file?.filepath || void 0;
return ensureAwaited(() => this.rpc.triggerCommand(
this.state.sessionId,
command,
filepath,
args
));
}
}
export { Locator as L, convertElementToCssSelector as c, selectorEngine as s };