Nota del traductor
Esta es la traducción del archivo readme.md. Aquí hay un enlace a las diferencias con la rama master de AVA (Si al hacer clic en el enlace no se encuentran modificaciones en el archivo readme.md
, será por que la traducción está actualizada).
Test runner futurista
A pesar de que JavaScript se ejecuta en un solo hilo, IO en Node.js puede ejecutarse en paralelo debido a su naturaleza asíncrona. AVA aprovecha esto y corre sus tests al mismo tiempo, lo que es especialmente beneficioso para tests pesados en IO. Además, los archivos de test se ejecutan en paralelo como procesos separados, que le da un mejor rendimiento y un entorno aislado para cada archivo de test. Cambiando de Mocha a AVA en Pageres llevó el tiempo de los test por debajo de 31 segundos, concretamente a 11 segundos. El tener tests que se ejecutan al mismo tiempo nos obliga a escribir tests atómicos, es decir, los tests no dependen del estado global o el estado de otros tests, lo que está muy bien!
Lea nuestra guía de contribución si está pensando en contribuir (issues/PRs/etc).
- Mínima y rápida
- Sintaxis simple de test
- Ejecuta los tests concurrentemente
- Fuerza a escribir tests atómicos
- Sin globales implícitas
- Entorno aislado para cada archivo de test
- Escribe tus tests en ES2015
- Soporte a Promesas
- Soporte a Generadores
- Soporte a Async
- Soporte a Observable
- Aserciones mejoradas
- Salida de TAP opcional
import test from 'ava';
test(t => {
t.same([1, 2], [1, 2]);
});
Instalar AVA globalmente $ npm install --global ava
y ejecutar $ ava --init
(con cualquiera de las opciones) para añadir AVA a tu package.json o crear una.
{
"name": "awesome-package",
"scripts": {
"test": "ava"
},
"devDependencies": {
"ava": "^0.6.0"
}
}
import test from 'ava';
import delay from 'delay';
test('foo', t => {
t.pass();
});
test('bar', async t => {
t.plan(1);
const bar = Promise.resolve('bar').then(delay(200));
t.is(await bar, 'bar');
});
$ npm test
$ ava --help
Usage
ava [<file|folder|glob> ...]
Options
--init Add AVA to your project
--fail-fast Stop after first test failure
--serial Run tests serially
--require Module to preload (Can be repeated)
--tap Generate TAP output
--verbose Enable verbose output
Examples
ava
ava test.js test2.js
ava test-*.js
ava test
ava --init
ava --init foo.js
Default patterns when no arguments:
test.js test-*.js test/**/*.js
Los directorios son recursivos por defecto. Los archivos que se encuentren en directorios llamados fixtures
y helpers
serán ignorados, así como los archivos que comienzan con _
. Esto nos puede ser útil para tener helpers en el mismo directorio que los archivos de test.
ADVERTENCIA: COMPORTAMIENTO NO ESTÁNDAR: La CLI de AVA tratará siempre de encontrar y utilizar su instalación local de AVA. Esto será así incluso cuando se ejecuta el comando ava
global. Este comportamiento no estándar resuelve un importante problema, y no debe tener ningún impacto en el uso diario.
Todas las opciones de CLI pueden configurarse en la sección de 'ava' de su 'package.json'. Esto le permite modificar el comportamiento predeterminado del comando 'ava', para no tener que escribir varias veces las mismas opciones en el indicador de comandos.
{
"ava": {
"files": [
"my-test-folder/*.js",
"!**/not-this-file.js"
],
"failFast": true,
"serial": true,
"tap": true,
"verbose": true,
"require": ["babel-core/register", "coffee-script/register"]
}
}
Los argumentos pasados al CLI siempre tendrán prioridad sobre la configuración en 'package.json'.
Los tests se ejecutan asincronamente y requieren devolver y soportar un objeto asíncrono (una promesa, u observable). Nosotros recomendamos altamente el uso de funciones asícronas; Hacen el código asíncrono, conciso y fácil de leer, y de forma implícita devuelven una promesa, por lo que no tiene que hacerla.
Si usted no devuelve uno de los objetos soportados y asincrónicos mencionados anteriormente, la prueba se considerará síncrona y terminará inmediatamente.
Si usted es incapaz de usar promesas u otros objetos asíncronos soportados, puede activar el "callback" por la definición de su test con test.cb([title], fn)
. Los test declarados de esta manera deben terminar manualmente con t.end()
. Este modo está pensado principalmente para las APIs de tests con estilo callback.
Debe definir todas las pruebas de forma sincrona. No pueden estar definidos dentro de setTimeout
, setImmediate
, etc.
Los archivos de test se ejecutan desde el directorio actual, con lo que process.cwd()
es siempre el mismo que __dirname
. Puede tambien usar rutas de acceso relativas en lugar de hacer path.join(__dirname, 'relative/path')
.
Para crear un test, llamaremos a la función de test
que requiera de AVA y pasaremos un nombre de test opcional y una función que contiene la ejecución del test. La función que pasemos será tomada en contexto como el primer argumento, dónde puedes invocar los diferentes métodos y aserciones de AVA.
test('name', t => {
t.pass();
});
Dar nombre a un test es opcional, pero se recomienda usar uno si tenemos más de un test.
test(t => {
t.pass();
});
También puede optar por utilizar una función nombrada en su lugar:
test(function name(t) {
t.pass();
});
Un plan de aserción se puede utilizar para garantizar que un número determinado de aserciones se cumplen. El escenario más común es validar que el test no ha salido antes de ejecutar el número esperado de aserciones. También falla el test si se ejecutan demasiadas aserciones, puede ser útil si tiene aserciones dentro de callbacks o bucles.
Esto terminará en un test ejecutado satisfactoriamente:
test(t => {
t.plan(1);
return Promise.resolve(3).then(n => {
t.is(n, 3);
});
});
test.cb(t => {
setTimeout(() => {
t.pass();
t.end();
}, 100);
});
AVA ya no soportará automáticamente la terminación de test via t.plan(...)
. Esto ayuda a prevenir falsos positivos si añade aserciones, pero olvidese de incrementar su recuento de plan.
// Esto ya no funcionará
test('auto ending is dangerous', t => {
t.plan(2);
t.pass();
t.pass();
// termina automáticamente después de llegar a las dos aserciones planificadas, se perderá la última
setTimeout(() => t.fail(), 10000);
});
Para que esto funcione, ahora debe usar "callback mode" y llamar explícitamente t.end()
.
test.cb('explicitly end your tests', t => {
t.plan(2);
t.pass();
t.pass();
setTimeout(() => {
// Este fallo ahora es recogido de forma fiable.
t.fail();
t.end();
}, 1000);
});
Mientras que la concurrencia es impresionante, hay algunas cosas que no se pueden hacer concurrentemente. En estos extraños casos, puede usar test.serial
, lo que obligará a esos tests funcionar en serie antes de los concurrentes.
test.serial(t => {
t.pass();
});
Only-tests fuerza a que se cumplan sólo los test que se ejecutan. Esto puede ser útil para el funcionamiento de sólo unos pocos tests durante el desarrollo.
test('will not be run', t => {
t.fail();
})
test.only('will be run', t => {
t.pass();
});
Skip-tests se muestran como omitidos pero nunca ejecutados.
test.skip('will not be run', t => {
t.fail();
});
Cuando se requiera empezar a preparar y/o abandonar, puede usar test.before()
y test.after()
,
usandolo de la misma manera que test()
. La función test permite el uso de test.before()
y test.after()
, siempre serán ejecutadas antes o despues de todos los tests. Puede usar incluso test.beforeEach()
y test.afterEach()
si necesita preparar algo antes y despues de cada test. Los hooks se ejecutan en serie en el archivo de test. Añada tantos como quiera. Opcionalmente puede especificar un título que se muestre en el error.
test.before(t => {
// esto se ejecuta antes de todos los tests
});
test.before(t => {
// esto se ejecuta después del anterior, pero antes de los tests
});
test.after('cleanup', t => {
// esto se ejecuta despues de todos los tests
});
test.beforeEach(t => {
// esto se ejecuta antes de cada test
});
test.afterEach(t => {
// esto se ejecuta despues de cada test
});
test(t => {
// test regular
});
Puede utilizar las funciones asíncronas, devolver objetos asincrónicos, o activar el "modo callback" en cualquiera de los hooks.
test.before(async t => {
await promiseFn();
});
test.cb.beforeEach(t => {
setTimeout(t.end);
});
test.afterEach.cb(t => {
setTimeout(t.end);
});
test.after(t => {
return new Promise(/* ... */);
});
Los hooks beforeEach
y afterEach
pueden compartir el contexto del test:
test.beforeEach(t => {
t.context.data = generateUniqueData();
});
test(t => {
t.is(t.context.data + 'bar', 'foobar');
});
El contexto por defecto es un objeto, pero también se puede asignar directamente:
test.beforeEach(t => {
t.context = 'unicorn';
});
test(t => {
t.is(t.context, 'unicorn');
});
Puede encadenar modificaciones de test juntas de la siguiente manera:
test.before.skip([title], testFn);
test.skip.after(....);
test.serial.only(...);
test.only.serial(...);
Es especialmente util utilizar temporalmente skip
o only
en un test, sin perder la información y el comportamiento que los otros modificadores proporcionan.
Puede utilizar cualquier módulo de aserción en lugar o además del que viene con AVA, pero no podrá utilizar el método .plan()
, aún.
import assert from 'assert';
test(t => {
assert(true);
});
AVA está construido con soporte a ES2015 a través de Babel 6. Sólo tiene que escribir sus pruebas en ES2015. No necesitará ninguna configuración adicional. Se puede utilizar cualquier versión de Babel en su proyecto. Utilizamos nuestro propio paquete de Babel con el es2015
y stage-2
preajustados.
AVA actualmente sólo transpilará los tests que usted le pida que ejecute. No transpilará módulos que importen
de fuera del test. Si bien hay razones válidas para adoptar este enfoque, puede que no sea lo que esperas!
Como solución simple, puede utilizar Babel's require hook con el fin de hacer transpilación sobre la marcha de los módulos que se importan posteriormente. Por que AVA soporta la sintaxis de módulo de ES2015, se puede utilizar para importar el hook requerido en sí:
import test from 'ava';
import 'babel-core/register';
import foo from './foo'; // <-- foo puede ser escrito en ES2015!
test('foo bar', t => {
t.same('baz', foo('bar'));
});
#111 esta haciendo seguimiento de este tema como una mejora potencial.
Si usted devuelve una promesa en el test no necesitará poner fin de manera explícita al test, ya que terminará cuando la promesa se resuelva.
test(t => {
return somePromise().then(result => {
t.is(result, 'unicorn');
});
});
AVA viene con soporte a generadores.
test(function * (t) {
const value = yield generatorFn();
t.true(value);
});
AVA viene con soporte a funciones async (async/await).
test(async function (t) {
const value = await promiseFn();
t.true(value);
});
// async arrow function
test(async t => {
const value = await promiseFn();
t.true(value);
});
AVA viene con soporte a observables. Si devuelve un observable a partir de un test, AVA automáticamente podrá consumirlo hasta su finalización antes de terminar el test.
Si no necesita usar "callback mode" o llamar a t.end()
.
test(t => {
t.plan(3);
return Observable.of(1, 2, 3, 4, 5, 6)
.filter(n => {
// sólo números
return n % 2 === 0;
})
.map(() => t.pass());
});
AVA es compatible con el uso de t.end
como callback final al utilizar las API de callback de error-first y node-style. AVA considerará como error cualquier valor truthy pasado como primer argumento de t.end
. Tenga en cuenta que t.end
requiere "callback mode", que se puede activar mediante el uso de la cadena test.cb
.
test.cb(t => {
// t.end comprueba automáticamente los errores para el primer argumento
fs.readFile('data.txt', t.end);
});
AVA puede generar una salida TAP a través de la opción --tap
para su uso con cualquier TAP reporter.
$ ava --tap | tap-nyan
Tipo: string
Título de test.
Tipo: function
Debe contener el test actual.
Pasado a la función de test y contiene los diferentes métodos de AVA y aserciones.
Planifique cuántas aserciones hay en el test. El test fallará si el recuento actual de aserciones no coincide con las aserciones planificadas.
Finalizar el test. Sólo funciona con test.cb()
.
Las aserciones se mezclan en el contexto del test:
test(t => {
t.ok('unicorn'); // aserción
});
Si se encuentran varios errores de aserción en un solo test, AVA sólo mostrará la primera.
Pasando la aserción.
Fallando la aserción.
Afirmando que valor
es truthy.
Afirmando que valor
es falsy.
Afirmando que valor
es true
.
Afirmando que valor
es false
.
Afirmando que valor
es igual a esperado
.
Afirmando que valor
no es igual a esperado
.
Afirmando que valor
es profundamente igual a esperado
.
Afirmando que valor
no es profundamente igual a esperado
.
Afirmando que function
arroja un error o promesa
rechazada.
error
puede contener un constructor, expresiones regulares, mensaje de error o la función de validación.
Afirma que function
no lanza un error
o resuelve la promise
.
Afirma que error
es falsy.
Cualquier aserción se puede omitir usando el modificador skip
. Aunque se omitan dichas aserciones aún se cuentan, con lo que no hay necesidad de cambiar el contador de aserciones planificado.
test(t => {
t.plan(2);
t.skip.is(foo(), 5); // no hay necesidad de cambiar su contador planificado cuando omita aserciones.
t.is(1, 1);
});
AVA viene con power-assert
incorporado, dándole mensajes de aserción más descriptivos. Lee el test y trata de inferir más información del código.
El siguiente test:
test(t => {
const x = 'foo';
t.ok(x === 'bar');
});
Normalmente dará la salida inútil:
false === true
Con las aserciones mejoradas, obtendrás:
t.ok(x === 'bar')
|
"foo"
Es cierto que se podría usar t.is()
en este caso, y probablemente se debería, pero esto es sólo un ejemplo sencillo.
Probemos un ejemplo más avanzado:
test(t => {
const a = /foo/;
const b = 'bar';
const c = 'baz';
t.ok(a.test(b) || b === c);
});
Y ahí lo tienes:
t.ok(a.test(b) || b === c)
| | | |
| "bar" "bar" "baz"
false
Todos los métodos assert se han mejorado.
¡Diviértete!
Cada archivo de test se ejecuta en un proceso de Node.js separado. Esto nos brinda un montón de beneficios. Los diferentes archivos de test ya no se afectan entre sí. Como archivos de test moqueados con el ambiente global, comandos internos imperativos, etc. Sin embargo, se hace principalmente por razones de rendimiento. Aunque Node.js puede ejecutar simultáneamente IO asíncrono, eso no ayuda mucho cuando las pruebas son operaciones síncronas pesadas que bloquean el hilo principal. Mediante la ejecución de tests al mismo tiempo y archivos de test en paralelo, tomamos todas las ventajas de los sistemas modernos.
Ejecutar tests simultáneamente tiene algunos desafíos, hacer IO es uno. Por lo general, los test por defecto crean directorios temporales en el directorio de test actual y lo limpian al final. Esto no funcionará cuando se ejecuten tests en paralelo y entrando en conflicto entre sí. La forma correcta de hacerlo es utilizar un nuevo directorio temporal para cada test. Los módulos tempfile
y temp-write
pueden ser útiles.
AVA ejecuta pruebas en paralelo por defecto, que es subóptimo cuando se necesita depurar algo. En su lugar, ejecuta pruebas en serie con la opción --serial
:
$ ava --serial
Puede usar istanbul
para la cobertura de código como AVA spawns the test files, pero puede usar nyc
en su luegar, que es básicamente istanbul
con soporte para subprocesos.
Desde la versión 5.0.0
utiliza source maps para reportar la cobertura de su código real, independientemente de la transpilación. Asegúrese de que el código que está probando incluye un source map en línea o referencia a un archivo de source map de origen. Si usa babel/register
se puede establecer la opción sourceMaps
en su .babelrc
a inline
.
Mocha requiere el uso de globales implícitas como describe
y it
por defecto (que utilizan la mayoría de las personas), sin demasiadas opiniones buenas, hinchado, síncrono por defecto, ejecuta los tests en serie y es lento. Tape y node-tap son bastante buenos. AVA está muy inspirado en su sintaxis. Sin embargo, ambos ejecutan los tests en serie y han hecho de TAP un ciudadano de primera clase que ha hecho en mi humilde opinión que sus códigos base sean un poco enrevesadas y acopladas. La salida de TAP es difícil de leer, así que siempre terminan usando una herramienta de reporte de TAP externa. AVA tiene bastantes buenas opiniones y es concurrente. Viene con un simple reporter por defecto y tiene voluntad en el futuro de dar apoyo a Tun TAP reporter.
AVA, no Ava o ava. Pronunciado /ˈeɪvə/
ay-və.
Concurrencia no es paralelismo. Permite paralelismo. Aprende más.
Sindre Sorhus | Kevin Mårtensson | Vadim Demedes | James Talmage |