supabase / functions-js

MIT License
64 stars 22 forks source link

Negative tests for edge functions with Deno #65

Open ghost opened 1 year ago

ghost commented 1 year ago

Bug report

Describe the bug

I am trying to write some negative tests for my edge functions, for example:

const testSomeFunction = async () => {
  const { data, error } = await supabaseUser.functions.invoke('some-function', {
    body: {
      userId: 'invalid-id'
    }
  })

  assertEquals(error.message, 'Edge Function returned a non-2xx status code')
  assertEquals(data, null)
}

But when running deno test, the test fails with:

error: Leaking resources:
  - A fetch response body (rid 18) was created during the test, but not consumed during the test. Consume or close the response body `ReadableStream`, e.g `await resp.text()` or `await resp.body.cancel()`.

But I cannot access the response to consume/close/cancel/... it.

To Reproduce

Steps to reproduce the behavior, please provide code snippets or a repository:

  1. Create edge function
  2. Create negative test for edge function
  3. Run deno test

Expected behavior

I expect the test to pass, without any leaking resources.

System information

LaskeJu commented 11 months ago

Ugly workaround to make my tests pass ...

Deno.test("Test something", async () => {
  try {
    await testSomething();
  } catch (error) {
    console.error(error);
  } finally {
    const resources = Deno.resources();
    for (const rid in resources) {
      if (resources[rid] === "fetchResponse") {
        Deno.close(parseInt(rid));
      }
    }
  }
});}
carlosdp commented 9 months ago

Also running into this when running tests with supabase-js, it seems to only happen on tests that are testing for an error response

chrissy0 commented 8 months ago

Any news on this?

ghost commented 8 months ago

This worked for us:

const { data, error } = await supabaseUser.functions.invoke('some-function', {
  body: {
    userId: 'invalid-id'
  }
})
assertEquals(data, null)
await assertError(error, 'expected error message')

And:

export async function assertError(
  error: FunctionsHttpError | FunctionsRelayError | FunctionsFetchError,
  expectedErrorMessage: string,
) {
  assertEquals(error.name, 'FunctionsHttpError')
  const { message: actualErrorMessage }: { message: string } = await error.context.json()
  assertEquals(
    actualErrorMessage,
    expectedErrorMessage,
  )
}

Because we always return a message with an error response:

const responseData = { message, data }
return new Response(JSON.stringify(responseData), {
  headers: { ...corsHeaders, 'Content-Type': 'application/json' },
  status: httpStatusCode,
})

Which we can assert in the edge function test.