Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ability to inject custom middleware #1612

Labels

Comments

@shanear
Copy link
Contributor

shanear commented Oct 9, 2015

We're trying to switch from test'em to karma, and one big issue is the inability to inject custom middleware into the karma test server.

Here is where test'em allows middleware injection via a configuration option:
https://github.com/airportyh/testem/blob/e70cbd7f67444b1a9070102d58c6789d39946529/lib/server/index.js#L149

The karma webserver has a mechanism that's far more obtuse and restrictive (also, the comments make it seem like it's on the chopping block):
https://github.com/karma-runner/karma/blob/master/lib/web-server.js#L65

Is there any plans to allow something like this? If there is, I could whip something up.

@maksimr
Copy link
Contributor

maksimr commented Oct 10, 2015

@shanear what issue you want resolve by custom middleware?

Thanks

@shanear
Copy link
Contributor Author

shanear commented Oct 10, 2015

We're using karma to test an application connected to an API. We're in a large organization, and we have little control over this API.

We've been using middleware to:

  • proxy requests to that api, it isn't CORS enabled
  • manipulate the headers to mimic the hosted environment (ie: change the Host header)
  • remove 'http-only' headers on some of the authentication cookies, so we can easily manipulate authentication from the browser.

It's been an effective solution for running the application locally, and it's been nice to use the same solution to run the automated tests locally too (via test'em).

shanear added a commit to shanear/karma that referenced this issue Oct 12, 2015
shanear added a commit to shanear/karma that referenced this issue Oct 12, 2015
shanear added a commit to shanear/karma that referenced this issue Oct 14, 2015
This was referenced Oct 14, 2015
@dtothefp
Copy link

dtothefp commented Dec 2, 2015

@shanear thanks for adding this feature, I'm having an issue getting a response from the server and parsing data from the request. Wondering if you could provide any useful suggestions.

  • I'm not getting useful information from the _parsedUrl property in the request
  • when I return response.end('whatevs') I never get the response or an error so my test timeouts.

Any info you could offer or example repos would be great.

//config
    files: [
      'http://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js',
      testPath
    ],
    preprocessors,
    middleware: ['custom', 'another', 'last'],
    plugins: [
      'karma-*',
      {
        'middleware:custom': ['factory', function(config) {
          return function(request, response, next) {
            console.log('RESPONSE1*********');
            next();
          };
        }],
        'middleware:another': ['factory', function(config) {
          return function(request, response, next) {
            console.log('RESPONSE2**********');
            next();
          };
        }],
        'middleware:last': ['factory', function(config) {
          return function(request, response, next) {
            console.log('RESPONSE3**********', request._parsedUrl);
            response.writeHead(222);
            return response.end('Hello There');
          };
        }]
      }
    ],
//spec
  it('should make a request', (cb) => {
    const defer = $.get({
      url: 'http:localhost:9876/whatevs?stuff=things'
    });

    defer.then((data) => {
      console.log('DATA', data);
      cb();
    }, (err) => {
      console.log('ERR', err);
      cb();
    });
  });
#terminal output
RESPONSE1*********
RESPONSE2**********
RESPONSE3********** Url {
  protocol: null,
  slashes: null,
  auth: null,
  host: null,
  port: null,
  hostname: null,
  hash: null,
  search: null,
  query: null,
  pathname: '/[object%20Object]',
  path: '/[object%20Object]',
  href: '/[object%20Object]',
  _raw: '/[object%20Object]' }

@shanear
Copy link
Contributor Author

shanear commented Dec 3, 2015

hi @dtothefp,

your middleware configuration looks fine. I'm wondering about the spec. It seems like the url might not be correct. Are you sure you need to precede it with http:localhost:9876?

Unfortunately the application I use this feature in is closed source, but the karma test code may help. You can check it out here:
https://github.com/karma-runner/karma/blob/master/test/unit/web-server.spec.js#L60

also we use this function for our tests and it works fine:

var customMiddleware = function (request, response, next) {
    if (request.url === "/middleware.html") {
      response.writeHead(222)
      return response.end("middleware!")
    }
    next()
  }
}
// ... config
middleware: ['custom'],
plugins: [
  {'middleware:custom': ['value', customMiddleware]}
]

Hope that helps!

@dtothefp
Copy link

dtothefp commented Dec 4, 2015

@shanear thanks yeh I was looking at your tests before. Ends up that making the request with jQuery was the problem. Does weird stuff with the request url in connect. When I use superagent all works fine.

On another note, it seems the middleware would be more useful if it followed the same syntax as projects such as browser-sync so middleware would not have to be customized for Karma (ie middleware can be a function or an array)

https://github.com/BrowserSync/browser-sync/blob/1d86f1a8bae3d9228f732d3022644c2ebe521186/lib/server/utils.js#L20

Not sure if this is possible though with the dependency injection system that karma is using?

ex

    middleware: ['custom'],
    plugins: [
      'karma-*',
      {
        'middleware:custom': ['factory', function(config) {
          return [
            function firstMiddleware(request, response, next) {
              if (/base/.test(request.url)) {
                response.writeHead(222);
                return response.end('hello!!!');
              }
              next();
            },
            function firstMiddleware(request, response, next) {
              response.writeHead(222);
              return response.end('gotcha!!!');
            }
          ]
        }]
      }
    ],

@fredericoschardong
Copy link

@dtothefp any luck on overwriting karma's middleware workflow?

Considering that any custom middleware will be executed after all standard middlewares:

var handler = connect()
    .use(injector.invoke(runnerMiddleware.create))
    .use(injector.invoke(stripHostMiddleware.create))
    .use(injector.invoke(karmaMiddleware.create))
    .use(injector.invoke(sourceFilesMiddleware.create))
    // TODO(vojta): extract the proxy into a plugin
    .use(proxyMiddlewareInstance)
    // TODO(vojta): remove, this is only here because of karma-dart
    // we need a better way of custom handlers
    .use(injector.invoke(createCustomHandler))

  if (config.middleware) {
    config.middleware.forEach(function (middleware) {
      console.log('injecting')
      handler.use(injector.get('middleware:' + middleware))
    })
  }

And that karmaMiddleware will grab pretty much everything:

    // ignore urls outside urlRoot
    if (requestUrl.indexOf(urlRoot) !== 0) {
      console.log('caleed next')
      return next()
    }

How one can have his/her middleware interpreting regular files?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment