honojs / hono

Web framework built on Web Standards
https://hono.dev
MIT License
20.3k stars 579 forks source link

Add Authorization header when testing using request #3431

Closed ikrom closed 1 week ago

ikrom commented 1 month ago

What version of Hono are you using?

4.5.11

What runtime/platform is your app running on?

cloudflare worker + bun

What steps can reproduce the bug?

when I want to create unit test using app.request, I can't add authorization header to check JWT is valid or not

code

What is the expected behavior?

It should not error and unit test can run successfully

What do you see instead?

unit test error and can't run it

Additional information

No response

yusukebe commented 1 month ago

Hi @ikrom

I can't reproduce it. Please provide a minimal project to reproduce it.

ikrom commented 1 month ago

Hi @yusukebe

Actually I want to create unit testing, I have app with route /home

import { Hono } from "hono";
const app = new Hono<{ Bindings: Bindings }>().basePath("/v1");
app.get("/home", async (c) => {
  return c.json({ env: c.env.ENVIRONMENT, message: "Hello World!" });
});

Then I create file home.test.ts to test the route /home

import { describe, test, expect } from "bun:test";
import { Bindings, MOCK_ENV } from "@type";

describe("Index Test", () => {
  test("GET /home", async () => {
    const res = await app.request(
      "/home",
      {
        headers: {
          authorization: `Bearer token`,
        },
      },
      MOCK_ENV
    );
    expect(res.status).toBe(200);
  });
});

But the result is like picture below

image

Could you help how to create unit test with authorization header jwt?

yusukebe commented 1 month ago

@ikrom

You should access /v1/home:

const res = await app.request(
  '/v1/home',
  {
    headers: {
      authorization: 'Bearer token',
    },
  },//...
)
ikrom commented 1 month ago

thank you for the correction @yusukebe

image

but there is another error, the res is undefined

yusukebe commented 1 month ago

@ikrom

I don't know, but the following code is working well:

const app = new Hono().basePath('/v1')

app.get('/home', async (c) => {
  return c.json({})
})

const res = await app.request(
  '/v1/home',
  {
    headers: {
      authorization: 'Bearer token',
    },
  } //...
)

console.log(res.status) // 2000
ikrom commented 1 month ago

should the const app = new Hono() in the same file with unit test? because the unit test can't run if the app in different file with unit test

yusukebe commented 1 month ago

should the const app = new Hono() in the same file with unit test?

No.

gerhardcit commented 1 month ago

Not sure if this helps, but I had to do a fallback in middleware.ts for env to work in production as well in tests.

app.ts

import { Hono } from "hono";
import { configureAppMiddleware } from "./middleware";
import { configureAppRoutes } from "./router";

export function getHonoApp() {
    const app = new Hono();
    configureAppMiddleware(app);
    configureAppRoutes(app);
    return app;
}

middleware.ts

import { Hono } from "hono";
import { env } from "hono/adapter";
import { bearerAuth } from "hono/bearer-auth";

export const configureAppMiddleware = (app: Hono) => {
app.use('/api/*', bearerAuth({
        verifyToken: async (token, c) => {
            // this works in runtime/production with the hono/adapter as per hono docs
            let { API_KEY } = env<{ API_KEY: string }>(c);

            // in testing when MOCK_ENV is passed in, we need to do this as a fallback
            if (!API_KEY) {
                API_KEY = c.env.API_KEY;
            }

            return token === API_KEY
        }
    }))
}

the test looks like this: app.authed.test.ts

import { beforeAll, describe, expect, test } from "vitest";
import { getHonoApp } from "./app";

const MOCK_ENV = {
    API_KEY: 'test_api_key',
}

describe('App - authed routes', () => {
    let app = getHonoApp(); 
    let headers: Record<string, string>;

    beforeAll(() => {
        headers = {
            "Content-Type": "application/json",
            "Authorization": `Bearer ${MOCK_ENV.API_KEY}`
        }
    });

    test('should return 200 and You are authorized on /api/page', async () => {
        // there is a /api/page route that returns some json
        const res = await app.request('/api/page', { headers }, MOCK_ENV);
        // this succeed because of the fallback (hack?) in middleware.ts
        expect(res.status).toBe(200);
        expect(await res.json()).toEqual({ message: 'You are authorized' })
    })
})
github-actions[bot] commented 1 week ago

This issue has been marked as stale due to inactivity.

github-actions[bot] commented 1 week ago

Closing this issue due to inactivity.