Repository: denoland/deno
Pull request: fix: serve handler error with 0 arguments

<!--
Before submitting a PR, please read https://docs.deno.com/runtime/manual/references/contributing

1. Give the PR a descriptive title.

  Examples of good title:
    - fix(std/http): Fix race condition in server
    - docs(console): Update docstrings
    - feat(doc): Handle nested reexports

  Examples of bad title:
    - fix #7123
    - update docs
    - fix bugs

2. Ensure there is a related issue and it is referenced in the PR text.
3. Ensure there are tests that cover the changes.
4. Ensure `cargo test` passes.
5. Ensure `./tools/format.js` passes without changing files.
6. Ensure `./tools/lint.js` passes.
7. Open as a draft PR if your work is still in progress. The CI won't run
   all steps, but you can add '[ci]' to a commit message to force it to.
8. If you would like to run the benchmarks on the CI, add the 'ci-bench' label.
-->

Fixes https://github.com/denoland/deno/issues/23651


Changed files:
filename: ext/http/00_serve.ts
patch: @@ -793,9 +793,9 @@ internals.serveHttpOnConnection = serveHttpOnConnection;
 
 function registerDeclarativeServer(exports) {
   if (ObjectHasOwn(exports, "fetch")) {
-    if (typeof exports.fetch !== "function" || exports.fetch.length !== 1) {
+    if (typeof exports.fetch !== "function") {
       throw new TypeError(
-        "Invalid type for fetch: must be a function with a single parameter",
+        "Invalid type for fetch: must be a function with a single or no parameter",
       );
     }
     return ({ servePort, serveHost }) => {

filename: tests/integration/serve_tests.rs
patch: @@ -14,12 +14,12 @@ async fn deno_serve_port_0() {
     .arg("serve")
     .arg("--port")
     .arg("0")
-    .arg("./serve.ts")
+    .arg("./serve/port_0.ts")
     .stdout_piped()
     .spawn()
     .unwrap();
   let stdout = child.stdout.as_mut().unwrap();
-  let mut buffer = [0; 50];
+  let mut buffer = [0; 52];
   let _read = stdout.read(&mut buffer).unwrap();
   let msg = std::str::from_utf8(&buffer).unwrap();
   let port_regex = Regex::new(r"(\d+)").unwrap();
@@ -49,3 +49,46 @@ async fn deno_serve_port_0() {
   child.kill().unwrap();
   child.wait().unwrap();
 }
+
+#[tokio::test]
+async fn deno_serve_no_args() {
+  let mut child = util::deno_cmd()
+    .current_dir(util::testdata_path())
+    .arg("serve")
+    .arg("--port")
+    .arg("0")
+    .arg("./serve/no_args.ts")
+    .stdout_piped()
+    .spawn()
+    .unwrap();
+  let stdout = child.stdout.as_mut().unwrap();
+  let mut buffer = [0; 52];
+  let _read = stdout.read(&mut buffer).unwrap();
+  let msg = std::str::from_utf8(&buffer).unwrap();
+  let port_regex = Regex::new(r"(\d+)").unwrap();
+  let port = port_regex.find(msg).unwrap().as_str();
+
+  let cert = reqwest::Certificate::from_pem(include_bytes!(
+    "../testdata/tls/RootCA.crt"
+  ))
+  .unwrap();
+
+  let client = reqwest::Client::builder()
+    .add_root_certificate(cert)
+    .http2_prior_knowledge()
+    .build()
+    .unwrap();
+
+  let res = client
+    .get(&format!("http://127.0.0.1:{port}"))
+    .send()
+    .await
+    .unwrap();
+  assert_eq!(200, res.status());
+
+  let body = res.text().await.unwrap();
+  assert_eq!(body, "deno serve with no args in fetch() works!");
+
+  child.kill().unwrap();
+  child.wait().unwrap();
+}

filename: tests/testdata/serve/no_args.ts
patch: @@ -0,0 +1,5 @@
+export default {
+  fetch() {
+    return new Response("deno serve with no args in fetch() works!");
+  },
+};