Problem while trying to spy on moment.js function

Viewed 546

I've been trying for a project to implement tests with jasmine on some Angular code.

Here is how I tried to make it work

beforeEach(() => {
        input = [
            "2020-09-30T21:00:00Z",
            "2020-09-30T21:00:20.2Z",
            "2020-09-30T21:00:00.0002Z",
            "2020-09-30T21:00:00.200002Z"
        ];

    });
    it('sould output a valid date format corresponding to entry date', () => {
        spyOn(moment().tz, 'format').and.callThrough()

        var output = [
            "23:00:00",
            "23:00:20.200",
            "23:00:00.000.2",
            "23:00:00.200.002"
        ];
        expect(myService.myFunction(input[0], "Europe/Paris")).toEqual(output[0]);
        expect(moment.format).toHaveBeenCalledWith('HH:mm:ss');
    });

And here is the function

let result = moment(date).tz(timezone).format('HH:mm:ss');

    if (date.includes(".")) {
        result += moment(date).tz(timezone).format('.SSS');

        const fracSec = date.split(".")[1].slice(0, -1); //remove Z and get fractionnal seconds
        if (fracSec.length > 3) {
            result += `.${fracSec.slice(-(fracSec.length - 3))}`;
        }
    }
    return result;

I've tried multiple solutions, changing spyOn() function call as well as the expect(), but I never made it work. The test fail saying that the function cannot be found.

    Error: <spyOn> : format() method does not exist
    Usage: spyOn(<object>, <methodName>)

I've managed to make the spy work with this :

spyOn(moment, 'tz').and.returnValue({
            format: jasmine.createSpy()
        });


expect(moment.tz().format).toHaveBeenCalled();

but then I get an error saying that the function was never called

Error: Expected spy unknown to have been called.

If you have propositions on how I could get this spy to work, thanks in advance.

2 Answers

The problem is that moment.tz() call always returns new value. So the format method will never be the same.

You came close to solving the issue in the last attempt. But in order to be able to check the spy, you need to save it.

const formatSpy = jasmine.createSpy();

spyOn(moment, 'tz').and.returnValue({
            format: formatSpy 
        });
// Call your function here.
myService.myFunction();

expect(formatSpy ).toHaveBeenCalled();

Because this is the unit test, you do not need to be able to call-throught. You can just test that the spy has been called with correct values - because you can be sure that the actual method implementation is correct. You can return bogus info if your code depends on it.

UPDATE As precised by kvetis, one of the problem is that a new format() function exist for each tz() called. I realised that I call moment(date) in my service, wich will probably have a new tz() function for each moment(date) call. I tested this by replacing this line in my service:

let result = moment(date).tz(timezone).format('HH:mm:ss');

By

let result = moment.tz(timezone).format('HH:mm:ss');

And sure inoff the test passed, now I need to find a way to get my moment(date) while calling .tz() from the moment class. Or a way to handle the new tz() for each new moment() function call

Related