Repository: denoland/deno
File: cli/tools/test/mod.rs (Rust)

Code before:

  pub fn overview(&self) -> String {
    match self {
      TestFailure::JsError(js_error) => js_error.exception_message.clone(),
      TestFailure::FailedSteps(1) => "1 test step failed".to_string(),
      TestFailure::FailedSteps(n) => format!("{n} test steps failed"),
      TestFailure::IncompleteSteps => {
        "Completed while steps were still running".to_string()
      }
      TestFailure::Incomplete => "Didn't complete before parent".to_string(),
      TestFailure::Leaked(_, _) => "Leaks detected".to_string(),
      TestFailure::OverlapsWithSanitizers(_) => {
        "Started test step while another test step with sanitizers was running"
          .to_string()
      }
      TestFailure::HasSanitizersAndOverlaps(_) => {
        "Started test step with sanitizers while another test step was running"
          .to_string()
      }
    }
  }

  pub fn error_location(&self) -> Option<TestLocation> {
    match self {
      // TODO: What happens if not enough call stack frames were recorded?
      // TODO: Could anything else trigger the ext:cli/40_test.js file? Maybe we should also test for the method name
      TestFailure::JsError(js_error) => js_error
        .frames
        .iter()
        .position(|v| v.file_name.as_deref() == Some("ext:cli/40_test.js"))
        // Go one up in the stack frame, this is where the user code was
        .and_then(|index| index.checked_sub(1))
        .and_then(|index| {
          let user_frame = &js_error.frames[index];
          let file_name = user_frame.file_name.as_ref()?.to_string();
          // Turn into zero based indices
          let line_number = user_frame.line_number.map(|v| v - 1)? as u32;
          let column_number =
            user_frame.column_number.map(|v| v - 1).unwrap_or(0) as u32;
          Some(TestLocation {
            file_name,
            line_number,
            column_number,
          })
        }),
      _ => None,
    }
  }

  fn format_label(&self) -> String {
    match self {

Review comment (bug):
Yes, it's quite easy to for something else to trigger a `ext:` file. Like an illegal call to `Deno.test` from within a test.

![image](https://github.com/user-attachments/assets/19660e6d-0ca7-402f-a31e-cee14ff6f618)

```
TypeError: The test name can't be empty
  Deno.test("",() => {
       ^
    at testInner (ext:cli/40_test.js:224:13)
    at Object.test (ext:cli/40_test.js:332:10)
    at addTest (file:///C:/Users/Stefnotch/Desktop/dt/main_test.ts:8:8)
```

This particular case happens to be handled correctly, since it fails to find a user function above the `ext` line. So it defaults back to "report it wherever the test is"

Code after:

  pub fn overview(&self) -> String {
    match self {
      TestFailure::JsError(js_error) => js_error.exception_message.clone(),
      TestFailure::FailedSteps(1) => "1 test step failed".to_string(),
      TestFailure::FailedSteps(n) => format!("{n} test steps failed"),
      TestFailure::IncompleteSteps => {
        "Completed while steps were still running".to_string()
      }
      TestFailure::Incomplete => "Didn't complete before parent".to_string(),
      TestFailure::Leaked(_, _) => "Leaks detected".to_string(),
      TestFailure::OverlapsWithSanitizers(_) => {
        "Started test step while another test step with sanitizers was running"
          .to_string()
      }
      TestFailure::HasSanitizersAndOverlaps(_) => {
        "Started test step with sanitizers while another test step was running"
          .to_string()
      }
    }
  }

  pub fn error_location(&self) -> Option<TestLocation> {
    const TEST_RUNNER: &str = "ext:cli/40_test.js";
    match self {
      TestFailure::JsError(js_error) => js_error
        .frames
        .iter()
        // The first line of user code comes above the test file.
        // The call stack usually contains the top 10 frames, and cuts off after that.
        // We need to explicitly check for the test runner here.
        // - Checking for a `ext:` is not enough, since other Deno `ext:`s can appear in the call stack.
        // - This check guarantees that the next frame is inside of the Deno.test(),
        //   and not somewhere else.
        .position(|v| v.file_name.as_deref() == Some(TEST_RUNNER))
        // Go one up in the stack frame, this is where the user code was
        .and_then(|index| index.checked_sub(1))
        .and_then(|index| {
          let user_frame = &js_error.frames[index];
          let file_name = user_frame.file_name.as_ref()?.to_string();
          // Turn into zero based indices
          let line_number = user_frame.line_number.map(|v| v - 1)? as u32;
          let column_number =
            user_frame.column_number.map(|v| v - 1).unwrap_or(0) as u32;
          Some(TestLocation {
            file_name,
            line_number,
            column_number,
          })
        }),
      _ => None,