You're building a test harness that needs to assert on what a piece of code logged — but reading real stdout from inside a test is awkward and flaky. Implement createLogHistory(), which replaces console.log with a wrapper that records every call's arguments into an array you can read later, still forwards each call to the real console.log so nothing disappears from the terminal, and hands you a restore() to put the original console.log back when you're done. This is the same shape as a logging spy — patch a global, record calls, restore it afterward.
// createLogHistory() patches console.log AT CALL TIME and returns a handle.
function createLogHistory(): {
// history[i] is the array of arguments passed to the i-th console.log call,
// in call order. console.log('a', 1) => history entry ['a', 1].
history: unknown[][];
// Put the ORIGINAL console.log back. After this, new logs are not recorded.
restore: () => void;
// Empty the history array in place, keeping the patch active.
clear: () => void;
};
Calling createLogHistory() installs the patch immediately — every console.log after that point is recorded until you call restore().
const { history, restore } = createLogHistory();
console.log('hello');
console.log('x =', 42);
restore();
history; // → [ ['hello'], ['x =', 42] ]
console.log('after restore'); // not recorded — history unchanged
history.length; // → 2
const log = createLogHistory();
console.log('a', 'b', 'c'); // all three args captured in one entry
log.history; // → [ ['a', 'b', 'c'] ]
log.clear();
log.history; // → [] (same array, emptied)
console.log('again');
log.history; // → [ ['again'] ] (patch still active after clear)
log.restore();
console.log so output keeps reaching the terminal. Capture a reference to the original before you overwrite console.log, then call it from inside your wrapper.history[i] is an array of all arguments, not just the first. console.log('x =', 42) records ['x =', 42]. A call with no arguments records [].restore() is mandatory. Without it, every test that patches console.log leaks the patch into the next test. restore() must reinstall the exact original function reference, not a fresh console.log.restore() stops recording. Calls made after restore() go straight to the original and never touch history.history inside clear() — empty the existing array in place (e.g. history.length = 0) so any reference the caller already holds stays valid.console.warn / console.error, formatting the args into a string, or timestamps — those are extensions covered in the solution's "Going further."