Repository: unjs/h3 (ts)

Issue:
Returning `null` overrides status code 
From https://github.com/unjs/ipx/issues/178 by @aaharu

```js
import { createServer } from 'node:http'
import { createApp, eventHandler, toNodeListener, setResponseStatus } from 'h3'

const app = createApp()
app.use(
  '/',
  eventHandler((event) => {
    setResponseStatus(event, 304)
    return null
  })
)

createServer(toNodeListener(app)).listen(process.env.PORT || 8000)
```

The `sendNoContent` utility should check already set status code and only try to override it if not already set to something else.

Pull request:
fix(sendNoContent): preserve custom status code if already set
<!---
bugfix: returning null doesnt override status code
-->

### 🔗 Linked issue

Resolves #560

### ❓ Type of change

- [ ] 📖 Documentation (updates to the documentation, readme, or JSdoc annotations)
- [x] 🐞 Bug fix (a non-breaking change that fixes an issue)
- [ ] 👌 Enhancement (improving an existing functionality like performance)
- [ ] ✨ New feature (a non-breaking change that adds functionality)
- [ ] 🧹 Chore (updates to the build process or auxiliary tools and libraries)
- [ ] ⚠️ Breaking change (fix or feature that would cause existing functionality to change)

### 📚 Description
Resolves #560
setResponseStatus didn't work when no content was returned from eventHandler

### 📝 Checklist

- [ X] I have linked an issue or discussion.
- [ ] I have updated the documentation accordingly.


Patch:
diff --git a/src/utils/response.ts b/src/utils/response.ts
index 3d36a97..b7f6ca5 100644
--- a/src/utils/response.ts
+++ b/src/utils/response.ts
@@ -36,6 +36,11 @@ export function sendNoContent(event: H3Event, code?: number) {
   if (event.handled) {
     return;
   }
+
+  if (!code && event.node.res.statusCode !== 200) {
+    // status code was set with setResponseStatus
+    code = event.node.res.statusCode;
+  }
   const _code = sanitizeStatusCode(code, 204);
   // 204 responses MUST NOT have a Content-Length header field
   // https://www.rfc-editor.org/rfc/rfc7230#section-3.3.2


Test patch:
diff --git a/test/status.test.ts b/test/status.test.ts
new file mode 100644
index 0000000..7d62661
--- /dev/null
+++ b/test/status.test.ts
@@ -0,0 +1,113 @@
+import { describe, it, expect, beforeEach } from "vitest";
+import {
+  createApp,
+  App,
+  toPlainHandler,
+  PlainHandler,
+  eventHandler,
+  setResponseStatus,
+} from "../src";
+
+describe("setResponseStatus", () => {
+  let app: App;
+  let handler: PlainHandler;
+
+  beforeEach(() => {
+    app = createApp({ debug: true });
+    handler = toPlainHandler(app);
+  });
+
+  describe("content response", () => {
+    it("sets status 200 as default", async () => {
+      app.use(
+        "/test",
+        eventHandler(() => {
+          return "text";
+        }),
+      );
+
+      const res = await handler({
+        method: "POST",
+        path: "/test",
+        headers: [],
+      });
+
+      expect(res).toMatchObject({
+        status: 200,
+        statusText: "",
+        body: "text",
+        headers: [["content-type", "text/html"]],
+      });
+    });
+    it("override status and statusText with setResponeStatus method", async () => {
+      app.use(
+        "/test",
+        eventHandler((event) => {
+          setResponseStatus(event, 418, "status-text");
+          return "text";
+        }),
+      );
+
+      const res = await handler({
+        method: "POST",
+        path: "/test",
+        headers: [],
+        body: "",
+      });
+
+      expect(res).toMatchObject({
+        status: 418,
+        statusText: "status-text",
+        body: "text",
+        headers: [["content-type", "text/html"]],
+      });
+    });
+  });
+
+  describe("no content response", () => {
+    it("sets status 204 as default", async () => {
+      app.use(
+        "/test",
+        eventHandler(() => {
+          return null;
+        }),
+      );
+
+      const res = await handler({
+        method: "POST",
+        path: "/test",
+        headers: [],
+      });
+
+      expect(res).toMatchObject({
+        status: 204,
+        statusText: "",
+        body: undefined,
+        headers: [],
+      });
+    });
+    it("override status and statusText with setResponeStatus method", async () => {
+      app.use(
+        "/test",
+        eventHandler((event) => {
+          setResponseStatus(event, 418, "status-text");
+          return null;
+        }),
+      );
+
+      const res = await handler({
+        method: "POST",
+        path: "/test",
+        headers: [],
+        body: "",
+      });
+
+      expect(res).toMatchObject({
+        status: 418,
+        statusText: "status-text",
+        body: undefined,
+        headers: [],
+      });
+    });
+  });
+});