89  89. Step 15: Automated Testing and Troubleshooting

As of Oct 22, 2026 · Official docs: Jest

Automated tests help ensure everything works after changes.

89.1 Integration Tests

The project includes integration tests in tests/integration/. They talk to your real Supabase project and your Stripe sandbox: they create test users, tasks and payments there. Use a test project, not one with real users.

The test files end in .test.ts (for example 2_auth.test.ts). The test runner, Jest, runs only files whose names end that way.

89.2 Set Up Test Environment

  1. In the project root (the task-app folder), copy the tests’ example settings file, .env.test.example, to a new file named .env.test.local:

    cp .env.test.example .env.test.local

    cp copies the first file to the second. The tests read their settings from .env.test.local in the project root. Like .env.local, it is ignored by Git, so your keys stay off GitHub.

  2. Open .env.test.local and fill in all six variables. Your worksheet’s Commands sheet has the six lines ready to paste; replace the file’s six placeholder lines with them and save the file. Paste keys only into the file, never into Claude’s chat.

    Variable Value
    NEXT_PUBLIC_SUPABASE_URL Your Supabase project URL
    NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY Your Supabase publishable key (sb_publishable_...)
    SUPABASE_SECRET_KEY Your Supabase secret key (sb_secret_...)
    STRIPE_SECRET_KEY Your Stripe sandbox secret key (sk_test_...)
    STRIPE_PRICE_ID Your price’s ID (price_...)
    STRIPE_WEBHOOK_SECRET Your webhook’s signing secret (whsec_...)

    The Supabase secret key is under Project Settings > API Keys (Secret keys) in the Supabase dashboard. It bypasses all of the database’s security rules, so the tests can create and delete test data, and so it goes only in this file, never in .env.local or in a NEXT_PUBLIC_ variable of the app.

  3. Keep the test settings separate from production credentials.

89.3 Run Tests

Run all tests:

npm test

Type it in VS Code’s terminal, in the task-app folder, and press Enter. npm test runs the project’s test script, which runs the tests with a testing tool named Jest.

Run one test file:

npm test tests/integration/2_auth.test.ts

If you see failures due to cold starts or timeouts:

  • Run the tests again.
  • Check that your Edge Functions are deployed and reachable.

89.4 Troubleshooting

A few quick checks for common problems.

89.4.1 Environment Variables Not Loading

  • Verify the filenames:
    • Local Next.js: .env.local
    • Supabase: supabase/.env (if applicable) and Supabase secrets.
  • Restart the dev server after any env changes.
  • Confirm the variables are defined in:
    • The Next.js runtime (console.log(process.env.NEXT_PUBLIC_... )).
    • Supabase dashboard (for secrets).

89.4.2 Authentication Errors

  • In Google Cloud Console (the OAuth client), check that:
    • The Authorized redirect URI is exactly your Supabase callback URL, https://[your-project-ref].supabase.co/auth/v1/callback.
    • The Authorized JavaScript origins include http://localhost:3000 and, once the app is online, your Vercel address.
  • In Supabase (Authentication > URL Configuration), check that:
    • The Site URL is http://localhost:3000 while you work locally, and your Vercel address once the app is online.
    • The Redirect URLs include http://localhost:3000/** and, once the app is online, https://YOUR-APP.vercel.app/**.
  • Inspect the browser network tab for auth-related errors.

89.4.3 Edge Functions Failing

  • Check that all required secrets are set (OPENAI_API_KEY, STRIPE_SECRET_KEY, STRIPE_PRICE_ID, STRIPE_WEBHOOK_SECRET). npx supabase secrets list shows their names.
  • In Supabase:
    • Open Edge Functions, click the function, and read its Logs to see runtime errors.
  • An “Invalid JWT” (401) error, with none of the function’s own messages in its logs: one known fix is to turn off Verify JWT with legacy secret for that function (Edge Functions > the function > Details). This is safe here: the functions check the user’s login themselves.
  • “No Supabase key found in SUPABASE_PUBLISHABLE_KEYS” (or SUPABASE_SECRET_KEYS): Supabase gives the functions these keys automatically, so check Project Settings > API Keys in the dashboard.
  • Make sure code imports are correct and dependencies are installed.

89.4.4 Stripe Webhook Not Working

  • Confirm that Verify JWT with legacy secret is off for stripe-webhook (Edge Functions > stripe-webhook > Details).
  • Check that the Stripe event destination uses the Snapshot payload style and sends checkout.session.completed and customer.subscription.deleted.
  • Double-check the webhook URL in Stripe:
    • It must match the function URL exactly (including https).
  • Ensure the Signing secret in Supabase matches the current secret shown in Stripe.
  • Buy a subscription with a test card, then read the stripe-webhook logs in Supabase (see Step 11).

89.4.5 Database Errors

  • Ensure npx supabase db push ran successfully without errors.
  • Check that RLS policies allow the operation you’re trying.
  • Confirm that the user is authenticated when performing actions that require auth.
  • Inspect Supabase logs or use the SQL editor to run queries manually.

Practice Questions

Easy

Question 1 · Short answer

What is an integration test, and what is its advantage over clicking through the app yourself after every change?

An integration test is a small program that checks that several parts work together - here, the app’s code with your real Supabase project (database, storage, edge functions). Because the tests are automated, one command re-runs all of them after every change, the same way every time. Clicking through by hand is slow, and it’s easy to forget a step.

Question 2 · Write the command

Write the command that runs all of the project’s automated tests.

npm test

Run it from the project root, the task-app folder.

Question 3 · Multiple choice

Which file holds the environment variables for the Next.js app when you run it on your own computer?

  1. .env.local
  2. package.json
  3. .gitignore
  4. README.md

a. The troubleshooting checklist names .env.local for local Next.js. package.json (b) lists the project’s packages and scripts, .gitignore (c) lists the files Git should ignore (including .env.local itself), and README.md (d) is documentation.

Question 4 · True or false

It’s fine to point the integration tests at your production Supabase project, the one that holds real users’ data.

False. The tests create, change and delete real records (users, tasks, payments) in whatever project they are pointed at. That is why the page says to use a test project, not one with real users, and to keep the test settings separate from production credentials.

Question 5 · Multiple choice

In .env.test.local, which variable holds your Supabase secret key (sb_secret_...)?

  1. NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY
  2. SUPABASE_SECRET_KEY
  3. NEXT_PUBLIC_SUPABASE_SECRET_KEY
  4. STRIPE_SECRET_KEY

b. SUPABASE_SECRET_KEY is the tests’ name for it. Option a holds the publishable key (sb_publishable_...), and d holds the Stripe secret key (sk_test_...). Option c is dangerous: a NEXT_PUBLIC_ name means “built into the web pages”, and a secret key must never get one.

Medium

Question 6 · Write the command

The project contains the test file tests/integration/3_storage.test.ts. Following the pattern on this page, write the command that runs only this file.

npm test tests/integration/3_storage.test.ts

npm passes the file name on to the test tool, Jest, which then runs only that file. (npm test -- tests/integration/3_storage.test.ts works too: the -- tells npm that everything after it is for the test tool, not for npm.)

Question 7 · Short answer

A test fails with a timeout the first time you run the tests, then passes when you run them again right away. What is a likely cause, and what does the page suggest?

A cold start: an edge function that hasn’t been used for a while needs a moment to start up, so the first request can be slow enough to hit the test’s time limit. On the second run the function is already “warm” and answers quickly. The page suggests running the tests again, and checking that your edge functions are deployed and reachable.

Question 8 · Multiple choice

Your deployed edge functions need keys such as OPENAI_API_KEY. Where do they read these values from?

  1. The supabase/.env file on your laptop
  2. The secrets stored in your Supabase project (set with npx supabase secrets set ...)
  3. The environment variables of your Vercel project
  4. The .env.local file

b. Deployed functions run on Supabase’s servers, which can’t read files on your laptop - not even supabase/.env (a). The values must be stored in the Supabase project as secrets. Vercel’s variables (c) and .env.local (d) are for the Next.js app, not for edge functions. To see which secrets are set, run npx supabase secrets list (it shows their names, not their values).

Question 9 · Matching

Match each symptom with the section of the troubleshooting checklist you would turn to first.

Symptom Checklist section
1. On the live site, after signing in with Google you land on localhost A. Database Errors
2. Saving data fails with an error that mentions a “row-level security policy” B. Edge Functions Failing
3. Stripe test payments succeed, but nothing changes in your database C. Environment Variables Not Loading
4. AI labels stopped appearing, and the function’s logs show errors D. Authentication Errors
5. You added a new key to .env.local, but the app still behaves as if it isn’t there E. Stripe Webhook Not Working

1 → D, 2 → A, 3 → E, 4 → B, 5 → C.

Question 10 · Short answer

An Edge Function’s logs show the error “No Supabase key found in SUPABASE_SECRET_KEYS”. Should you fix it with npx supabase secrets set? What do you check instead?

No. You don’t set SUPABASE_SECRET_KEYS yourself: Supabase gives the functions their project’s publishable and secret keys automatically. The message points to Project Settings > API Keys in the Supabase dashboard: check there that the project has a secret key. (npx supabase secrets set is for the keys of other services, such as OPENAI_API_KEY.)

Hard

Question 11 · Scenario

You deleted your old Stripe webhook endpoint and created a new one with the correct URL. Stripe now delivers events to your stripe-webhook function, but the database is never updated, and the function’s logs show a signature-verification error. What’s wrong, and how do you fix it?

Every Stripe webhook endpoint has its own signing secret (whsec_...). Your new endpoint got a new secret, but Supabase still holds the old one in STRIPE_WEBHOOK_SECRET, so the function can’t verify the signatures and rejects every event. Fix: copy the new endpoint’s signing secret from the Stripe Dashboard and store it in Supabase:

npx supabase secrets set STRIPE_WEBHOOK_SECRET=whsec_...

This is the checklist item “Ensure the Signing secret in Supabase matches the current secret shown in Stripe”.

Question 12 · Scenario

Clicking “Sign in with Google” takes you to a Google error page that says Error 400: redirect_uri_mismatch. What is the most likely cause, and what exactly would you compare?

The Authorized redirect URI saved in Google Cloud Console doesn’t exactly match the callback address that Supabase uses. Compare the URI in your OAuth credentials in Google Cloud Console with Supabase’s callback URL, which has the form https://[your-project-ref].supabase.co/auth/v1/callback. They must match character for character: look for a wrong project ref, http instead of https, a typo in /auth/v1/callback or an extra / at the end.

Question 13 · Scenario

Maria signs in and opens the dashboard, but her task list is empty. In the Supabase Table Editor you can see rows in the tasks table that belong to her. Using the “Database Errors” checklist, what two things would you check, and why might there be no error message at all?

Check that (1) the app’s request really is made as the signed-in user - a request without Maria’s sign-in information counts as anonymous - and (2) the RLS policies on tasks allow users to read their own rows. With row level security, rows you aren’t allowed to see are simply left out of the results, so the app gets an empty list instead of an error. The Table Editor shows the rows because the Supabase dashboard looks at the data with full admin rights, which RLS does not limit.

Question 14 · Scenario

Maria creates a task, but no AI label appears. In the create-task-with-ai logs she finds an “Invalid JWT” (401) error, and none of the messages the function’s code prints. Which section of the troubleshooting checklist applies, what is one known fix, and why is it safe?

“Edge Functions Failing”. Supabase’s JWT check refused the call before the function’s code ran. One known fix: turn off Verify JWT with legacy secret for that function (Edge Functions > create-task-with-ai > Details). It is safe because the function checks the user’s login itself and stops if nobody is signed in.

© 2025-2026 Y. Rosenthal. All rights reserved.