Ir al contenido

Probar schematics

Ejecuta tu factory con runFactoryForTest y comprueba el árbol resultante — sin CLI, sin un proceso del engine y sin archivos generados en disco.

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:

package.json
{
"private": true,
"type": "module"
}
Terminal window
npm install --save-dev --save-exact @pbuilder/[email protected] [email protected]

Utiliza un factory JavaScript ESM para que el ejemplo no dependa de transformaciones de TypeScript:

factory.js
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:

tests/vitest.test.js
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');
});
vitest.config.js
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: { environment: 'node', include: ['tests/vitest.test.js'] },
});
Terminal window
node node_modules/vitest/vitest.mjs run

Resultado 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.

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.

Terminal window
npm install --save-dev --save-exact @pbuilder/[email protected] [email protected]

En tests/jest.test.js, sustituye la importación de Vitest por:

import { expect, test } from '@jest/globals';
jest.config.js
export default {
testEnvironment: 'node',
testMatch: ['<rootDir>/tests/jest.test.js'],
transform: {},
};
Terminal window
node --experimental-vm-modules node_modules/jest/bin/jest.js --runInBand

Resultado 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.

Terminal window
npm install --save-dev --save-exact @pbuilder/[email protected] @rstest/[email protected]

En tests/rstest.test.js, sustituye la importación de Vitest por:

import { expect, test } from '@rstest/core';
rstest.config.js
import { defineConfig } from '@rstest/core';
export default defineConfig({
testEnvironment: 'node',
include: ['tests/rstest.test.js'],
});
Terminal window
node node_modules/@rstest/core/bin/rstest.js run

Resultado esperado: una prueba aprobada, con el mismo factory y las mismas aserciones.

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.

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.

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í.)

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.

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.

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 mapa exports de un paquete, que es la única vía hacia los subpaths de @pbuilder/sdk (./testing, ./commons y compañía). Sin esto, tu editor reporta Cannot find module '@pbuilder/sdk/commons' aunque el import sea correcto.
  • allowImportingTsExtensions: true — los factories importan los tipos generados con una extensión .ts explí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 resolver bun:test desde @types/bun.