Search code examples
javascriptjquerytdderror-logging

Detecting console.log() calls


I'm trying to write a test case for a debugging method that writes messages to the JavaScript console using console.log(). The test has to check that the message has been successfully written to the console. I'm using jQuery.

Is there a way to attach a hook to console.log() or otherwise check that a message has been written to the console, or any other suggestions on how to write the test case?


Solution

  • console.log doesn't keep a record of messages that are logged, or emit any events that you could listen for. It's not possible for your tests to directly verify its output from JavaScript. Instead, your test code will need to replace console.log with a mock implementation that does keep track of log messages for later verification.

    Mocking is a common feature supported by most JavaScript test frameworks. For example, the Jest test framework provides a jest.spyOn function which replaces a given method with a mock implementation that records the arguments for each call in a .mock property before passing them on to the original implementation. After each test you may want to call jest.clearAllMocks() to reset the recorded argument lists for the next test, or use the equivalent clearMocks: true config option.

    function saySomething() {
      console.log("Hello World");
    }
    
    jest.spyOn(console, 'log');
    
    test("saySomething says hello", () => {
      expect(console.log.mock.calls.length).toBe(0);
      saySomething();
      expect(console.log.mock.calls.length).toBe(1);
      expect(console.log.mock.calls[0][0]).toBe("Hello World");
    });
    
    afterEach(() => {
      jest.clearAllMocks();
    });
    

    If you're not using a test framework (you probably should), you can create a simple mock yourself.

    function saySomething() {
      console.log("Hello World");
    }
    
    function testSomething() {
      // Replace console.log with stub implementation.
      const originalLog = console.log;
      const calls = [];
      console.log = (...args) => {
        calls.push(args);
        originalLog(...args);
      };
    
      try {
        console.assert(calls.length == 0);
        saySomething();
        console.assert(calls.length == 1);
        console.assert(calls[0][0] == "Hello World");
      } catch (error) {
        console.error(error);
      } finally {
        // Restore original implementation after testing.
        console.log = originalLog;
      }
    }