Having trouble mocking server response in test spec

112 Views Asked by At

I have a monorepo that's Angular, Express, Node. I'm running test suites and reporting coverage fine, but when I try to build out unit tests for my main server file, index.ts, it fails on the first assertion I try:

index.spec.ts:

import * as request from 'supertest';
import * as express from 'express';

import { setupApp, sendAngularApp } from './index'; 

describe('Express server', () => {
  let app: express.Application;
  process.env.NODE_ENV = 'production';
  process.env.SERVER_PORT = '9200';
  var server: any;

  beforeEach(() => {
    app = setupApp(); // Use the helper function to set up the Express application
    // Store the original sendFile method and replace it with a mock implementation
    server = app.listen(process.env.SERVER_PORT || 3000, () => {
      console.log('Express server is running on ' + (process.env.SERVER_PORT || 3000))
    });
  });

  afterEach(() => {
    server.close();
  });

  describe('GET /', function() {
    it('serves the index file for the root path', async () => {
      const response = await request(app).get('/');
      expect(response.status).toBe(200);
      expect(response.headers['content-type']).toBe('text/html; charset=UTF-8');
    });
  });
});

I imagine it's related to the fact that the server has a catch-all to send the index of the angular app for any request. BUT that file doesn't exist during testing; it's built when the frontend is run. I outsourced the send to a function with the intent of mocking it in Jasmine, but can't seem to figure out how to do that.

index.ts:

import * as path from "path";
import * as express from 'express';
import { Request, Response, NextFunction } from 'express';
import * as pino from 'express-pino-logger';
import config from './config/environment';
import rateLimit from 'express-rate-limit';
import apiRouter from './routes/api';

declare global {
  var cache: {
    [resource: string]: {
      time: Date,
      data: any,
    }
  };
}
global.cache = {};

export function sendAngularApp(req: Request, res: Response) {
  res.sendFile(path.join(__dirname, 'client/dist/angular-boilerplate', 'index.html'));
}

export function setupApp(): express.Application {
  const app = express();

  const logger = pino();
  app.use(logger); // logging framework
  
  app.use(express.json());
  
  const apiLimiter = rateLimit({
    windowMs: 10 * 60 * 1000, // 10 minute window
    max: 2000, // Limit each IP to 2000 requests per `window`
    standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
    legacyHeaders: false, // Disable the `X-RateLimit-*` headers
  });
  
  app.use((req: Request, res: Response, next: NextFunction) => {
    console.log('Time:', Date.now());
    next();
  });
  app.use('/api', apiLimiter);
  app.use('/api', apiRouter);
  
  if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging' || process.env.NODE_ENV === 'development') {
    // Serve any static files
    let dirname = __dirname.replace("/server", "")
    app.use(express.static(path.join(dirname, 'client/dist/angular-boilerplate'),{maxAge:3600000}));
  
    // Handle app routing, return all requests to ngx app
    app.get('*', sendAngularApp);
  }
  return app;
}

if (require.main === module) {
  const app = setupApp();
  app.listen(config.server_port || 3000, () => {
    console.log('Express server is running on ' + (config.server_port || 3000))
  });
}

Link to repo: https://github.com/TheGameKnave/angular-boilerplate

Edit:
Steps tried:
leaning kind of heavily on Codeium (GPT) suggestions for mocking, but they always seem to assume I'm on Jest and don't have great suggestions for Jasime or Sinon spies. Perhaps I should just pivot to jest (I do prefer it in general) but I'm on Jasmine for the frontend and it feels odd to use 2 different test frameworks...(?)
One thing is that Codeium always seems to assume the index.ts file is a module, and tries to make suggestions to match (like referring to the sendAngularApp function as index.sendAngularApp). I'm more green with node and am not sure whether or how to convert to modules over flat ts files.

0

There are 0 best solutions below