Probar schematics
@pbuilder/sdk/testing ofrece utilidades para probar schematics con tu ejecutor de pruebas.
Bun no es necesario para el ejemplo de factory en memoria que aparece a continuación:
se ejecuta en Node con Vitest, Jest o Rstest.
Ejecuta tu factory con runFactoryForTest y comprueba el árbol resultante — sin CLI,
sin un proceso del engine y sin archivos generados en disco.
Un primer test
Sección titulada «Un primer test»Comienza en un directorio separado para no cambiar la configuración de pruebas de tu
aplicación. Utiliza Node 26.8.1 y npm 11.19.0, las versiones usadas para verificar
el ejemplo. Crea este package.json e instala el SDK y Vitest:
{ "private": true, "type": "module"}Utiliza un factory JavaScript ESM para que el ejemplo no dependa de transformaciones de TypeScript:
import { create } from '@pbuilder/sdk/commons';
export function greetingFactory(input) { create('src/greeting.txt', { template: `Hello, ${input.name}!\n`, options: {}, });}Crea un directorio tests y añade:
import process from 'node:process';import { expect, test } from 'vitest';import { runFactoryForTest } from '@pbuilder/sdk/testing';import { greetingFactory } from '../factory.js';
test('commits a greeting through the SDK harness on Node without Bun', async () => { expect(process.versions.node).toBeDefined(); expect(process.versions.bun).toBeUndefined(); const result = await runFactoryForTest(greetingFactory, { name: 'Ada' }); expect(result.error).toBeUndefined(); expect(result.tree.get('src/greeting.txt')).toBe('Hello, Ada!\n');});import { defineConfig } from 'vitest/config';
export default defineConfig({ test: { environment: 'node', include: ['tests/vitest.test.js'] },});node node_modules/vitest/vitest.mjs runResultado esperado: una prueba aprobada. El saludo existe en el árbol de escrituras
confirmadas en memoria, no como src/greeting.txt en disco. La interpolación de JavaScript
produce el texto; esta prueba no comprueba el renderizado de plantillas del SDK.
Usar Jest o Rstest en su lugar
Sección titulada «Usar Jest o Rstest en su lugar»Conserva el mismo package.json y factory.js. Copia la prueba anterior a la ruta del
ejecutor elegido y sustituye solo su importación de expect, test; conserva las demás
importaciones y aserciones. Instala únicamente el ejecutor que elijas. Cada configuración
selecciona su propio archivo de prueba, por lo que los tres ejemplos también pueden coexistir.
En tests/jest.test.js, sustituye la importación de Vitest por:
import { expect, test } from '@jest/globals';export default { testEnvironment: 'node', testMatch: ['<rootDir>/tests/jest.test.js'], transform: {},};node --experimental-vm-modules node_modules/jest/bin/jest.js --runInBandResultado esperado: una prueba aprobada. Se utiliza el modo ESM nativo de Jest sin transformaciones; Node emite una advertencia sobre el carácter experimental de VM Modules.
En tests/rstest.test.js, sustituye la importación de Vitest por:
import { expect, test } from '@rstest/core';import { defineConfig } from '@rstest/core';
export default defineConfig({ testEnvironment: 'node', include: ['tests/rstest.test.js'],});node node_modules/@rstest/core/bin/rstest.js runResultado esperado: una prueba aprobada, con el mismo factory y las mismas aserciones.
Alcance del ejemplo verificado
Sección titulada «Alcance del ejemplo verificado»Estas versiones aprobaron el caso de create con contenido inline en Node 26.8.1 sobre
macOS ARM64. El SDK declara Node >=25.9.0 y Bun 1.3.14 en sus engines; este resultado
no modifica esos requisitos ni establece soporte oficial exclusivo de Node para todas
las funciones del SDK. El ejemplo no cubre la validación de esquemas, el scaffolding
del sistema de archivos, el renderizado de plantillas ni la comprobación de tipos de TypeScript.
Referencias de los ejecutores: configuración de Vitest, ESM en Jest y configuración de Rstest.
Leer el árbol resultante
Sección titulada «Leer el árbol resultante»result.tree tiene el tipo ReadonlyMap<string, string> y es un Map en tiempo de
ejecución, no un objeto plano. Utiliza .get(path) para leer el contenido (undefined
si no existe), .has(path) para comprobar su presencia, [...result.tree.keys()] para
listar rutas y .size para contar entradas. No utilices result.tree[path] para leer archivos.
Archivos seed e idempotencia
Sección titulada «Archivos seed e idempotencia»La opción seed es un objeto plano (Record<string, string>); el result.tree devuelto
es un Map que contiene solo las escrituras confirmadas, no una instantánea completa
del espacio de trabajo. El factory puede leer los archivos iniciales, pero sus rutas no
aparecen en el Map si no se modifican. Una escritura en una ruta inicial aparece al confirmarse:
import { test, expect } from "vitest";import { runFactoryForTest } from "@pbuilder/sdk/testing";import { find, replaceContent } from "@pbuilder/sdk/commons";
test("a seeded file is readable; only the write is committed", async () => { const run = async (input: { name: string }) => { const existing = await find("services.txt").read(); replaceContent("services.txt", `${existing}\n${input.name}`); };
const seed = { "services.txt": "payments", "untouched.txt": "keep" }; const result = await runFactoryForTest(run, { name: "orders" }, { seed });
expect(result.error).toBeUndefined(); expect(result.tree.get("services.txt")).toEqual("payments\norders"); expect(result.tree.has("untouched.txt")).toBe(false);});packageDir — anclar los verbos locales al paquete
Sección titulada «packageDir — anclar los verbos locales al paquete»El otro campo de las opciones, packageDir (el directorio absoluto del paquete del schematic), ancla los
verbos locales al paquete (scaffold, copyIn, create({ templateFile })) y activa en la
ejecución la validación de entradas derivada del schema contra el schema.json adyacente.
Sin él, esos verbos no tienen contra qué resolverse. (Cuando la CLI ejecuta tu schematic,
pasa la ubicación del paquete automáticamente — esto solo importa al testear. Consulta
Scaffolding para conocer los verbos en sí.)
Qué simula el harness — y qué no
Sección titulada «Qué simula el harness — y qué no»Las plantillas se guardan tal cual en el árbol de prueba — el renderizado ocurre en el
engine al momento de builder execute, y el harness no lo simula. Así que hacer
aserciones sobre un create con plantilla significa hacerlas sobre el texto crudo
{= .name =}, no sobre la salida renderizada.
@pbuilder/sdk/testing se publica como 0.x, exento de semver, hasta que el uso real
valide la forma del resultado.
Bun como alternativa
Sección titulada «Bun como alternativa»También puedes utilizar el ejecutor de pruebas de Bun con el harness. Importa test
y expect desde bun:test en tus pruebas de Bun y ejecuta bun test con su ruta. Las
aserciones sobre el entorno Node del ejemplo anterior son específicas de esa prueba;
omítelas al ejecutar con Bun.
¿Errores del editor con bun:test?
Sección titulada «¿Errores del editor con bun:test?»bun test elimina los tipos en lugar de verificarlos, así que corre bien de cualquier
manera — pero tu editor necesita algunos ajustes de tsconfig para resolver los imports.
Agrega typescript y @types/bun como dependencias de desarrollo y asegúrate de que tu
tsconfig.json tenga:
moduleResolution: "NodeNext"(o"bundler") — la resolución legada por defecto de TypeScript no puede leer el mapaexportsde un paquete, que es la única vía hacia los subpaths de@pbuilder/sdk(./testing,./commonsy compañía). Sin esto, tu editor reportaCannot find module '@pbuilder/sdk/commons'aunque el import sea correcto.allowImportingTsExtensions: true— los factories importan los tipos generados con una extensión.tsexplícita (./schema.generated.ts), que TypeScript rechaza por defecto.- Si restringes los tipos ambientales con
types, incluye"bun"junto a las entradas existentes para que el editor pueda resolverbun:testdesde@types/bun.