0

The Problem

What I'm trying to do is test that the error is caught and returned with the correct status code when a use case function returns a rejected promise.

The problem I'm having is that instead of a rejected promise, i just get this error instead of the mock function just returning a rejected promise.

This is the error that I'm getting: TypeError: Cannot read properties of undefined (reading 'then')

The code

Inside a test suite I have this setup:

const container = new Container();

describe('Controller Error Tests', () => {
     let reportController: ReportController;
     
     let generateReportUseCase: IGenerateReportUseCase = mock<IGenerateReportUseCase>();

     container.bind<ReportServiceLocator>(TYPES.ReportServiceLocator).to(ReportServiceLocator);
     
     beforeAll(async () => {
        jest.clearAllMocks();
        cleanUpMetadata();
        dotenv.config();
        reportController = new ReportController(container.get<ReportServiceLocator>(Symbol.for("ReportServiceLocator")));
    });

     it('User held shares report use case throws error', async () => {
        let requestObj = httpMocks.createRequest({
            cookies: {
                token: jwt.sign({ id: 'test' }, process.env.JWT_SECRET_KEY!),
            },
            query: {
                report_type: 'CSV'
            }
        });

        let responseObj = httpMocks.createResponse();

        mock(generateReportUseCase).usersHeldShares.mockRejectedValue(new Error('Could not generate report'));

        await reportController.userHeldShares(requestObj, responseObj);
        expect(responseObj.statusCode).toEqual(500);
    })
})

reportController.userHeldShares is an inversify controller that looks like this:

@httpGet('/held-shares')
    public async userHeldShares(@request() req: express.Request, @response() res: express.Response){
        let jwtSecretKey = process.env.JWT_SECRET_KEY;
        let ascending: boolean = req.query.ascending === "false" ? false : true;
        let report_type: string = String(req.query.reportformat);
        let cookieData = await <IUserDto>jwt.verify(req.cookies.token, jwtSecretKey!);
            
        if(!cookieData.id){
            return res.status(401).json({error: 'User not authorised'});
        }
        
        return await this.generateReportUseCase.usersHeldShares(cookieData.id!, ascending, report_type)
            .then((userDto: IUserDto) => {
                res.status(200).json(userDto)
            })
            .catch((err: Error) => {
                res.status(500).json(err);
            });
    }

Here is what the first few lines of generateReportUseCase.usersHeldShares looks like, which is where the error comes from:

usersHeldShares(user_id: string, ascending: boolean, report_type: string): Promise<IUserDto> {
        return new Promise(async (resolve, reject) => {
            this.tradeReadOnlyRepository.fetch({user_id: user_id}, false)
            .then(async trades => {

What I am expecting

When it hits the line return await this.generateReportUseCase.usersHeldShares(cookieData.id!, ascending, report_type) in the inversify controller it just returns a rejected promise without entering the logic of the actual function.

Adam Cole
  • 1
  • 1

1 Answers1

0

It turns out I was still using a service locator for the proper implementation of the report generator. I replaced this with a TestServiceLocator which will now contain all of the mock return values.

The implementation of this is like so: container.bind<TestServiceLocator>(TYPES.ReportServiceLocator).to(TestServiceLocator);

@injectable()
export default class TestServiceLocator {
    constructor(@inject(TYPES.IStockReadOnlyRepository) private stockReadRepository: IStockReadOnlyRepository,
                @inject(TYPES.IStockWriteOnlyRepository) private stockWriteRepository: IStockWriteOnlyRepository,
                @inject(TYPES.IUserWriteOnlyRepository) private userWriteRepository: IUserWriteOnlyRepository,
                @inject(TYPES.IUserReadOnlyRepository) private userReadRepository: IUserReadOnlyRepository,
                @inject(TYPES.ITradeReadOnlyRepository) private tradeReadRepository: ITradeReadOnlyRepository,
                @inject(TYPES.ITradeWriteOnlyRepository) private tradeWriteRepository: ITradeWriteOnlyRepository){}

    public GetGenerateReportUseCase(): IGenerateReportUseCase {
        let generateReportUseCase: IGenerateReportUseCase = mock<IGenerateReportUseCase>();
        mock(generateReportUseCase).completeStockValues.mockRejectedValue(new Error('Could not generate report'));
        mock(generateReportUseCase).selectedCompanyDetails.mockRejectedValue(new Error('Could not generate report'));
        mock(generateReportUseCase).usersHeldShares.mockRejectedValue(new Error('Could not generate report'));
        return generateReportUseCase;
    }

    public GetDownloadReportUseCase(): IDownloadReportUseCase {
        let downloadReportUseCase: IDownloadReportUseCase = mock<IDownloadReportUseCase>();
        mock(downloadReportUseCase).invoke.mockRejectedValue(new Error('Could not get report data'));
        return downloadReportUseCase;
    }
}
Adam Cole
  • 1
  • 1