LeaVerou / htest

Declarative, boilerplate-free unit testing
https://htest.dev/
MIT License
19 stars 3 forks source link

Messy CLI output #26

Closed LeaVerou closed 6 months ago

LeaVerou commented 6 months ago

I recently made a change where children that have finished and everything passes are not displayed. This helped a lot with decluttering the output, but means I now get this:

image
DmitrySharabin commented 6 months ago

We face messy outputs like this one

image

because when we output the test execution protocol with logUpdate, every call of any of the console methods messes it up.

In the example above, the Color,js's parse() method does it. See https://github.com/color-js/color.js/blob/4de8e038ff6dcde6a845714e64a391cf0653f7a6/src/parse.js#L61-L68.

UPDATE: I confirm this (👆) is the reason for the messy CLI output.

I'll try to figure out whether it's possible to suspend all standard console methods while logUpdate is in charge.

LeaVerou commented 6 months ago

I'll try to figure out whether it's possible to suspend all standard console methods while logUpdate is in charge.

We probably still want to display them, but not in a way that messes up the output. Possibly all before or after the actual test output? One way would be to override the console methods without our own while a test is running, so we can capture the output, and do whatever with it.

DmitrySharabin commented 6 months ago

We probably still want to display them, but not in a way that messes up the output. Possibly all before or after the actual test output? One way would be to override the console methods without our own while a test is running, so we can capture the output, and do whatever with it.

Makes perfect sense. It was on my list to figure out whether we can override the console methods. Glad to know it wasn't a bad idea. 😅

DmitrySharabin commented 6 months ago

One way would be to override the console methods without our own while a test is running, so we can capture the output, and do whatever with it.

Something like this?

function interceptConsole (fn) {
    const methods = ["log", "warn", "error", "info"];
    let originalConsole = {};
    let messages = {};

    for (let method of methods) {
        messages[method] = [];

        originalConsole[method] = console[method];
        console[method] = (...params) => messages[method].push(...params);
    }

    fn();

    for (let method of methods) {
        console[method] = originalConsole[method];
    }

    return messages;
}

And later on, we can re-play (if needed) what was intercepted:

for (let method in messages) {
    for (let message of messages[method]) {
        console[method](message);
    }
}
LeaVerou commented 6 months ago

Yup! Only nit is that your code wouldn't replay them in order, since it groups by method. You'd probably want to use a single queue and store objects like {args, method}, then you can replay them entirely in order. Also note that console.trace() will have the same effect, and it's much harder to replay (since it will then trace to our own code).