From c53c7360b78611e4efcd86c426f552cf3d6eabec Mon Sep 17 00:00:00 2001 From: pooya parsa Date: Fri, 11 Feb 2022 14:22:58 +0100 Subject: [PATCH] feat: `@nuxt/test-utils` (#2952) Co-authored-by: Anthony Fu --- package.json | 1 + packages/test-utils/README.md | 3 + packages/test-utils/build.config.ts | 15 ++ packages/test-utils/package.json | 35 ++++ packages/test-utils/src/browser.ts | 44 +++++ packages/test-utils/src/context.ts | 36 ++++ packages/test-utils/src/index.ts | 5 + packages/test-utils/src/nuxt.ts | 63 +++++++ packages/test-utils/src/server.ts | 63 +++++++ packages/test-utils/src/setup/index.ts | 71 ++++++++ packages/test-utils/src/setup/jest.ts | 13 ++ packages/test-utils/src/setup/vitest.ts | 9 + packages/test-utils/src/types.ts | 38 +++++ test/examples/hello-world.test.ts | 19 +++ yarn.lock | 216 +++++++++++++++++++++++- 15 files changed, 627 insertions(+), 4 deletions(-) create mode 100644 packages/test-utils/README.md create mode 100644 packages/test-utils/build.config.ts create mode 100644 packages/test-utils/package.json create mode 100644 packages/test-utils/src/browser.ts create mode 100644 packages/test-utils/src/context.ts create mode 100644 packages/test-utils/src/index.ts create mode 100644 packages/test-utils/src/nuxt.ts create mode 100644 packages/test-utils/src/server.ts create mode 100644 packages/test-utils/src/setup/index.ts create mode 100644 packages/test-utils/src/setup/jest.ts create mode 100644 packages/test-utils/src/setup/vitest.ts create mode 100644 packages/test-utils/src/types.ts create mode 100644 test/examples/hello-world.test.ts diff --git a/package.json b/package.json index ee875c7c5a..766c1a4831 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "test:bridge:webpack": "TEST_BRIDGE=1 yarn test:presets", "test:bridge:vite": "TEST_BRIDGE_VITE=1 TEST_BRIDGE=1 yarn test:presets", "test:unit": "vitest packages", + "test:utils": "vitest run test/examples", "version": "yarn && git add yarn.lock" }, "resolutions": { diff --git a/packages/test-utils/README.md b/packages/test-utils/README.md new file mode 100644 index 0000000000..fec2807b96 --- /dev/null +++ b/packages/test-utils/README.md @@ -0,0 +1,3 @@ +# Nuxt Test Utils + +Test utilities for Nuxt. diff --git a/packages/test-utils/build.config.ts b/packages/test-utils/build.config.ts new file mode 100644 index 0000000000..9b21f94154 --- /dev/null +++ b/packages/test-utils/build.config.ts @@ -0,0 +1,15 @@ +import { defineBuildConfig } from 'unbuild' + +export default defineBuildConfig({ + declaration: true, + entries: [ + 'src/index' + ], + dependencies: [ + ], + externals: [ + 'vitest', + 'playwright', + 'playwright-core' + ] +}) diff --git a/packages/test-utils/package.json b/packages/test-utils/package.json new file mode 100644 index 0000000000..a6f86dbe54 --- /dev/null +++ b/packages/test-utils/package.json @@ -0,0 +1,35 @@ +{ + "name": "@nuxt/test-utils", + "version": "3.0.0", + "repository": "nuxt/framework", + "license": "MIT", + "type": "module", + "exports": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "prepack": "unbuild" + }, + "dependencies": { + "@nuxt/kit": "3.0.0", + "@nuxt/schema": "3.0.0", + "defu": "^5.0.1", + "execa": "^6.0.0", + "get-port-please": "^2.2.0", + "jiti": "^1.12.15", + "ohmyfetch": "^0.4.15" + }, + "devDependencies": { + "playwright": "^1.18.0", + "unbuild": "latest", + "vitest": "^0.3.2" + }, + "peerDependencies": { + "vue": "3.2.29" + }, + "engines": { + "node": "^14.16.0 || ^16.11.0 || ^17.0.0" + } +} diff --git a/packages/test-utils/src/browser.ts b/packages/test-utils/src/browser.ts new file mode 100644 index 0000000000..9338358fe6 --- /dev/null +++ b/packages/test-utils/src/browser.ts @@ -0,0 +1,44 @@ +import type { Browser, BrowserContextOptions } from 'playwright' +import { useTestContext } from './context' +import { url } from './server' + +export async function createBrowser () { + const ctx = useTestContext() + + let playwright: typeof import('playwright') + try { + playwright = await import('playwright') + } catch { + /* istanbul ignore next */ + throw new Error(` + The dependency 'playwright' not found. + Please run 'yarn add --dev playwright' or 'npm install --save-dev playwright' + `) + } + + const { type, launch } = ctx.options.browserOptions + if (!playwright[type]) { + throw new Error(`Invalid browser '${type}'`) + } + + ctx.browser = await playwright[type].launch(launch) +} + +export async function getBrowser (): Promise { + const ctx = useTestContext() + if (!ctx.browser) { + await createBrowser() + } + return ctx.browser +} + +export async function createPage (path?: string, options?: BrowserContextOptions) { + const browser = await getBrowser() + const page = await browser.newPage(options) + + if (path) { + await page.goto(url(path)) + } + + return page +} diff --git a/packages/test-utils/src/context.ts b/packages/test-utils/src/context.ts new file mode 100644 index 0000000000..016df63f6f --- /dev/null +++ b/packages/test-utils/src/context.ts @@ -0,0 +1,36 @@ +import { resolve } from 'path' +import defu from 'defu' +import type { TestContext, TestOptions, TestRunner } from './types' + +let currentContext: TestContext + +export function createTestContext (options: Partial): TestContext { + const _options: Partial = defu(options, { + testDir: resolve(process.cwd(), 'test'), + fixture: 'fixture', + configFile: 'nuxt.config', + setupTimeout: 60000, + server: options.browser, + build: options.browser || options.server, + nuxtConfig: {}, + // TODO: auto detect based on process.env + runner: 'vitest', + browserOptions: { + type: 'chromium' + } + }) + + return setTestContext({ options: _options as TestOptions }) +} + +export function useTestContext (): TestContext { + if (!currentContext) { + throw new Error('No context is available. (Forgot calling setup or createContext?)') + } + return currentContext +} + +export function setTestContext (context: TestContext): TestContext { + currentContext = context + return currentContext +} diff --git a/packages/test-utils/src/index.ts b/packages/test-utils/src/index.ts new file mode 100644 index 0000000000..fda71ddb41 --- /dev/null +++ b/packages/test-utils/src/index.ts @@ -0,0 +1,5 @@ +export * from './browser' +export * from './context' +export * from './nuxt' +export * from './server' +export * from './setup' diff --git a/packages/test-utils/src/nuxt.ts b/packages/test-utils/src/nuxt.ts new file mode 100644 index 0000000000..91c24b1713 --- /dev/null +++ b/packages/test-utils/src/nuxt.ts @@ -0,0 +1,63 @@ +import { existsSync, promises as fsp } from 'fs' +import { resolve } from 'path' +import * as _kit from '@nuxt/kit' +import { useTestContext } from './context' + +// @ts-ignore type cast +const kit: typeof _kit = _kit.default || _kit + +const isNuxtApp = (dir: string) => { + return existsSync(dir) && ( + existsSync(resolve(dir, 'pages')) || + existsSync(resolve(dir, 'nuxt.config.js')) || + existsSync(resolve(dir, 'nuxt.config.ts')) + ) +} + +const resolveRootDir = () => { + const { options } = useTestContext() + + const dirs = [ + options.rootDir, + resolve(options.testDir, options.fixture), + process.cwd() + ] + + for (const dir of dirs) { + if (dir && isNuxtApp(dir)) { + return dir + } + } + + throw new Error('Invalid nuxt app. (Please explicitly set `options.rootDir` pointing to a valid nuxt app)') +} + +export async function loadFixture () { + const ctx = useTestContext() + + ctx.options.rootDir = resolveRootDir() + + const randomId = Math.random().toString(36).substr(2, 8) + const buildDir = resolve(ctx.options.rootDir, '.nuxt', randomId) + Object.assign(ctx.options.nuxtConfig, { + buildDir, + nitro: { + output: { + dir: resolve(buildDir, 'output') + } + } + }) + + ctx.nuxt = await kit.loadNuxt({ + rootDir: ctx.options.rootDir, + config: ctx.options.nuxtConfig, + configFile: ctx.options.configFile + }) + + await fsp.mkdir(ctx.nuxt.options.buildDir, { recursive: true }) +} + +export async function buildFixture () { + const ctx = useTestContext() + await kit.buildNuxt(ctx.nuxt) +} diff --git a/packages/test-utils/src/server.ts b/packages/test-utils/src/server.ts new file mode 100644 index 0000000000..9eb62eac72 --- /dev/null +++ b/packages/test-utils/src/server.ts @@ -0,0 +1,63 @@ +import { resolve } from 'path' +import { createServer, AddressInfo } from 'net' +import { execa } from 'execa' +import { getPort } from 'get-port-please' +import { fetch as _fetch, $fetch as _$fetch, FetchOptions } from 'ohmyfetch' +import { useTestContext } from './context' + +// TODO: use the export from `get-port-please` +function checkPort (port: number, host: string): Promise { + return new Promise((resolve) => { + const server = createServer() + server.unref() + server.on('error', () => { resolve(false) }) + server.listen(port, host, () => { + const { port } = server.address() as AddressInfo + server.close(() => { resolve(port) }) + }) + }) +} + +export async function listen () { + const ctx = useTestContext() + const host = process.env.HOST || '0.0.0.0' + const port = await getPort({ host }) + + ctx.url = 'http://localhost:' + port + execa('node', [ + // @ts-ignore + resolve(ctx.nuxt.options.nitro.output.dir, 'server/index.mjs') + ], { + env: { + PORT: String(port), + NODE_ENV: 'test' + } + }) + + const TRIES = 50 + const DELAY = 100 + + for (let i = TRIES; i; i--) { + await new Promise(resolve => setTimeout(resolve, DELAY)) + // wait until port is in used + if (await checkPort(port, host) === false) { + return + } + } +} + +export function fetch (path: string, options?: any) { + return _fetch(url(path), options) +} + +export function $fetch (path: string, options?: FetchOptions) { + return _$fetch(url(path), options) +} + +export function url (path: string) { + const ctx = useTestContext() + if (!ctx.url) { + throw new Error('url is not availabe (is server option enabled?)') + } + return ctx.url + path +} diff --git a/packages/test-utils/src/setup/index.ts b/packages/test-utils/src/setup/index.ts new file mode 100644 index 0000000000..743d09e387 --- /dev/null +++ b/packages/test-utils/src/setup/index.ts @@ -0,0 +1,71 @@ +import { createTestContext, setTestContext } from '../context' +import { loadFixture, buildFixture } from '../nuxt' +import { listen } from '../server' +import { createBrowser } from '../browser' +import type { TestHooks, TestOptions } from '../types' +import setupJest from './jest' +import setupVitest from './vitest' + +export const setupMaps = { + jest: setupJest, + vitest: setupVitest +} + +export function createTest (options: Partial): TestHooks { + const ctx = createTestContext(options) + + const beforeEach = () => { + setTestContext(ctx) + } + + const afterEach = () => { + setTestContext(undefined) + } + + const afterAll = async () => { + if (ctx.nuxt && ctx.nuxt.options.dev) { + await ctx.nuxt.close() + } + if (ctx.browser) { + await ctx.browser.close() + } + } + + const setup = async () => { + if (ctx.options.fixture) { + await loadFixture() + } + + if (ctx.options.build) { + await buildFixture() + } + + if (ctx.options.server) { + await listen() + } + + if (ctx.options.waitFor) { + await (new Promise(resolve => setTimeout(resolve, ctx.options.waitFor))) + } + + if (ctx.options.browser) { + await createBrowser() + } + } + + return { + beforeEach, + afterEach, + afterAll, + setup, + ctx + } +} + +export async function setup (options: Partial) { + const hooks = createTest(options) + + const setupFn = setupMaps[hooks.ctx.options.runner] + + await setupFn(hooks) +} diff --git a/packages/test-utils/src/setup/jest.ts b/packages/test-utils/src/setup/jest.ts new file mode 100644 index 0000000000..f3eda619db --- /dev/null +++ b/packages/test-utils/src/setup/jest.ts @@ -0,0 +1,13 @@ +import type { TestHooks } from '../types' + +export default function setupJest (hooks: TestHooks) { + // TODO: add globals existing check to provide better error message + // @ts-expect-error jest types + test('setup', hooks.setup, 60000) + // @ts-expect-error jest types + beforeEach(hooks.beforeEach) + // @ts-expect-error jest types + afterEach(hooks.afterEach) + // @ts-expect-error jest types + afterAll(hooks.afterAll) +} diff --git a/packages/test-utils/src/setup/vitest.ts b/packages/test-utils/src/setup/vitest.ts new file mode 100644 index 0000000000..8114506749 --- /dev/null +++ b/packages/test-utils/src/setup/vitest.ts @@ -0,0 +1,9 @@ +import type { TestHooks } from '../types' + +export default async function setupVitest (hooks: TestHooks) { + const vitest = await import('vitest') + vitest.test('setup nuxt', hooks.setup, 60000) + vitest.beforeEach(hooks.beforeEach) + vitest.afterEach(hooks.afterEach) + vitest.afterAll(hooks.afterAll) +} diff --git a/packages/test-utils/src/types.ts b/packages/test-utils/src/types.ts new file mode 100644 index 0000000000..7d10c41c8c --- /dev/null +++ b/packages/test-utils/src/types.ts @@ -0,0 +1,38 @@ +import type { Nuxt, NuxtConfig } from '@nuxt/schema' +import type { Browser, LaunchOptions } from 'playwright' + +export type TestRunner = 'vitest' | 'jest' + +export interface TestOptions { + testDir: string + fixture: string + configFile: string + rootDir: string + buildDir: string + nuxtConfig: NuxtConfig + build: boolean + setupTimeout: number + waitFor: number + browser: boolean + runner: TestRunner + browserOptions: { + type: 'chromium' | 'firefox' | 'webkit' + launch?: LaunchOptions + } + server: boolean +} + +export interface TestContext { + options: TestOptions + nuxt?: Nuxt + browser?: Browser + url?: string +} + +export interface TestHooks { + beforeEach: () => void + afterEach: () => void + afterAll: () => void + setup: () => void + ctx: TestContext +} diff --git a/test/examples/hello-world.test.ts b/test/examples/hello-world.test.ts new file mode 100644 index 0000000000..2f259c9e97 --- /dev/null +++ b/test/examples/hello-world.test.ts @@ -0,0 +1,19 @@ +import { fileURLToPath } from 'url' +import { resolve } from 'path' +import { describe, expect, it } from 'vitest' +// TODO: Should import from @nuxt/test-utils +import { setup, $fetch } from '../../packages/test-utils/src' + +const examplesDir = fileURLToPath(new URL('../../examples', import.meta.url)) + +await setup({ + rootDir: resolve(examplesDir, 'hello-world'), + runner: 'vitest', + server: true +}) + +describe('examples:hello-world', () => { + it('Render hello world test', async () => { + expect(await $fetch('/')).to.contain('Hello Nuxt 3!') + }) +}) diff --git a/yarn.lock b/yarn.lock index 60f17c8813..04f0544b72 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3168,6 +3168,25 @@ __metadata: languageName: node linkType: hard +"@nuxt/test-utils@workspace:packages/test-utils": + version: 0.0.0-use.local + resolution: "@nuxt/test-utils@workspace:packages/test-utils" + dependencies: + "@nuxt/kit": 3.0.0 + "@nuxt/schema": 3.0.0 + defu: ^5.0.1 + execa: ^6.0.0 + get-port-please: ^2.2.0 + jiti: ^1.12.15 + ohmyfetch: ^0.4.15 + playwright: ^1.18.0 + unbuild: latest + vitest: ^0.3.2 + peerDependencies: + vue: 3.2.29 + languageName: unknown + linkType: soft + "@nuxt/types@npm:^2.15.8": version: 2.15.8 resolution: "@nuxt/types@npm:2.15.8" @@ -4612,6 +4631,15 @@ __metadata: languageName: node linkType: hard +"@types/yauzl@npm:^2.9.1": + version: 2.9.2 + resolution: "@types/yauzl@npm:2.9.2" + dependencies: + "@types/node": "*" + checksum: dfb49abe82605615712fc694eaa4f7068fe30aa03f38c085e2c2e74408beaad30471d36da9654a811482ece2ea4405575fd99b19c0aa327ed2a9736b554bbf43 + languageName: node + linkType: hard + "@typescript-eslint/eslint-plugin@npm:^5.1.0": version: 5.11.0 resolution: "@typescript-eslint/eslint-plugin@npm:5.11.0" @@ -6685,7 +6713,7 @@ __metadata: languageName: node linkType: hard -"buffer-crc32@npm:^0.2.1, buffer-crc32@npm:^0.2.13": +"buffer-crc32@npm:^0.2.1, buffer-crc32@npm:^0.2.13, buffer-crc32@npm:~0.2.3": version: 0.2.13 resolution: "buffer-crc32@npm:0.2.13" checksum: 06252347ae6daca3453b94e4b2f1d3754a3b146a111d81c68924c22d91889a40623264e95e67955b1cb4a68cbedf317abeabb5140a9766ed248973096db5ce1c @@ -7525,6 +7553,13 @@ __metadata: languageName: node linkType: hard +"commander@npm:^8.2.0": + version: 8.3.0 + resolution: "commander@npm:8.3.0" + checksum: 0f82321821fc27b83bd409510bb9deeebcfa799ff0bf5d102128b500b7af22872c0c92cb6a0ebc5a4cf19c6b550fba9cedfa7329d18c6442a625f851377bacf0 + languageName: node + linkType: hard + "commander@npm:~9.0.0": version: 9.0.0 resolution: "commander@npm:9.0.0" @@ -9872,6 +9907,13 @@ __metadata: languageName: node linkType: hard +"escape-string-regexp@npm:^2.0.0": + version: 2.0.0 + resolution: "escape-string-regexp@npm:2.0.0" + checksum: 9f8a2d5743677c16e85c810e3024d54f0c8dea6424fad3c79ef6666e81dd0846f7437f5e729dfcdac8981bc9e5294c39b4580814d114076b8d36318f46ae4395 + languageName: node + linkType: hard + "escape-string-regexp@npm:^4.0.0": version: 4.0.0 resolution: "escape-string-regexp@npm:4.0.0" @@ -10638,6 +10680,23 @@ __metadata: languageName: node linkType: hard +"extract-zip@npm:^2.0.1": + version: 2.0.1 + resolution: "extract-zip@npm:2.0.1" + dependencies: + "@types/yauzl": ^2.9.1 + debug: ^4.1.1 + get-stream: ^5.1.0 + yauzl: ^2.10.0 + dependenciesMeta: + "@types/yauzl": + optional: true + bin: + extract-zip: cli.js + checksum: 8cbda9debdd6d6980819cc69734d874ddd71051c9fe5bde1ef307ebcedfe949ba57b004894b585f758b7c9eeeea0e3d87f2dda89b7d25320459c2c9643ebb635 + languageName: node + linkType: hard + "extsprintf@npm:1.3.0": version: 1.3.0 resolution: "extsprintf@npm:1.3.0" @@ -10695,6 +10754,15 @@ __metadata: languageName: node linkType: hard +"fd-slicer@npm:~1.1.0": + version: 1.1.0 + resolution: "fd-slicer@npm:1.1.0" + dependencies: + pend: ~1.2.0 + checksum: c8585fd5713f4476eb8261150900d2cb7f6ff2d87f8feb306ccc8a1122efd152f1783bdb2b8dc891395744583436bfd8081d8e63ece0ec8687eeefea394d4ff2 + languageName: node + linkType: hard + "fetch-blob@npm:^3.1.2, fetch-blob@npm:^3.1.4": version: 3.1.4 resolution: "fetch-blob@npm:3.1.4" @@ -11294,6 +11362,15 @@ __metadata: languageName: node linkType: hard +"get-stream@npm:^5.1.0": + version: 5.2.0 + resolution: "get-stream@npm:5.2.0" + dependencies: + pump: ^3.0.0 + checksum: 8bc1a23174a06b2b4ce600df38d6c98d2ef6d84e020c1ddad632ad75bac4e092eeb40e4c09e0761c35fc2dbc5e7fff5dab5e763a383582c4a167dd69a905bd12 + languageName: node + linkType: hard + "get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": version: 6.0.1 resolution: "get-stream@npm:6.0.1" @@ -12912,6 +12989,13 @@ __metadata: languageName: node linkType: hard +"jpeg-js@npm:^0.4.2": + version: 0.4.3 + resolution: "jpeg-js@npm:0.4.3" + checksum: 9e5bacc9135efa7da340b62e81fa56fab0c8516ef617228758132af5b7d31b516cc6e1500cdffb82d3161629be341be980099f2b37eb76b81e26db6e3e848c77 + languageName: node + linkType: hard + "js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" @@ -15972,6 +16056,13 @@ __metadata: languageName: node linkType: hard +"pend@npm:~1.2.0": + version: 1.2.0 + resolution: "pend@npm:1.2.0" + checksum: 6c72f5243303d9c60bd98e6446ba7d30ae29e3d56fdb6fae8767e8ba6386f33ee284c97efe3230a0d0217e2b1723b8ab490b1bbf34fcbb2180dbc8a9de47850d + languageName: node + linkType: hard + "performance-now@npm:^2.1.0": version: 2.1.0 resolution: "performance-now@npm:2.1.0" @@ -16057,6 +16148,43 @@ __metadata: languageName: node linkType: hard +"playwright-core@npm:=1.18.1": + version: 1.18.1 + resolution: "playwright-core@npm:1.18.1" + dependencies: + commander: ^8.2.0 + debug: ^4.1.1 + extract-zip: ^2.0.1 + https-proxy-agent: ^5.0.0 + jpeg-js: ^0.4.2 + mime: ^2.4.6 + pngjs: ^5.0.0 + progress: ^2.0.3 + proper-lockfile: ^4.1.1 + proxy-from-env: ^1.1.0 + rimraf: ^3.0.2 + socks-proxy-agent: ^6.1.0 + stack-utils: ^2.0.3 + ws: ^7.4.6 + yauzl: ^2.10.0 + yazl: ^2.5.1 + bin: + playwright: cli.js + checksum: 7b3d5a228bb0559eece28c82f6aa963a9f3cb68f56e470feb968fe414e4f0074edb9a2d9b27266f4927be31d57203cdfb739e57d5b30744d5f30800a8025b3b8 + languageName: node + linkType: hard + +"playwright@npm:^1.18.0": + version: 1.18.1 + resolution: "playwright@npm:1.18.1" + dependencies: + playwright-core: =1.18.1 + bin: + playwright: cli.js + checksum: a50c4c3b04c0f4c2698898003b5cba8d24af0de01e13e9af754d34af4d928d5397704ab7e84a593fb614d538fe72e307f69f01971219857118cd619ee3f91c88 + languageName: node + linkType: hard + "pluralize@npm:^8.0.0": version: 8.0.0 resolution: "pluralize@npm:8.0.0" @@ -16064,6 +16192,13 @@ __metadata: languageName: node linkType: hard +"pngjs@npm:^5.0.0": + version: 5.0.0 + resolution: "pngjs@npm:5.0.0" + checksum: 04e912cc45fb9601564e2284efaf0c5d20d131d9b596244f8a6789fc6cdb6b18d2975a6bbf7a001858d7e159d5c5c5dd7b11592e97629b7137f7f5cef05904c8 + languageName: node + linkType: hard + "pnp-webpack-plugin@npm:^1.6.4, pnp-webpack-plugin@npm:^1.7.0": version: 1.7.0 resolution: "pnp-webpack-plugin@npm:1.7.0" @@ -17703,6 +17838,13 @@ __metadata: languageName: node linkType: hard +"progress@npm:^2.0.3": + version: 2.0.3 + resolution: "progress@npm:2.0.3" + checksum: f67403fe7b34912148d9252cb7481266a354bd99ce82c835f79070643bb3c6583d10dbcfda4d41e04bbc1d8437e9af0fb1e1f2135727878f5308682a579429b7 + languageName: node + linkType: hard + "promise-inflight@npm:^1.0.1": version: 1.0.1 resolution: "promise-inflight@npm:1.0.1" @@ -17729,7 +17871,7 @@ __metadata: languageName: node linkType: hard -"proper-lockfile@npm:^4.1.2": +"proper-lockfile@npm:^4.1.1, proper-lockfile@npm:^4.1.2": version: 4.1.2 resolution: "proper-lockfile@npm:4.1.2" dependencies: @@ -17754,6 +17896,13 @@ __metadata: languageName: node linkType: hard +"proxy-from-env@npm:^1.1.0": + version: 1.1.0 + resolution: "proxy-from-env@npm:1.1.0" + checksum: ed7fcc2ba0a33404958e34d95d18638249a68c430e30fcb6c478497d72739ba64ce9810a24f53a7d921d0c065e5b78e3822759800698167256b04659366ca4d4 + languageName: node + linkType: hard + "prr@npm:~1.0.1": version: 1.0.1 resolution: "prr@npm:1.0.1" @@ -19208,7 +19357,7 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^6.0.0": +"socks-proxy-agent@npm:^6.0.0, socks-proxy-agent@npm:^6.1.0": version: 6.1.1 resolution: "socks-proxy-agent@npm:6.1.1" dependencies: @@ -19463,6 +19612,15 @@ __metadata: languageName: node linkType: hard +"stack-utils@npm:^2.0.3": + version: 2.0.5 + resolution: "stack-utils@npm:2.0.5" + dependencies: + escape-string-regexp: ^2.0.0 + checksum: 76b69da0f5b48a34a0f93c98ee2a96544d2c4ca2557f7eef5ddb961d3bdc33870b46f498a84a7c4f4ffb781df639840e7ebf6639164ed4da5e1aeb659615b9c7 + languageName: node + linkType: hard + "stackframe@npm:^1.1.1": version: 1.2.0 resolution: "stackframe@npm:1.2.0" @@ -21216,6 +21374,37 @@ __metadata: languageName: node linkType: hard +"vitest@npm:^0.3.2": + version: 0.3.2 + resolution: "vitest@npm:0.3.2" + dependencies: + "@types/chai": ^4.3.0 + "@types/chai-subset": ^1.3.3 + chai: ^4.3.6 + local-pkg: ^0.4.1 + tinypool: ^0.1.1 + tinyspy: ^0.2.10 + vite: ">=2.7.13" + peerDependencies: + "@vitest/ui": "*" + c8: "*" + happy-dom: "*" + jsdom: "*" + peerDependenciesMeta: + "@vitest/ui": + optional: true + c8: + optional: true + happy-dom: + optional: true + jsdom: + optional: true + bin: + vitest: vitest.mjs + checksum: 858dd3d16f7583b77bca0ab7810d4b1efdba92392cd6a2d97a62cf26ef1c041bda08e15e1694f69d1654bb7aaaab65d52c3684e03a8c364e5edab261f992e218 + languageName: node + linkType: hard + "vm-browserify@npm:^1.0.1": version: 1.1.2 resolution: "vm-browserify@npm:1.1.2" @@ -21934,7 +22123,7 @@ __metadata: languageName: node linkType: hard -"ws@npm:^7.3.1, ws@npm:^7.5.0": +"ws@npm:^7.3.1, ws@npm:^7.4.6, ws@npm:^7.5.0": version: 7.5.7 resolution: "ws@npm:7.5.7" peerDependencies: @@ -22073,6 +22262,25 @@ __metadata: languageName: node linkType: hard +"yauzl@npm:^2.10.0": + version: 2.10.0 + resolution: "yauzl@npm:2.10.0" + dependencies: + buffer-crc32: ~0.2.3 + fd-slicer: ~1.1.0 + checksum: 7f21fe0bbad6e2cb130044a5d1d0d5a0e5bf3d8d4f8c4e6ee12163ce798fee3de7388d22a7a0907f563ac5f9d40f8699a223d3d5c1718da90b0156da6904022b + languageName: node + linkType: hard + +"yazl@npm:^2.5.1": + version: 2.5.1 + resolution: "yazl@npm:2.5.1" + dependencies: + buffer-crc32: ~0.2.3 + checksum: daec5154b5485d8621bfea359e905ddca0b2f068430a4aa0a802bf5d67391157a383e0c2767acccbf5964264851da643bc740155a9458e2d8dce55b94c1cc2ed + languageName: node + linkType: hard + "yocto-queue@npm:^0.1.0": version: 0.1.0 resolution: "yocto-queue@npm:0.1.0"