INTEGRITY Документация

Известные проблемы

У плагина Workers Vitest есть следующие известные проблемы:

Покрытие

Встроенное покрытие кода через V8 не поддерживается. Необходимо использовать инструментированное покрытие кода через Istanbul вместо этого. См. Документация Vitest Coverage для инструкций по настройке.

Поддельные таймеры

Vitest fake timers не применяются к симуляторам KV, R2 и кеша. Например, вы не можете сделать ключ KV просроченным, сдвинув фиктивное время.

Динамический import() инструкции с exports и Durable Objects

Динамический import() инструкции не работают внутри export default { ... } обработчиков при написании интеграционных тестов с exports.default.fetch(), либо внутри обработчиков событий Durable Object. Необходимо импортировать и вызывать обработчики напрямую, либо использовать статические import инструкции в глобальной области видимости.

WebSockets

Использование WebSockets с Durable Objects не поддерживается при изоляции хранилища на уровне файлов. Чтобы обойти это ограничение, запускайте тесты с общим хранилищем, используя --max-workers=1 --no-isolate.

Изоляция хранилища

Изоляция хранилища выполняется на уровне тестового файла. В конце каждого тестового файла средство запуска тестов отменяет все записи в хранилище, как описано в разделе документация по изоляции и параллелизму. Cloudflare рекомендует следующие действия, чтобы избежать распространённых проблем:

Дождитесь завершения всех операций с хранилищем

Всегда await все Promises, которые читают данные из служб хранения или записывают в них.

// Example: Seed data
beforeAll(async () => {
	await env.KV.put("message", "test message");
	await env.R2.put("file", "hello-world");
});

Явно сообщать об освобождении ресурса

При вызове методов RPC у Service Worker или Durable Object, возвращающих непримитивные значения (например, объекты или классы, расширяющие RpcTarget), используйте using ключевое слово, чтобы явно указать, когда ресурсы можно освободить. См. этот пример теста и обратитесь к explicit-resource-management для дополнительных сведений.

using result = await stub.getCounter();

Чтение тел ответов

При выполнении запросов через fetch или R2.get(), считайте всё тело ответа целиком, даже если вы не проверяете его содержимое. Например:

test("check if file exists", async () => {
	await env.R2.put("file", "hello-world");
	const response = await env.R2.get("file");

	expect(response).not.toBe(null);
	// Consume the response body even if you are not asserting it
	await response.text();
});

Отсутствуют свойства у ctx.exports

ctx.exports свойство предоставляет доступ к экспортам основного Worker. Интеграция Workers Vitest пытается автоматически определить эти экспорты путем статического анализа исходного кода Worker с помощью esbuild. Однако сложные конфигурации сборки, например использующие виртуальные модули или экспорт с подстановочными знаками (wildcard re-exports), которые esbuild не может отследить, могут привести к отсутствию некоторых свойств у ctx.exports объект.

Например, рассмотрим Worker, который повторно экспортирует точку входа из виртуального модуля с помощью wildcard-экспорта:

// index.ts
export * from "@virtual-module";

В этом случае любые экспортируемые значения из @virtual-module (например, MyEntrypoint) невозможно определить автоматически, поэтому оно будет отсутствовать в ctx.exports.

Чтобы обойти эту проблему, добавьте additionalExports параметр в конфигурацию Vitest:

import { cloudflareTest } from "@cloudflare/vitest-plugin";
import { defineConfig } from "vitest/config";

export default defineConfig({
	plugins: [
		cloudflareTest({
			wrangler: { configPath: "./wrangler.jsonc" },
			additionalExports: {
				MyEntrypoint: "WorkerEntrypoint",
			},
		}),
	],
});

additionalExports параметр представляет собой карту (map), в которой ключами служат имена экспортов, а значениями тип экспорта ("WorkerEntrypoint", "DurableObject", или "WorkflowEntrypoint").

Разрешение модулей

Если вы столкнулись с проблемами разрешения модулей, такими как: Error: Cannot use require() to import an ES Module или Error: No such module, вы можете объединить эти зависимости с помощью deps.optimizer параметр:

import { cloudflareTest } from "@cloudflare/vitest-plugin";
import { defineConfig } from "vitest/config";

export default defineConfig({
	plugins: [
		cloudflareTest({
			// ...
		}),
	],
	test: {
		deps: {
			optimizer: {
				ssr: {
					enabled: true,
					include: ["your-package-name"],
				},
			},
		},
	},
});

Пример можно найти в Рецепты страницу.

Импорт модулей из глобального файла настройки

Хотя Vitest настроен на разрешение пакетов для workerd среда выполнения запускает ваш глобальный файл настройки в окружении Node.js. Это может вызвать проблемы при импорте таких пакетов, как Postgres.js, который экспортирует версию без Node для workerd. Чтобы обойти эту проблему, можно создать обёртку, которая использует SSR загрузчик модулей Vite для импорта глобального файла настройки при нужных условиях. Затем настройте конфигурацию Vitest так, чтобы она указывала на эту обёртку. Например:

// File: global-setup-wrapper.ts
import { createServer } from "vite";

// Import the actual global setup file with the correct setup
const mod = await viteImport("./global-setup.ts");

export default mod.default;

// Helper to import the file with default node setup
async function viteImport(file: string) {
	const server = await createServer({
		root: import.meta.dirname,
		configFile: false,
		server: { middlewareMode: true, hmr: false, watch: null, ws: false },
		optimizeDeps: { noDiscovery: true },
		clearScreen: false,
	});
	const mod = await server.ssrLoadModule(file);
	await server.close();
	return mod;
}
// File: vitest.config.ts
import { cloudflareTest } from "@cloudflare/vitest-plugin";
import { defineConfig } from "vitest/config";

export default defineConfig({
	plugins: [
		cloudflareTest({
			// ...
		}),
	],
	test: {
		// Replace the globalSetup with the wrapper file
		globalSetup: ["./global-setup-wrapper.ts"],
	},
});