Brunobkr/llama.cpp_AlgMor24_github
ΩFFFΣLLIa • llama.cpp • AlgMor24 ██████╗ ███████╗███████╗███████╗██╗ ██╗ ██╗ █████╗ ██╔═══██╗██╔════╝██╔════╝██╔════╝██║ ██║ ██║██╔══██╗ ██║ ██║█████╗ █████╗ █████╗ ██║ ██║ ██║███████║ ██║ ██║██╔══╝ ██╔══╝ ██╔══╝ ██║ ██║ ██║██╔══██║ ╚██████╔╝██║ ██║ ███████╗███████╗███████╗██║██║ ██║ ╚═════╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝╚══════╝╚═╝╚═╝ ╚═╝ High-Performance LLM / VLM Inference & Autonomous Agentic Ecosystem… See the full description on the dataset page: https://huggingface.co/datasets/Brunobkr/llama.cpp_AlgMor24_github.
03.1k
1import { asLocator, parseKeyDef, resolveScreenshotPath, assertBrowserApiWrite, assertBrowserFileAccess, defineBrowserProvider } from '@vitest/browser';2export { defineBrowserCommand } from '@vitest/browser';3import { createManualModuleSource } from '@vitest/mocker/node';4import c from 'tinyrainbow';5import { createDebugger, isCSSRequest } from 'vitest/node';6import { mkdir, unlink } from 'node:fs/promises';7import { fileURLToPath } from 'node:url';8 9const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;10function normalizeWindowsPath(input = "") {11 if (!input) {12 return input;13 }14 return input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());15}16 17const _UNC_REGEX = /^[/\\]{2}/;18const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;19const _DRIVE_LETTER_RE = /^[A-Za-z]:$/;20const _ROOT_FOLDER_RE = /^\/([A-Za-z]:)?$/;21const normalize = function(path) {22 if (path.length === 0) {23 return ".";24 }25 path = normalizeWindowsPath(path);26 const isUNCPath = path.match(_UNC_REGEX);27 const isPathAbsolute = isAbsolute(path);28 const trailingSeparator = path[path.length - 1] === "/";29 path = normalizeString(path, !isPathAbsolute);30 if (path.length === 0) {31 if (isPathAbsolute) {32 return "/";33 }34 return trailingSeparator ? "./" : ".";35 }36 if (trailingSeparator) {37 path += "/";38 }39 if (_DRIVE_LETTER_RE.test(path)) {40 path += "/";41 }42 if (isUNCPath) {43 if (!isPathAbsolute) {44 return `//./${path}`;45 }46 return `//${path}`;47 }48 return isPathAbsolute && !isAbsolute(path) ? `/${path}` : path;49};50function cwd() {51 if (typeof process !== "undefined" && typeof process.cwd === "function") {52 return process.cwd().replace(/\\/g, "/");53 }54 return "/";55}56const resolve = function(...arguments_) {57 arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));58 let resolvedPath = "";59 let resolvedAbsolute = false;60 for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {61 const path = index >= 0 ? arguments_[index] : cwd();62 if (!path || path.length === 0) {63 continue;64 }65 resolvedPath = `${path}/${resolvedPath}`;66 resolvedAbsolute = isAbsolute(path);67 }68 resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute);69 if (resolvedAbsolute && !isAbsolute(resolvedPath)) {70 return `/${resolvedPath}`;71 }72 return resolvedPath.length > 0 ? resolvedPath : ".";73};74function normalizeString(path, allowAboveRoot) {75 let res = "";76 let lastSegmentLength = 0;77 let lastSlash = -1;78 let dots = 0;79 let char = null;80 for (let index = 0; index <= path.length; ++index) {81 if (index < path.length) {82 char = path[index];83 } else if (char === "/") {84 break;85 } else {86 char = "/";87 }88 if (char === "/") {89 if (lastSlash === index - 1 || dots === 1) ; else if (dots === 2) {90 if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {91 if (res.length > 2) {92 const lastSlashIndex = res.lastIndexOf("/");93 if (lastSlashIndex === -1) {94 res = "";95 lastSegmentLength = 0;96 } else {97 res = res.slice(0, lastSlashIndex);98 lastSegmentLength = res.length - 1 - res.lastIndexOf("/");99 }100 lastSlash = index;101 dots = 0;102 continue;103 } else if (res.length > 0) {104 res = "";105 lastSegmentLength = 0;106 lastSlash = index;107 dots = 0;108 continue;109 }110 }111 if (allowAboveRoot) {112 res += res.length > 0 ? "/.." : "..";113 lastSegmentLength = 2;114 }115 } else {116 if (res.length > 0) {117 res += `/${path.slice(lastSlash + 1, index)}`;118 } else {119 res = path.slice(lastSlash + 1, index);120 }121 lastSegmentLength = index - lastSlash - 1;122 }123 lastSlash = index;124 dots = 0;125 } else if (char === "." && dots !== -1) {126 ++dots;127 } else {128 dots = -1;129 }130 }131 return res;132}133const isAbsolute = function(p) {134 return _IS_ABSOLUTE_RE.test(p);135};136const relative = function(from, to) {137 const _from = resolve(from).replace(_ROOT_FOLDER_RE, "$1").split("/");138 const _to = resolve(to).replace(_ROOT_FOLDER_RE, "$1").split("/");139 if (_to[0][1] === ":" && _from[0][1] === ":" && _from[0] !== _to[0]) {140 return _to.join("/");141 }142 const _fromCopy = [..._from];143 for (const segment of _fromCopy) {144 if (_to[0] !== segment) {145 break;146 }147 _from.shift();148 _to.shift();149 }150 return [..._from.map(() => ".."), ..._to].join("/");151};152const dirname = function(p) {153 const segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);154 if (segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0])) {155 segments[0] += "/";156 }157 return segments.join("/") || (isAbsolute(p) ? "/" : ".");158};159const basename = function(p, extension) {160 const segments = normalizeWindowsPath(p).split("/");161 let lastSegment = "";162 for (let i = segments.length - 1; i >= 0; i--) {163 const val = segments[i];164 if (val) {165 lastSegment = val;166 break;167 }168 }169 return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;170};171 172// strip iframe locator part from the trace description e.g.173// - locator('[data-vitest="true"]').contentFrame().getByRole('button')174// ⇓175// - getByRole('button')176function getDescribedLocator(context, selector) {177 const locator = context.iframe.locator(selector);178 return typeof locator.describe === "function" ? locator.describe(asLocator("javascript", selector)) : locator;179}180 181const clear = async (context, selector) => {182 const element = getDescribedLocator(context, selector);183 await element.clear();184};185 186const click = async (context, selector, options = {}) => {187 await getDescribedLocator(context, selector).click(options);188};189const dblClick = async (context, selector, options = {}) => {190 await getDescribedLocator(context, selector).dblclick(options);191};192const tripleClick = async (context, selector, options = {}) => {193 await getDescribedLocator(context, selector).click({194 ...options,195 clickCount: 3196 });197};198 199const dragAndDrop = async (context, source, target, options_) => {200 const frame = await context.frame();201 await frame.dragAndDrop(source, target, options_);202};203 204const fill = async (context, selector, text, options = {}) => {205 const element = getDescribedLocator(context, selector);206 await element.fill(text, options);207};208 209const hover = async (context, selector, options = {}) => {210 await getDescribedLocator(context, selector).hover(options);211};212 213const keyboard = async (context, text, state) => {214 const frame = await context.frame();215 await frame.evaluate(focusIframe);216 const pressed = new Set(state.unreleased);217 await keyboardImplementation(pressed, context.provider, context.sessionId, text, async () => {218 const frame = await context.frame();219 await frame.evaluate(selectAll);220 }, true);221 return { unreleased: Array.from(pressed) };222};223const keyboardCleanup = async (context, state) => {224 const { provider, sessionId } = context;225 if (!state.unreleased) {226 return;227 }228 const page = provider.getPage(sessionId);229 for (const key of state.unreleased) {230 await page.keyboard.up(key);231 }232};233// fallback to insertText for non US key234// https://github.com/microsoft/playwright/blob/50775698ae13642742f2a1e8983d1d686d7f192d/packages/playwright-core/src/server/input.ts#L95235const VALID_KEYS = new Set([236 "Escape",237 "F1",238 "F2",239 "F3",240 "F4",241 "F5",242 "F6",243 "F7",244 "F8",245 "F9",246 "F10",247 "F11",248 "F12",249 "Backquote",250 "`",251 "~",252 "Digit1",253 "1",254 "!",255 "Digit2",256 "2",257 "@",258 "Digit3",259 "3",260 "#",261 "Digit4",262 "4",263 "$",264 "Digit5",265 "5",266 "%",267 "Digit6",268 "6",269 "^",270 "Digit7",271 "7",272 "&",273 "Digit8",274 "8",275 "*",276 "Digit9",277 "9",278 "(",279 "Digit0",280 "0",281 ")",282 "Minus",283 "-",284 "_",285 "Equal",286 "=",287 "+",288 "Backslash",289 "\\",290 "|",291 "Backspace",292 "Tab",293 "KeyQ",294 "q",295 "Q",296 "KeyW",297 "w",298 "W",299 "KeyE",300 "e",301 "E",302 "KeyR",303 "r",304 "R",305 "KeyT",306 "t",307 "T",308 "KeyY",309 "y",310 "Y",311 "KeyU",312 "u",313 "U",314 "KeyI",315 "i",316 "I",317 "KeyO",318 "o",319 "O",320 "KeyP",321 "p",322 "P",323 "BracketLeft",324 "[",325 "{",326 "BracketRight",327 "]",328 "}",329 "CapsLock",330 "KeyA",331 "a",332 "A",333 "KeyS",334 "s",335 "S",336 "KeyD",337 "d",338 "D",339 "KeyF",340 "f",341 "F",342 "KeyG",343 "g",344 "G",345 "KeyH",346 "h",347 "H",348 "KeyJ",349 "j",350 "J",351 "KeyK",352 "k",353 "K",354 "KeyL",355 "l",356 "L",357 "Semicolon",358 ";",359 ":",360 "Quote",361 "'",362 "\"",363 "Enter",364 "\n",365 "\r",366 "ShiftLeft",367 "Shift",368 "KeyZ",369 "z",370 "Z",371 "KeyX",372 "x",373 "X",374 "KeyC",375 "c",376 "C",377 "KeyV",378 "v",379 "V",380 "KeyB",381 "b",382 "B",383 "KeyN",384 "n",385 "N",386 "KeyM",387 "m",388 "M",389 "Comma",390 ",",391 "<",392 "Period",393 ".",394 ">",395 "Slash",396 "/",397 "?",398 "ShiftRight",399 "ControlLeft",400 "Control",401 "MetaLeft",402 "Meta",403 "AltLeft",404 "Alt",405 "Space",406 " ",407 "AltRight",408 "AltGraph",409 "MetaRight",410 "ContextMenu",411 "ControlRight",412 "PrintScreen",413 "ScrollLock",414 "Pause",415 "PageUp",416 "PageDown",417 "Insert",418 "Delete",419 "Home",420 "End",421 "ArrowLeft",422 "ArrowUp",423 "ArrowRight",424 "ArrowDown",425 "NumLock",426 "NumpadDivide",427 "NumpadMultiply",428 "NumpadSubtract",429 "Numpad7",430 "Numpad8",431 "Numpad9",432 "Numpad4",433 "Numpad5",434 "Numpad6",435 "NumpadAdd",436 "Numpad1",437 "Numpad2",438 "Numpad3",439 "Numpad0",440 "NumpadDecimal",441 "NumpadEnter",442 "ControlOrMeta"443]);444async function keyboardImplementation(pressed, provider, sessionId, text, selectAll, skipRelease) {445 const page = provider.getPage(sessionId);446 const actions = parseKeyDef(text);447 for (const { releasePrevious, releaseSelf, repeat, keyDef } of actions) {448 const key = keyDef.key;449 // TODO: instead of calling down/up for each key, join non special450 // together, and call `type` once for all non special keys,451 // and then `press` for special keys452 if (pressed.has(key)) {453 if (VALID_KEYS.has(key)) {454 await page.keyboard.up(key);455 }456 pressed.delete(key);457 }458 if (!releasePrevious) {459 if (key === "selectall") {460 await selectAll();461 continue;462 }463 for (let i = 1; i <= repeat; i++) {464 if (VALID_KEYS.has(key)) {465 await page.keyboard.down(key);466 } else {467 await page.keyboard.insertText(key);468 }469 }470 if (releaseSelf) {471 if (VALID_KEYS.has(key)) {472 await page.keyboard.up(key);473 }474 } else {475 pressed.add(key);476 }477 }478 }479 if (!skipRelease && pressed.size) {480 for (const key of pressed) {481 if (VALID_KEYS.has(key)) {482 await page.keyboard.up(key);483 }484 }485 }486 return { pressed };487}488function focusIframe() {489 if (!document.activeElement || document.activeElement.ownerDocument !== document || document.activeElement === document.body) {490 window.focus();491 }492}493function selectAll() {494 const element = document.activeElement;495 if (element && typeof element.select === "function") {496 element.select();497 }498}499 500/**501* Takes a screenshot using the provided browser context and returns a buffer and the expected screenshot path.502*503* **Note**: the returned `path` indicates where the screenshot *might* be found.504* It is not guaranteed to exist, especially if `options.save` is `false`.505*506* @throws {Error} If the function is not called within a test or if the browser provider does not support screenshots.507*/508async function takeScreenshot(context, name, options) {509 if (!context.testPath) {510 throw new Error(`Cannot take a screenshot without a test path`);511 }512 const path = resolveScreenshotPath(context.testPath, name, context.project.config, options.path);513 // playwright does not need a screenshot path if we don't intend to save it514 let savePath;515 if (options.save) {516 savePath = normalize(path);517 assertBrowserApiWrite(context.project, savePath);518 assertBrowserFileAccess(context.project, savePath);519 await mkdir(dirname(savePath), { recursive: true });520 }521 const mask = options.mask?.map((selector) => getDescribedLocator(context, selector));522 if (options.element) {523 const { element: selector, ...config } = options;524 const element = getDescribedLocator(context, selector);525 const buffer = await element.screenshot({526 ...config,527 mask,528 path: savePath529 });530 return {531 buffer,532 path533 };534 }535 const buffer = await getDescribedLocator(context, "body").screenshot({536 ...options,537 mask,538 path: savePath539 });540 return {541 buffer,542 path543 };544}545 546const selectOptions = async (context, selector, userValues, options = {}) => {547 const value = userValues;548 const selectElement = getDescribedLocator(context, selector);549 const values = await Promise.all(value.map(async (v) => {550 if (typeof v === "string") {551 return v;552 }553 const elementHandler = await getDescribedLocator(context, v.element).elementHandle();554 if (!elementHandler) {555 throw new Error(`Element not found: ${v.element}`);556 }557 return elementHandler;558 }));559 await selectElement.selectOption(values, options);560};561 562const tab = async (context, options = {}) => {563 const page = context.page;564 await page.keyboard.press(options.shift === true ? "Shift+Tab" : "Tab");565};566 567const startTracing = async ({ context, project, provider, sessionId }) => {568 if (isPlaywrightProvider(provider)) {569 if (provider.tracingContexts.has(sessionId)) {570 return;571 }572 provider.tracingContexts.add(sessionId);573 const options = project.config.browser.trace;574 await context.tracing.start({575 screenshots: options.screenshots ?? true,576 snapshots: options.snapshots ?? true,577 sources: options.sources ?? true578 }).catch(() => {579 provider.tracingContexts.delete(sessionId);580 });581 return;582 }583 throw new TypeError(`The ${provider.name} provider does not support tracing.`);584};585const startChunkTrace = async (command, { name, title }) => {586 const { provider, sessionId, testPath, context } = command;587 if (!testPath) {588 throw new Error(`stopChunkTrace cannot be called outside of the test file.`);589 }590 if (isPlaywrightProvider(provider)) {591 if (!provider.tracingContexts.has(sessionId)) {592 await startTracing(command);593 }594 const path = resolveTracesPath(command, name);595 provider.pendingTraces.set(path, sessionId);596 await context.tracing.startChunk({597 name,598 title599 });600 return;601 }602 throw new TypeError(`The ${provider.name} provider does not support tracing.`);603};604const stopChunkTrace = async (context, { name }) => {605 if (isPlaywrightProvider(context.provider)) {606 const path = resolveTracesPath(context, name);607 assertBrowserApiWrite(context.project, path);608 assertBrowserFileAccess(context.project, path);609 context.provider.pendingTraces.delete(path);610 await context.context.tracing.stopChunk({ path });611 return { tracePath: path };612 }613 throw new TypeError(`The ${context.provider.name} provider does not support tracing.`);614};615const markTrace = async (context, payload) => {616 if (isPlaywrightProvider(context.provider)) {617 // skip if tracing is not active618 // this is only safe guard and this isn't expected to happen since619 // runner already checks if tracing is active before sending this command620 if (!context.provider.tracingContexts.has(context.sessionId)) {621 return;622 }623 const { name, selector, stack } = payload;624 const location = parseLocation(context, stack);625 // mark trace via group/groupEnd with dummy calls to force snapshot.626 // https://github.com/microsoft/playwright/issues/39308627 await context.context.tracing.group(name, { location });628 try {629 if (selector) {630 const locator = getDescribedLocator(context, selector);631 if (typeof locator._expect === "function") {632 await locator._expect("to.be.attached", {633 isNot: false,634 timeout: 1635 });636 } else {637 await context.page.evaluate(() => 0);638 }639 } else {640 await context.page.evaluate(() => 0);641 }642 } catch {}643 await context.context.tracing.groupEnd();644 return;645 }646 throw new TypeError(`The ${context.provider.name} provider does not support tracing.`);647};648const groupTraceStart = async (context, payload) => {649 if (isPlaywrightProvider(context.provider)) {650 if (!context.provider.tracingContexts.has(context.sessionId)) {651 return;652 }653 const { name, stack } = payload;654 const location = parseLocation(context, stack);655 await context.context.tracing.group(name, { location });656 return;657 }658 throw new TypeError(`The ${context.provider.name} provider does not support tracing.`);659};660const groupTraceEnd = async (context) => {661 if (isPlaywrightProvider(context.provider)) {662 if (!context.provider.tracingContexts.has(context.sessionId)) {663 return;664 }665 await context.context.tracing.groupEnd();666 return;667 }668 throw new TypeError(`The ${context.provider.name} provider does not support tracing.`);669};670function parseLocation(context, stack) {671 if (!stack) {672 return;673 }674 const parsedStacks = context.project.browser.parseStacktrace(stack);675 return parsedStacks[0];676}677function resolveTracesPath({ testPath, project }, name) {678 if (!testPath) {679 throw new Error(`This command can only be called inside a test file.`);680 }681 const options = project.config.browser.trace;682 const sanitizedName = `${project.name.replace(/[^a-z0-9]/gi, "-")}-${name}.trace.zip`;683 if (options.tracesDir) {684 return resolve(options.tracesDir, sanitizedName);685 }686 const dir = dirname(testPath);687 const base = basename(testPath);688 return resolve(dir, "__traces__", base, `${project.name.replace(/[^a-z0-9]/gi, "-")}-${name}.trace.zip`);689}690const deleteTracing = async (context, { traces }) => {691 if (!context.testPath) {692 throw new Error(`stopChunkTrace cannot be called outside of the test file.`);693 }694 if (isPlaywrightProvider(context.provider)) {695 for (const trace of traces) {696 assertBrowserApiWrite(context.project, trace);697 assertBrowserFileAccess(context.project, trace);698 }699 return Promise.all(traces.map((trace) => unlink(trace).catch((err) => {700 if (err.code === "ENOENT") {701 // Ignore the error if the file doesn't exist702 return;703 }704 // Re-throw other errors705 throw err;706 })));707 }708 throw new Error(`provider ${context.provider.name} is not supported`);709};710const annotateTraces = async ({ project }, { testId, traces }) => {711 const vitest = project.vitest;712 await Promise.all(traces.map((trace) => {713 assertBrowserApiWrite(project, trace);714 assertBrowserFileAccess(project, trace);715 const entity = vitest.state.getReportedEntityById(testId);716 const location = entity?.location ? {717 file: entity.module.moduleId,718 line: entity.location.line,719 column: entity.location.column720 } : undefined;721 return vitest._testRun.recordArtifact(testId, {722 type: "internal:annotation",723 annotation: {724 message: relative(project.config.root, trace),725 type: "traces",726 attachment: {727 path: trace,728 contentType: "application/octet-stream"729 },730 location731 },732 location733 });734 }));735};736function isPlaywrightProvider(provider) {737 return provider.name === "playwright";738}739 740const type = async (context, selector, text, options = {}) => {741 const { skipClick = false, skipAutoClose = false } = options;742 const unreleased = new Set(Reflect.get(options, "unreleased") ?? []);743 const element = getDescribedLocator(context, selector);744 if (!skipClick) {745 await element.focus();746 }747 await keyboardImplementation(unreleased, context.provider, context.sessionId, text, () => element.selectText(), skipAutoClose);748 return { unreleased: Array.from(unreleased) };749};750 751const upload = async (context, selector, files, options) => {752 const testPath = context.testPath;753 if (!testPath) {754 throw new Error(`Cannot upload files outside of a test`);755 }756 const root = context.project.config.root;757 const playwrightFiles = files.map((file) => {758 if (typeof file === "string") {759 const filepath = resolve(root, file);760 assertBrowserFileAccess(context.project, filepath);761 return filepath;762 }763 return {764 name: file.name,765 mimeType: file.mimeType,766 buffer: Buffer.from(file.base64, "base64")767 };768 });769 await getDescribedLocator(context, selector).setInputFiles(playwrightFiles, options);770};771 772const wheel = async (context, selector, options) => {773 await hover(context, selector);774 const times = options.times ?? 1;775 const deltaX = options.delta.x ?? 0;776 const deltaY = options.delta.y ?? 0;777 for (let count = 0; count < times; count += 1) {778 await context.page.mouse.wheel(deltaX, deltaY);779 }780};781 782var commands = {783 __vitest_upload: upload,784 __vitest_click: click,785 __vitest_dblClick: dblClick,786 __vitest_tripleClick: tripleClick,787 __vitest_wheel: wheel,788 __vitest_takeScreenshot: takeScreenshot,789 __vitest_type: type,790 __vitest_clear: clear,791 __vitest_fill: fill,792 __vitest_tab: tab,793 __vitest_keyboard: keyboard,794 __vitest_selectOptions: selectOptions,795 __vitest_dragAndDrop: dragAndDrop,796 __vitest_hover: hover,797 __vitest_cleanup: keyboardCleanup,798 __vitest_deleteTracing: deleteTracing,799 __vitest_startChunkTrace: startChunkTrace,800 __vitest_startTracing: startTracing,801 __vitest_stopChunkTrace: stopChunkTrace,802 __vitest_annotateTraces: annotateTraces,803 __vitest_markTrace: markTrace,804 __vitest_groupTraceStart: groupTraceStart,805 __vitest_groupTraceEnd: groupTraceEnd806};807 808const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");809const distRoot = resolve(pkgRoot, "dist");810 811const debug = createDebugger("vitest:browser:playwright");812const playwrightBrowsers = [813 "firefox",814 "webkit",815 "chromium"816];817// Enable intercepting of requests made by service workers - experimental API is only available in Chromium based browsers818// Requests from service workers are only available on context.route() https://playwright.dev/docs/service-workers-experimental819process.env.PW_EXPERIMENTAL_SERVICE_WORKER_NETWORK_EVENTS ??= "1";820function playwright(options = {}) {821 return defineBrowserProvider({822 name: "playwright",823 supportedBrowser: playwrightBrowsers,824 options,825 providerFactory(project) {826 return new PlaywrightBrowserProvider(project, options);827 }828 });829}830class PlaywrightBrowserProvider {831 name = "playwright";832 supportsParallelism = true;833 browser = null;834 persistentContext = null;835 contexts = new Map();836 pages = new Map();837 mocker;838 browserName;839 browserPromise = null;840 closing = false;841 tracingContexts = new Set();842 pendingTraces = new Map();843 initScripts = [resolve(distRoot, "locators.js")];844 constructor(project, options) {845 this.project = project;846 this.options = options;847 this.browserName = project.config.browser.name;848 this.mocker = this.createMocker();849 for (const [name, command] of Object.entries(commands)) {850 project.browser.registerCommand(name, command);851 }852 // make sure the traces are finished if the test hangs853 process.on("SIGTERM", this.onSIGTERM);854 }855 onSIGTERM = () => {856 if (!this.browser) {857 return;858 }859 const promises = [];860 for (const [trace, contextId] of this.pendingTraces.entries()) {861 promises.push((() => {862 const context = this.contexts.get(contextId);863 return context?.tracing.stopChunk({ path: trace });864 })());865 }866 return Promise.allSettled(promises);867 };868 async openBrowser(openBrowserOptions) {869 await this._throwIfClosing();870 if (this.browserPromise) {871 debug?.("[%s] the browser is resolving, reusing the promise", this.browserName);872 return this.browserPromise;873 }874 if (this.browser) {875 debug?.("[%s] the browser is resolved, reusing it", this.browserName);876 return this.browser;877 }878 this.browserPromise = (async () => {879 const options = this.project.config.browser;880 const playwright = await import('playwright');881 const launchOptions = {882 ...this.options.launchOptions,883 headless: options.headless884 };885 if (typeof options.trace === "object" && options.trace.tracesDir) {886 launchOptions.tracesDir = options.trace?.tracesDir;887 }888 const inspector = this.project.vitest.config.inspector;889 if (inspector.enabled) {890 // NodeJS equivalent defaults: https://nodejs.org/en/learn/getting-started/debugging#enable-inspector891 const port = inspector.port || 9229;892 const host = inspector.host || "127.0.0.1";893 launchOptions.args ||= [];894 launchOptions.args.push(`--remote-debugging-port=${port}`);895 if (host !== "localhost" && host !== "127.0.0.1" && host !== "::1") {896 this.project.vitest.logger.warn(`Custom inspector host "${host}" will be ignored. Chromium only allows remote debugging on localhost.`);897 }898 this.project.vitest.logger.log(`Debugger listening on ws://127.0.0.1:${port}`);899 }900 // start Vitest UI maximized only on supported browsers901 if (this.project.config.browser.ui && this.browserName === "chromium") {902 if (!launchOptions.args) {903 launchOptions.args = [];904 }905 if (!launchOptions.args.includes("--start-maximized") && !launchOptions.args.includes("--start-fullscreen")) {906 launchOptions.args.push("--start-maximized");907 }908 }909 debug?.("[%s] initializing the browser with launch options: %O", this.browserName, launchOptions);910 if (this.options.connectOptions) {911 let { wsEndpoint, headers = {}, ...connectOptions } = this.options.connectOptions;912 if ("x-playwright-launch-options" in headers) {913 this.project.vitest.logger.warn(c.yellow("Detected \"x-playwright-launch-options\" in connectOptions.headers. Provider config launchOptions is ignored."));914 } else {915 headers = {916 ...headers,917 "x-playwright-launch-options": JSON.stringify(launchOptions)918 };919 }920 this.browser = await playwright[this.browserName].connect(wsEndpoint, {921 ...connectOptions,922 headers923 });924 this.browserPromise = null;925 return this.browser;926 }927 let persistentContextOption = this.options.persistentContext;928 if (persistentContextOption && openBrowserOptions.parallel) {929 persistentContextOption = false;930 this.project.vitest.logger.warn(c.yellow(`The persistentContext option is ignored because tests are running in parallel.`));931 }932 if (persistentContextOption) {933 const userDataDir = typeof this.options.persistentContext === "string" ? this.options.persistentContext : "./node_modules/.cache/vitest-playwright-user-data";934 // TODO: how to avoid default "about" page?935 this.persistentContext = await playwright[this.browserName].launchPersistentContext(userDataDir, {936 ...launchOptions,937 ...this.getContextOptions()938 });939 this.browser = this.persistentContext.browser();940 } else {941 this.browser = await playwright[this.browserName].launch(launchOptions);942 }943 this.browserPromise = null;944 return this.browser;945 })();946 return this.browserPromise;947 }948 createMocker() {949 const idPredicates = new Map();950 const sessionIds = new Map();951 function createPredicate(url) {952 const moduleUrl = new URL(url, "http://localhost");953 const predicate = (url) => {954 if (url.searchParams.has("_vitest_original")) {955 return false;956 }957 // different modules, ignore request958 if (url.pathname !== moduleUrl.pathname) {959 return false;960 }961 url.searchParams.delete("t");962 url.searchParams.delete("v");963 url.searchParams.delete("import");964 // different search params, ignore request965 if (url.searchParams.size !== moduleUrl.searchParams.size) {966 return false;967 }968 // check that all search params are the same969 for (const [param, value] of url.searchParams.entries()) {970 if (moduleUrl.searchParams.get(param) !== value) {971 return false;972 }973 }974 return true;975 };976 return {977 url: moduleUrl.href,978 predicate979 };980 }981 function predicateKey(sessionId, url) {982 return `${sessionId}:${url}`;983 }984 return {985 register: async (sessionId, module) => {986 const page = this.getPage(sessionId);987 const { url: moduleUrl, predicate } = createPredicate(module.url);988 const key = predicateKey(sessionId, moduleUrl);989 const existingPredicate = idPredicates.get(key);990 if (existingPredicate) {991 await page.context().unroute(existingPredicate);992 }993 const ids = sessionIds.get(sessionId) ?? new Set();994 ids.add(moduleUrl);995 sessionIds.set(sessionId, ids);996 idPredicates.set(key, predicate);997 await page.context().route(predicate, async (route) => {998 if (module.type === "manual") {999 const exports$1 = Object.keys(await module.resolve());1000 const body = createManualModuleSource(module.url, exports$1);1001 return route.fulfill({1002 body,1003 headers: getHeaders(this.project.browser.vite.config)1004 });1005 }1006 // webkit doesn't support redirect responses1007 // https://github.com/microsoft/playwright/issues/183181008 const isWebkit = this.browserName === "webkit";1009 if (isWebkit) {1010 let url;1011 if (module.type === "redirect") {1012 const redirect = new URL(module.redirect);1013 url = redirect.href.slice(redirect.origin.length);1014 } else {1015 const request = new URL(route.request().url());1016 request.searchParams.set("mock", module.type);1017 url = request.href.slice(request.origin.length);1018 }1019 const result = await this.project.browser.vite.transformRequest(url).catch(() => null);1020 if (!result) {1021 return route.continue();1022 }1023 let content = result.code;1024 if (result.map && "version" in result.map && result.map.mappings) {1025 const type = isDirectCSSRequest(url) ? "css" : "js";1026 content = getCodeWithSourcemap(type, content.toString(), result.map);1027 }1028 return route.fulfill({1029 body: content,1030 headers: getHeaders(this.project.browser.vite.config)1031 });1032 }1033 if (module.type === "redirect") {1034 return route.fulfill({1035 status: 302,1036 headers: { Location: module.redirect }1037 });1038 } else if (module.type === "automock" || module.type === "autospy") {1039 const url = new URL(route.request().url());1040 url.searchParams.set("mock", module.type);1041 return route.fulfill({1042 status: 302,1043 headers: { Location: url.href }1044 });1045 } else ;1046 });1047 },1048 delete: async (sessionId, id) => {1049 const page = this.getPage(sessionId);1050 const key = predicateKey(sessionId, id);1051 const predicate = idPredicates.get(key);1052 if (predicate) {1053 await page.context().unroute(predicate).finally(() => idPredicates.delete(key));1054 }1055 },1056 clear: async (sessionId) => {1057 const page = this.getPage(sessionId);1058 const ids = sessionIds.get(sessionId) ?? new Set();1059 const promises = [...ids].map((id) => {1060 const key = predicateKey(sessionId, id);1061 const predicate = idPredicates.get(key);1062 if (predicate) {1063 return page.context().unroute(predicate).finally(() => idPredicates.delete(key));1064 }1065 return null;1066 });1067 await Promise.all(promises).finally(() => sessionIds.delete(sessionId));1068 }1069 };1070 }1071 async createContext(sessionId, openBrowserOptions) {1072 await this._throwIfClosing();1073 if (this.contexts.has(sessionId)) {1074 debug?.("[%s][%s] the context already exists, reusing it", sessionId, this.browserName);1075 return this.contexts.get(sessionId);1076 }1077 const browser = await this.openBrowser(openBrowserOptions);1078 await this._throwIfClosing(browser);1079 const actionTimeout = this.options.actionTimeout;1080 const options = this.getContextOptions();1081 // TODO: investigate the consequences for Vitest 51082 // else {1083 // if UI is disabled, keep the iframe scale to 11084 // options.viewport ??= this.project.config.browser.viewport1085 // }1086 const context = this.persistentContext ?? await browser.newContext(options);1087 await this._throwIfClosing(context);1088 if (actionTimeout != null) {1089 context.setDefaultTimeout(actionTimeout);1090 }1091 debug?.("[%s][%s] the context is ready", sessionId, this.browserName);1092 this.contexts.set(sessionId, context);1093 return context;1094 }1095 getContextOptions() {1096 const contextOptions = this.options.contextOptions ?? {};1097 const options = {1098 ...contextOptions,1099 ignoreHTTPSErrors: true1100 };1101 if (this.project.config.browser.ui) {1102 options.viewport = null;1103 }1104 return options;1105 }1106 getPage(sessionId) {1107 const page = this.pages.get(sessionId);1108 if (!page) {1109 throw new Error(`Page "${sessionId}" not found in ${this.browserName} browser.`);1110 }1111 return page;1112 }1113 getCommandsContext(sessionId) {1114 const page = this.getPage(sessionId);1115 return {1116 page,1117 context: this.contexts.get(sessionId),1118 frame() {1119 return new Promise((resolve, reject) => {1120 const frame = page.frame("vitest-iframe");1121 if (frame) {1122 return resolve(frame);1123 }1124 const timeout = setTimeout(() => {1125 const err = new Error(`Cannot find "vitest-iframe" on the page. This is a bug in Vitest, please report it.`);1126 reject(err);1127 }, 1e3).unref();1128 page.on("frameattached", (frame) => {1129 clearTimeout(timeout);1130 resolve(frame);1131 });1132 });1133 },1134 get iframe() {1135 return page.frameLocator("[data-vitest=\"true\"]");1136 }1137 };1138 }1139 async openBrowserPage(sessionId, options) {1140 await this._throwIfClosing();1141 if (this.pages.has(sessionId)) {1142 debug?.("[%s][%s] the page already exists, closing the old one", sessionId, this.browserName);1143 const page = this.pages.get(sessionId);1144 await page.close();1145 this.pages.delete(sessionId);1146 }1147 const context = await this.createContext(sessionId, options);1148 const page = await context.newPage();1149 debug?.("[%s][%s] the page is ready", sessionId, this.browserName);1150 await this._throwIfClosing(page);1151 this.pages.set(sessionId, page);1152 if (process.env.VITEST_PW_DEBUG) {1153 page.on("requestfailed", (request) => {1154 console.error("[PW Error]", request.resourceType(), "request failed for", request.url(), "url:", request.failure()?.errorText);1155 });1156 }1157 return page;1158 }1159 async openPage(sessionId, url, options) {1160 debug?.("[%s][%s] creating the browser page for %s", sessionId, this.browserName, url);1161 const browserPage = await this.openBrowserPage(sessionId, options);1162 debug?.("[%s][%s] browser page is created, opening %s", sessionId, this.browserName, url);1163 await browserPage.goto(url, { timeout: 0 });1164 await this._throwIfClosing(browserPage);1165 }1166 async _throwIfClosing(disposable) {1167 if (this.closing) {1168 debug?.("[%s] provider was closed, cannot perform the action on %s", this.browserName, String(disposable));1169 await disposable?.close();1170 this.pages.clear();1171 this.contexts.clear();1172 this.browser = null;1173 this.browserPromise = null;1174 throw new Error(`[vitest] The provider was closed.`);1175 }1176 }1177 async getCDPSession(sessionid) {1178 const page = this.getPage(sessionid);1179 const cdp = await page.context().newCDPSession(page);1180 return {1181 send: cdp.send.bind(cdp),1182 on: cdp.on.bind(cdp),1183 off: cdp.off.bind(cdp),1184 once: cdp.once.bind(cdp)1185 };1186 }1187 async close() {1188 process.off("SIGTERM", this.onSIGTERM);1189 debug?.("[%s] closing provider", this.browserName);1190 this.closing = true;1191 if (this.browserPromise) {1192 await this.browserPromise;1193 this.browserPromise = null;1194 }1195 const browser = this.browser;1196 this.browser = null;1197 await Promise.all([...this.pages.values()].map((p) => p.close()));1198 this.pages.clear();1199 if (this.persistentContext) {1200 await this.persistentContext.close();