todo
incluido
joel a. villarreal bertoldi
testing con node.js
sin dependencias externas
beerjscba#94
hola!
soy Joey.
dev lead en ID Plans
escribo código desde 1999
emperador del té en proceso
casado + padre de perruhija
hablemos de las cosas
que necesitamos para testear
#5:
paciencia.
2022
node.js 18 incluye la primera versión del módulo node:test, se backportea a node.js 16.17 (LTS)
2023
features de node:test comienzan a considerarse stable con node.js 20
2023
se comienza a incluir timers, suites, skip/todo/only
?
2024
node.js 22, se comienza a incluir module mocking
?
〞
¡Pero entonces ya podemos despedirnos de ........... en Node.js!
– Torcuato, dev minimalista
SÍ*
*teniendo en cuenta que las features más avanzadas están bajo flags experimentales y podrían cambiar en cualquier momento, sin perjuicio de romper por completo cualquier integración que tengas con dichos módulos.
CLI
Programado
node --test
import dotenv from 'dotenv';
import { spec } from 'node:test/reporters';
import { run } from 'node:test';
import process from 'node:process';
import fs from 'node:fs';
import path from 'node:path';
const files = fs.readdirSync(
path.resolve(__dirname),
{ recursive: true, encoding: 'utf8', },
).filter(
file => file.endsWith('.spec.ts'),
).map(
file => path.resolve(__dirname, file),
);
run({
setup() { dotenv.config({ path: '.env' }); },
files,
}).compose(spec).pipe(process.stdout);
import dotenv from 'dotenv';
import { spec } from 'node:test/reporters';
import { run } from 'node:test';
import process from 'node:process';
import fs from 'node:fs';
import path from 'node:path';
const files = fs.readdirSync(
path.resolve(__dirname),
{ recursive: true, encoding: 'utf8', },
).filter(
file => file.endsWith('.spec.ts'),
).map(
file => path.resolve(__dirname, file),
);
run({
setup() { dotenv.config({ path: '.env' }); },
files,
}).compose(spec).pipe(process.stdout);
archivos
de test
a correr
ejecución
con spec
reporter
〞
¡Ah, pero para TypeScript ya voy a tener que instalar alguna cosa! Es igual a ts-jest al final.
– Torcuato, dev comparatista
SÍ, pero*
*node.js ahora tiene algo llamado loaders**.
** import si node > 20.5.1
node --import tsx
npm i -D tsx
veamos cómo migramos
Expectations
node:test utiliza assert en vez de expect, por lo que se escribe en otro estilo.
1.
Mocks
node:test tiene un sistema de mocks muy similar al de otros testing frameworks.
2.
Algo más avanzado
Acá entran module mocking, timers, coverage y demás.
3.
jest expect
node assert
expect(
value
).toBe(
true
);
assert.ok(
value
);
assert.strictEqual(
value,
true
);
expect(value).toBe(true)
assert.strictEqual(value, true)
Espero que valor sea verdadero
Afirmo la estricta igualdad entre valor y verdadero
assert(condition, errorMessage);
# Negativos
doesNotMatch
doesNotReject
doesNotThrow
notDeepEqual
notDeepStrictEqual
notEqual
notStrictEqual
# Positivos
deepEqual (objetos, ==)
deepStrictEqual (objetos, ===)
equal
strictEqual
ifError
match
ok
rejects
throws
node:assert
algunos de estos
métodos existen
desde node v0.1
import {
it,
describe
} from 'node:test';
import assert from 'node:assert/strict';
import db, { sql } from '../../src';
describe('Connection', () => {
it('should connect to the database', async () => {
const results = await db.query(
sql`SELECT 2 + 3 as result`
);
assert.deepEqual(results, [{ result: 5 }]);
});
});
test con asserts
import {
it,
describe
} from 'node:test';
import assert from 'node:assert/strict';
import db, { sql } from '../../src';
describe('Connection', () => {
it('should connect to the database', /* .... */);
it('should call onError when failing', async (ctx) => {
const onError = ctx.mock.fn(); // CREATE MOCK
const results = await db.query(
sql`SE 2 + 3 as result`,
{ onError } // PASS MOCK
);
// EVAL MOCK
assert.strictEqual(onError.mock.callCount(), 1);
})
});
test con mocks
¡Ah, pero tengo que repetir código todo el tiempo! ¿Dónde están mis beforeEach, afterEach?
– Torcuato, dev estructuralista
〞
son iguales
before(), beforeEach(), after(), afterEach() funcionan exactamente igual en node:test
Bueno pero ¿y mis snapshots? A que esos no los tenés.
– Torcuato, dev fotógrafo
〞
test('snapshot sin serializador', (ctx) => {
t.assert.snapshot({
value1: 1, value2: 2
});
});
test('snapshot con serializador', (ctx) => {
t.assert.snapshot({
value3: 3, value4: 4
}, {
serializers: [
(value) => JSON.stringify(value)
]
});
});
Stage 1 - Early Development
import { it, describe } from 'node:test';
import assert from 'node:assert/strict';
import db, { sql } from '../../src';
describe('Connection', () => {
it('should log queries', async (ctx) => {
const mockedLogFn = ctx.mock.fn();
const mockedLogger = ctx.mock.module("logger", {
namedExports: { log: mockedLog }
})
await db.query(sql`SELECT 2 + 3 as result`);
// EVAL MOCK
assert.strictEqual(mockedLogFn.log.callCount(), 1);
const [call] = mockedLogFn.calls;
assert.strictEqual(call.arguments, [
'Executing query: SELECT 2 + 3 as result'
]);
})
});
test con module mocking
(usa --experimental-test-module-mocks)
¿
preguntas
?
se admiten preguntas de sommelierie de té
beban agua, tomen sol y toquen pasto
~ negru
gracias!
BeerJS 94
By Joel Alejandro Villarreal Bertoldi
BeerJS 94
- 39