1

I'm developing a SvelteKit application and I try to use Vitest to run some tests.

I want to test a simple API endpoint:

// src/routes/api/test/+server.ts

import { testService } from '$lib/server/testService';

export const POST: RequestHandler = async (requestEvent) => {
  return text(testService.sayHello());
};

My backend services are declared as singletons, they never contain any state:

// src/lib/server/testService.ts

class TestService {
  public sayHello() {
    return 'Hello';
  }
}

export const testService = new TestService();

Using Vitest to run some tests:

  1. testing the Service directly works well:

    import { testService } from '$lib/server/testService';
    //...
    
    test('test service', async () => {
      const result = testService.sayHello();
      assert.equal(result, 'Hello');
    });
    
  2. Mocking the "sayHello" method on the service and calling it locally works well too:

    import { testService } from '$lib/server/testService';
    //...
    
    test('test mocked service', async () => {
      const sayHelloSpy = vi.spyOn(testService, 'sayHello');
      sayHelloSpy.mockImplementation(() => 'mocked!');
    
      const result = testService.sayHello();
      assert.equal(result, 'mocked!');
    
      sayHelloSpy.mockRestore();
    });
    
  3. But I'm unable to mock the service so that an HTTP fetch call will use the mocked version!:

    import { testService } from '$lib/server/testService';
    //...
    
    test('test mocked service with fetch', async () => {
      const sayHelloSpy = vi.spyOn(testService, 'sayHello');
      sayHelloSpy.mockImplementation(() => 'mocked!');
    
      const response = await fetch(`http://localhost:12323/api/test`, {
        method: 'POST',
        headers: {
          'content-type': 'application/json'
        }
      });
      assert.isTrue(response.ok);
    
      const result = await response.text();
      assert.equal(result, 'mocked!'); // <--- Fails! This is always "Hello", not "mocked!"
    
      sayHelloSpy.mockRestore();
    });
    

I'm debugging those tests in VS Code using this launch configuration:

{
  "name": "Vitest - current file",
  "type": "node",
  "request": "launch",
  "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
  "args": [
    "run"
    "--run"
    "--test-timeout=0"
    "--api"
    "12323"
    "${fileDirname}/${fileBasenameNoExtension}.ts"
  ],
  "env": {
    "NODE_ENV": "tests"
  },
  "skipFiles": ["<node_internals>/**", "**/node_modules/**"],
  "sourceMaps": true,
  "smartStep": true,
  "timeout": 10000,
  "autoAttachChildProcesses": true,
  "internalConsoleOptions": "neverOpen",
  "console": "integratedTerminal",
  "outputCapture": "std",
  "protocol": "inspector"
},

I'm very impressed with Vitest and how easy it is to run a test that sets up the server correctly so that HTTP calls can be made!

But I'd like to be able to mock some objects that are in the server "context". Is it possible?

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.