typemoq icon indicating copy to clipboard operation
typemoq copied to clipboard

detecting multiple calls when only one is present

Open troywweber7 opened this issue 5 years ago • 2 comments

This seems to completely be a bug and I don't see this happening anywhere else... I have an isolated test as shown below:

fdescribe('getSelectedRangeAsHelper', () =>
{
	const address = 'ABC123:DEF456';

	beforeAll(() =>
	{
		spyOnProperty(service, 'ctx').and.returnValue(mContext.object);
		mocks.forEach(m => m.reset());
		mContext.setup(x => x.workbook).returns(() => mWorkbook.object);
		mContext.setup(x => x.sync()).returns(() => Promise.resolve(undefined));
		mWorkbook.setup(x => x.getSelectedRange()).returns(() => mRange.object);
		mRange.setup(x => x.address).returns(() => address);
	});

	it('should return a range helper for the address of the selected range', async () =>
	{
		const helper = await service.getSelectedRangeAsHelper();

		// TODO not sure why this one is broke and saying it is run 3 times... --- TWW
		expect(() => mWorkbook.verify(x => x.getSelectedRange(), Times.once())).not.toThrow();
		expect(() => mRange.verify(x => x.load({ address: true }), Times.once())).not.toThrow();
		expect(() => mContext.verify(x => x.sync(), Times.once())).not.toThrow();
		expect(helper).toEqual(jasmine.any(Helpers.RangeHelper));
		expect(helper.address()).toEqual(address);
	});
});

Some background: I'm mocking objects from the ExcelApi which is not available at runtime when the karma-jasmine test runs, so the dynamic testing is required. Also, this is karma-jasmine run for an Angular project.

The function being tested is on a class:

async getSelectedRangeAsHelper():Promise<RangeHelper>
{
	const ctx = this.ctx;
	const selected = ctx.workbook.getSelectedRange();
	selected.load({ address: true });
	await ctx.sync();
	return new RangeHelper(selected.address);
}

Any ideas what might be happening? Other mocking/testing methods show that it is indeed being called once, so I sense that I could be misunderstanding or misusing typemoq or that this is a bug.

troywweber7 avatar Oct 29 '18 16:10 troywweber7

... and I'm having it happen again on this test...

The function on the class:

async sheetExists(name:string):Promise<boolean>
{
	const ctx = this.ctx;
	const ws = ctx.workbook.worksheets.getItemOrNullObject(name);
	ws.load('isNullObject');
	await ctx.sync();
	return !ws.isNullObject;
}

The test that is failing (the second spec says that it is being invoked 7 times when it is clearly being invoked once per test)...

fdescribe('sheetExists', () =>
{
	beforeEach(() =>
	{
		spyOnProperty(service, 'ctx').and.returnValue(mContext.object);
		mocks.forEach(m => m.reset());
		mContext.setup(x => x.workbook).returns(() => mWorkbook.object);
		mContext.setup(x => x.sync()).returns(() => Promise.resolve(undefined));
		mWorkbook.setup(x => x.worksheets).returns(() => mWorksheets.object);
		mWorksheets.setup(x => x.getItemOrNullObject('existing sheet')).returns(() => mNullObject.object);
		mWorksheets.setup(x => x.getItemOrNullObject('non existing sheet')).returns(() => mNullObject.object);
	});

	it('should getItemOrNullObject and return false if it is a null object', async () =>
	{
		mNullObject.setup(x => x.isNullObject).returns(() => false);
		const exists = await service.sheetExists('existing sheet');
		expect(exists).toBe(true);
		expect(() => mWorksheets.verify(x => x.getItemOrNullObject('existing sheet'),Times.once())).not.toThrow();
		expect(() => mNullObject.verify(x => x.load('isNullObject'), Times.once())).not.toThrow();
		expect(() => mContext.verify(x => x.sync(), Times.once())).not.toThrow();
	});

	it('should getItemOrNullObject and return true if it is not a null object', async () =>
	{
		mNullObject.setup(x => x.isNullObject).returns(() => true);
		const exists = await service.sheetExists('non existing sheet');

		expect(exists).toBe(false);
		expect(() => mWorksheets.verify(x => x.getItemOrNullObject('non existing sheet'), Times.once())).not.toThrow();
		expect(() => mNullObject.verify(x => x.load('isNullObject'), Times.once())).not.toThrow();
		expect(() => mContext.verify(x => x.sync(), Times.once())).not.toThrow();
	});
});

Unless I'm doing something wrong in my syntax, then this is making typemoq completely unusable.

troywweber7 avatar Oct 29 '18 17:10 troywweber7

I am also running into this issue. I think it is related to verify on a function named "load". I think the number that it returns instead of one is returning the count of other invocations. It was saying that I was invoking load five times which correlates to the number of await calls I called in my class + the one actual call to "load".

Zephan92 avatar Dec 21 '18 21:12 Zephan92