From 01fa8d383c2d7c55a621d5964c078ceb7eb79951 Mon Sep 17 00:00:00 2001 From: Paolo Insogna Date: Tue, 6 Feb 2024 11:39:27 +0100 Subject: [PATCH] chore: Replace tap with Node test runner. --- package.json | 10 +- src/index.ts | 2 - test/index.test.ts | 610 +++++++++++++++++++++++---------------------- 3 files changed, 310 insertions(+), 312 deletions(-) diff --git a/package.json b/package.json index ff78600..8b471aa 100644 --- a/package.json +++ b/package.json @@ -35,8 +35,8 @@ "format": "prettier -w src test", "lint": "eslint --cache --ext .js,.jsx,.ts,.tsx src test", "typecheck": "tsc -p . --emitDeclarationOnly", - "test": "c8 -c test/config/c8-local.json tap test/*.test.ts", - "test:ci": "c8 -c test/config/c8-ci.json tap --no-color test/*.test.ts", + "test": "c8 -c test/config/c8-local.json node --import tsx test/index.test.ts", + "test:ci": "c8 -c test/config/c8-ci.json node --import tsx --test-reporter=tap test/index.test.ts", "ci": "npm run build && npm run test:ci", "prepublishOnly": "npm run ci", "postpublish": "git push origin && git push origin -f --tags" @@ -57,14 +57,10 @@ "concurrently": "^8.2.2", "fastify": "^4.25.2", "prettier": "^3.2.4", - "tap": "^18.7.0", - "ts-node": "^10.9.2", + "tsx": "^4.7.0", "typescript": "^5.3.3" }, "engines": { "node": ">= 18.18.0" - }, - "tap": { - "extends": "./test/config/tap.yml" } } diff --git a/src/index.ts b/src/index.ts index a4e6644..c6753bf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -62,9 +62,7 @@ function printRoutes(routes: RouteOptions[], useColors: boolean, compact: boolea const styler = useColors ? colorize : clean // Sort and eventually unify routes - /* c8 ignore start */ routes = routes.filter(r => getRouteConfig(r).hide !== true && filter(r)).sort(sortRoutes) - /* c8 ignore end */ if (compact) { routes = unifyRoutes(routes) diff --git a/test/index.test.ts b/test/index.test.ts index bd7deff..410a7a8 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -1,12 +1,20 @@ /* eslint-disable @typescript-eslint/no-floating-promises */ import fastify, { type RouteOptions } from 'fastify' +import { strictEqual } from 'node:assert' +import { test, type MockedObject, type TestContext } from 'node:test' import { table } from 'table' -import t from 'tap' import { plugin as fastifyPrintRoutes } from '../src/index.js' function handler(): void {} +function mockConsole(t: TestContext): MockedObject { + const fn = t.mock.method(console, 'log') + fn.mock.mockImplementation(() => {}) + + return fn +} + function generateOutput(rows: string[][], header: string[] = ['Method(s)', 'Path', 'Description']): string { return ( 'Available routes:\n\n' + @@ -29,361 +37,357 @@ function generateOutput(rows: string[][], header: string[] = ['Method(s)', 'Path ) } -t.test('Plugin', t => { - t.test('should correctly list unhidden routes with colors', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() +test('should correctly list unhidden routes with colors', async t => { + const logCalls = mockConsole(t) + const server = fastify() - await server.register(fastifyPrintRoutes) + await server.register(fastifyPrintRoutes) - server.get('/abc', { handler }) + server.get('/abc', { handler }) - server.options('/abc', { handler }) - - server.route({ - url: '/another/:params', - method: ['POST', 'GET'], - handler, - config: { - description: 'Title' - } - }) + server.options('/abc', { handler }) - server.route({ - url: '/path3', - method: ['POST', 'GET'], - handler, - config: { - hide: true - } - }) + server.route({ + url: '/another/:params', + method: ['POST', 'GET'], + handler, + config: { + description: 'Title' + } + }) - await server.listen({ port: 0 }) - await server.close() - - t.equal( - // eslint-disable-next-line no-control-regex - logCalls()[0].args[0].replaceAll(/\u001B\[\d+m/g, ''), - generateOutput([ - ['GET', '/abc', ''], - ['HEAD', '/abc', ''], - ['OPTIONS', '/abc', ''], - ['GET | POST', '/another/:params', 'Title'], - ['HEAD', '/another/:params', 'Title'] - ]) - ) + server.route({ + url: '/path3', + method: ['POST', 'GET'], + handler, + config: { + hide: true + } }) - t.test('should correctly include querystring in the URL if present', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() - - await server.register(fastifyPrintRoutes, { compact: true }) - - server.route({ - url: '/first', - method: ['GET'], - handler, - schema: { - querystring: { - type: 'object', - properties: { - foo: { - type: 'string' - }, - bar: { - type: 'integer' - } + await server.listen({ port: 0 }) + await server.close() + + strictEqual( + // eslint-disable-next-line no-control-regex + logCalls.mock.calls[0].arguments[0].replaceAll(/\u001B\[\d+m/g, ''), + generateOutput([ + ['GET', '/abc', ''], + ['HEAD', '/abc', ''], + ['OPTIONS', '/abc', ''], + ['GET | POST', '/another/:params', 'Title'], + ['HEAD', '/another/:params', 'Title'] + ]) + ) +}) + +test('should correctly include querystring in the URL if present', async t => { + const logCalls = mockConsole(t) + const server = fastify() + + await server.register(fastifyPrintRoutes, { compact: true }) + + server.route({ + url: '/first', + method: ['GET'], + handler, + schema: { + querystring: { + type: 'object', + properties: { + foo: { + type: 'string' }, - required: ['foo'] - } + bar: { + type: 'integer' + } + }, + required: ['foo'] } - }) + } + }) - server.route({ - url: '/second', - method: ['GET'], - handler, - schema: { - querystring: { - type: 'object', - properties: { - foo: { - type: 'string' - }, - bar: { - type: 'integer' - } + server.route({ + url: '/second', + method: ['GET'], + handler, + schema: { + querystring: { + type: 'object', + properties: { + foo: { + type: 'string' }, - required: ['bar'] - } + bar: { + type: 'integer' + } + }, + required: ['bar'] } - }) + } + }) - server.route({ - url: '/third', - method: ['GET'], - handler, - schema: { - querystring: { - type: 'object', - properties: { - foo: { - type: 'string' - }, - bar: { - type: 'integer' - }, - baz: { - type: 'integer' - } + server.route({ + url: '/third', + method: ['GET'], + handler, + schema: { + querystring: { + type: 'object', + properties: { + foo: { + type: 'string' }, - required: ['bar'] - } + bar: { + type: 'integer' + }, + baz: { + type: 'integer' + } + }, + required: ['bar'] } - }) + } + }) - server.route({ - url: '/fourth', - method: ['GET'], - handler, - schema: { - querystring: { - type: 'object', - properties: { - foo: { - type: 'string' - }, - bar: { - type: 'integer' - }, - baz: { - type: 'integer' - } + server.route({ + url: '/fourth', + method: ['GET'], + handler, + schema: { + querystring: { + type: 'object', + properties: { + foo: { + type: 'string' }, - required: ['baz'] - } + bar: { + type: 'integer' + }, + baz: { + type: 'integer' + } + }, + required: ['baz'] } - }) - - await server.listen({ port: 0 }) - await server.close() - - t.equal( - // eslint-disable-next-line no-control-regex - logCalls()[0].args[0].replaceAll(/\u001B\[\d+m/g, ''), - generateOutput( - [ - ['GET | HEAD', '/first?foo=value(&bar=value)'], - ['GET | HEAD', '/fourth?(foo=value&)(bar=value&)baz=value'], - ['GET | HEAD', '/second?(foo=value&)bar=value'], - ['GET | HEAD', '/third?(foo=value&)bar=value(&baz=value)'] - ], - ['Method(s)', 'Path'] - ) - ) + } }) - t.test('should correctly list unhidden routes without colors', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() + await server.listen({ port: 0 }) + await server.close() + + strictEqual( + // eslint-disable-next-line no-control-regex + logCalls.mock.calls[0].arguments[0].replaceAll(/\u001B\[\d+m/g, ''), + generateOutput( + [ + ['GET | HEAD', '/first?foo=value(&bar=value)'], + ['GET | HEAD', '/fourth?(foo=value&)(bar=value&)baz=value'], + ['GET | HEAD', '/second?(foo=value&)bar=value'], + ['GET | HEAD', '/third?(foo=value&)bar=value(&baz=value)'] + ], + ['Method(s)', 'Path'] + ) + ) +}) - await server.register(fastifyPrintRoutes, { useColors: false }) +test('should correctly list unhidden routes without colors', async t => { + const logCalls = mockConsole(t) + const server = fastify() - server.get('/abc', { handler }) + await server.register(fastifyPrintRoutes, { useColors: false }) - server.options('/abc', { handler }) + server.get('/abc', { handler }) - server.route({ - url: '/another/:params', - method: ['POST', 'GET'], - handler, - config: { - description: 'Title' - } - }) + server.options('/abc', { handler }) - server.route({ - url: '/path3', - method: ['POST', 'GET'], - handler, - config: { - hide: true - } - }) - await server.listen({ port: 0 }) - await server.close() - - t.equal( - logCalls()[0].args[0], - generateOutput([ - ['GET', '/abc', ''], - ['HEAD', '/abc', ''], - ['OPTIONS', '/abc', ''], - ['GET | POST', '/another/:params', 'Title'], - ['HEAD', '/another/:params', 'Title'] - ]) - ) + server.route({ + url: '/another/:params', + method: ['POST', 'GET'], + handler, + config: { + description: 'Title' + } }) - t.test('should correctly list filtered routes without colors', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() + server.route({ + url: '/path3', + method: ['POST', 'GET'], + handler, + config: { + hide: true + } + }) + await server.listen({ port: 0 }) + await server.close() + + strictEqual( + logCalls.mock.calls[0].arguments[0], + generateOutput([ + ['GET', '/abc', ''], + ['HEAD', '/abc', ''], + ['OPTIONS', '/abc', ''], + ['GET | POST', '/another/:params', 'Title'], + ['HEAD', '/another/:params', 'Title'] + ]) + ) +}) - await server.register(fastifyPrintRoutes, { - useColors: false, - filter(route: RouteOptions): boolean { - return route.url === '/abc' - } - }) +test('should correctly list filtered routes without colors', async t => { + const logCalls = mockConsole(t) + const server = fastify() - server.get('/abc', { - handler, - config: { - description: 'Title' - } - }) + await server.register(fastifyPrintRoutes, { + useColors: false, + filter(route: RouteOptions): boolean { + return route.url === '/abc' + } + }) - server.options('/abc', { handler }) + server.get('/abc', { + handler, + config: { + description: 'Title' + } + }) - server.route({ - url: '/another/:params', - method: ['POST', 'GET'], - handler, - config: { - description: 'Title' - } - }) + server.options('/abc', { handler }) - server.route({ - url: '/path3', - method: ['POST', 'GET'], - handler, - config: { - hide: true - } - }) - await server.listen({ port: 0 }) - await server.close() - - t.equal( - logCalls()[0].args[0], - generateOutput([ - ['GET', '/abc', 'Title'], - ['HEAD', '/abc', 'Title'], - ['OPTIONS', '/abc', ''] - ]) - ) + server.route({ + url: '/another/:params', + method: ['POST', 'GET'], + handler, + config: { + description: 'Title' + } }) - t.test('should correctly compact routes', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() + server.route({ + url: '/path3', + method: ['POST', 'GET'], + handler, + config: { + hide: true + } + }) + await server.listen({ port: 0 }) + await server.close() + + strictEqual( + logCalls.mock.calls[0].arguments[0], + generateOutput([ + ['GET', '/abc', 'Title'], + ['HEAD', '/abc', 'Title'], + ['OPTIONS', '/abc', ''] + ]) + ) +}) - await server.register(fastifyPrintRoutes, { compact: true }) +test('should correctly compact routes', async t => { + const logCalls = mockConsole(t) + const server = fastify() - server.get('/abc', { - handler, - config: { - description: 'Another title' - } - }) + await server.register(fastifyPrintRoutes, { compact: true }) - server.options('/abc', { handler }) + server.get('/abc', { + handler, + config: { + description: 'Another title' + } + }) - server.get('/cde', { handler }) + server.options('/abc', { handler }) - server.route({ - url: '/cde', - method: ['OPTIONS'], - handler - }) + server.get('/cde', { handler }) - server.route({ - url: '/another/:params', - method: ['POST', 'GET'], - handler, - config: { - description: 'Title' - } - }) + server.route({ + url: '/cde', + method: ['OPTIONS'], + handler + }) - server.route({ - url: '/path3', - method: ['POST', 'GET'], - handler, - config: { - hide: true - } - }) + server.route({ + url: '/another/:params', + method: ['POST', 'GET'], + handler, + config: { + description: 'Title' + } + }) - await server.listen({ port: 0 }) - await server.close() - - t.equal( - // eslint-disable-next-line no-control-regex - logCalls()[0].args[0].replaceAll(/\u001B\[\d+m/g, ''), - generateOutput([ - ['GET | HEAD | OPTIONS', '/abc', ''], - ['GET | POST | HEAD', '/another/:params', 'Title'], - ['GET | HEAD | OPTIONS', '/cde', ''] - ]) - ) + server.route({ + url: '/path3', + method: ['POST', 'GET'], + handler, + config: { + hide: true + } }) - t.test('should omit description column if not needed', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() + await server.listen({ port: 0 }) + await server.close() + + strictEqual( + // eslint-disable-next-line no-control-regex + logCalls.mock.calls[0].arguments[0].replaceAll(/\u001B\[\d+m/g, ''), + generateOutput([ + ['GET | HEAD | OPTIONS', '/abc', ''], + ['GET | POST | HEAD', '/another/:params', 'Title'], + ['GET | HEAD | OPTIONS', '/cde', ''] + ]) + ) +}) - await server.register(fastifyPrintRoutes, { useColors: false }) +test('should omit description column if not needed', async t => { + const logCalls = mockConsole(t) + const server = fastify() - server.get('/abc', { handler }) + await server.register(fastifyPrintRoutes, { useColors: false }) - server.options('/abc', { handler }) + server.get('/abc', { handler }) - server.route({ - url: '/another/:params', - method: ['POST', 'GET'], - handler - }) + server.options('/abc', { handler }) - server.route({ - url: '/path3', - method: ['POST', 'GET'], - handler, - config: { - hide: true - } - }) + server.route({ + url: '/another/:params', + method: ['POST', 'GET'], + handler + }) - await server.listen({ port: 0 }) - await server.close() - - t.equal( - logCalls()[0].args[0], - generateOutput( - [ - ['GET', '/abc'], - ['HEAD', '/abc'], - ['OPTIONS', '/abc'], - ['GET | POST', '/another/:params'], - ['HEAD', '/another/:params'] - ], - ['Method(s)', 'Path'] - ) - ) + server.route({ + url: '/path3', + method: ['POST', 'GET'], + handler, + config: { + hide: true + } }) - t.test('should print nothing when no routes are available', async t => { - const logCalls = t.capture(console, 'log') - const server = fastify() + await server.listen({ port: 0 }) + await server.close() + + strictEqual( + logCalls.mock.calls[0].arguments[0], + generateOutput( + [ + ['GET', '/abc'], + ['HEAD', '/abc'], + ['OPTIONS', '/abc'], + ['GET | POST', '/another/:params'], + ['HEAD', '/another/:params'] + ], + ['Method(s)', 'Path'] + ) + ) +}) - await server.register(fastifyPrintRoutes) - await server.listen({ port: 0 }) - await server.close() +test('should print nothing when no routes are available', async t => { + const logCalls = mockConsole(t) + const server = fastify() - t.equal(logCalls().length, 0) - }) + await server.register(fastifyPrintRoutes) + await server.listen({ port: 0 }) + await server.close() - t.end() + strictEqual(logCalls.mock.callCount(), 0) })