sstur / nbit

A zero-dependency, strongly-typed web framework for Bun, Node and Cloudflare workers
65 stars 4 forks source link

How to test route via import? #7

Closed ImLunaHey closed 1 year ago

ImLunaHey commented 1 year ago

The tests show how to test a route that's defined in the test file but what about one that's imported?

This is failing with a 404 and I have a feeling that's because home imports it's defineRoutes from the application.ts.

import { createApplication, Request } from '@nbit/bun';
import { expect, test } from 'bun:test';
import home from './home';

const { defineRoutes, createRequestHandler } = createApplication();
const requestHandler = createRequestHandler(home);

test('should handle a request', async () => {
    const request = new Request('http://localhost/');
    const response = await requestHandler(request);
    expect(response.status).toBe(200);
    const data = await response.json();
    expect(data).toEqual({ hello: 'world' });
});
import { Response } from '@nbit/bun';
import { defineRoutes } from '../application';

export default defineRoutes(app => [
    app.get('/', () => {
        try {
            return Response.file('public/index.html')
        } catch (error) {
            console.error(error);
        }
    }),
    app.get('/images/favicon.ico', () => Response.file('public/images/favicon.ico')),
]);
sstur commented 1 year ago

Short answer, I think the 404 is because of Response.file(), the same issue as #8.

However to add some more context here..

home imports it's defineRoutes from the application.ts [yet the tests file creates a new defineRoutes]

If you're not using context, then it doesn't really matter which defineRoutes you use, this function is essentially a no-op and exists purely for TypeScript types. If you are using context, then that's where the TypeScript type stuff comes in, and you should use the correct defineRoutes.

const { defineRoutes, attachRoutes } = createApplication({
  getContext: (request) => ({
    authenticate: async () => { ... },
  }),
});

const routes = defineRoutes((app) => [
  app.get('/foo', (request) => {
    await request.authenticate(); // TS knows this method exists because we defined it above
    // Side note: in the next major version the above line will be:
    // await request.context.authenticate()
  }),
]);

So the question becomes, how to load the correct defineRoutes for testing. One potential way is to import the real defineRoutes from application.ts into your tests file. If it has some logic that needs to be mocked, you could do it conditionally:

// application.ts
export const { defineRoutes, attachRoutes } = createApplication({
  getContext: (request) => ({
    authenticate: async () => {
      if (process.env.NODE_ENV === 'test') {
        // do some mock thing
        return mockUser;
      }
      return await db.user.get(...)
    },
  }),
});